diff --git a/migrations/Version20221229125204.php b/migrations/Version20221229125204.php deleted file mode 100644 index d05471c5..00000000 --- a/migrations/Version20221229125204.php +++ /dev/null @@ -1,39 +0,0 @@ -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/migrations/Version20221231173322.php b/migrations/Version20221231173322.php new file mode 100644 index 00000000..06fd0bd8 --- /dev/null +++ b/migrations/Version20221231173322.php @@ -0,0 +1,48 @@ +addSql('ALTER TABLE device_parts ADD price_currency_id INT DEFAULT NULL, ADD name VARCHAR(255) DEFAULT NULL, ADD comment LONGTEXT NOT NULL, ADD price NUMERIC(11, 5) DEFAULT NULL COMMENT \'(DC2Type:big_decimal)\', 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 device_parts ADD CONSTRAINT FK_AFC547993FFDCD60 FOREIGN KEY (price_currency_id) REFERENCES currencies (id)'); + $this->addSql('CREATE INDEX IDX_AFC547993FFDCD60 ON device_parts (price_currency_id)'); + $this->addSql('ALTER TABLE devices ADD status VARCHAR(64) DEFAULT NULL, ADD description LONGTEXT NOT NULL'); + $this->addSql('ALTER TABLE groups CHANGE permissions_data permissions_data LONGTEXT DEFAULT \'[]\' NOT NULL COMMENT \'(DC2Type:json)\''); + $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)'); + $this->addSql('ALTER TABLE users CHANGE permissions_data permissions_data LONGTEXT DEFAULT \'[]\' NOT NULL COMMENT \'(DC2Type:json)\''); + } + + 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 FOREIGN KEY FK_AFC547993FFDCD60'); + $this->addSql('DROP INDEX IDX_AFC547993FFDCD60 ON device_parts'); + $this->addSql('ALTER TABLE device_parts DROP price_currency_id, DROP name, DROP comment, DROP price, DROP last_modified, DROP datetime_added, CHANGE quantity quantity INT NOT NULL'); + $this->addSql('ALTER TABLE `groups` CHANGE permissions_data permissions_data LONGTEXT NOT NULL COMMENT \'(DC2Type:json)\''); + $this->addSql('ALTER TABLE log CHANGE level level TINYINT(1) 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'); + $this->addSql('ALTER TABLE `users` CHANGE permissions_data permissions_data LONGTEXT NOT NULL COMMENT \'(DC2Type:json)\''); + } +} diff --git a/src/Entity/ProjectSystem/ProjectBOMEntry.php b/src/Entity/ProjectSystem/ProjectBOMEntry.php index 80b0da7c..754283bf 100644 --- a/src/Entity/ProjectSystem/ProjectBOMEntry.php +++ b/src/Entity/ProjectSystem/ProjectBOMEntry.php @@ -25,6 +25,10 @@ namespace App\Entity\ProjectSystem; use App\Entity\Base\AbstractDBElement; use App\Entity\Base\TimestampTrait; use App\Entity\Parts\Part; +use App\Entity\PriceInformations\Currency; +use App\Validator\Constraints\BigDecimal\BigDecimalPositive; +use App\Validator\Constraints\Selectable; +use Brick\Math\BigDecimal; use Doctrine\ORM\Mapping as ORM; use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity; use Symfony\Component\Validator\Constraints as Assert; @@ -86,6 +90,29 @@ class ProjectBOMEntry extends AbstractDBElement */ protected ?Part $part = null; + /** + * @var BigDecimal The price of this non-part BOM entry + * @ORM\Column(type="big_decimal", precision=11, scale=5, nullable=true) + * @Assert\AtLeastOneOf({ + * @BigDecimalPositive(), + * @Assert\IsNull() + * }) + */ + protected ?BigDecimal $price; + + /** + * @var ?Currency The currency for the price of this non-part BOM entry + * @ORM\ManyToOne(targetEntity="App\Entity\PriceInformations\Currency") + * @ORM\JoinColumn(nullable=true) + * @Selectable() + */ + protected ?Currency $price_currency = null; + + public function __construct() + { + $this->price = BigDecimal::zero()->toScale(5); + } + /** * @return float */ @@ -196,6 +223,44 @@ class ProjectBOMEntry extends AbstractDBElement return $this; } + /** + * Returns the price of this BOM entry, if existing. + * Prices are only valid on non-Part BOM entries. + * @return BigDecimal|null + */ + public function getPrice(): ?BigDecimal + { + return $this->price; + } + + /** + * Sets the price of this BOM entry. + * Prices are only valid on non-Part BOM entries. + * @param BigDecimal|null $price + */ + public function setPrice(?BigDecimal $price): void + { + $this->price = $price; + } + + /** + * @return Currency|null + */ + public function getPriceCurrency(): ?Currency + { + return $this->price_currency; + } + + /** + * @param Currency|null $price_currency + */ + public function setPriceCurrency(?Currency $price_currency): void + { + $this->price_currency = $price_currency; + } + + + /** * @Assert\Callback */ @@ -231,6 +296,13 @@ class ProjectBOMEntry extends AbstractDBElement ->addViolation(); } + //Prices are only only allowed on non-part BOM entries + if ($this->part !== null && $this->price !== null) { + $context->buildViolation('project.bom_entry.price_not_allowed_on_parts') + ->atPath('price') + ->addViolation(); + } + //Check that the part is not the build representation part of this device or one of its parents if ($this->part && $this->part->getBuiltProject() !== null) { //Get the associated project diff --git a/src/Form/ProjectSystem/ProjectBOMEntryType.php b/src/Form/ProjectSystem/ProjectBOMEntryType.php index 99730375..49292235 100644 --- a/src/Form/ProjectSystem/ProjectBOMEntryType.php +++ b/src/Form/ProjectSystem/ProjectBOMEntryType.php @@ -4,6 +4,8 @@ namespace App\Form\ProjectSystem; use App\Entity\Parts\Part; use App\Entity\ProjectSystem\ProjectBOMEntry; +use App\Form\Type\BigDecimalNumberType; +use App\Form\Type\CurrencyEntityType; use App\Form\Type\PartSelectType; use App\Form\Type\RichTextEditorType; use App\Form\Type\SIUnitType; @@ -63,6 +65,22 @@ class ProjectBOMEntryType extends AbstractType 'rows' => 2, ], ]) + ->add('price', BigDecimalNumberType::class, [ + 'label' => false, + 'required' => false, + 'scale' => 5, + 'html5' => true, + 'attr' => [ + 'min' => 0, + 'step' => 'any', + ], + ]) + ->add('priceCurrency', CurrencyEntityType::class, [ + 'required' => false, + 'label' => false, + 'short' => true, + ]) + ; } diff --git a/templates/Form/collection_types_layout.html.twig b/templates/Form/collection_types_layout.html.twig index f2be11af..02b2090f 100644 --- a/templates/Form/collection_types_layout.html.twig +++ b/templates/Form/collection_types_layout.html.twig @@ -61,6 +61,17 @@
{{ form_row(form.mountnames) }} +
+ +
+
+ {{ form_widget(form.price) }} + {{ form_widget(form.priceCurrency, {'attr': {'class': 'selectpicker', 'data-controller': 'elements--selectpicker'}}) }} +
+ {{ form_errors(form.price) }} + {{ form_errors(form.priceCurrency) }} +
+
{{ form_row(form.comment) }}
diff --git a/translations/messages.en.xlf b/translations/messages.en.xlf index 9be05717..9213bd48 100644 --- a/translations/messages.en.xlf +++ b/translations/messages.en.xlf @@ -10127,5 +10127,11 @@ Element 3 Subprojects + + + project.bom.price + Price + + diff --git a/translations/validators.en.xlf b/translations/validators.en.xlf index a1983bb2..cc38990f 100644 --- a/translations/validators.en.xlf +++ b/translations/validators.en.xlf @@ -275,5 +275,11 @@ The project BOM has to include all subprojects builds parts. Part %part_name% of project %project_name% missing! + + + project.bom_entry.price_not_allowed_on_parts + Prices are not allowed on BOM entries associated with a part. Define the price on the part instead. + +