Sendungen programmatisch erstellen

32

Ich habe verschiedene Möglichkeiten gefunden, Sendungen programmatisch zu erstellen. Sie sind

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

Was sind die Unterschiede zwischen diesen Methoden. Von den drei Methoden ist die richtige Methode, um Sendungen zu erstellen und Tracking-Nummern hinzuzufügen.

blakcaps
quelle
Gibt es weitere Einzelheiten zu meiner Antwort, um eine Annahme- und Kopfgeldprämie zu rechtfertigen? Ich bin offen für Kritik oder Klärung, wenn Sie es wünschen.
Philwinkle

Antworten:

47

Ich versuche es mal. Nehmen wir sie nacheinander:

Methode 1

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

$converterOben wird aus der Klasse geladen Mage_Sales_Model_Convert_Order, die einen Core-Helper verwendet, der aufgerufen wird copyFieldset, um Bestelldetails in ein Sendungsobjekt zu kopieren. $ order muss vom Typ array oder sein Varien_Object.

Diese Methode bildet den Kern von Methode 3, wie sie Mage::getModel('sales/convert_order')in ihrem Konstruktoraufruf verwendet wird.

Hauptunterscheidungsmerkmal dieser Methode: Sie kann ein Array oder ein Objekt aufnehmen $orderund ein Basisobjekt generieren $shipment. Es handelt sich um eine Methode auf niedrigerer Ebene, die ausschließlich von den Methoden verwendet wird, die Sie in Methode 2, Methode 3 beschrieben haben.

Methode 2

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

Dies scheint die beliebteste Methode im Kern von Magento zu sein, um eine Sendung zu generieren, da sie sowohl in Sendungs- als auch in Rechnungsprüfern verwendet wird. $orderwird als Konstruktorargument für die Instanziierung von verwendet Mage_Sales_Model_Service_Orderund als geschützte Eigenschaft für das Objekt festgelegt.

Dann rufst du an prepareShipmentund übergibst eine Menge. Da diese Methode die Konverterklasse von Methode 1 verwendet, müssen Sie in dem hier mit aufgerufenen Argument keine weiteren Details angeben, z . Um dies in Ihrem eigenen Kontext zu verwenden, müssen Sie lediglich die Anzahl der Elemente in einem Array mit dem folgenden Format übergeben:prepareShipment$this->_getItemQtys

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

Das wichtigste Unterscheidungsmerkmal dieser Methode: Sie erhalten ein $ -Versandobjekt zurück, auf dem jedoch alle Elemente konvertiert sind. Es ist Plug-and-Play.

Methode 3

Ich konnte keine Beweise für die Verwendung dieser Methode im Core finden. Es sieht aus wie ein Hack, um ehrlich zu sein. Hier ist die Methode:

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

Schritt 1 entspricht genau der obigen Methode 2. Kein Unterschied. Sie erhalten jedoch ein $shipmentObjekt zurück, das durch eine direkte Insantiation von ersetzt wird Mage_Sales_Model_Order_Shipment_Api. Dies ist kein Standard. Die beste Methode zum Abrufen eines Versand-API-Objekts ist der Aufruf Mage::getModel('sales/order_shipment_api').

Anschließend wird dieses überschriebene neue Versand-API-Objekt verwendet, um einen Versand aus einer $orderIdVariablen zu erstellen , die in Ihrem Code nicht definiert wurde. Auch dies scheint eine Problemumgehung zu sein.

Auf den ersten Blick Mage_Sales_Model_Order_Shipment_Api::create()scheint es ein One-Stop-Shop für das Generieren einer Sendung zu sein, da die grundlegendsten Details, die zum Erstellen der Sendung benötigt werden, nur eine Bestellung sind increment_id.

Dies ist ein Hack, der von keinem Modul oder keiner Erweiterung verwendet werden sollte. Diese API soll von Funktionen genutzt werden, die über XML-RPC / SOAP-API-Anforderungen verfügbar gemacht werden, und ist absichtlich grundlegend, um API-Anforderungen mit mehreren Schritten zu eliminieren.

Schließlich kommt Methode 3 jedoch auf den Punkt und ruft über einen Aufruf von Mage_Sales_Model_Order auf prepareShipment, was eine Abstraktion höherer Ordnung für die bekannte Methode 2 oben ist:

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

