From 94a52a0a2284e6ab96a2c3fb2fb4a38b9a386cc7 Mon Sep 17 00:00:00 2001 From: Nicolas MELONI Date: Thu, 6 May 2021 16:12:33 +0200 Subject: [PATCH] allow channel selection to enabled them on product import --- src/Entity/ProductConfiguration.php | 42 ++++++++ src/Form/Type/ProductConfigurationType.php | 10 ++ src/Migrations/Version20210506132536.php | 52 ++++++++++ src/Resources/translations/messages.en.yml | 6 ++ src/Resources/translations/messages.fr.yml | 6 ++ .../products_configuration.html.twig | 12 ++- src/Service/ProductChannelEnabler.php | 97 ++++++++++++++----- .../ProductChannelEnablerInterface.php | 12 +++ .../Product/EnableDisableProductsTask.php | 6 +- .../EnableDisableProductModelsTask.php | 6 +- 10 files changed, 220 insertions(+), 29 deletions(-) create mode 100644 src/Migrations/Version20210506132536.php create mode 100644 src/Service/ProductChannelEnablerInterface.php diff --git a/src/Entity/ProductConfiguration.php b/src/Entity/ProductConfiguration.php index 4e1cbf86..c7d1a0ff 100644 --- a/src/Entity/ProductConfiguration.php +++ b/src/Entity/ProductConfiguration.php @@ -7,6 +7,7 @@ use Doctrine\Common\Collections\ArrayCollection; use Doctrine\Common\Collections\Collection; use Doctrine\ORM\Mapping as ORM; +use Sylius\Component\Core\Model\ChannelInterface; use Sylius\Component\Resource\Model\ResourceInterface; /** @@ -75,10 +76,27 @@ class ProductConfiguration implements ResourceInterface */ private $regenerateUrlRewrites; + /** + * @var bool + * @ORM\Column(name="enable_imported_products", type="boolean", options={"default" = 0}) + */ + private $enableImportedProducts = false; + + /** + * @var ChannelInterface[]|Collection + * @ORM\ManyToMany (targetEntity=ChannelInterface::class) + * @ORM\JoinTable(name="akeneo_product_configuration_channels", + * joinColumns={@ORM\JoinColumn(name="product_configuration_id", referencedColumnName="id")}, + * inverseJoinColumns={@ORM\JoinColumn(name="channel_id", referencedColumnName="id", unique=true)} + * ) + */ + private $channelsToEnable; + public function __construct() { $this->akeneoImageAttributes = new ArrayCollection(); $this->productImagesMapping = new ArrayCollection(); + $this->channelsToEnable = new ArrayCollection(); } public function getId(): ?int @@ -205,4 +223,28 @@ public function setAkeneoEnabledChannelsAttribute(?string $akeneoEnabledChannels return $this; } + + public function getEnableImportedProducts(): bool + { + return $this->enableImportedProducts; + } + + public function setEnableImportedProducts(bool $enableImportedProducts): self + { + $this->enableImportedProducts = $enableImportedProducts; + + return $this; + } + + public function getChannelsToEnable(): Collection + { + return $this->channelsToEnable; + } + + public function setChannelsToEnable(Collection $channelsToEnable): self + { + $this->channelsToEnable = $channelsToEnable; + + return $this; + } } diff --git a/src/Form/Type/ProductConfigurationType.php b/src/Form/Type/ProductConfigurationType.php index 5eb7dcf2..41661ec9 100644 --- a/src/Form/Type/ProductConfigurationType.php +++ b/src/Form/Type/ProductConfigurationType.php @@ -22,6 +22,16 @@ final class ProductConfigurationType extends AbstractType public function buildForm(FormBuilderInterface $builder, array $options): void { $builder + ->add('enableImportedProducts', CheckboxType::class, [ + 'label' => 'sylius.ui.admin.akeneo.products.enable_imported_products', + 'required' => false, + ]) + ->add('channelsToEnable', \Sylius\Bundle\ChannelBundle\Form\Type\ChannelChoiceType::class, [ + 'label' => 'sylius.ui.admin.akeneo.products.enable_imported_products_channels', + 'required' => false, + 'multiple' => true, + 'expanded' => true, + ]) ->add('akeneoPriceAttribute', AttributeCodeChoiceType::class, [ 'label' => 'sylius.ui.admin.akeneo.products.akeneo_price_attribute', ]) diff --git a/src/Migrations/Version20210506132536.php b/src/Migrations/Version20210506132536.php new file mode 100644 index 00000000..89a9abd5 --- /dev/null +++ b/src/Migrations/Version20210506132536.php @@ -0,0 +1,52 @@ +addSql('CREATE TABLE akeneo_product_configuration_channels ( + product_configuration_id INT NOT NULL, + channel_id INT NOT NULL, + INDEX IDX_E6A56A05FD7F4924 (product_configuration_id), + UNIQUE INDEX UNIQ_E6A56A0572F5A1AA (channel_id), + PRIMARY KEY( + product_configuration_id, channel_id + ) + ) DEFAULT CHARACTER SET UTF8 COLLATE `UTF8_unicode_ci` ENGINE = InnoDB'); + $this->addSql('ALTER TABLE + akeneo_product_configuration_channels + ADD + CONSTRAINT FK_E6A56A05FD7F4924 FOREIGN KEY (product_configuration_id) REFERENCES akeneo_api_configuration_product (id)'); + $this->addSql('ALTER TABLE + akeneo_product_configuration_channels + ADD + CONSTRAINT FK_E6A56A0572F5A1AA FOREIGN KEY (channel_id) REFERENCES sylius_channel (id)'); + $this->addSql('ALTER TABLE + akeneo_api_configuration_product + ADD + enable_imported_products TINYINT(1) DEFAULT \'0\' NOT NULL'); + } + + public function down(Schema $schema): void + { + // this down() migration is auto-generated, please modify it to your needs + $this->addSql('DROP TABLE akeneo_product_configuration_channels'); + $this->addSql('ALTER TABLE akeneo_api_configuration_product DROP enable_imported_products'); + } +} diff --git a/src/Resources/translations/messages.en.yml b/src/Resources/translations/messages.en.yml index 1eab0d93..774c8f2c 100644 --- a/src/Resources/translations/messages.en.yml +++ b/src/Resources/translations/messages.en.yml @@ -77,6 +77,12 @@ sylius: sylius_attribute: Sylius attributes akeneo_attribute: Akeneo attributes regenerate_url_rewrites: Regenerate url rewrites + enable_imported_products: Enable products at import + enable_imported_products_help: Checking this box overrides the configuration "Akeneo enabled channels attribute" + enable_imported_products_channels: Channels on which imported products will be enabled + channels_checkboxes_priority: If at least one box is checked, this will overwrite the attribute information defined in the "Akeneo enabled channels attribute" section. + akeneo_enabled_channels_attribute_priority: If this field is filled in, do not check any channels in the section above. + enabled_at_import_help: If unchecked, the products will not be automatically activated on import. attributes: title: Attributes subtitle: Attributes configuration diff --git a/src/Resources/translations/messages.fr.yml b/src/Resources/translations/messages.fr.yml index 5a479317..93f234ee 100644 --- a/src/Resources/translations/messages.fr.yml +++ b/src/Resources/translations/messages.fr.yml @@ -77,6 +77,12 @@ sylius: sylius_attribute: Attribut Sylius akeneo_attribute: Attribut Akeneo regenerate_url_rewrites: Regenerate url rewrites + enable_imported_products: Activer les produits à l'import + enable_imported_products_help: Cocher cette case écrasera la configuration "Attribut Akeneo des channels actifs". + enable_imported_products_channels: Canaux sur lesquelles les produits importés seront activés + channels_checkboxes_priority: Si au moins une case est cochée, cela écrasera les informations de l'attribut défini dans la section "Attribut Akeneo des channels actifs". + akeneo_enabled_channels_attribute_priority: Si ce champs est rempli, ne cochez pas de canaux dans la section du dessus. + enabled_at_import_help: Si décoché, les produits ne seront pas activés automatiquement à l'import. attributes: title: Attributs subtitle: Configuration des attributs diff --git a/src/Resources/views/Admin/AkeneoConnector/products_configuration.html.twig b/src/Resources/views/Admin/AkeneoConnector/products_configuration.html.twig index d99f5037..016f1b51 100644 --- a/src/Resources/views/Admin/AkeneoConnector/products_configuration.html.twig +++ b/src/Resources/views/Admin/AkeneoConnector/products_configuration.html.twig @@ -18,8 +18,18 @@ {% endblock %}
{{ form_start(form, {'attr': {'class': 'ui loadable form', 'novalidate': 'novalidate'}}) }} +
+
+ {{ 'sylius.ui.admin.akeneo.products.enabled_at_import_help'|trans }} + {{ form_row(form.enableImportedProducts) }} + {{ 'sylius.ui.admin.akeneo.products.channels_checkboxes_priority'|trans }} + {{ form_row(form.channelsToEnable) }} +
+ {{ 'sylius.ui.admin.akeneo.products.akeneo_enabled_channels_attribute_priority'|trans }} + {{ form_row(form.akeneoEnabledChannelsAttribute) }} +
+
{{ form_row(form.akeneoPriceAttribute) }} - {{ form_row(form.akeneoEnabledChannelsAttribute) }}
{{ form_row(form.importMediaFiles) }}
diff --git a/src/Service/ProductChannelEnabler.php b/src/Service/ProductChannelEnabler.php index 46513150..b1e9decb 100644 --- a/src/Service/ProductChannelEnabler.php +++ b/src/Service/ProductChannelEnabler.php @@ -14,7 +14,7 @@ use Synolia\SyliusAkeneoPlugin\Repository\ChannelRepository; use Synolia\SyliusAkeneoPlugin\Repository\ProductConfigurationRepository; -final class ProductChannelEnabler +final class ProductChannelEnabler implements ProductChannelEnablerInterface { /** @var \Synolia\SyliusAkeneoPlugin\Repository\ChannelRepository */ private $channelRepository; @@ -43,32 +43,20 @@ public function __construct( public function enableChannelForProduct(ProductInterface $product, array $resource): void { try { - $enabledChannels = $this->getEnabledChannelsAttributeData($product, $resource); + $productConfiguration = $this->getProductConfiguration(); + + if (!$productConfiguration->getEnableImportedProducts()) { + return; + } $this->entityManager->beginTransaction(); //Disable the product for all channels $product->getChannels()->clear(); - foreach ($enabledChannels as $enabledChannel) { - $channel = $this->channelRepository->findOneBy(['code' => $enabledChannel]); - if (!$channel instanceof ChannelInterface) { - $this->logger->warning(\sprintf( - 'Channel "%s" could not be activated for product "%s" because the channel was not found in the database.', - $enabledChannel, - $product->getCode() - )); - - continue; - } - - $product->addChannel($channel); - $this->logger->info(\sprintf( - 'Enabled channel "%s" for product "%s"', - $channel->getCode(), - $product->getCode() - )); - } + $this->handleByAkeneoEnabledChannelsAttribute($productConfiguration, $product, $resource); + $this->handleBySyliusConfiguration($productConfiguration, $product); + $this->entityManager->flush(); $this->entityManager->commit(); } catch (\Throwable $throwable) { @@ -80,7 +68,17 @@ public function enableChannelForProduct(ProductInterface $product, array $resour } } - public function getEnabledChannelsAttributeData(ProductInterface $product, array $resource): array + private function addProductToChannel(ProductInterface $product, ChannelInterface $channel): void + { + $product->addChannel($channel); + $this->logger->info(\sprintf( + 'Enabled channel "%s" for product "%s"', + $channel->getCode(), + $product->getCode() + )); + } + + private function getProductConfiguration(): ProductConfiguration { /** @var \Synolia\SyliusAkeneoPlugin\Entity\ProductConfiguration|null $productConfiguration */ $productConfiguration = $this->productConfigurationRepository->findOneBy([]); @@ -89,6 +87,14 @@ public function getEnabledChannelsAttributeData(ProductInterface $product, array throw new NoProductConfigurationException('Product Configuration is not configured in BO.'); } + return $productConfiguration; + } + + private function getEnabledChannelsAttributeData( + ProductConfiguration $productConfiguration, + ProductInterface $product, + array $resource + ): array { if (null === $productConfiguration->getAkeneoEnabledChannelsAttribute()) { throw new NoProductConfigurationException('Product configuration -> Enabled channels is not configured in BO.'); } @@ -107,4 +113,51 @@ public function getEnabledChannelsAttributeData(ProductInterface $product, array throw new NoAttributeResourcesException(\sprintf('Enabled channels attribute not found for product "%s".', $product->getCode())); } + + private function handleByAkeneoEnabledChannelsAttribute( + ProductConfiguration $productConfiguration, + ProductInterface $product, + array $resource + ): void { + $channels = $productConfiguration->getChannelsToEnable(); + if ($channels->count() > 0) { + //Channel configuration section as higher priority. + return; + } + + $enabledChannels = $this->getEnabledChannelsAttributeData($productConfiguration, $product, $resource); + + foreach ($enabledChannels as $enabledChannel) { + $channel = $this->channelRepository->findOneBy(['code' => $enabledChannel]); + if (!$channel instanceof ChannelInterface) { + $this->logger->warning(\sprintf( + 'Channel "%s" could not be activated for product "%s" because the channel was not found in the database.', + $enabledChannel, + $product->getCode() + )); + + continue; + } + + $this->addProductToChannel($product, $channel); + } + } + + private function handleBySyliusConfiguration(ProductConfiguration $productConfiguration, ProductInterface $product): void + { + $channels = $productConfiguration->getChannelsToEnable(); + + if (0 < $channels->count()) { + return; + } + + $this->addProductToChannels($product, $channels); + } + + private function addProductToChannels(ProductInterface $product, iterable $channels): void + { + foreach ($channels as $channel) { + $this->addProductToChannel($product, $channel); + } + } } diff --git a/src/Service/ProductChannelEnablerInterface.php b/src/Service/ProductChannelEnablerInterface.php new file mode 100644 index 00000000..8026db1f --- /dev/null +++ b/src/Service/ProductChannelEnablerInterface.php @@ -0,0 +1,12 @@ +productRepository = $productRepository; diff --git a/src/Task/ProductModel/EnableDisableProductModelsTask.php b/src/Task/ProductModel/EnableDisableProductModelsTask.php index 4d179292..840ae71e 100644 --- a/src/Task/ProductModel/EnableDisableProductModelsTask.php +++ b/src/Task/ProductModel/EnableDisableProductModelsTask.php @@ -13,7 +13,7 @@ use Synolia\SyliusAkeneoPlugin\Payload\Product\ProductPayload; use Synolia\SyliusAkeneoPlugin\Payload\ProductModel\ProductModelPayload; use Synolia\SyliusAkeneoPlugin\Repository\ProductRepository; -use Synolia\SyliusAkeneoPlugin\Service\ProductChannelEnabler; +use Synolia\SyliusAkeneoPlugin\Service\ProductChannelEnablerInterface; use Synolia\SyliusAkeneoPlugin\Task\AkeneoTaskInterface; final class EnableDisableProductModelsTask implements AkeneoTaskInterface @@ -24,7 +24,7 @@ final class EnableDisableProductModelsTask implements AkeneoTaskInterface /** @var \Psr\Log\LoggerInterface */ private $logger; - /** @var \Synolia\SyliusAkeneoPlugin\Service\ProductChannelEnabler */ + /** @var ProductChannelEnablerInterface */ private $productChannelEnabler; /** @var \Doctrine\ORM\EntityManagerInterface */ @@ -33,7 +33,7 @@ final class EnableDisableProductModelsTask implements AkeneoTaskInterface public function __construct( ProductRepository $productRepository, LoggerInterface $akeneoLogger, - ProductChannelEnabler $productChannelEnabler, + ProductChannelEnablerInterface $productChannelEnabler, EntityManagerInterface $entityManager ) { $this->productRepository = $productRepository;