diff --git a/application/items/__pycache__/database_items.cpython-312.pyc b/application/items/__pycache__/database_items.cpython-312.pyc index fd32af6..56e5d99 100644 Binary files a/application/items/__pycache__/database_items.cpython-312.pyc and b/application/items/__pycache__/database_items.cpython-312.pyc differ diff --git a/application/items/__pycache__/items_API.cpython-312.pyc b/application/items/__pycache__/items_API.cpython-312.pyc index 5794732..70f8b6d 100644 Binary files a/application/items/__pycache__/items_API.cpython-312.pyc and b/application/items/__pycache__/items_API.cpython-312.pyc differ diff --git a/application/items/database_items.py b/application/items/database_items.py index 0a28425..b252c9d 100644 --- a/application/items/database_items.py +++ b/application/items/database_items.py @@ -60,6 +60,24 @@ def getItemAllByID(site:str, payload: tuple, convert:bool=True): except Exception as error: postsqldb.DatabaseError(error, payload, sql) +def getItemAllByBarcode(site:str, payload: tuple, convert:bool=True): + database_config = config.config() + with open('application/items/sql/getItemAllByBarcode.sql', 'r+') as file: + sql = file.read().replace("%%site_name%%", site) + record = () + 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 + except Exception as error: + postsqldb.DatabaseError(error, payload, sql) + def getItemsWithQOH(site:str, payload: tuple, convert:bool=True): database_config = config.config() with open('application/items/sql/getItemsWithQOH.sql', 'r+') as file: @@ -193,7 +211,19 @@ def paginateBrands(site:str, payload:tuple, convert:bool=True): except Exception as error: raise postsqldb.DatabaseError(error, payload, sql) -def postUpdateItem(site:str, payload:dict, convert:bool=True): +def postUpdateItem(site:str, payload:dict): + """ POST and update to an item + + Args: + site (str): name of the site the item exists in. + payload (dict): STRICT FORMAT + {id: item_id, data: SEE BELOW, user_id: updater} + + data is complex structure + top level keys should be a combo of: ['item', 'item_info', 'logistics_info', 'food_info'] + with in each of these top levels there are key value pairs in this format + {'column_name': 'new_value'} + """ def postUpdateData(conn, table, payload, convert=True): updated = () @@ -214,7 +244,7 @@ def postUpdateItem(site:str, payload:dict, convert:bool=True): def postAddTransaction(conn, site, payload, convert=False): transaction = () - with open(f"sql/INSERT/insertTransactionsTuple.sql", "r+") as file: + with open(f"application/items/sql/insertTransactionsTuple.sql", "r+") as file: sql = file.read().replace("%%site_name%%", site) try: with conn.cursor() as cur: @@ -273,4 +303,59 @@ def postUpdateItem(site:str, payload:dict, convert:bool=True): ) postAddTransaction(conn, site, trans.payload()) except Exception as error: - raise postsqldb.DatabaseError(error, payload, "MULTICALL!") \ No newline at end of file + raise postsqldb.DatabaseError(error, payload, "MULTICALL!") + +def postUpdateItemLink(site: str, payload: dict): + def postUpdateData(conn, table, payload, convert=True): + updated = () + set_clause, values = postsqldb.updateStringFactory(payload['update']) + values.append(payload['id']) + sql = f"UPDATE {table} SET {set_clause} WHERE id=%s RETURNING *;" + try: + 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 + except Exception as error: + raise postsqldb.DatabaseError(error, payload, sql) + return updated + + def postAddTransaction(conn, site, payload, convert=False): + transaction = () + with open(f"application/items/sql/insertTransactionsTuple.sql", "r+") as file: + sql = file.read().replace("%%site_name%%", site) + try: + 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 + except Exception as error: + raise postsqldb.DatabaseError(error, payload, sql) + return transaction + + database_config = config.config() + transaction_time = datetime.datetime.now() + barcode = payload['barcode'] + with psycopg2.connect(**database_config) as conn: + linkedItem = getItemAllByBarcode(site, (barcode, )) + + transaction = postsqldb.TransactionPayload( + timestamp=transaction_time, + logistics_info_id=linkedItem['logistics_info_id'], + barcode=barcode, + name=linkedItem['item_name'], + transaction_type='UPDATE', + quantity=0.0, + description='Link updated!', + user_id=payload['user_id'], + data={'new_conv_factor': payload['update']['conv_factor'], 'old_conv_factor': payload['old_conv_factor']} + ) + + postUpdateData(conn, f"{site}_itemlinks", {'id': payload['id'], 'update': {'conv_factor': payload['update']['conv_factor']}}) + postAddTransaction(conn, site, transaction.payload()) \ No newline at end of file diff --git a/application/items/items_API.py b/application/items/items_API.py index 93e2298..9fef416 100644 --- a/application/items/items_API.py +++ b/application/items/items_API.py @@ -316,6 +316,7 @@ def getLocationsBySkuZone(): return jsonify({'locations': locations, 'endpage': math.ceil(count/limit), 'error': True, 'message': f'method {request.method} is not allowed.'}) @items_api.route('/item/getBrands', methods=['GET']) +@login_required def getBrands(): """ GET brands from the system by passing page, limit --- @@ -350,6 +351,7 @@ def getBrands(): @items_api.route('/item/updateItem', methods=['POST']) +@login_required def updateItem(): """ POST update to item in the system by passing item_id, data --- @@ -378,36 +380,49 @@ def updateItem(): @items_api.route('/item/updateItemLink', methods=['POST']) def updateItemLink(): + """ UPDATE item link by passing id, conv_factor, barcode, old_conv + --- + parameters: + - in: query + name: id + schema: + type: integer + minimum: 1 + default: 1 + required: true + description: Id of item link to update + - in: query + name: conv_factor + schema: + type: integer + required: true + description: new conversion factor of item_link id + - in: query + name: barcode + schema: + type: string + required: true + description: barcode of item_link id + - in: query + name: old_conv + schema: + type: integer + required: true + description: old conversion factor of item_link id + responses: + 200: + description: Item Link updated successfully. + """ if request.method == "POST": id = request.get_json()['id'] conv_factor = request.get_json()['conv_factor'] barcode = request.get_json()['barcode'] old_conv_factor = request.get_json()['old_conv'] - - - database_config = config() site_name = session['selected_site'] - user_id = session['user_id'] - transaction_time = datetime.datetime.now() - with psycopg2.connect(**database_config) as conn: - linkedItem = database.getItemAllByBarcode(conn, site_name, (barcode, ), convert=True) - - transaction = MyDataclasses.TransactionPayload( - timestamp=transaction_time, - logistics_info_id=linkedItem['logistics_info_id'], - barcode=barcode, - name=linkedItem['item_name'], - transaction_type='UPDATE', - quantity=0.0, - description='Link updated!', - user_id=user_id, - data={'new_conv_factor': conv_factor, 'old_conv_factor': old_conv_factor} - ) - - database.__updateTuple(conn, site_name, f"{site_name}_itemlinks", {'id': id, 'update': {'conv_factor': conv_factor}}) - database.insertTransactionsTuple(conn, site_name, transaction.payload()) - return jsonify(error=False, message="Linked Item was updated successfully") - return jsonify(error=True, message="Unable to save this change, ERROR!") + payload = {'id': id, 'update':{'conv_factor': conv_factor}, 'barcode': barcode, 'old_conv_factor': old_conv_factor, 'user_id':session['user_id'] } + database_items.postUpdateItemLink(site_name, payload) + return jsonify({'error':False, 'message': "Linked Item was updated successfully"}) + return jsonify({'error': True, 'message': f"method {request.method} not allowed."}) @items_api.route('/item/getPossibleLocations', methods=["GET"]) diff --git a/application/items/sql/getItemAllByBarcode.sql b/application/items/sql/getItemAllByBarcode.sql new file mode 100644 index 0000000..b2c4b8d --- /dev/null +++ b/application/items/sql/getItemAllByBarcode.sql @@ -0,0 +1,75 @@ +WITH passed_id AS (SELECT id AS passed_id FROM %%site_name%%_items WHERE barcode=%s), + logistics_id AS (SELECT logistics_info_id FROM %%site_name%%_items WHERE id=(SELECT passed_id FROM passed_id)), + info_id AS (SELECT item_info_id FROM %%site_name%%_items WHERE id=(SELECT passed_id FROM passed_id)), + cte_item_info AS ( + SELECT + %%site_name%%_item_info.*, + row_to_json(units.*) as uom + FROM %%site_name%%_item_info + LEFT JOIN units ON %%site_name%%_item_info.uom = units.id + WHERE %%site_name%%_item_info.id = (SELECT item_info_id FROM info_id) + ), + cte_groups AS ( + SELECT + %%site_name%%_groups.*, + %%site_name%%_group_items.uuid, + %%site_name%%_group_items.item_type, + %%site_name%%_group_items.qty + FROM %%site_name%%_groups + JOIN %%site_name%%_group_items ON %%site_name%%_groups.id = %%site_name%%_group_items.gr_id + WHERE %%site_name%%_group_items.item_id = (SELECT passed_id FROM passed_id) + ), + cte_shopping_lists AS ( + SELECT + %%site_name%%_shopping_lists.*, + %%site_name%%_shopping_list_items.uuid, + %%site_name%%_shopping_list_items.item_type, + %%site_name%%_shopping_list_items.qty + FROM %%site_name%%_shopping_lists + JOIN %%site_name%%_shopping_list_items ON %%site_name%%_shopping_lists.id = %%site_name%%_shopping_list_items.sl_id + WHERE %%site_name%%_shopping_list_items.item_id = (SELECT passed_id FROM passed_id) + ), + cte_itemlinks AS ( + SELECT * FROM %%site_name%%_itemlinks WHERE link=(SELECT passed_id FROM passed_id) + ), + cte_item_locations AS ( + SELECT * FROM %%site_name%%_item_locations + LEFT JOIN %%site_name%%_locations ON %%site_name%%_locations.id = %%site_name%%_item_locations.location_id + WHERE part_id = (SELECT passed_id FROM passed_id) + ), + cte_logistics_info AS ( + SELECT + li.*, + row_to_json(pl) AS primary_location, + row_to_json(ail) AS auto_issue_location, + row_to_json(pz) AS primary_zone, + row_to_json(aiz) AS auto_issue_zone + FROM %%site_name%%_logistics_info AS li + LEFT JOIN %%site_name%%_locations AS pl ON li.primary_location = pl.id + LEFT JOIN %%site_name%%_locations AS ail ON li.auto_issue_location = ail.id + LEFT JOIN %%site_name%%_zones AS pz ON li.primary_zone = pz.id + LEFT JOIN %%site_name%%_zones AS aiz ON li.auto_issue_zone = aiz.id + WHERE li.id=(SELECT logistics_info_id FROM logistics_id) + ) + +SELECT + (SELECT passed_id FROM passed_id) AS passed_id, + %%site_name%%_items.*, + (SELECT COALESCE(row_to_json(logis), '{}') FROM cte_logistics_info logis) AS logistics_info, + row_to_json(%%site_name%%_food_info.*) as food_info, + row_to_json(%%site_name%%_brands.*) as brand, + (SELECT COALESCE(row_to_json(ii), '{}') FROM cte_item_info ii) AS item_info, + (SELECT COALESCE(array_agg(row_to_json(g)), '{}') FROM cte_groups g) AS item_groups, + (SELECT COALESCE(array_agg(row_to_json(sl)), '{}') FROM cte_shopping_lists sl) AS item_shopping_lists, + (SELECT COALESCE(array_agg(row_to_json(il)), '{}') FROM cte_itemlinks il) AS linked_items, + (SELECT COALESCE(array_agg(row_to_json(ils)), '{}') FROM cte_item_locations ils) AS item_locations +FROM %%site_name%%_items + LEFT JOIN %%site_name%%_item_info ON %%site_name%%_items.item_info_id = %%site_name%%_item_info.id + LEFT JOIN %%site_name%%_food_info ON %%site_name%%_items.food_info_id = %%site_name%%_food_info.id + LEFT JOIN %%site_name%%_brands ON %%site_name%%_items.brand = %%site_name%%_brands.id + LEFT JOIN units ON %%site_name%%_item_info.uom = units.id + LEFT JOIN cte_groups ON %%site_name%%_items.id = cte_groups.id + LEFT JOIN cte_shopping_lists ON %%site_name%%_items.id = cte_shopping_lists.id +WHERE %%site_name%%_items.id=(SELECT passed_id FROM passed_id) +GROUP BY + %%site_name%%_items.id, %%site_name%%_item_info.id, %%site_name%%_food_info.id, %%site_name%%_brands.id; \ No newline at end of file diff --git a/application/items/sql/itemsModal.sql b/application/items/sql/itemsModal.sql index 7af323e..ef10e65 100644 --- a/application/items/sql/itemsModal.sql +++ b/application/items/sql/itemsModal.sql @@ -1,3 +1,5 @@ -SELECT item.id, item.barcode, item.item_name FROM %%site_name%%_items item +SELECT item.id, item.barcode, item.item_name, u.id as uom FROM %%site_name%%_items item +LEFT JOIN %%site_name%%_item_info item_info ON item_info.id = item.item_info_id +LEFT JOIN units u ON u.id = item_info.uom WHERE item.search_string LIKE '%%' || %s || '%%' LIMIT %s OFFSET %s; \ No newline at end of file diff --git a/database.log b/database.log index 5cf6446..abc5896 100644 --- a/database.log +++ b/database.log @@ -1931,4 +1931,7 @@ sql='UPDATE test_items SET brand = %s, item_type = %s WHERE id=%s RETURNING *;') 2025-04-27 18:20:02.983151 --- ERROR --- DatabaseError(message='can't adapt type 'builtin_function_or_method'', payload={'id': , 'update': {'brand': 1066, 'item_type': 'FOOD_PLU'}}, - sql='UPDATE test_items SET brand = %s, item_type = %s WHERE id=%s RETURNING *;') \ No newline at end of file + sql='UPDATE test_items SET brand = %s, item_type = %s WHERE id=%s RETURNING *;') +2025-04-28 06:46:35.145654 --- ERROR --- DatabaseError(message='can't adapt type 'builtin_function_or_method'', + payload={'id': , 'update': {'conv_factor': 3}}, + sql='UPDATE test_itemlinks SET conv_factor = %s WHERE id=%s RETURNING *;') \ No newline at end of file diff --git a/static/handlers/itemEditHandler.js b/static/handlers/itemEditHandler.js index e7577d6..a7e594e 100644 --- a/static/handlers/itemEditHandler.js +++ b/static/handlers/itemEditHandler.js @@ -702,7 +702,7 @@ async function updateItemsModalTable(logis) { tableRow.id = fetchedItems[i].id tableRow.onclick = async function(){ - closeZoneLocationBrandModal([fetchedItems[i].barcode, fetchedItems[i].item_info.uom], fetchedItems[i].id, logis) + closeZoneLocationBrandModal([fetchedItems[i].barcode, fetchedItems[i].uom], fetchedItems[i].id, logis) } tableRow.append(idCell, barcodeCell, nameCell) itemsTableBody.append(tableRow) diff --git a/templates/items/itemlink.html b/templates/items/itemlink.html index a55b93f..e41d463 100644 --- a/templates/items/itemlink.html +++ b/templates/items/itemlink.html @@ -129,6 +129,7 @@ } async function postUpdate(){ + console.log(linked_item) const response = await fetch(`/item/updateItemLink`, { method: 'POST', headers: { @@ -138,7 +139,7 @@ id: parseInt(id), conv_factor: parseFloat(document.getElementById('conversion').value), barcode: document.getElementById('barcode').value, - old_conv: linked_item[4] + old_conv: linked_item['conv_factor'] }), }); data = await response.json()