Creazione programmatica di spedizioni


32

Mi sono imbattuto in diversi modi per creare la spedizione a livello di codice. Loro sono

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

Quali sono le differenze tra questi metodi. Tra i tre metodi che è il metodo corretto per creare spedizioni e aggiungere numeri di tracciamento.


Ci sono altri dettagli di cui hai bisogno nella mia risposta per giustificare un premio di accettazione e generosità? Sono aperto a critiche o chiarimenti se lo desideri.
Filwinkle

Risposte:


47

Ci proverò. Prendiamoli uno alla volta:

Metodo 1

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

$convertersopra viene caricato dalla classe Mage_Sales_Model_Convert_Order, che utilizza un helper principale chiamato copyFieldsetper copiare i dettagli dell'ordine in un oggetto di spedizione. $ order deve essere di tipo array o Varien_Object.

Questo metodo è in realtà al centro del Metodo 3, come viene utilizzato Mage::getModel('sales/convert_order')nella sua chiamata del costruttore.

Differenziatore chiave di questo metodo: può prendere un array o un oggetto $ordere generare un $shipmentoggetto di base . È un metodo di livello inferiore utilizzato esclusivamente dai metodi indicati nel Metodo 2, Metodo 3.

Metodo 2

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

Questo sembra essere il modo più popolare nel Core di Magento di generare una spedizione in quanto viene utilizzato sia nei controller di spedizione che in quelli di fatturazione. $orderviene utilizzato come argomento del costruttore per l'istanza di Mage_Sales_Model_Service_Order, impostandolo come proprietà protetta sull'oggetto.

Stai quindi chiamando prepareShipmente passando una quantità. Poiché questo metodo utilizza la classe del convertitore dal Metodo 1, non è necessario specificare ulteriori dettagli come gli articoli dell'ordine passano i dettagli della quantità di spedizione prepareShipmentnell'argomento, chiamati qui con $this->_getItemQtys. Per utilizzarlo nel proprio contesto, è sufficiente passare la quantità di articoli in un array con il seguente formato:

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

Differenziatore chiave di questo metodo: ti restituisce un oggetto $ shipping, ma con tutti gli articoli convertiti su di esso. È plug-and-play.

Metodo 3

Non sono riuscito a trovare prove dell'utilizzo di questo metodo nel Core. Sembra un trucco, a dire il vero. Ecco il metodo:

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

Il passaggio 1 è esattamente lo stesso del metodo 2 sopra. Nessuna differenza. Tuttavia, si ottiene indietro un $shipmentoggetto, che viene sostituito da un'insantiazione diretta di Mage_Sales_Model_Order_Shipment_Api. Questo non è standard. Il modo migliore per ottenere un oggetto Api di spedizione sarebbe quello di chiamare Mage::getModel('sales/order_shipment_api').

Successivamente, utilizza quel nuovo oggetto API di spedizione sovrascritto per creare una spedizione da una $orderIdvariabile che non è stata definita nel codice. Ancora una volta, sembra una soluzione alternativa.

Guardando Mage_Sales_Model_Order_Shipment_Api::create(), sembra uno sportello unico per generare una spedizione poiché i dettagli di base necessari per creare la spedizione sono solo un ordine increment_id.

Questo è un hack che non dovrebbe essere usato da nessun modulo o estensione. Questa API deve essere utilizzata da funzionalità esposte tramite richieste API XML RPC / SOAP ed è intenzionalmente di base per eliminare richieste API a più passaggi.

Alla fine, il Metodo 3 arriva al nocciolo della verità, e tramite una chiamata a Mage_Sales_Model_Order, chiama prepareShipment, che è un'astrazione di ordine superiore per il familiare Metodo 2 sopra:

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

Differenziatore chiave qui - se hai bisogno di una spedizione, non preoccuparti degli hack e hai solo un increment_id - usa questo metodo. Informazioni utili anche se si preferisce gestirlo tramite l'API SOAP.

Spero che aiuti.


1
Un testa a testa per chiunque usi Magestore Inventory Management: il Metodo 3 non fa scattare i propri hook, quindi finirai per avere discrepanze tra le spedizioni core di Magento e le spedizioni di Magazzino. Anche una buona risposta OP :)
Ricky Odin Matthews,

7

La cosa chiave qui è che i metodi 1 e 2 non funzionano ...

Sono d'accordo con @philwinkle, il metodo 3 è hacky. Le funzioni API non dovrebbero essere chiamate in un contesto non API. Non si sa mai quali versioni future potrebbero portare a infrangere questo tipo di codice.

Quindi che cosa lascia? Bene, i metodi 1 e 2 non sono esattamente rotti. È solo che svolgono solo una parte del lavoro. Ecco come dovrebbero apparire:

Nota: per brevità, i seguenti frammenti di codice aggiungeranno tutti gli articoli idonei alla spedizione. Se vuoi solo spedire una parte di un ordine, dovrai modificare alcune parti del codice, ma spero di averti dato abbastanza per continuare.

Metodo 1

Se guardi il codice in app/code/core/Mage/Sales/Model/Order/Shipment/Api.php(come usato nel metodo 3) vedrai che oltre a $convertor->toShipment($order)questo chiama anche $item = $convertor->itemToShipmentItem($orderItem), $item->setQty($qty)e$shipment->addItem($item) per ogni articolo di ordine ammissibili. Sì, Magento è davvero così pigro, devi convincerlo attraverso ogni. Singolo. Passo. Quindi devi saltare alcuni altri cerchi per salvare effettivamente la spedizione nel database.

Quindi il metodo 1 dovrebbe apparire così:

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

Metodo 2

Prima di tutto, hai una chiamata a $this->_getItemQtys() cui ovviamente funzionerà solo in determinate classi (quelle che hanno o ereditano una funzione _getItemQtys, natch). Quindi ciò deve cambiare e, come per il metodo 1, è necessario anche perfezionare il processo.

Guardare app/code/core/Mage/Adminhtml/controllers/Sales/Order/ShipmentController.phpè una situazione leggermente migliore con questo approccio: sembra che gli articoli vengano convertiti insieme alla spedizione stessa. Ma devi ancora recuperare un oggetto temporaneo, che devi salvare nel database da solo, in questo modo:

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

Ti consiglierei anche di aggiungere un piccolo controllo degli errori, ad esempio per assicurarti che la tua spedizione contenga effettivamente degli articoli prima di te register().

Qual è la migliore?

Direi che è una questione di opinione. Non ho fatto alcun test di benchmark ma sono abbastanza sicuro che la differenza di velocità tra i due metodi sarebbe trascurabile. Per quanto riguarda le dimensioni del codice e la leggibilità non c'è molto tra di loro.

Mi piace il metodo 2 per non dover convertire esplicitamente tutti gli articoli nell'ordine, ma richiede comunque di esaminarli per estrarre le quantità. Per un footprint di codice ridotto, il metodo 3 sarebbe il mio preferito! Ma come ingegnere del software non posso raccomandarlo. Quindi plump per il metodo 2.


1

Ragazzi Nessuna delle precedenti ha funzionato sul mio problema. Quanto segue ha funzionato per me. Mettendolo qui nel caso in cui aiuti qualcuno di voi là fuori.

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

Perché qty_shipped non viene popolato nella tabella sales_flat_order_item con questo metodo?
Creative Apps
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.