0

I have to override the Admin shipment save controller. Overridden it in my custom module and it's calling. But when I'm going to create the shipment I'm getting an error.

Fatal error: Uncaught Error: Call to a member function validate() on null for line

$validationResult = $this->shipmentValidator->validate($shipment, [QuantityValidator::class]);

<preference for="Magento\Shipping\Controller\Adminhtml\Order\Shipment\Save" type="Vendor\Module\Controller\Adminhtml\Order\Shipment\Save" />

<?php
    namespace Vendor\Module\Controller\Adminhtml\Order\Shipment;

    use Magento\Framework\App\Action\HttpPostActionInterface;
    use Magento\Framework\Controller\ResultFactory;
    use Magento\Sales\Model\Order\Shipment\Validation\QuantityValidator;

    Class Save extends \Magento\Shipping\Controller\Adminhtml\Order\Shipment\Save implements HttpPostActionInterface
    {

    /**
     * @var \Magento\Shipping\Controller\Adminhtml\Order\ShipmentLoader
     */
    protected $shipmentLoader;

    /**
     * @var \Magento\Shipping\Model\Shipping\LabelGenerator
     */
    protected $labelGenerator;

    /**
     * @var \Magento\Sales\Model\Order\Email\Sender\ShipmentSender
     */
    protected $shipmentSender;

    /**
     * @var \Magento\Sales\Model\Order\Shipment\ShipmentValidatorInterface
     */
    private $shipmentValidator;

    /**
     * @var \Magento\Framework\App\ResourceConnection
     */
    protected $resourceConnection;

    public function __construct(
        \Magento\Backend\App\Action\Context $context,
        \Magento\Shipping\Controller\Adminhtml\Order\ShipmentLoader $shipmentLoader,
        \Magento\Shipping\Model\Shipping\LabelGenerator $labelGenerator,
        \Magento\Sales\Model\Order\Email\Sender\ShipmentSender $shipmentSender,
        \Magento\Sales\Model\Order\Shipment\ShipmentValidatorInterface $shipmentValidator = null,
        \Magento\Framework\App\ResourceConnection $resourceConnection
    ) {
        $this->resourceConnection = $resourceConnection;
        parent::__construct(
            $context,
            $shipmentLoader,
            $labelGenerator,
            $shipmentSender,
            $shipmentValidator ?: \Magento\Framework\App\ObjectManager::getInstance()
            ->get(\Magento\Sales\Model\Order\Shipment\ShipmentValidatorInterface::class)
        );
    }

    public function execute()
    {
        /** @var \Magento\Backend\Model\View\Result\Redirect $resultRedirect */
        $resultRedirect = $this->resultRedirectFactory->create();

        $formKeyIsValid = $this->_formKeyValidator->validate($this->getRequest());
        $isPost = $this->getRequest()->isPost();
        if (!$formKeyIsValid || !$isPost) {
            $this->messageManager->addErrorMessage(__('We can\'t save the shipment right now.'));
            return $resultRedirect->setPath('sales/order/index');
        }

        $data = $this->getRequest()->getParam('shipment');

        $connection = $this->resourceConnection->getConnection();

        if (!empty($data['comment_text'])) {
            $this->_objectManager->get(\Magento\Backend\Model\Session::class)->setCommentText($data['comment_text']);
        }

        $isNeedCreateLabel = isset($data['create_shipping_label']) && $data['create_shipping_label'];
        $responseAjax = new \Magento\Framework\DataObject();

        try {
            $this->shipmentLoader->setOrderId($this->getRequest()->getParam('order_id'));
            $this->shipmentLoader->setShipmentId($this->getRequest()->getParam('shipment_id'));
            $this->shipmentLoader->setShipment($data);
            $this->shipmentLoader->setTracking($this->getRequest()->getParam('tracking'));
            $shipment = $this->shipmentLoader->load();
            if (!$shipment) {
                return $this->resultFactory->create(ResultFactory::TYPE_FORWARD)->forward('noroute');
            }

            if (!empty($data['comment_text'])) {
                $shipment->addComment(
                    $data['comment_text'],
                    isset($data['comment_customer_notify']),
                    isset($data['is_visible_on_front'])
                );

                $shipment->setCustomerNote($data['comment_text']);
                $shipment->setCustomerNoteNotify(isset($data['comment_customer_notify']));
            }
            $validationResult = $this->shipmentValidator->validate($shipment, [QuantityValidator::class]);

            if ($validationResult->hasMessages()) {
                $this->messageManager->addErrorMessage(
                    __("Shipment Document Validation Error(s):\n" . implode("\n", $validationResult->getMessages()))
                );
                return $resultRedirect->setPath('*/*/new', ['order_id' => $this->getRequest()->getParam('order_id')]);
            }
            $shipment->register();

            $shipment->getOrder()->setCustomerNoteNotify(!empty($data['send_email']));

            if ($isNeedCreateLabel) {
                $this->labelGenerator->create($shipment, $this->_request);
                $responseAjax->setOk(true);
            }

            $this->_saveShipment($shipment);

            if (!empty($data['send_email'])) {
                $this->shipmentSender->send($shipment);
            }

            $shipmentCreatedMessage = __('The shipment has been created.');
            $labelCreatedMessage = __('You created the shipping label.');

            $this->messageManager->addSuccessMessage(
                $isNeedCreateLabel ? $shipmentCreatedMessage . ' ' . $labelCreatedMessage : $shipmentCreatedMessage
            );
            $this->_objectManager->get(\Magento\Backend\Model\Session::class)->getCommentText(true);
        } catch (\Magento\Framework\Exception\LocalizedException $e) {
            if ($isNeedCreateLabel) {
                $responseAjax->setError(true);
                $responseAjax->setMessage($e->getMessage());
            } else {
                $this->messageManager->addErrorMessage($e->getMessage());
                return $resultRedirect->setPath('*/*/new', ['order_id' => $this->getRequest()->getParam('order_id')]);
            }
        } catch (\Exception $e) {
            $this->_objectManager->get(\Psr\Log\LoggerInterface::class)->critical($e);
            if ($isNeedCreateLabel) {
                $responseAjax->setError(true);
                $responseAjax->setMessage(__('An error occurred while creating shipping label.'));
            } else {
                $this->messageManager->addErrorMessage(__('Cannot save shipment.'));
                return $resultRedirect->setPath('*/*/new', ['order_id' => $this->getRequest()->getParam('order_id')]);
            }
        }
        if ($isNeedCreateLabel) {
            return $this->resultFactory->create(ResultFactory::TYPE_JSON)->setJsonData($responseAjax->toJson());
        }

        return $resultRedirect->setPath('sales/order/view', ['order_id' => $shipment->getOrderId()]);
    }
}

