Asset-side printer save, status CRUD, real printer types, network fix

- Printers save through the asset blueprint (PUT /printers) instead of the
  legacy machines API; restrict supply-model picker to printer models.
- Asset statuses get full CRUD (PUT/DELETE with in-use guard); canonical set.
- Printer types reseeded to a real classification set + list filter.
- Equipment accepts gauge/maintenance references.
- Fix network list emitting network_device instead of networkdevice (View 404).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
cproudlock
2026-06-26 08:35:32 -04:00
parent 4626280dc4
commit 0436e8b0af
8 changed files with 451 additions and 39 deletions

View File

@@ -42,7 +42,7 @@ def seed_cli():
def seed_reference_data():
"""Seed reference data (machine types, statuses, etc.)."""
from shopdb.extensions import db
from shopdb.core.models import MachineType, MachineStatus, OperatingSystem
from shopdb.core.models import MachineType, MachineStatus, OperatingSystem, AssetStatus
from shopdb.core.models.relationship import RelationshipType
# Machine types
@@ -82,6 +82,24 @@ def seed_reference_data():
s = MachineStatus(**s_data)
db.session.add(s)
# Asset statuses (canonical set - the asset model is the contract)
asset_statuses = [
{'status': 'In Use', 'description': 'Currently in use', 'color': '#28a745'},
{'status': 'Inventory', 'description': 'In inventory', 'color': '#17a2b8'},
{'status': 'In Repair', 'description': 'Being repaired', 'color': '#ffc107'},
{'status': 'Retired', 'description': 'No longer in use', 'color': '#6c757d'},
{'status': 'Returned', 'description': 'Returned to vendor or owner', 'color': '#fd7e14'},
{'status': 'Warrantied', 'description': 'Under warranty service', 'color': '#20c997'},
{'status': 'Lost', 'description': 'Lost or missing', 'color': '#dc3545'},
]
for s_data in asset_statuses:
existing = AssetStatus.query.filter_by(status=s_data['status']).first()
if not existing:
db.session.add(AssetStatus(isactive=True, **s_data))
elif existing.isactive is not True:
existing.isactive = True
# Operating systems
os_list = [
{'osname': 'Windows 10', 'osversion': '10.0'},

View File

@@ -53,6 +53,7 @@ class Config:
LOG_LEVEL = os.environ.get('LOG_LEVEL', 'INFO')
ZABBIX_ENABLED = os.environ.get('ZABBIX_ENABLED', 'false').lower() == 'true'
ZABBIX_URL = os.environ.get('ZABBIX_URL', '')
ZABBIX_TOKEN = os.environ.get('ZABBIX_TOKEN', '')

View File

@@ -153,6 +153,56 @@ def create_asset_status():
return success_response(s.to_dict(), message='Asset status created', http_code=201)
@assets_bp.route('/statuses/<int:status_id>', methods=['PUT'])
@jwt_required()
def update_asset_status(status_id: int):
"""Update an asset status."""
s = AssetStatus.query.get(status_id)
if not s:
return error_response(ErrorCodes.NOT_FOUND, 'Asset status not found',
http_code=404)
data = request.get_json() or {}
# Conflict check on rename
if 'status' in data and data['status'] != s.status:
if AssetStatus.query.filter_by(status=data['status']).first():
return error_response(
ErrorCodes.CONFLICT,
f"Asset status '{data['status']}' already exists",
http_code=409
)
for key in ('status', 'description', 'color', 'isactive'):
if key in data:
setattr(s, key, data[key])
db.session.commit()
return success_response(s.to_dict(), message='Asset status updated')
@assets_bp.route('/statuses/<int:status_id>', methods=['DELETE'])
@jwt_required()
def delete_asset_status(status_id: int):
"""Delete an asset status. Refused if any asset still uses it."""
s = AssetStatus.query.get(status_id)
if not s:
return error_response(ErrorCodes.NOT_FOUND, 'Asset status not found',
http_code=404)
inuse = Asset.query.filter_by(statusid=status_id).count()
if inuse:
return error_response(
ErrorCodes.CONFLICT,
f"Cannot delete: {inuse} asset(s) still use this status",
http_code=409
)
db.session.delete(s)
db.session.commit()
return success_response(message='Asset status deleted')
# =============================================================================
# Assets
# =============================================================================

View File

@@ -35,7 +35,7 @@ PLUGIN_TABLE_OWNERS: dict[str, Iterable[str]] = {
'equipment': ('equipmenttypes', 'equipment'),
'network': ('networkdevicetypes', 'networkdevices', 'vlans', 'subnets'),
'notifications': ('notificationtypes', 'notifications'),
'printers': ('printertypes', 'printers', 'printerdata'),
'printers': ('printertypes', 'printers', 'printerdata', 'modelsupplies'),
'usb': ('usbdevicetypes', 'usbdevices', 'usbcheckouts'),
}