Skip to content

Commit

Permalink
Merge pull request PrestaShop#21336 from zuk3975/m/product/prices-rep
Browse files Browse the repository at this point in the history
Refactor UpdateProductPricesHandler to use ProductRepository [product page migration]
  • Loading branch information
jolelievre authored Nov 24, 2020
2 parents 3ea3a56 + 4044553 commit 64e72ca
Show file tree
Hide file tree
Showing 12 changed files with 440 additions and 310 deletions.
192 changes: 30 additions & 162 deletions src/Adapter/Product/CommandHandler/UpdateProductPricesHandler.php
Original file line number Diff line number Diff line change
Expand Up @@ -28,223 +28,91 @@

namespace PrestaShop\PrestaShop\Adapter\Product\CommandHandler;

use PrestaShop\Decimal\DecimalNumber;
use PrestaShop\PrestaShop\Adapter\Entity\TaxRulesGroup;
use PrestaShop\PrestaShop\Adapter\Product\AbstractProductHandler;
use PrestaShop\PrestaShop\Adapter\Product\Repository\ProductRepository;
use PrestaShop\PrestaShop\Adapter\Product\Update\ProductPricePropertiesFiller;
use PrestaShop\PrestaShop\Core\Domain\Product\Command\UpdateProductPricesCommand;
use PrestaShop\PrestaShop\Core\Domain\Product\CommandHandler\UpdateProductPricesHandlerInterface;
use PrestaShop\PrestaShop\Core\Domain\Product\Exception\CannotUpdateProductException;
use PrestaShop\PrestaShop\Core\Domain\Product\Exception\ProductConstraintException;
use PrestaShop\PrestaShop\Core\Domain\Product\Exception\ProductException;
use PrestaShop\PrestaShop\Core\Domain\Product\ProductTaxRulesGroupSettings;
use PrestaShop\PrestaShop\Core\Util\Number\NumberExtractor;
use PrestaShopException;
use Product;

