Giter Site home page Giter Site logo

webgriffe / syliusakeneoplugin Goto Github PK

View Code? Open in Web Editor NEW
22.0 6.0 3.0 5.35 MB

Plugin allowing to import data from Akeneo PIM to your Sylius store.

Home Page: https://webgriffe.github.io/SyliusAkeneoPlugin/

License: MIT License

PHP 95.46% JavaScript 0.44% Gherkin 2.44% Twig 1.52% Makefile 0.14%
sylius akeneo-pim symfony akeneo akeneo-connector sylius-plugin

syliusakeneoplugin's Introduction

Sylius logo

Sylius Akeneo Plugin

Plugin allowing to import data from Akeneo PIM to your Sylius store.

Build Status

What does this plugin do?

The SyliusAkeneoPlugin takes care of importing and updating products, product associations and attributes from Akeneo to Sylius.

How can I install the plugin on my Sylius store?

Please, check the documentation at the Installation step.

Where do I start?

First, we recommend that you read the entire documentation. Then you could start to install the plugin and use the basic features it gives such as the abandoned cart. You could also think to suggest some new features that this plugin could add. So, let's start! 🚀

License

This plugin is under the MIT license. See the complete license in the LICENSE file.

Credits

Developed by Webgriffe®.

syliusakeneoplugin's People

Contributors

aleho avatar azambon avatar fabianaromagnoli avatar lruozzi9 avatar lucagallinari avatar mmenozzi avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar

syliusakeneoplugin's Issues

Import metric property on Sylius

Thanks to #32 we could now import metrical attributes on Akeneo to Sylius attributes.
Anyway, at the moment the metrical attributes could not be imported as Sylius generic properties.
For example, if I have a metrical attribute 'Weight' on Akeneo I could import it as a weight attribute, but this would be limiting for the reasons that that attribute would be of type text containing the unit measurement and all the logic of shipping rules must be changed to use that attribute instead of the native property of the product. The same for the length, height, and width properties.

A solution could be to edit the GenericPropertyValueHandler to handle the metrical data type, but it could be risky because of the mixed type returned by the getValue method (it must remain compatible with other properties).

So, the solution that seems to be better is adding a MetricPropertyValueHandler that accepts 'attribute_code_on_akeneo' and 'property_path_on_sylius' to map the metric value of the attribute from Akeneo on the property path specified on Sylius. However, this assumes that the value will be imported in the unit of measurement used in Akeneo.

What do you think @webgriffe/wg-devs, @aleho?

Add retry counter to queue

On busy sites a failure might actually be retryable (deadlocks come to mind) and could already work a few seconds later.

The current implementation will try forever (even for items that are likely to never succeed), which on the other hand makes sense considering that the enqueue command with since-file cannot check for "changed after date X or not yet imported".

