Skip to content

Commit

Permalink
Merge pull request #29 from lruozzi9/enqueue-product
Browse files Browse the repository at this point in the history
Enqueue product
  • Loading branch information
mmenozzi authored Jan 11, 2021
2 parents 5b1c42a + 75be6a1 commit b5f9beb
Show file tree
Hide file tree
Showing 14 changed files with 292 additions and 0 deletions.
16 changes: 16 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,16 @@
bin/console sylius:theme:assets:install
```

6. _Optional_. If you want you can also add the Schedule Akeneo PIM import button in the product's detail and edit page.
Override Sylius template by create a new file in the folder: `templates/bundles/SyliusAdminBundle/Product/_showInShopButton.html.twig`. Copy the content from the original Sylius file and paste it in the new file. Finally, add the button to the bottom of the file.

# ...

<a class="ui labeled icon button green" href="{{ path('webgriffe_sylius_akeneo_product_enqueue', {'productId': product.id }) }}" >
<i class="icon cloud download"></i>
{{ 'webgriffe_sylius_akeneo.ui.enqueue'|trans }}
</a>

## Configuration

First of all you must configure your Akeneo API connection parameters. Edit the `config/packages/webgriffe_sylius_akeneo_plugin.yaml` file by adding the following content:
Expand Down Expand Up @@ -356,6 +366,12 @@ This plugin will also import product associations. It's a zero configuration imp

To actually import data you must first create queue items with the **enqueue command** and then you can import them with the **consume command**.

#### Schedule Akeneo PIM import button

This button allows you to queue a product directly from the admin index page. By adding the product to the queue, it will be updated by the Akeneo PIM at the next consume run.

![Schedule Akeneo PIM import button](schedule-akeneo-import-button.png)

#### Enqueue command

To create queue items you can use the `webgriffe:akeneo:enqueue` console command:
Expand Down
21 changes: 21 additions & 0 deletions features/enqueuing_products.feature
Original file line number Diff line number Diff line change
Expand Up @@ -32,3 +32,24 @@ Feature: Enqueuing products
Then the queue item with identifier "product-1" for the "Product" importer should not be in the Akeneo queue
And the queue item with identifier "product-2" for the "Product" importer should be in the Akeneo queue
And there is a file with name "last-date" that contains "2020-01-25T12:00:00+01:00"

@ui
Scenario: Enqueue a product
Given I am logged in as an administrator
And the store has a product "Braided hat m" with code "braided-hat-m"
When I browse products
And I schedule an Akeneo PIM import for the "braided-hat-m" product
Then I should be notified that it has been successfully enqueued
When I browse Akeneo queue items
Then I should see 1, not imported, queue items in the list

@ui
Scenario: Enqueue a product already enqueued
Given I am logged in as an administrator
And the store has a product "Braided hat l" with code "braided-hat-l"
And there is one item to import with identifier "braided-hat-l" for the "Product" importer in the Akeneo queue
When I browse products
And I schedule an Akeneo PIM import for the "braided-hat-l" product
Then I should be notified that it has been already enqueued
When I browse Akeneo queue items
Then I should see 1, not imported, queue items in the list
Binary file added schedule-akeneo-import-button.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
82 changes: 82 additions & 0 deletions src/Controller/ProductEnqueueController.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
<?php

declare(strict_types=1);

namespace Webgriffe\SyliusAkeneoPlugin\Controller;

use Sylius\Component\Product\Model\ProductInterface;
use Sylius\Component\Product\Repository\ProductRepositoryInterface;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
use Symfony\Contracts\Translation\TranslatorInterface;
use Webgriffe\SyliusAkeneoPlugin\Entity\QueueItem;
use Webgriffe\SyliusAkeneoPlugin\Repository\QueueItemRepositoryInterface;
use Webmozart\Assert\Assert;

final class ProductEnqueueController extends AbstractController
{
/** @var QueueItemRepositoryInterface */
private $queueItemRepository;

/** @var UrlGeneratorInterface */
private $urlGenerator;

/** @var ProductRepositoryInterface */
private $productRepository;

/**
* ProductEnqueueController constructor.
*/
public function __construct(QueueItemRepositoryInterface $queueItemRepository, ProductRepositoryInterface $productRepository, UrlGeneratorInterface $urlGenerator)
{
$this->queueItemRepository = $queueItemRepository;
$this->urlGenerator = $urlGenerator;
$this->productRepository = $productRepository;
}

public function enqueueAction(int $productId): Response
{
/** @var TranslatorInterface $translator */
$translator = $this->get('translator');
/** @var ProductInterface|null $product */
$product = $this->productRepository->find($productId);
if ($product === null) {
throw new NotFoundHttpException('Product not found');
}

/** @var array $productEnqueued */
$productEnqueued = $this->queueItemRepository->findBy([
'akeneoIdentifier' => $product->getCode(),
'akeneoEntity' => 'Product',
'importedAt' => null,
]);
if (count($productEnqueued) > 0) {
$this->addFlash(
'error',
$translator->trans('webgriffe_sylius_akeneo.ui.product_already_enqueued')
);

return $this->redirectToRoute('sylius_admin_product_index');
}

/** @var ?string $productCode */
$productCode = $product->getCode();

Assert::notNull($productCode);

$queueItem = new QueueItem();
$queueItem->setAkeneoEntity('Product');
$queueItem->setAkeneoIdentifier($productCode);
$queueItem->setCreatedAt(new \DateTime());
$this->queueItemRepository->add($queueItem);

$this->addFlash(
'success',
$translator->trans('webgriffe_sylius_akeneo.ui.enqueued_success')
);

return $this->redirectToRoute('sylius_admin_product_index');
}
}
4 changes: 4 additions & 0 deletions src/Resources/config/admin_routing.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,7 @@ webgriffe_sylius_akeneo_admin_queue_item:
index:
icon: 'cloud download'
type: sylius.resource

webgriffe_sylius_akeneo_product_enqueue:
controller: webgriffe_sylius_akeneo_plugin.controller.product_enqueue_controller:enqueueAction
path: product/{productId}/enqueue
18 changes: 18 additions & 0 deletions src/Resources/config/config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@ sylius_resource:
repository: Webgriffe\SyliusAkeneoPlugin\Doctrine\ORM\QueueItemRepository

sylius_grid:
templates:
action:
enqueueProduct: '@WebgriffeSyliusAkeneoPlugin\Product\Grid\Action\enqueue.html.twig'
grids:
webgriffe_sylius_akeneo_admin_queue_item:
driver:
Expand Down Expand Up @@ -54,3 +57,18 @@ sylius_grid:
actions:
main: ~
item: ~

sylius_admin_product:
actions:
item:
enqueue:
type: enqueueProduct
label: webgriffe_sylius_akeneo.ui.enqueue
options:
link:
route: webgriffe_sylius_akeneo_product_enqueue
parameters:
productId: resource.id
icon: cloud download
color: violet

7 changes: 7 additions & 0 deletions src/Resources/config/services.xml
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,13 @@
<service id="webgriffe_sylius_akeneo.slugify" class="Cocur\Slugify\Slugify" />
<service id="Cocur\Slugify\SlugifyInterface" alias="webgriffe_sylius_akeneo.slugify" />

<service id="webgriffe_sylius_akeneo_plugin.controller.product_enqueue_controller" class="Webgriffe\SyliusAkeneoPlugin\Controller\ProductEnqueueController" >
<tag name="controller.service_arguments"/>
<argument type="service" id='webgriffe_sylius_akeneo_plugin.repository.queue_item' />
<argument type="service" id="sylius.repository.product" />
<argument type="service" id="router.default" />
</service>

<service id="webgriffe_sylius_akeneo.temporary_file_manager" class="Webgriffe\SyliusAkeneoPlugin\TemporaryFilesManager">
<argument type="service" id="filesystem" />
<argument type="service">
Expand Down
5 changes: 5 additions & 0 deletions src/Resources/translations/messages.en.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,8 @@ webgriffe_sylius_akeneo:
imported_yes: Yes, at %date%
imported_no: No
error_message: Error message
enqueue: Schedule Akeneo PIM import
enqueued_success: Akeneo PIM product import has been successfully scheduled
product_not_exist: Product not found
product_already_enqueued: Akeneo PIM import for this product has been already scheduled before
product_without_code: Product does not have code
5 changes: 5 additions & 0 deletions src/Resources/translations/messages.it.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,8 @@ webgriffe_sylius_akeneo:
imported_yes: Si, il %date%
imported_no: No
error_message: Messaggio d'errore
enqueue: Programma importazione da Akeneo PIM
enqueued_success: L'importazione del prodotto da Akeneo PIM è stata correttamente programmata
product_not_exist: Prodotto non trovato
product_already_enqueued: L'importazione del prodotto da Akeneo PIM è già stata programmata precedentemente
product_without_code: Prodotto senza codice
5 changes: 5 additions & 0 deletions src/Resources/views/Product/Grid/Action/enqueue.html.twig
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{% import '@SyliusUi/Macro/buttons.html.twig' as buttons %}

{% set path = options.link.url|default(path(options.link.route, options.link.parameters)) %}

{{ buttons.default(path, action.label, null, options.icon, options.color) }}
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
{% set enabledChannels = product.channels|filter(channel => channel.enabled == true) %}

{% if sylius_bundle_loaded_checker('SyliusShopBundle') %}
{% if not product.enabled or enabledChannels|length < 1 %}
<a class="ui labeled icon button disabled" href="#">
<i class="angle right icon"></i>
{{ 'sylius.ui.show_product_in_shop_page'|trans }}
</a>
{% elseif enabledChannels|length > 1 %}
<div class="ui floating dropdown labeled icon button">
<i class="share alternate icon"></i>
<span class="text">
{{ 'sylius.ui.show_product_in_shop_page'|trans }}
</span>
<div class="menu">
<div class="scrolling menu">
{% for channel in enabledChannels %}
{% set url = channel.hostname is not null ? 'http://' ~ channel.hostname ~ path('sylius_shop_product_show', {'slug': product.slug, '_locale': channel.defaultLocale.code}) : url('sylius_shop_product_show', {'slug': product.slug, '_locale': channel.defaultLocale.code}) %}
<a href="{{ url|raw }}" class="item" target="_blank">
<i class="angle right icon"></i>
{{ 'sylius.ui.show_in'|trans }}
{{ channel.name }} ({{ channel.code }})
</a>
{% endfor %}
</div>
</div>
</div>
{% else %}
{% for channel in enabledChannels %}
{% set url = channel.hostname is not null ? 'http://' ~ channel.hostname ~ path('sylius_shop_product_show', {'slug': product.slug, '_locale': channel.defaultLocale.code}) : url('sylius_shop_product_show', {'slug': product.slug, '_locale': channel.defaultLocale.code}) %}
<a class="ui labeled icon button" href="{{ url|raw }}" target="_blank">
<i class="angle right icon"></i>
{{ 'sylius.ui.show_product_in_shop_page'|trans }}
</a>
{% endfor %}
{% endif %}
{% endif %}

<a class="ui labeled icon button violet" href="{{ path('webgriffe_sylius_akeneo_product_enqueue', {'productId': product.id }) }}" >
<i class="icon cloud download"></i>
{{ 'webgriffe_sylius_akeneo.ui.enqueue'|trans }}
</a>
67 changes: 67 additions & 0 deletions tests/Behat/Context/Ui/Admin/ManagingProductsContext.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
<?php

declare(strict_types=1);

namespace Tests\Webgriffe\SyliusAkeneoPlugin\Behat\Context\Ui\Admin;

use Behat\Behat\Context\Context;
use Behat\Mink\Element\NodeElement;
use Sylius\Behat\NotificationType;
use Sylius\Behat\Page\Admin\Product\IndexPageInterface;
use Sylius\Behat\Service\Helper\JavaScriptTestHelperInterface;
use Sylius\Behat\Service\NotificationCheckerInterface;

final class ManagingProductsContext implements Context
{
private const SCHEDULE_AKENEO_PIM_IMPORT = 'Schedule Akeneo PIM import';

/** @var IndexPageInterface */
private $indexPage;

/** @var JavaScriptTestHelperInterface */
private $testHelper;

/** @var NotificationCheckerInterface */
private $notificationChecker;

/**
* ProductItems constructor.
*/
public function __construct(IndexPageInterface $indexPage, JavaScriptTestHelperInterface $testHelper, NotificationCheckerInterface $notificationChecker)
{
$this->indexPage = $indexPage;
$this->testHelper = $testHelper;
$this->notificationChecker = $notificationChecker;
}

/**
* @When /^I schedule an Akeneo PIM import for the "([^"]*)" product$/
*/
public function scheduleAnAkeneoPimImportForTheProduct($code)
{
/** @var NodeElement $actionsNodeProduct */
$actionsNodeProduct = $this->indexPage->getActionsForResource(['code' => $code]);

$actionsNodeProduct->clickLink(self::SCHEDULE_AKENEO_PIM_IMPORT);
}

/**
* @Then I should be notified that it has been successfully enqueued
*/
public function iShouldBeNotifiedThatItHasBeenSuccessfullyEnqueued()
{
$this->testHelper->waitUntilNotificationPopups(
$this->notificationChecker, NotificationType::success(), 'Akeneo PIM product import has been successfully scheduled'
);
}

/**
* @Given /^I should be notified that it has been already enqueued$/
*/
public function iShouldBeNotifiedThatItHasBeenAlreadyEnqueued()
{
$this->testHelper->waitUntilNotificationPopups(
$this->notificationChecker, NotificationType::success(), 'Akeneo PIM import for this product has been already scheduled before'
);
}
}
6 changes: 6 additions & 0 deletions tests/Behat/Resources/services.xml
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,12 @@
<argument type="service" id="webgriffe_sylius_akeneo.behat.page.admin.queue_item.index" />
</service>

<service id="webgriffe_sylius_akeneo.behat.context.ui.admin.managing_products" class="Tests\Webgriffe\SyliusAkeneoPlugin\Behat\Context\Ui\Admin\ManagingProductsContext">
<argument type="service" id="sylius.behat.page.admin.product.index" />
<argument type="service" id="sylius.behat.java_script_test_helper" />
<argument type="service" id="sylius.behat.notification_checker" />
</service>

<service id="webgriffe_sylius_akeneo.behat.page.admin.queue_item.index" parent="sylius.behat.page.admin.crud.index" class="Tests\Webgriffe\SyliusAkeneoPlugin\Behat\Page\Admin\QueueItem\IndexPage" public="false">
<argument type="string">webgriffe_sylius_akeneo_admin_queue_item_index</argument>
</service>
Expand Down
14 changes: 14 additions & 0 deletions tests/Behat/Resources/suites.yml
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,20 @@ default:
filters:
tags: "@enqueuing_products && @cli"

ui_enqueuing_products:
contexts:
- sylius.behat.context.hook.doctrine_orm

- sylius.behat.context.setup.admin_security
- sylius.behat.context.setup.product
- webgriffe_sylius_akeneo.behat.context.setup.queue

- sylius.behat.context.ui.admin.managing_products
- webgriffe_sylius_akeneo.behat.context.ui.admin.managing_products
- webgriffe_sylius_akeneo.behat.context.ui.admin.managing_queue_items
filters:
tags: "@enqueuing_products && @ui"

cli_enqueuing_products_associations:
contexts:
- sylius.behat.context.hook.doctrine_orm
Expand Down

0 comments on commit b5f9beb

Please sign in to comment.