Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Handle metrical and boolean attribute types as variant axis (#106) #132

Merged
merged 7 commits into from
May 23, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
182 changes: 156 additions & 26 deletions spec/ValueHandler/ProductOptionValueHandlerSpec.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

use Doctrine\Common\Collections\ArrayCollection;
use PhpSpec\ObjectBehavior;
use RuntimeException;
use Sylius\Component\Core\Model\ProductInterface;
use Sylius\Component\Core\Model\ProductVariantInterface;
use Sylius\Component\Product\Model\ProductOptionInterface;
Expand All @@ -15,6 +16,7 @@
use Sylius\Component\Resource\Factory\FactoryInterface;
use Sylius\Component\Resource\Repository\RepositoryInterface;
use Sylius\Component\Resource\Translation\Provider\TranslationLocaleProviderInterface;
use Symfony\Contracts\Translation\TranslatorInterface;
use Webgriffe\SyliusAkeneoPlugin\ApiClientInterface;
use Webgriffe\SyliusAkeneoPlugin\ValueHandler\ProductOptionValueHandler;
use Webgriffe\SyliusAkeneoPlugin\ValueHandlerInterface;
Expand Down Expand Up @@ -45,13 +47,21 @@ function let(
ProductOptionValueInterface $productOptionValue,
ProductOptionValueTranslationInterface $englishProductOptionValueTranslation,
ProductOptionValueTranslationInterface $italianProductOptionValueTranslation,
TranslationLocaleProviderInterface $translationLocaleProvider
TranslationLocaleProviderInterface $translationLocaleProvider,
TranslatorInterface $translator,
ProductOptionValueInterface $existentProductOptionValue
) {
$productVariant->getCode()->willReturn(self::VARIANT_CODE);
$productVariant->getProduct()->willReturn($product);
$product->getCode()->willReturn(self::PRODUCT_CODE);
$product->getOptions()->willReturn(new ArrayCollection([$productOption->getWrappedObject()]));
$productOption->getCode()->willReturn(self::OPTION_CODE);
$apiClient->findAttribute(self::OPTION_CODE)->willReturn(
[
'code' => self::OPTION_CODE,
'type' => 'pim_catalog_simpleselect'
]
);
$apiClient
->findAttributeOption(self::OPTION_CODE, self::VALUE_CODE)
->willReturn(
Expand All @@ -72,48 +82,51 @@ function let(
$englishProductOptionValueTranslation->getLocale()->willReturn('en_US');
$translationLocaleProvider->getDefinedLocalesCodes()->willReturn(['en_US', 'it_IT']);

$productOptionValueRepository->findOneBy(['code' => self::OPTION_CODE . '_' . self::VALUE_CODE])->willReturn($existentProductOptionValue);

$this->beConstructedWith(
$apiClient,
$productOptionRepository,
$productOptionValueFactory,
$productOptionValueTranslationFactory,
$productOptionValueRepository,
$translationLocaleProvider
$translationLocaleProvider,
$translator
);
}

function it_is_initializable()
public function it_is_initializable(): void
{
$this->shouldHaveType(ProductOptionValueHandler::class);
}

function it_implements_value_handler_interface()
public function it_implements_value_handler_interface(): void
{
$this->shouldHaveType(ValueHandlerInterface::class);
}

function it_supports_product_variant_as_subject(ProductVariantInterface $productVariant)
public function it_supports_product_variant_as_subject(ProductVariantInterface $productVariant)
{
$this->supports($productVariant, self::OPTION_CODE, [])->shouldReturn(true);
}

function it_does_not_support_other_type_of_subject()
public function it_does_not_support_other_type_of_subject(): void
{
$this->supports(new \stdClass(), self::OPTION_CODE, [])->shouldReturn(false);
}

function it_supports_option_code_of_parent_product(ProductVariantInterface $productVariant)
public function it_supports_option_code_of_parent_product(ProductVariantInterface $productVariant): void
{
$this->supports($productVariant, self::OPTION_CODE, [])->shouldReturn(true);
}

function it_does_not_support_different_attribute_than_option_code_of_parent_product(
public function it_does_not_support_different_attribute_than_option_code_of_parent_product(
ProductVariantInterface $productVariant
) {
): void {
$this->supports($productVariant, 'other-attribute', [])->shouldReturn(false);
}

function it_throws_exception_during_handle_when_subject_is_not_product_variant()
public function it_throws_exception_during_handle_when_subject_is_not_product_variant(): void
{
$this
->shouldThrow(
Expand All @@ -128,9 +141,9 @@ function it_throws_exception_during_handle_when_subject_is_not_product_variant()
->during('handle', [new \stdClass(), self::OPTION_CODE, []]);
}

function it_throws_exception_during_handle_when_value_has_an_invalid_number_of_values(
public function it_throws_exception_during_handle_when_value_has_an_invalid_number_of_values(
ProductVariantInterface $productVariant
) {
): void {
$value = [
[
'scope' => null,
Expand All @@ -145,7 +158,7 @@ function it_throws_exception_during_handle_when_value_has_an_invalid_number_of_v
];

$this->shouldThrow(
new \RuntimeException(
new RuntimeException(
sprintf(
'Cannot handle option value on Akeneo product "%s", the option of the parent product "%s" is ' .
'"%s". More than one value is set for this attribute on Akeneo but this handler only supports ' .
Expand All @@ -158,10 +171,37 @@ function it_throws_exception_during_handle_when_value_has_an_invalid_number_of_v
)->during('handle', [$productVariant, self::OPTION_CODE, $value]);
}

function it_throws_an_exception_during_handle_if_attribute_option_does_not_exists_on_akeneo(
public function it_throws_an_exception_during_handle_if_attribute_does_not_exists_on_akeneo(
ProductVariantInterface $productVariant,
ApiClientInterface $apiClient
) {
): void {
$value = [
[
'scope' => null,
'locale' => null,
'data' => self::VALUE_CODE,
],
];
$apiClient->findAttribute(self::OPTION_CODE)->willReturn(null);

$this->shouldThrow(
new RuntimeException(
sprintf(
'Cannot handle option value on Akeneo product "%s", the option of the parent product "%s" is ' .
'"%s". The attribute "%s" was not found on Akeneo.',
self::VARIANT_CODE,
self::PRODUCT_CODE,
self::OPTION_CODE,
self::OPTION_CODE,
)
)
)->during('handle', [$productVariant, self::OPTION_CODE, $value]);
}

public function it_throws_an_exception_during_handle_if_attribute_option_does_not_exists_on_akeneo(
ProductVariantInterface $productVariant,
ApiClientInterface $apiClient
): void {
$value = [
[
'scope' => null,
Expand All @@ -172,7 +212,7 @@ function it_throws_an_exception_during_handle_if_attribute_option_does_not_exist
$apiClient->findAttributeOption(self::OPTION_CODE, self::VALUE_CODE)->willReturn(null);

$this->shouldThrow(
new \RuntimeException(
new RuntimeException(
sprintf(
'Cannot handle option value on Akeneo product "%s", the option of the parent product "%s" is ' .
'"%s". The option value for this variant is "%s" but there is no such option on Akeneo.',
Expand All @@ -185,10 +225,10 @@ function it_throws_an_exception_during_handle_if_attribute_option_does_not_exist
)->during('handle', [$productVariant, self::OPTION_CODE, $value]);
}

function it_throws_an_exception_if_product_option_does_not_exists_on_sylius(
public function it_throws_an_exception_if_product_option_does_not_exists_on_sylius(
ProductVariantInterface $productVariant,
ProductOptionRepositoryInterface $productOptionRepository
) {
): void {
$value = [
[
'scope' => null,
Expand All @@ -199,7 +239,7 @@ function it_throws_an_exception_if_product_option_does_not_exists_on_sylius(
$productOptionRepository->findOneBy(['code' => self::OPTION_CODE])->willReturn(null);

$this->shouldThrow(
new \RuntimeException(
new RuntimeException(
sprintf(
'Cannot import Akeneo product "%s", the option "%s" is not set on the parent product "%s".',
self::VARIANT_CODE,
Expand All @@ -210,21 +250,22 @@ function it_throws_an_exception_if_product_option_does_not_exists_on_sylius(
)->during('handle', [$productVariant, self::OPTION_CODE, $value]);
}

function it_creates_product_option_value_from_factory_with_all_translations_if_does_not_already_exists(
public function it_creates_product_option_value_from_factory_with_all_translations_if_does_not_already_exists(
ProductVariantInterface $productVariant,
ProductOptionValueInterface $productOptionValue,
ProductOptionValueTranslationInterface $englishProductOptionValueTranslation,
ProductOptionValueTranslationInterface $italianProductOptionValueTranslation,
ProductOptionInterface $productOption,
RepositoryInterface $productOptionValueRepository
) {
): void {
$value = [
[
'scope' => null,
'locale' => null,
'data' => self::VALUE_CODE,
],
];
$productOptionValueRepository->findOneBy(['code' => self::OPTION_CODE . '_' . self::VALUE_CODE])->willReturn(null);
$productVariant->hasOptionValue($productOptionValue)->willReturn(false);

$this->handle($productVariant, self::OPTION_CODE, $value);
Expand All @@ -240,21 +281,20 @@ function it_creates_product_option_value_from_factory_with_all_translations_if_d
$productVariant->addOptionValue($productOptionValue)->shouldHaveBeenCalled();
}

function it_updates_existing_product_option_value_and_all_translations(
public function it_updates_existing_product_option_value_and_all_translations(
ProductVariantInterface $productVariant,
RepositoryInterface $productOptionValueRepository,
ProductOptionValueInterface $existentProductOptionValue,
ProductOptionValueTranslationInterface $englishProductOptionValue,
ProductOptionValueTranslationInterface $italianProductOptionValue
) {
): void {
$value = [
[
'scope' => null,
'locale' => null,
'data' => self::VALUE_CODE,
],
];
$productOptionValueRepository->findOneBy(['code' => self::OPTION_CODE . '_' . self::VALUE_CODE])->willReturn($existentProductOptionValue);
$englishProductOptionValue->getLocale()->willReturn('en_US');
$italianProductOptionValue->getLocale()->willReturn('it_IT');
$existentProductOptionValue->getTranslation('en_US')->willReturn($englishProductOptionValue);
Expand All @@ -269,7 +309,7 @@ function it_updates_existing_product_option_value_and_all_translations(
$italianProductOptionValue->setValue(self::IT_LABEL)->shouldHaveBeenCalled();
}

function it_skips_locale_not_defined_on_sylius(
public function it_skips_locale_not_defined_on_sylius(
ProductVariantInterface $productVariant,
ProductOptionValueInterface $productOptionValue,
ProductOptionValueTranslationInterface $englishProductOptionValueTranslation,
Expand All @@ -278,14 +318,15 @@ function it_skips_locale_not_defined_on_sylius(
RepositoryInterface $productOptionValueRepository,
ApiClientInterface $apiClient,
FactoryInterface $productOptionValueTranslationFactory
) {
): void {
$value = [
[
'scope' => null,
'locale' => null,
'data' => self::VALUE_CODE,
],
];
$productOptionValueRepository->findOneBy(['code' => self::OPTION_CODE . '_' . self::VALUE_CODE])->willReturn(null);
$productVariant->hasOptionValue($productOptionValue)->willReturn(false);
$apiClient
->findAttributeOption(self::OPTION_CODE, self::VALUE_CODE)
Expand Down Expand Up @@ -313,4 +354,93 @@ function it_skips_locale_not_defined_on_sylius(
$productVariant->addOptionValue($productOptionValue)->shouldHaveBeenCalled();
$productOptionValueTranslationFactory->createNew()->shouldHaveBeenCalledOnce();
}

public function it_supports_product_option_metrical_value(
ProductVariantInterface $productVariant,
ProductOptionValueInterface $productOptionValue,
ProductOptionValueTranslationInterface $englishProductOptionValueTranslation,
ProductOptionValueTranslationInterface $italianProductOptionValueTranslation,
ProductOptionInterface $productOption,
RepositoryInterface $productOptionValueRepository,
ApiClientInterface $apiClient,
FactoryInterface $productOptionValueTranslationFactory,
TranslatorInterface $translator
): void {
$apiClient->findAttribute(self::OPTION_CODE)->willReturn(
[
'code' => self::OPTION_CODE,
'type' => 'pim_catalog_metric'
]
);
$value = [
[
'scope' => null,
'locale' => null,
'data' => [
'amount' => '250.0000',
'unit' => 'CUBIC_CENTIMETER',
],
],
];
$translator->trans('webgriffe_sylius_akeneo.ui.metric_amount_unit', ['unit' => 'CUBIC_CENTIMETER', 'amount' => 250.0000], null, 'en_US')->shouldBeCalledOnce()->willReturn('250 cm3');
$translator->trans('webgriffe_sylius_akeneo.ui.metric_amount_unit', ['unit' => 'CUBIC_CENTIMETER', 'amount' => 250.0000], null, 'it_IT')->shouldBeCalledOnce()->willReturn('250 cm3');
$productVariant->hasOptionValue($productOptionValue)->willReturn(false);
$productOptionValueRepository->findOneBy(['code' => 'option-code_2500000_CUBIC_CENTIMETER'])->willReturn(null);

$this->handle($productVariant, self::OPTION_CODE, $value);

$productOptionValue->setCode('option-code_2500000_CUBIC_CENTIMETER')->shouldHaveBeenCalled();
$productOptionValue->setOption($productOption)->shouldHaveBeenCalled();
$productOption->addValue($productOptionValue)->shouldHaveBeenCalled();
$englishProductOptionValueTranslation->setValue('250 cm3')->shouldHaveBeenCalled();
$italianProductOptionValueTranslation->setLocale('it_IT')->shouldHaveBeenCalled();
$italianProductOptionValueTranslation->setValue('250 cm3')->shouldHaveBeenCalled();
$productOptionValue->addTranslation($englishProductOptionValueTranslation)->shouldHaveBeenCalled();
$productOptionValue->addTranslation($italianProductOptionValueTranslation)->shouldHaveBeenCalled();
$productVariant->addOptionValue($productOptionValue)->shouldHaveBeenCalled();
$productOptionValueTranslationFactory->createNew()->shouldHaveBeenCalledOnce();
}

public function it_supports_product_option_boolean_value(
ProductVariantInterface $productVariant,
ProductOptionValueInterface $productOptionValue,
ProductOptionValueTranslationInterface $englishProductOptionValueTranslation,
ProductOptionValueTranslationInterface $italianProductOptionValueTranslation,
ProductOptionInterface $productOption,
RepositoryInterface $productOptionValueRepository,
ApiClientInterface $apiClient,
FactoryInterface $productOptionValueTranslationFactory,
TranslatorInterface $translator
): void {
$apiClient->findAttribute(self::OPTION_CODE)->willReturn(
[
'code' => self::OPTION_CODE,
'type' => 'pim_catalog_boolean'
]
);
$value = [
[
'scope' => null,
'locale' => null,
'data' => true,
],
];
$translator->trans('sylius.ui.yes_label', [], null, 'en_US')->shouldBeCalledOnce()->willReturn('Yes');
$translator->trans('sylius.ui.yes_label', [], null, 'it_IT')->shouldBeCalledOnce()->willReturn('Si');
$productVariant->hasOptionValue($productOptionValue)->willReturn(false);
$productOptionValueRepository->findOneBy(['code' => 'option-code_1'])->willReturn(null);

$this->handle($productVariant, self::OPTION_CODE, $value);

$productOptionValue->setCode('option-code_1')->shouldHaveBeenCalled();
$productOptionValue->setOption($productOption)->shouldHaveBeenCalled();
$productOption->addValue($productOptionValue)->shouldHaveBeenCalled();
$englishProductOptionValueTranslation->setValue('Yes')->shouldHaveBeenCalled();
$italianProductOptionValueTranslation->setLocale('it_IT')->shouldHaveBeenCalled();
$italianProductOptionValueTranslation->setValue('Si')->shouldHaveBeenCalled();
$productOptionValue->addTranslation($englishProductOptionValueTranslation)->shouldHaveBeenCalled();
$productOptionValue->addTranslation($italianProductOptionValueTranslation)->shouldHaveBeenCalled();
$productVariant->addOptionValue($productOptionValue)->shouldHaveBeenCalled();
$productOptionValueTranslationFactory->createNew()->shouldHaveBeenCalledOnce();
}
}
1 change: 1 addition & 0 deletions src/DependencyInjection/WebgriffeSyliusAkeneoExtension.php
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,7 @@ final class WebgriffeSyliusAkeneoExtension extends AbstractResourceExtension imp
'$productOptionValueTranslationFactory' => 'sylius.factory.product_option_value_translation',
'$productOptionValueRepository' => 'sylius.repository.product_option_value',
'$translationLocaleProvider' => 'sylius.translation_locale_provider.admin',
'$translator' => 'translator',
],
],
'translatable_property' => [
Expand Down
Loading