Let's think this through:
The year is 2010
- An order is created in your store for an iPhone 3GS
- The admin loads the order to capture funds, and generate shipment
- The customer receives the order on time and is happy.
Fast forward to 2013
The customer's contract is up and wants to upgrade and purchase a new iPhone. You ask for the contract number. They don't know their account number; no problem, you'll look it up on the original order.
You load up the order to look at it and BAM:
PHP Fatal error: cannot call method getData on a non-object.
Why?! What happened*?
The product no longer exists in the store. The product was deleted by your merchandising team ages ago because you no longer sell iPhone 3GS's. Sure, the product was around for a couple years and maybe it was deactivated or listed as out of stock. But one day came and someone decided to delete it and now you're trying to load the product model and get an attribute from it.
Well, I guess you're out of luck, then.
This is a simple case of "I'm sorry Mario but our princess is in another castle" - product information is volatile. Products will one day go out of fashion, run out of stock, suppliers die off, or import tariffs/FDA regulations change and you can no longer make or sell the item.
To mitigate the problem at hand we need to copy pertinent information to the sales quote itself, and eventually to the sales order. I know, I know, this goes against everything you ever thought you knew about normalization. But the problem as I explained it is quite simple and the only solution is to either not allow admins to delete products or to duplicate information as it was at the time of the customer purchase.
Another example would be if you never did delete that iPhone 3GS; instead you renamed it to iPhone 4, then 4S, and then 5. You wouldn't want to come back 4 years later and it look as if the customer purchased an iPhone 5 in 2010, now, would you?
Rather, you'll want to store and then retrieve this information from the sales model. This has been answered half a dozen times on Magento.SE - here are a few:
When the time comes, you'll want to load up the attribute on the sales/order model as such:
$order = Mage::registry('current_order');
$suppliers = $order->getSuppliers();
$cost = $order->getCost();
Of course, this is done from within a template file that is rendered by a block that is added to your order view page in a custom module.
This is too much work
You're right; but it's the correct approach.
Instead you may want to use custom options. Save the attributes in question to the options object in the quote item at the time of the order and when the order is viewed in the backend you should see all options listed in the order view.
Tim has a great talk on how to accomplish this:
Magento is hard, isn't it? I'm glad we have Stackexchange. :) Cheers.
* This is probably the most disastrous example of poorly implemented functionality; in reality the most recent information would likely be displayed as any normal and sane person wouldn't call
Mage::getModel('catalog/product')->load($id); again on the page when the product is already loaded. Right? Right?!