Refactor brand and item models to introduce 'identifier' property for consistency; update dropdown rendering in templates to utilize new properties and improve input handling.

This commit is contained in:
Yaro Kasear 2025-07-22 13:04:31 -05:00
parent 8631e4082c
commit 9242ce6eab
5 changed files with 52 additions and 58 deletions

View file

@ -23,13 +23,13 @@ class Brand(ValidatableMixin, db.Model):
def __repr__(self):
return f"<Brand(id={self.id}, name={repr(self.name)})>"
def serialize(self):
return {
'id': self.id,
'name': self.name
}
@classmethod
def sync_from_state(cls, submitted_items: list[dict]) -> dict[str, int]:
submitted_clean = []
@ -93,7 +93,7 @@ class Brand(ValidatableMixin, db.Model):
if not isinstance(item, dict):
errors.append(f"Area entry #{index + 1} is not a valid object.")
continue
name = item.get('name')
if not name or not str(name).strip():
errors.append(f"Area entry #{index + 1} is missing a name.")
@ -107,3 +107,7 @@ class Brand(ValidatableMixin, db.Model):
errors.append(f"Area entry #{index + 1} has invalid ID: {raw_id}")
return errors
@property
def identifier(self) -> str:
return self.name if self.name else f"ID: {self.id}"

View file

@ -42,6 +42,7 @@ class Inventory(db.Model, ImageAttachable):
item: Mapped['Item'] = relationship('Item', back_populates='inventory')
work_logs: Mapped[List['WorkLog']] = relationship('WorkLog', back_populates='work_item')
image: Mapped[Optional['Image']] = relationship('Image', back_populates='inventory', passive_deletes=True)
type: Mapped[Optional['Item']] = relationship('Item', back_populates='inventory')
def __init__(self, timestamp: datetime.datetime, condition: str, type_id: Optional[int] = None,
name: Optional[str] = None, serial: Optional[str] = None,

View file

@ -1,6 +1,6 @@
from typing import List, Optional, TYPE_CHECKING
if TYPE_CHECKING:
from .inventory import Inventory
from .inventory import Inventory
from sqlalchemy import Identity, Integer, Unicode
from sqlalchemy.orm import Mapped, mapped_column, relationship
@ -20,18 +20,21 @@ class Item(ValidatableMixin, db.Model):
def __init__(self, description: Optional[str] = None, category: Optional[str] = None):
self.description = description
self.category = category
def __repr__(self):
return f"<Item(id={self.id}, description={repr(self.description)}, category={repr(self.category)})>"
return f"<Item(id={self.id}, description={repr(self.description)})>"
def serialize(self):
return {
'id': self.id,
'name': self.description,
'category': self.category
}
@property
def identifier(self):
return self.description if self.description else f"Item {self.id}"
@classmethod
def sync_from_state(cls, submitted_items: list[dict]) -> dict[str, int]:
submitted_clean = []
@ -84,7 +87,7 @@ class Item(ValidatableMixin, db.Model):
**{str(temp): real for temp, real in temp_id_map.items()}
}
return id_map
@classmethod
def validate_state(cls, submitted_items: list[dict]) -> list[str]:
errors = []
@ -93,7 +96,7 @@ class Item(ValidatableMixin, db.Model):
if not isinstance(item, dict):
errors.append(f"Area entry #{index + 1} is not a valid object.")
continue
name = item.get('name')
if not name or not str(name).strip():
errors.append(f"Area entry #{index + 1} is missing a name.")

View file

@ -10,7 +10,7 @@
<div class="dropdown">
<button class="btn btn-outline-dark dropdown-toggle w-100" type="button" data-bs-toggle="dropdown"
data-inv-value="{{ current_item.id if current_item else '' }}" id="{{ id }}Button"{% if not enabled %} disabled{% endif %}
style="border-color: rgb(222, 226, 230);{% if not enabled %}background-color: rgb(233, 236, 239); color: rgb(0, 0, 0);{% endif %}">
style="border-color: rgb(222, 226, 230);{% if not enabled %} background-color: rgb(233, 236, 239); color: rgb(0, 0, 0);{% endif %}">
{{ current_item.identifier if current_item else '-' }}
</button>
<input type="hidden" name="{{ id }}" id="{{ id }}" value="{{ current_item.id if current_item else '' }}">

