diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..485dee6 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +.idea diff --git a/Api/Pimcore/PimcoreAttributeMapperInterface.php b/Api/Pimcore/PimcoreAttributeMapperInterface.php index 673c247..71a89fb 100644 --- a/Api/Pimcore/PimcoreAttributeMapperInterface.php +++ b/Api/Pimcore/PimcoreAttributeMapperInterface.php @@ -33,6 +33,11 @@ interface PimcoreAttributeMapperInterface */ const WYSIWYG= 'wysiwyg'; + /** + * Pimcore quantityValue type + */ + const QVALUE= 'quantityValue'; + /** * Pimcore object type object */ diff --git a/CHANGELOG.md b/CHANGELOG.md index d48d4f5..052a02a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,24 @@ +1.0.8.1 +============= +- add missing data transformator for a quantityValue type attribute + +1.0.8 +============= +- add quantity value strategy type + +1.0.7 +============= +* add price override configuration `configuration/prices/is_override_enabled`. If yes then price from Pimcore will override current price, otherwise price will be set only on the first one. + +1.0.6.0 +============= +* now it is possible to configure attribute data from a Pimcore. Additional informations kept in 'attr_conf' key in attribute will be merged and override default configuration of an attribute. `\Divante\PimcoreIntegration\Model\Catalog\Product\Attribute\Creator\Strategy\AbstractStrategy::getMergedConfig` + +1.0.5.5 +============= +* add .gitignore +* update console commands to be compatible with 2.3.x + 1.0.5.4 ============= * GitHub PR: @@ -19,4 +40,4 @@ 1.0.4.13 ============= -* Initial commit \ No newline at end of file +* Initial commit diff --git a/Console/Command/AssetsImportCommand.php b/Console/Command/AssetsImportCommand.php index 2fcfa03..fb3c332 100644 --- a/Console/Command/AssetsImportCommand.php +++ b/Console/Command/AssetsImportCommand.php @@ -76,7 +76,7 @@ protected function execute(InputInterface $input, OutputInterface $output) // fail gracefully } - $this->registry->register('isSecureArea', true); + $this->registry->register('isSecureArea', true, true); $start = $this->getCurrentMs(); diff --git a/Console/Command/CategoryImportCommand.php b/Console/Command/CategoryImportCommand.php index 5793f4c..5a5cc97 100644 --- a/Console/Command/CategoryImportCommand.php +++ b/Console/Command/CategoryImportCommand.php @@ -83,7 +83,7 @@ protected function execute(InputInterface $input, OutputInterface $output) // fail gracefully } - $this->registry->register('isSecureArea', true); + $this->registry->register('isSecureArea', true, true); $start = $this->getCurrentMs(); diff --git a/Console/Command/ProductImportCommand.php b/Console/Command/ProductImportCommand.php index cad4b5f..bd66449 100644 --- a/Console/Command/ProductImportCommand.php +++ b/Console/Command/ProductImportCommand.php @@ -82,7 +82,7 @@ protected function execute(InputInterface $input, OutputInterface $output) // fail gracefully } - $this->registry->register('isSecureArea', true); + $this->registry->register('isSecureArea', true, true); $start = $this->getCurrentMs(); diff --git a/Model/Catalog/Product/Attribute/Creator/Strategy/AbstractStrategy.php b/Model/Catalog/Product/Attribute/Creator/Strategy/AbstractStrategy.php index 5d130f3..2f8a8f6 100644 --- a/Model/Catalog/Product/Attribute/Creator/Strategy/AbstractStrategy.php +++ b/Model/Catalog/Product/Attribute/Creator/Strategy/AbstractStrategy.php @@ -37,27 +37,6 @@ abstract class AbstractStrategy implements AttributeCreationStrategyInterface */ protected $code; - /** - * @var array - */ - protected static $defaultAttrConfig = [ - 'backend' => '', - 'frontend' => '', - 'input' => 'text', - 'class' => '', - 'source' => '', - 'global' => ScopedAttributeInterface::SCOPE_STORE, - 'visible' => true, - 'required' => false, - 'user_defined' => true, - 'searchable' => true, - 'filterable' => true, - 'comparable' => true, - 'visible_on_front' => true, - 'used_in_product_listing' => true, - 'unique' => false, - ]; - /** * AbstractStrategy constructor. * @@ -77,4 +56,43 @@ public function __construct( $this->attrData = $attrData; $this->code = $code; } + + /** + * @param array $base + * + * @return array + */ + public function getMergedConfig(array $base = []): array + { + return array_merge($this->getDefaultAttributeConfig(), $base, $this->attrData['attr_conf'] ?? []); + } + + /** + * @return array + */ + abstract public function getBaseAttrConfig(): array; + + /** + * @return array + */ + public function getDefaultAttributeConfig(): array + { + return [ + 'backend' => '', + 'frontend' => '', + 'input' => 'text', + 'class' => '', + 'source' => '', + 'global' => ScopedAttributeInterface::SCOPE_STORE, + 'visible' => true, + 'required' => false, + 'user_defined' => true, + 'searchable' => true, + 'filterable' => true, + 'comparable' => true, + 'visible_on_front' => true, + 'used_in_product_listing' => true, + 'unique' => false, + ]; + } } diff --git a/Model/Catalog/Product/Attribute/Creator/Strategy/DatetimeStrategy.php b/Model/Catalog/Product/Attribute/Creator/Strategy/DatetimeStrategy.php index f4bd98c..827d3df 100644 --- a/Model/Catalog/Product/Attribute/Creator/Strategy/DatetimeStrategy.php +++ b/Model/Catalog/Product/Attribute/Creator/Strategy/DatetimeStrategy.php @@ -22,17 +22,26 @@ class DatetimeStrategy extends AbstractStrategy public function execute(): int { $eavSetup = $this->eavSetupFactory->create(); + $eavSetup->addAttribute( Product::ENTITY, $this->code, - array_merge(self::$defaultAttrConfig, [ - 'type' => 'datetime', - 'label' => $this->attrData['label'], - 'input' => 'date', - 'backend' => Datetime::class, - ]) + $this->getMergedConfig($this->getBaseAttrConfig()) ); return $eavSetup->getAttributeId(Product::ENTITY, $this->code); } + + /** + * @return array + */ + public function getBaseAttrConfig(): array + { + return [ + 'type' => 'datetime', + 'label' => $this->attrData['label'], + 'input' => 'date', + 'backend' => Datetime::class, + ]; + } } diff --git a/Model/Catalog/Product/Attribute/Creator/Strategy/MultiselectStrategy.php b/Model/Catalog/Product/Attribute/Creator/Strategy/MultiselectStrategy.php index fc17cda..7a7c109 100644 --- a/Model/Catalog/Product/Attribute/Creator/Strategy/MultiselectStrategy.php +++ b/Model/Catalog/Product/Attribute/Creator/Strategy/MultiselectStrategy.php @@ -84,18 +84,24 @@ protected function createNewAttribute(array $options) { $eavSetup = $this->eavSetupFactory->create(); - $data = [ + $eavSetup->addAttribute( + Product::ENTITY, + $this->code, + $this->getMergedConfig($this->getBaseAttrConfig()) + ); + } + + /** + * @return array + */ + public function getBaseAttrConfig(): array + { + return [ 'type' => 'varchar', 'label' => $this->attrData['label'], 'input' => 'multiselect', 'user_defined' => true, 'backend' => ArrayBackend::class, ]; - - $eavSetup->addAttribute( - Product::ENTITY, - $this->code, - array_merge(self::$defaultAttrConfig, $data) - ); } } diff --git a/Model/Catalog/Product/Attribute/Creator/Strategy/QuantityValueStrategy.php b/Model/Catalog/Product/Attribute/Creator/Strategy/QuantityValueStrategy.php new file mode 100644 index 0000000..11bd1f3 --- /dev/null +++ b/Model/Catalog/Product/Attribute/Creator/Strategy/QuantityValueStrategy.php @@ -0,0 +1,54 @@ + + * @copyright 2020 Divante Sp. z o.o. + * @license See LICENSE_DIVANTE.txt for license details. + */ + +namespace Divante\PimcoreIntegration\Model\Catalog\Product\Attribute\Creator\Strategy; + +use Magento\Catalog\Model\Product; +use Magento\Eav\Setup\EavSetup; + +/** + * Class QuantityValueStrategy + */ +class QuantityValueStrategy extends AbstractStrategy +{ + /** + * @return int + */ + public function execute(): int + { + /** @var EavSetup $eavSetup */ + $eavSetup = $this->eavSetupFactory->create(); + $eavSetup->addAttribute( + Product::ENTITY, + $this->code, + $this->getMergedConfig($this->getBaseAttrConfig()) + ); + + return $eavSetup->getAttributeId(Product::ENTITY, $this->code); + } + + /** + * @return array + */ + public function getBaseAttrConfig(): array + { + return [ + 'type' => 'decimal', + 'label' => $this->getLabel(), + 'input' => 'text', + ]; + } + + /** + * @return string + */ + private function getLabel(): string + { + return $this->attrData['label'] . ' (' . $this->attrData['unit'] . ')'; + } +} diff --git a/Model/Catalog/Product/Attribute/Creator/Strategy/SelectStrategy.php b/Model/Catalog/Product/Attribute/Creator/Strategy/SelectStrategy.php index 9251724..3fef171 100644 --- a/Model/Catalog/Product/Attribute/Creator/Strategy/SelectStrategy.php +++ b/Model/Catalog/Product/Attribute/Creator/Strategy/SelectStrategy.php @@ -80,6 +80,26 @@ protected function createNewAttribute(array $options) { $eavSetup = $this->eavSetupFactory->create(); + $eavSetup->addAttribute( + Product::ENTITY, + $this->code, + $this->getMergedConfig($this->getBaseAttrConfig()) + ); + } + + /** + * @return bool + */ + private function isConfigurable(): bool + { + return (!empty($this->attrData['is_configurable']) && true === $this->attrData['is_configurable']); + } + + /** + * @return array + */ + public function getBaseAttrConfig(): array + { $data = [ 'type' => 'int', 'label' => $this->attrData['label'], @@ -93,18 +113,6 @@ protected function createNewAttribute(array $options) ]); } - $eavSetup->addAttribute( - Product::ENTITY, - $this->code, - array_merge(self::$defaultAttrConfig, $data) - ); - } - - /** - * @return bool - */ - private function isConfigurable(): bool - { - return (!empty($this->attrData['is_configurable']) && true === $this->attrData['is_configurable']); + return $data; } } diff --git a/Model/Catalog/Product/Attribute/Creator/Strategy/TextStrategy.php b/Model/Catalog/Product/Attribute/Creator/Strategy/TextStrategy.php index e131d75..89cd7ce 100644 --- a/Model/Catalog/Product/Attribute/Creator/Strategy/TextStrategy.php +++ b/Model/Catalog/Product/Attribute/Creator/Strategy/TextStrategy.php @@ -26,13 +26,21 @@ public function execute(): int $eavSetup->addAttribute( Product::ENTITY, $this->code, - array_merge(self::$defaultAttrConfig, [ - 'type' => 'varchar', - 'label' => $this->attrData['label'], - 'input' => 'text', - ]) + $this->getMergedConfig($this->getBaseAttrConfig()) ); return $eavSetup->getAttributeId(Product::ENTITY, $this->code); } + + /** + * @return array + */ + public function getBaseAttrConfig(): array + { + return [ + 'type' => 'varchar', + 'label' => $this->attrData['label'], + 'input' => 'text', + ]; + } } diff --git a/Model/Catalog/Product/Attribute/Creator/Strategy/TextareaStrategy.php b/Model/Catalog/Product/Attribute/Creator/Strategy/TextareaStrategy.php index a4ff65a..63a7f93 100644 --- a/Model/Catalog/Product/Attribute/Creator/Strategy/TextareaStrategy.php +++ b/Model/Catalog/Product/Attribute/Creator/Strategy/TextareaStrategy.php @@ -24,15 +24,23 @@ public function execute(): int $eavSetup->addAttribute( Product::ENTITY, $this->code, - array_merge(self::$defaultAttrConfig, [ - 'type' => 'text', - 'label' => $this->attrData['label'], - 'input' => 'textarea', - 'wysiwyg_enabled' => false, - 'is_html_allowed_on_front' => false, - ]) + $this->getMergedConfig($this->getBaseAttrConfig()) ); return $eavSetup->getAttributeId(Product::ENTITY, $this->code); } + + /** + * @return array + */ + public function getBaseAttrConfig(): array + { + return [ + 'type' => 'text', + 'label' => $this->attrData['label'], + 'input' => 'textarea', + 'wysiwyg_enabled' => false, + 'is_html_allowed_on_front' => false, + ]; + } } diff --git a/Model/Catalog/Product/Attribute/Creator/Strategy/WysiwygStrategy.php b/Model/Catalog/Product/Attribute/Creator/Strategy/WysiwygStrategy.php index a42e00b..b435e28 100644 --- a/Model/Catalog/Product/Attribute/Creator/Strategy/WysiwygStrategy.php +++ b/Model/Catalog/Product/Attribute/Creator/Strategy/WysiwygStrategy.php @@ -24,15 +24,23 @@ public function execute(): int $eavSetup->addAttribute( Product::ENTITY, $this->code, - array_merge(self::$defaultAttrConfig, [ - 'type' => 'text', - 'label' => $this->attrData['label'], - 'input' => 'textarea', - 'wysiwyg_enabled' => true, - 'is_html_allowed_on_front' => true, - ]) + $this->getMergedConfig($this->getBaseAttrConfig()) ); return $eavSetup->getAttributeId(Product::ENTITY, $this->code); } + + /** + * @return array + */ + public function getBaseAttrConfig(): array + { + return [ + 'type' => 'text', + 'label' => $this->attrData['label'], + 'input' => 'textarea', + 'wysiwyg_enabled' => true, + 'is_html_allowed_on_front' => true, + ]; + } } diff --git a/Model/Catalog/Product/Attribute/Creator/Strategy/YesnoStrategy.php b/Model/Catalog/Product/Attribute/Creator/Strategy/YesnoStrategy.php index 4866ca8..0c71894 100644 --- a/Model/Catalog/Product/Attribute/Creator/Strategy/YesnoStrategy.php +++ b/Model/Catalog/Product/Attribute/Creator/Strategy/YesnoStrategy.php @@ -24,14 +24,22 @@ public function execute(): int $eavSetup->addAttribute( Product::ENTITY, $this->code, - array_merge(self::$defaultAttrConfig, [ - 'type' => 'int', - 'label' => $this->attrData['label'], - 'input' => 'boolean', - 'source' => \Magento\Eav\Model\Entity\Attribute\Source\Boolean::class, - ]) + $this->getMergedConfig($this->getBaseAttrConfig()) ); return $eavSetup->getAttributeId(Product::ENTITY, $this->code); } + + /** + * @return array + */ + public function getBaseAttrConfig(): array + { + return [ + 'type' => 'int', + 'label' => $this->attrData['label'], + 'input' => 'boolean', + 'source' => \Magento\Eav\Model\Entity\Attribute\Source\Boolean::class, + ]; + } } diff --git a/Model/Pimcore/SimpleAttributeMapper.php b/Model/Pimcore/SimpleAttributeMapper.php index 993b5a2..de422bf 100644 --- a/Model/Pimcore/SimpleAttributeMapper.php +++ b/Model/Pimcore/SimpleAttributeMapper.php @@ -31,6 +31,7 @@ public function mapUsingType(array $attributeData) case self::YESNO: case self::DATETIME: case self::WYSIWYG: + case self::QVALUE: return $this->mapText($attributeData); case self::SELECT: return $this->mapSelect($attributeData); diff --git a/Queue/Action/Product/CategoryIdsModifier.php b/Queue/Action/Product/CategoryIdsModifier.php index 913f082..5636175 100644 --- a/Queue/Action/Product/CategoryIdsModifier.php +++ b/Queue/Action/Product/CategoryIdsModifier.php @@ -77,7 +77,8 @@ public function __construct( */ public function handle(Product $product, PimcoreProductInterface $pimcoreProduct): array { - $pimCatIds = $pimcoreProduct->getData('category_ids'); + $pimCatIds = $pimcoreProduct->getData('category_ids') ?? []; + $catCollection = $this->getMageCatCollection($pimcoreProduct); $mageCatIds = $catCollection->getAllIds(); $pimcoreProduct->setData('category_ids', $mageCatIds); diff --git a/Queue/Action/Product/PriceModifier.php b/Queue/Action/Product/PriceModifier.php index 38d1267..8940fbd 100644 --- a/Queue/Action/Product/PriceModifier.php +++ b/Queue/Action/Product/PriceModifier.php @@ -9,6 +9,7 @@ namespace Divante\PimcoreIntegration\Queue\Action\Product; use Divante\PimcoreIntegration\Api\Pimcore\PimcoreProductInterface; +use Divante\PimcoreIntegration\System\ConfigInterface; use Magento\Catalog\Model\Product; /** @@ -21,6 +22,21 @@ class PriceModifier implements DataModifierInterface */ public static $defaultPriceValue = 0; + /** + * @var ConfigInterface + */ + private $config; + + /** + * PriceModifier constructor. + * + * @param ConfigInterface $config + */ + public function __construct(ConfigInterface $config) + { + $this->config = $config; + } + /** * @param Product $product * @param PimcoreProductInterface $pimcoreProduct @@ -32,12 +48,26 @@ public function handle(Product $product, PimcoreProductInterface $pimcoreProduct if (null === $pimcoreProduct->getData('price') && null === $product->getPrice()) { $pimcoreProduct->setData('price', self::$defaultPriceValue); $pimcoreProduct->setData('base_price', self::$defaultPriceValue); - } elseif (null !== $product->getPrice()) { - $pimcoreProduct->setData('price', $product->getPrice()); + } elseif ($this->isPriceAlreadySet($product)) { + if ($this->config->getIsPriceOverride()) { + $pimcoreProduct->setData('price', $pimcoreProduct->getData('price') ?? self::$defaultPriceValue); + } else { + $pimcoreProduct->setData('price', $product->getPrice()); + } } $pimcoreProduct->setData('base_price', $pimcoreProduct->getData('price')); return [$product, $pimcoreProduct]; } + + /** + * @param Product $product + * + * @return bool + */ + private function isPriceAlreadySet(Product $product): bool + { + return (null !== $product->getPrice()); + } } diff --git a/System/Config.php b/System/Config.php index f12a23f..2c2d6ed 100644 --- a/System/Config.php +++ b/System/Config.php @@ -142,4 +142,12 @@ public function getIsProductPublishActive(): bool { return (bool) $this->scopeConfig->getValue(static::XML_PATH_CRON_PUBLISH_IS_ACTIVE, $this->scope); } + + /** + * @return bool + */ + public function getIsPriceOverride(): bool + { + return (bool) $this->scopeConfig->getValue(static::XML_PATH_PRICES_OVERRIDE, $this->scope); + } } diff --git a/System/ConfigInterface.php b/System/ConfigInterface.php index fe10a48..ec83e54 100644 --- a/System/ConfigInterface.php +++ b/System/ConfigInterface.php @@ -28,6 +28,11 @@ interface ConfigInterface */ const XML_PATH_QUEUE_OUTDATED = 'configuration/basic/queue_outdated'; + /** + * Configuration path for rices override settings + */ + const XML_PATH_PRICES_OVERRIDE = 'configuration/prices/is_override_enabled'; + /** * Configuration path for Pimcore API Key used for request authorization */ @@ -63,6 +68,7 @@ interface ConfigInterface */ const XML_PATH_CRON_PUBLISH_IS_ACTIVE = 'cron/enable_products/is_active'; + /** * @return bool */ @@ -117,4 +123,9 @@ public function getQueueOutdatedValue(): string; * @return bool */ public function getIsProductPublishActive(): bool; + + /** + * @return bool + */ + public function getIsPriceOverride(): bool; } diff --git a/Test/Unit/Model/Catalog/Product/Attribute/Creator/Strategy/AbstractStrategyTest.php b/Test/Unit/Model/Catalog/Product/Attribute/Creator/Strategy/AbstractStrategyTest.php new file mode 100644 index 0000000..8d17cff --- /dev/null +++ b/Test/Unit/Model/Catalog/Product/Attribute/Creator/Strategy/AbstractStrategyTest.php @@ -0,0 +1,139 @@ + + * @copyright 2020 Divante Sp. z o.o. + * @license See LICENSE_DIVANTE.txt for license details. + */ + +namespace Divante\PimcoreIntegration\Test\Unit\Model\Catalog\Product\Attribute\Creator\Strategy; + +use Divante\PimcoreIntegration\Model\Catalog\Product\Attribute\Creator\Strategy\AbstractStrategy; +use Magento\Catalog\Model\Category\AttributeRepository; +use Magento\Eav\Api\AttributeRepositoryInterface; +use Magento\Eav\Model\Entity\Attribute\ScopedAttributeInterface; +use Magento\Eav\Setup\EavSetup; +use Magento\Eav\Setup\EavSetupFactory; +use PHPUnit\Framework\MockObject\MockObject; + +/** + * Class TextStrategyTest + */ +class AbstractStrategyTest extends \PHPUnit\Framework\TestCase +{ + /** + * @var MockObject|EavSetupFactory + */ + private $eavSetupFactoryMock; + + /** + * @var MockObject|EavSetup + */ + private $eavSetupMock; + + /** + * @var MockObject|AttributeRepository + */ + private $attributeRepositoryMock; + + /** + * @var array + */ + private $defaultAttrConfig = [ + 'backend' => '', + 'frontend' => '', + 'input' => 'text', + 'class' => '', + 'source' => '', + 'global' => ScopedAttributeInterface::SCOPE_STORE, + 'visible' => true, + 'required' => false, + 'user_defined' => true, + 'searchable' => true, + 'filterable' => true, + 'comparable' => true, + 'visible_on_front' => true, + 'used_in_product_listing' => true, + 'unique' => false, + ]; + + public function setUp() + { + $this->eavSetupFactoryMock = $this->getMockBuilder(EavSetupFactory::class) + ->disableOriginalConstructor() + ->setMethods(['create']) + ->getMock(); + + $this->eavSetupMock = $this->getMockBuilder(EavSetup::class) + ->disableOriginalConstructor() + ->setMethods([]) + ->getMock(); + + $this->eavSetupMock = $this->getMockBuilder(EavSetup::class) + ->disableOriginalConstructor() + ->setMethods([]) + ->getMock(); + + $this->attributeRepositoryMock = $this->getMockBuilder(AttributeRepositoryInterface::class) + ->disableOriginalConstructor() + ->setMethods([]) + ->getMock(); + } + + /** + * @return array[] + */ + public function attrDataProvider() + { + return [ + [['attr_conf' => ['test' => 1]], []], + [['attr_conf' => ['test' => 1]], ['input' => 'select']], + [['attr_conf' => ['test' => 1]], ['input' => 'select']], + [['attr_conf' => ['test' => 1]], ['input' => 'select']], + [['something_else' => [], 'attr_conf' => ['test' => 1]], ['input' => 'select']], + [['missed_key' => ['test' => 1, 'required' => true]], []], + ]; + } + + public function testGetDefaultAttrConfig() + { + $strategy = $this->getAbstractStrategyMockImplementation('test'); + $this->assertEquals($this->defaultAttrConfig, $strategy->getDefaultAttributeConfig()); + } + + /** + * @dataProvider attrDataProvider + */ + public function testGetMergedConfig(array $attrData, $base) + { + $strategy = $this->getAbstractStrategyMockImplementation('test', $attrData); + $result = array_merge($this->defaultAttrConfig, $base, $attrData['attr_conf'] ?? []); + $this->assertEquals($result, $strategy->getMergedConfig($base)); + } + + /** + * @param string $code + * @param array $attrData + * + * @return AbstractStrategy + */ + private function getAbstractStrategyMockImplementation(string $code, array $attrData = []) + { + return new class( + $this->eavSetupFactoryMock, + $this->attributeRepositoryMock, + $attrData, + $code + ) extends AbstractStrategy { + public function getBaseAttrConfig(): array + { + return []; + } + + public function execute(): int + { + return 1; + } + }; + } +} diff --git a/Test/Unit/Model/Catalog/Product/Attribute/Creator/Strategy/BaseTestAbstract.php b/Test/Unit/Model/Catalog/Product/Attribute/Creator/Strategy/BaseTestAbstract.php new file mode 100644 index 0000000..4ba411f --- /dev/null +++ b/Test/Unit/Model/Catalog/Product/Attribute/Creator/Strategy/BaseTestAbstract.php @@ -0,0 +1,120 @@ + + * @copyright 2020 Divante Sp. z o.o. + * @license See LICENSE_DIVANTE.txt for license details. + */ + +namespace Divante\PimcoreIntegration\Test\Unit\Model\Catalog\Product\Attribute\Creator\Strategy; + +use Divante\PimcoreIntegration\Model\Catalog\Product\Attribute\Creator\Strategy\TextStrategy; +use Magento\Catalog\Model\Category\AttributeRepository; +use Magento\Eav\Api\AttributeRepositoryInterface; +use Magento\Eav\Setup\EavSetup; +use Magento\Eav\Setup\EavSetupFactory; +use Magento\Framework\TestFramework\Unit\Helper\ObjectManager; +use PHPUnit\Framework\MockObject\MockObject; +use PHPUnit\Framework\TestCase; + +/** + * Class TestAbstract + */ +abstract class BaseTestAbstract extends TestCase +{ + /** + * @var ObjectManager + */ + protected $om; + + /** + * @var MockObject|EavSetupFactory + */ + protected $eavSetupFactoryMock; + + /** + * @var MockObject|EavSetup + */ + protected $eavSetupMock; + + /** + * @var MockObject|AttributeRepository + */ + protected $attributeRepositoryMock; + + /** + * Test Setup + */ + public function setUp() + { + $this->om = new ObjectManager($this); + + $this->eavSetupFactoryMock = $this->getMockBuilder(EavSetupFactory::class) + ->disableOriginalConstructor() + ->setMethods(['create']) + ->getMock(); + + $this->eavSetupMock = $this->getMockBuilder(EavSetup::class) + ->disableOriginalConstructor() + ->setMethods(['addAttribute', 'getAttributeId']) + ->getMock(); + + $this->eavSetupMock = $this->getMockBuilder(EavSetup::class) + ->disableOriginalConstructor() + ->setMethods([]) + ->getMock(); + + $this->attributeRepositoryMock = $this->getMockBuilder(AttributeRepositoryInterface::class) + ->disableOriginalConstructor() + ->setMethods([]) + ->getMock(); + } + + /** + * @return array[] + */ + abstract public function attrDataProvider(): array; + + /** + * @return string + */ + abstract public function getStrategyClass(): string; + + /** + * @return array + */ + abstract public function getBaseAttrConfig(): array; + + /** + * @dataProvider attrDataProvider + */ + public function testExecution(array $attrData, $code) + { + $this->markTestIncomplete('You must implement execution test.'); + } + + /** + * @dataProvider attrDataProvider + */ + public function testGetBaseAttrConf(array $attrData, $code) + { + $strategy = $this->createStrategyObject($this->getStrategyClass(), $code, $attrData); + $this->assertEquals($this->getBaseAttrConfig(), $strategy->getBaseAttrConfig()); + } + + /** + * @param string $code + * @param array $attrData + * + * @return object + */ + protected function createStrategyObject(string $strategyClass, string $code, array $attrData = []) + { + return $this->om->getObject($strategyClass, [ + 'eavSetupFactory' => $this->eavSetupFactoryMock, + 'attributeRepository' => $this->attributeRepositoryMock, + 'attrData' => $attrData, + 'code' => $code + ]); + } +} diff --git a/Test/Unit/Model/Catalog/Product/Attribute/Creator/Strategy/QuantityValueStrategyTest.php b/Test/Unit/Model/Catalog/Product/Attribute/Creator/Strategy/QuantityValueStrategyTest.php new file mode 100644 index 0000000..de307bf --- /dev/null +++ b/Test/Unit/Model/Catalog/Product/Attribute/Creator/Strategy/QuantityValueStrategyTest.php @@ -0,0 +1,68 @@ + + * @copyright 2020 Divante Sp. z o.o. + * @license See LICENSE_DIVANTE.txt for license details. + */ + +namespace Divante\PimcoreIntegration\Test\Unit\Model\Catalog\Product\Attribute\Creator\Strategy; + +use Divante\PimcoreIntegration\Model\Catalog\Product\Attribute\Creator\Strategy\QuantityValueStrategy; + +/** + * Class QuantityValueStrategyTest + */ +class QuantityValueStrategyTest extends BaseTestAbstract +{ + /** + * @dataProvider attrDataProvider + */ + public function testExecution(array $attrData, $code) + { + $strategy = $this->createStrategyObject($this->getStrategyClass(), $code, $attrData); + + $this->eavSetupFactoryMock->expects($this->once()) + ->method('create') + ->willReturn($this->eavSetupMock); + + $this->eavSetupMock->expects($this->once()) + ->method('addAttribute'); + + $this->eavSetupMock->expects($this->once()) + ->method('getAttributeId') + ->willReturn(1); + + $strategy->execute(); + } + + /** + * @return array|array[] + */ + public function attrDataProvider(): array + { + return [ + [['label' => 'quantity', 'unit' => 'km'], 'test'], + ]; + } + + /** + * @return string + */ + public function getStrategyClass(): string + { + return QuantityValueStrategy::class; + } + + /** + * @return array|string[] + */ + public function getBaseAttrConfig(): array + { + return [ + 'type' => 'decimal', + 'label' => 'quantity (km)', + 'input' => 'text', + ]; + } +} diff --git a/Test/Unit/Model/Catalog/Product/Attribute/Creator/Strategy/TextStrategyTest.php b/Test/Unit/Model/Catalog/Product/Attribute/Creator/Strategy/TextStrategyTest.php new file mode 100644 index 0000000..9ebdbe3 --- /dev/null +++ b/Test/Unit/Model/Catalog/Product/Attribute/Creator/Strategy/TextStrategyTest.php @@ -0,0 +1,76 @@ + + * @copyright 2020 Divante Sp. z o.o. + * @license See LICENSE_DIVANTE.txt for license details. + */ + +namespace Divante\PimcoreIntegration\Test\Unit\Model\Catalog\Product\Attribute\Creator\Strategy; + +use Divante\PimcoreIntegration\Model\Catalog\Product\Attribute\Creator\Strategy\TextStrategy; +use Magento\Catalog\Model\Category\AttributeRepository; +use Magento\Catalog\Model\Product; +use Magento\Eav\Api\AttributeRepositoryInterface; +use Magento\Eav\Model\Entity\Attribute\ScopedAttributeInterface; +use Magento\Eav\Setup\EavSetup; +use Magento\Eav\Setup\EavSetupFactory; +use Magento\Framework\TestFramework\Unit\Helper\ObjectManager; +use PHPUnit\Framework\MockObject\MockObject; + +/** + * Class TextStrategyTest + */ +class TextStrategyTest extends BaseTestAbstract +{ + /** + * @return array[] + */ + public function attrDataProvider(): array + { + return [ + [['label' => 'test_label'], 'test'], + ]; + } + + /** + * @dataProvider attrDataProvider + */ + public function testExecution(array $attrData, $code) + { + $strategy = $this->createStrategyObject($this->getStrategyClass(), $code, $attrData); + + $this->eavSetupFactoryMock->expects($this->once()) + ->method('create') + ->willReturn($this->eavSetupMock); + + $this->eavSetupMock->expects($this->once()) + ->method('addAttribute'); + + $this->eavSetupMock->expects($this->once()) + ->method('getAttributeId') + ->willReturn(1); + + $strategy->execute(); + } + + /** + * @return string + */ + public function getStrategyClass(): string + { + return TextStrategy::class; + } + + /** + * @return array|string[] + */ + public function getBaseAttrConfig(): array + { + return [ + 'type' => 'varchar', + 'label' => 'test_label', + 'input' => 'text', + ]; + } +} diff --git a/Test/Unit/Queue/Action/Product/PriceModifierTest.php b/Test/Unit/Queue/Action/Product/PriceModifierTest.php index 461a94a..88c6c47 100644 --- a/Test/Unit/Queue/Action/Product/PriceModifierTest.php +++ b/Test/Unit/Queue/Action/Product/PriceModifierTest.php @@ -11,8 +11,12 @@ use Divante\PimcoreIntegration\Model\Pimcore\PimcoreProduct; use Divante\PimcoreIntegration\Queue\Action\Product\DataModifierInterface; use Divante\PimcoreIntegration\Queue\Action\Product\PriceModifier; +use Divante\PimcoreIntegration\System\Config; +use Divante\PimcoreIntegration\System\ConfigInterface; use Magento\Catalog\Model\Product; +use Magento\Catalog\Model\Product\Type\Price; use Magento\Framework\TestFramework\Unit\Helper\ObjectManager; +use PHPUnit\Framework\MockObject\MockObject; /** * PriceModifierTest @@ -25,12 +29,12 @@ class PriceModifierTest extends \PHPUnit\Framework\TestCase private $priceModifier; /** - * @var PimcoreProduct|\PHPUnit_Framework_MockObject_MockObject + * @var PimcoreProduct|MockObject */ private $pimcoreProduct; /** - * @var Product|\PHPUnit_Framework_MockObject_MockObject + * @var Product|MockObject */ private $product; @@ -39,21 +43,40 @@ class PriceModifierTest extends \PHPUnit\Framework\TestCase */ private $objectManager; + /** + * @var ConfigInterface|MockObject + */ + private $configMock; + + /** + * @var Price|MockObject + */ + private $mockPriceModel; + public function setUp() { $this->objectManager = new ObjectManager($this); - $this->product = $this->mockProduct = $this->getMockBuilder(Product::class) + $this->mockPriceModel = $this->getMockBuilder(Price::class) ->disableOriginalConstructor() ->setMethods(['getPrice']) ->getMock(); - $this->pimcoreProduct = $this->mockPimcoreProduct = $this->getMockBuilder(PimcoreProduct::class) + $this->product = $this->getMockBuilder(Product::class) ->disableOriginalConstructor() - ->setMethods(['getData', 'setData']) + ->setMethods(['getPriceModel']) ->getMock(); - $this->priceModifier = $this->objectManager->getObject(PriceModifier::class); + $this->pimcoreProduct = $this->objectManager->getObject(PimcoreProduct::class); + + $this->configMock = $this->getMockBuilder(Config::class) + ->disableOriginalConstructor() + ->setMethods(['getIsPriceOverride']) + ->getMock(); + + $this->priceModifier = $this->objectManager->getObject(PriceModifier::class, [ + 'config' => $this->configMock + ]); } /** @@ -66,22 +89,32 @@ public function priceDataProvider(): array [10, null, 10], [null, 10, 10], [12, 10, 12], + [15, 20, 20, true], + [15, 20, 15, false], ]; } /** * @dataProvider priceDataProvider */ - public function testHandle($price, $pimPrice, $final) + public function testHandle($price, $pimPrice, $final, $override = false) { - $this->pimcoreProduct->expects($this->exactly(2)) - ->method('getData') - ->willReturn($pimPrice); + $this->product->setPrice($price); + $this->product->expects($this->any()) + ->method('getPriceModel') + ->willReturn($this->mockPriceModel); - $this->product->expects($this->atLeast(1)) + $this->mockPriceModel->expects($this->any()) ->method('getPrice') ->willReturn($price); - $this->priceModifier->handle($this->product, $this->pimcoreProduct); + $this->configMock->expects($this->any()) + ->method('getIsPriceOverride') + ->willReturn($override); + + $this->pimcoreProduct->setData('price', $pimPrice); + + $result = $this->priceModifier->handle($this->product, $this->pimcoreProduct); + $this->assertEquals($final, $result[1]->getPrice()); } } diff --git a/etc/adminhtml/system.xml b/etc/adminhtml/system.xml index bb61b6d..05d01c3 100644 --- a/etc/adminhtml/system.xml +++ b/etc/adminhtml/system.xml @@ -38,6 +38,16 @@ + + + + + Magento\Config\Model\Config\Source\Yesno + + +
separator-top diff --git a/etc/config.xml b/etc/config.xml index 04e8a87..f1881a2 100644 --- a/etc/config.xml +++ b/etc/config.xml @@ -6,6 +6,9 @@ 0 60 + + 1 +