Esaminiamo il canShip
metodo per vedere come viene calcolato:
/**
* 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;
}
I metodi di ordine possono essere sostituiti come segue
canUnhold ()
order->state === 'holded'
isPaymentReview ()
order->state === 'payment_review'
getIsVirtual ()
order->is_virtual === 1
isCanceled ()
order->state === 'canceled'
getActionFlag ()
I flag di azione vengono impostati durante i processi di vendita, non rilevanti per il recupero degli ordini dal database
getAllItems ()
Qui dobbiamo fare un join sugli articoli dell'ordine. is_virtual
e locked_do_ship
sono colonne della sale_flat_order_item
tabella.
getQtyToShip ()
Questo viene nuovamente calcolato in base ad altri attributi
/**
* Retrieve item qty available for ship
*
* @return float|integer
*/
public function getQtyToShip()
{
if ($this->isDummy(true)) {
return 0;
}
return $this->getSimpleQtyToShip();
}
isDummy
il reso è vero se parent_id === null
e il prodotto ha l'opzione "spedisci separatamente" O se parent_id !== null
e il prodotto non ha l'opzione "spedisci separatamente".
getSimpleQtyToShip
ritorna qty_ordered - qty_shipped - qty_refunded - qty_canceled
.
Il codice
Con queste informazioni possiamo preparare una raccolta:
$collection = Mage::getModel('sales/order')->getCollection();
Innanzitutto, uniamo gli articoli che appartengono a ciascun ordine:
$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');
Quindi, filtriamo gli stati degli ordini che non possono essere spediti ("nin" = "non in"):
$collection
->addFieldToFilter('status', array('nin' => array(
'holded', 'payment_review', 'canceled'
)))
->addFieldToFilter('main_table.is_virtual', '0');
Quindi, creiamo un'espressione SQL per il numero di articoli che possono essere spediti:
- sommiamo la quantità disponibile per gli articoli dell'ordine
- per gli oggetti virtuali il risultato è 0
- per gli elementi "bloccati" il risultato è 0
- per tutti gli altri, il risultato è uguale
qty_ordered - qty_shipped - qty_refunded - qty_canceled
TODO: prendi in considerazione l'opzione del prodotto "spedisci separatamente. Questa query conterà tutti gli articoli padre e figlio, quindi ci saranno falsi positivi. Lascerò come un esercizio al lettore per calcolare anche il risultato isDummy()
in SQL.
La somma sarà disponibile con 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'));
Infine filtriamo solo gli ordini con un numero positivo di articoli spedibili. Dobbiamo usare "HAVING" invece di "WHERE" perché la colonna viene calcolata con una funzione aggregata:
$collection->getSelect()->having('shippable_items > 0'));