diff --git a/__pycache__/config.cpython-312.pyc b/__pycache__/config.cpython-312.pyc index eb8a59b..88aded8 100644 Binary files a/__pycache__/config.cpython-312.pyc and b/__pycache__/config.cpython-312.pyc differ diff --git a/__pycache__/main.cpython-312.pyc b/__pycache__/main.cpython-312.pyc index 9276f36..0830de1 100644 Binary files a/__pycache__/main.cpython-312.pyc and b/__pycache__/main.cpython-312.pyc differ diff --git a/main.py b/main.py index 0637477..cf89749 100644 --- a/main.py +++ b/main.py @@ -6,6 +6,34 @@ import json, datetime, copy, csv def lst2pgarr(alist): return '{' + ','.join(alist) + '}' +def update_item_primary(site_name, barcode, new_primary: str): + zone, location = new_primary.split("@") + + database_config = config() + + with psycopg2.connect(**database_config) as conn: + zone_exists = False + location_exists = False + try: + with conn.cursor() as cur: + cur.execute(f"SELECT name FROM {site_name}_zones WHERE name=%s;", (zone, )) + rows = cur.fetchone() + if len(rows) > 0: + zone_exists = True + cur.execute(f"SELECT name FROM {site_name}_locations WHERE name=%s;", (location, )) + rows = cur.fetchone() + if len(rows) > 0: + location_exists = True + + if zone_exists and location_exists: + with conn.cursor() as cur: + cur.execute(f"UPDATE {site_name}_logistics_info SET primary_location = %s WHERE barcode = %s;", (new_primary, barcode)) + + except (Exception, psycopg2.DatabaseError) as error: + print(error) + conn.rollback() + return False + def insert_row(table_name, name): sql = f"INSERT INTO {table_name}(id, name) VALUES(%s, %s) RETURNING id" id = None @@ -45,6 +73,7 @@ def create_table(sql_file: str): def create_logistics_info(conn, site_name, barcode, payload): sql = f"INSERT INTO {site_name}_logistics_info(barcode, primary_location, auto_issue_location, dynamic_locations, location_data, quantity_on_hand) VALUES (%s, %s, %s, %s, %s, %s) RETURNING id;" logistics_info_id = None + try: with conn.cursor() as cur: cur.execute(sql, @@ -78,7 +107,6 @@ def create_item_info(conn, site_name, barcode, payload): return item_info_id - def create_food_info(conn, site_name, payload): sql = f"INSERT INTO {site_name}_food_info(ingrediants, food_groups, nutrients, expires) VALUES (%s, %s, %s, %s) RETURNING id;" food_info_id = None @@ -95,6 +123,42 @@ def create_food_info(conn, site_name, payload): return food_info_id +def add_location(site_name, name, zone_id): + database_config = config() + with psycopg2.connect(**database_config) as conn: + sql = f"INSERT INTO {site_name}_locations (uuid, name, zone_id, items) VALUES (%s, %s, %s, %s);" + zone_name = None + try: + with conn.cursor() as cur: + cur.execute(f"SELECT name FROM {site_name}_zones WHERE id=%s;", (zone_id, )) + zone_name = cur.fetchone()[0] + print(zone_name) + except (Exception, psycopg2.DatabaseError) as error: + print(error) + conn.rollback() + return False + + uuid = f"{zone_name}@{name}" + try: + with conn.cursor() as cur: + cur.execute(sql, (uuid, name, zone_id, json.dumps({}))) + except (Exception, psycopg2.DatabaseError) as error: + print(error) + conn.rollback() + return False + +def add_zone(site_name, name): + database_config = config() + with psycopg2.connect(**database_config) as conn: + sql = f"INSERT INTO {site_name}_zones (name) VALUES (%s);" + try: + with conn.cursor() as cur: + cur.execute(sql, (name,)) + except (Exception, psycopg2.DatabaseError) as error: + print(error) + conn.rollback() + return False + def add_transaction(site_name, barcode, qty, user_id, transaction_type = "info", description = "", data = {}, location=None): database_config = config() with psycopg2.connect(**database_config) as conn: @@ -135,12 +199,11 @@ def add_transaction(site_name, barcode, qty, user_id, transaction_type = "info", else: mover = location - location_items = None location_id = None try: with conn.cursor() as cur: - cur.execute(f"SELECT id, items FROM {site_name}_locations WHERE name=%s;", (mover, )) + cur.execute(f"SELECT id, items FROM {site_name}_locations WHERE uuid=%s;", (mover, )) location = cur.fetchone() if location: location_id = location[0] @@ -155,8 +218,6 @@ def add_transaction(site_name, barcode, qty, user_id, transaction_type = "info", else: location_items[logistics_info[3]] = qty - print(location_items) - if mover in logistics_info[0].keys(): logistics_info[0][mover] = logistics_info[0][mover] + qty else: @@ -182,8 +243,9 @@ def add_food_item(site_name: str, barcode: str, name: str, qty: float, payload: # TODO: I need to validate the name so that it doesnt have characters against the SQL database schema such as ' defaults = config(filename=f"sites/{site_name}/site.ini", section="defaults") - payload["logistics_info"]["primary_location"] = defaults["default_primary_location"] - payload["logistics_info"]["auto_issue_location"] = defaults["default_auto_issue_location"] + uuid = f"{defaults["default_zone"]}@{defaults["default_primary_location"]}" + payload["logistics_info"]["primary_location"] = uuid + payload["logistics_info"]["auto_issue_location"] = uuid database_config = config() @@ -218,7 +280,6 @@ def add_food_item(site_name: str, barcode: str, name: str, qty: float, payload: add_transaction(site_name, barcode, qty=0, user_id=1, description="Added Item to System!") add_transaction(site_name, barcode, qty=qty, user_id=1, description="scan in") - def drop_table(sql_file: str): database_config = config() @@ -266,7 +327,7 @@ def create_site(site_name): create_table(f'sites/{site_name}/sql/create/locations.sql') sql = f"INSERT INTO {site_name}_zones(name) VALUES (%s) RETURNING id;" - sqltwo = f"INSERT INTO {site_name}_locations(name, zone_id, items) VALUES (%s, %s, %s);" + sqltwo = f"INSERT INTO {site_name}_locations(uuid, name, zone_id, items) VALUES (%s, %s, %s, %s);" database_config = config() with psycopg2.connect(**database_config) as conn: @@ -282,9 +343,11 @@ def create_site(site_name): conn.rollback() return False + uuid = f"{site_config["default_zone"]}@{site_config["default_primary_location"]}" + try: with conn.cursor() as cur: - cur.execute(sqltwo, (site_config["default_primary_location"], zone_id, json.dumps({}))) + cur.execute(sqltwo, (uuid, site_config["default_primary_location"], zone_id, json.dumps({}))) except (Exception, psycopg2.DatabaseError) as error: print(error) conn.rollback() diff --git a/manage.py b/manage.py index dcf13ce..10ec4b5 100644 --- a/manage.py +++ b/manage.py @@ -33,7 +33,6 @@ def rename_create_sql(site_name): with open(f"sites/{site_name}/sql/create/{file_name}", "w") as file: file.write(words) - def create(): site_name = input("Site Name: ") site_owner = input("Site Owner: ") @@ -78,27 +77,55 @@ def create(): if __name__ == "__main__": if len(sys.argv) > 1: func_name = sys.argv[1] + argument = sys.argv[2] - if func_name == "create_site": + if func_name == "create" and argument == "site": create() - if func_name == "propagate": - main.create_site(sys.argv[2]) + if func_name == "propagate" and argument == "site": + main.create_site(sys.argv[3]) - if func_name == "delete": - main.delete_site(sys.argv[2]) - shutil.rmtree(f"sites/{sys.argv[2]}") + if func_name == "delete" and argument == "site": + main.delete_site(sys.argv[3]) + shutil.rmtree(f"sites/{sys.argv[3]}") - if func_name == "add_item": - barcode = input("barcode: ") - name = input("name: ") - qty = float(input("qty: ")) - main.add_food_item(sys.argv[2], barcode, name, qty, payload=main.payload_food_item) + if func_name == "item": + if argument == "add": + barcode = input("barcode: ") + name = input("name: ") + qty = float(input("qty: ")) + main.add_food_item(sys.argv[3], barcode, name, qty, payload=main.payload_food_item) - if func_name == "transact": - barcode = input("barcode: ") - qty = float(input("qty: ")) - location = input("TO: ") + if argument == "update_primary": + barcode = input("barcode: ") + location = input(f"New Zone/Location (default@all): ") + main.update_item_primary(sys.argv[3], barcode, location) - main.add_transaction(sys.argv[2], barcode, qty, 1, description="manual", location=location) + if argument == "transact": + barcode = input("barcode: ") + qty = float(input("qty: ")) + location = str(input("TO: ")).strip() + if location == "": + location = None + + main.add_transaction(sys.argv[3], barcode, qty, 1, description="manual", location=location) + + if argument == "transfer": + barcode = input("barcode: ") + qty = float(input("qty: ")) + from_location = str(input("From: ")).strip() + to_location = str(input("To: ")).strip() + + + if func_name == "location": + if argument == "add": + location_name = str(input(f"New Location Name: ")).replace(" ", "_") + zone_id = int(input(f"Zone ID: ")) + main.add_location(sys.argv[3], location_name, zone_id) + + if func_name == "zone": + if argument == "add": + zone_name = str(input(f"New Zone Name: ")).replace(" ", "_") + + main.add_zone(sys.argv[3], zone_name) \ No newline at end of file diff --git a/sites/default/sql/create/locations.sql b/sites/default/sql/create/locations.sql index 7f0ca04..43f6e61 100644 --- a/sites/default/sql/create/locations.sql +++ b/sites/default/sql/create/locations.sql @@ -1,9 +1,10 @@ CREATE TABLE IF NOT EXISTS %sitename%_locations( id SERIAL PRIMARY KEY, + uuid VARCHAR(255) NOT NULL, name VARCHAR(32) NOT NULL, zone_id INTEGER NOT NULL, items JSONB, - UNIQUE(name), + UNIQUE(uuid), CONSTRAINT fk_zone FOREIGN KEY(zone_id) REFERENCES %sitename%_zones(id) diff --git a/sites/default/sql/create/logistics_info.sql b/sites/default/sql/create/logistics_info.sql index 370f3be..e8ceab2 100644 --- a/sites/default/sql/create/logistics_info.sql +++ b/sites/default/sql/create/logistics_info.sql @@ -1,8 +1,8 @@ CREATE TABLE IF NOT EXISTS %sitename%_logistics_info( id SERIAL PRIMARY KEY, barcode VARCHAR(255) NOT NULL, - primary_location VARCHAR(16), - auto_issue_location VARCHAR(16), + primary_location VARCHAR(64), + auto_issue_location VARCHAR(64), dynamic_locations JSONB, location_data JSONB, quantity_on_hand FLOAT8 NOT NULL, diff --git a/sites/main/site.ini b/sites/main/site.ini new file mode 100644 index 0000000..d08dec8 --- /dev/null +++ b/sites/main/site.ini @@ -0,0 +1,9 @@ +[site] +site_name=main +site_owner=jadowyne +email= + +[defaults] +default_zone=default +default_primary_location=all +default_auto_issue_location=all diff --git a/sites/main/sql/create/brands.sql b/sites/main/sql/create/brands.sql new file mode 100644 index 0000000..172eb8f --- /dev/null +++ b/sites/main/sql/create/brands.sql @@ -0,0 +1,4 @@ +CREATE TABLE IF NOT EXISTS main_brands ( + id SERIAL PRIMARY KEY, + name VARCHAR(255) +); \ No newline at end of file diff --git a/sites/main/sql/create/food_info.sql b/sites/main/sql/create/food_info.sql new file mode 100644 index 0000000..eff6aaf --- /dev/null +++ b/sites/main/sql/create/food_info.sql @@ -0,0 +1,7 @@ +CREATE TABLE IF NOT EXISTS main_food_info ( + id SERIAL PRIMARY KEY, + food_groups TEXT [], + ingrediants TEXT [], + nutrients JSONB, + expires BOOLEAN +); \ No newline at end of file diff --git a/sites/main/sql/create/groups.sql b/sites/main/sql/create/groups.sql new file mode 100644 index 0000000..678cb61 --- /dev/null +++ b/sites/main/sql/create/groups.sql @@ -0,0 +1,8 @@ +CREATE TABLE IF NOT EXISTS main_groups( + id SERIAL PRIMARY KEY, + name VARCHAR(255) NOT NULL, + description TEXT, + included_items INTEGER [], + group_type VARCHAR(255), + UNIQUE (name) +); \ No newline at end of file diff --git a/sites/main/sql/create/item.sql b/sites/main/sql/create/item.sql new file mode 100644 index 0000000..5f1c027 --- /dev/null +++ b/sites/main/sql/create/item.sql @@ -0,0 +1,27 @@ +CREATE TABLE IF NOT EXISTS main_items( + id SERIAL PRIMARY KEY, + barcode VARCHAR(255) NOT NULL, + item_name VARCHAR(255) NOT NULL, + brand INTEGER, + tags TEXT [], + links TEXT [], + item_info_id INTEGER NOT NULL, + logistics_info_id INTEGER NOT NULL, + food_info_id INTEGER, + row_type VARCHAR(255) NOT NULL, + item_type VARCHAR(255) NOT NULL, + search_string TEXT NOT NULL, + UNIQUE(barcode, item_info_id), + CONSTRAINT fk_item_info + FOREIGN KEY(item_info_id) + REFERENCES main_item_info(id), + CONSTRAINT fk_food_info + FOREIGN KEY(food_info_id) + REFERENCES main_food_info(id), + CONSTRAINT fk_brand + FOREIGN KEY(brand) + REFERENCES main_brands(id), + CONSTRAINT fk_logistics_info + FOREIGN KEY(logistics_info_id) + REFERENCES main_logistics_info(id) +); diff --git a/sites/main/sql/create/item_info.sql b/sites/main/sql/create/item_info.sql new file mode 100644 index 0000000..4a5de26 --- /dev/null +++ b/sites/main/sql/create/item_info.sql @@ -0,0 +1,15 @@ +CREATE TABLE IF NOt EXISTS main_item_info ( + id SERIAL PRIMARY KEY, + barcode VARCHAR(255) NOT NULL, + linked_items INTEGER [], + shopping_lists INTEGER [], + recipes INTEGER [], + groups INTEGER [], + packaging VARCHAR(255), + uom VARCHAR(255), + cost FLOAT8, + safety_stock FLOAT8, + lead_time_days FLOAT8, + ai_pick BOOLEAN, + UNIQUE(barcode) +); \ No newline at end of file diff --git a/sites/main/sql/create/linked_items.sql b/sites/main/sql/create/linked_items.sql new file mode 100644 index 0000000..54afe9d --- /dev/null +++ b/sites/main/sql/create/linked_items.sql @@ -0,0 +1,8 @@ +CREATE TABLE IF NOT EXISTS main_itemlinks ( + id SERIAL PRIMARY KEY, + barcode VARCHAR(255) NOt NULL, + link INTEGER NOT NULL, + data JSONB NOT NULL, + conv_factor FLOAT8 NOt NULL, + UNIQUE(barcode) +); \ No newline at end of file diff --git a/sites/main/sql/create/locations.sql b/sites/main/sql/create/locations.sql new file mode 100644 index 0000000..179587b --- /dev/null +++ b/sites/main/sql/create/locations.sql @@ -0,0 +1,11 @@ +CREATE TABLE IF NOT EXISTS main_locations( + id SERIAL PRIMARY KEY, + uuid VARCHAR(255) NOT NULL, + name VARCHAR(32) NOT NULL, + zone_id INTEGER NOT NULL, + items JSONB, + UNIQUE(uuid), + CONSTRAINT fk_zone + FOREIGN KEY(zone_id) + REFERENCES main_zones(id) +); \ No newline at end of file diff --git a/sites/main/sql/create/logins.sql b/sites/main/sql/create/logins.sql new file mode 100644 index 0000000..f69b01b --- /dev/null +++ b/sites/main/sql/create/logins.sql @@ -0,0 +1,16 @@ +CREATE TABLE IF NOT EXISTS logins( + id SERIAL PRIMARY KEY, + username VARCHAR(255), + password VARCHAR(255), + favorites JSONB, + unseen_pantry_items INTEGER [], + unseen_groups INTEGER [], + unseen_shopping_lists INTEGER [], + unseen_recipes INTEGER [], + seen_pantry_items INTEGER [], + seen_groups INTEGER[], + seen_shopping_lists INTEGER [], + seen_recipes INTEGER [], + flags JSONB +); + diff --git a/sites/main/sql/create/logistics_info.sql b/sites/main/sql/create/logistics_info.sql new file mode 100644 index 0000000..cdeee33 --- /dev/null +++ b/sites/main/sql/create/logistics_info.sql @@ -0,0 +1,10 @@ +CREATE TABLE IF NOT EXISTS main_logistics_info( + id SERIAL PRIMARY KEY, + barcode VARCHAR(255) NOT NULL, + primary_location VARCHAR(64), + auto_issue_location VARCHAR(64), + dynamic_locations JSONB, + location_data JSONB, + quantity_on_hand FLOAT8 NOT NULL, + UNIQUE(barcode) +); \ No newline at end of file diff --git a/sites/main/sql/create/transactions.sql b/sites/main/sql/create/transactions.sql new file mode 100644 index 0000000..25ec73d --- /dev/null +++ b/sites/main/sql/create/transactions.sql @@ -0,0 +1,15 @@ +CREATE TABLE IF NOT EXISTS main_Transactions ( + id SERIAL PRIMARY KEY, + timestamp TIMESTAMP, + logistics_info_id INTEGER NOT NULL, + barcode VARCHAR(255) NOT NULL, + name VARCHAR(255), + transaction_type VARCHAR(255) NOT NULL, + quantity FLOAT8 NOT NULL, + description TEXT, + user_id INTEGER NOT NULL, + data JSONB, + CONSTRAINT fk_logistics_info + FOREIGN KEY(logistics_info_id) + REFERENCES main_logistics_info(id) +); \ No newline at end of file diff --git a/sites/main/sql/create/zones.sql b/sites/main/sql/create/zones.sql new file mode 100644 index 0000000..f06afa4 --- /dev/null +++ b/sites/main/sql/create/zones.sql @@ -0,0 +1,5 @@ +CREATE TABLE IF NOT EXISTS main_zones( + id SERIAL PRIMARY KEY, + name VARCHAR(32) NOT NULL, + UNIQUE(name) +); diff --git a/sites/main/sql/drop/brands.sql b/sites/main/sql/drop/brands.sql new file mode 100644 index 0000000..62263a0 --- /dev/null +++ b/sites/main/sql/drop/brands.sql @@ -0,0 +1 @@ +DROP TABLE main_brands CASCADE; \ No newline at end of file diff --git a/sites/main/sql/drop/food_info.sql b/sites/main/sql/drop/food_info.sql new file mode 100644 index 0000000..f74a1b9 --- /dev/null +++ b/sites/main/sql/drop/food_info.sql @@ -0,0 +1 @@ +DROP TABLE main_food_info CASCADE; \ No newline at end of file diff --git a/sites/main/sql/drop/groups.sql b/sites/main/sql/drop/groups.sql new file mode 100644 index 0000000..9f949d7 --- /dev/null +++ b/sites/main/sql/drop/groups.sql @@ -0,0 +1 @@ +DROP TABLE main_groups CASCADE; \ No newline at end of file diff --git a/sites/main/sql/drop/item_info.sql b/sites/main/sql/drop/item_info.sql new file mode 100644 index 0000000..2d34b05 --- /dev/null +++ b/sites/main/sql/drop/item_info.sql @@ -0,0 +1 @@ +DROP TABLE main_item_info CASCADE; \ No newline at end of file diff --git a/sites/main/sql/drop/items.sql b/sites/main/sql/drop/items.sql new file mode 100644 index 0000000..2371e76 --- /dev/null +++ b/sites/main/sql/drop/items.sql @@ -0,0 +1 @@ +DROP TABLE main_items CASCADE; \ No newline at end of file diff --git a/sites/main/sql/drop/linked_items.sql b/sites/main/sql/drop/linked_items.sql new file mode 100644 index 0000000..227c0d2 --- /dev/null +++ b/sites/main/sql/drop/linked_items.sql @@ -0,0 +1 @@ +DROP TABLE main_itemlinks CASCADE; \ No newline at end of file diff --git a/sites/main/sql/drop/locations.sql b/sites/main/sql/drop/locations.sql new file mode 100644 index 0000000..b1a53aa --- /dev/null +++ b/sites/main/sql/drop/locations.sql @@ -0,0 +1 @@ +DROP TABLE main_locations CASCADE; \ No newline at end of file diff --git a/sites/main/sql/drop/logistics_info.sql b/sites/main/sql/drop/logistics_info.sql new file mode 100644 index 0000000..dd3de21 --- /dev/null +++ b/sites/main/sql/drop/logistics_info.sql @@ -0,0 +1 @@ +DROP TABLE main_logistics_info CASCADE; \ No newline at end of file diff --git a/sites/main/sql/drop/transactions.sql b/sites/main/sql/drop/transactions.sql new file mode 100644 index 0000000..6d36751 --- /dev/null +++ b/sites/main/sql/drop/transactions.sql @@ -0,0 +1 @@ +DROP TABLE main_transactions CASCADE; \ No newline at end of file diff --git a/sites/main/sql/drop/zones.sql b/sites/main/sql/drop/zones.sql new file mode 100644 index 0000000..6a616e1 --- /dev/null +++ b/sites/main/sql/drop/zones.sql @@ -0,0 +1 @@ +DROP TABLE main_zones CASCADE; \ No newline at end of file