Programowe tworzenie przesyłek

32

Natknąłem się na różne sposoby programowego tworzenia przesyłki. Oni są

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

Jaka jest różnica między tymi metodami. Jedna z trzech metod, która jest właściwą metodą do tworzenia przesyłek i dodawania numerów śledzenia.

blakcaps
źródło
Czy potrzebujesz więcej szczegółów w mojej odpowiedzi, aby uzasadnić nagrodę „Akceptuj i nagrodę”? Jestem otwarty na krytykę lub wyjaśnienia, jeśli chcesz.
philwinkle

Odpowiedzi:

47

Spróbuję. Weźmy je pojedynczo:

Metoda 1

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

$converterpowyżej jest ładowany z klasy Mage_Sales_Model_Convert_Order, która korzysta z pomocnika rdzenia wywoływanego copyFieldsetdo kopiowania szczegółów zamówienia do obiektu wysyłki. $ order musi być typu tablica lub Varien_Object.

Ta metoda jest właściwie rdzeniem metody 3, ponieważ jest używana Mage::getModel('sales/convert_order')w wywołaniu konstruktora.

Kluczowy wyróżnik tej metody - może pobrać tablicę lub obiekt $orderi wygenerować $shipmentobiekt podstawowy . Jest to metoda niższego poziomu używana wyłącznie przez metody przedstawione w Metodzie 2, Metodzie 3.

Metoda 2

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

Wydaje się, że jest to najpopularniejszy sposób generowania przesyłki w rdzeniu Magento, ponieważ jest ona używana zarówno w kontrolerach przesyłek, jak i fakturach. $orderjest używany jako argument konstruktora do wystąpienia Mage_Sales_Model_Service_Order, ustawiając go jako chronioną właściwość obiektu.

Następnie dzwonisz prepareShipmenti przekazujesz ilość. Ponieważ ta metoda wykorzystuje klasę konwertera z metody 1, nie trzeba określać więcej szczegółów, takich jak zamówienie zamówienia przekazuje szczegółowe informacje dotyczące wysyłki przedmiotu w prepareShipmentargumencie, wywoływanym tutaj za pomocą $this->_getItemQtys. Aby użyć tego we własnym kontekście, wystarczy przekazać liczbę elementów w tablicy o następującym formacie:

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

Kluczowy wyróżnik tej metody - daje z powrotem obiekt wysyłki $, ale z wszystkimi konwertowanymi na nim przedmiotami. To plug-and-play.

Metoda 3

Nie mogłem znaleźć dowodów na użycie tej metody w rdzeniu. Szczerze mówiąc, wygląda to na hack. Oto metoda:

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

Krok 1 jest dokładnie taki sam jak metoda 2 powyżej. Bez różnicy. Jednak $shipmentodzyskujesz obiekt, który jest zastępowany przez bezpośrednie insantiation of Mage_Sales_Model_Order_Shipment_Api. To jest niestandardowe. Najlepszym sposobem na uzyskanie obiektu Api do wysyłki byłoby zadzwonienie Mage::getModel('sales/order_shipment_api').

Następnie używa tego zastąpionego, nowego obiektu API przesyłki do utworzenia przesyłki ze $orderIdzmiennej, która nie została zdefiniowana w kodzie. Znowu wydaje się to obejściem.

Patrząc na Mage_Sales_Model_Order_Shipment_Api::create()to, wydaje się, że jest to punkt kompleksowej obsługi do generowania przesyłki, ponieważ najbardziej podstawowe szczegóły potrzebne do utworzenia przesyłki to tylko zamówienie increment_id.

Jest to hack, którego nie powinien używać żaden moduł ani rozszerzenie. Ten interfejs API jest przeznaczony do korzystania z funkcji udostępnianych za pośrednictwem żądań interfejsu API RPC / SOAP XML i jest celowo podstawowy w celu wyeliminowania wieloetapowych żądań interfejsu API.

Ostatecznie jednak Metoda 3 przechodzi do drobiazgów i poprzez wywołanie Mage_Sales_Model_Order, wywołuje prepareShipment, co jest abstrakcją wyższego rzędu dla znanej powyżej Metody 2:

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

