让我们检查一下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;
}
订购方法可以如下替换
canUnhold()
order->state === 'holded'
isPaymentReview()
order->state === 'payment_review'
getIsVirtual()
order->is_virtual === 1
isCanceled()
order->state === 'canceled'
getActionFlag()
动作标志是在销售过程中设置的,与从数据库检索订单无关
getAllItems()
在这里,我们需要对订单商品进行联接。is_virtual
和locked_do_ship
是表的列sale_flat_order_item
。
getQtyToShip()
再次根据其他属性进行计算
/**
* Retrieve item qty available for ship
*
* @return float|integer
*/
public function getQtyToShip()
{
if ($this->isDummy(true)) {
return 0;
}
return $this->getSimpleQtyToShip();
}
isDummy
如果parent_id === null
并且产品具有“单独运输”选项,或者如果parent_id !== null
并且产品不具有“单独运输”选项,则返回true 。
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:将产品选项“ ship”单独考虑在内。此查询将计算所有父项和子项,因此会出现误报。我将其作为练习让读者也可以计算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'));