If you are developer, adding custom product attribute to quote and order items in Magento is pretty common task. And if you face with the same issue we will be very glad when you find this article helpful. Start with creating new module. In config.xml we need to define resources section which allows us to use install and upgrade scripts. This way all necessary changes will be made in the database – so, let’s do it:
<resources>
    <custom_attributes_setup>
        <setup>
            <module>Atwix_CustomAttribute</module>
            <class>Mage_Catalog_Model_Resource_Setup</class>
        </setup>
    </custom_attributes_setup>
</resources>
Note, that module installation process will be divided in several steps. Using Magento setup classes (in our case Mage_Catalog_Model_Resource_Setup) we add new custom product attribute. This is our first step and here is how install script looks like (install-1.0.1.php):
$installer = $this;

$installer->addAttribute('catalog_product', 'custom_attribute', array(
    'group'             => 'General',
    'type'              => Varien_Db_Ddl_Table::TYPE_VARCHAR,
    'backend'           => '',
    'frontend'          => '',
    'label'             => 'Custom Attribute',
    'input'             => 'text',
    'class'             => '',
    'source'            => '',
    'global'            => Mage_Catalog_Model_Resource_Eav_Attribute::SCOPE_STORE,
    'visible'           => true,
    'required'          => false,
    'user_defined'      => true,
    'default'           => '',
    'searchable'        => true,
    'filterable'        => true,
    'comparable'        => true,
    'visible_on_front'  => true,
    'unique'            => false,
    'apply_to'          => 'simple,configurable,virtual',
    'is_configurable'   => false
));
After launching installer script we can see our custom attribute at the backend: Magento Admin Product Edit Next installation step is to add our custom attribute to the entities. In other words: to add neccessary fields to the tables, so we will be able to store our attribute. File upgrade-1.0.1-1.0.2.php:
$installer = new Mage_Sales_Model_Resource_Setup('core_setup');
/**
 * Add 'custom_attribute' attribute for entities
 */
$entities = array(
    'quote',
    'quote_address',
    'quote_item',
    'quote_address_item',
    'order',
    'order_item'
);
$options = array(
    'type'     => Varien_Db_Ddl_Table::TYPE_VARCHAR,
    'visible'  => true,
    'required' => false
);
foreach ($entities as $entity) {
    $installer->addAttribute($entity, 'custom_attribute', $options);
}
$installer->endSetup();
Note. Exclude entities that you don’t need. So, the database tables are ready. Furthermore, we need to implement the mechanism for converting (copying) our custom product attribute to quote item and order item. Fortunately, it is pretty easy with Magento. At first, you should add custom attribute to sales->quote->item->product_attributes node:
<sales>
    <quote>
        <item>
            <product_attributes>
                <custom_attribute />
            </product_attributes>
        </item>
    </quote>
</sales>
This makes attribute accessible when we will be copying it from the product to quote item – which is our next step. For this task the observer is used, and the event will be called sales_quote_item_set_product:
<sales_quote_item_set_product>
    <observers>
        <atwix_customattribute>
            <class>atwix_customattribute/observer</class>
            <method>salesQuoteItemSetCustomAttribute</method>
        </atwix_customattribute>
    </observers>
</sales_quote_item_set_product>
Obsever:
public function salesQuoteItemSetCustomAttribute($observer)
{
    $quoteItem = $observer->getQuoteItem();
    $product = $observer->getProduct();
    $quoteItem->setCustomAttribute($product->getCustomAttribute());
}
The last thing we need to carry about – it is converting attribute from quote item to order item. And this can be done with xml:
<fieldsets>
    <sales_convert_quote_item>
        <custom_attribute>
            <to_order_item>*</to_order_item>
        </custom_attribute>
    </sales_convert_quote_item>
    <sales_convert_order_item>
        <custom_attribute>
            <to_quote_item>*</to_quote_item>
        </custom_attribute>
    </sales_convert_order_item>
</fieldsets>
That’s it. Make a test order and check sales_flat_order_item table. If you see your custom attribute there that means – everything works. And source code can be found here. Good luck!