3 Answers 3

0

Check with below constructor

public function __construct(
    \Magento\Backend\App\Action\Context $context,
    \Magento\Shipping\Controller\Adminhtml\Order\ShipmentLoader $shipmentLoader,
    \Magento\Shipping\Model\Shipping\LabelGenerator $labelGenerator,
    \Magento\Sales\Model\Order\Email\Sender\ShipmentSender $shipmentSender,
    \Magento\Sales\Model\Order\Shipment\ShipmentValidatorInterface $shipmentValidator,
    \Magento\Framework\App\ResourceConnection $resourceConnection
) {
    $this->resourceConnection = $resourceConnection;
    parent::__construct(
        $context,
        $shipmentLoader,
        $labelGenerator,
        $shipmentSender,
        $shipmentValidator
    );
}
6
  • I'm getting error for shipment validator not form validator
    – m2dev
    Apr 7, 2021 at 11:19
  • If you are using preference then there is no need to use constructor Apr 7, 2021 at 11:19
  • But I have injected additional class there \Magento\Framework\App\ResourceConnection $resourceConnection
    – m2dev
    Apr 7, 2021 at 11:21
  • I have updated my answer please check. Apr 7, 2021 at 11:29
  • Still the same error.
    – m2dev
    Apr 7, 2021 at 11:54
0

try below code.

