diff --git a/migrations/Version20221218192108.php b/migrations/Version20221218192108.php deleted file mode 100644 index df5cb87e..00000000 --- a/migrations/Version20221218192108.php +++ /dev/null @@ -1,33 +0,0 @@ -addSql('ALTER TABLE device_parts ADD name VARCHAR(255) NULL, ADD comment LONGTEXT NOT NULL, ADD last_modified DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL, ADD datetime_added DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL, CHANGE quantity quantity DOUBLE PRECISION NOT NULL'); - $this->addSql('ALTER TABLE devices ADD description LONGTEXT NOT NULL'); - } - - public function down(Schema $schema): void - { - // this down() migration is auto-generated, please modify it to your needs - $this->addSql('ALTER TABLE devices DROP description'); - $this->addSql('ALTER TABLE device_parts DROP name, DROP comment, DROP last_modified, DROP datetime_added, CHANGE quantity quantity INT NOT NULL'); - } -} diff --git a/migrations/Version20221229125204.php b/migrations/Version20221229125204.php new file mode 100644 index 00000000..d05471c5 --- /dev/null +++ b/migrations/Version20221229125204.php @@ -0,0 +1,39 @@ +addSql('ALTER TABLE device_parts ADD name VARCHAR(255) DEFAULT NULL, ADD comment LONGTEXT NOT NULL, ADD last_modified DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL, ADD datetime_added DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL, CHANGE quantity quantity DOUBLE PRECISION NOT NULL'); + $this->addSql('ALTER TABLE devices ADD status VARCHAR(64) NOT NULL, ADD description LONGTEXT NOT NULL'); + $this->addSql('ALTER TABLE parts ADD built_project_id INT DEFAULT NULL'); + $this->addSql('ALTER TABLE parts ADD CONSTRAINT FK_6940A7FEE8AE70D9 FOREIGN KEY (built_project_id) REFERENCES devices (id)'); + $this->addSql('CREATE UNIQUE INDEX UNIQ_6940A7FEE8AE70D9 ON parts (built_project_id)'); + } + + public function down(Schema $schema): void + { + // this down() migration is auto-generated, please modify it to your needs + $this->addSql('ALTER TABLE devices DROP status, DROP description'); + $this->addSql('ALTER TABLE device_parts DROP name, DROP comment, DROP last_modified, DROP datetime_added, CHANGE quantity quantity INT NOT NULL'); + $this->addSql('ALTER TABLE `parts` DROP FOREIGN KEY FK_6940A7FEE8AE70D9'); + $this->addSql('DROP INDEX UNIQ_6940A7FEE8AE70D9 ON `parts`'); + $this->addSql('ALTER TABLE `parts` DROP built_project_id'); + } +} diff --git a/src/Entity/Parts/PartTraits/ProjectTrait.php b/src/Entity/Parts/PartTraits/ProjectTrait.php index 998d6bc8..19bc0dff 100644 --- a/src/Entity/Parts/PartTraits/ProjectTrait.php +++ b/src/Entity/Parts/PartTraits/ProjectTrait.php @@ -15,6 +15,13 @@ trait ProjectTrait */ protected $project_bom_entries = []; + /** + * @var Project|null If a project is set here, then this part is special and represents the builds of a project. + * @ORM\OneToOne(targetEntity="App\Entity\ProjectSystem\Project", inversedBy="build_part") + * @ORM\JoinColumn(nullable=true) + */ + protected ?Project $built_project = null; + /** * Returns all ProjectBOMEntries that use this part. * @return Collection|ProjectBOMEntry[] @@ -24,6 +31,36 @@ trait ProjectTrait return $this->project_bom_entries; } + /** + * Checks whether this part represents the builds of a project + * @return bool True if it represents the builds, false if not + */ + public function isProjectBuildPart(): bool + { + return $this->built_project !== null; + } + + /** + * Returns the project that this part represents the builds of, or null if it doesnt + * @return Project|null + */ + public function getBuiltProject(): ?Project + { + return $this->built_project; + } + + + /** + * Sets the project that this part represents the builds of + * @param Project|null $built_project The project that this part represents the builds of, or null if it is not a build part + */ + public function setBuiltProject(?Project $built_project): self + { + $this->built_project = $built_project; + return $this; + } + + /** * Get all devices which uses this part. * diff --git a/src/Entity/ProjectSystem/Project.php b/src/Entity/ProjectSystem/Project.php index a54c6d65..26a3f7ee 100644 --- a/src/Entity/ProjectSystem/Project.php +++ b/src/Entity/ProjectSystem/Project.php @@ -25,6 +25,7 @@ namespace App\Entity\ProjectSystem; use App\Entity\Attachments\ProjectAttachment; use App\Entity\Base\AbstractStructuralDBElement; use App\Entity\Parameters\ProjectParameter; +use App\Entity\Parts\Part; use Doctrine\Common\Collections\ArrayCollection; use Doctrine\Common\Collections\Collection; use Doctrine\ORM\Mapping as ORM; @@ -63,6 +64,20 @@ class Project extends AbstractStructuralDBElement */ protected int $order_quantity = 0; + /** + * @var string The current status of the project + * @ORM\Column(type="string", length=64) + * @Assert\Choice({"draft","planning","in_production","finished","archived", ""}) + */ + protected string $status; + + + /** + * @var Part|null The (optional) part that represents the builds of this project in the stock + * @ORM\OneToOne(targetEntity="App\Entity\Parts\Part", mappedBy="built_project", cascade={"persist"}, orphanRemoval=true) + */ + protected ?Part $build_part = null; + /** * @ORM\Column(type="boolean") */ @@ -219,5 +234,52 @@ class Project extends AbstractStructuralDBElement return $this; } + /** + * @return string + */ + public function getStatus(): string + { + return $this->status; + } + + /** + * @param string $status + */ + public function setStatus(string $status): void + { + $this->status = $status; + } + + /** + * Checks if this project has a associated part representing the builds of this project in the stock. + * @return bool + */ + public function hasBuildPart(): bool + { + return $this->build_part !== null; + } + + /** + * Gets the part representing the builds of this project in the stock, if it is existing + * @return Part|null + */ + public function getBuildPart(): ?Part + { + return $this->build_part; + } + + /** + * Sets the part representing the builds of this project in the stock. + * @param Part|null $build_part + */ + public function setBuildPart(?Part $build_part): void + { + $this->build_part = $build_part; + if ($build_part) { + $build_part->setBuiltProject($this); + } + } + + } diff --git a/src/Form/AdminPages/ProjectAdminForm.php b/src/Form/AdminPages/ProjectAdminForm.php index 4957973e..e9938933 100644 --- a/src/Form/AdminPages/ProjectAdminForm.php +++ b/src/Form/AdminPages/ProjectAdminForm.php @@ -24,6 +24,7 @@ use App\Entity\Base\AbstractNamedDBElement; use App\Form\ProjectSystem\ProjectBOMEntryCollectionType; use App\Form\ProjectSystem\ProjectBOMEntryType; use App\Form\Type\RichTextEditorType; +use Symfony\Component\Form\Extension\Core\Type\ChoiceType; use Symfony\Component\Form\Extension\Core\Type\CollectionType; use Symfony\Component\Form\FormBuilderInterface; @@ -43,5 +44,20 @@ class ProjectAdminForm extends BaseEntityAdminForm ]); $builder->add('bom_entries', ProjectBOMEntryCollectionType::class); + + $builder->add('status', ChoiceType::class, [ + 'attr' => [ + 'class' => 'form-select', + ], + 'label' => 'project.edit.status', + 'required' => false, + 'choices' => [ + 'project.status.draft' => 'draft', + 'project.status.planning' => 'planning', + 'project.status.in_production' => 'in_production', + 'project.status.finished' => 'finished', + 'project.status.archived' => 'archived', + ], + ]); } } \ No newline at end of file diff --git a/templates/AdminPages/DeviceAdmin.html.twig b/templates/AdminPages/DeviceAdmin.html.twig index 1842b0a6..b1375a89 100644 --- a/templates/AdminPages/DeviceAdmin.html.twig +++ b/templates/AdminPages/DeviceAdmin.html.twig @@ -18,6 +18,7 @@ {% block additional_controls %} {{ form_row(form.description) }} + {{ form_row(form.status) }} {% endblock %} {% block additional_panes %} diff --git a/translations/messages.en.xlf b/translations/messages.en.xlf index 0661663a..4a184a88 100644 --- a/translations/messages.en.xlf +++ b/translations/messages.en.xlf @@ -10019,5 +10019,41 @@ Element 3 BOM entry + + + project.edit.status + Project status + + + + + project.status.draft + Draft + + + + + project.status.planning + Planning + + + + + project.status.in_production + In production + + + + + project.status.finished + Finished + + + + + project.status.archived + Archived + +