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 @@ - +