/**
* Updates product price information using legacy object models
*/
final class UpdateProductPricesHandler extends AbstractProductHandler implements UpdateProductPricesHandlerInterface
final class UpdateProductPricesHandler implements UpdateProductPricesHandlerInterface
{
/**
* @var NumberExtractor
* @var ProductRepository
*/
private $numberExtractor;
private $productRepository;

/**
* @var Product the product being updated
* @var ProductPricePropertiesFiller
*/
private $product;
private $productPricePropertiesFiller;

/**
* @param NumberExtractor $numberExtractor
* @param ProductRepository $productRepository
* @param ProductPricePropertiesFiller $productPricePropertiesFiller
*/
public function __construct(
NumberExtractor $numberExtractor
ProductRepository $productRepository,
ProductPricePropertiesFiller $productPricePropertiesFiller
) {
$this->numberExtractor = $numberExtractor;
$this->productRepository = $productRepository;
$this->productPricePropertiesFiller = $productPricePropertiesFiller;
}

/**
* {@inheritdoc}
*/
public function handle(UpdateProductPricesCommand $command): void
{
$product = $this->getProduct($command->getProductId());
$this->product = $product;
$this->fillUpdatableFieldsWithCommandData($product, $command);
$product->setFieldsToUpdate($this->fieldsToUpdate);
$product = $this->productRepository->get($command->getProductId());
$updatableProperties = $this->fillUpdatableProperties($product, $command);

if (empty($this->fieldsToUpdate)) {
return;
}

$this->performUpdate($product, CannotUpdateProductException::FAILED_UPDATE_PRICES);
$this->productRepository->partialUpdate($product, $updatableProperties, CannotUpdateProductException::FAILED_UPDATE_PRICES);
}

/**
* @param Product $product
* @param UpdateProductPricesCommand $command
*
* @return string[] updatable properties
*
* @throws ProductConstraintException
*/
private function fillUpdatableFieldsWithCommandData(Product $product, UpdateProductPricesCommand $command): void
private function fillUpdatableProperties(Product $product, UpdateProductPricesCommand $command): array
{
if (null !== $command->getPrice()) {
$product->price = (float) (string) $command->getPrice();
$this->validateField($product, 'price', ProductConstraintException::INVALID_PRICE);
$this->fieldsToUpdate['price'] = true;
}

$this->handleUnitPriceInfo($command);
$updatableProperties = $this->productPricePropertiesFiller->fillWithPrices(
$product,
$command->getPrice(),
$command->getUnitPrice(),
$command->getWholesalePrice()
);

if (null !== $command->getUnity()) {
$product->unity = $command->getUnity();
$this->fieldsToUpdate['unity'] = true;
$updatableProperties[] = 'unity';
}

if (null !== $command->getEcotax()) {
$product->ecotax = (float) (string) $command->getEcotax();
$this->validateField($product, 'ecotax', ProductConstraintException::INVALID_ECOTAX);
$this->fieldsToUpdate['ecotax'] = true;
$updatableProperties[] = 'ecotax';
}

$taxRulesGroupId = $command->getTaxRulesGroupId();

if (null !== $taxRulesGroupId) {
$product->id_tax_rules_group = $taxRulesGroupId;
$this->validateField($product, 'id_tax_rules_group', ProductConstraintException::INVALID_TAX_RULES_GROUP_ID);
$this->assertTaxRulesGroupExists($taxRulesGroupId);
$this->fieldsToUpdate['id_tax_rules_group'] = true;
$updatableProperties[] = 'id_tax_rules_group';
}

if (null !== $command->isOnSale()) {
$product->on_sale = $command->isOnSale();
$this->fieldsToUpdate['on_sale'] = true;
}

if (null !== $command->getWholesalePrice()) {
$product->wholesale_price = (string) $command->getWholesalePrice();
$this->validateField($product, 'wholesale_price', ProductConstraintException::INVALID_WHOLESALE_PRICE);
$this->fieldsToUpdate['wholesale_price'] = true;
}
}

/**
* Update unit_price and unit_price ration depending on price
*
* @param UpdateProductPricesCommand $command
*
* @throws ProductConstraintException
*/
private function handleUnitPriceInfo(UpdateProductPricesCommand $command): void
{
$price = $command->getPrice();
$unitPrice = $command->getUnitPrice();

// if price was reset then also reset unit_price and unit_price_ratio
$priceWasReset = null !== $price && $price->equalsZero();
if ($priceWasReset) {
$this->resetUnitPriceInfo();
}

//if price was not reset then allow setting new unit_price and unit_price_ratio
if (!$priceWasReset && null !== $unitPrice) {
$this->setUnitPriceInfo($this->product, $unitPrice, $price);
}
}

/**
* @throws ProductConstraintException
*/
private function resetUnitPriceInfo(): void
{
$zero = new DecimalNumber('0');
$this->setUnitPriceInfo($this->product, $zero, $zero);
}

/**
* @param int $taxRulesGroupId
*
* @throws ProductConstraintException
* @throws ProductException
*/
private function assertTaxRulesGroupExists(int $taxRulesGroupId): void
{
if (ProductTaxRulesGroupSettings::NONE_APPLIED === $taxRulesGroupId) {
return;
}

try {
$taxRulesGroup = new TaxRulesGroup($taxRulesGroupId);
if (!$taxRulesGroup->id) {
throw new ProductConstraintException(
sprintf(
'Invalid tax rules group id "%d". Group doesn\'t exist',
$taxRulesGroupId
),
ProductConstraintException::INVALID_TAX_RULES_GROUP_ID
);
}
} catch (PrestaShopException $e) {
throw new ProductException(
sprintf(
'Error occurred when trying to load tax rules group #%d for product',
$taxRulesGroupId
),
0,
$e
);
$updatableProperties[] = 'on_sale';
}
}

/**
* @param Product $product
* @param DecimalNumber $unitPrice
* @param DecimalNumber $price
*
* @throws ProductConstraintException
*/
private function setUnitPriceInfo(Product $product, DecimalNumber $unitPrice, ?DecimalNumber $price): void
{
$this->validateUnitPrice($unitPrice);

if (null === $price) {
$price = $this->numberExtractor->extract($product, 'price');
}

// If unit price or price is zero, then reset ratio to zero too
if ($unitPrice->equalsZero() || $price->equalsZero()) {
$ratio = new DecimalNumber('0');
} else {
$ratio = $price->dividedBy($unitPrice);
}

$product->unit_price_ratio = (float) (string) $ratio;
//unit_price is not saved to database, it is only calculated depending on price and unit_price_ratio
$product->unit_price = (float) (string) $unitPrice;

$this->fieldsToUpdate['unit_price_ratio'] = true;
$this->fieldsToUpdate['unit_price'] = true;
}

/**
* Unit price validation is not involved in legacy validation, so it is checked manually to have unsigned int value
*
* @param DecimalNumber $unitPrice
*
* @throws ProductConstraintException
*/
private function validateUnitPrice(DecimalNumber $unitPrice): void
{
if ($unitPrice->isLowerThanZero()) {
throw new ProductConstraintException(
sprintf(
'Invalid product unit_price. Got "%s"',
$unitPrice
),
ProductConstraintException::INVALID_UNIT_PRICE
);
}
return $updatableProperties;
}
}
18 changes: 17 additions & 1 deletion src/Adapter/Product/Repository/ProductRepository.php
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
use PrestaShop\Decimal\DecimalNumber;
use PrestaShop\PrestaShop\Adapter\AbstractObjectModelRepository;
use PrestaShop\PrestaShop\Adapter\Product\Validate\ProductValidator;
use PrestaShop\PrestaShop\Adapter\TaxRulesGroup\Repository\TaxRulesGroupRepository;
use PrestaShop\PrestaShop\Core\Domain\Language\ValueObject\LanguageId;
use PrestaShop\PrestaShop\Core\Domain\Product\Exception\CannotAddProductException;
use PrestaShop\PrestaShop\Core\Domain\Product\Exception\CannotBulkDeleteProductException;
Expand All @@ -42,9 +43,11 @@
use PrestaShop\PrestaShop\Core\Domain\Product\Exception\ProductException;
use PrestaShop\PrestaShop\Core\Domain\Product\Exception\ProductNotFoundException;
use PrestaShop\PrestaShop\Core\Domain\Product\Pack\Exception\ProductPackConstraintException;
use PrestaShop\PrestaShop\Core\Domain\Product\ProductTaxRulesGroupSettings;
use PrestaShop\PrestaShop\Core\Domain\Product\Stock\Exception\ProductStockConstraintException;
use PrestaShop\PrestaShop\Core\Domain\Product\ValueObject\ProductId;
use PrestaShop\PrestaShop\Core\Domain\Shop\ValueObject\ShopId;
use PrestaShop\PrestaShop\Core\Domain\TaxRulesGroup\ValueObject\TaxRulesGroupId;
use PrestaShop\PrestaShop\Core\Exception\CoreException;
use PrestaShopException;
use Product;
Expand Down Expand Up @@ -74,22 +77,30 @@ class ProductRepository extends AbstractObjectModelRepository
*/
private $defaultCategoryId;

