From 1212473c4867f1a07ce403d95807940d71a06823 Mon Sep 17 00:00:00 2001 From: Jadowyne Ulve Date: Sun, 10 Aug 2025 09:47:48 -0500 Subject: [PATCH] Implemeted first attempt at Recipe Receipting --- .../__pycache__/poe_processes.cpython-313.pyc | Bin 5894 -> 5894 bytes .../database_recipes.cpython-313.pyc | Bin 15707 -> 27326 bytes .../recipe_processes.cpython-313.pyc | Bin 0 -> 6196 bytes .../__pycache__/recipes_api.cpython-313.pyc | Bin 14355 -> 15202 bytes application/recipes/database_recipes.py | 277 +++++++++++++++++- application/recipes/recipe_processes.py | 143 +++++++++ application/recipes/recipes_api.py | 17 +- .../recipes/sql/getItemTupleByUUID.sql | 6 + .../recipes/sql/insertCostLayersTuple.sql | 4 + .../recipes/sql/insertTransactionsTuple.sql | 5 + .../recipes/sql/updateItemLocation.sql | 4 + .../recipes/static/js/recipeViewHandler.js | 59 +++- .../recipes/templates/recipe_view.html | 27 +- logs/database.log | 20 +- 14 files changed, 543 insertions(+), 19 deletions(-) create mode 100644 application/recipes/__pycache__/recipe_processes.cpython-313.pyc create mode 100644 application/recipes/recipe_processes.py create mode 100644 application/recipes/sql/getItemTupleByUUID.sql create mode 100644 application/recipes/sql/insertCostLayersTuple.sql create mode 100644 application/recipes/sql/insertTransactionsTuple.sql create mode 100644 application/recipes/sql/updateItemLocation.sql diff --git a/application/poe/__pycache__/poe_processes.cpython-313.pyc b/application/poe/__pycache__/poe_processes.cpython-313.pyc index e02cea010a354cff4fffb28e94003d0f49e122cf..a0870bea65ac076a68cb5131e52c46492c76d82e 100644 GIT binary patch delta 20 acmZqEYt!TY%*)Hg00at4XKdvDEd~HL+Xb}% delta 20 acmZqEYt!TY%*)Hg00c5c(>HSe76Sk_hy{HB diff --git a/application/recipes/__pycache__/database_recipes.cpython-313.pyc b/application/recipes/__pycache__/database_recipes.cpython-313.pyc index 147a3b50d31d0c267eea89e79040bc9c260455df..6d5ab8f9c6fb03b42061860d2ee230580091cf4f 100644 GIT binary patch literal 27326 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 Nw`>0nf00}K{{d(eRiyv` delta 972 zcmZXROH5Ni6ozN+v$rj!^g*Gew6qA+_`raVfDvd5E#V>UrQoAM2_Xd%1TGpA7RpvP z0w+e|BU%@-fEe{|5kr8)#AxDz#E9a?g*(B=#+cx_QbQt>%$fiE-<&x!_b#l`wK3E8 ztSmjj5of0R9{VRvc{Dg#daT7Nb51fq6;Zazd{QS1Nl6xy`bt68q0b>PAkiE~mNJfU zXKy7Z>oabaY@M9*U;Y1>tPD2q6lEHiG9+gg$<7eVE@I9Q>n@VBO}vV27qVoE>?sItIgVZz&e2~O#>t1=f?I=AgD^CH64na$LntbX6AkND$0HH$MO}Q5 zu1a+9i)cHeI{8Fxj$&yDxuoTdTj*3fF`mjz~ z=0xFIsf9O@eL@)JHS#RVQZ9&6ZEk(XsGpiVRA|HW z4uP3iyLzhSH7hh=K30z3Ef1bVIEciY<_KC!R11w-XoitkxgevQBkD{{qBN#Hjo)X4 z(`Y>>(2-bGU-Z7GGy%6$r9y{R(+PtX2dt+|LK4$g+9n^^`mRf7Fb&Z5KrYPo#f!Bc zplEMXw5KTAtrhKpiq=ih&R3Gq+V9qPqog=TZE&f-%acv3r|W+bTsC|H&6{R72rds2 SKeT1j4CaAxX0rg&1MWXyI_FCO diff --git a/application/recipes/__pycache__/recipe_processes.cpython-313.pyc b/application/recipes/__pycache__/recipe_processes.cpython-313.pyc new file mode 100644 index 0000000000000000000000000000000000000000..05e07d39b460da0ac9dd931e055119989abd8b59 GIT binary patch literal 6196 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 literal 0 HcmV?d00001 diff --git a/application/recipes/__pycache__/recipes_api.cpython-313.pyc b/application/recipes/__pycache__/recipes_api.cpython-313.pyc index 241808ba40d57a4736514e012f42fe964ea7690f..2dff7dba3a47fc28ef468d1279ef85486fa93c1b 100644 GIT binary patch delta 3110 zcmZ`*Yit|G5xzaXb$m!9Es>N&@gbW!N)a7Njx9gxSQ3&dvYptBR5w;ZpUIPSHYJ|- zj!xwURvRR!T{Li=1rjAjfj$r^HM_OVkf8dhdBWZ5;jm`^W1`iv!oaA@tAdsV@vX=EJ@im*ujy znfAvzus_DlqXd_=&j+%OtTXExx8mS@@Z=!r7z%jW_8@SZ$m?bEG>-Ma@DX7K`Ct`mEcH*;uS3T{rm9An2^Bv?${)5N$AHhia*Nq`BHgB$HP>{8S<<988gK`Y?6*Ki>>$ha7PV z08*s6J=HNHh#)=)FhXALNVJcFI0gVLlX#a@D4b*!#-}P$=RQQkzS{K=AK4EpfC0=l$|zvpG5vk_i(TKIO=Owy>2h7w4r4T&3ThI%668V=}n?X$#cC! z!e-)=hLwnQ!dWx61{6bBqhs6DlBUlZUS-k|B{b-3(ObNo1r3q&@xzftSi1zE z0GtCj4^Sk(hz}gtEZ}`lY^9{fq++r3v|Nab-j;eY{#Xl5!qO7}CrK)?`{*o)tYLr= z(aH*J@C1?Tf_VffHCwXxLiUqoO)o72aagZ>KhXoVzm+WWYn!||6l%@UGYrJxW$X+>A`RfE_fWaDJB@n=$S5gfwINAL=WEo6|lcZFM8iEVqci-bn8 zr|1i+!3L~X0WJVwfGynE4Q^OPS!C#@x)pYZH7aW0ABt<1*DC-+v{4y7&s3gDMS-5x zf!9$GxTw2TC9jvUoKq!z3FpaJTC_J#LOwk)QJ`~Ji_@~OsFz`pYe6YCR6Q}8 zYOy30rkCNpca{7t{W?mMYlA46vHNME)`IK_(6H z{257AGW0abimDq^Ag|^Rn#V%__x$AN{xtd`L45%$ciPI4!+|gn`#PFqQCO3YYpCrG64iE1Hz2<%wm>dHAj`l#9jHIG*5$;2U0x zi;k9pvqR{n>+7A3TR`J>01w~>PeKF-1=^mhGuemd2x#Fu+fsfys(U^~DSn0OehafM zQTQtNiJe<>`o4boYnRtMZ#()ng5B$n*MdV=TpRxIx>)n~UvX?i(sv?9-isW$CH`UV zOLyiL-kV#vJ-2i_qFnV|vH!)lV*f0bT%j z5#S{NpywvXk~2O*&V$RPLb)h^4u6lD;1aH#Aa}=7mcMcnmF_(s@e?0gUFaP8IK=Uu tJIG%{{%Rog)~>fgRVtzVe?r0?6se)eUEYZn(LD>tcLN-_YlSh3^nb6+wvPY+ delta 2451 zcmZ`)O>7fa5cb=6?HKaO$ZJNAr65S5RDpAXd5?$N^K;d&m$MehG?Qme%W;AQ;qUTlCCxb5zQD!?ufL!c^O=Ck-`x zd|7{*WCK%zP0T2gfyf{Z6dqHxA@wLQx9OO;w#rz1?J`{1!B>BeaEAO~pkZV;*N@x_Sy zFlso15KQ>{1Cn4kG+owf8r{!KDqQkUkukXAABpf&(@d!e3^obUV;JBV{Nbl8q#T$d z0pv*g5s)I|_MmOdJ&58c!hZO>Eg2X?aU9_Q!UPPr$CLaJ_vC4|HiFLJu^A|}udzJO z+Cu_444s{QBm~o)H|^*IA9wDDjm|{(3HI_9eTAXqrFQh=*^a_^*W!U!@qHEnbI_9r zm{$`Su(n%`cggwuJkC?03-#~1GK8i5H*`=4PoW2Pfbv3li+Q2@;I(j=@hOCd+-bCL zmU}y#*;(%6aN^BLJd|M|Ir&ypXkJrv$`hEA!vkj#IM+i=(wq!9O^ax2LD6S*rKHhw z@OICCjOIe*G}+S_tl_9t*@h|<_wSxyP9_K6MtjK#_$|8E-5kYHh{gued zUBs;BQtql&G=0I0dI7W;u%ymCUkeVNGz32;UJmEcS3y`tC?KpLsL-DroNmr&!y7MG z^tfCsR^CM zqg5tq*i{^+HBL8IS&W#k|1`%@Kn_$y+)N>Rn}MNdH7^Va%}GQ z_d~~z%j^u@oB~gJ6`fqmYH`y8^KY2}THUp3u_EVZOZX+b4zt5|i3CrFA2@jH--G(z z^z{1}*TsNMm&fIo;2OHKFQC4%Eu@RxgPh6(-h}AL8?1!#$mb-*=i865cx;@}%!bFj z+Hov7PM2YCI+kn>gj*ay z))4xD;XNBgqUI;5^>C?@uN9S-=xwGW>|YCmD>KmYt8KJCo_Qj;pW0pIBH=Fo1GqaO Ak^lez diff --git a/application/recipes/database_recipes.py b/application/recipes/database_recipes.py index b6fad27..18251a4 100644 --- a/application/recipes/database_recipes.py +++ b/application/recipes/database_recipes.py @@ -91,20 +91,30 @@ def getRecipes(site:str, payload:tuple, convert=True): raise postsqldb.DatabaseError(error, payload, sql) return recordset, count -def getRecipe(site, payload:tuple, convert=True): - database_config = config.config() +def getRecipe(site, payload:tuple, convert=True, conn=None): + self_conn = False + record = () with open(f"application/recipes/sql/getRecipeByID.sql", "r+") as file: sql = file.read().replace("%%site_name%%", site) try: - with psycopg2.connect(**database_config) as conn: - with conn.cursor() as cur: - cur.execute(sql, payload) - rows = cur.fetchone() - if rows and convert: - record = postsqldb.tupleDictionaryFactory(cur.description, rows) - if rows and not convert: - record = rows - return record + 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) + if rows and not convert: + record = rows + + if self_conn: + conn.close() + + return record except (Exception, psycopg2.DatabaseError) as error: raise postsqldb.DatabaseError(error, payload, sql) @@ -116,6 +126,164 @@ def getPicturePath(site:str, payload:tuple): rows = cur.fetchone()[0] 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): database_config = config.config() record = () @@ -200,6 +368,93 @@ def postDeleteRecipeItem(site:str, payload:tuple, convert:bool=True): deleted = rows 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): database_config = config.config() deleted = () diff --git a/application/recipes/recipe_processes.py b/application/recipes/recipe_processes.py new file mode 100644 index 0000000..0894b20 --- /dev/null +++ b/application/recipes/recipe_processes.py @@ -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, "" diff --git a/application/recipes/recipes_api.py b/application/recipes/recipes_api.py index 45a4b83..0a79bc6 100644 --- a/application/recipes/recipes_api.py +++ b/application/recipes/recipes_api.py @@ -8,7 +8,7 @@ import math import main import webpush 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 recipes_api = Blueprint('recipes_api', __name__, template_folder="templates", static_folder="static") @@ -198,4 +198,17 @@ def saveRecipeItem(): updated_line = database_recipes.postUpdateRecipeItem(site_name, {'id': id, 'update': update}) 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': True, 'message': f'method {request.method} not allowed!'}) \ No newline at end of file + 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!") \ No newline at end of file diff --git a/application/recipes/sql/getItemTupleByUUID.sql b/application/recipes/sql/getItemTupleByUUID.sql new file mode 100644 index 0000000..e481bc8 --- /dev/null +++ b/application/recipes/sql/getItemTupleByUUID.sql @@ -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; \ No newline at end of file diff --git a/application/recipes/sql/insertCostLayersTuple.sql b/application/recipes/sql/insertCostLayersTuple.sql new file mode 100644 index 0000000..c3d381f --- /dev/null +++ b/application/recipes/sql/insertCostLayersTuple.sql @@ -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 *; \ No newline at end of file diff --git a/application/recipes/sql/insertTransactionsTuple.sql b/application/recipes/sql/insertTransactionsTuple.sql new file mode 100644 index 0000000..d8ee48d --- /dev/null +++ b/application/recipes/sql/insertTransactionsTuple.sql @@ -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 *; \ No newline at end of file diff --git a/application/recipes/sql/updateItemLocation.sql b/application/recipes/sql/updateItemLocation.sql new file mode 100644 index 0000000..7316d94 --- /dev/null +++ b/application/recipes/sql/updateItemLocation.sql @@ -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 *; \ No newline at end of file diff --git a/application/recipes/static/js/recipeViewHandler.js b/application/recipes/static/js/recipeViewHandler.js index 4c6ad65..6ad1f26 100644 --- a/application/recipes/static/js/recipeViewHandler.js +++ b/application/recipes/static/js/recipeViewHandler.js @@ -21,6 +21,7 @@ async function replenishRecipe() { await replenishIngrediantsTable() await replenishInstructions() + await replenishTransactionsTable() await getImage() @@ -32,16 +33,21 @@ async function replenishIngrediantsTable() { for(let i=0; iHave` - } else { + if (qty_needed <= quantity_on_hand && item_type === "sku"){ + markerCell.innerHTML = `On Hand` + } else if (qty_needed > quantity_on_hand && item_type === "sku") { markerCell.innerHTML = `Missing` + } else { + markerCell.innerHTML = "" } - let nameCell = document.createElement('td') 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() { let tileList = document.getElementById('tileList') tileList.innerHTML = "" @@ -89,4 +116,28 @@ async function getImage(){ const imageURL = URL.createObjectURL(imageBlob); 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 + }); } \ No newline at end of file diff --git a/application/recipes/templates/recipe_view.html b/application/recipes/templates/recipe_view.html index d2edb8b..50048f4 100644 --- a/application/recipes/templates/recipe_view.html +++ b/application/recipes/templates/recipe_view.html @@ -140,11 +140,36 @@
- +
+
+
+ + +
+
+

Recipe Receipt Transaction

+

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.

+ + + + + + + + + +
ItemQty
+

+ + +

+
+