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
canUnhold ()
order->state === 'holded'
isPaymentReview ()
order->state === 'payment_review'
getIsVirtual ()
order->is_virtual === 1
est annulé()
order->state === 'canceled'
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
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.
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'));