/**
* @var TaxRulesGroupRepository
*/
private $taxRulesGroupRepository;

/**
* @param Connection $connection
* @param string $dbPrefix
* @param ProductValidator $productValidator
* @param int $defaultCategoryId
* @param TaxRulesGroupRepository $taxRulesGroupRepository
*/
public function __construct(
Connection $connection,
string $dbPrefix,
ProductValidator $productValidator,
int $defaultCategoryId
int $defaultCategoryId,
TaxRulesGroupRepository $taxRulesGroupRepository
) {
$this->connection = $connection;
$this->dbPrefix = $dbPrefix;
$this->productValidator = $productValidator;
$this->defaultCategoryId = $defaultCategoryId;
$this->taxRulesGroupRepository = $taxRulesGroupRepository;
}

/**
Expand Down Expand Up @@ -275,6 +286,11 @@ public function create(array $localizedNames, bool $isVirtual): Product
*/
public function partialUpdate(Product $product, array $propertiesToUpdate, int $errorCode): void
{
$taxRulesGroupId = (int) $product->id_tax_rules_group;
if ($taxRulesGroupId !== ProductTaxRulesGroupSettings::NONE_APPLIED) {
$this->taxRulesGroupRepository->assertTaxRulesGroupExists(new TaxRulesGroupId($taxRulesGroupId));
}

$this->productValidator->validate($product);
$this->partiallyUpdateObjectModel(
$product,
Expand Down
Loading

0 comments on commit 64e72ca

Please sign in to comment.