Order entities are awkwardly not like normal entities, they use a flat table instead of EAV, which means that it's not enough to just assign an attribute. You must alter the flat table (which I tried here) or create additional tables then join them to the flat table. With hindsight I see I should have taken the second option, it's safer.
I've been looking a bit closer at the order template and there might a hackish sort of workaround via a lesser used block. To start with let's make changes in a layout/local.xml
file so it's safe from overwriting by upgrades;
<layout>
<adminhtml_sales_order_create_index>
<reference name="gift_options">
<block type="adminhtml/template" template="YOUR/TEMPLATE.phtml" />
</reference>
</adminhtml_sales_order_create_index>
</layout>
The gift options block is constructed in an open-ended way so adding to it is relatively easy. Obviously replace YOUR/TEMPLATE.phtml
with the path of a file you will create. The template being inserted needs to have input fields with names like order[testattr]
and those should be copied directly to the database table (according to Mage_Adminhtml_Model_Sales_Order_Create
, if I am reading the source code right). The gift options block already creates a <fieldset>
inside the order's <form>
so only the input fields are needed.
Magento provides a capability for adding options that aren't product attributes or product custom options. They are set on the product and quote items with the option code additional_options
.
There are two steps you need to take, each can be handled via an event observer. If you want the additional options to carry through reordering, you will need also observe a third event.
Add options to quote item
The first step is to add the event observer to set the additional options on the loaded product before it is added to the cart. One option is to use the catalog_product_load_after
event.
<catalog_product_load_after>
<observers>
<extra_options>
<type>model</type>
<class>extra_options/observer</class>
<method>catalogProductLoadAfter</method>
</extra_options>
</observers>
</catalog_product_load_after>
In the event observer you can add additional checks the requested page is indeed an add to cart action. The main point of this observer method is to add the selection of your special options to the additional_options
option on the product model.
public function catalogProductLoadAfter(Varien_Event_Observer $observer)
{
// set the additional options on the product
$action = Mage::app()->getFrontController()->getAction();
if ($action->getFullActionName() == 'checkout_cart_add')
{
// assuming you are posting your custom form values in an array called extra_options...
if ($options = $action->getRequest()->getParam('extra_options'))
{
$product = $observer->getProduct();
// add to the additional options array
$additionalOptions = array();
if ($additionalOption = $product->getCustomOption('additional_options'))
{
$additionalOptions = (array) unserialize($additionalOption->getValue());
}
foreach ($options as $key => $value)
{
$additionalOptions[] = array(
'label' => $key,
'value' => $value,
);
}
// add the additional options array with the option code additional_options
$observer->getProduct()
->addCustomOption('additional_options', serialize($additionalOptions));
}
}
}
The additional options will be moved from the product to the quote item automatically. With this observer in place, your options will appear in the cart and the checkout review.
Add options to order item
In order to have them persist, one additional observer is needed (only since Magento 1.5).
<sales_convert_quote_item_to_order_item>
<observers>
<extra_options>
<type>model</type>
<class>extra_options/observer</class>
<method>salesConvertQuoteItemToOrderItem</method>
</extra_options>
</observers>
</sales_convert_quote_item_to_order_item>
Here we move the option from the quote item to the order item.
public function salesConvertQuoteItemToOrderItem(Varien_Event_Observer $observer)
{
$quoteItem = $observer->getItem();
if ($additionalOptions = $quoteItem->getOptionByCode('additional_options')) {
$orderItem = $observer->getOrderItem();
$options = $orderItem->getProductOptions();
$options['additional_options'] = unserialize($additionalOptions->getValue());
$orderItem->setProductOptions($options);
}
}
From this point on the additional options will be visible in the customer order history in the frontend and the order emails, as well as in the admin interface order view, invoices, shipments, creditmemos and PDFs.
Add support for reorders
In order to carry the oprions over to the new order during a reorder, you need to take care to copy them over. Here is one possibility using the checkout_cart_product_add_after
event.
<checkout_cart_product_add_after>
<observers>
<extra_options>
<type>singleton</type>
<class>extra_options/observer</class>
<method>checkoutCartProductAddAfter</method>
</extra_options>
</observers>
</checkout_cart_product_add_after>
The parsing of the extra options and building the additional options array should be moved into a separate function to avoid code duplication, but for this example I'll leave the required logic for each method in place for clarity.
public function checkoutCartProductAddAfter(Varien_Event_Observer $observer)
{
$action = Mage::app()->getFrontController()->getAction();
if ($action->getFullActionName() == 'sales_order_reorder')
{
$item = $observer->getQuoteItem();
$buyInfo = $item->getBuyRequest();
if ($options = $buyInfo->getExtraOptions())
{
$additionalOptions = array();
if ($additionalOption = $item->getOptionByCode('additional_options'))
{
$additionalOptions = (array) unserialize($additionalOption->getValue());
}
foreach ($options as $key => $value)
{
$additionalOptions[] = array(
'label' => $key,
'value' => $value,
);
}
$item->addOption(array(
'code' => 'additional_options',
'value' => serialize($additionalOptions)
));
}
}
}
Translation:
There is no mechanism in place to translate these option labels or values. Here are a few ideas that might be useful in that regard.
In a quote_item_load_after event observer, get the additional options array and set $option['print_value'] = $helper->__($option['value']);
. If print_value
is set, Magento will use that for rendering the display.
The same can be done with order items.
There is no such thing as a print_label
, but you could set a custom index (label_source
maybe) and set the label on the fly using that as the source, e.g. $option['label'] = $helper->__($option['label_source']);
.
Beyond that you would probably have to resort to modifying the templates (grep for getItemOptions()
), or overriding the block classes (grep additional_options
).
Best Answer
Have you verified that the attribute is being added to
eav_attribute
table in the database with the correctentity_type_id
? (I think sales_order is 11 by default, but don't assume that)At first glance, it looks like you should be using
HTH, JD