Kluczowy wyróżnik tutaj - jeśli potrzebujesz przesyłki, nie przejmuj się hackami i masz tylko increment_id - skorzystaj z tej metody. Przydatne informacje, jeśli wolisz obsługiwać to za pośrednictwem interfejsu API SOAP.

Mam nadzieję że to pomogło.

philwinkle
źródło
1
Head up dla każdego, kto korzysta z Magestore Inventory Management: Metoda 3 nie uruchamia haków, więc możesz mieć rozbieżności między przesyłkami podstawowymi Magento a przesyłkami z magazynu. Również dobra odpowiedź OP :)
Ricky Odin Matthews
7

Kluczową kwestią jest to, że metody 1 i 2 nie działają ...

Zgadzam się z @philwinkle, metoda 3 jest hacky. Funkcje API tak naprawdę nie powinny być wywoływane w kontekście innym niż API. Nigdy nie wiadomo, jakie przyszłe wydania mogą przynieść złamanie tego rodzaju kodu.

Co to pozostawia? Cóż, metody 1 i 2 nie są dokładnie złamane. Po prostu wykonują tylko część pracy. Oto jak powinny wyglądać:

Uwaga: dla zwięzłości następujące fragmenty kodu dodadzą wszystkie kwalifikujące się elementy do przesyłki. Jeśli chcesz tylko wysłać część zamówienia, musisz zmodyfikować niektóre części kodu - mam jednak nadzieję, że dałem ci wystarczająco dużo, aby kontynuować.

Metoda 1

Jeśli spojrzeć na kod w app/code/core/Mage/Sales/Model/Order/Shipment/Api.php(stosowany w metodzie 3) zobaczysz, że oprócz $convertor->toShipment($order)niego wzywa także $item = $convertor->itemToShipmentItem($orderItem), $item->setQty($qty)i $shipment->addItem($item)dla każdego kwalifikującego się przedmiotu zamówienia. Tak, Magento jest naprawdę tak leniwy, że trzeba go nakłonić do każdego. Pojedynczy. Krok. Następnie musisz przeskoczyć jeszcze kilka obręczy, aby faktycznie zapisać przesyłkę w bazie danych.

Więc metoda 1 powinna wyglądać następująco:

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

Metoda 2

Po pierwsze, masz wywołanie, do $this->_getItemQtys()którego oczywiście będzie działać tylko w niektórych klasach (tych, które mają lub dziedziczą funkcję _getItemQtys, natch). To musi się zmienić i podobnie jak w metodzie 1, musisz także dopracować proces.

Patrząc na app/code/core/Mage/Adminhtml/controllers/Sales/Order/ShipmentController.phpto jest nieco lepsza sytuacja z tym podejściem - wydaje się, że elementy są konwertowane wraz z samym transportem. Ale nadal dostajesz po prostu obiekt przejściowy, który musisz sam zapisać do bazy danych:

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

Polecam również dodanie trochę sprawdzania błędów, np. Aby upewnić się, że Twoja przesyłka rzeczywiście zawiera jakieś elementy przed tobą register().

Który jest najlepszy

Powiedziałbym, że to kwestia opinii. Nie wykonałem żadnych testów porównawczych, ale jestem pewien, że różnica prędkości między tymi dwiema metodami byłaby znikoma. Jeśli chodzi o rozmiar i czytelność kodu, nie ma między nimi wiele.

Podoba mi się metoda 2 polegająca na tym, że nie muszę jawnie konwertować wszystkich pozycji w kolejności, ale nadal wymaga przejścia przez nie w celu wyodrębnienia ilości. Dla małego śladu kodu metoda 3 byłaby moim ulubionym! Ale jako inżynier oprogramowania nie mogę tego polecić. Więc wybiorę dla metody 2.

Doug McLean
źródło
1

Chłopaki Żadne z powyższych nie działało w moim wydaniu. Poniższe działało dla mnie. Odłóż go tutaj, na wypadek, gdyby pomógł komukolwiek z was.

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
źródło
Dlaczego metoda qty_shipped nie jest wypełniana w tabeli sales_flat_order_item przy użyciu tej metody?
Aplikacje kreatywne