public function __construct(
    \Magento\Backend\App\Action\Context $context,
    \Magento\Shipping\Controller\Adminhtml\Order\ShipmentLoader $shipmentLoader,
    \Magento\Shipping\Model\Shipping\LabelGenerator $labelGenerator,
    \Magento\Sales\Model\Order\Email\Sender\ShipmentSender $shipmentSender,
    \Magento\Sales\Model\Order\Shipment\ShipmentValidatorInterface $shipmentValidator,
    \Magento\Framework\App\ResourceConnection $resourceConnection
) {
    $this->resourceConnection = $resourceConnection;
    $this->shipmentValidator = $shipmentValidator ?: \Magento\Framework\App\ObjectManager::getInstance()
        ->get(\Magento\Sales\Model\Order\Shipment\ShipmentValidatorInterface::class);
    parent::__construct(
        $context,
        $shipmentLoader,
        $labelGenerator,
        $shipmentSender,
        $this->shipmentValidator
    );

}

Hope it will work for you.

0

In my case i try to do by preference, for that need to add admin di.xml

  1. adminhtml/di.xml

  1. Create custom save.php

namespace Vendor\Module\Controller\Adminhtml\Order\Shipment;

use Magento\Framework\App\Action\HttpPostActionInterface; use Magento\Framework\Controller\ResultFactory; use Magento\Sales\Model\Order\Shipment\Validation\QuantityValidator;

