diff --git a/application/receipts/receipts_api.py b/application/receipts/receipts_api.py index 80d9e13..5d2fe57 100644 --- a/application/receipts/receipts_api.py +++ b/application/receipts/receipts_api.py @@ -104,18 +104,17 @@ def getReceipt(): return jsonify({'receipt': record, 'error': False, "message": "Get Receipts Successful!"}) return jsonify({'receipt': record, 'error': True, "message": "Something went wrong while getting receipts!"}) +# added to database @receipt_api.route('/api/addReceipt', methods=["POST", "GET"]) def addReceipt(): if request.method == "GET": user_id = session['user_id'] site_name = session['selected_site'] - database_config = config() - with psycopg2.connect(**database_config) as conn: - receipt = MyDataclasses.ReceiptPayload( - receipt_id=f"PR-{database.request_receipt_id(conn, site_name)}", - submitted_by=user_id - ) - database.insertReceiptsTuple(conn, site_name, receipt.payload()) + receipt = database_payloads.ReceiptPayload( + receipt_id=f"PR-{receipts_database.requestNextReceiptID(site_name)}", + submitted_by=user_id + ) + receipts_database.insertReceiptsTuple(site_name, receipt.payload()) return jsonify({'error': False, "message": "Receipt Added Successful!"}) return jsonify({'error': True, "message": "Something went wrong while adding receipt!"}) @@ -145,41 +144,37 @@ def addSKULine(): return jsonify({'error': False, "message": "Line added Succesfully"}) return jsonify({'error': True, "message": "Something went wrong while add SKU line!"}) +# Added to Database @receipt_api.route('/api/deleteLine', methods=["POST"]) def deleteLine(): if request.method == "POST": line_id = int(request.get_json()['line_id']) site_name = session['selected_site'] - database_config = config() - with psycopg2.connect(**database_config) as conn: - database.deleteReceiptItemsTuple(conn, site_name, (line_id, )) - + receipts_database.deleteReceiptItemsTuple(site_name, (line_id, )) return jsonify({'error': False, "message": "Line Deleted Succesfully"}) return jsonify({'error': True, "message": "Something went wrong while deleting line!"}) +# Added to Database @receipt_api.route('/api/denyLine', methods=["POST"]) def denyLine(): if request.method == "POST": line_id = int(request.get_json()['line_id']) site_name = session['selected_site'] - database_config = config() - with psycopg2.connect(**database_config) as conn: - database.__updateTuple(conn, site_name, f"{site_name}_receipt_items", {'id': line_id, 'update': {'status': 'Denied'}}) + receipts_database.updateReceiptItemsTuple(site_name, {'id': line_id, 'update': {'status': 'Denied'}}) return jsonify({'error': False, "message": "Line Denied Succesfully"}) return jsonify({'error': True, "message": "Something went wrong while denying line!"}) +# Added to database @receipt_api.route('/api/saveLine', methods=["POST"]) def saveLine(): if request.method == "POST": line_id = int(request.get_json()['line_id']) payload = request.get_json()['payload'] site_name = session['selected_site'] - database_config = config() - with psycopg2.connect(**database_config) as conn: - receipt_item = database.__selectTuple(conn, site_name, f"{site_name}_receipt_items", (line_id, ), convert=True) - if 'api_data' in receipt_item['data'].keys(): - payload['data']['api_data'] = receipt_item['data']['api_data'] - database.__updateTuple(conn, site_name, f"{site_name}_receipt_items", {'id': line_id, 'update': payload}) + receipt_item = receipts_database.selectReceiptItemsTuple(site_name, (line_id, )) + if 'api_data' in receipt_item['data'].keys(): + payload['data']['api_data'] = receipt_item['data']['api_data'] + receipts_database.updateReceiptItemsTuple(site_name, {'id': line_id, 'update': payload}) return jsonify({'error': False, "message": "Line Saved Succesfully"}) return jsonify({'error': True, "message": "Something went wrong while saving line!"}) @@ -377,9 +372,12 @@ def uploadFile(receipt_id): return jsonify({}) +# Does not need to be added to Database @receipt_api.route('/api/getFile/') def getFile(file_name): - return send_from_directory('static/files/receipts', file_name) + path_ = current_app.config['FILES_FOLDER'] + "/receipts" + print(path_) + return send_from_directory(path_, file_name) @receipt_api.route('/api/checkAPI', methods=["POST"]) def checkAPI(): @@ -390,7 +388,7 @@ def checkAPI(): database_config = config() with psycopg2.connect(**database_config) as conn: print(barcode, line_id) - api_response, api_data = get_open_facts(barcode) + api_response, api_data = receipts_processes.get_open_facts(barcode) if api_response: receipt_item = database.__selectTuple(conn, site_name, f"{site_name}_receipt_items", (line_id, ), convert=True) item_data = receipt_item['data'] @@ -405,16 +403,4 @@ def checkAPI(): else: return jsonify({'error': True, "message": "Item not in WorldFoodFacts!"}) return jsonify({'error': False, "message": "Line Saved Succesfully"}) - return jsonify({'error': True, "message": "Something went wrong while saving line!"}) - -open_food_api = openfoodfacts.API(user_agent="MyAwesomeApp/1.0") - -open_food_enabled = True - -def get_open_facts(barcode): - if open_food_enabled: - barcode: str = barcode.replace('%', "") - data = open_food_api.product.get(barcode) - if data != None: - return True, data - return False, {} \ No newline at end of file + return jsonify({'error': True, "message": "Something went wrong while saving line!"}) \ No newline at end of file diff --git a/application/receipts/receipts_database.py b/application/receipts/receipts_database.py index 2ddaa2b..adf8584 100644 --- a/application/receipts/receipts_database.py +++ b/application/receipts/receipts_database.py @@ -1,9 +1,48 @@ import psycopg2 - import config from application import postsqldb +def requestNextReceiptID(site_name, conn=None): + """gets the next id for receipts_id, currently returns a 8 digit number + + Args: + site (str): site to get the next id for + + Returns: + json: receipt_id, message, error keys + """ + next_receipt_id = None + self_conn = False + sql = f"SELECT receipt_id FROM {site_name}_receipts ORDER BY id DESC LIMIT 1;" + 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) + next_receipt_id = cur.fetchone() + if next_receipt_id == None: + next_receipt_id = "00000001" + else: + next_receipt_id = next_receipt_id[0] + next_receipt_id = int(next_receipt_id.split("-")[1]) + 1 + y = str(next_receipt_id) + len_str = len(y) + x = "".join(["0" for _ in range(8 - len_str)]) + next_receipt_id = x + y + + if self_conn: + conn.commit() + conn.close() + + return next_receipt_id + except (Exception, psycopg2.DatabaseError) as error: + raise postsqldb.DatabaseError(error, payload=(), sql=sql) + def getItemsWithQOH(site, payload, convert=True, conn=None): recordset = [] count = 0 @@ -69,7 +108,59 @@ def getItemAllByID(site, payload, convert=True, conn=None): except (Exception, psycopg2.DatabaseError) as error: raise postsqldb.DatabaseError(error, payload, getItemAllByID_sql) +def selectReceiptItemsTuple(site, payload, convert=True, conn=None): + selected = () + self_conn = False + sql = f"SELECT * FROM {site}_receipt_items 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) + if rows and not convert: + selected = rows + + if self_conn: + conn.close() + + return selected + except (Exception, psycopg2.DatabaseError) as error: + raise postsqldb.DatabaseError(error, payload, sql) + +def deleteReceiptItemsTuple(site, payload, convert=True, conn=None): + deleted = () + self_conn = False + sql = f"WITH deleted_rows AS (DELETE FROM {site}_receipt_items 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 insertReceiptItemsTuple(site, payload, convert=True, conn=None): receipt_item = () @@ -96,5 +187,79 @@ def insertReceiptItemsTuple(site, payload, convert=True, conn=None): conn.close() return receipt_item + except Exception as error: + raise postsqldb.DatabaseError(error, payload, sql) + +def insertReceiptsTuple(site, payload, convert=True, conn=None): + receipt = () + self_conn = False + with open(f"application/receipts/sql/insertReceiptsTuple.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: + receipt = postsqldb.tupleDictionaryFactory(cur.description, rows) + elif rows and not convert: + receipt = rows + + if self_conn: + conn.commit() + conn.close() + + return receipt + except Exception as error: + raise postsqldb.DatabaseError(error, payload, sql) + +def updateReceiptItemsTuple(site, payload, convert=True, conn=None): + """_summary_ + + Args: + conn (_T_connector@connect): Postgresql Connector + site (str): + payload (dict): {'id': row_id, 'update': {... column_to_update: value_to_update_to...}} + convert (bool, optional): determines if to return tuple as dictionary. Defaults to True. + + Raises: + DatabaseError: + + Returns: + tuple or dict: updated tuple + """ + updated = () + self_conn = False + + set_clause, values = postsqldb.updateStringFactory(payload['update']) + values.append(payload['id']) + sql = f"UPDATE {site}_receipt_items 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: + updated = postsqldb.tupleDictionaryFactory(cur.description, rows) + elif rows and not convert: + updated = rows + + if self_conn: + conn.commit() + conn.close() + + return updated + except Exception as error: raise postsqldb.DatabaseError(error, payload, sql) \ No newline at end of file diff --git a/application/receipts/receipts_processes.py b/application/receipts/receipts_processes.py index 1d36b84..023e062 100644 --- a/application/receipts/receipts_processes.py +++ b/application/receipts/receipts_processes.py @@ -1,6 +1,7 @@ import pymupdf import os import PIL +import openfoodfacts def create_pdf_preview(pdf_path, output_path, size=(600, 400)): pdf = pymupdf.open(pdf_path) @@ -11,4 +12,17 @@ def create_pdf_preview(pdf_path, output_path, size=(600, 400)): output_path = output_path + file_name + '.jpg' img.thumbnail(size) img.save(output_path) - return file_name + '.jpg' \ No newline at end of file + return file_name + '.jpg' + + +# OPEN FOOD FACTS API INTEGRATION +open_food_api = openfoodfacts.API(user_agent="MyAwesomeApp/1.0") +open_food_enabled = True + +def get_open_facts(barcode): + if open_food_enabled: + barcode: str = barcode.replace('%', "") + data = open_food_api.product.get(barcode) + if data != None: + return True, data + return False, {} \ No newline at end of file diff --git a/application/receipts/sql/insertReceiptsTuple.sql b/application/receipts/sql/insertReceiptsTuple.sql new file mode 100644 index 0000000..8ddaf60 --- /dev/null +++ b/application/receipts/sql/insertReceiptsTuple.sql @@ -0,0 +1,4 @@ +INSERT INTO %%site_name%%_receipts +(receipt_id, receipt_status, date_submitted, submitted_by, vendor_id, files) +VALUES (%s, %s, %s, %s, %s, %s) +RETURNING *; \ No newline at end of file diff --git a/application/receipts/static/js/receiptHandler.js b/application/receipts/static/js/receiptHandler.js index a20f9b7..dfd870e 100644 --- a/application/receipts/static/js/receiptHandler.js +++ b/application/receipts/static/js/receiptHandler.js @@ -250,7 +250,7 @@ async function viewFile(source) { document.getElementById('filenameiframemodal').innerHTML = source let iframe = document.createElement('iframe') - iframe.src = `/receipt/getFile/${source}` + iframe.src = `/receipts/api/getFile/${source}` iframe.width = "100%" iframe.style.height = "100%" diff --git a/application/receipts/templates/receipts_index.html b/application/receipts/templates/receipts_index.html index da5b01b..542688a 100644 --- a/application/receipts/templates/receipts_index.html +++ b/application/receipts/templates/receipts_index.html @@ -91,12 +91,12 @@
-
+