Cleanup-Logik für Baugruppen und BOM-Einträge im Statistik-Bereich überarbeiten bzw. erweitern

This commit is contained in:
Marcel Diegelmann 2026-02-13 16:34:43 +01:00
parent d67e93064c
commit b08df9b812
35 changed files with 864 additions and 233 deletions

View file

@ -43,11 +43,13 @@ namespace App\Controller;
use App\Services\Tools\StatisticsHelper;
use App\Entity\AssemblySystem\AssemblyBOMEntry;
use App\Entity\AssemblySystem\Assembly;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Attribute\Route;
use Symfony\Contracts\Translation\TranslatorInterface;
class StatisticsController extends AbstractController
{
@ -62,31 +64,95 @@ class StatisticsController extends AbstractController
}
#[Route(path: '/statistics/cleanup-assembly-bom-entries', name: 'statistics_cleanup_assembly_bom_entries', methods: ['POST'])]
public function cleanupAssemblyBOMEntries(EntityManagerInterface $em): JsonResponse
{
public function cleanupAssemblyBOMEntries(
EntityManagerInterface $em,
StatisticsHelper $helper,
TranslatorInterface $translator
): JsonResponse {
$this->denyAccessUnlessGranted('@tools.statistics');
$qb = $em->createQueryBuilder();
$qb->select('be', 'IDENTITY(be.part) AS part_id')
->from(AssemblyBOMEntry::class, 'be')
->leftJoin('be.part', 'p')
->where('be.part IS NOT NULL')
->andWhere('p.id IS NULL');
try {
// We fetch the IDs of the entries that have a non-existent part.
// We use a raw SQL approach or a more robust DQL to avoid proxy initialization issues.
$qb = $em->createQueryBuilder();
$qb->select('be.id', 'IDENTITY(be.part) AS part_id')
->from(AssemblyBOMEntry::class, 'be')
->leftJoin('be.part', 'p')
->where('be.part IS NOT NULL')
->andWhere('p.id IS NULL');
$results = $qb->getQuery()->getResult();
$count = count($results);
$results = $qb->getQuery()->getResult();
$count = count($results);
foreach ($results as $result) {
/** @var AssemblyBOMEntry $entry */
$entry = $result[0];
$part_id = $result['part_id'] ?? 'unknown';
foreach ($results as $result) {
$entryId = $result['id'];
$partId = $result['part_id'] ?? 'unknown';
$entry->setPart(null);
$entry->setName(sprintf('part-id=%s not found', $part_id));
$entry = $em->find(AssemblyBOMEntry::class, $entryId);
if ($entry instanceof AssemblyBOMEntry) {
$entry->setPart(null);
$entry->setName(sprintf('part-id=%s not found', $partId));
}
}
$em->flush();
return new JsonResponse([
'success' => true,
'count' => $count,
'message' => $translator->trans('statistics.cleanup_assembly_bom_entries.success', [
'%count%' => $count,
]),
'new_count' => $helper->getInvalidPartBOMEntriesCount(),
]);
} catch (\Exception $e) {
return new JsonResponse([
'success' => false,
'message' => $translator->trans('statistics.cleanup_assembly_bom_entries.error') . ' ' . $e->getMessage(),
], Response::HTTP_INTERNAL_SERVER_ERROR);
}
}
$em->flush();
#[Route(path: '/statistics/cleanup-assembly-preview-attachments', name: 'statistics_cleanup_assembly_preview_attachments', methods: ['POST'])]
public function cleanupAssemblyPreviewAttachments(
EntityManagerInterface $em,
StatisticsHelper $helper,
TranslatorInterface $translator
): JsonResponse {
$this->denyAccessUnlessGranted('@tools.statistics');
return new JsonResponse(['success' => true, 'count' => $count]);
try {
$qb = $em->createQueryBuilder();
$qb->select('a')
->from(Assembly::class, 'a')
->leftJoin('a.master_picture_attachment', 'm')
->where('a.master_picture_attachment IS NOT NULL')
->andWhere('m.id IS NULL');
$assemblies = $qb->getQuery()->getResult();
$count = count($assemblies);
foreach ($assemblies as $assembly) {
if ($assembly instanceof Assembly) {
$assembly->setMasterPictureAttachment(null);
}
}
$em->flush();
return new JsonResponse([
'success' => true,
'count' => $count,
'message' => $translator->trans('statistics.cleanup_assembly_preview_attachments.success', [
'%count%' => $count,
]),
'new_count' => $helper->getInvalidAssemblyPreviewAttachmentsCount(),
]);
} catch (\Exception $e) {
return new JsonResponse([
'success' => false,
'message' => $translator->trans('statistics.cleanup_assembly_preview_attachments.error') . ' ' . $e->getMessage(),
], Response::HTTP_INTERNAL_SERVER_ERROR);
}
}
}

View file

@ -33,7 +33,6 @@ use Symfony\Component\Serializer\Attribute\Context;
* @extends Attachment<Assembly>
*/
#[UniqueEntity(['name', 'attachment_type', 'element'])]
#[UniqueEntity(['name', 'attachment_type', 'element'])]
#[ORM\Entity]
class AssemblyAttachment extends Attachment
{

View file

@ -190,4 +190,19 @@ class StatisticsHelper
return (int) $qb->getQuery()->getSingleScalarResult();
}
/**
* Returns the number of assemblies that have a master_picture_attachment that does not exist anymore.
*/
public function getInvalidAssemblyPreviewAttachmentsCount(): int
{
$qb = $this->em->createQueryBuilder();
$qb->select('COUNT(a.id)')
->from(Assembly::class, 'a')
->leftJoin('a.master_picture_attachment', 'at')
->where('a.master_picture_attachment IS NOT NULL')
->andWhere('at.id IS NULL');
return (int) $qb->getQuery()->getSingleScalarResult();
}
}