From 462c0776818347e93963f02eb5cdad4c895b4042 Mon Sep 17 00:00:00 2001 From: Yaro Kasear Date: Tue, 22 Jul 2025 11:49:47 -0500 Subject: [PATCH] Refactor user, room, and inventory models to replace 'full_name' property with 'identifier' for consistency; update related templates and routes accordingly. --- inventory/models/inventory.py | 4 +- inventory/models/rooms.py | 2 +- inventory/models/users.py | 2 +- inventory/routes/helpers.py | 10 ++-- inventory/routes/index.py | 8 ++-- inventory/routes/inventory.py | 46 +++++++++--------- inventory/routes/user.py | 30 ++++++------ inventory/routes/worklog.py | 32 ++++++------- .../fragments/_dropdown_fragment.html | 47 +++++++++++++++++++ inventory/templates/inventory.html | 4 +- inventory/templates/layout.html | 1 + inventory/templates/user.html | 8 ++-- inventory/templates/worklog.html | 23 ++++----- 13 files changed, 129 insertions(+), 88 deletions(-) create mode 100644 inventory/templates/fragments/_dropdown_fragment.html diff --git a/inventory/models/inventory.py b/inventory/models/inventory.py index e431f44..b77c422 100644 --- a/inventory/models/inventory.py +++ b/inventory/models/inventory.py @@ -74,10 +74,10 @@ class Inventory(db.Model, ImageAttachable): parts.append(f"notes={repr(self.notes)}") if self.owner: - parts.append(f"owner={repr(self.owner.full_name)}") + parts.append(f"owner={repr(self.owner.identifier)}") if self.location: - parts.append(f"location={repr(self.location.full_name)}") + parts.append(f"location={repr(self.location.identifier)}") return f"" diff --git a/inventory/models/rooms.py b/inventory/models/rooms.py index eb06b18..b9ea03b 100644 --- a/inventory/models/rooms.py +++ b/inventory/models/rooms.py @@ -35,7 +35,7 @@ class Room(ValidatableMixin, db.Model): return f"" @property - def full_name(self): + def identifier(self): name = self.name or "" func = self.room_function.description if self.room_function else "" return f"{name} - {func}".strip(" -") diff --git a/inventory/models/users.py b/inventory/models/users.py index 7962b66..a2748c2 100644 --- a/inventory/models/users.py +++ b/inventory/models/users.py @@ -31,7 +31,7 @@ class User(db.Model, ImageAttachable): image: Mapped[Optional['Image']] = relationship('Image', back_populates='user', passive_deletes=True) @property - def full_name(self) -> str: + def identifier(self) -> str: return f"{self.first_name or ''} {self.last_name or ''}".strip() def __init__(self, first_name: Optional[str] = None, last_name: Optional[str] = None, diff --git a/inventory/routes/helpers.py b/inventory/routes/helpers.py index 356d169..cdf2e14 100644 --- a/inventory/routes/helpers.py +++ b/inventory/routes/helpers.py @@ -20,8 +20,8 @@ inventory_headers = { "Model": lambda i: {"text": i.model}, "Item Type": lambda i: {"text": i.item.description} if i.item else {"text": None}, "Shared?": lambda i: {"text": i.shared, "type": "bool", "html": checked_box if i.shared else unchecked_box}, - "Owner": lambda i: {"text": i.owner.full_name, "url": url_for("main.user", id=i.owner.id)} if i.owner else {"text": None}, - "Location": lambda i: {"text": i.location.full_name} if i.location else {"Text": None}, + "Owner": lambda i: {"text": i.owner.identifier, "url": url_for("main.user", id=i.owner.id)} if i.owner else {"text": None}, + "Location": lambda i: {"text": i.location.identifier} if i.location else {"Text": None}, "Condition": lambda i: {"text": i.condition} } @@ -52,14 +52,14 @@ FILTER_MAP = { user_headers = { "Last Name": lambda i: {"text": i.last_name}, "First Name": lambda i: {"text": i.first_name}, - "Supervisor": lambda i: {"text": i.supervisor.full_name, "url": url_for("main.user", id=i.supervisor.id)} if i.supervisor else {"text": None}, - "Location": lambda i: {"text": i.location.full_name} if i.location else {"text": None}, + "Supervisor": lambda i: {"text": i.supervisor.identifier, "url": url_for("main.user", id=i.supervisor.id)} if i.supervisor else {"text": None}, + "Location": lambda i: {"text": i.location.identifier} if i.location else {"text": None}, "Staff?": lambda i: {"text": i.staff, "type": "bool", "html": checked_box if i.staff else unchecked_box}, "Active?": lambda i: {"text": i.active, "type": "bool", "html": checked_box if i.active else unchecked_box} } worklog_headers = { - "Contact": lambda i: {"text": i.contact.full_name, "url": url_for("main.user", id=i.contact.id)} if i.contact else {"Text": None}, + "Contact": lambda i: {"text": i.contact.identifier, "url": url_for("main.user", id=i.contact.id)} if i.contact else {"Text": None}, "Work Item": lambda i: {"text": i.work_item.identifier, "url": url_for('main.inventory_item',id=i.work_item.id)} if i.work_item else {"text": None}, "Start Time": lambda i: {"text": i.start_time.strftime("%Y-%m-%d")}, "End Time": lambda i: {"text": i.end_time.strftime("%Y-%m-%d")} if i.end_time else {"text": None}, diff --git a/inventory/routes/index.py b/inventory/routes/index.py index 0149c85..b53b842 100644 --- a/inventory/routes/index.py +++ b/inventory/routes/index.py @@ -61,10 +61,10 @@ def index(): users = set([log.contact for log in worklog_query if log.contact]) work_summary = {} - for user in sorted(users, key=lambda u: u.full_name): - work_summary[user.full_name] = {} - work_summary[user.full_name]['active_count'] = len([log for log in worklog_query if log.contact == user and not log.complete]) - work_summary[user.full_name]['complete_count'] = len([log for log in worklog_query if log.contact == user and log.complete]) + for user in sorted(users, key=lambda u: u.identifier): + work_summary[user.identifier] = {} + work_summary[user.identifier]['active_count'] = len([log for log in worklog_query if log.contact == user and not log.complete]) + work_summary[user.identifier]['complete_count'] = len([log for log in worklog_query if log.contact == user and log.complete]) datasets['work_summary'] = [{ 'type': 'bar', diff --git a/inventory/routes/inventory.py b/inventory/routes/inventory.py index 0100936..b6552b2 100644 --- a/inventory/routes/inventory.py +++ b/inventory/routes/inventory.py @@ -31,11 +31,11 @@ def list_inventory(): if filter_by == 'user': if not (user := db.session.query(User).filter(User.id == id).first()): return "Invalid User ID", 400 - filter_name = user.full_name + filter_name = user.identifier elif filter_by == 'location': if not (room := db.session.query(Room).filter(Room.id == id).first()): return "Invalid Location ID", 400 - filter_name = room.full_name + filter_name = room.identifier else: if not (item := db.session.query(Item).filter(Item.id == id).first()): return "Invalid Type ID", 400 @@ -49,7 +49,7 @@ def list_inventory(): inventory = sorted(inventory, key=lambda i: i.identifier) return render_template( - 'table.html', + 'table.html', title=f"Inventory Listing ({filter_name})" if filter_by else "Inventory Listing", breadcrumb=[{'label': 'Inventory', 'url': url_for('main.inventory_index')}], header=inventory_headers, @@ -79,11 +79,11 @@ def inventory_index(): listing = chunk_list(types, 12) elif category: return f"Dude, why {category}?" - + return render_template( - 'inventory_index.html', - title=f"Inventory ({category.capitalize()} Index)" if category else "Inventory", - category=category, + 'inventory_index.html', + title=f"Inventory ({category.capitalize()} Index)" if category else "Inventory", + category=category, listing=listing ) @@ -109,14 +109,14 @@ def inventory_item(id): title = f"Inventory Record - {item.identifier}" else: title = "Inventory Record - Not Found" - return render_template('error.html', + return render_template('error.html', title=title, message=f'Inventory item with id {id} not found!', endpoint='inventory_item', endpoint_args={'id': -1}) - return render_template("inventory.html", title=title, item=item, - brands=brands, users=users, rooms=rooms, + return render_template("inventory.html", title=title, item=item, + brands=brands, users=users, rooms=rooms, worklog=worklog, worklog_headers=filtered_worklog_headers, worklog_rows=[{"id": log.id, "cells": [fn(log) for fn in filtered_worklog_headers.values()]} for log in worklog], @@ -147,7 +147,7 @@ def new_inventory_item(): worklog=[], worklog_headers={}, worklog_rows=[] - ) + ) @main.route("/api/inventory", methods=["POST"]) def create_inventory_item(): @@ -160,11 +160,11 @@ def create_inventory_item(): db.session.commit() return jsonify({"success": True, "id": new_item.id}), 201 - + except Exception as e: db.session.rollback() return jsonify({"success": False, "error": str(e)}), 400 - + @main.route("/api/inventory/", methods=["PUT"]) def update_inventory_item(id): try: @@ -194,7 +194,7 @@ def update_inventory_item(id): except Exception as e: db.session.rollback() return jsonify({"success": False, "error": str(e)}), 400 - + @main.route("/api/inventory/", methods=["DELETE"]) def delete_inventory_item(id): try: @@ -202,16 +202,16 @@ def delete_inventory_item(id): if not item: return jsonify({"success": False, "error": f"Item with ID {id} not found"}), 404 - + db.session.delete(item) db.session.commit() return jsonify({"success": True}), 200 - + except Exception as e: db.session.rollback() return jsonify({"success": False, "error": str(e)}), 400 - + @main.route("/api/inventory/export", methods=["POST"]) def get_inventory_csv(): def export_value(item, col): @@ -220,24 +220,24 @@ def get_inventory_csv(): case "brand": return item.brand.name case "location": - return item.location.full_name + return item.location.identifier case "owner": - return item.owner.full_name + return item.owner.identifier case "type": return item.item.description case _: return getattr(item, col, "") except Exception: return "" - + data = request.get_json() ids = data.get('ids', []) if not ids: return jsonify({"success": False, "error": "No IDs provided"}), 400 - + rows = eager_load_inventory_relationships(db.session.query(Inventory).filter(Inventory.id.in_(ids))).all() - + columns = [ "id", "timestamp", @@ -259,7 +259,7 @@ def get_inventory_csv(): @main.route("/inventory_available") def inventory_available(): query = eager_load_inventory_relationships(db.session.query(Inventory).filter(Inventory.condition == "Working")) - + inventory = query.all() inventory = sorted(inventory, key=lambda i: i.identifier) diff --git a/inventory/routes/user.py b/inventory/routes/user.py index 91c2812..6ffff6e 100644 --- a/inventory/routes/user.py +++ b/inventory/routes/user.py @@ -40,9 +40,9 @@ def user(id): .filter(Inventory.owner_id == id) # type: ignore .filter(Inventory.condition.in_(ACTIVE_STATUSES)) ) - + inventory = inventory_query.all() - filtered_inventory_headers = {k: v for k, v in inventory_headers.items() if k not in ['Date Entered', 'Name', 'Serial Number', + filtered_inventory_headers = {k: v for k, v in inventory_headers.items() if k not in ['Date Entered', 'Name', 'Serial Number', 'Bar Code', 'Condition', 'Owner', 'Notes', 'Brand', 'Model', 'Shared?', 'Location']} worklog_query = eager_load_worklog_relationships(db.session.query(WorkLog)).filter(WorkLog.contact_id == id) @@ -50,7 +50,7 @@ def user(id): filtered_worklog_headers = {k: v for k, v in worklog_headers.items() if k not in ['Contact', 'Follow Up?', 'Quick Analysis?']} if user: - title = f"User Record - {user.full_name}" if user.active else f"User Record - {user.full_name} (Inactive)" + title = f"User Record - {user.identifier}" if user.active else f"User Record - {user.identifier} (Inactive)" else: title = f"User Record - User Not Found" return render_template( @@ -60,9 +60,9 @@ def user(id): ) return render_template( - "user.html", - title=title, - user=user, users=users, rooms=rooms, assets=inventory, + "user.html", + title=title, + user=user, users=users, rooms=rooms, assets=inventory, inventory_headers=filtered_inventory_headers, inventory_rows=[{"id": item.id, "cells": [fn(item) for fn in filtered_inventory_headers.values()]} for item in inventory], worklog=worklog, @@ -98,7 +98,7 @@ def create_user(): db.session.commit() return jsonify({"success": True, "id": new_user.id}), 201 - + except Exception as e: db.session.rollback() return jsonify({"success": False, "error": str(e)}), 400 @@ -111,7 +111,7 @@ def update_user(id): if not user: return jsonify({"success": False, "error": f"User with ID {id} not found."}), 404 - + user.staff = bool(data.get("staff", user.staff)) user.active = bool(data.get("active", user.active)) user.last_name = data.get("last_name", user.last_name) @@ -122,33 +122,33 @@ def update_user(id): db.session.commit() return jsonify({"success": True, "id": user.id}), 200 - + except Exception as e: db.session.rollback() return jsonify({"success": False, "error": str(e)}), 400 - + @main.route("/api/user/export", methods=["POST"]) def get_user_csv(): def export_value(user, col): try: match col: case "location": - return user.location.full_name + return user.location.identifier case "supervisor": - return user.supervisor.full_name + return user.supervisor.identifier case _: return getattr(user, col, "") except Exception: return "" - + data = request.get_json() ids = data.get('ids', []) if not ids: return jsonify({"success": False, "error": "No IDs provided"}), 400 - + rows = eager_load_user_relationships(db.session.query(User).filter(User.id.in_(ids))).all() - + columns = [ "id", "staff", diff --git a/inventory/routes/worklog.py b/inventory/routes/worklog.py index 57798d5..6327c41 100644 --- a/inventory/routes/worklog.py +++ b/inventory/routes/worklog.py @@ -13,7 +13,7 @@ from ..utils.load import eager_load_worklog_relationships, eager_load_user_relat @main.route("/worklog") def list_worklog(): - query = eager_load_worklog_relationships(db.session.query(WorkLog)) + query = eager_load_worklog_relationships(db.session.query(WorkLog)) return render_template( 'table.html', header=worklog_headers, @@ -48,10 +48,10 @@ def worklog_entry(id): ) return render_template( - "worklog.html", - title=title, - log=log, - users=users, + "worklog.html", + title=title, + log=log, + users=users, items=items ) @@ -86,7 +86,7 @@ def create_worklog(): db.session.commit() return jsonify({"success": True, "id": new_worklog.id}), 201 - + except Exception as e: db.session.rollback() return jsonify({"success": False, "error": str(e)}), 400 @@ -110,7 +110,7 @@ def update_worklog(id): existing = {str(note.id): note for note in log.updates} incoming = data.get("updates", []) new_updates = [] - + for note_data in incoming: if isinstance(note_data, dict): if "id" in note_data and str(note_data["id"]) in existing: @@ -119,13 +119,13 @@ def update_worklog(id): new_updates.append(note) elif "content" in note_data: new_updates.append(WorkNote(content=note_data["content"])) - + log.updates[:] = new_updates # This replaces in-place db.session.commit() return jsonify({"success": True, "id": log.id}), 200 - + except Exception as e: db.session.rollback() return jsonify({"success": False, "error": str(e)}), 400 @@ -137,23 +137,23 @@ def delete_worklog(id): if not log: return jsonify({"success": False, "errpr": f"Item with ID {id} not found!"}), 404 - + db.session.delete(log) db.session.commit() return jsonify({"success": True}), 200 - + except Exception as e: db.session.rollback() return jsonify({"success": False, "error": str(e)}), 400 - + @main.route("/api/worklog/export", methods=["POST"]) def get_worklog_csv(): def export_value(log, col): try: match col: case "contact": - return log.contact.full_name + return log.contact.identifier case "work_item": return log.work_item.identifier case "latest_update": @@ -164,15 +164,15 @@ def get_worklog_csv(): return getattr(log, col, "") except Exception: return "" - + data = request.get_json() ids = data.get('ids', []) if not ids: return jsonify({"success": False, "error": "No IDs provided"}), 400 - + rows = eager_load_worklog_relationships(db.session.query(WorkLog).filter(WorkLog.id.in_(ids))).all() - + columns = [ "id", "start_time", diff --git a/inventory/templates/fragments/_dropdown_fragment.html b/inventory/templates/fragments/_dropdown_fragment.html new file mode 100644 index 0000000..22590df --- /dev/null +++ b/inventory/templates/fragments/_dropdown_fragment.html @@ -0,0 +1,47 @@ +{% macro render_dropdown(id, list, label, current_item = None, entry_link = None) %} + + + +{% endmacro %} \ No newline at end of file diff --git a/inventory/templates/inventory.html b/inventory/templates/inventory.html index bd2ca3d..aec53ea 100644 --- a/inventory/templates/inventory.html +++ b/inventory/templates/inventory.html @@ -209,7 +209,7 @@ {% for user in users %} {% endfor %} @@ -221,7 +221,7 @@ {% for room in rooms %} + room.identifier }} {% endfor %} diff --git a/inventory/templates/layout.html b/inventory/templates/layout.html index 6b01a75..f4b911f 100644 --- a/inventory/templates/layout.html +++ b/inventory/templates/layout.html @@ -1,6 +1,7 @@ {% import "fragments/_button_fragment.html" as buttons %} {% import "fragments/_breadcrumb_fragment.html" as breadcrumbs %} {% import "fragments/_combobox_fragment.html" as combos %} +{% import "fragments/_dropdown_fragment.html" as dropdowns %} {% import "fragments/_editor_fragment.html" as editor %} {% import "fragments/_icon_fragment.html" as icons %} {% import "fragments/_image_fragment.html" as images %} diff --git a/inventory/templates/user.html b/inventory/templates/user.html index 29cdeb4..568824a 100644 --- a/inventory/templates/user.html +++ b/inventory/templates/user.html @@ -108,7 +108,7 @@ {% for supervisor in users %} + {{ supervisor.identifier }} {% endfor %} @@ -119,7 +119,7 @@ {% for location in rooms %} + location.identifier }} {% endfor %} @@ -142,7 +142,7 @@ {% set inventory_title %} Assets {{ links.export_link( - (user.full_name | lower | replace(' ', '_')) + '_user_inventory', + (user.identifier | lower | replace(' ', '_')) + '_user_inventory', 'inventory', {'ids': id_list} ) }} @@ -157,7 +157,7 @@ {% set worklog_title %} Work Done {{ links.export_link( - (user.full_name | lower | replace(' ', '_')) + '_user_worklog', + (user.identifier | lower | replace(' ', '_')) + '_user_worklog', 'worklog', {'ids': id_list} ) }} diff --git a/inventory/templates/worklog.html b/inventory/templates/worklog.html index 92ab0b9..5c20330 100644 --- a/inventory/templates/worklog.html +++ b/inventory/templates/worklog.html @@ -24,7 +24,7 @@ analysis: document.querySelector("input[name='analysis']").checked, followup: document.querySelector("input[name='followup']").checked, contact_id: parseInt(document.querySelector("select[name='contact']").value) || null, - work_item_id: parseInt(document.querySelector("select[name='item']").value) || null, + work_item_id: parseInt(document.querySelector("input[name='item']").value) || null, updates: updates }; @@ -163,25 +163,18 @@ {% for contact in users %} {% endfor %}
- - + {{ dropdowns.render_dropdown( + id='item', + list=items, + label='Work Item', + current_item=log.work_item + ) }}