In my opinion a retry stategy (something like Symfony's RetryStrategyInterface) might still come in handy.

What do you think?

Attribute options importer

This plugin should provide an attribute options importer out of the box.
Indeed if there are simple select or multi select attributes on Akeneo and those attributes are mapped to the corresponding select attributes on Sylius (with the AttributeValueHandler), an attribute options importer is a must-have to be able to synchronize attributes options.

Taxon association after product is created

What happens if:

  • a product was created in Sylius
  • a new created was created and associated with that product in Akeneo
  • the same taxon (category) was created in Sylius

The sync will update automatically taxon association with the new data?

Can't install in sylius 1.9

Hello, I upgraded my version of Sylius to 1.9 and when I tried to install the SyliusAkeneoPlugin by composer require webgriffe/SyliusAkeneoPlugin , the following Exception is thrown:

Executing script cache:clear [KO]
 [KO]
Script cache:clear returned with error code 255
!!  PHP Fatal error:  Access level to Webgriffe\SyliusAkeneoPlugin\Command\QueueCleanupCommand::SUCCESS must be public (as in class Symfony\Component\Console\Command\Command) in /Users/jorge/Coding/Bitbucket/babyq-shop-sylius/vendor/webgriffe/sylius-akeneo-plugin/src/Command/QueueCleanupCommand.php on line 101
!!  PHP Stack trace:
!!  PHP   1. {main}() /Users/jorge/Coding/Bitbucket/babyq-shop-sylius/bin/console:0
!!  PHP   2. Symfony\Bundle\FrameworkBundle\Console\Application->run() /Users/jorge/Coding/Bitbucket/babyq-shop-sylius/bin/console:38
!!  PHP   3. Symfony\Bundle\FrameworkBundle\Console\Application->doRun() /Users/jorge/Coding/Bitbucket/babyq-shop-sylius/vendor/symfony/console/Application.php:166
!!  PHP   4. Symfony\Bundle\FrameworkBundle\Console\Application->registerCommands() /Users/jorge/Coding/Bitbucket/babyq-shop-sylius/vendor/symfony/framework-bundle/Console/Application.php:74
!!  PHP   5. App\Kernel->boot() /Users/jorge/Coding/Bitbucket/babyq-shop-sylius/vendor/symfony/framework-bundle/Console/Application.php:168
!!  PHP   6. App\Kernel->preBoot() /Users/jorge/Coding/Bitbucket/babyq-shop-sylius/vendor/symfony/http-kernel/Kernel.php:121
!!  PHP   7. App\Kernel->initializeContainer() /Users/jorge/Coding/Bitbucket/babyq-shop-sylius/vendor/symfony/http-kernel/Kernel.php:780
!!  PHP   8. Symfony\Component\DependencyInjection\ContainerBuilder->compile() /Users/jorge/Coding/Bitbucket/babyq-shop-sylius/vendor/symfony/http-kernel/Kernel.php:541
!!  PHP   9. Symfony\Component\DependencyInjection\Compiler\Compiler->compile() /Users/jorge/Coding/Bitbucket/babyq-shop-sylius/vendor/symfony/dependency-injection/ContainerBuilder.php:736
!!  PHP  10. Symfony\Component\DependencyInjection\Compiler\AutowirePass->process() /Users/jorge/Coding/Bitbucket/babyq-shop-sylius/vendor/symfony/dependency-injection/Compiler/Compiler.php:91
!!  PHP  11. Symfony\Component\DependencyInjection\Compiler\AutowirePass->process() /Users/jorge/Coding/Bitbucket/babyq-shop-sylius/vendor/symfony/dependency-injection/Compiler/AutowirePass.php:54
!!  PHP  12. Symfony\Component\DependencyInjection\Compiler\AutowirePass->processValue() /Users/jorge/Coding/Bitbucket/babyq-shop-sylius/vendor/symfony/dependency-injection/Compiler/AbstractRecursivePass.php:46
!!  PHP  13. Symfony\Component\DependencyInjection\Compiler\AutowirePass->doProcessValue() /Users/jorge/Coding/Bitbucket/babyq-shop-sylius/vendor/symfony/dependency-injection/Compiler/AutowirePass.php:72
!!  PHP  14. Symfony\Component\DependencyInjection\Compiler\AutowirePass->processValue() /Users/jorge/Coding/Bitbucket/babyq-shop-sylius/vendor/symfony/dependency-injection/Compiler/AutowirePass.php:103
!!  PHP  15. Symfony\Component\DependencyInjection\Compiler\AutowirePass->processValue() /Users/jorge/Coding/Bitbucket/babyq-shop-sylius/vendor/symfony/dependency-injection/Compiler/AbstractRecursivePass.php:81
!!  PHP  16. Symfony\Component\DependencyInjection\Compiler\AutowirePass->doProcessValue() /Users/jorge/Coding/Bitbucket/babyq-shop-sylius/vendor/symfony/dependency-injection/Compiler/AutowirePass.php:72
!!  PHP  17. Symfony\Component\DependencyInjection\Compiler\AutowirePass->autowireCalls() /Users/jorge/Coding/Bitbucket/babyq-shop-sylius/vendor/symfony/dependency-injection/Compiler/AutowirePass.php:126
!!  PHP  18. Symfony\Component\DependencyInjection\Compiler\AutowirePass->autowireMethod() /Users/jorge/Coding/Bitbucket/babyq-shop-sylius/vendor/symfony/dependency-injection/Compiler/AutowirePass.php:171
!!  PHP  19. Symfony\Component\DependencyInjection\Compiler\AutowirePass->Symfony\Component\DependencyInjection\Compiler\{closure:/Users/jorge/Coding/Bitbucket/babyq-shop-sylius/vendor/symfony/dependency-injection/Compiler/AutowirePass.php:229-241}() /Users/jorge/Coding/Bitbucket/babyq-shop-sylius/vendor/symfony/dependency-injection/Compiler/AutowirePass.php:261
!!  PHP  20. Symfony\Component\DependencyInjection\Exception\AutowiringFailedException->__construct() /Users/jorge/Coding/Bitbucket/babyq-shop-sylius/vendor/symfony/dependency-injection/Compiler/AutowirePass.php:236
!!  PHP  21. Symfony\Component\DependencyInjection\Compiler\AutowirePass->Symfony\Component\DependencyInjection\Compiler\{closure:/Users/jorge/Coding/Bitbucket/babyq-shop-sylius/vendor/symfony/dependency-injection/Compiler/AutowirePass.php:387-389}() /Users/jorge/Coding/Bitbucket/babyq-shop-sylius/vendor/symfony/dependency-injection/Exception/AutowiringFailedException.php:29
!!  PHP  22. Symfony\Component\DependencyInjection\Compiler\AutowirePass->createTypeNotFoundMessage() /Users/jorge/Coding/Bitbucket/babyq-shop-sylius/vendor/symfony/dependency-injection/Compiler/AutowirePass.php:388
!!  PHP  23. Symfony\Component\DependencyInjection\Compiler\AutowirePass->createTypeAlternatives() /Users/jorge/Coding/Bitbucket/babyq-shop-sylius/vendor/symfony/dependency-injection/Compiler/AutowirePass.php:407
!!  PHP  24. Symfony\Component\DependencyInjection\Compiler\AutowirePass->populateAvailableTypes() /Users/jorge/Coding/Bitbucket/babyq-shop-sylius/vendor/symfony/dependency-injection/Compiler/AutowirePass.php:433
!!  PHP  25. Symfony\Component\DependencyInjection\Compiler\AutowirePass->populateAvailableType() /Users/jorge/Coding/Bitbucket/babyq-shop-sylius/vendor/symfony/dependency-injection/Compiler/AutowirePass.php:323
!!  PHP  26. Symfony\Component\DependencyInjection\ContainerBuilder->getReflectionClass() /Users/jorge/Coding/Bitbucket/babyq-shop-sylius/vendor/symfony/dependency-injection/Compiler/AutowirePass.php:337
!!  PHP  27. Symfony\Component\Config\Resource\ClassExistenceResource->isFresh() /Users/jorge/Coding/Bitbucket/babyq-shop-sylius/vendor/symfony/dependency-injection/ContainerBuilder.php:348
!!  PHP  28. class_exists() /Users/jorge/Coding/Bitbucket/babyq-shop-sylius/vendor/symfony/config/Resource/ClassExistenceResource.php:84
!!  PHP  29. spl_autoload_call() /Users/jorge/Coding/Bitbucket/babyq-shop-sylius/vendor/symfony/config/Resource/ClassExistenceResource.php:84
!!  PHP  30. Composer\Autoload\ClassLoader->loadClass() /Users/jorge/Coding/Bitbucket/babyq-shop-sylius/vendor/symfony/config/Resource/ClassExistenceResource.php:84
!!  PHP  31. Composer\Autoload\includeFile() /Users/jorge/Coding/Bitbucket/babyq-shop-sylius/vendor/composer/ClassLoader.php:322

Is it absolutely not possible to install it with that version of Sylius? Or is there any dependencies conflict?

Thanks in advance

Lockable commands

All commands of this plugin should be "lockable" to not overlap. We could use the Symfony's lock component.

Refresh Akeneo API access token when it has expired

Method \Webgriffe\SyliusAkeneoPlugin\ApiClient::authenticatedRequest makes login only if token is not set. But the Akeneo API access token has a lifetime (3600 seconds) and when it is expired the request responds with a 401 error.
If you have hundreds of products on Akeneo, and you run all importers for all products, this is likely to happen. In this case the importer stops with this error:

Screenshot 2021-01-26 at 20 46 41

The ApiClient should handle this case and login again, or even better, according to oauth protocol, il should refresh the access token using the refresh token.

Handle different Akeneo data types in value handlers

Currently there are some value handlers assuming a specific value array. For example all the TVs on the Akeneo demo cannot be imported with this plugin because its variant axe is the attribute display_diagonale which is an Akeneo pim_catalog_metric attribute. In this case the data key in the value array is like {"amount":"-12.78","unit":"KILOWATT"} but the ProductOptionValueHandler assume that this data is a plain string.

The full list of possible data types could be found here: https://api.akeneo.com/documentation/resources.html#product

Can't know the source of a product event

At the moment there's no way to find the source of a sylius.product.* event.

In my use case I'd like to be able to know that the Akeneo importer dispatched it, so I can handle only those (especially ensuring some default values are set on import, which might get overridden by the user).

If you think this would be a good addition, I could provide a PR.

Error importing products without a family set on Akeneo

While importing products without a family set on Akeneo the following error occurs:

There has been an error importing Product entity with identifier XXX. The error was: Argument 2 passed to Webgriffe\SyliusAkeneoPlugin\Product\Importer::addMissingAttributes() must be of the type string, null given

Split TranslatablePropertyValueHandler

The TranslatablePropertyValueHandler currently sets property value on both ProductVariantTranslation and ProductTranslation.

Given the fact that there could be more than one value handler for each Akeneo value, it should be split into two separate value handlers: ProductTranslationPropertyValueHandler and ProductVariantTranslationPropertyValueHandler.

Handle deleted entities or code/identifier change on Akeneo

Currently the enqueue command retrieves, from registered importers, entities modified since a given date and put them into the import queue.

This kind of architecture doesn't allow us to easily tell if a product has been deleted from Akeneo or if it's code/identifier has been changed.

Error importing a new Product with an already existent ProductVariant

Given on Akeneo there is a Product Model with one or more Product Variants and on Sylius those Product Variant have been already imported as simple products before. Trying to import the new Product Model, to have the corresponding configurable product on Sylius where already existent variants are moved under the new parent product, the following error occurs:

A new entity was found through the relationship 'App\Entity\Product\ProductVariant#product' that was not configured to cascade persist operations for entity: . To solve this issue: Either explicitly call EntityManager#persist() on this unknown entity or configure cascade persist this association in the mapping for example @ManyToOne(..,cascade={"persist"})

The culprit seems to be in this line:

https://github.com/webgriffe/SyliusAkeneoPlugin/blob/master/src/ValueHandler/ProductOptionValueHandler.php#L163

Because the add call will flush the entity manager which tries to flush also the Product Variant with the new not-managed associated Product.

That line seems to be unnecessary. Indeed the final Product flush should also persist the new/updated Product Option Values.

Error while installing the plugin

If one tries to install the plugin using composer require as indicated in the documentation with the Symfony Flex enabled, then the following error is generated:

The service "webgriffe_sylius_akeneo.command.queue_cleanup" has a dependency on a non-existent service "webgriffe_sylius_akeneo.manager.queue_item".

As a workaround, one can manually execute steps 2 and 3 of the installation guide, which should solve the problem. But still it would be nice to have the installation succeed without having to do this.

Improve the product status handling by using the new Sylius 1.8 toggleable product variant

Has stated here, currently the product status is set to disabled only if the Akeneo product is disabled and doesn't belong to a parent product model.

The problem is that in Sylius the product status is at product level and not (also) at product variant level; instead in Akeneo the status is only at product level and not at product model level.

So, in Akeneo, you could have only one disabled product variant for a parent product which have several other variants enabled. This situation couldn't be mapped currently on Sylius.

Simplify adding other attribute value handlers

Currently if someone wants to add value handlers to the Webgriffe\SyliusAkeneoPlugin\PriorityValueHandlersResolver has to redefine the whole webgriffe_sylius_akeneo.product.value_handlers_resolver and the friendly configuration at webgriffe_sylius_akeneo.value_handlers is not used anymore.

It should be easier to add more value handlers.

One solution could be to enrich the dependency injection extension to automatically inject value handlers inside the webgriffe_sylius_akeneo.product.value_handlers_resolver with a specific value handler tag.

Import fails trying to create empty translation

Since commit bbaecd1 import fails with:

[Doctrine\DBAL\Exception\NotNullConstraintViolationException]
An exception occurred while executing 'INSERT INTO sylius_product_translation (name, slug, description, meta_keywords, meta_description, short_description, locale, translatable_id) VALUES (?, ?, ?, ?, ?, ?, ?, ?)' with params [null, null, null, null, null, null, "en_US", 3755]:

SQLSTATE[23000]: Integrity constraint violation: 1048 Column 'name' cannot be null

Reverting bbaecd1 "fixes" the problem.

Any ideas what's going on?

Add product to import queue

It would be optimal to have a button on the product pages of the backoffice to add a product to the import queue from Akeneo.

Properly handle import when a Product Model has the same code of a different Product in Akeneo

Currently if on Akeneo there's a Product Model whose code is the same of a different Product which is not a variant of the Product Model itself, the importer puts everything inside the same Product on Sylius.

For example if on Akeneo you have:

  • Product Model A
  • Product A.1 (variant of A)
  • Product A.2 (variant of A)
  • Product A

On Sylius you'll have:

  • Product A
  • Product Variant A (variant of A)
  • Product Variant A.1 (variant of A)
  • Product Variant A.2 (variant of A)

Instead, expected result on Sylius should be:

  • Product A
  • Product Variant A.1 (variant of A)
  • Product Variant A.2 (variant of A)
  • Product ?
  • Product Variant A (variant of ?)

The issue here is that Akeneo have Product Models only for configurable products but Sylius always have Product (which is the Product Model on Akeneo) and Product Variant (which is Product on Akeneo). When the product importer imports a simple Product from Akeneo it creates a the Product and Product Variant on Sylius with the same code. So there would be a code collision between Product on Sylius if on Akeneo a Product Model has the same code of a different Product.

How should we handle this?

Ability to customize which identifiers to enqueue

Currently the responsibility to find which are the identifiers to enqueue is given to the importer which have to implement the method \Webgriffe\SyliusAkeneoPlugin\ImporterInterface::getIdentifiersModifiedSince().

So if one wants to customize that logic (for example adding some kind of filter) he needs to replace the entire importer.

So I suggest to isolate the responsibility of finding identifiers that have been modified since a given date to a dedicated interface.

Handling more than one variant axes

Currently the "direct" parent of a product is created / retrieved when importing products with more than one variant.

Sylius doesn't support the two levels of Akeneo, but it does support multiple options, generating a variant of the combinations.

On import the options are resolved in ProductOptionsResolver by only considering the first tier.
Likewise, in Product\Importer and ProductAssociations\Importer only the "direct" parent of a variant is considered (1st axis variant if 2nd axis) instead of the root product.

We've changed the importers / option resolver to check the parent of a parent and also to import all options locally. This works well because the 2nd tier variantCode matches the Akeneo code anyway.

What's your take on this?
Are you planning on supporting the second Akeneo variant axis level?

Enqueuing all identifiers logic

As stated in #5, currently the only way for an importer to enqueue identifiers is to implement the \Webgriffe\SyliusAkeneoPlugin\ImporterInterface::getIdentifiersModifiedSince() which assumes that you can get from the Akeneo API only those resources modified since a given date.

Unfortunately this is not always true. On the contrary this is true only for products and product models, all other resources cannot be fetched by "updated at" date/time.

So we need a different enqueuing logic.
Based on the fact that all these resources are "catalog structure", they should not change very often. So one solution could be to enqueue all identifiers for this resources.
Doing so will require a change in the webgriffe:akeneo:enqueue CLI command to allow users to have a different cron schedule potentially for every resource/importer (or a completely separate command).

Product model not enqueued if modified

It seems that if someone modify a product model on Akeneo (without changing any variant-specific attribute, only model ones) the related variant products are not enqueued byt the Product importer.

Maybe is because in such situation Akeneo APIs do not return variants (products) as modified since the given date. Only parent product (product model). If this is the case, here:

/**
* {@inheritdoc}
* @psalm-return array<array-key, string>
*/
public function getIdentifiersModifiedSince(\DateTime $sinceDate): array
{
$products = $this->apiClient->findProductsModifiedSince($sinceDate);
$identifiers = [];
foreach ($products as $product) {
Assert::string($product['identifier']);
$identifiers[] = $product['identifier'];
}
return $identifiers;
}

We should also enqueue products of those product models modified since the given date.

ImageValueHandler does not remove downloaded images

ImageValueHandler downloads product images from Akeneo, using method \Webgriffe\SyliusAkeneoPlugin\ApiClient::downloadFile. This method downloads the image files to the system temp dir, but the ImageValueHandler doesn't remove images from temp dir after using them, so that image files pile up and soon or later they end up filling up the disk.

ProductAttribute configuration not complete will throw an error on storing attribute value

The Actual AttributeOptions/Importer will import attributes with configuration property populated by the 'choices' key, as follow:

array (
  'choices' => 
  array (
    'value1' => 
    array (
      'it_IT' => 'Value 1',
    ),
    'value2' => 
    array (
      'it_IT' => 'Value 2',
    ),
    'value3' => 
    array (
      'it_IT' => 'Value 3',
    ),
  ),
)

This will throw an error when trying to store a new product with this attribute and also when trying to edit an existing product with an already defined value from these attributes. The error is the following:
Argument 1 passed to Sylius\Component\Attribute\Model\AttributeValue::setJson() must be of the type array or null, string given, called in AttributeValue.php on line 105
This is due to the attempt to pass, for example, the 'value1' value as an array to the setJson method.

Using the complete configuration generated by Sylius which includes the keys 'multiple', 'min', and 'max' apparently will solve this problem.

array (
  'choices' => 
  array (
    'value1' => 
    array (
      'it_IT' => 'Value 1',
    ),
    'value2' => 
    array (
      'it_IT' => 'Value 2',
    ),
    'value3' => 
    array (
      'it_IT' => 'Value 3',
    ),
  ),
  'multiple' => false,
  'min' => NULL,
  'max' => NULL,
)

To complete this configuration the importer needs to know these configurations by querying the Akeneo WS.

Handle the Akeneo product status (enabled/disabled)

Currently this plugin completely ignores the Akeneo product status (enabled/disabled).

Of course, this status should be mapped with the analog Sylius's product status. The problem is that in Sylius the product status is at product level and not (also) at product variant level; instead in Akeneo the status is only at product level and not at product model level.

So, in Akeneo, you could have only one disabled product variant for a parent product which have several other variants enabled. This situation couldn't be mapped currently on Sylius.

Unable to import metrical product option value

The ProductOptionValueHandler is unable to import a product option matrical value. You can replicate the error by launching the application test and trying to import the product variant TVSAM32 by the Akeneo demo, for example.

Queue items grid in the admin

It would be very useful an admin grid of the queue items especially to examine error messages of not imported items.

Remove existing images

When images are created in Akeneo and transferred via the plugin, they can no longer be removed.
Despite deletion in Akeneo this is still present after an import in Sylius

Handling of common attribute of type "image"

Hey there!
I am dealing with the following situation: In Akeneo I have a product model with a variant of 1 axis. The product model has a common attribute named Image, and the axis has another attribute named ImageVariant.
When I import them to Sylius, the common Image gets imported n times as existent variants.

Shouldn't it get imported only once, as it is a common attribute?

This is how I configured the import of those attributes in webgriffe_sylius_akeneo_plugin.yaml

        image:
            type: 'image'
            options:
                akeneo_attribute_code: 'image'
                sylius_image_type: 'image'        
                
        image_variant:
            type: 'image'
            options:
                akeneo_attribute_code: 'variation_image'
                sylius_image_type: 'variation_image'`

Have I mistaken something in my configuration? Or is it a matter of enhancement of the plugin. Thanks in advance.

Best regards.

Channels resolver per product

If, for whatever reason, an import from a single Akeneo channel should be split for different Sylius channels (e.g. via attribute channel) there's currently no way to have different products land in different channels.

What's your opinion on this?
Shouldn't the ChannelsResolverInterface rather be a single ChannelResolverInterface operating per product instead of on all?

I might be able to draft a PR next week, if you agree.

(This is probably related to #2.)

Wrong (?) taxon handling in product import

Here:

private function handleTaxons(ProductInterface $product, array $akeneoProduct): void
{
$taxons = $this->taxonsResolver->resolve($akeneoProduct);
foreach ($taxons as $taxon) {
if ($product->hasTaxon($taxon)) {
continue;
}
$productTaxon = $this->productTaxonFactory->createNew();
Assert::isInstanceOf($productTaxon, ProductTaxonInterface::class);
/** @var ProductTaxonInterface $productTaxon */
$productTaxon->setTaxon($taxon);
$productTaxon->setPosition(0);
$product->addProductTaxon($productTaxon);
}
}

When handling taxons we only add resolved taxons to the product without removing those that were previously associated.

IMHO it's a bug.

Error on generating slug for three or more products with same name

There is a BUG in ImmutableSlugValueHandler on generating slug for a product with the same name as another.
For example:
If I have three products named "T-shirt banana", the importer will generate a "t-shirt-banana" slug for the first one, "t-shirt-banana-1" for the second one, and "t-shirt-banana-1-2" for the third instead of "t-shirt-banana-2".

Handle multiple Akeneo channels

At the moment there isn't any logic about Akeneo channels. The plugin assumes that there's only one channel on Akeneo. If there was multiple channels some value handlers could throw exceptions.

Special characters in code break API

While I'm not especially fond of special characters in an SKU, if customer requires it they shouldn't break API calls nevertheless.

Currently, an SKU 123#456 will fail:

Client error: `GET http://pim/api/rest/v1/products/123#456` resulted in a `404 Not Found` response:
{"code":404,"message":"Product \"123\" does not exist or you do not have permission to access it."}

Solution might be to simply urlencode() each code or, even better, use the official client.

Is there a plan to switch to it or should I provide a PR for the current implementation?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.