Hauptunterscheidungsmerkmal hier - wenn Sie eine Sendung benötigen, keine Hacks und nur eine increment_id haben - verwenden Sie diese Methode. Auch nützliche Informationen, wenn Sie dies lieber über die SOAP-API erledigen möchten.

Ich hoffe das hilft.

Philwinkle
quelle
1
Ein Heads-Up für alle, die Magestore Inventory Management verwenden: Methode 3 löst keine Hooks aus, sodass es zu Versanddifferenzen zwischen Magento-Kernsendungen und Warehouse-Sendungen kommt. Auch gute Antwort OP :)
Ricky Odin Matthews
7

Der Schlüssel hier ist, dass die Methoden 1 und 2 nicht funktionieren ...

Ich stimme jedoch mit @philwinkle überein, Methode 3 ist hacky. Die API-Funktionen sollten eigentlich nicht in einem Nicht-API-Kontext aufgerufen werden. Sie wissen nie, welche zukünftigen Releases dazu führen können, dass ein derartiger Code kaputt geht.

Was bleibt also übrig? Nun, Methoden 1 und 2 sind nicht genau gebrochen. Es ist nur so, dass sie nur einen Teil der Arbeit erledigen. So sollten sie aussehen:

Hinweis: Der Kürze halber werden mit den folgenden Codefragmenten alle in Frage kommenden Artikel zur Sendung hinzugefügt. Wenn Sie nur einen Teil einer Bestellung versenden möchten, müssen Sie bestimmte Teile des Codes ändern - hoffentlich habe ich Ihnen jedoch genug gegeben, um fortzufahren.

Methode 1

Wenn Sie den Code anschauen in app/code/core/Mage/Sales/Model/Order/Shipment/Api.php(wie in Methode 3 verwendet) Sie werden sehen , dass zusätzlich zu dem $convertor->toShipment($order)sie auch nennen $item = $convertor->itemToShipmentItem($orderItem), $item->setQty($qty)und $shipment->addItem($item)für jede qualifizierte Auftragsposition. Ja, Magento ist wirklich so faul, dass man es durch jeden hindurch locken muss. Single. Schritt. Dann müssen Sie ein paar weitere Reifen durchspringen, um die Sendung tatsächlich in der Datenbank zu speichern.

Methode 1 sollte also so aussehen:

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

Methode 2

Zunächst einmal haben Sie einen Aufruf, $this->_getItemQtys()der natürlich nur in bestimmten Klassen funktioniert (solche, die eine _getItemQtys-Funktion haben oder erben, natch). Das muss sich also ändern, und wie bei Methode 1 müssen Sie auch den Prozess konkretisieren.

Suchen Sie in app/code/core/Mage/Adminhtml/controllers/Sales/Order/ShipmentController.phpes ist eine etwas bessere Situation mit diesem Ansatz - es scheint , werden die Elemente zusammen mit der Sendung selbst umgewandelt. Sie erhalten jedoch nur ein vorübergehendes Objekt zurück, das Sie selbst in der Datenbank speichern müssen.

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

Ich würde auch empfehlen, dort eine kleine Fehlerüberprüfung hinzuzufügen, um beispielsweise sicherzustellen, dass Ihre Sendung tatsächlich Artikel enthält, bevor Sie register()diese erhalten.

Welches das Beste ist?

Ich würde sagen, es ist Ansichtssache. Ich habe noch keine Benchmark-Tests durchgeführt, bin aber ziemlich zuversichtlich, dass der Geschwindigkeitsunterschied zwischen den beiden Methoden vernachlässigbar ist. In Bezug auf Codegröße und Lesbarkeit gibt es nicht viel zwischen ihnen.

Ich mag Methode 2, weil nicht alle Artikel in der Bestellung explizit konvertiert werden müssen, aber Sie müssen sie trotzdem durchgehen, um die Mengen zu extrahieren. Für einen schönen kleinen Code-Footprint wäre Methode 3 mein Favorit! Aber als Softwareentwickler kann ich es nicht empfehlen. Also werde ich mich für Methode 2 entscheiden.

Doug McLean
quelle
1

Jungs Keiner der oben genannten hat an meinem Problem funktioniert. Folgendes hat bei mir funktioniert. Stellen Sie es hier ab, falls es irgendjemandem von Ihnen da draußen hilft.

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
quelle
Warum wird die Menge_versand nicht mit dieser Methode in die Tabelle "sales_flat_order_item" eingetragen?
Kreative Apps