From 70dff6a7a52ddb0e7579305c83a2adb5e7f670ee Mon Sep 17 00:00:00 2001 From: Manuel Aranda Date: Tue, 23 Sep 2025 08:35:12 +0200 Subject: [PATCH 1/2] refs #2693. Updated backend --- migrations/Version20241217000001.php | 1 + migrations/Version20250917113636.php | 31 +++ migrations/Version20250917114148.php | 31 +++ migrations/Version20250918065132.php | 45 ++++ src/Command/LoadHardwareTypesCommand.php | 76 ++++++ .../OgAgent/HardwareInventoryAction.php | 216 +++++++++++++++++- src/Dto/Input/HardwareProfileInput.php | 14 +- src/Dto/Output/ClientOutput.php | 12 +- src/Dto/Output/HardwareProfileOutput.php | 8 +- src/Dto/Output/HardwareTypeOutput.php | 12 + src/Entity/Client.php | 2 +- src/Entity/HardwareProfile.php | 49 +--- src/Entity/HardwareType.php | 30 +++ 13 files changed, 457 insertions(+), 70 deletions(-) create mode 100644 migrations/Version20241217000001.php create mode 100644 migrations/Version20250917113636.php create mode 100644 migrations/Version20250917114148.php create mode 100644 migrations/Version20250918065132.php create mode 100644 src/Command/LoadHardwareTypesCommand.php diff --git a/migrations/Version20241217000001.php b/migrations/Version20241217000001.php new file mode 100644 index 0000000..0519ecb --- /dev/null +++ b/migrations/Version20241217000001.php @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/migrations/Version20250917113636.php b/migrations/Version20250917113636.php new file mode 100644 index 0000000..50334ee --- /dev/null +++ b/migrations/Version20250917113636.php @@ -0,0 +1,31 @@ +addSql('ALTER TABLE hardware_type ADD description VARCHAR(255) DEFAULT NULL'); + } + + public function down(Schema $schema): void + { + // this down() migration is auto-generated, please modify it to your needs + $this->addSql('ALTER TABLE hardware_type DROP description'); + } +} diff --git a/migrations/Version20250917114148.php b/migrations/Version20250917114148.php new file mode 100644 index 0000000..d9e32d6 --- /dev/null +++ b/migrations/Version20250917114148.php @@ -0,0 +1,31 @@ +addSql('ALTER TABLE hardware_type ADD code VARCHAR(10) DEFAULT NULL'); + } + + public function down(Schema $schema): void + { + // this down() migration is auto-generated, please modify it to your needs + $this->addSql('ALTER TABLE hardware_type DROP code'); + } +} diff --git a/migrations/Version20250918065132.php b/migrations/Version20250918065132.php new file mode 100644 index 0000000..99f990e --- /dev/null +++ b/migrations/Version20250918065132.php @@ -0,0 +1,45 @@ +addSql('ALTER TABLE client DROP FOREIGN KEY FK_C7440455CFA495C1'); + $this->addSql('DROP INDEX IDX_C7440455CFA495C1 ON client'); + $this->addSql('ALTER TABLE client DROP hardware_profile_id'); + $this->addSql('ALTER TABLE hardware_profile DROP FOREIGN KEY FK_2D9A2460FB84408A'); + $this->addSql('DROP INDEX IDX_2D9A2460FB84408A ON hardware_profile'); + $this->addSql('ALTER TABLE hardware_profile CHANGE organizational_unit_id client_id INT NOT NULL'); + $this->addSql('ALTER TABLE hardware_profile ADD CONSTRAINT FK_2D9A246019EB6921 FOREIGN KEY (client_id) REFERENCES client (id)'); + $this->addSql('CREATE INDEX IDX_2D9A246019EB6921 ON hardware_profile (client_id)'); + } + + public function down(Schema $schema): void + { + // this down() migration is auto-generated, please modify it to your needs + $this->addSql('ALTER TABLE hardware_profile DROP FOREIGN KEY FK_2D9A246019EB6921'); + $this->addSql('DROP INDEX IDX_2D9A246019EB6921 ON hardware_profile'); + $this->addSql('ALTER TABLE hardware_profile CHANGE client_id organizational_unit_id INT NOT NULL'); + $this->addSql('ALTER TABLE hardware_profile ADD CONSTRAINT FK_2D9A2460FB84408A FOREIGN KEY (organizational_unit_id) REFERENCES organizational_unit (id)'); + $this->addSql('CREATE INDEX IDX_2D9A2460FB84408A ON hardware_profile (organizational_unit_id)'); + $this->addSql('ALTER TABLE client ADD hardware_profile_id INT DEFAULT NULL'); + $this->addSql('ALTER TABLE client ADD CONSTRAINT FK_C7440455CFA495C1 FOREIGN KEY (hardware_profile_id) REFERENCES hardware_profile (id)'); + $this->addSql('CREATE INDEX IDX_C7440455CFA495C1 ON client (hardware_profile_id)'); + } +} diff --git a/src/Command/LoadHardwareTypesCommand.php b/src/Command/LoadHardwareTypesCommand.php new file mode 100644 index 0000000..c0285f5 --- /dev/null +++ b/src/Command/LoadHardwareTypesCommand.php @@ -0,0 +1,76 @@ + 'boo', 'name' => 'BIOS', 'description' => 'Sistema básico de entrada/salida'], + ['code' => 'mod', 'name' => 'Motherboard', 'description' => 'Placa base del sistema'], + ['code' => 'boa', 'name' => 'Board', 'description' => 'Placa base o tarjeta madre'], + ['code' => 'cpu', 'name' => 'CPU', 'description' => 'Procesador central'], + ['code' => 'mem', 'name' => 'Memory', 'description' => 'Memoria RAM'], + ['code' => 'ide', 'name' => 'IDE Controller', 'description' => 'Controlador IDE'], + ['code' => 'vga', 'name' => 'Graphics Card', 'description' => 'Tarjeta gráfica'], + ['code' => 'dis', 'name' => 'Disk', 'description' => 'Disco de almacenamiento'], + ['code' => 'usb', 'name' => 'USB Controller', 'description' => 'Controlador USB'], + ['code' => 'cdr', 'name' => 'CD/DVD', 'description' => 'Unidad de CD/DVD'], + ['code' => 'net', 'name' => 'Network Card', 'description' => 'Tarjeta de red'], + ]; + + $repository = $this->entityManager->getRepository(HardwareType::class); + $created = 0; + $updated = 0; + + foreach ($hardwareTypes as $typeData) { + // Buscar por nombre primero + $hardwareType = $repository->findOneBy(['name' => $typeData['name']]); + + if (!$hardwareType) { + $hardwareType = new HardwareType(); + $hardwareType->setName($typeData['name']); + $created++; + $io->writeln(sprintf('Creando tipo: %s (%s)', $typeData['name'], $typeData['code'])); + } else { + $updated++; + $io->writeln(sprintf('Actualizando tipo: %s (%s)', $typeData['name'], $typeData['code'])); + } + + $hardwareType->setDescription($typeData['description']); + $hardwareType->setCode($typeData['code']); + $this->entityManager->persist($hardwareType); + } + + $this->entityManager->flush(); + + $io->success(sprintf( + 'Tipos de hardware cargados exitosamente. Creados: %d, Actualizados: %d', + $created, + $updated + )); + + return Command::SUCCESS; + } +} \ No newline at end of file diff --git a/src/Controller/OgAgent/HardwareInventoryAction.php b/src/Controller/OgAgent/HardwareInventoryAction.php index 3c6792d..fb95c52 100644 --- a/src/Controller/OgAgent/HardwareInventoryAction.php +++ b/src/Controller/OgAgent/HardwareInventoryAction.php @@ -3,6 +3,9 @@ namespace App\Controller\OgAgent; use App\Entity\Client; +use App\Entity\Hardware; +use App\Entity\HardwareProfile; +use App\Entity\HardwareType; use App\Model\CommandTypes; use App\Model\TraceStatus; use Symfony\Component\HttpFoundation\JsonResponse; @@ -42,16 +45,221 @@ class HardwareInventoryAction extends AbstractOgAgentController throw new BadRequestHttpException('Error performing hardware inventory: '.$response['error']); } - $this->logger->info('Login client', ['client' => $client->getId()]); + $responseData = $response; + + if (isset($responseData['res']) && $responseData['res'] === 2) { + throw new BadRequestHttpException('Error en el inventario de hardware: operación fallida'); + } - $jobId = $response['job_id']; + $this->logger->info('Hardware inventory for client', ['client' => $client->getId()]); $inputData = [ 'client' => $client->getIp(), ]; - $this->createService->__invoke($client, CommandTypes::HARDWARE_INVENTORY, TraceStatus::IN_PROGRESS, $jobId, $inputData); + $this->createService->__invoke($client, CommandTypes::HARDWARE_INVENTORY, TraceStatus::SUCCESS, null, $inputData); - return new JsonResponse(data: [], status: Response::HTTP_OK); + if (isset($responseData['res']) && $responseData['res'] === 1) { + $this->processHardwareInventory($client, $responseData); + + return new JsonResponse(data: $responseData, status: Response::HTTP_OK); + } + + return new JsonResponse(data: $response, status: Response::HTTP_OK); + } + + private function processHardwareInventory(Client $client, array $responseData): void + { + if (!isset($responseData['hrd'])) { + $this->logger->warning('No hay datos de hardware en la respuesta', ['client' => $client->getId()]); + return; + } + + $this->logger->info('Iniciando procesamiento de inventario de hardware', ['client' => $client->getId()]); + + $hardwareData = base64_decode($responseData['hrd']); + + if ($hardwareData === false) { + $this->logger->error('Error decodificando datos de hardware base64', ['client' => $client->getId()]); + return; + } + + $this->logger->debug('Datos de hardware decodificados', [ + 'client' => $client->getId(), + 'data_length' => strlen($hardwareData) + ]); + + $hardwareLines = explode("\n", $hardwareData); + $this->logger->info('Líneas de hardware encontradas', [ + 'client' => $client->getId(), + 'total_lines' => count($hardwareLines) + ]); + + $hardwareRepository = $this->entityManager->getRepository(Hardware::class); + $hardwareTypeRepository = $this->entityManager->getRepository(HardwareType::class); + + $hardwareItems = []; + $processedLines = 0; + $createdHardware = 0; + + foreach ($hardwareLines as $line) { + $line = trim($line); + if (empty($line)) { + continue; + } + + $parts = explode('=', $line, 2); + if (count($parts) !== 2) { + $this->logger->debug('Línea de hardware ignorada (formato incorrecto)', [ + 'client' => $client->getId(), + 'line' => $line + ]); + continue; + } + + $typeCode = trim($parts[0]); + $description = trim($parts[1]); + + if (empty($typeCode) || empty($description)) { + $this->logger->debug('Línea de hardware ignorada (datos vacíos)', [ + 'client' => $client->getId(), + 'line' => $line + ]); + continue; + } + + $hardwareType = $this->getOrCreateHardwareType($typeCode, $hardwareTypeRepository); + + if ($hardwareType->getId() === null) { + $this->logger->debug('Nuevo tipo de hardware creado', [ + 'client' => $client->getId(), + 'type_name' => $hardwareType->getName(), + 'type_code' => $typeCode + ]); + } + + $hardware = $hardwareRepository->findOneBy([ + 'name' => $description, + 'type' => $hardwareType + ]); + + if (!$hardware) { + $hardware = new Hardware(); + $hardware->setName($description); + $hardware->setDescription($description); + $hardware->setType($hardwareType); + $this->entityManager->persist($hardware); + $createdHardware++; + $this->logger->debug('Nuevo hardware creado', [ + 'client' => $client->getId(), + 'hardware_name' => $description, + 'hardware_type' => $hardwareType->getName() + ]); + } + + $hardwareItems[] = $hardware; + $processedLines++; + } + + $this->logger->info('Procesamiento de líneas de hardware completado', [ + 'client' => $client->getId() + ]); + + $hardwareProfile = $client->getHardwareProfile(); + $isNewProfile = false; + + if (!$hardwareProfile) { + $hardwareProfile = new HardwareProfile(); + $hardwareProfile->setDescription('Perfil de hardware generado automáticamente para ' . $client->getIp()); + $hardwareProfile->setClient($client); + $this->entityManager->persist($hardwareProfile); + $isNewProfile = true; + + $this->logger->info('Nuevo perfil de hardware creado', [ + 'client' => $client->getId(), + 'client_ip' => $client->getIp() + ]); + + $client->setHardwareProfile($hardwareProfile); + } else { + $this->logger->info('Actualizando perfil de hardware existente', [ + 'client' => $client->getId(), + 'profile_id' => $hardwareProfile->getId() + ]); + } + + foreach ($hardwareItems as $hardware) { + $hardwareProfile->addHardwareCollection($hardware); + } + + $this->logger->debug('Nuevo hardware añadido al perfil', [ + 'client' => $client->getId(), + 'added_hardware_count' => count($hardwareItems) + ]); + + $client->setHardwareProfile($hardwareProfile); + $this->entityManager->persist($client); + + $this->entityManager->flush(); + + $this->logger->info('Inventario de hardware guardado exitosamente', [ + 'client' => $client->getId(), + 'profile_id' => $hardwareProfile->getId(), + 'is_new_profile' => $isNewProfile, + 'total_hardware_items' => count($hardwareItems) + ]); + } + + private function getOrCreateHardwareType(string $typeCode, $hardwareTypeRepository): HardwareType + { + $hardwareTypeMapping = [ + 'boo' => 'BIOS', + 'mod' => 'Motherboard', + 'boa' => 'Board', + 'cpu' => 'CPU', + 'mem' => 'Memory', + 'ide' => 'IDE Controller', + 'vga' => 'Graphics Card', + 'dis' => 'Disk', + 'usb' => 'USB Controller', + 'cdr' => 'CD/DVD', + 'net' => 'Network Card' + ]; + + $hardwareType = $hardwareTypeRepository->findOneBy(['code' => $typeCode]); + + if (!$hardwareType) { + $typeName = $hardwareTypeMapping[$typeCode] ?? strtoupper($typeCode); + $hardwareType = $hardwareTypeRepository->findOneBy(['name' => $typeName]); + } + + if (!$hardwareType) { + $typeName = $hardwareTypeMapping[$typeCode] ?? strtoupper($typeCode); + $hardwareType = new HardwareType(); + $hardwareType->setName($typeName); + $hardwareType->setCode($typeCode); + + if (isset($hardwareTypeMapping[$typeCode])) { + $descriptions = [ + 'boo' => 'Sistema básico de entrada/salida', + 'mod' => 'Placa base del sistema', + 'boa' => 'Placa base o tarjeta madre', + 'cpu' => 'Procesador central', + 'mem' => 'Memoria RAM', + 'ide' => 'Controlador IDE', + 'vga' => 'Tarjeta gráfica', + 'dis' => 'Disco de almacenamiento', + 'usb' => 'Controlador USB', + 'cdr' => 'Unidad de CD/DVD', + 'net' => 'Tarjeta de red' + ]; + + $hardwareType->setDescription($descriptions[$typeCode] ?? null); + } + + $this->entityManager->persist($hardwareType); + } + + return $hardwareType; } } \ No newline at end of file diff --git a/src/Dto/Input/HardwareProfileInput.php b/src/Dto/Input/HardwareProfileInput.php index e44990e..c162328 100644 --- a/src/Dto/Input/HardwareProfileInput.php +++ b/src/Dto/Input/HardwareProfileInput.php @@ -3,9 +3,9 @@ namespace App\Dto\Input; use ApiPlatform\Metadata\ApiProperty; -use App\Dto\Output\OrganizationalUnitOutput; use App\Entity\HardwareProfile; use Symfony\Component\Serializer\Annotation\Groups; +use App\Dto\Output\ClientOutput; final class HardwareProfileInput { @@ -18,8 +18,8 @@ final class HardwareProfileInput public ?string $comments = null; #[Groups(['hardware-profile:write'])] - #[ApiProperty(description: 'The organizational unit of the hardware profile')] - public ?OrganizationalUnitOutput $organizationalUnit = null; + #[ApiProperty(description: 'The client of the hardware profile', readableLink: true)] + public ?ClientOutput $client = null; public function __construct(?HardwareProfile $hardwareProfile = null) { @@ -29,9 +29,7 @@ final class HardwareProfileInput $this->description = $hardwareProfile->getDescription(); $this->comments = $hardwareProfile->getComments(); - if($hardwareProfile->getOrganizationalUnit()) { - $this->organizationalUnit = new OrganizationalUnitOutput($hardwareProfile->getOrganizationalUnit()); - } + $this->client = new ClientOutput($hardwareProfile->getClient()); } public function createOrUpdateEntity(?HardwareProfile $hardwareProfile = null): HardwareProfile @@ -42,9 +40,7 @@ final class HardwareProfileInput $hardwareProfile->setDescription($this->description); $hardwareProfile->setComments($this->comments); - if ($this->organizationalUnit) { - $hardwareProfile->setOrganizationalUnit($this->organizationalUnit->getEntity()); - } + $hardwareProfile->setClient($this->client->getEntity()); return $hardwareProfile; } diff --git a/src/Dto/Output/ClientOutput.php b/src/Dto/Output/ClientOutput.php index 8e600d7..bc7ca50 100644 --- a/src/Dto/Output/ClientOutput.php +++ b/src/Dto/Output/ClientOutput.php @@ -13,16 +13,16 @@ final class ClientOutput extends AbstractOutput { CONST string TYPE = 'client'; - #[Groups(['client:read', 'organizational-unit:read', 'pxe-template:read', 'trace:read', 'subnet:read'])] + #[Groups(['client:read', 'organizational-unit:read', 'pxe-template:read', 'trace:read', 'subnet:read', 'hardware-profile:read'])] public string $name; #[Groups(['client:read', 'organizational-unit:read'])] public string $type = self::TYPE; - #[Groups(['client:read', 'organizational-unit:read', 'pxe-template:read', 'trace:read', 'subnet:read'])] + #[Groups(['client:read', 'organizational-unit:read', 'pxe-template:read', 'trace:read', 'subnet:read', 'hardware-profile:read'])] public ?string $ip = ''; - #[Groups(['client:read', 'organizational-unit:read', 'pxe-template:read', 'trace:read', 'subnet:read'])] + #[Groups(['client:read', 'organizational-unit:read', 'pxe-template:read', 'trace:read', 'subnet:read', 'hardware-profile:read'])] public ?string $mac = ''; #[Groups(['client:read'])] @@ -47,10 +47,6 @@ final class ClientOutput extends AbstractOutput #[Groups(['client:read'])] public ?MenuOutput $menu = null; - #[Groups(['client:read'])] - #[ApiProperty(readableLink: true )] - public ?HardwareProfileOutput $hardwareProfile = null; - #[Groups(['client:read'])] #[ApiProperty(readableLink: true )] public ?ImageRepositoryOutput $repository = null; @@ -122,8 +118,6 @@ final class ClientOutput extends AbstractOutput $this->pxeTemplate = $template ? new PxeTemplateOutput($template) : null; - $this->hardwareProfile = $client->getHardwareProfile() ? new HardwareProfileOutput($client->getHardwareProfile()) : null; - if ($client->getSubnet()){ $this->subnet = $client->getSubnet()?->getIpAddress().'/' . $this->convertMaskToCIDR($client->getSubnet() ? $client->getSubnet()->getNetmask() : $client->getOrganizationalUnit()->getNetworkSettings()->getNetmask()); diff --git a/src/Dto/Output/HardwareProfileOutput.php b/src/Dto/Output/HardwareProfileOutput.php index 128f2c8..22b73f3 100644 --- a/src/Dto/Output/HardwareProfileOutput.php +++ b/src/Dto/Output/HardwareProfileOutput.php @@ -11,14 +11,14 @@ use Symfony\Component\Serializer\Annotation\Groups; #[Get(shortName: 'HardwareProfile')] final class HardwareProfileOutput extends AbstractOutput { - #[Groups(['hardware-profile:read', 'client:read', 'organizational-unit:read'])] + #[Groups(['hardware-profile:read', 'client:read'])] public ?string $description = ''; #[Groups(['hardware-profile:read'])] public ?string $comments = ''; #[Groups(['hardware-profile:read'])] - public ?OrganizationalUnitOutput $organizationalUnit = null; + public ?ClientOutput $client = null; #[Groups(['hardware-profile:read'])] public ?array $hardwareCollection = []; @@ -35,8 +35,8 @@ final class HardwareProfileOutput extends AbstractOutput $this->description = $hardwareProfile->getDescription(); $this->comments = $hardwareProfile->getComments(); - if($hardwareProfile->getOrganizationalUnit()) { - $this->organizationalUnit = new OrganizationalUnitOutput($hardwareProfile->getOrganizationalUnit()); + if($hardwareProfile->getClient()) { + $this->client = new ClientOutput($hardwareProfile->getClient()); } $this->hardwareCollection = $hardwareProfile->getHardwareCollection()->map( diff --git a/src/Dto/Output/HardwareTypeOutput.php b/src/Dto/Output/HardwareTypeOutput.php index 860e86f..9606d3a 100644 --- a/src/Dto/Output/HardwareTypeOutput.php +++ b/src/Dto/Output/HardwareTypeOutput.php @@ -12,10 +12,22 @@ final class HardwareTypeOutput extends AbstractOutput #[Groups(['hardware-type:read', 'hardware:read'])] public string $name; + #[Groups(['hardware-type:read', 'hardware:read'])] + public ?string $description = null; + + #[Groups(['hardware-type:read', 'hardware:read'])] + public ?string $code = null; + + #[Groups(['hardware-type:read', 'hardware:read'])] + public \DateTime $createdAt; + public function __construct(HardwareType $hardwareType) { parent::__construct($hardwareType); $this->name = $hardwareType->getName(); + $this->description = $hardwareType->getDescription(); + $this->code = $hardwareType->getCode(); + $this->createdAt = $hardwareType->getCreatedAt(); } } \ No newline at end of file diff --git a/src/Entity/Client.php b/src/Entity/Client.php index 0ada71c..89513db 100644 --- a/src/Entity/Client.php +++ b/src/Entity/Client.php @@ -54,7 +54,7 @@ class Client extends AbstractEntity #[ORM\JoinColumn( onDelete: 'SET NULL')] private ?Menu $menu = null; - #[ORM\ManyToOne] + #[ORM\OneToOne(mappedBy: 'client', cascade: ['persist', 'remove'])] private ?HardwareProfile $hardwareProfile = null; #[ORM\Column(nullable: true)] diff --git a/src/Entity/HardwareProfile.php b/src/Entity/HardwareProfile.php index 3538baf..448be48 100644 --- a/src/Entity/HardwareProfile.php +++ b/src/Entity/HardwareProfile.php @@ -16,9 +16,9 @@ class HardwareProfile extends AbstractEntity #[ORM\Column(length: 255, nullable: true)] private ?string $comments = null; - #[ORM\ManyToOne(targetEntity: OrganizationalUnit::class)] + #[ORM\ManyToOne(targetEntity: Client::class, inversedBy: 'hardwareProfile')] #[ORM\JoinColumn(nullable: false)] - private ?OrganizationalUnit $organizationalUnit = null; + private ?Client $client = null; /** * @var Collection @@ -26,18 +26,11 @@ class HardwareProfile extends AbstractEntity #[ORM\ManyToMany(targetEntity: Hardware::class, inversedBy: 'hardwareProfiles')] private Collection $hardwareCollection; - /** - * @var Collection - */ - #[ORM\OneToMany(mappedBy: 'hardwareProfile', targetEntity: Client::class)] - private Collection $clients; - public function __construct() { parent::__construct(); $this->hardwareCollection = new ArrayCollection(); - $this->clients = new ArrayCollection(); } public function getId(): ?int @@ -69,14 +62,14 @@ class HardwareProfile extends AbstractEntity return $this; } - public function getOrganizationalUnit(): ?OrganizationalUnit + public function getClient(): ?Client { - return $this->organizationalUnit; + return $this->client; } - public function setOrganizationalUnit(?OrganizationalUnit $organizationalUnit): static + public function setClient(?Client $client): static { - $this->organizationalUnit = $organizationalUnit; + $this->client = $client; return $this; } @@ -104,34 +97,4 @@ class HardwareProfile extends AbstractEntity return $this; } - - /** - * @return Collection - */ - public function getClients(): Collection - { - return $this->clients; - } - - public function addClient(Client $client): static - { - if (!$this->clients->contains($client)) { - $this->clients->add($client); - $client->setHardwareProfile($this); - } - - return $this; - } - - public function removeClient(Client $client): static - { - if ($this->clients->removeElement($client)) { - // set the owning side to null (unless already changed) - if ($client->getHardwareProfile() === $this) { - $client->setHardwareProfile(null); - } - } - - return $this; - } } diff --git a/src/Entity/HardwareType.php b/src/Entity/HardwareType.php index e0c2260..82a7f34 100644 --- a/src/Entity/HardwareType.php +++ b/src/Entity/HardwareType.php @@ -9,4 +9,34 @@ use Doctrine\ORM\Mapping as ORM; class HardwareType extends AbstractEntity { use NameableTrait; + + #[ORM\Column(length: 255, nullable: true)] + private ?string $description = null; + + #[ORM\Column(length: 10, nullable: true)] + private ?string $code = null; + + public function getDescription(): ?string + { + return $this->description; + } + + public function setDescription(?string $description): static + { + $this->description = $description; + + return $this; + } + + public function getCode(): ?string + { + return $this->code; + } + + public function setCode(?string $code): static + { + $this->code = $code; + + return $this; + } } From 084a1d6f394174323628be4cf9c03aa5433db96d Mon Sep 17 00:00:00 2001 From: Manuel Aranda Date: Tue, 23 Sep 2025 08:36:14 +0200 Subject: [PATCH 2/2] refs #2693. Updated backend --- CHANGELOG.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index a6a1a98..69fd0f0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,9 @@ # Changelog +## [0.25.0] - 2025-09-23 +### Added +- Se ha añadido logica para obtener el inventario hardware de un cliente para poder almanecarlo en base de datos. + +--- ## [0.24.4] - 2025-09-21 ### Fixed - Se ha arreglado un error en el servicio de clonado de imagen cuando los equipos no estan conectados.