diff --git a/application/controllers/AssetController.php b/application/controllers/AssetController.php
index 0c8ddd9..764eda9 100644
--- a/application/controllers/AssetController.php
+++ b/application/controllers/AssetController.php
@@ -340,6 +340,59 @@ class AssetController extends BaseController
$this->jsonSuccess(['id' => $id, 'voce_code' => $voce, 'label' => $label], 'Sottoclasse aggiunta', 201);
}
+ /**
+ * PUT /api/assets/subclasses/{id} { label* }
+ * Rinomina una sottoclasse ORGANIZZATIVA dell'org corrente. Le sottoclassi di
+ * sistema (organization_id NULL) NON sono modificabili dall'utente.
+ */
+ public function updateSubclass(int $id): void
+ {
+ $this->requireOrgRole(['org_admin', 'compliance_manager']);
+ $body = $this->getJsonBody();
+ $label = trim((string) ($body['label'] ?? ''));
+ if ($label === '' || mb_strlen($label) > 120) {
+ $this->jsonError('Etichetta sottoclasse obbligatoria (max 120 caratteri)', 422, 'INVALID_LABEL');
+ }
+ $orgId = $this->getCurrentOrgId();
+ $row = Database::fetchOne(
+ 'SELECT id, voce_code FROM inventory_subclassi WHERE id = ? AND organization_id = ?',
+ [$id, $orgId]
+ );
+ if (!$row) {
+ $this->jsonError('Sottoclasse non trovata o non modificabile (le voci di sistema non si modificano)', 404, 'SUBCLASS_NOT_FOUND');
+ }
+ $dup = Database::fetchOne(
+ 'SELECT id FROM inventory_subclassi WHERE voce_code = ? AND label = ? AND (organization_id = ? OR organization_id IS NULL) AND id <> ?',
+ [$row['voce_code'], $label, $orgId, $id]
+ );
+ if ($dup) { $this->jsonError('Sottoclasse già esistente', 409, 'DUPLICATE'); }
+ Database::update('inventory_subclassi', ['label' => $label], 'id = ? AND organization_id = ?', [$id, $orgId]);
+ $this->jsonSuccess(['id' => $id, 'label' => $label], 'Sottoclasse aggiornata');
+ }
+
+ /**
+ * DELETE /api/assets/subclasses/{id}
+ * Rimuove una sottoclasse ORGANIZZATIVA dell'org corrente. Gli asset che la
+ * usano restano senza sottoclasse (FK ON DELETE SET NULL su assets.subclass_id).
+ * Le sottoclassi di sistema (organization_id NULL) NON sono eliminabili.
+ */
+ public function deleteSubclass(int $id): void
+ {
+ $this->requireOrgRole(['org_admin', 'compliance_manager']);
+ $orgId = $this->getCurrentOrgId();
+ $row = Database::fetchOne(
+ 'SELECT id FROM inventory_subclassi WHERE id = ? AND organization_id = ?',
+ [$id, $orgId]
+ );
+ if (!$row) {
+ $this->jsonError('Sottoclasse non trovata o non eliminabile (le voci di sistema non si rimuovono)', 404, 'SUBCLASS_NOT_FOUND');
+ }
+ $used = Database::fetchOne('SELECT COUNT(*) AS c FROM assets WHERE subclass_id = ?', [$id]);
+ $usedCount = (int) ($used['c'] ?? 0);
+ Database::delete('inventory_subclassi', 'id = ? AND organization_id = ?', [$id, $orgId]);
+ $this->jsonSuccess(['id' => $id, 'unlinked_assets' => $usedCount], 'Sottoclasse rimossa');
+ }
+
public function delete(int $id): void
{
$this->requireOrgRole(['org_admin']);
diff --git a/public/assets.html b/public/assets.html
index 9f9db7b..1c3deaa 100644
--- a/public/assets.html
+++ b/public/assets.html
@@ -361,7 +361,7 @@
-
+