Creación programática de envíos

32

Encontré diferentes formas de crear envíos programáticamente. Son

     //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

¿Cuál es la diferencia entre estos métodos? De los tres métodos, que es el método adecuado para crear envíos y agregar números de seguimiento.

blakcaps
fuente
¿Hay más detalles que necesita sobre mi respuesta para garantizar un premio de aceptación y recompensa? Estoy abierto a críticas o aclaraciones si lo desea.
philwinkle

Respuestas:

47

Lo intentaré. Tomemos uno a la vez:

Método 1

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

$converter arriba se carga desde la clase Mage_Sales_Model_Convert_Order , que utiliza un asistente central llamado copyFieldsetpara copiar los detalles del pedido en un objeto de envío. $ order tiene que ser de tipo array o Varien_Object.

Este método es realmente el núcleo del Método 3, ya que utiliza Mage::getModel('sales/convert_order') en su llamada de constructor.

Diferenciador clave de este método: puede tomar una matriz o un objeto$order y generar un $shipmentobjeto básico . Es un método de nivel inferior utilizado exclusivamente por los métodos que expuso en el Método 2, Método 3.

Método 2

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

Esta parece ser la forma más popular en el núcleo de Magento de generar un envío, ya que se utiliza tanto en los controladores de envío como en los de factura. $orderse utiliza como argumento constructor para la instanciación de Mage_Sales_Model_Service_Order, configurándolo como una propiedad protegida en el objeto.

Entonces estás llamando prepareShipmenty pasando una cantidad. Como este método usa la clase de convertidor del Método 1, no necesita especificar más detalles, como que los artículos de pedido pasen los detalles de cantidad de envío del artículo en el prepareShipmentargumento, llamado aquí con $this->_getItemQtys. Para usar esto en su propio contexto, todo lo que necesita hacer es pasar la cantidad de elementos en una matriz con el siguiente formato:

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

Diferenciador clave de este método: le devuelve un objeto de envío $, pero con todos los artículos convertidos en él. Es plug-and-play.

Método 3

No pude encontrar evidencia de uso de este método en el Core. Parece un truco, para ser honesto. Aquí está el método:

$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);

El paso 1 es exactamente el mismo que el Método 2 anterior. Ninguna diferencia. Sin embargo, recupera un $shipmentobjeto, que se reemplaza por una insaciación directa de Mage_Sales_Model_Order_Shipment_Api. Esto no es estándar. La mejor forma de obtener un objeto Api de envío sería llamarMage::getModel('sales/order_shipment_api') .

A continuación, utiliza ese nuevo objeto API de envío sobrescrito para crear un envío a partir de una $orderIdvariable que no se ha definido en su código. Nuevamente, esto parece una solución alternativa.

Mirando Mage_Sales_Model_Order_Shipment_Api::create(), parece una ventanilla única para generar un envío, ya que los detalles más básicos necesarios para crear el envío son solo un pedido increment_id.

Este es un truco que no debe ser utilizado por ningún módulo o extensión. Esta API está destinada a ser consumida por características expuestas a través de solicitudes API XML RPC / SOAP y es intencionalmente básica para eliminar solicitudes API de pasos múltiples.

Eventualmente, el Método 3 llega a lo esencial, y a través de una llamada a Mage_Sales_Model_Order, llama prepareShipment, que es una abstracción de orden superior para el conocido Método 2 anterior:

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

Diferenciador clave aquí : si necesita un envío, no le importen los hacks y solo tenga un increment_id, use este método. También información útil si prefiere manejar esto a través de la API SOAP.

Espero que eso ayude.

philwinkle
fuente
1
Un aviso para cualquiera que use Magestore Inventory Management: el Método 3 no activa sus ganchos, por lo que terminará teniendo discrepancias de envío entre los envíos principales de Magento y los envíos de Almacén. También buena respuesta OP :)
Ricky Odin Matthews
7

La clave aquí es que los métodos 1 y 2 no funcionan ...

Sin embargo, estoy de acuerdo con @philwinkle, el método 3 es hacky. Las funciones API no deberían llamarse realmente en un contexto que no sea API. Nunca se sabe qué versiones futuras pueden traer para romper este tipo de código.

Entonces, ¿qué deja eso? Bueno, los métodos 1 y 2 no están rotos exactamente. Es solo que solo hacen parte del trabajo. Así es como deberían verse:

Nota: por brevedad, los siguientes fragmentos de código agregarán todos los artículos elegibles al envío. Si solo desea enviar parte de un pedido, tendrá que modificar ciertas partes del código, aunque espero haberle dado lo suficiente para continuar.

Método 1

Si observa el código en app/code/core/Mage/Sales/Model/Order/Shipment/Api.php(como se usa en el método 3) verá que además de $convertor->toShipment($order)eso también llama $item = $convertor->itemToShipmentItem($orderItem), $item->setQty($qty)y$shipment->addItem($item) para cada artículo de pedido elegible. Sí, Magento realmente es tan flojo, tienes que convencerlo para que lo haga. Soltero. Paso. Luego, debe saltar algunos aros más para guardar el envío en la base de datos.

Entonces el método 1 debería verse así:

$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();

Método 2

En primer lugar, tienes una llamada para $this->_getItemQtys() que, por supuesto, solo funcionará en ciertas clases (las que tienen o heredan una función _getItemQtys, natch). Por lo tanto, eso debe cambiar, y al igual que con el método 1, también es necesario desarrollar el proceso.

Mirando app/code/core/Mage/Adminhtml/controllers/Sales/Order/ShipmentController.phpes una situación un poco mejor con este enfoque: parece que los artículos se convierten junto con el envío en sí. Pero aún así solo recupera un objeto transitorio, que debe guardar en la base de datos usted mismo, así:

$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();

También recomendaría agregar un poco de verificación de errores allí, por ejemplo, para asegurarse de que su envío realmente contenga algún artículo antes que usted register().

¿Cuál es el mejor?

Yo diría que es una cuestión de opinión. No he hecho ninguna prueba de referencia, pero estoy bastante seguro de que la diferencia de velocidad entre los dos métodos sería insignificante. En cuanto al tamaño del código y la legibilidad, no hay mucho entre ellos.

Me gusta el método 2 por no tener que convertir explícitamente todos los artículos en el pedido, pero todavía requiere que los revise para extraer las cantidades. ¡Para una huella de código pequeña y agradable, el método 3 sería mi favorito! Pero como ingeniero de software no puedo recomendarlo. Así que voy a rellenar para el método 2.

Doug McLean
fuente
1

Chicos Ninguno de los anteriores funcionó en mi problema. Lo siguiente funcionó para mí. Poniéndolo aquí en caso de que ayude a alguno de ustedes.

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
fuente
¿Por qué el qty_shipped no se llena en la tabla sales_flat_order_item con este método?
Aplicaciones creativas