class Save extends \Magento\Shipping\Controller\Adminhtml\Order\Shipment\Save {

const ADMIN_RESOURCE = 'Magento_Sales::shipment';

protected $shipmentLoader;


protected $labelGenerator;


protected $shipmentSender;


private $shipmentValidator;

/**
 * @param \Magento\Backend\App\Action\Context $context
 * @param \Magento\Shipping\Controller\Adminhtml\Order\ShipmentLoader $shipmentLoader
 * @param \Magento\Shipping\Model\Shipping\LabelGenerator $labelGenerator
 * @param \Magento\Sales\Model\Order\Email\Sender\ShipmentSender $shipmentSender
 * @param \Magento\Sales\Model\Order\Shipment\ShipmentValidatorInterface|null $shipmentValidator
 */
public function __construct(
    \Magento\Backend\App\Action\Context $context,
    \Magento\Shipping\Controller\Adminhtml\Order\ShipmentLoader $shipmentLoader,
    \Magento\Shipping\Model\Shipping\LabelGenerator $labelGenerator,
    \Magento\Sales\Model\Order\Email\Sender\ShipmentSender $shipmentSender,
    \Magento\Sales\Model\Order\Shipment\ShipmentValidatorInterface $shipmentValidator = null
) {
    $this->shipmentLoader = $shipmentLoader;
    $this->labelGenerator = $labelGenerator;
    $this->shipmentSender = $shipmentSender;
    $this->shipmentValidator = $shipmentValidator ?: \Magento\Framework\App\ObjectManager::getInstance()
        ->get(\Magento\Sales\Model\Order\Shipment\ShipmentValidatorInterface::class);
    parent::__construct($context, $shipmentLoader,$labelGenerator,$shipmentSender, $shipmentValidator );
}

/**
 * Save shipment and order in one transaction
 *
 * @param \Magento\Sales\Model\Order\Shipment $shipment
 * @return \Magento\Shipping\Controller\Adminhtml\Order\Shipment\Save
 */
protected function _saveShipment($shipment)
{
    $shipment->getOrder()->setIsInProcess(true);
    $transaction = $this->_objectManager->create(
        \Magento\Framework\DB\Transaction::class
    );
    $transaction->addObject(
        $shipment
    )->addObject(
        $shipment->getOrder()
    )->save();

    return $this;
}

/**
 * Save shipment
 *
 * We can save only new shipment. Existing shipments are not editable
 *
 * @return \Magento\Framework\Controller\ResultInterface
 * @SuppressWarnings(PHPMD.CyclomaticComplexity)
 * @SuppressWarnings(PHPMD.NPathComplexity)
 */
public function execute()
{
    /** @var \Magento\Backend\Model\View\Result\Redirect $resultRedirect */
    $resultRedirect = $this->resultRedirectFactory->create();

    $formKeyIsValid = $this->_formKeyValidator->validate($this->getRequest());
    $isPost = $this->getRequest()->isPost();
    if (!$formKeyIsValid || !$isPost) {
        $this->messageManager->addErrorMessage(__('We can\'t save the shipment right now.'));
        return $resultRedirect->setPath('sales/order/index');
    }

    $data = $this->getRequest()->getParam('shipment');
    if (!empty($data['comment_text'])) {
        $this->_objectManager->get(\Magento\Backend\Model\Session::class)->setCommentText($data['comment_text']);
    }

    $isNeedCreateLabel = isset($data['create_shipping_label']) && $data['create_shipping_label'];
    $responseAjax = new \Magento\Framework\DataObject();
    try {
        $this->shipmentLoader->setOrderId($this->getRequest()->getParam('order_id'));
        $this->shipmentLoader->setShipmentId($this->getRequest()->getParam('shipment_id'));
        $this->shipmentLoader->setShipment($data);
        $this->shipmentLoader->setTracking($this->getRequest()->getParam('tracking'));
        $shipment = $this->shipmentLoader->load();
        if (!$shipment) {
            return $this->resultFactory->create(ResultFactory::TYPE_FORWARD)->forward('noroute');
        }

        if (!empty($data['comment_text'])) {
            $shipment->addComment(
                $data['comment_text'],
                isset($data['comment_customer_notify']),
                isset($data['is_visible_on_front'])
            );

            $shipment->setCustomerNote($data['comment_text']);
            $shipment->setCustomerNoteNotify(isset($data['comment_customer_notify']));
        }
        $validationResult = $this->shipmentValidator->validate($shipment, [QuantityValidator::class]);

        if ($validationResult->hasMessages()) {
            $this->messageManager->addErrorMessage(
                __("Shipment Document Validation Error(s):\n" . implode("\n", $validationResult->getMessages()))
            );
            return $resultRedirect->setPath('*/*/new', ['order_id' => $this->getRequest()->getParam('order_id')]);
        }
        $shipment->register();

        $shipment->getOrder()->setCustomerNoteNotify(!empty($data['send_email']));

        if ($isNeedCreateLabel) {
            $this->labelGenerator->create($shipment, $this->_request);
            $responseAjax->setOk(true);
        }
        $this->_saveShipment($shipment);

        if (!empty($data['send_email'])) {
            $this->shipmentSender->send($shipment);
        }

        $shipmentCreatedMessage = __('The shipment has been created.');
        $labelCreatedMessage = __('You created the shipping label.');

        $this->messageManager->addSuccessMessage(
            $isNeedCreateLabel ? $shipmentCreatedMessage . ' ' . $labelCreatedMessage : $shipmentCreatedMessage
        );
        $this->_objectManager->get(\Magento\Backend\Model\Session::class)->getCommentText(true);
    } catch (\Magento\Framework\Exception\LocalizedException $e) {
        if ($isNeedCreateLabel) {
            $responseAjax->setError(true);
            $responseAjax->setMessage($e->getMessage());
        } else {
            $this->messageManager->addErrorMessage($e->getMessage());
            return $resultRedirect->setPath('*/*/new', ['order_id' => $this->getRequest()->getParam('order_id')]);
        }
    } catch (\Exception $e) {
        $this->_objectManager->get(\Psr\Log\LoggerInterface::class)->critical($e);
        if ($isNeedCreateLabel) {
            $responseAjax->setError(true);
            $responseAjax->setMessage(__('An error occurred while creating shipping label.'));
        } else {
            $this->messageManager->addErrorMessage(__('Cannot save shipment.'));
            return $resultRedirect->setPath('*/*/new', ['order_id' => $this->getRequest()->getParam('order_id')]);
        }
    }
    if ($isNeedCreateLabel) {
        return $this->resultFactory->create(ResultFactory::TYPE_JSON)->setJsonData($responseAjax->toJson());
    }

    return $resultRedirect->setPath('sales/order/view', ['order_id' => $shipment->getOrderId()]);
}

}

1
  • <preference for="Magento\Shipping\Controller\Adminhtml\Order\Shipment\Save" type="Vendor\Module\Controller\Adminhtml\Order\Shipment\Save" /> Sep 28, 2021 at 15:40

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.