Files

430 lines
13 KiB
Python
Raw Permalink Normal View History

2023-12-03 10:18:20 -08:00
import json
import uuid
from datetime import datetime
import requests
from flask import Flask, request, send_from_directory
from flask_cors import CORS, cross_origin
from util import (
check_existing_token,
convert_to_mysql_query,
get_category_id,
get_data_from_db,
add_or_update_to_db,
delete_from_db,
get_store_id,
load_conf,
load_db_conn,
delete_receipt,
update_server_config,
convert_pdf_to_png
)
app = Flask(
__name__,
static_url_path="",
static_folder="../webroot",
)
cors = CORS(app, resources={r"/api/upload/*": {"origins": "*"}})
app.config["CORS_HEADERS"] = "Content-Type"
cfg = None
api_token = None
@app.before_first_request
def first():
global cfg
global api_token
cfg = load_conf()
api_token = check_existing_token()
@app.before_request
def before_request():
if request.endpoint in ('static', 'index'):
return
if not request.args:
return "No token provided! Add &token= to URL", 401
if api_token != request.args["token"]:
return "Unauthorized", 401
global cfg
cfg = load_conf()
if ((
not cfg["dbMode"]
or not cfg["sqlDatabase"]
or not cfg["sqlPassword"]
or not cfg["sqlServerIP"]
or not cfg["sqlUsername"]
)
and request.endpoint != 'updateConfig'
and request.endpoint != 'getBackendConfig'
):
return "Settings incomplete!", 512
@app.route("/", methods=["GET"])
def index():
return send_from_directory(app.static_folder, "index.html")
@app.route("/api/getBackendConfig", methods=["GET", "OPTIONS"])
@cross_origin(origin="*", headers=["Content-Type"])
def getBackendConfig():
return json.dumps(cfg)
@app.route("/api/updateConfig", methods=["POST", "OPTIONS"])
@cross_origin(origin="*", headers=["Content-Type"])
def updateConfig():
post_string = json.dumps(request.get_json())
post_json = json.loads(post_string)
update_server_config(post_json)
return "Config updated", 200
@app.route("/api/upload", methods=["POST", "OPTIONS"])
@cross_origin(origin="*", headers=["Content-Type"])
def upload():
file = request.files["file"]
file_name = file.filename
gaussian_blur = True
if file.content_type == "application/pdf":
file = convert_pdf_to_png(file.read())
file_name = file_name.split(".")[0] + ".png"
gaussian_blur = False
if not file:
return "No valid file found", 500
url = (
"http://"
+ str(cfg["parserIP"])
+ ":"
+ str(cfg["parserPort"])
+ "/api/upload?access_token="
+ str(cfg["parserToken"])
+ "&legacy_parser=True"
+ "&grayscale_image=True"
+ "&rotate_image=True"
+ "&gaussian_blur=" + str(gaussian_blur)
+ "&median_blur=True"
)
receipt_upload = requests.post(url, files={"file": (file_name, file)})
if receipt_upload.status_code == 200:
upload_response = json.dumps(receipt_upload.content.decode("utf8"))
response_json = json.loads(upload_response)
response_json = json.loads(response_json)
# Replace " in Date
if '"' in response_json["receiptDate"]:
response_json["receiptDate"] = response_json["receiptDate"].replace('"', "")
# Create 4 digit year
if response_json["receiptDate"] != "null":
year_string = response_json["receiptDate"].split(".")
if len(year_string[2]) < 4:
year_string[2] = "20" + year_string[2]
response_json["receiptDate"] = (
year_string[0] + "." + year_string[1] + "." + year_string[2]
)
conn, cursor = load_db_conn()
for idx, article in enumerate(response_json["receiptItems"]):
article = article[0]
splitted_articles = article.split(" ")
for article in splitted_articles:
if len(article) > 3:
if cfg["dbMode"] == "mysql":
sql_query = "SELECT category FROM purchaseData where article_name like %s order by timestamp desc limit 1"
else:
sql_query = "SELECT TOP 1 category FROM purchaseData where article_name like ? order by timestamp desc"
cursor.execute(sql_query, [f"%{article}%"])
row = cursor.fetchone()
if row:
if cfg["dbMode"] == "mysql":
found_cat = row[0]
else:
found_cat = row.category
copy_array = response_json["receiptItems"][idx]
copy_array.insert(2, found_cat)
response_json["receiptItems"][idx] = copy_array
break
conn.close()
return json.dumps(response_json)
else:
return "Error on upload", receipt_upload.status_code
@app.route("/api/getHistory", methods=["GET", "OPTIONS"])
@cross_origin(origin="*", headers=["Content-Type"])
def get_history():
conn, cursor = load_db_conn()
history_json = []
cursor.execute(
"select SUM(total) as totalSum, location, id, timestamp from purchaseData \
where id is not null \
GROUP BY timestamp, id, location \
ORDER BY timestamp desc"
)
rows = cursor.fetchall()
for row in rows:
if cfg["dbMode"] == "mysql":
add_json = {
"location": row[1],
"totalSum": str(row[0]),
"timestamp": str(row[3]),
"id": row[2],
}
else:
add_json = {
"location": row.location,
"totalSum": str(row.totalSum),
"timestamp": str(row.timestamp),
"id": row.id,
}
history_json.append(add_json)
conn.close()
return json.dumps(history_json)
@app.route("/api/getHistoryDetails", methods=["GET", "OPTIONS"])
@cross_origin(origin="*", headers=["Content-Type"])
def get_history_details():
purchase_id = request.args["purchaseID"]
conn, cursor = load_db_conn()
sql_query = (
"SELECT storeName, total, date, purchaseId " +
"FROM receipts re " +
"JOIN stores st ON re.storeId = st.id " +
"where re.id = ?"
)
if cfg["dbMode"] == "mysql":
sql_query = convert_to_mysql_query(sql_query)
cursor.execute(sql_query, [purchase_id])
row = cursor.fetchone()
if row:
if cfg["dbMode"] == "mysql":
store_name = row[0]
receipt_total = row[1]
receipt_date = row[2]
db_purchase_id = row[3]
else:
store_name = row.storeName
receipt_total = row.total
receipt_date = row.date
db_purchase_id = row.purchaseId
receipt_date = receipt_date.strftime("%d.%m.%Y")
purchase_details = {
"storeName": store_name,
"receiptTotal": str(receipt_total),
"receiptDate": receipt_date,
"purchaseID": db_purchase_id,
"receiptItems": [],
}
sql_query = "select article_name, total, category from purchaseData where id = ?"
if cfg["dbMode"] == "mysql":
sql_query = convert_to_mysql_query(sql_query)
cursor.execute(sql_query, [purchase_id])
rows = cursor.fetchall()
for row in rows:
if cfg["dbMode"] == "mysql":
add_json = [row[0], str(row[1]), row[2]]
else:
add_json = [row.article_name, str(row.total), row.category]
purchase_details["receiptItems"].append(add_json)
conn.close()
return json.dumps(purchase_details)
else:
return "Purchase not found!", 500
@app.route("/api/getValue", methods=["GET", "OPTIONS"])
@cross_origin(origin="*", headers=["Content-Type"])
def get_categories():
get_values_from = request.args["getValuesFrom"]
ret_json = get_data_from_db(get_values_from)
return json.dumps(ret_json, ensure_ascii=False)
@app.route("/api/addValue", methods=["POST", "OPTIONS"])
@cross_origin(origin="*", headers=["Content-Type"])
def add_value():
to_add_array = request.args["toAddArray"]
to_add_value = request.args["toAddValue"]
item_id = request.args["id"]
add_or_update_to_db(to_add_array, item_id, to_add_value)
return "Done!"
@app.route("/api/deleteValue", methods=["POST", "OPTIONS"])
@cross_origin(origin="*", headers=["Content-Type"])
def delete_value():
table_name = request.args["tableName"]
item_id = request.args["id"]
delete_from_db(table_name, item_id)
return "Done!"
@app.route("/api/deleteReceiptFromDB", methods=["POST", "OPTIONS"])
@cross_origin(origin="*", headers=["Content-Type"])
def delete_receipt_from_db():
receipt_id = request.args["purchaseID"]
delete_receipt(receipt_id)
return "Done!"
@app.route("/api/updateReceiptToDB", methods=["POST", "OPTIONS"])
@cross_origin(origin="*", headers=["Content-Type"])
def update_receipt_to_db():
post_string = json.dumps(request.get_json())
post_json = json.loads(post_string)
conn, cursor = load_db_conn()
store_id = get_store_id(post_json["storeName"])
receipt_date = post_json["receiptDate"]
receipt_total = post_json["receiptTotal"]
receipt_id = post_json["purchaseID"]
receipt_date = datetime.strptime(receipt_date, "%d.%m.%Y")
receipt_date = receipt_date.strftime("%m-%d-%Y")
# Clean old db data
delete_receipt(receipt_id)
# Write article positions
for article in post_json["receiptItems"]:
article_name = article[1]
article_sum = article[2]
article_id = int(str(uuid.uuid1().int)[:8])
article_category_id = get_category_id(article[3])
sql_query = "INSERT INTO items values (?,?,?,?)"
if cfg["dbMode"] == "mysql":
sql_query = convert_to_mysql_query(sql_query)
cursor.execute(
sql_query, [article_id, article_name, article_sum, article_category_id]
)
sql_query = "INSERT INTO purchasesArticles values (?,?)"
if cfg["dbMode"] == "mysql":
sql_query = convert_to_mysql_query(sql_query)
cursor.execute(sql_query, [receipt_id, article_id])
# Write receipt summary
if cfg["dbMode"] == "mysql":
sql_query = (
"INSERT INTO receipts values (%s,%s,STR_TO_DATE(%s,'%m-%d-%Y'),%s,%s,%s)"
)
else:
sql_query = "INSERT INTO receipts values (?,?,?,?,?,?)"
cursor.execute(
sql_query, [receipt_id, store_id, receipt_date, receipt_total, None, receipt_id]
)
conn.commit()
conn.close()
return "Done!"
@app.route("/api/writeReceiptToDB", methods=["POST", "OPTIONS"])
@cross_origin(origin="*", headers=["Content-Type"])
def write_receipt_to_db():
post_string = json.dumps(request.get_json())
post_json = json.loads(post_string)
conn, cursor = load_db_conn()
store_id = get_store_id(post_json["storeName"])
receipt_date = post_json["receiptDate"]
receipt_total = post_json["receiptTotal"]
receipt_id = int(str(uuid.uuid1().int)[:6])
receipt_date = datetime.strptime(receipt_date, "%d.%m.%Y")
receipt_date = receipt_date.strftime("%m-%d-%Y")
# Write article positions
for article in post_json["receiptItems"]:
article_id = int(str(uuid.uuid1().int)[:8])
article_name = article[1]
article_sum = article[2]
article_category_id = get_category_id(article[3])
if not article_category_id:
return "Category id for category: " + article[3] + " not found", 500
sql_query = "INSERT INTO items values (?,?,?,?)"
if cfg["dbMode"] == "mysql":
sql_query = convert_to_mysql_query(sql_query)
cursor.execute(
sql_query, [article_id, article_name, article_sum, article_category_id]
)
sql_query = "INSERT INTO purchasesArticles values (?,?)"
if cfg["dbMode"] == "mysql":
sql_query = convert_to_mysql_query(sql_query)
cursor.execute(sql_query, [receipt_id, article_id])
# Write receipt summary
if cfg["dbMode"] == "mysql":
sql_query = (
"INSERT INTO receipts values (%s,%s,STR_TO_DATE(%s,'%m-%d-%Y'),%s,%s,%s)"
)
else:
sql_query = "INSERT INTO receipts values (?,?,?,?,?,?)"
cursor.execute(
sql_query, [receipt_id, store_id, receipt_date, receipt_total, None, receipt_id]
)
conn.commit()
conn.close()
return "Done!"
@app.after_request
def add_header(r):
r.headers["Cache-Control"] = "no-cache, no-store, must-revalidate"
r.headers["Pragma"] = "no-cache"
r.headers["Expires"] = "0"
r.headers['Cache-Control'] = 'public, max-age=0'
return r