I'm assuming you ask this because you want the benefit of all the sales rules which can be applied, inluding coupon codes and third-party logic that might come into play.
I have not exactly tried this before (except to test for this answer), but it makes sense to me that you would clone the visitor's quote, purge all items except the target, and recollect totals.
A solution might look like this:
require_once '/path/to/app/Mage.php';
Mage::app()->setCurrentStore(1);
$quote = Mage::getSingleton('checkout/cart')->getQuote();
// Or load a specific model
//$quote = Mage::getModel('sales/quote')->load(35);
$clone = clone $quote;
$target = $clone->getItemsCollection()->getItemByColumnValue('product_id', 1);
// Or mock an item from another product in the catalog
//$product = Mage::getModel('catalog/product')->load(258);
//$target = new Varien_Object(array('product' => $product, 'buy_request' => '1'));
$clone->getBillingAddress();
$clone->getShippingAddress()
->unsCachedItemsNominal()
->unsCachedItemsNonnominal()
->unsCachedItemsAll();
$clone->unsEntityId()
->removeAllItems()
->unsItemsCollection()
->setIsSuperMode(true);
$target->isDeleted(false);
$result = $clone->addProduct($target->getProduct(), $target->getBuyRequest());
$clone->setTotalsCollectedFlag(false)
->collectTotals();
foreach ($clone->getAllVisibleItems() as $item) {
var_dump(
"{$item->getSku()} x {$item->getQty()} = $" . ($item->getRowTotal() - $item->getDiscountAmount())
);
}
var_dump($clone->getGrandTotal());
I won't do too much to unpack this, as it seems like you're already advanced enough to trace these lines back into the core for details.
What I will give you are some general comments:
- Goal is to clone current quote but sever all ties to DB representation
- We clear all items and add the desired/replace one existing
- We do any housekeeping required to reset quote state for totals collection
- We check our item totals (note use of
row_total
and discount_amount
)