feat: add inventory metadata updates

This commit is contained in:
lussierj committed 2026-07-28 19:30:51 +00:00
1 parent 51aec1b404
commit a87ab2709f
11 files changed
+1048 -12

No files matched your search

+87 -4
View File
@@ -13,6 +13,7 @@ from app.inventory.exceptions import (
)
from app.inventory.models import (
InventoryCreateRequest,
InventoryMetadataUpdateRequest,
InventoryMinerDetail,
InventoryMinerSummary,
InventorySearchFilters,
@@ -197,6 +198,85 @@ class InventoryService:
return self._detail_model(row)
def update_metadata(
self,
miner_id: UUID,
request: InventoryMetadataUpdateRequest,
*,
actor_user_id: UUID,
) -> InventoryMinerDetail:
fields_set = request.model_fields_set
if not fields_set:
raise InventoryValidationError(
"At least one metadata field must be provided"
)
requested_asset_id = None
if "asset_id" in fields_set:
if request.asset_id is None:
raise InventoryValidationError("Asset ID cannot be cleared")
requested_asset_id = self.normalize_asset_id(request.asset_id)
requested_values: dict[str, Any] = {}
field_map = {
"miner_sn": "miner_sn",
"psu_serial": "power_sn",
"model": "model",
"notes": "notes",
}
for model_field, database_column in field_map.items():
if model_field in fields_set:
requested_values[database_column] = self._clean_optional_text(
getattr(request, model_field)
)
try:
with self.repository.transaction() as repository:
existing = repository.get_miner_by_id_for_update(miner_id)
if not existing:
raise MinerNotFound(miner_id)
previous_asset_id = (
str(existing.get("asset_tag") or "").strip() or None
)
asset_id_changed = (
requested_asset_id is not None
and requested_asset_id != previous_asset_id
)
values = {
key: value
for key, value in requested_values.items()
if existing.get(key) != value
}
if asset_id_changed:
duplicate = repository.get_miner_by_asset_id(
requested_asset_id
)
if duplicate and duplicate["id"] != miner_id:
raise DuplicateAssetID(requested_asset_id)
values["asset_tag"] = requested_asset_id
if not values:
return self._detail_model(existing)
self._before_update(existing, values)
row = repository.update_miner(miner_id, values)
if asset_id_changed:
repository.add_asset_id_history(
miner_id,
previous_asset_id,
requested_asset_id,
actor_user_id,
)
row = repository.get_miner_by_id(miner_id)
self._after_update(row)
except UniqueViolation as exc:
asset_id = requested_asset_id or "unknown"
raise DuplicateAssetID(asset_id) from exc
return self._detail_model(row)
def update_miner(
self,
miner_id: UUID,
@@ -213,10 +293,13 @@ class InventoryService:
if request.asset_id is None:
raise InventoryValidationError("Asset ID cannot be cleared")
asset_id = self.normalize_asset_id(request.asset_id)
duplicate = self.repository.get_miner_by_asset_id(asset_id)
if duplicate and duplicate["id"] != miner_id:
raise DuplicateAssetID(asset_id)
values["asset_tag"] = asset_id
existing_asset_id = (
str(existing.get("asset_tag") or "").strip() or None
)
if asset_id != existing_asset_id:
raise InventoryValidationError(
"Asset ID changes require actor-attributed metadata update"
)
else:
asset_id = existing["asset_tag"]