Added possibility to associate a part with a project that represents the builds of the project

This commit is contained in:
Jan Böhmer 2022-12-29 16:21:04 +01:00
parent adc070d10c
commit fdcd1b9d9d
6 changed files with 106 additions and 10 deletions

View file

@ -31,6 +31,7 @@ use App\Entity\Parts\PartLot;
use App\Entity\Parts\Storelocation; use App\Entity\Parts\Storelocation;
use App\Entity\Parts\Supplier; use App\Entity\Parts\Supplier;
use App\Entity\PriceInformations\Orderdetail; use App\Entity\PriceInformations\Orderdetail;
use App\Entity\ProjectSystem\Project;
use App\Exceptions\AttachmentDownloadException; use App\Exceptions\AttachmentDownloadException;
use App\Form\Part\PartBaseType; use App\Form\Part\PartBaseType;
use App\Services\Attachments\AttachmentSubmitHandler; use App\Services\Attachments\AttachmentSubmitHandler;
@ -40,10 +41,12 @@ use App\Services\LogSystem\HistoryHelper;
use App\Services\LogSystem\TimeTravel; use App\Services\LogSystem\TimeTravel;
use App\Services\Parameters\ParameterExtractor; use App\Services\Parameters\ParameterExtractor;
use App\Services\Parts\PricedetailHelper; use App\Services\Parts\PricedetailHelper;
use App\Services\ProjectSystem\ProjectBuildPartHelper;
use DateTime; use DateTime;
use Doctrine\ORM\EntityManagerInterface; use Doctrine\ORM\EntityManagerInterface;
use Exception; use Exception;
use Omines\DataTablesBundle\DataTableFactory; use Omines\DataTablesBundle\DataTableFactory;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\ParamConverter;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\Form\FormInterface; use Symfony\Component\Form\FormInterface;
use Symfony\Component\HttpFoundation\RedirectResponse; use Symfony\Component\HttpFoundation\RedirectResponse;
@ -203,14 +206,26 @@ class PartController extends AbstractController
/** /**
* @Route("/new", name="part_new") * @Route("/new", name="part_new")
* @Route("/{id}/clone", name="part_clone") * @Route("/{id}/clone", name="part_clone")
* @Route("/new_build_part/{project_id}", name="part_new_build_part")
* @ParamConverter("part", options={"id" = "id"})
* @ParamConverter("project", options={"id" = "project_id"})
*/ */
public function new(Request $request, EntityManagerInterface $em, TranslatorInterface $translator, public function new(Request $request, EntityManagerInterface $em, TranslatorInterface $translator,
AttachmentSubmitHandler $attachmentSubmitHandler, ?Part $part = null): Response AttachmentSubmitHandler $attachmentSubmitHandler, ProjectBuildPartHelper $projectBuildPartHelper,
?Part $part = null, ?Project $project = null): Response
{ {
if (null === $part) {
$new_part = new Part(); if ($part) { //Clone part
} else {
$new_part = clone $part; $new_part = clone $part;
} else if ($project) { //Initialize a new part for a build part from the given project
//Ensure that the project has not already a build part
if ($project->getBuildPart() !== null) {
$this->addFlash('error', 'part.new_build_part.error.build_part_already_exists');
return $this->redirectToRoute('part_edit', ['id' => $project->getBuildPart()->getID()]);
}
$new_part = $projectBuildPartHelper->getPartInitialization($project);
} else { //Create an empty part from scratch
$new_part = new Part();
} }
$this->denyAccessUnlessGranted('create', $new_part); $this->denyAccessUnlessGranted('create', $new_part);
@ -280,6 +295,11 @@ class PartController extends AbstractController
$em->flush(); $em->flush();
$this->addFlash('success', 'part.created_flash'); $this->addFlash('success', 'part.created_flash');
//If a redirect URL was given, redirect there
if ($request->query->get('_redirect')) {
return $this->redirect($request->query->get('_redirect'));
}
//Redirect to clone page if user wished that... //Redirect to clone page if user wished that...
//@phpstan-ignore-next-line //@phpstan-ignore-next-line
if ('save_and_clone' === $form->getClickedButton()->getName()) { if ('save_and_clone' === $form->getClickedButton()->getName()) {

View file

@ -66,10 +66,10 @@ class Project extends AbstractStructuralDBElement
/** /**
* @var string The current status of the project * @var string The current status of the project
* @ORM\Column(type="string", length=64) * @ORM\Column(type="string", length=64, nullable=true)
* @Assert\Choice({"draft","planning","in_production","finished","archived", ""}) * @Assert\Choice({"draft","planning","in_production","finished","archived"})
*/ */
protected string $status; protected ?string $status = null;
/** /**
@ -237,7 +237,7 @@ class Project extends AbstractStructuralDBElement
/** /**
* @return string * @return string
*/ */
public function getStatus(): string public function getStatus(): ?string
{ {
return $this->status; return $this->status;
} }
@ -245,7 +245,7 @@ class Project extends AbstractStructuralDBElement
/** /**
* @param string $status * @param string $status
*/ */
public function setStatus(string $status): void public function setStatus(?string $status): void
{ {
$this->status = $status; $this->status = $status;
} }

View file

@ -34,9 +34,9 @@ class ProjectAdminForm extends BaseEntityAdminForm
{ {
$builder->add('description', RichTextEditorType::class, [ $builder->add('description', RichTextEditorType::class, [
'required' => false, 'required' => false,
'empty_data' => '',
'label' => 'part.edit.description', 'label' => 'part.edit.description',
'mode' => 'markdown-single_line', 'mode' => 'markdown-single_line',
'empty_data' => '',
'attr' => [ 'attr' => [
'placeholder' => 'part.edit.description.placeholder', 'placeholder' => 'part.edit.description.placeholder',
'rows' => 2, 'rows' => 2,
@ -51,6 +51,7 @@ class ProjectAdminForm extends BaseEntityAdminForm
], ],
'label' => 'project.edit.status', 'label' => 'project.edit.status',
'required' => false, 'required' => false,
'empty_data' => '',
'choices' => [ 'choices' => [
'project.status.draft' => 'draft', 'project.status.draft' => 'draft',
'project.status.planning' => 'planning', 'project.status.planning' => 'planning',

View file

@ -0,0 +1,34 @@
<?php
namespace App\Services\ProjectSystem;
use App\Entity\Parts\Part;
use App\Entity\ProjectSystem\Project;
class ProjectBuildPartHelper
{
/**
* Returns a part that represents the builds of a project. This part is not saved to the database, and can be used
* as initial data for the new part form.
* @param Project $project
* @return Part
*/
public function getPartInitialization(Project $project): Part
{
$part = new Part();
//Associate the part with the project
$part->setBuiltProject($project);
//Set the name of the part to the name of the project
$part->setName($project->getName());
//Set the description of the part to the description of the project
$part->setDescription($project->getDescription());
//Add a tag to the part that indicates that it is a build part
$part->setTags('project-build');
return $part;
}
}

View file

@ -1,5 +1,7 @@
{% extends "AdminPages/EntityAdminBase.html.twig" %} {% extends "AdminPages/EntityAdminBase.html.twig" %}
{# @var entity App\Entity\ProjectSystem\Project #}
{% block card_title %} {% block card_title %}
<i class="fas fa-archive fa-fw"></i> {% trans %}device.caption{% endtrans %} <i class="fas fa-archive fa-fw"></i> {% trans %}device.caption{% endtrans %}
{% endblock %} {% endblock %}
@ -19,6 +21,21 @@
{% block additional_controls %} {% block additional_controls %}
{{ form_row(form.description) }} {{ form_row(form.description) }}
{{ form_row(form.status) }} {{ form_row(form.status) }}
{% if entity.id %}
<div class="mb-2 row">
<label class="col-form-label col-sm-3">{% trans %}project.edit.associated_build_part{% endtrans %}</label>
<div class="col-sm-9">
{% if entity.buildPart %}
<span class="form-control-static"><a href="{{ entity_url(entity.buildPart) }}">{{ entity.buildPart.name }}</a></span>
{% else %}
<a href="{{ path('part_new_build_part', {"project_id": entity.id , "_redirect": app.request.requestUri}) }}"
class="btn btn-outline-success">{% trans %}project.edit.associated_build_part.add{% endtrans %}</a>
{% endif %}
<p class="text-muted">{% trans %}project.edit.associated_build.hint{% endtrans %}</p>
</div>
</div>
{% endif %}
{% endblock %} {% endblock %}
{% block additional_panes %} {% block additional_panes %}

View file

@ -10055,5 +10055,29 @@ Element 3</target>
<target>Archived</target> <target>Archived</target>
</segment> </segment>
</unit> </unit>
<unit id="jcf.5wX" name="part.new_build_part.error.build_part_already_exists">
<segment>
<source>part.new_build_part.error.build_part_already_exists</source>
<target>The project already has an build part!</target>
</segment>
</unit>
<unit id="usGnetL" name="project.edit.associated_build_part">
<segment>
<source>project.edit.associated_build_part</source>
<target>Associated builds part</target>
</segment>
</unit>
<unit id="xXpskqU" name="project.edit.associated_build_part.add">
<segment>
<source>project.edit.associated_build_part.add</source>
<target>Add builds part</target>
</segment>
</unit>
<unit id="5rnE1fK" name="project.edit.associated_build.hint">
<segment>
<source>project.edit.associated_build.hint</source>
<target>This part represents the builds of this project, which are stored somewhere.</target>
</segment>
</unit>
</file> </file>
</xliff> </xliff>