4

I have an menu option to create multiple shipments from selected orders in an extension.

It works on some stores (tested) but the store I'm trying to get it to work on (2.3.1) uses MSI and I'm wondering if it's something to do with that?

 protected function massAction(AbstractCollection $collection)
{ 
 $countShipOrder = 0;
 foreach ($collection->getItems() as $order) 
 { 
 try 
 { 
 $shipOrder = $this->_shipOrder->create();
 $ship = $shipOrder->shipOrder($order->getId());
 $countShipOrder++; 
 }
 catch (\Exception $e) 
 {
 $this->messageManager->addError(__('Order Shipments Already Created For : %1',$order['increment_id']));
 } 
 }
 $countNonShipOrder = $collection->count() - $countShipOrder;
 if ($countShipOrder) {
 $string = $countShipOrder.' success, '.$countNonShipOrder .' fails';
 $this->messageManager->addSuccess(__('Order shipments processed : %1.', $string));
 }
 $this->_redirect('sales/order/index');
}

class ShipOrder extends \Magento\Framework\Model\AbstractModel
{ 
 protected $_scopeConfig;
 protected $_order;
 protected $_orderConverter;
 protected $eventManager;
 public function __construct(
 \Magento\Framework\App\Config\ScopeConfigInterface $scopeConfig,
 \Magento\Sales\Model\OrderFactory $order,
 \Magento\Sales\Model\Convert\OrderFactory $orderConverter,
 \Magento\Framework\Event\Manager $eventManager,
 \Magento\Framework\Model\Context $context
 ){
 $this->_scopeConfig = $scopeConfig;
 $this->_order = $order;
 $this->eventManager = $eventManager;
 $this->_orderConverter = $orderConverter;
 }
 public function shipOrder($orderId)
 {
 //load by order 
 $order = $this->_order->create()->load($orderId);
 // Check if order can be shipped or has already shipped
 if ( !$order->canShip()) {
 throw new \Magento\Framework\Exception\LocalizedException(
 __('You can\'t create an shipment for order increment id: %1', $order->getIncrementId())
 );
 return false;
 }
 else {
 $shipment = $this->createShipment($order);
 return $shipment;
 }
 }
 public function createShipment($order){
 // Initialize the order shipment object
 $convertOrder = $this->_orderConverter->create();
 $shipment = $convertOrder->toShipment($order);
 // Loop through order items
 foreach ($order->getAllItems() as $orderItem) {
 // Check if order item has qty to ship or is virtual
 if (! $orderItem->getQtyToShip() || $orderItem->getIsVirtual()) {
 continue;
 }
 $qtyShipped = $orderItem->getQtyToShip();
 // Create shipment item with qty
 $shipmentItem = $convertOrder->itemToShipmentItem($orderItem)->setQty($qtyShipped);
 // Add shipment item to shipment
 $shipment->addItem($shipmentItem);
 }
 // Register shipment
 $shipment->register();
 $shipment->getOrder()->setIsInProcess(true);
 try {
 // Save created shipment and order
 $shipment->save();
 $shipment->getOrder()->save();
 return $shipment;
 } catch (\Exception $e) {
 throw new \Magento\Framework\Exception\LocalizedException(__($e->getMessage()));
 }
 }

That final try catch where it tries to save the shipment is where the error is being thrown.

The undefined variable sourceCode is coming from /vendor/magento/module-inventory-shipping/Observer/SourceDeductionProcessor.php on line 112

Anas Mansuri
2,6371 gold badge12 silver badges29 bronze badges
asked Aug 7, 2019 at 10:26
5
  • Have you search for sourceCode references? Commented Aug 7, 2019 at 10:37
  • I missed the full exception, my bad, I've put in where the undefined variable sits in Magento vendor Commented Aug 7, 2019 at 10:44
  • Well I'm afraid you going to have to put a fix of your own github.com/magento/inventory/blob/2.3-develop/app/code/Magento/… Is not done properly :/ Commented Aug 7, 2019 at 10:55
  • this doesnt help explain to me what the problem is. Commented Aug 7, 2019 at 13:34
  • 1
    The problem is $this->isSingleSourceMode->execute() and $shipment->getExtensionAttributes() fail the conditions therefore the $sourceCode variable is never initialise. You will need to find out why both of those fail. Use a debugger and trace it down. Commented Aug 7, 2019 at 13:42

2 Answers 2

6

As MSI has been implemented, in your code you have to specify the source location.

Add the following line before $shipment save()

$shipment->getExtensionAttributes()->setSourceCode('default');
answered Oct 9, 2019 at 8:34
0
$source = '';
$product = $this->_productFactory->create()->load($productId);
$_sources = $this->getSourceItemDetailBySKU($product->getSku());
if(empty($source)) {
 if (count($_sources) > 0) {
 foreach ($_sources as $_source) {
 $dataSource = $_source->getData();
 $qty = (int)$dataSource['quantity'];
 if((int)$dataSource['quantity'] == 0){ continue ;}
 if (empty($arraySource[$dataSource['source_code']])) {
 $arraySource[$dataSource['source_code']] = 1;
 } else {
 $arraySource[$dataSource['source_code']] = (int)$arraySource[$dataSource['source_code']] + 1;
 }
 if ($arraySource[$dataSource['source_code']] == count($order->getAllItems())) {
 $source = $dataSource['source_code'];
 break;
 }
 }
 }
}
$shipment->getExtensionAttributes()->setSourceCode($source);
Anas Mansuri
2,6371 gold badge12 silver badges29 bronze badges
answered Mar 24, 2020 at 2:49

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

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

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.