I am trying to change a custom value each time I add to the cart via the “reorder” button.
Right now I am trying to do this in the file “MagentoSalesModelReorderReorder.php” but without success. This is the code:
<?php
/**
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
declare(strict_types=1);
namespace MagentoSalesModelReorder;
use MagentoCatalogApiDataProductInterface;
use MagentoCatalogModelProduct;
use MagentoCatalogModelResourceModelProductCollection;
use MagentoFrameworkExceptionInputException;
use MagentoFrameworkExceptionNoSuchEntityException;
use MagentoQuoteApiCartRepositoryInterface;
use MagentoQuoteApiDataCartInterface;
use MagentoQuoteModelCartCustomerCartResolver;
use MagentoQuoteModelQuote;
use MagentoQuoteModelGuestCartGuestCartResolver;
use MagentoSalesApiDataOrderItemInterface;
use MagentoSalesHelperReorder as ReorderHelper;
use MagentoSalesModelOrderItem;
use MagentoSalesModelOrderFactory;
use MagentoSalesModelResourceModelOrderItemCollection as ItemCollection;
use MagentoCatalogModelResourceModelProductCollectionFactory as ProductCollectionFactory;
use PsrLogLoggerInterface;
/**
* Allows customer quickly to reorder previously added products and put them to the Cart
* @SuppressWarnings(PHPMD.CouplingBetweenObjects)
*/
class Reorder
{
/**#@+
* Error message codes
*/
private const ERROR_PRODUCT_NOT_FOUND = 'PRODUCT_NOT_FOUND';
private const ERROR_INSUFFICIENT_STOCK = 'INSUFFICIENT_STOCK';
private const ERROR_NOT_SALABLE = 'NOT_SALABLE';
private const ERROR_REORDER_NOT_AVAILABLE = 'REORDER_NOT_AVAILABLE';
private const ERROR_UNDEFINED = 'UNDEFINED';
/**#@-*/
/**
* List of error messages and codes.
*/
private const MESSAGE_CODES = [
'The required options you selected are not available' => self::ERROR_NOT_SALABLE,
'Product that you are trying to add is not available' => self::ERROR_NOT_SALABLE,
'This product is out of stock' => self::ERROR_NOT_SALABLE,
'There are no source items' => self::ERROR_NOT_SALABLE,
'The fewest you may purchase is' => self::ERROR_INSUFFICIENT_STOCK,
'The most you may purchase is' => self::ERROR_INSUFFICIENT_STOCK,
'The requested qty is not available' => self::ERROR_INSUFFICIENT_STOCK,
];
/**
* @var OrderFactory
*/
private $orderFactory;
/**
* @var ReorderHelper
*/
private $reorderHelper;
/**
* @var LoggerInterface
*/
private $logger;
/**
* @var CartRepositoryInterface
*/
private $cartRepository;
/**
* @var DataError[]
*/
private $errors = [];
/**
* @var CustomerCartResolver
*/
private $customerCartProvider;
/**
* @var ProductCollectionFactory
*/
private $productCollectionFactory;
/**
* @var GuestCartResolver
*/
private $guestCartResolver;
/**
* @var OrderInfoBuyRequestGetter
*/
private $orderInfoBuyRequestGetter;
/**
* @param OrderFactory $orderFactory
* @param CustomerCartResolver $customerCartProvider
* @param GuestCartResolver $guestCartResolver
* @param CartRepositoryInterface $cartRepository
* @param ReorderHelper $reorderHelper
* @param LoggerInterface $logger
* @param ProductCollectionFactory $productCollectionFactory
* @param OrderInfoBuyRequestGetter $orderInfoBuyRequestGetter
*/
public function __construct(
OrderFactory $orderFactory,
CustomerCartResolver $customerCartProvider,
GuestCartResolver $guestCartResolver,
CartRepositoryInterface $cartRepository,
ReorderHelper $reorderHelper,
LoggerInterface $logger,
ProductCollectionFactory $productCollectionFactory,
OrderInfoBuyRequestGetter $orderInfoBuyRequestGetter
) {
$this->orderFactory = $orderFactory;
$this->cartRepository = $cartRepository;
$this->reorderHelper = $reorderHelper;
$this->logger = $logger;
$this->customerCartProvider = $customerCartProvider;
$this->guestCartResolver = $guestCartResolver;
$this->productCollectionFactory = $productCollectionFactory;
$this->orderInfoBuyRequestGetter = $orderInfoBuyRequestGetter;
}
/**
* Allows customer quickly to reorder previously added products and put them to the Cart
*
* @param string $orderNumber
* @param string $storeId
* @return DataReorderOutput
* @throws InputException Order is not found
* @throws NoSuchEntityException The specified customer does not exist.
* @throws MagentoFrameworkExceptionCouldNotSaveException Could not create customer Cart
*/
public function execute(string $orderNumber, string $storeId): DataReorderOutput
{
$order = $this->orderFactory->create()->loadByIncrementIdAndStoreId($orderNumber, $storeId);
$orderIncrementId = $order->getIncrementId();
if (!$order->getId()) {
throw new InputException(
__('Cannot find order number "%1" in store "%2"', $orderNumber, $storeId)
);
}
$customerId = (int)$order->getCustomerId();
$this->errors = [];
$cart = $customerId === 0
? $this->guestCartResolver->resolve()
: $this->customerCartProvider->resolve($customerId);
if (!$this->reorderHelper->isAllowed($order->getStore())) {
$this->addError((string)__('Reorders are not allowed.'), self::ERROR_REORDER_NOT_AVAILABLE);
return $this->prepareOutput($cart);
}
$this->addItemsToCart($cart, $order->getItemsCollection(), $storeId);
try {
$this->cartRepository->save($cart);
} catch (MagentoFrameworkExceptionLocalizedException $e) {
// handle exception from MagentoQuoteModelQuoteRepositorySaveHandler::save
$this->addError($e->getMessage());
}
$savedCart = $this->cartRepository->get($cart->getId());
return $this->prepareOutput($savedCart);
}
/**
* Add collections of order items to cart.
*
* @param Quote $cart
* @param ItemCollection $orderItems
* @param string $storeId
* @return void
*/
private function addItemsToCart(Quote $cart, ItemCollection $orderItems, string $storeId): void
{
$orderItemProductIds = [];
/** @var MagentoSalesModelOrderItem[] $orderItemsByProductId */
$orderItemsByProductId = [];
/** @var MagentoSalesModelOrderItem $item */
foreach ($orderItems as $item) {
if ($item->getParentItem() === null) {
$orderItemProductIds[] = $item->getProductId();
$orderItemsByProductId[$item->getProductId()][$item->getId()] = $item;
}
}
$products = $this->getOrderProducts($storeId, $orderItemProductIds);
// compare founded products and throw an error if some product not exists
$productsNotFound = array_diff($orderItemProductIds, array_keys($products));
if (!empty($productsNotFound)) {
foreach ($productsNotFound as $productId) {
/** @var MagentoSalesModelOrderItem $orderItemProductNotFound */
$this->addError(
(string)__('Could not find a product with ID "%1"', $productId),
self::ERROR_PRODUCT_NOT_FOUND
);
}
}
foreach ($orderItemsByProductId as $productId => $orderItems) {
if (!isset($products[$productId])) {
continue;
}
$product = $products[$productId];
foreach ($orderItems as $orderItem) {
$sku = $orderItem->getSku();
if (substr($sku, 0, 3) !== 'TGR') {
$this->addItemToCart($orderItem, $cart, clone $product);
$this->getQuoteItem();
}
}
}
}
/**
* Get order products by store id and order item product ids.
*
* @param string $storeId
* @param int[] $orderItemProductIds
* @return Product[]
* @throws MagentoFrameworkExceptionLocalizedException
*/
private function getOrderProducts(string $storeId, array $orderItemProductIds): array
{
/** @var Collection $collection */
$collection = $this->productCollectionFactory->create();
$collection->setStore($storeId)
->addIdFilter($orderItemProductIds)
->addStoreFilter()
->addAttributeToSelect('*')
->joinAttribute('status', 'catalog_product/status', 'entity_id', null, 'inner')
->joinAttribute('visibility', 'catalog_product/visibility', 'entity_id', null, 'inner')
->addOptionsToResult();
return $collection->getItems();
}
/**
* Adds order item product to cart.
*
* @param OrderItemInterface $orderItem
* @param Quote $cart
* @param ProductInterface $product
* @return void
*/
private function addItemToCart(OrderItemInterface $orderItem, Quote $cart, ProductInterface $product): void
{
$infoBuyRequest = $this->orderInfoBuyRequestGetter->getInfoBuyRequest($orderItem);
$addProductResult = null;
try {
$addProductResult = $cart->addProduct($product, $infoBuyRequest);
} catch (MagentoFrameworkExceptionLocalizedException $e) {
$this->addError($this->getCartItemErrorMessage($orderItem, $product, $e->getMessage()));
} catch (Throwable $e) {
$this->logger->critical($e);
$this->addError($this->getCartItemErrorMessage($orderItem, $product), self::ERROR_UNDEFINED);
}
// error happens in case the result is string
if (is_string($addProductResult)) {
$errors = array_unique(explode("n", $addProductResult));
foreach ($errors as $error) {
$this->addError($this->getCartItemErrorMessage($orderItem, $product, $error));
}
}
}
/**
* Add order line item error
*
* @param string $message
* @param string|null $code
* @return void
*/
private function addError(string $message, string $code = null): void
{
$this->errors[] = new DataError(
$message,
$code ?? $this->getErrorCode($message)
);
}
/**
* Get message error code. Ad-hoc solution based on message parsing.
*
* @param string $message
* @return string
*/
private function getErrorCode(string $message): string
{
$code = self::ERROR_UNDEFINED;
$matchedCodes = array_filter(
self::MESSAGE_CODES,
function ($key) use ($message) {
return false !== strpos($message, $key);
},
ARRAY_FILTER_USE_KEY
);
if (!empty($matchedCodes)) {
$code = current($matchedCodes);
}
return $code;
}
/**
* Prepare output
*
* @param CartInterface $cart
* @return DataReorderOutput
*/
private function prepareOutput(CartInterface $cart): DataReorderOutput
{
$output = new DataReorderOutput($cart, $this->errors);
$this->errors = [];
// we already show user errors, do not expose it to cart level
$cart->setHasError(false);
return $output;
}
/**
* Get error message for a cart item
*
* @param Item $item
* @param Product $product
* @param string|null $message
* @return string
*/
private function getCartItemErrorMessage(Item $item, Product $product, string $message = null): string
{
// try to get sku from line-item first.
// for complex product type: if custom option is not available it can cause error
$sku = $item->getSku() ?? $product->getData('sku');
return (string)($message
? __('Could not add the product with SKU "%1" to the shopping cart: %2', $sku, $message)
: __('Could not add the product with SKU "%1" to the shopping cart', $sku));
}
}
Basically I would like to have a value set in the “quote_item” table for each item taken back from the order and added back to the cart.
How can I do something like this when I click Reorder?