Criando Remessas Programaticamente

32

Me deparei com diferentes maneiras de criar remessas programaticamente. Eles são

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

Quais são as diferenças entre esses métodos. Dos três métodos, é o método adequado para criar remessas e adicionar números de rastreamento.

blakcaps
fonte
Há mais detalhes necessários sobre minha resposta para garantir um prêmio de aceitação e recompensa? Estou aberto a críticas ou esclarecimentos, se desejar.
Philwinkle

Respostas:

47

Vou tentar. Vamos levá-los um de cada vez:

Método 1

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

$converteracima é carregado da classe Mage_Sales_Model_Convert_Order, que usa um auxiliar central chamado copyFieldsetpara copiar detalhes do pedido em um objeto de remessa. $ order deve ser do tipo array ou Varien_Object.

Na verdade, esse método está no centro do método 3, como ele usa Mage::getModel('sales/convert_order')em sua chamada de construtor.

Diferenciador chave deste método - ele pode pegar uma matriz ou um objeto $ordere gerar um $shipmentobjeto básico . É um método de nível inferior usado exclusivamente pelos métodos apresentados no método 2, método 3.

Método 2

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

Essa parece ser a maneira mais popular no Core do Magento de gerar uma remessa, pois é usada nos controladores de remessa e fatura. $orderé usado como um argumento construtor para a instanciação de Mage_Sales_Model_Service_Order, configurando-o como uma propriedade protegida no objeto.

Você está ligando prepareShipmente passando uma quantidade. Como esse método usa a classe converter do Método 1, você não precisa especificar mais detalhes, como itens de pedido, que passam os detalhes da quantidade de remessa de itens no prepareShipmentargumento, chamado aqui com $this->_getItemQtys. Para usar isso em seu próprio contexto, tudo o que você precisa fazer é passar a quantidade de itens em uma matriz com o seguinte formato:

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

Diferenciador chave deste método - ele devolve um objeto $ shipment, mas com todos os itens convertidos nele. É plug-and-play.

Método 3

Não consegui encontrar evidências do uso desse método no Core. Parece um truque, para ser sincero. Aqui está o 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);

O passo 1 é exatamente o mesmo que o método 2 acima. Não faz diferença. No entanto, você recebe de volta um $shipmentobjeto, que é substituído por uma insatiação direta de Mage_Sales_Model_Order_Shipment_Api. Isso não é padrão. A melhor maneira de obter um objeto Api de remessa seria chamar Mage::getModel('sales/order_shipment_api').

Em seguida, ele usa esse novo objeto de API de remessa substituído para criar uma remessa a partir de uma $orderIdvariável que não foi definida no seu código. Novamente, isso parece uma solução alternativa.

Observando Mage_Sales_Model_Order_Shipment_Api::create(), parece um balcão único para gerar uma remessa, pois os detalhes mais básicos necessários para criar a remessa são apenas um pedido increment_id.

Este é um hack que não deve ser usado por nenhum módulo ou extensão. Essa API deve ser consumida por recursos expostos por meio de solicitações XML RPC / SOAP API e é intencionalmente básica para eliminar solicitações de várias etapas da API.

Eventualmente, o Método 3 chega ao âmago da questão, porém, e por meio de uma chamada para Mage_Sales_Model_Order, ele chama prepareShipment, que é uma abstração de ordem superior para o familiar Método 2 acima:

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

O principal diferencial aqui - se você precisar de uma remessa, não se importe com hacks e tenha apenas um increment_id - use esse método. Informações também úteis, se você preferir lidar com isso por meio da API SOAP.

Espero que ajude.

philwinkle
fonte
1
Um alerta para quem usa o Magestore Inventory Management: o método 3 não aciona seus ganchos, portanto você terá discrepâncias de remessa entre as remessas principais do Magento e as remessas do Warehouse. Também boa resposta OP :)
Ricky Odin Matthews
7

O principal aqui é que os métodos 1 e 2 não funcionam ...

Eu concordo com @philwinkle, porém, o método 3 é hacky. As funções da API não devem realmente ser chamadas em um contexto que não seja da API. Você nunca sabe quais lançamentos futuros podem trazer para quebrar esse tipo de código.

Então, o que isso deixa? Bem, os métodos 1 e 2 não são quebrados exatamente. Só que eles fazem parte do trabalho. Aqui está como eles devem ser:

Nota: por questões de brevidade, os seguintes trechos de código adicionarão todos os itens elegíveis à remessa. Se você quiser apenas enviar parte de um pedido, precisará modificar algumas partes do código - espero que tenha lhe dado o suficiente para continuar.

Método 1

Se você olhar para o código app/code/core/Mage/Sales/Model/Order/Shipment/Api.php(como o usado no método 3), você verá que, além de $convertor->toShipment($order)também chama $item = $convertor->itemToShipmentItem($orderItem), $item->setQty($qty)e $shipment->addItem($item)para cada item da ordem elegíveis. Sim, o Magento é realmente tão preguiçoso, você precisa persuadi-lo a todos. Solteiro. Degrau. Em seguida, você precisará percorrer mais alguns obstáculos para realmente salvar a remessa no banco de dados.

Portanto, o método 1 deve ficar assim:

$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

Primeiro, você tem uma chamada para a $this->_getItemQtys()qual, obviamente, só funcionará em determinadas classes (aquelas que possuem ou herdam uma função _getItemQtys, natch). Portanto, isso precisa mudar e, como no método 1, você também precisa aprimorar o processo.

Olhando para app/code/core/Mage/Adminhtml/controllers/Sales/Order/ShipmentController.phpela, é uma situação um pouco melhor com essa abordagem - parece que os itens são convertidos junto com a remessa. Mas você ainda recebe de volta um objeto transitório, que precisa salvar no banco de dados, assim:

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

Também recomendo adicionar um pouco de verificação de erros, por exemplo, para garantir que sua remessa realmente contenha itens antes de você register().

Qual é melhor?

Eu diria que é uma questão de opinião. Eu não fiz nenhum teste de benchmark, mas estou bastante confiante de que a diferença de velocidade entre os dois métodos seria insignificante. Quanto ao tamanho e legibilidade do código, não há muito entre eles.

Eu gosto do método 2 por não ter que converter explicitamente todos os itens do pedido, mas ainda é necessário que você os revise para extrair as quantidades. Para uma boa pegada de código pequeno, o método 3 seria o meu favorito! Mas, como engenheiro de software, não posso recomendar. Então, eu vou insistir no método 2.

Doug McLean
fonte
1

Caras Nenhuma das opções acima funcionou no meu problema. O seguinte funcionou para mim. Colocando aqui em baixo, caso isso ajude algum de vocês lá fora.

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
fonte
Por que o qty_shipped não é preenchido na tabela sales_flat_order_item com esse método?
Creative Apps