From 732acaff3f849aecf8ce8b83357fe0025c119cc1 Mon Sep 17 00:00:00 2001 From: Jadowyne Ulve Date: Sat, 2 Aug 2025 10:57:19 -0500 Subject: [PATCH] migrated receipts.postLine to new schema --- application/receipts/receipts_api.py | 90 +---------- application/receipts/receipts_database.py | 145 ++++++++++++++++++ application/receipts/receipts_processes.py | 93 +++++++++++ .../receipts/sql/insertCostLayersTuple.sql | 4 + .../receipts/sql/insertTransactionsTuple.sql | 5 + .../receipts/sql/updateItemLocation.sql | 4 + 6 files changed, 257 insertions(+), 84 deletions(-) create mode 100644 application/receipts/sql/insertCostLayersTuple.sql create mode 100644 application/receipts/sql/insertTransactionsTuple.sql create mode 100644 application/receipts/sql/updateItemLocation.sql diff --git a/application/receipts/receipts_api.py b/application/receipts/receipts_api.py index 0b2529e..549e068 100644 --- a/application/receipts/receipts_api.py +++ b/application/receipts/receipts_api.py @@ -192,105 +192,27 @@ def postLinkedItem(): return jsonify({'error': False, "message": "Line Saved Succesfully"}) return jsonify({'error': True, "message": "Something went wrong while saving line!"}) - +# Added to processes and Database @receipt_api.route('/api/resolveLine', methods=["POST"]) def resolveLine(): if request.method == "POST": line_id = int(request.get_json()['line_id']) site_name = session['selected_site'] user_id = session['user_id'] - database_config = config() - with psycopg2.connect(**database_config) as conn: - transaction_time = datetime.datetime.now() - receipt_item = database.__selectTuple(conn, site_name, f"{site_name}_receipt_items", (line_id, ), convert=True) - receipt = database.getReceiptByID(conn, site_name, (receipt_item['receipt_id'], ), convert=True) - conv_factor = 1.0 - if receipt_item['data']['expires'] is not False: - print(receipt_item['data']['expires']) - expiration = datetime.datetime.strptime(receipt_item['data']['expires'], "%Y-%m-%d") - else: - expiration = None - - if receipt_item['type'] == 'sku': - linked_item = database.getLinkedItemByBarcode(conn, site_name, (receipt_item['barcode'], )) - if len(linked_item) > 1: - conv_factor = linked_item['conv_factor'] - receipt_item['data']['linked_child'] = linked_item['barcode'] - - if receipt_item['type'] == 'api': - - data = { - 'barcode': receipt_item['barcode'], - 'name': receipt_item['name'], - 'subtype': 'FOOD' - } - process.postNewBlankItem(conn, site_name, user_id, data) - - if receipt_item['type'] == "new sku": - data = { - 'barcode': receipt_item['barcode'], - 'name': receipt_item['name'], - 'subtype': 'FOOD' - } - process.postNewBlankItem(conn, site_name, user_id, data) - - item = database.getItemAllByBarcode(conn, site_name, (receipt_item['barcode'], ), convert=True) - location = database.selectItemLocationsTuple(conn, site_name, (item['id'], item['logistics_info']['primary_location']['id']), convert=True) - cost_layers: list = location['cost_layers'] - - receipt_item['data']['location'] = item['logistics_info']['primary_location']['uuid'] - - transaction = MyDataclasses.TransactionPayload( - timestamp=transaction_time, - logistics_info_id=item['logistics_info_id'], - barcode=item['barcode'], - name=item['item_name'], - transaction_type="Adjust In", - quantity=(float(receipt_item['qty'])*conv_factor), - description=f"{receipt['receipt_id']}", - user_id=session['user_id'], - data=receipt_item['data'] - ) - - cost_layer = MyDataclasses.CostLayerPayload( - aquisition_date=transaction_time, - quantity=float(receipt_item['qty']), - cost=float(receipt_item['data']['cost']), - currency_type="USD", - vendor=receipt['vendor_id'], - expires=expiration - ) - - cost_layer = database.insertCostLayersTuple(conn, site_name, cost_layer.payload(), convert=True) - cost_layers.append(cost_layer['id']) - - quantity_on_hand = float(location['quantity_on_hand']) + float(receipt_item['qty']) - - updated_item_location_payload = (cost_layers, quantity_on_hand, item['id'], item['logistics_info']['primary_location']['id']) - database.updateItemLocation(conn, site_name, updated_item_location_payload) - - site_location = database.__selectTuple(conn, site_name, f"{site_name}_locations", (location['location_id'], ), convert=True) - - receipt_item['data']['location'] = site_location['uuid'] - - database.insertTransactionsTuple(conn, site_name, transaction.payload()) - - database.__updateTuple(conn, site_name, f"{site_name}_receipt_items", {'id': receipt_item['id'], 'update': {'status': "Resolved"}}) - - + payload = {'line_id': line_id} + receipts_processes.postLine(site_name, user_id, payload) return jsonify({'error': False, "message": "Line Saved Succesfully"}) return jsonify({'error': True, "message": "Something went wrong while saving line!"}) +# add to database @receipt_api.route('/api/postVendorUpdate', methods=["POST"]) def postVendorUpdate(): if request.method == "POST": receipt_id = int(request.get_json()['receipt_id']) vendor_id = int(request.get_json()['vendor_id']) site_name = session['selected_site'] - database_config = config() - with psycopg2.connect(**database_config) as conn: - postsqldb.ReceiptTable.update_receipt(conn, site_name, {'id': receipt_id, 'update': {'vendor_id': vendor_id}}) - return jsonify({'error': False, "message": "Line Saved Succesfully"}) + receipts_database.updateReceiptsTuple(site_name, {'id': receipt_id, 'update': {'vendor_id': vendor_id}}) + return jsonify({'error': False, "message": "Line Saved Succesfully"}) return jsonify({'error': True, "message": "Something went wrong while saving line!"}) # added to database diff --git a/application/receipts/receipts_database.py b/application/receipts/receipts_database.py index 1556f4c..8dd4232 100644 --- a/application/receipts/receipts_database.py +++ b/application/receipts/receipts_database.py @@ -301,6 +301,60 @@ def paginateLinkedLists(site, payload, convert=True, conn=None): except (Exception, psycopg2.DatabaseError) as error: raise postsqldb.DatabaseError(error, payload, sql) +def selectItemLocationsTuple(site_name, payload, convert=True, conn=None): + """payload (tuple): [item_id, location_id]""" + 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.close() + + return item_locations + 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.close() + + return selected + + except Exception as error: + raise postsqldb.DatabaseError(error, payload, sql) + def selectReceiptsTuple(site, payload, convert=True, conn=None): selected = () self_conn = False @@ -382,6 +436,39 @@ def deleteReceiptItemsTuple(site, payload, convert=True, conn=None): 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_type[str], quantity[float], description[str], user_id[int], data[jsonb]) + """ + transaction = () + self_conn = False + with open(f"application/receipts/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() + + return transaction + + except Exception as error: + raise postsqldb.DatabaseError(error, payload, sql) + def insertItemLinksTuple(site, payload, convert=True, conn=None): """payload (tuple): (barcode[str], link[int], data[jsonb], conv_factor[float]) """ link = () @@ -411,6 +498,36 @@ def insertItemLinksTuple(site, payload, convert=True, conn=None): except Exception as error: raise postsqldb.DatabaseError(error, payload, sql) +def insertCostLayersTuple(site, payload, convert=True, conn=None): + """payload (tuple): (aquisition_date[timestamp], quantity[float], cost[float], currency_type[str], expires[timestamp/None], vendor[int])""" + cost_layer = () + self_conn = False + + with open(f"application/receipts/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 insertReceiptItemsTuple(site, payload, convert=True, conn=None): receipt_item = () @@ -498,7 +615,35 @@ def updateItemsTuple(site, payload, convert=True, conn=None): except Exception as error: raise postsqldb.DatabaseError(error, payload, sql) + +def updateItemLocation(site, payload, convert=True, conn=None): + item_location = () + self_conn = False + with open(f"application/receipts/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 updateReceiptsTuple(site, payload, convert=True, conn=None): """payload (dict): {'id': row_id, 'update': {... column_to_update: value_to_update_to...}}""" updated = () diff --git a/application/receipts/receipts_processes.py b/application/receipts/receipts_processes.py index b211694..2444a80 100644 --- a/application/receipts/receipts_processes.py +++ b/application/receipts/receipts_processes.py @@ -3,6 +3,8 @@ import os import PIL import openfoodfacts import psycopg2 +import datetime + from application.receipts import receipts_database from application import database_payloads @@ -90,6 +92,97 @@ def linkItem(site, user_id, data, conn=None): receipts_database.updateReceiptItemsTuple(site, payload, conn=conn) + if self_conn: + conn.commit() + conn.close() + return False + + return conn + +def postLine(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 + transaction_time = datetime.datetime.now() + receipt_item = receipts_database.selectReceiptItemsTuple(site, (data['line_id'],), conn=conn) + receipt = receipts_database.getReceiptByID(site, (receipt_item['receipt_id'], ), conn=conn) + conv_factor = 1.0 + if receipt_item['data']['expires'] is not False: + expiration = datetime.datetime.strptime(receipt_item['data']['expires'], "%Y-%m-%d") + else: + expiration = None + + if receipt_item['type'] == 'sku': + linked_item = receipts_database.getLinkedItemByBarcode(site, (receipt_item['barcode'], ), conn=conn) + if len(linked_item) > 1: + conv_factor = linked_item['conv_factor'] + receipt_item['data']['linked_child'] = linked_item['barcode'] + + if receipt_item['type'] == 'api': + new_item_data = { + 'barcode': receipt_item['barcode'], + 'name': receipt_item['name'], + 'subtype': 'FOOD' + } + postNewBlankItem(site, user_id, new_item_data, conn=conn) + + if receipt_item['type'] == "new sku": + new_item_data = { + 'barcode': receipt_item['barcode'], + 'name': receipt_item['name'], + 'subtype': 'FOOD' + } + postNewBlankItem(site, user_id, new_item_data, conn=conn) + + item = receipts_database.getItemAllByBarcode(site, (receipt_item['barcode'], ), conn=conn) + + location = receipts_database.selectItemLocationsTuple(site, (item['id'], item['logistics_info']['primary_location']['id']), conn=conn) + cost_layers: list = location['cost_layers'] + + receipt_item['data']['location'] = item['logistics_info']['primary_location']['uuid'] + + transaction = database_payloads.TransactionPayload( + timestamp=transaction_time, + logistics_info_id=item['logistics_info_id'], + barcode=item['barcode'], + name=item['item_name'], + transaction_type="Adjust In", + quantity=(float(receipt_item['qty'])*conv_factor), + description=f"{receipt['receipt_id']}", + user_id=user_id, + data=receipt_item['data'] + ) + + cost_layer = database_payloads.CostLayerPayload( + aquisition_date=transaction_time, + quantity=float(receipt_item['qty']), + cost=float(receipt_item['data']['cost']), + currency_type="USD", + vendor=receipt['vendor_id'], + expires=expiration + ) + + cost_layer = receipts_database.insertCostLayersTuple(site, cost_layer.payload(), conn=conn) + cost_layers.append(cost_layer['id']) + + quantity_on_hand = float(location['quantity_on_hand']) + float(receipt_item['qty']) + + updated_item_location_payload = (cost_layers, quantity_on_hand, item['id'], item['logistics_info']['primary_location']['id']) + receipts_database.updateItemLocation(site, updated_item_location_payload, conn=conn) + + + site_location = receipts_database.selectLocationsTuple(site, (location['location_id'], ), conn=conn) + + receipt_item['data']['location'] = site_location['uuid'] + receipts_database.insertTransactionsTuple(site, transaction.payload(), conn=conn) + + receipts_database.updateReceiptItemsTuple(site, {'id': receipt_item['id'], 'update': {'status': "Resolved"}}, conn=conn) + + + if self_conn: conn.commit() conn.close() diff --git a/application/receipts/sql/insertCostLayersTuple.sql b/application/receipts/sql/insertCostLayersTuple.sql new file mode 100644 index 0000000..c3d381f --- /dev/null +++ b/application/receipts/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/receipts/sql/insertTransactionsTuple.sql b/application/receipts/sql/insertTransactionsTuple.sql new file mode 100644 index 0000000..d8ee48d --- /dev/null +++ b/application/receipts/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/receipts/sql/updateItemLocation.sql b/application/receipts/sql/updateItemLocation.sql new file mode 100644 index 0000000..7316d94 --- /dev/null +++ b/application/receipts/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