0

How could I go about programmatically invoicing a single product off of a sales order of more than one product?

I.E Order X has three products, SKU1, SKU2 & SKU3. I only want to create an invoice for SKU1.

I've looked into

\app\code\core\Mage\Adminhtml\controllers\Sales\Order\InvoiceController.php

Though I get a little stuck when I see the _getItemQtys() method.

Could really use some advice.

2
$order = Mage::getModel('sales/order')->loadByIncrementId($increment_id);
$items = $order->getAllItems();

$qtys = array(); //this will be used for processing the invoice

foreach($items as $item){
    if ($item->getSku() == 'SKU1') {
        $qty_to_invoice = $item->getQtyOrdered(); // now gets order quantity of item
    } else {
        $qty_to_invoice = 0;
    }

    $qtys[$item->getId()] = $qty_to_invoice;
    <!-- Note that the ->getId() method gets the item_id on the order, not the product_id -->
}

$invoice = Mage::getModel('sales/service_order', $order)->prepareInvoice($qtys);

Enhanced the answer so it's more clear when you want only a specific SKU

1

The solution is setting up an array with the key being the order's item_id (note that this is not the same as product_id, it is a unique identifier).

Let's say you have an order $increment_id (order number):

$order = Mage::getModel('sales/order')->loadByIncrementId($increment_id);
$items = $order->getItemsCollection();

$qtys = array(); //this will be used for processing the invoice

foreach($items as $item){
    $qty_to_invoice = x; //where x is the amount you wish to invoice
    <!-- please note that if you don't want to invoice this product, set this value to 0 -->
    $qtys[$item->getId()] = $qty_to_invoice;
    <!-- Note that the ->getId() method gets the item_id on the order, not the product_id -->
}

$invoice = Mage::getModel('sales/service_order', $order)->prepareInvoice($qtys);
<!-- The rest is only required when handling a partial invoice as in this example-->
$amount = $invoice->getGrandTotal();
$invoice->register()->pay();
$invoice->getOrder()->setIsInProcess(true);

$history = $invoice->getOrder()->addStatusHistoryComment(
    'Partial amount of $' . $amount . ' captured automatically.', false
);

$history->setIsCustomerNotified(true);

$order->save();

Mage::getModel('core/resource_transaction')
    ->addObject($invoice)
    ->addObject($invoice->getOrder())
    ->save();
$invoice->save();
$invoice->sendEmail(true, ''); //set this to false to not send the invoice via email
  • This seems to work, but when you look at the invoice generated, the quantity is correct for the item, but the subtotal is equal to the order total, not the total of the items being invoiced. – Corgalore Sep 11 '15 at 15:16
  • It seems to be in the invoice's collectTotals() base method. Might be best to overwrite those totals near the end of the prepareInvoice() method. – Corgalore Sep 11 '15 at 15:32
0

Try this one...

<?php
$orderID = "145000010"; //order increment id
$orderDetails = Mage::getModel('sales/order')->loadByIncrementId($orderID);

if($orderDetails->canInvoice() and $orderDetails->getIncrementId())
{
    //$order = Mage::getModel('sales/order')->loadByIncrementId($order_id);
    $orderItems = $orderDetails->getAllItems();
    $invoiceItems = array();

    foreach ($orderItems as $_eachItem) {
    $opid = $_eachItem->getId();
    $opdtId = $_eachItem->getProductId();
    $itemss = Mage::getModel('catalog/product')->load($opdtId);
    $psku = $itemss->getSku(); // get product attribute which is used your condition
    if($psku=='Test product1'){
        $qty = $_eachItem->getQtyOrdered();
    } else {
        $qty = 0;
    }

    $itemsarray[$opid] = $qty;
    }

    if($orderDetails->canInvoice()) { 
    echo $invoiceId = Mage::getModel('sales/order_invoice_api')
    ->create($orderDetails->getIncrementId(), $itemsarray ,'Partially create Invoice programatically' ,0,0);
    }
}
?>

For more info

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.