Программно создавая отгрузки

32

Я сталкивался с различными способами создания программных отправлений. Они есть

     //Type 1
     $converter=Mage::getModel('sales/convert_order');
     $shipment=$converter->toShipment($order);
     // snip

     //Type 2
     $shipment = Mage::getModel('sales/service_order', $order)
                                ->prepareShipment($this->_getItemQtys($order));
     // snip

     //Type 3
     $shipment = Mage::getModel('sales/service_order', $order)->prepareShipment($itemQty);
     $shipment = new Mage_Sales_Model_Order_Shipment_Api();
     $shipmentId = $shipment->create($orderId);
     // snip

В чем разница между этими методами. Один из трех методов - это правильный метод создания отправлений и добавления номеров отслеживания.

blakcaps
источник
Есть ли еще какие-либо детали, которые вам нужны в моем ответе, чтобы гарантировать получение вознаграждения? Я открыт для критики или разъяснений, если хотите.
Филвинкл

Ответы:

47

Я сделаю это. Давайте возьмем их по одному:

Способ 1

$converter=Mage::getModel('sales/convert_order');
$shipment=$converter->toShipment($order);

$converterвыше загружен из класса Mage_Sales_Model_Convert_Order, который использует основной помощник, вызываемый copyFieldsetдля копирования деталей заказа в объект отгрузки. $ order должен иметь тип array или Varien_Object.

Этот метод фактически лежит в основе метода 3, так как он используется Mage::getModel('sales/convert_order')в вызове конструктора.

Ключевой отличительный признак этого метода - он может принимать массив или объект $orderи генерировать базовый $shipmentобъект. Это низкоуровневый метод, используемый исключительно методами, описанными в методе 2, методе 3.

Способ 2

 $shipment = Mage::getModel('sales/service_order', $order)
                            ->prepareShipment($this->_getItemQtys($order));

Похоже, что это наиболее популярный способ в Magento Core генерировать груз, так как он используется в контроллерах отгрузки и счета. $orderиспользуется в качестве аргумента конструктора для создания экземпляра Mage_Sales_Model_Service_Order, устанавливая его как защищенное свойство объекта.

Вы тогда звоните prepareShipmentи передаете количество. Поскольку этот метод использует класс преобразователя от метода 1, то не нужно указать больше деталей , таких как элементы заказа передать запись детали отгрузки Кол - во в prepareShipmentаргументе, называется здесь с $this->_getItemQtys. Чтобы использовать это в своем собственном контексте, все, что вам нужно сделать, это передать количество элементов в массиве в следующем формате:

array(
  'order_item_id'=>$qty,
  'order_item_id'=>$qty,
  'order_item_id'=>$qty
)

Ключевой отличительный признак этого метода - он возвращает вам объект $ shipment, но со всеми предметами, преобразованными на нем. Это подключи и играй.

Способ 3

Я не смог найти доказательств использования этого метода в ядре. Похоже, взломать, если честно. Вот метод:

$itemQty =  $order->getItemsCollection()->count();
$shipment = Mage::getModel('sales/service_order', $order)->prepareShipment($itemQty);
$shipment = new Mage_Sales_Model_Order_Shipment_Api();
$shipmentId = $shipment->create($orderId);

Шаг 1 точно такой же, как метод 2 выше. Нет разницы. Тем не менее, вы получаете обратно $shipmentобъект, который заменяется на прямое сумасшествие Mage_Sales_Model_Order_Shipment_Api. Это нестандартно. Лучшим способом получения отгружаемого объекта Api будет вызов Mage::getModel('sales/order_shipment_api').

Затем он использует этот перезаписанный новый объект API отгрузки для создания отправки из $orderIdпеременной, которая не была определена в вашем коде. Опять же, это похоже на обходной путь.

Глядя на Mage_Sales_Model_Order_Shipment_Api::create()это, это похоже на единый подход к созданию отправления, поскольку самые основные детали, необходимые для создания отправления, - это всего лишь заказ increment_id.

Это хак, который не должен использоваться ни одним модулем или расширением. Этот API предназначен для использования функциями, предоставляемыми через запросы XML RPC / SOAP API, и является намеренно базовым для устранения многоэтапных запросов API.

В конце концов, метод 3 доходит до мелочей, однако и через вызов Mage_Sales_Model_Order он вызывает prepareShipment, что является абстракцией высшего порядка для знакомого метода 2 выше:

public function prepareShipment($qtys = array())
{
    $shipment = Mage::getModel('sales/service_order', $this)->prepareShipment($qtys);
    return $shipment;
}

Ключевой отличительный признак здесь - если вам нужна пересылка, не возражайте против взлома, и у вас есть только increment_id - используйте этот метод. Также полезная информация, если вы предпочитаете обрабатывать это через SOAP API.

Надеюсь, это поможет.

