2022-12-18 21:58:21 +01:00
|
|
|
<?php
|
|
|
|
/*
|
|
|
|
* This file is part of Part-DB (https://github.com/Part-DB/Part-DB-symfony).
|
|
|
|
*
|
|
|
|
* Copyright (C) 2019 - 2022 Jan Böhmer (https://github.com/jbtronics)
|
|
|
|
*
|
|
|
|
* This program is free software: you can redistribute it and/or modify
|
|
|
|
* it under the terms of the GNU Affero General Public License as published
|
|
|
|
* by the Free Software Foundation, either version 3 of the License, or
|
|
|
|
* (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU Affero General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU Affero General Public License
|
|
|
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
|
|
*/
|
|
|
|
|
|
|
|
namespace App\Controller;
|
|
|
|
|
|
|
|
use App\DataTables\ProjectBomEntriesDataTable;
|
2022-12-28 23:32:46 +01:00
|
|
|
use App\Entity\Parts\Part;
|
2022-12-18 21:58:21 +01:00
|
|
|
use App\Entity\ProjectSystem\Project;
|
2022-12-28 23:32:46 +01:00
|
|
|
use App\Entity\ProjectSystem\ProjectBOMEntry;
|
|
|
|
use App\Form\ProjectSystem\ProjectBOMEntryCollectionType;
|
2023-01-22 00:01:16 +01:00
|
|
|
use App\Form\ProjectSystem\ProjectBuildType;
|
2022-12-28 23:32:46 +01:00
|
|
|
use App\Form\Type\StructuralEntityType;
|
2023-01-22 00:01:16 +01:00
|
|
|
use App\Helpers\Projects\ProjectBuildRequest;
|
2023-01-18 23:07:51 +01:00
|
|
|
use App\Services\ProjectSystem\ProjectBuildHelper;
|
2022-12-28 23:32:46 +01:00
|
|
|
use Doctrine\Common\Collections\ArrayCollection;
|
|
|
|
use Doctrine\ORM\EntityManagerInterface;
|
2022-12-18 21:58:21 +01:00
|
|
|
use Omines\DataTablesBundle\DataTableFactory;
|
2022-12-29 13:15:26 +01:00
|
|
|
use Sensio\Bundle\FrameworkExtraBundle\Configuration\ParamConverter;
|
2022-12-18 21:58:21 +01:00
|
|
|
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
2022-12-28 23:32:46 +01:00
|
|
|
use Symfony\Component\Form\Extension\Core\Type\SubmitType;
|
2022-12-18 21:58:21 +01:00
|
|
|
use Symfony\Component\HttpFoundation\Request;
|
2022-12-28 23:32:46 +01:00
|
|
|
use Symfony\Component\HttpFoundation\Response;
|
2022-12-18 21:58:21 +01:00
|
|
|
use Symfony\Component\Routing\Annotation\Route;
|
2022-12-29 13:15:26 +01:00
|
|
|
use Symfony\Component\Validator\Constraints\NotNull;
|
2022-12-18 21:58:21 +01:00
|
|
|
|
|
|
|
/**
|
|
|
|
* @Route("/project")
|
|
|
|
*/
|
|
|
|
class ProjectController extends AbstractController
|
|
|
|
{
|
|
|
|
private DataTableFactory $dataTableFactory;
|
|
|
|
|
|
|
|
public function __construct(DataTableFactory $dataTableFactory)
|
|
|
|
{
|
|
|
|
$this->dataTableFactory = $dataTableFactory;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2023-01-08 23:07:25 +01:00
|
|
|
* @Route("/{id}/info", name="project_info", requirements={"id"="\d+"})
|
2022-12-18 21:58:21 +01:00
|
|
|
*/
|
2023-01-18 23:07:51 +01:00
|
|
|
public function info(Project $project, Request $request, ProjectBuildHelper $buildHelper)
|
2022-12-18 21:58:21 +01:00
|
|
|
{
|
|
|
|
$this->denyAccessUnlessGranted('read', $project);
|
|
|
|
|
|
|
|
$table = $this->dataTableFactory->createFromType(ProjectBomEntriesDataTable::class, ['project' => $project])
|
|
|
|
->handleRequest($request);
|
|
|
|
|
|
|
|
if ($table->isCallback()) {
|
|
|
|
return $table->getResponse();
|
|
|
|
}
|
|
|
|
|
2022-12-31 14:17:46 +01:00
|
|
|
return $this->render('Projects/info/info.html.twig', [
|
2023-01-18 23:07:51 +01:00
|
|
|
'buildHelper' => $buildHelper,
|
2022-12-18 21:58:21 +01:00
|
|
|
'datatable' => $table,
|
|
|
|
'project' => $project,
|
|
|
|
]);
|
|
|
|
}
|
2022-12-28 23:32:46 +01:00
|
|
|
|
2023-01-21 21:41:08 +01:00
|
|
|
/**
|
|
|
|
* @Route("/{id}/build", name="project_build", requirements={"id"="\d+"})
|
|
|
|
*/
|
2023-01-22 16:59:58 +01:00
|
|
|
public function build(Project $project, Request $request, ProjectBuildHelper $buildHelper, EntityManagerInterface $entityManager): Response
|
2023-01-21 21:41:08 +01:00
|
|
|
{
|
|
|
|
$this->denyAccessUnlessGranted('read', $project);
|
|
|
|
|
|
|
|
//If no number of builds is given (or it is invalid), just assume 1
|
|
|
|
$number_of_builds = $request->query->getInt('n', 1);
|
|
|
|
if ($number_of_builds < 1) {
|
|
|
|
$number_of_builds = 1;
|
|
|
|
}
|
|
|
|
|
2023-01-22 00:01:16 +01:00
|
|
|
$projectBuildRequest = new ProjectBuildRequest($project, $number_of_builds);
|
|
|
|
$form = $this->createForm(ProjectBuildType::class, $projectBuildRequest);
|
2023-01-21 21:41:08 +01:00
|
|
|
|
2023-01-22 00:01:16 +01:00
|
|
|
$form->handleRequest($request);
|
2023-01-22 16:59:58 +01:00
|
|
|
if ($form->isSubmitted()) {
|
|
|
|
if ($form->isValid()) {
|
2023-01-22 23:40:10 +01:00
|
|
|
//Ensure that the user can withdraw stock from all parts
|
|
|
|
$this->denyAccessUnlessGranted('@parts_stock.withdraw');
|
|
|
|
|
2023-01-22 23:27:45 +01:00
|
|
|
//We have to do a flush already here, so that the newly created partLot gets an ID and can be logged to DB later.
|
|
|
|
$entityManager->flush();
|
|
|
|
$buildHelper->doBuild($projectBuildRequest);
|
2023-01-22 16:59:58 +01:00
|
|
|
$entityManager->flush();
|
|
|
|
$this->addFlash('success', 'project.build.flash.success');
|
|
|
|
|
|
|
|
return $this->redirect(
|
|
|
|
$request->get('_redirect',
|
|
|
|
$this->generateUrl('project_info', ['id' => $project->getID()]
|
|
|
|
)));
|
|
|
|
} else {
|
|
|
|
$this->addFlash('error', 'project.build.flash.invalid_input');
|
|
|
|
}
|
2023-01-22 00:01:16 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
return $this->renderForm('Projects/build/build.html.twig', [
|
2023-01-21 21:41:08 +01:00
|
|
|
'buildHelper' => $buildHelper,
|
|
|
|
'project' => $project,
|
2023-01-22 00:01:16 +01:00
|
|
|
'build_request' => $projectBuildRequest,
|
2023-01-21 21:41:08 +01:00
|
|
|
'number_of_builds' => $number_of_builds,
|
2023-01-22 00:01:16 +01:00
|
|
|
'form' => $form,
|
2023-01-21 21:41:08 +01:00
|
|
|
]);
|
|
|
|
}
|
|
|
|
|
2022-12-28 23:32:46 +01:00
|
|
|
/**
|
2022-12-29 13:15:26 +01:00
|
|
|
* @Route("/add_parts", name="project_add_parts_no_id")
|
|
|
|
* @Route("/{id}/add_parts", name="project_add_parts", requirements={"id"="\d+"})
|
2022-12-28 23:32:46 +01:00
|
|
|
* @param Request $request
|
|
|
|
* @param Project|null $project
|
|
|
|
*/
|
2022-12-29 13:15:26 +01:00
|
|
|
public function addPart(Request $request, EntityManagerInterface $entityManager, ?Project $project): Response
|
2022-12-28 23:32:46 +01:00
|
|
|
{
|
2022-12-29 13:15:26 +01:00
|
|
|
if($project) {
|
|
|
|
$this->denyAccessUnlessGranted('edit', $project);
|
|
|
|
} else {
|
2023-01-08 20:10:58 +01:00
|
|
|
$this->denyAccessUnlessGranted('@projects.edit');
|
2022-12-29 13:15:26 +01:00
|
|
|
}
|
2022-12-28 23:32:46 +01:00
|
|
|
|
|
|
|
$builder = $this->createFormBuilder();
|
|
|
|
$builder->add('project', StructuralEntityType::class, [
|
|
|
|
'class' => Project::class,
|
|
|
|
'required' => true,
|
2022-12-29 13:15:26 +01:00
|
|
|
'disabled' => $project !== null, //If a project is given, disable the field
|
2022-12-28 23:32:46 +01:00
|
|
|
'data' => $project,
|
2022-12-29 13:15:26 +01:00
|
|
|
'constraints' => [
|
|
|
|
new NotNull()
|
|
|
|
]
|
2022-12-28 23:32:46 +01:00
|
|
|
]);
|
|
|
|
$builder->add('bom_entries', ProjectBOMEntryCollectionType::class);
|
|
|
|
$builder->add('submit', SubmitType::class, ['label' => 'save']);
|
|
|
|
$form = $builder->getForm();
|
|
|
|
|
|
|
|
//Preset the BOM entries with the selected parts, when the form was not submitted yet
|
|
|
|
$preset_data = new ArrayCollection();
|
|
|
|
foreach (explode(',', $request->get('parts', '')) as $part_id) {
|
|
|
|
$part = $entityManager->getRepository(Part::class)->find($part_id);
|
|
|
|
if (null !== $part) {
|
|
|
|
//If there is already a BOM entry for this part, we use this one (we edit it then)
|
|
|
|
$bom_entry = $entityManager->getRepository(ProjectBOMEntry::class)->findOneBy([
|
|
|
|
'project' => $project,
|
|
|
|
'part' => $part
|
|
|
|
]);
|
|
|
|
if ($bom_entry) {
|
|
|
|
$preset_data->add($bom_entry);
|
|
|
|
} else { //Otherwise create an empty one
|
|
|
|
$entry = new ProjectBOMEntry();
|
|
|
|
$entry->setProject($project);
|
|
|
|
$entry->setPart($part);
|
|
|
|
$preset_data->add($entry);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
$form['bom_entries']->setData($preset_data);
|
|
|
|
|
|
|
|
$form->handleRequest($request);
|
|
|
|
if ($form->isSubmitted() && $form->isValid()) {
|
2022-12-29 13:15:26 +01:00
|
|
|
$target_project = $project ?? $form->get('project')->getData();
|
|
|
|
|
|
|
|
//Ensure that we really have acces to the selected project
|
|
|
|
$this->denyAccessUnlessGranted('edit', $target_project);
|
|
|
|
|
2022-12-28 23:32:46 +01:00
|
|
|
$data = $form->getData();
|
|
|
|
$bom_entries = $data['bom_entries'];
|
|
|
|
foreach ($bom_entries as $bom_entry){
|
2022-12-29 13:15:26 +01:00
|
|
|
$target_project->addBOMEntry($bom_entry);
|
2022-12-28 23:32:46 +01:00
|
|
|
}
|
|
|
|
$entityManager->flush();
|
|
|
|
|
|
|
|
//If a redirect query parameter is set, redirect to this page
|
|
|
|
if ($request->query->get('_redirect')) {
|
|
|
|
return $this->redirect($request->query->get('_redirect'));
|
|
|
|
}
|
|
|
|
//Otherwise just show the project info page
|
2022-12-29 13:15:26 +01:00
|
|
|
return $this->redirectToRoute('project_info', ['id' => $target_project->getID()]);
|
2022-12-28 23:32:46 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
return $this->renderForm('Projects/add_parts.html.twig', [
|
|
|
|
'project' => $project,
|
|
|
|
'form' => $form,
|
|
|
|
]);
|
|
|
|
}
|
2022-12-18 21:58:21 +01:00
|
|
|
}
|