Comment récupérer les commandes qui peuvent être expédiées?

8

J'ai besoin de commandes qui ne sont pas encore expédiées ou qui sont partiellement expédiées. J'utilise le code ci-dessous pour obtenir des commandes qui peuvent être expédiées.

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

Mais je ne veux pas utiliser foreach. J'ai besoin de quelque chose comme ci-dessous.

Mage::getModel('sales/order')->getCollection()
    ->addFieldToFilter('status','can_ship');
piyush_systematix
la source

Réponses:

9

Examinons la canShipméthode pour voir comment elle est calculée:

/**
 * 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;
}

Les méthodes de commande peuvent être remplacées comme suit

  1. canUnhold ()

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

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

    order->is_virtual === 1
  4. est annulé()

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

    Les indicateurs d'action sont définis pendant les processus de vente, non pertinents pour récupérer les commandes de la base de données

  6. getAllItems ()

    Ici, nous devons faire une jointure sur les articles de la commande. is_virtualet locked_do_shipsont des colonnes du sale_flat_order_itemtableau.

    1. getQtyToShip ()

      Ceci est à nouveau calculé sur la base d'autres attributs

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

      isDummyrenvoie est vrai si parent_id === nullet le produit a l'option «expédier séparément» OU si parent_id !== nullet le produit n'a pas l'option «expédier séparément».

      getSimpleQtyToShipretourne qty_ordered - qty_shipped - qty_refunded - qty_canceled.

Le code

Avec ces informations, nous pouvons préparer une collection:

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

Tout d'abord, nous joignons les articles qui appartiennent à chaque commande:

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

Ensuite, nous filtrons les statuts de commande qui ne peuvent pas être expédiés ("nin" = "not in"):

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

Ensuite, nous créons une expression SQL pour le nombre d'articles qui peuvent être expédiés:

  • nous additionnons la quantité expédiable sur les articles de la commande
  • pour les objets virtuels, le résultat est 0
  • pour les éléments "verrouillés", le résultat est 0
  • pour tous les autres, le résultat est égal à qty_ordered - qty_shipped - qty_refunded - qty_canceled

TODO: prendre en compte l'option de produit "expédier séparément. Cette requête comptera tous les éléments parents et enfants, donc il y aura des faux positifs. Je laisserai au lecteur un exercice pour calculer également le résultat de isDummy()SQL.

La somme sera disponible avec l'alias "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'));

Enfin, nous filtrons uniquement les commandes avec un nombre positif d'articles expédiables. Nous devons utiliser "HAVING" au lieu de "WHERE" car la colonne est calculée avec une fonction d'agrégation:

$collection->getSelect()->having('shippable_items > 0'));
Fabian Schmengler
la source
bonne explication. Je vais vérifier. + 1
Amit Bera
2

Il ne peut pas être possible de because of lot of conditionsvérifier et chaque fois que la we use canShip()fonction est trop complexe.

C'est not only depend one /two order fields dependcomme

  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

etc

Donc, cela dépend d'une logique / condition complexe comme:

Voir une vue sur la classe Mage_Sales_Model_Order , et vous pouvez comprendre cela.

 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;
    }
Amit Bera
la source