philwinkle
источник
1
Опасность для любого, кто использует Magestore Inventory Management: метод 3 не вызывает их зацепки, поэтому у вас могут возникнуть расхождения между основными поставками Magento и складскими поставками. Также хороший ответ ОП :)
Рики Один Мэттьюс
7

Ключевым моментом здесь является то, что методы 1 и 2 не работают ...

Я согласен с @philwinkle, хотя, метод 3 хакерский. Функции API на самом деле не должны вызываться в не-API контексте. Вы никогда не знаете, какие будущие выпуски могут привести к взлому такого кода.

Так, что это оставляет? Ну, методы 1 и 2 точно не нарушены. Просто они выполняют только часть работы. Вот как они должны выглядеть:

Примечание: для краткости следующие фрагменты кода добавят все подходящие элементы к отправке. Если вы просто хотите отправить часть заказа, вам придется изменить определенные части кода - надеюсь, я дал вам достаточно, чтобы продолжить.

Способ 1

Если вы посмотрите на код в app/code/core/Mage/Sales/Model/Order/Shipment/Api.php(как и в способе 3) вы увидите , что в дополнение к $convertor->toShipment($order)ним также требует $item = $convertor->itemToShipmentItem($orderItem), $item->setQty($qty)и $shipment->addItem($item)для каждого элемента , имеющих право заказа. Да, Magento действительно такой ленивый, ты должен уговорить его через каждого. Не замужем. Шаг. Затем вам нужно перепрыгнуть через несколько обручей, чтобы фактически сохранить груз в базе данных.

Итак, метод 1 должен выглядеть так:

$convertor = Mage::getModel('sales/convert_order');
$shipment = $convertor->toShipment($order);
foreach ($order->getAllItems() as $orderItem) {
    if ($orderItem->getQtyToShip() && !$orderItem->getIsVirtual()) {
        $item = $convertor->itemToShipmentItem($orderItem);
        $item->setQty($orderItem->getQtyToShip());
        $shipment->addItem($item);
    }
}
$shipment->register();
$order->setIsInProcess(true);
Mage::getModel('core/resource_transaction')
         ->addObject($shipment)
         ->addObject($order))
         ->save();

Способ 2

Во-первых, у вас есть вызов, $this->_getItemQtys()который, конечно, будет работать только в определенных классах (те, которые имеют или наследуют функцию _getItemQtys, natch). Так что это должно измениться, и, как и в случае с методом 1, вам также необходимо конкретизировать процесс.

В app/code/core/Mage/Adminhtml/controllers/Sales/Order/ShipmentController.phpэтом подходе ситуация несколько лучше - кажется, что товары конвертируются вместе с самой поставкой. Но вы все равно просто возвращаете временный объект, который вы должны сохранить в базе данных самостоятельно, например, так:

$itemQtys = array();
foreach ($order->getAllItems() as $orderItem) {
    if ($orderItem->getQtyToShip() && !$orderItem->getIsVirtual()) {
        $itemQtys[$orderItem->getId()] = $orderItem->getQtyToShip();
    }
}
$shipment = Mage::getModel('sales/service_order', $order)->prepareShipment($itemQtys);
$shipment->register();
$order->setIsInProcess(true);
Mage::getModel('core/resource_transaction')
         ->addObject($shipment)
         ->addObject($order)
         ->save();

Я также рекомендовал бы добавить небольшую проверку на наличие ошибок, например, чтобы убедиться, что ваш груз действительно содержит какие-либо элементы перед вами register().

Какой лучше?

Я бы сказал, что это вопрос мнения. Я не проводил никаких тестов, но уверен, что разница в скорости между этими двумя методами будет незначительной. Что касается размера кода и читабельности, между ними не так много.

Мне нравится метод 2 за то, что нет необходимости явно конвертировать все элементы в заказе, но он все равно требует, чтобы вы просмотрели их для извлечения количеств. Для небольшого кода, метод 3 будет моим любимым! Но, как инженер-программист, я не могу рекомендовать это. Так что я буду пухленьким для метода 2.

Даг Маклин
источник
1

Ребята Ничто из вышеперечисленного не сработало в моем выпуске. Следующее сработало для меня. Положите это здесь на случай, если это поможет любому из вас там.

public function _createShipment($orderIncrementId = '100310634'){
    // Load Product ..
    $order = Mage::getModel('sales/order')->loadByIncrementId($orderIncrementId);

    // Create Qty array
    $shipmentItems = array();
    foreach ($order->getAllItems() as $item) {
        $shipmentItems [$item->getId()] = $item->getQtyToShip();
    }

    // Prepear shipment and save ....
    if ($order->getId() && !empty($shipmentItems) && $order->canShip()) {
        $shipment = Mage::getModel('sales/service_order', $order)->prepareShipment($shipmentItems);
        $shipment->save();
    }
}
m82amjad
источник
Почему qty_shipped не заполняется в таблице sales_flat_order_item этим методом?
Креативные приложения