Как получить коллекцию заказов, которые можно отправить?

8

Мне нужны заказы, которые еще не отправлены или частично отправлены. Я использую код ниже, чтобы получить заказы, которые могут быть отправлены.

foreach ($orderIds as $orderId) {
    $order = Mage::getModel('sales/order')->load($orderId);
    if ($order->canShip()) {
        echo "Shipping Pending";
    }
}

Но я не хочу использовать foreach. Мне нужно что-то вроде ниже.

Mage::getModel('sales/order')->getCollection()
    ->addFieldToFilter('status','can_ship');
piyush_systematix
источник

Ответы:

9

Давайте рассмотрим canShipметод, чтобы увидеть, как он рассчитывается:

/**
 * Retrieve order shipment availability
 *
 * @return bool
 */
public function canShip()
{
    if ($this->canUnhold() || $this->isPaymentReview()) {
        return false;
    }

    if ($this->getIsVirtual() || $this->isCanceled()) {
        return false;
    }

    if ($this->getActionFlag(self::ACTION_FLAG_SHIP) === false) {
        return false;
    }

    foreach ($this->getAllItems() as $item) {
        if ($item->getQtyToShip()>0 && !$item->getIsVirtual()
            && !$item->getLockedDoShip())
        {
            return true;
        }
    }
    return false;
}

Методы заказа могут быть заменены следующим образом

  1. canUnhold ()

    order->state === 'holded'
  2. isPaymentReview ()

    order->state === 'payment_review'
  3. getIsVirtual ()

    order->is_virtual === 1
  4. isCanceled ()

    order->state === 'canceled'
  5. getActionFlag ()

    Флаги действий устанавливаются в процессе продаж и не имеют отношения к получению заказов из базы данных.

  6. getAllItems ()

    Здесь нам нужно объединить элементы заказа. is_virtualи locked_do_shipявляются столбцами sale_flat_order_itemтаблицы.

    1. getQtyToShip ()

      Это снова рассчитывается на основе других атрибутов

      /**
       * Retrieve item qty available for ship
       *
       * @return float|integer
       */
      public function getQtyToShip()
      {
          if ($this->isDummy(true)) {
              return 0;
          }
      
          return $this->getSimpleQtyToShip();
      }

      isDummyreturn is true, если parent_id === nullи у продукта есть опция «отправить отдельно» ИЛИ если parent_id !== nullу продукта нет опции «отправить отдельно».

      getSimpleQtyToShipвозвращается qty_ordered - qty_shipped - qty_refunded - qty_canceled.

Код

С помощью этой информации мы можем подготовить коллекцию:

$collection = Mage::getModel('sales/order')->getCollection();

Сначала мы объединяем элементы, которые принадлежат каждому заказу:

$collection->getSelect()
    ->joinLeft(
        array('order_item' => $collection->getTable('sales/order_item')),
        'main_table.entity_id=order_item.order_id', array('qty_ordered', 'qty_shipped', 'qty_refunded', 'qty_canceled', 'is_virtual', 'locked_do_ship'))
    ->group('main_table.entity_id');

Затем мы фильтруем статусы заказов, которые не могут быть отправлены ("nin" = "not in"):

$collection
    ->addFieldToFilter('status', array('nin' => array(
        'holded', 'payment_review', 'canceled'
    )))
    ->addFieldToFilter('main_table.is_virtual', '0');

Затем мы создаем выражение SQL для количества отправляемых товаров:

  • мы суммируем кол-во отправляемого товара
  • для виртуальных предметов результат равен 0
  • для "заблокированных" элементов результат равен 0
  • для всех остальных результат равен qty_ordered - qty_shipped - qty_refunded - qty_canceled

TODO: принять опцию продукта "поставляется отдельно во внимание. Этот запрос будет подсчитывать все родительские и дочерние элементы, поэтому будут ложные срабатывания. Я оставлю это в качестве упражнения для читателя, чтобы также вычислить результат isDummy()в SQL.

Сумма будет доступна с псевдонимом "shippable_items"

$collection->addExpressionFieldToSelect(
    'shippable_items',
    'SUM(({{qty_ordered}} - {{qty_shipped}} - {{qty_refunded}} - {{qty_canceled}}) * !{{is_virtual}} * {{locked_do_ship}} IS NOT NULL)',
    array(
        'qty_ordered' => 'order_item.qty_ordered',
        'qty_shipped' => 'order_item.qty_shipped',
        'qty_refunded' => 'order_item.qty_refunded',
        'qty_canceled' => 'order_item.qty_canceled',
        'is_virtual' => 'order_item.is_virtual',
        'locked_do_ship' => 'order_item.locked_do_ship'));

Наконец, мы фильтруем только заказы с положительным количеством отправляемых товаров. Мы должны использовать «HAVING» вместо «WHERE», потому что столбец рассчитывается с помощью статистической функции:

$collection->getSelect()->having('shippable_items > 0'));
Фабиан Шменглер
источник
хорошее объяснение .Я проверю + 1.
Amit Бера
2

Это не может быть возможно because of lot of conditionsпроверить и всякий раз, когда we use canShip()функция. Это слишком сложно, чтобы сделать это.

Это not only depend one /two order fields dependкак

  1. order status hold or not.
  2. order status cancel or not,
  3. order virtual or not.
  4. Order item is capable to do ship order

так далее

Итак, это зависит от некоторой сложной логики / условия, например:

Посмотрите на класс Mage_Sales_Model_Order , и вы можете это понять.

 public function canShip()
    {
        if ($this->canUnhold() || $this->isPaymentReview()) {
            return false;
        }

        if ($this->getIsVirtual() || $this->isCanceled()) {
            return false;
        }

        if ($this->getActionFlag(self::ACTION_FLAG_SHIP) === false) {
            return false;
        }

        foreach ($this->getAllItems() as $item) {
            if ($item->getQtyToShip()>0 && !$item->getIsVirtual()
                && !$item->getLockedDoShip())
            {
                return true;
            }
        }
        return false;
    }
Амит Бера
источник