View file

@ -10,14 +10,14 @@
const payload = {
timestamp: document.querySelector("input[name='timestamp']").value,
condition: document.querySelector("select[name='condition']").value,
type_id: parseInt(document.querySelector("select[name='type']").value),
type_id: parseInt(document.querySelector("input[name='type']").value),
name: document.querySelector("input[name='name']").value || null,
serial: document.querySelector("input[name='serial']").value || null,
model: document.querySelector("input[name='model']").value || null,
notes: document.querySelector("textarea[name='editornotes']").value || null,
owner_id: parseInt(document.querySelector("select#userList").value) || null,
brand_id: parseInt(document.querySelector("select[name='brand']").value) || null,
location_id: parseInt(document.querySelector("select#room").value) || null,
owner_id: parseInt(document.querySelector("input[name='owner']").value) || null,
brand_id: parseInt(document.querySelector("input[name='brand']").value) || null,
location_id: parseInt(document.querySelector("input[name='room']").value) || null,
barcode: document.querySelector("input[name='barcode']").value || null,
shared: document.querySelector("input[name='shared']").checked
};
@ -167,16 +167,13 @@
</div>
<div class="row">
<div class="col-4">
<label for="brand" class="form-label">Brand</label>
<select class="form-select" id="brand" name="brand" {% if item.condition in ["Removed", "Disposed" ]
%} disabled{% endif %}>
<option>-</option>
{% for brand in brands %}
<option value="{{ brand.id }}" {% if brand.id==item.brand_id %} selected{% endif %}>{{
brand.name }}
</option>
{% endfor %}
</select>
{{ dropdowns.render_dropdown(
id='brand',
list=brands,
label='Brand',
current_item=item.brand,
enabled=item.condition not in ["Removed", "Disposed"]
) }}
</div>
<div class="col-4">
<label for="model" class="form-label">Model</label>
@ -185,45 +182,34 @@
%} disabled{% endif %}>
</div>
<div class="col-4">
<label for="type" class="form-label">Category</label>
<select name="type" id="type" class="form-select" {% if item.condition in ["Removed", "Disposed" ]
%} disabled{% endif %}>
<option>-</option>
{% for t in types %}
<option value="{{ t.id }}" {% if t.id==item.type_id %} selected{% endif %}>{{ t.description }}
</option>
{% endfor %}
</select>
{{ dropdowns.render_dropdown(
id='type',
list=types,
label='Category',
current_item=item.type,
enabled=item.condition not in ["Removed", "Disposed"]
) }}
</div>
</div>
<div class="row">
<div class="col-4">
<label for="owner" class="form-label">
Contact
{% if item.owner %}
{{ links.entry_link('user', item.owner_id) }}
{% endif %}
</label>
<select class="form-select" id="userList" {% if item.condition in ["Removed", "Disposed" ] %}
disabled{% endif %}>
<option>-</option>
{% for user in users %}
<option value="{{ user.id }}" {% if user.id==item.owner_id %} selected{% endif %}>{{
user.identifier
}}</option>
{% endfor %}
</select>
{{ dropdowns.render_dropdown(
id='owner',
list=users,
label='Contact',
current_item=item.owner,
entry_link='user',
enabled=item.condition not in ["Removed", "Disposed"]
) }}
</div>
<div class="col-4">
<label for="location" class="form-label">Location</label>
<select class="form-select" id="room" {% if item.condition in ["Removed", "Disposed" ] %} disabled{%
endif %}>
<option>-</option>
{% for room in rooms %}
<option value="{{ room.id }}" {% if room.id==item.location_id %} selected{% endif %}>{{
room.identifier }}</option>
{% endfor %}
</select>
{{ dropdowns.render_dropdown(
id='room',
list=rooms,
label='Location',
current_item=item.location,
enabled=item.condition not in ["Removed", "Disposed"]
) }}
</div>
<div class="col-2">
<label for="condition" class="form-label">Condition</label>