Implemeted first attempt at Recipe Receipting
This commit is contained in:
parent
da0c67b7f7
commit
1212473c48
Binary file not shown.
Binary file not shown.
BIN
application/recipes/__pycache__/recipe_processes.cpython-313.pyc
Normal file
BIN
application/recipes/__pycache__/recipe_processes.cpython-313.pyc
Normal file
Binary file not shown.
Binary file not shown.
@ -91,12 +91,18 @@ def getRecipes(site:str, payload:tuple, convert=True):
|
|||||||
raise postsqldb.DatabaseError(error, payload, sql)
|
raise postsqldb.DatabaseError(error, payload, sql)
|
||||||
return recordset, count
|
return recordset, count
|
||||||
|
|
||||||
def getRecipe(site, payload:tuple, convert=True):
|
def getRecipe(site, payload:tuple, convert=True, conn=None):
|
||||||
database_config = config.config()
|
self_conn = False
|
||||||
|
record = ()
|
||||||
with open(f"application/recipes/sql/getRecipeByID.sql", "r+") as file:
|
with open(f"application/recipes/sql/getRecipeByID.sql", "r+") as file:
|
||||||
sql = file.read().replace("%%site_name%%", site)
|
sql = file.read().replace("%%site_name%%", site)
|
||||||
try:
|
try:
|
||||||
with psycopg2.connect(**database_config) as conn:
|
if not conn:
|
||||||
|
database_config = config.config()
|
||||||
|
conn = psycopg2.connect(**database_config)
|
||||||
|
conn.autocommit = True
|
||||||
|
self_conn = True
|
||||||
|
|
||||||
with conn.cursor() as cur:
|
with conn.cursor() as cur:
|
||||||
cur.execute(sql, payload)
|
cur.execute(sql, payload)
|
||||||
rows = cur.fetchone()
|
rows = cur.fetchone()
|
||||||
@ -104,6 +110,10 @@ def getRecipe(site, payload:tuple, convert=True):
|
|||||||
record = postsqldb.tupleDictionaryFactory(cur.description, rows)
|
record = postsqldb.tupleDictionaryFactory(cur.description, rows)
|
||||||
if rows and not convert:
|
if rows and not convert:
|
||||||
record = rows
|
record = rows
|
||||||
|
|
||||||
|
if self_conn:
|
||||||
|
conn.close()
|
||||||
|
|
||||||
return record
|
return record
|
||||||
except (Exception, psycopg2.DatabaseError) as error:
|
except (Exception, psycopg2.DatabaseError) as error:
|
||||||
raise postsqldb.DatabaseError(error, payload, sql)
|
raise postsqldb.DatabaseError(error, payload, sql)
|
||||||
@ -116,6 +126,164 @@ def getPicturePath(site:str, payload:tuple):
|
|||||||
rows = cur.fetchone()[0]
|
rows = cur.fetchone()[0]
|
||||||
return rows
|
return rows
|
||||||
|
|
||||||
|
def selectItemLocationsTuple(site_name, payload, convert=True, conn=None):
|
||||||
|
item_locations = ()
|
||||||
|
self_conn = False
|
||||||
|
select_item_location_sql = f"SELECT * FROM {site_name}_item_locations WHERE part_id = %s AND location_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(select_item_location_sql, payload)
|
||||||
|
rows = cur.fetchone()
|
||||||
|
if rows and convert:
|
||||||
|
item_locations = postsqldb.tupleDictionaryFactory(cur.description, rows)
|
||||||
|
elif rows and not convert:
|
||||||
|
item_locations = rows
|
||||||
|
|
||||||
|
if self_conn:
|
||||||
|
conn.commit()
|
||||||
|
conn.close()
|
||||||
|
|
||||||
|
return item_locations
|
||||||
|
except Exception as error:
|
||||||
|
return error
|
||||||
|
|
||||||
|
def selectCostLayersTuple(site_name, payload, convert=True):
|
||||||
|
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;"
|
||||||
|
try:
|
||||||
|
with psycopg2.connect(**database_config) as conn:
|
||||||
|
with conn.cursor() as cur:
|
||||||
|
cur.execute(select_cost_layers_sql, payload)
|
||||||
|
rows = cur.fetchall()
|
||||||
|
if rows and convert:
|
||||||
|
cost_layers = rows
|
||||||
|
cost_layers = [postsqldb.tupleDictionaryFactory(cur.description, layer) for layer in rows]
|
||||||
|
elif rows and not convert:
|
||||||
|
cost_layers = rows
|
||||||
|
return cost_layers
|
||||||
|
except Exception as error:
|
||||||
|
return error
|
||||||
|
|
||||||
|
def selectLocationsTuple(site, payload, convert=True, conn=None):
|
||||||
|
selected = ()
|
||||||
|
self_conn = False
|
||||||
|
sql = f"SELECT * FROM {site}_locations WHERE 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:
|
||||||
|
selected = postsqldb.tupleDictionaryFactory(cur.description, rows)
|
||||||
|
elif rows and not convert:
|
||||||
|
selected = rows
|
||||||
|
|
||||||
|
if self_conn:
|
||||||
|
conn.commit()
|
||||||
|
conn.close()
|
||||||
|
|
||||||
|
return selected
|
||||||
|
except Exception as error:
|
||||||
|
raise postsqldb.DatabaseError(error, payload, sql)
|
||||||
|
|
||||||
|
def selectItemTupleByUUID(site, payload, convert=True, conn=None):
|
||||||
|
selected = ()
|
||||||
|
self_conn = False
|
||||||
|
with open(f"application/recipes/sql/getItemTupleByUUID.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:
|
||||||
|
selected = postsqldb.tupleDictionaryFactory(cur.description, rows)
|
||||||
|
elif rows and not convert:
|
||||||
|
selected = rows
|
||||||
|
|
||||||
|
if self_conn:
|
||||||
|
conn.commit()
|
||||||
|
conn.close()
|
||||||
|
|
||||||
|
return selected
|
||||||
|
except Exception as error:
|
||||||
|
raise postsqldb.DatabaseError(error, payload, sql)
|
||||||
|
|
||||||
|
def insertCostLayersTuple(site, payload, convert=True, conn=None):
|
||||||
|
cost_layer = ()
|
||||||
|
self_conn = False
|
||||||
|
|
||||||
|
with open(f"application/recipes/sql/insertCostLayersTuple.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:
|
||||||
|
cost_layer = postsqldb.tupleDictionaryFactory(cur.description, rows)
|
||||||
|
elif rows and not convert:
|
||||||
|
cost_layer = rows
|
||||||
|
|
||||||
|
if self_conn:
|
||||||
|
conn.commit()
|
||||||
|
conn.close()
|
||||||
|
|
||||||
|
return cost_layer
|
||||||
|
except Exception as error:
|
||||||
|
raise postsqldb.DatabaseError(error, payload, sql)
|
||||||
|
|
||||||
|
def insertTransactionsTuple(site, payload, convert=True, conn=None):
|
||||||
|
# payload (tuple): (timestamp[timestamp], logistics_info_id[int], barcode[str], name[str],
|
||||||
|
transaction = ()
|
||||||
|
self_conn = False
|
||||||
|
with open(f"application/recipes/sql/insertTransactionsTuple.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:
|
||||||
|
transaction = postsqldb.tupleDictionaryFactory(cur.description, rows)
|
||||||
|
elif rows and not convert:
|
||||||
|
transaction = rows
|
||||||
|
|
||||||
|
if self_conn:
|
||||||
|
conn.commit()
|
||||||
|
conn.close()
|
||||||
|
|
||||||
|
except Exception as error:
|
||||||
|
raise postsqldb.DatabaseError(error, payload, sql)
|
||||||
|
return transaction
|
||||||
|
|
||||||
def postAddRecipe(site:str, payload:tuple, convert:bool=True):
|
def postAddRecipe(site:str, payload:tuple, convert:bool=True):
|
||||||
database_config = config.config()
|
database_config = config.config()
|
||||||
record = ()
|
record = ()
|
||||||
@ -200,6 +368,93 @@ def postDeleteRecipeItem(site:str, payload:tuple, convert:bool=True):
|
|||||||
deleted = rows
|
deleted = rows
|
||||||
return deleted
|
return deleted
|
||||||
|
|
||||||
|
def updateCostLayersTuple(site, payload, convert=True, conn=None):
|
||||||
|
cost_layer = ()
|
||||||
|
self_conn = False
|
||||||
|
|
||||||
|
set_clause, values = postsqldb.updateStringFactory(payload['update'])
|
||||||
|
values.append(payload['id'])
|
||||||
|
sql = f"UPDATE {site}_cost_layers 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:
|
||||||
|
cost_layer = postsqldb.tupleDictionaryFactory(cur.description, rows)
|
||||||
|
elif rows and not convert:
|
||||||
|
cost_layer = rows
|
||||||
|
|
||||||
|
if self_conn:
|
||||||
|
conn.commit()
|
||||||
|
conn.close()
|
||||||
|
|
||||||
|
return cost_layer
|
||||||
|
except Exception as error:
|
||||||
|
return error
|
||||||
|
|
||||||
|
def updateItemLocation(site, payload, convert=True, conn=None):
|
||||||
|
item_location = ()
|
||||||
|
self_conn = False
|
||||||
|
|
||||||
|
with open(f"application/recipes/sql/updateItemLocation.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:
|
||||||
|
item_location = postsqldb.tupleDictionaryFactory(cur.description, rows)
|
||||||
|
elif rows and not convert:
|
||||||
|
item_location = rows
|
||||||
|
|
||||||
|
if self_conn:
|
||||||
|
conn.commit()
|
||||||
|
conn.close()
|
||||||
|
|
||||||
|
return item_location
|
||||||
|
except Exception as error:
|
||||||
|
return error
|
||||||
|
|
||||||
|
def deleteCostLayersTuple(site, payload, convert=True, conn=None):
|
||||||
|
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;"
|
||||||
|
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 deleteRecipe(site:str, payload:tuple, convert:bool=True):
|
def deleteRecipe(site:str, payload:tuple, convert:bool=True):
|
||||||
database_config = config.config()
|
database_config = config.config()
|
||||||
deleted = ()
|
deleted = ()
|
||||||
|
|||||||
143
application/recipes/recipe_processes.py
Normal file
143
application/recipes/recipe_processes.py
Normal file
@ -0,0 +1,143 @@
|
|||||||
|
import psycopg2
|
||||||
|
import datetime
|
||||||
|
|
||||||
|
from application import database_payloads, postsqldb
|
||||||
|
from application.recipes import database_recipes
|
||||||
|
import config
|
||||||
|
|
||||||
|
def postTransaction(site_name, user_id, data: dict, conn=None):
|
||||||
|
""" dict_keys(['item_id', 'logistics_info_id', 'barcode', 'item_name', 'transaction_type',
|
||||||
|
'quantity', 'description', 'cost', 'vendor', 'expires', 'location_id'])"""
|
||||||
|
def quantityFactory(quantity_on_hand:float, quantity:float, transaction_type:str):
|
||||||
|
if transaction_type == "Adjust In":
|
||||||
|
quantity_on_hand += quantity
|
||||||
|
return quantity_on_hand
|
||||||
|
if transaction_type == "Adjust Out":
|
||||||
|
quantity_on_hand -= quantity
|
||||||
|
return quantity_on_hand
|
||||||
|
raise Exception("The transaction type is wrong!")
|
||||||
|
|
||||||
|
self_conn = False
|
||||||
|
if not conn:
|
||||||
|
database_config = config.config()
|
||||||
|
conn = psycopg2.connect(**database_config)
|
||||||
|
conn.autocommit = False
|
||||||
|
self_conn = True
|
||||||
|
|
||||||
|
|
||||||
|
transaction_time = datetime.datetime.now()
|
||||||
|
|
||||||
|
cost_layer = postsqldb.CostLayerPayload(
|
||||||
|
aquisition_date=transaction_time,
|
||||||
|
quantity=float(data['quantity']),
|
||||||
|
cost=float(data['cost']),
|
||||||
|
currency_type="USD",
|
||||||
|
vendor=int(data['vendor']),
|
||||||
|
expires=data['expires']
|
||||||
|
)
|
||||||
|
transaction = postsqldb.TransactionPayload(
|
||||||
|
timestamp=transaction_time,
|
||||||
|
logistics_info_id=int(data['logistics_info_id']),
|
||||||
|
barcode=data['barcode'],
|
||||||
|
name=data['item_name'],
|
||||||
|
transaction_type=data['transaction_type'],
|
||||||
|
quantity=float(data['quantity']),
|
||||||
|
description=data['description'],
|
||||||
|
user_id=user_id,
|
||||||
|
)
|
||||||
|
|
||||||
|
location = database_recipes.selectItemLocationsTuple(site_name, (data['item_id'], data['location_id']), conn=conn)
|
||||||
|
site_location = database_recipes.selectLocationsTuple(site_name, (location['location_id'], ), conn=conn)
|
||||||
|
print(location)
|
||||||
|
cost_layers: list = location['cost_layers']
|
||||||
|
if data['transaction_type'] == "Adjust In":
|
||||||
|
cost_layer = database_recipes.insertCostLayersTuple(site_name, cost_layer.payload(), conn=conn)
|
||||||
|
cost_layers.append(cost_layer['id'])
|
||||||
|
|
||||||
|
if data['transaction_type'] == "Adjust Out":
|
||||||
|
if float(location['quantity_on_hand']) < float(data['quantity']):
|
||||||
|
raise Exception(f"The quantity on hand for {data['item_name']} in {site_location['uuid']} is not enough to satisfy your transaction!")
|
||||||
|
cost_layers = database_recipes.selectCostLayersTuple(site_name, payload=(location['id'], ))
|
||||||
|
|
||||||
|
new_cost_layers = []
|
||||||
|
qty = float(data['quantity'])
|
||||||
|
for layer in cost_layers:
|
||||||
|
if qty == 0.0:
|
||||||
|
new_cost_layers.append(layer['id'])
|
||||||
|
elif qty >= float(layer['quantity']):
|
||||||
|
qty -= float(layer['quantity'])
|
||||||
|
layer['quantity'] = 0.0
|
||||||
|
else:
|
||||||
|
layer['quantity'] -= qty
|
||||||
|
new_cost_layers.append(layer['id'])
|
||||||
|
database_recipes.updateCostLayersTuple(site_name, {'id': layer['id'], 'update': {'quantity': layer['quantity']}}, conn=conn)
|
||||||
|
qty = 0.0
|
||||||
|
|
||||||
|
if layer['quantity'] == 0.0:
|
||||||
|
database_recipes.deleteCostLayersTuple(site_name, (layer['id'],), conn=conn)
|
||||||
|
|
||||||
|
cost_layers = new_cost_layers
|
||||||
|
|
||||||
|
quantity_on_hand = quantityFactory(float(location['quantity_on_hand']), data['quantity'], data['transaction_type'])
|
||||||
|
|
||||||
|
updated_item_location_payload = (cost_layers, quantity_on_hand, data['item_id'], data['location_id'])
|
||||||
|
database_recipes.updateItemLocation(site_name, updated_item_location_payload, conn=conn)
|
||||||
|
|
||||||
|
#site_location = database_recipes.selectLocationsTuple(site_name, (location['location_id'], ), conn=conn)
|
||||||
|
|
||||||
|
transaction.data = {'location': site_location['uuid']}
|
||||||
|
|
||||||
|
database_recipes.insertTransactionsTuple(site_name, transaction.payload(), conn=conn)
|
||||||
|
|
||||||
|
if self_conn:
|
||||||
|
conn.commit()
|
||||||
|
conn.close()
|
||||||
|
return conn
|
||||||
|
|
||||||
|
return {"error": False, "message":f"Transaction Successful!"}
|
||||||
|
|
||||||
|
def process_recipe_receipt(site_name, user_id, data:dict, conn=None):
|
||||||
|
"""data={'recipe_id': recipe_id}"""
|
||||||
|
|
||||||
|
self_conn = False
|
||||||
|
if not conn:
|
||||||
|
database_config = config.config()
|
||||||
|
conn = psycopg2.connect(**database_config)
|
||||||
|
conn.autocommit = False
|
||||||
|
self_conn = True
|
||||||
|
|
||||||
|
recipe = database_recipes.getRecipe(site_name, (data['recipe_id'],), conn=conn)
|
||||||
|
|
||||||
|
sku_items = [rp_item for rp_item in recipe['recipe_items'] if rp_item['item_type'] == "sku"]
|
||||||
|
for item in sku_items:
|
||||||
|
""" dict_keys(['item_id', 'logistics_info_id', 'barcode', 'item_name', 'transaction_type',
|
||||||
|
'quantity', 'description', 'cost', 'vendor', 'expires', 'location_id'])"""
|
||||||
|
item_stuff = database_recipes.selectItemTupleByUUID(site_name, (item['item_uuid'],), conn=conn)
|
||||||
|
print(item_stuff)
|
||||||
|
payload = {
|
||||||
|
'item_id': item_stuff['item_id'],
|
||||||
|
'logistics_info_id': item_stuff['logistics_info_id'],
|
||||||
|
'barcode': "",
|
||||||
|
'item_name': item_stuff['item_name'],
|
||||||
|
'transaction_type': "Adjust Out",
|
||||||
|
'quantity': item['qty'],
|
||||||
|
'description': f"Recipe Receipt - {data['recipe_id']}",
|
||||||
|
'cost': 0.00,
|
||||||
|
'vendor': 0,
|
||||||
|
'expires': False,
|
||||||
|
'location_id': item_stuff['auto_issue_location']
|
||||||
|
}
|
||||||
|
print(payload)
|
||||||
|
|
||||||
|
try:
|
||||||
|
postTransaction(site_name, user_id, payload, conn=conn)
|
||||||
|
except Exception as error:
|
||||||
|
conn.rollback()
|
||||||
|
conn.close()
|
||||||
|
return False, str(error)
|
||||||
|
|
||||||
|
if self_conn:
|
||||||
|
conn.commit()
|
||||||
|
conn.close()
|
||||||
|
|
||||||
|
return True, ""
|
||||||
@ -8,7 +8,7 @@ import math
|
|||||||
import main
|
import main
|
||||||
import webpush
|
import webpush
|
||||||
from application.access_module import access_api
|
from application.access_module import access_api
|
||||||
from application.recipes import database_recipes
|
from application.recipes import database_recipes, recipe_processes
|
||||||
from application import postsqldb as db
|
from application import postsqldb as db
|
||||||
|
|
||||||
recipes_api = Blueprint('recipes_api', __name__, template_folder="templates", static_folder="static")
|
recipes_api = Blueprint('recipes_api', __name__, template_folder="templates", static_folder="static")
|
||||||
@ -199,3 +199,16 @@ def saveRecipeItem():
|
|||||||
recipe = database_recipes.getRecipe(site_name, (int(updated_line['rp_id']), ))
|
recipe = database_recipes.getRecipe(site_name, (int(updated_line['rp_id']), ))
|
||||||
return jsonify({'recipe': recipe, 'error': False, 'message': f'Recipe Item {updated_line['item_name']} was updated successful!'})
|
return jsonify({'recipe': recipe, 'error': False, 'message': f'Recipe Item {updated_line['item_name']} was updated successful!'})
|
||||||
return jsonify({'recipe': recipe, 'error': True, 'message': f'method {request.method} not allowed!'})
|
return jsonify({'recipe': recipe, 'error': True, 'message': f'method {request.method} not allowed!'})
|
||||||
|
|
||||||
|
|
||||||
|
@recipes_api.route('/api/receiptRecipe', methods=["POST"])
|
||||||
|
@access_api.login_required
|
||||||
|
def receiptRecipe():
|
||||||
|
if request.method == "POST":
|
||||||
|
site_name = session['selected_site']
|
||||||
|
user_id = session['user_id']
|
||||||
|
status, message = recipe_processes.process_recipe_receipt(site_name, user_id, request.get_json())
|
||||||
|
if not status:
|
||||||
|
return jsonify(status=400, message=message)
|
||||||
|
return jsonify(status=201, message="Recipe Transacted Successfully!")
|
||||||
|
return jsonify(status=405, message=f"{request.method} is not an allowed method on this endpoint!")
|
||||||
6
application/recipes/sql/getItemTupleByUUID.sql
Normal file
6
application/recipes/sql/getItemTupleByUUID.sql
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
SELECT items.id AS item_id,
|
||||||
|
items.item_name as item_name,
|
||||||
|
items.logistics_info_id as logistics_info_id,
|
||||||
|
lginf.auto_issue_location as auto_issue_location
|
||||||
|
FROM %%site_name%%_items items
|
||||||
|
LEFT JOIN %%site_name%%_logistics_info lginf ON lginf.id = items.logistics_info_id WHERE item_uuid=%s;
|
||||||
4
application/recipes/sql/insertCostLayersTuple.sql
Normal file
4
application/recipes/sql/insertCostLayersTuple.sql
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
INSERT INTO %%site_name%%_cost_layers
|
||||||
|
(aquisition_date, quantity, cost, currency_type, expires, vendor)
|
||||||
|
VALUES (%s, %s, %s, %s, %s, %s)
|
||||||
|
RETURNING *;
|
||||||
5
application/recipes/sql/insertTransactionsTuple.sql
Normal file
5
application/recipes/sql/insertTransactionsTuple.sql
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
INSERT INTO %%site_name%%_transactions
|
||||||
|
(timestamp, logistics_info_id, barcode, name, transaction_type,
|
||||||
|
quantity, description, user_id, data)
|
||||||
|
VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s)
|
||||||
|
RETURNING *;
|
||||||
4
application/recipes/sql/updateItemLocation.sql
Normal file
4
application/recipes/sql/updateItemLocation.sql
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
UPDATE %%site_name%%_item_locations
|
||||||
|
SET cost_layers = %s, quantity_on_hand = %s
|
||||||
|
WHERE part_id=%s AND location_id=%s
|
||||||
|
RETURNING *;
|
||||||
@ -21,6 +21,7 @@ async function replenishRecipe() {
|
|||||||
|
|
||||||
await replenishIngrediantsTable()
|
await replenishIngrediantsTable()
|
||||||
await replenishInstructions()
|
await replenishInstructions()
|
||||||
|
await replenishTransactionsTable()
|
||||||
|
|
||||||
await getImage()
|
await getImage()
|
||||||
|
|
||||||
@ -32,16 +33,21 @@ async function replenishIngrediantsTable() {
|
|||||||
|
|
||||||
|
|
||||||
for(let i=0; i<recipe.recipe_items.length; i++){
|
for(let i=0; i<recipe.recipe_items.length; i++){
|
||||||
|
let qty_needed = recipe.recipe_items[i].qty
|
||||||
|
let quantity_on_hand = recipe.recipe_items[i].quantity_on_hand
|
||||||
|
let item_type = recipe.recipe_items[i].item_type
|
||||||
|
|
||||||
let tableRow = document.createElement('tr')
|
let tableRow = document.createElement('tr')
|
||||||
|
|
||||||
let markerCell = document.createElement('td')
|
let markerCell = document.createElement('td')
|
||||||
if (recipe.recipe_items[i].qty <= recipe.recipe_items[i].quantity_on_hand){
|
if (qty_needed <= quantity_on_hand && item_type === "sku"){
|
||||||
markerCell.innerHTML = `<span class="uk-label uk-label-success">Have</span>`
|
markerCell.innerHTML = `<span class="uk-label uk-label-success">On Hand</span>`
|
||||||
} else {
|
} else if (qty_needed > quantity_on_hand && item_type === "sku") {
|
||||||
markerCell.innerHTML = `<span class="uk-label uk-label-danger">Missing</span>`
|
markerCell.innerHTML = `<span class="uk-label uk-label-danger">Missing</span>`
|
||||||
|
} else {
|
||||||
|
markerCell.innerHTML = ""
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
let nameCell = document.createElement('td')
|
let nameCell = document.createElement('td')
|
||||||
nameCell.innerHTML = `${recipe.recipe_items[i].item_name}`
|
nameCell.innerHTML = `${recipe.recipe_items[i].item_name}`
|
||||||
|
|
||||||
@ -54,6 +60,27 @@ async function replenishIngrediantsTable() {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function replenishTransactionsTable() {
|
||||||
|
let receiptRecipeTableBody = document.getElementById('receiptRecipeTableBody')
|
||||||
|
receiptRecipeTableBody.innerHTML = ""
|
||||||
|
|
||||||
|
for(let i=0; i < recipe.recipe_items.length; i++){
|
||||||
|
if (recipe.recipe_items[i].item_type === "sku"){
|
||||||
|
let tableRow = document.createElement('tr')
|
||||||
|
|
||||||
|
let nameCell = document.createElement('td')
|
||||||
|
nameCell.innerHTML = `${recipe.recipe_items[i].item_name}`
|
||||||
|
|
||||||
|
let qtyUOMCell = document.createElement('td')
|
||||||
|
qtyUOMCell.innerHTML = `${recipe.recipe_items[i].qty}`
|
||||||
|
|
||||||
|
tableRow.append(nameCell, qtyUOMCell)
|
||||||
|
receiptRecipeTableBody.append(tableRow)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
async function replenishInstructions() {
|
async function replenishInstructions() {
|
||||||
let tileList = document.getElementById('tileList')
|
let tileList = document.getElementById('tileList')
|
||||||
tileList.innerHTML = ""
|
tileList.innerHTML = ""
|
||||||
@ -90,3 +117,27 @@ async function getImage(){
|
|||||||
document.getElementById('recipeImage').src = imageURL;
|
document.getElementById('recipeImage').src = imageURL;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function receiptRecipe(){
|
||||||
|
let recipe_id = recipe.id
|
||||||
|
const response = await fetch(`/recipes/api/receiptRecipe`, {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
},
|
||||||
|
body: JSON.stringify({
|
||||||
|
recipe_id: recipe_id
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
data = await response.json()
|
||||||
|
message_type = "primary"
|
||||||
|
if(data.error){
|
||||||
|
message_type = "danger"
|
||||||
|
}
|
||||||
|
UIkit.notification({
|
||||||
|
message: data.message,
|
||||||
|
status: message_type,
|
||||||
|
pos: 'top-right',
|
||||||
|
timeout: 5000
|
||||||
|
});
|
||||||
|
}
|
||||||
@ -140,9 +140,34 @@
|
|||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
<div id="tileList" class="uk-width-1-2@l uk-child-width-1-1 uk-grid-collapse">
|
<div id="tileList" class="uk-width-1-2@l uk-child-width-1-1 uk-grid-collapse">
|
||||||
|
</div>
|
||||||
|
<div class="uk-width-1-1">
|
||||||
|
<button class="uk-button uk-button-primary" type="button" uk-toggle="target: #receiptRecipeModal">Receipt Recipe</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
</div>
|
<!-- Receipt Recipe Modal -->
|
||||||
</div>
|
<div id="receiptRecipeModal" uk-modal>
|
||||||
|
<div class="uk-modal-dialog uk-modal-body">
|
||||||
|
<h2 class="uk-modal-title">Recipe Receipt Transaction</h2>
|
||||||
|
<p>You are about to receipt these items from the system, please confirm before completing these Transaction as once they have been completed
|
||||||
|
this cannot be reversed.</p>
|
||||||
|
<table class="uk-table uk-table-striped">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>Item</th>
|
||||||
|
<th>Qty</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody id="receiptRecipeTableBody">
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
<p class="uk-text-right">
|
||||||
|
<button class="uk-button uk-button-default uk-modal-close" type="button">Cancel</button>
|
||||||
|
<button onclick="receiptRecipe()" class="uk-button uk-button-primary" type="button">Complete</button>
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</body>
|
</body>
|
||||||
|
|||||||
@ -122,3 +122,21 @@
|
|||||||
2025-08-10 07:48:28.429239 --- ERROR --- DatabaseError(message='missing FROM-clause entry for table "item"LINE 24: LEFT JOIN sum_cte ON item.id = sum_cte.id ^',
|
2025-08-10 07:48:28.429239 --- ERROR --- DatabaseError(message='missing FROM-clause entry for table "item"LINE 24: LEFT JOIN sum_cte ON item.id = sum_cte.id ^',
|
||||||
payload=(1,),
|
payload=(1,),
|
||||||
sql='WITH passed_id AS (SELECT %s AS passed_id), sum_cte AS ( SELECT mi.id, 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.*, /*COALESCE(main_items.barcode, items.uuid) AS uuid,*/ (SELECT COALESCE(row_to_json(units.*), '{}') FROM units WHERE units.id=main_item_info.uom) AS item_uom, COALESCE(main_items.item_name, items.item_name) AS item_name, COALESCE(main_items.links, items.links) AS links, row_to_json(units.*) as uom, (SELECT COALESCE(array_agg(jsonb_build_object('conversion', conv, 'unit', units)), '{}') FROM main_conversions conv LEFT JOIN units ON conv.uom_id = units.id WHERE conv.item_id = main_items.id) AS conversions, COALESCE(sum_cte.total_sum, 0) AS quantity_on_hand FROM main_recipe_items items LEFT JOIN main_items ON items.item_id = main_items.id LEFT JOIN main_item_info ON main_items.item_info_id = main_item_info.id LEFT JOIN units ON units.id = items.uom LEFT JOIN sum_cte ON item.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, main_recipes.*, logins.username as author, (SELECT COALESCE(array_agg(row_to_json(ris)), '{}') FROM cte_recipe_items ris) AS recipe_itemsFROM main_recipesJOIN logins ON main_recipes.author = logins.idWHERE main_recipes.id=(SELECT passed_id FROM passed_id)')
|
sql='WITH passed_id AS (SELECT %s AS passed_id), sum_cte AS ( SELECT mi.id, 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.*, /*COALESCE(main_items.barcode, items.uuid) AS uuid,*/ (SELECT COALESCE(row_to_json(units.*), '{}') FROM units WHERE units.id=main_item_info.uom) AS item_uom, COALESCE(main_items.item_name, items.item_name) AS item_name, COALESCE(main_items.links, items.links) AS links, row_to_json(units.*) as uom, (SELECT COALESCE(array_agg(jsonb_build_object('conversion', conv, 'unit', units)), '{}') FROM main_conversions conv LEFT JOIN units ON conv.uom_id = units.id WHERE conv.item_id = main_items.id) AS conversions, COALESCE(sum_cte.total_sum, 0) AS quantity_on_hand FROM main_recipe_items items LEFT JOIN main_items ON items.item_id = main_items.id LEFT JOIN main_item_info ON main_items.item_info_id = main_item_info.id LEFT JOIN units ON units.id = items.uom LEFT JOIN sum_cte ON item.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, main_recipes.*, logins.username as author, (SELECT COALESCE(array_agg(row_to_json(ris)), '{}') FROM cte_recipe_items ris) AS recipe_itemsFROM main_recipesJOIN logins ON main_recipes.author = logins.idWHERE main_recipes.id=(SELECT passed_id FROM passed_id)')
|
||||||
|
2025-08-10 08:56:10.432791 --- ERROR --- DatabaseError(message=''int' object does not support indexing',
|
||||||
|
payload=4,
|
||||||
|
sql='WITH passed_id AS (SELECT %s AS passed_id), 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-10 08:57:07.377357 --- ERROR --- DatabaseError(message=''int' object does not support indexing',
|
||||||
|
payload=4,
|
||||||
|
sql='WITH passed_id AS (SELECT %s AS passed_id), 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-10 08:57:32.169483 --- ERROR --- DatabaseError(message=''int' object does not support indexing',
|
||||||
|
payload=4,
|
||||||
|
sql='WITH passed_id AS (SELECT %s AS passed_id), 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-10 09:12:15.585887 --- ERROR --- DatabaseError(message='syntax error at or near "%"LINE 1: SELECT * FROM test_items items LEFT JOIN %site_name%_logisti... ^',
|
||||||
|
payload=('44c41878-e645-4e16-a402-e480936ac4aa',),
|
||||||
|
sql='SELECT * FROM test_items items LEFT JOIN %%site_name%%_logistics_info lginf ON lginf.id = items.logistics_info_id WHERE item_uuid=%s;')
|
||||||
|
2025-08-10 09:21:38.180067 --- ERROR --- DatabaseError(message='duplicate key value violates unique constraint "test_item_locations_part_id_location_id_key"DETAIL: Key (part_id, location_id)=(2016, 2) already exists.',
|
||||||
|
payload=(2016, 2, 0.0, '{}'),
|
||||||
|
sql='INSERT INTO test_item_locations(part_id, location_id, quantity_on_hand, cost_layers) VALUES (%s, %s, %s, %s)RETURNING *;')
|
||||||
|
2025-08-10 09:26:25.470903 --- ERROR --- DatabaseError(message='syntax error at or near "{"LINE 1: SELECT items.*, lginf.* AS logistics_info FROM {site}_items ... ^',
|
||||||
|
payload=('44c41878-e645-4e16-a402-e480936ac4aa',),
|
||||||
|
sql='SELECT items.*, lginf.* AS logistics_info FROM {site}_items items LEFT JOIN {site}_logistics_info lginf ON lginf.id = items.logistics_info_id WHERE item_uuid=%s;')
|
||||||
Loading…
x
Reference in New Issue
Block a user