diff --git a/Classes/Utility/StockUtility.php b/Classes/Utility/StockUtility.php index 3c70601..f51a904 100644 --- a/Classes/Utility/StockUtility.php +++ b/Classes/Utility/StockUtility.php @@ -3,6 +3,7 @@ namespace Extcode\CartProducts\Utility; use TYPO3\CMS\Core\Cache\CacheManager; +use TYPO3\CMS\Core\Database\ConnectionPool; use TYPO3\CMS\Core\Utility\GeneralUtility; /** @@ -48,34 +49,27 @@ public function handleStock($params) { $cartProduct = $params['cartProduct']; - if ($cartProduct->getProductType() == 'CartProducts') { - /** @var \Extcode\Cart\Domain\Repository\Product\ProductRepository $productRepository */ - $productRepository = $this->objectManager->get( - \Extcode\CartProducts\Domain\Repository\Product\ProductRepository::class - ); - /** @var \Extcode\Cart\Domain\Repository\Product\BeVariantRepository $beVariantRepository */ - $beVariantRepository = $this->objectManager->get( - \Extcode\CartProducts\Domain\Repository\Product\BeVariantRepository::class - ); - - $product = $productRepository->findByUid($cartProduct->getProductId()); - if ($product->isHandleStock()) { - if ($product->isHandleStockInVariants()) { - /** @var \Extcode\Cart\Domain\Model\Cart\BeVariant $cartBeVariant */ - foreach ($cartProduct->getBeVariants() as $cartBeVariant) { - /** @var \Extcode\Cart\Domain\Model\Product\BeVariant $productBeVariant */ - $productBeVariant = $beVariantRepository->findByUid($cartBeVariant->getId()); - $productBeVariant->removeFromStock($cartBeVariant->getQuantity()); - $beVariantRepository->update($productBeVariant); - } + if ($cartProduct->getProductType() === 'CartProducts') { + $productConnection = GeneralUtility::makeInstance(ConnectionPool::class) + ->getConnectionForTable('tx_cartproducts_domain_model_product_product'); + $productQueryBuilder = $productConnection->createQueryBuilder(); + + $product = $productQueryBuilder + ->select('uid', 'handle_stock', 'handle_stock_in_variants') + ->from('tx_cartproducts_domain_model_product_product') + ->where( + $productQueryBuilder->expr()->eq('uid', $productQueryBuilder->createNamedParameter($cartProduct->getProductId(), \PDO::PARAM_INT)) + ) + ->execute()->fetch(); + + if ($product['handle_stock']) { + if ($product['handle_stock_in_variants']) { + $this->handleStockInBeVariant($cartProduct); } else { - $product->removeFromStock($cartProduct->getQuantity()); - $productRepository->update($product); + $this->handleStockInProduct($cartProduct); } - $this->persistenceManager->persistAll(); - - $this->flushCache($product->getUid()); + $this->flushCache($product['uid']); } } } @@ -91,4 +85,64 @@ protected function flushCache(int $productId) $cacheManager->flushCachesInGroupByTag('pages', $cacheTag); } + + /** + * @param \Extcode\Cart\Domain\Model\Cart\Product $cartProduct + */ + protected function handleStockInProduct(\Extcode\Cart\Domain\Model\Cart\Product $cartProduct): void + { + $productConnection = GeneralUtility::makeInstance(ConnectionPool::class) + ->getConnectionForTable('tx_cartproducts_domain_model_product_product'); + $productQueryBuilder = $productConnection->createQueryBuilder(); + + $product = $productQueryBuilder + ->select('stock') + ->from('tx_cartproducts_domain_model_product_product') + ->where( + $productQueryBuilder->expr()->eq('uid', $productQueryBuilder->createNamedParameter($cartProduct->getProductId(), \PDO::PARAM_INT)) + ) + ->execute()->fetch(); + + $productQueryBuilder + ->update('tx_cartproducts_domain_model_product_product') + ->where( + $productQueryBuilder->expr()->eq('uid', $productQueryBuilder->createNamedParameter($cartProduct->getProductId(), \PDO::PARAM_INT)) + ) + ->orWhere( + $productQueryBuilder->expr()->eq('l10n_parent', $productQueryBuilder->createNamedParameter($cartProduct->getProductId(), \PDO::PARAM_INT)) + ) + ->set('stock', $product['stock'] - $cartProduct->getQuantity()) + ->execute(); + } + + /** + * @param \Extcode\Cart\Domain\Model\Cart\Product $cartProduct + */ + protected function handleStockInBeVariant(\Extcode\Cart\Domain\Model\Cart\Product $cartProduct): void + { + $beVariantConnection = GeneralUtility::makeInstance(ConnectionPool::class) + ->getConnectionForTable('tx_cartproducts_domain_model_product_bevariant'); + + foreach ($cartProduct->getBeVariants() as $cartBeVariant) { + $beVariantQueryBuilder = $beVariantConnection->createQueryBuilder(); + $beVariant = $beVariantQueryBuilder + ->select('stock') + ->from('tx_cartproducts_domain_model_product_bevariant') + ->where( + $beVariantQueryBuilder->expr()->eq('uid', $beVariantQueryBuilder->createNamedParameter($cartBeVariant->getId(), \PDO::PARAM_INT)) + ) + ->execute()->fetch(); + + $beVariantQueryBuilder + ->update('tx_cartproducts_domain_model_product_bevariant') + ->where( + $beVariantQueryBuilder->expr()->eq('uid', $beVariantQueryBuilder->createNamedParameter($cartBeVariant->getId(), \PDO::PARAM_INT)) + ) + ->orWhere( + $beVariantQueryBuilder->expr()->eq('l10n_parent', $beVariantQueryBuilder->createNamedParameter($cartBeVariant->getId(), \PDO::PARAM_INT)) + ) + ->set('stock', $beVariant['stock'] - $cartBeVariant->getQuantity()) + ->execute(); + } + } } diff --git a/Configuration/TCA/tx_cartproducts_domain_model_product_bevariant.php b/Configuration/TCA/tx_cartproducts_domain_model_product_bevariant.php index 310ceda..6fa247c 100644 --- a/Configuration/TCA/tx_cartproducts_domain_model_product_bevariant.php +++ b/Configuration/TCA/tx_cartproducts_domain_model_product_bevariant.php @@ -311,7 +311,9 @@ 'size' => 30, 'eval' => 'required,int', 'default' => 0, - ] + ], + 'l10n_mode' => 'exclude', + 'l10n_display' => 'defaultAsReadonly', ], 'product' => [ diff --git a/Configuration/TCA/tx_cartproducts_domain_model_product_product.php b/Configuration/TCA/tx_cartproducts_domain_model_product_product.php index 36af524..d4e47bf 100644 --- a/Configuration/TCA/tx_cartproducts_domain_model_product_product.php +++ b/Configuration/TCA/tx_cartproducts_domain_model_product_product.php @@ -774,6 +774,8 @@ 'type' => 'check', ], 'onChange' => 'reload', + 'l10n_mode' => 'exclude', + 'l10n_display' => 'defaultAsReadonly', ], 'handle_stock_in_variants' => [ 'exclude' => 1, @@ -788,6 +790,8 @@ 'type' => 'check', ], 'onChange' => 'reload', + 'l10n_mode' => 'exclude', + 'l10n_display' => 'defaultAsReadonly', ], 'stock' => [ 'exclude' => 1, @@ -803,7 +807,9 @@ 'size' => 30, 'eval' => 'int', 'default' => 0, - ] + ], + 'l10n_mode' => 'exclude', + 'l10n_display' => 'defaultAsReadonly', ], 'tags' => [ diff --git a/Documentation/Changelog/2.1/Important-46-ExcludeStockHandlingFromTranslation.rst b/Documentation/Changelog/2.1/Important-46-ExcludeStockHandlingFromTranslation.rst new file mode 100644 index 0000000..c10e0e5 --- /dev/null +++ b/Documentation/Changelog/2.1/Important-46-ExcludeStockHandlingFromTranslation.rst @@ -0,0 +1,87 @@ +.. include:: ../../Includes.txt + +======================================================== +Important: #46 - Exclude Stock Handling from Translation +======================================================== + +See :issue:`46` + +Description +=========== + +For each product you can activate the stock management in the backend. Up to now, stock management was carried out +independently for each language. +The online shops implemented with the extension sell products with translated product titles and descriptions, but +not translated products. +Therefore there should be a collective stock for all translations of a product. + +.. IMPORTANT:: + Check your database for differences in translated products. + If any query shows a result, please take a closer look at the products + or its backend variants and update them. + If you are sure, the respective update query can also be used to adapt + the data of the translations to the original language. For different + stock levels in the products or their backend variants, this should be + compared with the actual stock level. + + .. code-block:: sql + :caption: **Check and Update handle_stock in Products** + + SELECT orig.uid AS orig_uid, orig.title AS orig_title, orig.handle_stock AS orig_handle_stock, trans.uid AS trans_uid, trans.title AS trans_title, trans.handle_stock AS trans_handle_stock + FROM `tx_cartproducts_domain_model_product_product` AS orig + JOIN `tx_cartproducts_domain_model_product_product` AS trans ON orig.uid = trans.l10n_parent + WHERE orig.handle_stock <> trans.handle_stock + + UPDATE `tx_cartproducts_domain_model_product_product` AS trans + JOIN `tx_cartproducts_domain_model_product_product` AS orig ON orig.uid = trans.l10n_parent + SET trans.handle_stock = orig.handle_stock + WHERE orig.handle_stock <> trans.handle_stock + + .. code-block:: sql + :caption: **Check and Update handle_stock_in_variants in Products** + + SELECT orig.uid AS orig_uid, orig.title AS orig_title, orig.handle_stock_in_variants AS orig_handle_stock_in_variants, trans.uid AS trans_uid, trans.title AS trans_title, trans.handle_stock_in_variants AS trans_handle_stock_in_variants + FROM `tx_cartproducts_domain_model_product_product` AS orig + JOIN `tx_cartproducts_domain_model_product_product` AS trans ON orig.uid = trans.l10n_parent + WHERE orig.handle_stock_in_variants <> trans.handle_stock_in_variants + + UPDATE `tx_cartproducts_domain_model_product_product` AS trans + JOIN `tx_cartproducts_domain_model_product_product` AS orig ON orig.uid = trans.l10n_parent + SET trans.handle_stock_in_variants = orig.handle_stock_in_variants + WHERE orig.handle_stock_in_variants <> trans.handle_stock_in_variants + + .. code-block:: sql + :caption: **Check and Update stock in Products** + + SELECT orig.uid AS orig_uid, orig.title AS orig_title, orig.stock AS orig_stock, trans.uid AS trans_uid, trans.title AS trans_title, trans.stock AS trans_stock + FROM `tx_cartproducts_domain_model_product_product` AS orig + JOIN `tx_cartproducts_domain_model_product_product` AS trans ON orig.uid = trans.l10n_parent + WHERE orig.stock <> trans.stock + + UPDATE `tx_cartproducts_domain_model_product_product` AS trans + JOIN `tx_cartproducts_domain_model_product_product` AS orig ON orig.uid = trans.l10n_parent + SET trans.stock = orig.stock + WHERE orig.stock <> trans.stock + + .. code-block:: sql + :caption: **Check and Update stock in Backend Variants** + + SELECT orig.product, orig_product.title, orig.uid AS orig_uid, orig.stock AS orig_stock, trans.uid AS trans_uid, trans.stock AS trans_stock + FROM `tx_cartproducts_domain_model_product_bevariant` AS orig + JOIN `tx_cartproducts_domain_model_product_bevariant` AS trans ON orig.uid = trans.l10n_parent + JOIN `tx_cartproducts_domain_model_product_product` AS orig_product ON orig.product = orig_product.uid + WHERE orig.stock IS NOT NULL AND orig.stock <> trans.stock; + + UPDATE `tx_cartproducts_domain_model_product_bevariant` AS trans + JOIN `tx_cartproducts_domain_model_product_bevariant` AS orig ON orig.uid = trans.l10n_parent + SET trans.stock = orig.stock + WHERE orig.stock IS NOT NULL AND orig.stock <> trans.stock + + Saving the products in the backend should update the field as well. + +.. NOTE:: + + If you require the old language-specific stock management, this version **must not** be installed. + Please contact me in this case, so that an appropriate solution can be developed. + +.. index:: TCA \ No newline at end of file diff --git a/Documentation/Changelog/2.1/Important-47-ExcludeProductTypeFromTranslation.rst b/Documentation/Changelog/2.1/Important-47-ExcludeProductTypeFromTranslation.rst index a08f36c..16364bc 100644 --- a/Documentation/Changelog/2.1/Important-47-ExcludeProductTypeFromTranslation.rst +++ b/Documentation/Changelog/2.1/Important-47-ExcludeProductTypeFromTranslation.rst @@ -15,4 +15,24 @@ The product must of course have the same type in all languages. Therefore, this change will remove the product type in the translations and take the type of the original language. +.. IMPORTANT:: + Check your database for differences in translated products. + If you are sure, the respective update query can also be used to adapt + the data of the translations to the original language. + + .. code-block:: sql + :caption: **Check and Update product_type in Products** + + SELECT orig.uid AS orig_uid, orig.title AS orig_title, orig.product_type AS orig_product_type, trans.uid AS trans_uid, trans.title AS trans_title, trans.product_type AS trans_product_type + FROM `tx_cartproducts_domain_model_product_product` AS orig + JOIN `tx_cartproducts_domain_model_product_product` AS trans ON orig.uid = trans.l10n_parent + WHERE orig.product_type <> trans.product_type + + UPDATE `tx_cartproducts_domain_model_product_product` AS trans + JOIN `tx_cartproducts_domain_model_product_product` AS orig ON orig.uid = trans.l10n_parent + SET trans.product_type = orig.product_type + WHERE orig.product_type <> trans.product_type + + Saving the products in the backend should update the field as well. + .. index:: TCA \ No newline at end of file