Magento - add custom attribute (column) to sales_order index grid - magento

I've added a custom attribute to the sales_order_flat table, and I'm trying to display this attribute in the grid at sales_order/index.
I've done this with customer attributes successfully, but I'm getting errors when trying the same thing with order data.
<global>
<blocks>
<adminhtml>
<rewrite>
<sales_order_grid>WACI_AdminHtmlExt_Block_Sales_Order_Grid</sales_order_grid>
</rewrite>
</adminhtml>
</blocks>
<!-- etc -->
app/code/local/namespace/module/Block/Sales/Order/Grid.php
class WACI_AdminHtmlExt_Block_Sales_Order_Grid extends Mage_Adminhtml_Block_Sales_Order_Grid
{
protected function _prepareColumns()
{
$this->addColumn('dynamics_ord', array(
'header' => $this->__('Dynamics ID'),
'width' => '75px',
'index' => 'dynamics_ord',
));
$this->addColumnsOrder('dynamics_ord','entity_id');
return parent::_prepareColumns();
}
}
I see that _prepareCollection is sometimes used, but I'm trying to just amend the collection during setCollection for, if nothing else, simplicity.
Whatever the case, the column displays, but no data is produced. (And the page errors out when I try to sort).
Any ideas on this?
Update
This post is an extension of this SO thread I've updated it to match the modules current status. That is, I'm adding columns to both sales_flat_order and sales_flat_order_grid.
From that post, I've got an action that takes place to set this attribute value (after the order has been completed).
My question at this point is - how does updateGridRecords() come into play?
=> updateGridRecords appears to be called automatically when the $order->save() gets called (something I'm doing manually after the order is complete).
If I understand this correctly, because I'm not pulling data from any other model, the _prepareColumns call is all that's required.
=> yep. Displaying and sorting properly after the attr is saved. Win!

The difference between customer collection and order grid collection is that customer collection is derived from Mage_Eav_Model_Entity_Collection_Abstract and sales_flat_order_grid collection is derived from Mage_Sales_Model_Resource_Abstract which is not EAV.
Because of that you can't add attributes to select like you would normaly be able to do with EAV - all the attributes that you want to use must be represented as a table column in the flat table.
The function addAttributeToSelect that you are calling is implemented in Mage_Sales_Model_Resource_Collection_Abstract class and uses in background addFieldToSelect so in you case you should have a column with name dynamics_ord in sales_flat_order_grid table.
The function that moves attribute values from order EAV to order grid is Mage_Sales_Model_Resource_Order_Abstract::updateGridRecords and this function reads the structure of sales_flat_order_grid table to know which attributes should be written to sales_flat_order_grid table so if dynamics_ord column is missing you will have to add it in your module's install script.
I came across this stack overflow solution on how to add the column in install script and then add it to the grid. The answer is a bit outdated but I think it could work.
I have also found this out of the box solution on how to add an attribute that will be used on orders grid but haven't tested it so I can't be certain if it works.

When you make a join EAV table with FLAT table then you can not filter the data in grid.
I had faced same problem earlier and had invested 4 days in that with my seniors, then finally come 2 conclusion that you can not do that....!!!

Related

Displaying single product through list.phtml edit

So what i'm trying to achieve is that the product with the attribute 'promotion' set to 'yes' is displayed on the frontpage of the website. This is working, but the .phtml file i'am using with this is the regular list.phtml. This is currently showing all the items I have set to promotion but I only want to show 1.
So in short: How do I edit the list.phtml to only show 1 product instead of everything?
Change how you are pulling your collection. Clone/Rename your list.phtml, for example promotion.phtml. Then change this line, from this:
$_productCollection=$this->getLoadedProductCollection();
To this:
$_productCollection = Mage::getModel('catalog/product')
->getCollection()
->addAttributeToSelect('*')
->addFieldToFilter('promotion', 1)
->addAttributeToSort('updated_at', 'DESC')
->clear()->setPageSize(1)->load();
And it should load only one item with promotion set to yes. Make sure you set the new template in either your CMS Page Content or XML, depending on which method this is added.
Explanation
Mage::getModel('catalog/product')->getCollection(): Gets the Product Collection. You can get other collections by changing the model, such as "catalog/category" and "cms/page".
->addAttributeToSelect('*'): Adds All Product Columns. This can be exchanged for things like ('name', 'url'). I'm assuming it's faster than loading all but I haven't benchmarked it. Since you're using the full template it's probably best to leave this set to all.
->addFieldToFilter('promotion', 1): Filters out products by attributes. Here we have the products filtered for all those with the 'promotion' attribute set to 1(yes/true). Products use this one, while categories use ->addAttributeToFilter() oddly enough. Definitely give Alan Storm's Collection Explanation(link below) a read through to know what all you can do with this one. You can add multiple filters to your collection, either by adding another ->addFieldToFilter(), or storing your filters in nested arrays.
->addAttributeToSort('updated_at', 'DESC'): Sorts the product collection by specific attribute and direction. Here I have the "updated_at" date set to descending order, "ASC" is ascending. You can add multiple sorting attributes, pay attention to the order you add them in, of course.
->clear()->setPageSize(1)->load(): These three are needed to make adjustments to how much the collection pulls. ->clear() must be called before it will allow changing how many products are pulled. The ->setPageSize() bit is where you specify how many products you would like to return, and ->load() of course loads the collection. Note that if you do not limit the size of the collection returned, you do not need this entire line, the products will iterate without having to call ->load().
Resources
Alan Storm said it best, give this a read and you should be a pro at manipulating collections: http://alanstorm.com/magento_collections

Magento: Not able to save data on multiple tables on DB

I've followed some suggestions to have some data copied over from one table to another table on the DB but it's not working.
Based on the response I received on this questions: Magento: How to save data to order_payment and quote_payment
I tried to do the following on the Mage/Sales/etc/Config.xml file
<sales_convert_order_payment>
<cc_bankname>
<to_quote_payment>cc_bankname</to_quote_payment>
</cc_bankname>
</sales_convert_order_payment>
and this
<sales_convert_quote_payment>
<cc_bankname>
<to_order_payment>cc_bankname</to_order_payment>
</cc_bankname>
</sales_convert_quote_payment>
but the bank name is only saved on the sales_flat_quote_payment table and not on the sales_flat_order_payment table which is the one I need to have this new data displayed on the order invoice and on the admin back-end under order/view.
If I manually input the data on the DB (the bank name that is) I'm able to display this information where it's needed but I cannot keep track of every transaction to manually input the data upon order completion since customers get to see their order details once it has been sumbited and they would not be able to view the new data until I have done so myself.
does anyone know why the data is not being carried over to the sales_fat_order_payment table?
I'm having the same issue with a new mobile number attribute I created but I believe if I can solve this one, then I should be able to handle all other similar issues.
That technique (naming it using same name with Mage) won't work for config.xml.
How it works? You need to read this article written by Alanstorm http://alanstorm.com/magento_config_declared_modules_tutorial
You need to create your own module by defining it in app/etc/modules (of course you should name it other than Mage).
eg:
app/etc/modules/Test_Sales.xml
content:
<?xml version="1.0"?>
<config>
<modules>
<Test_Sales>
<active>true</active>
<codePool>local</codePool>
</Test_Sales>
</modules>
</config>
app/code/local/Test/Sales/etc/config.xml -> define your new config in here
In older version of magento, sales order stored in eav type.
In higher version, it has been flatten.
Look at the name: sales_flat_quote_payment, sales_flat_order_payment
Magento always keep their data backward compatible, that's why it has attribute name cc_owner in eav_attribute.
In your case, you don't need to create new value in eav_attribute (you just need to add column cc_bankname in sales_flat_quote_payment and sales_flat_order_payment which I'm pretty sure you have already created).
As you have said before, the problem why it is not saved to sales_flat_order_payment is because of cache issue (Magento cache the config.xml so you need to refresh it System > Cache Management > Configuration)

Magento: How to save data to order_payment and quote_payment

I'm trying to have a custom credit card payment attribute save to two different tables but I'm not sure how to do this.
The normal credit card information saves to two different tables.
sales_flat_quote_payment
sales_flat_order_payment
I created the new attribute and it should be saved to both tables. The column with the correct value has been set on both tables but it only saves to one "sales_flat_quote_payment" right when the customer places the order.
How can I make it so it saves the data to both tables?
I found this reference but I'm not sure how to implemente it to make it work with a credit card attribute value.
http://www.magentocommerce.com/boards/viewthread/19344/P0/
Can anyone confirm if this would work?
<sales_copy_order_payment>
<cc_bankname>
<to_order>*</to_order>
</cc_bankname>
</sales_copy_order_payment>
Did you configure Magento to convert the new attribute from quote to order? If you check the config.xml from the Mage_Sales module and search for sales_convert_quote_payment. You see something as follows:
<sales_convert_quote_payment>
<method><to_order_payment>*</to_order_payment></method>
<additional_data><to_order_payment>*</to_order_payment></additional_data>
<additional_information><to_order_payment>*</to_order_payment></additional_information>
<po_number><to_order_payment>*</to_order_payment></po_number>
<cc_type><to_order_payment>*</to_order_payment></cc_type>
<cc_number_enc><to_order_payment>*</to_order_payment></cc_number_enc>
<cc_last4><to_order_payment>*</to_order_payment></cc_last4>
<cc_owner><to_order_payment>*</to_order_payment></cc_owner>
<cc_exp_month><to_order_payment>*</to_order_payment></cc_exp_month>
<cc_exp_year><to_order_payment>*</to_order_payment></cc_exp_year>
<cc_number><to_order_payment>*</to_order_payment></cc_number>
<cc_cid><to_order_payment>*</to_order_payment></cc_cid>
<cc_ss_issue><to_order_payment>*</to_order_payment></cc_ss_issue>
<cc_ss_start_month><to_order_payment>*</to_order_payment></cc_ss_start_month>
<cc_ss_start_year><to_order_payment>*</to_order_payment></cc_ss_start_year>
</sales_convert_quote_payment>
Magento uses these fieldsets to transport data from entity to entity. In this case from the quote_payment to the order_payment.
Since all config XML is merged into one big heap of XML, you can add additional nodes from your own modules config.xml. Something like:
<global>
<fieldsets>
<sales_convert_quote_payment>
<your_attribute><to_order_payment>*</to_order_payment></your_attribute>
</sales_convert_quote_payment>
</fieldsets>
</global>
Hope this helps you get underway.

Magento: which table should be used in the following code?

I read this article http://inchoo.net/ecommerce/magento/how-to-add-new-custom-category-attribute-in-magento/comment-page-1/
There is part of code in the installer:
//this will set data of your custom attribute for root category
Mage::getModel('catalog/category')
->load(1)
->setImportedCatId(0)
->setInitialSetupFlag(true)
->save();
//this will set data of your custom attribute for default category
Mage::getModel('catalog/category')
->load(2)
->setImportedCatId(0)
->setInitialSetupFlag(true)
->save();
Two question here:
Function load has a parameter. It is ID. Which table should be used for?
What is for setImportedCatId here? it's setter, but I don't understad what is it for.
Magento categories still use the EAV table structure, so the table you're interested in is
catalog_category_entity
However, you won't be able to see the category names here. Most data for the category objects are persisted to
catalog_category_entity_varchar
indexed back to the catalog_category_entity table by entity_id.
I grepped around modern source trees and it appears that the data property imported_cat_id (which is what the setter could be setting), but based on patterns used elsewhere in the Magento system my guess is that some version of Magento has code in the category saving tree that looks for imported_cat_id, and if it's set the new category data will be based on the old category. In other words, it allows you to quickly copy a category and save all it's meta-data. By setting it to 0 above, the Inchoo code is telling Magento that this is a new category.
That's just a guess though, but it's not something I'd worry about.

Magento 1.4.0.1 create and populate new attribute value for almost all products

I am trying to figure out how I might be able to do this - possibly in the mysql database, but I'm not sure of all the tables involved, so daren't go much further?
I have added an attribute called "condition" to the defaul attribute set.
I need to populate that attribute value for every product, but the admin system requires me to fill in many other attributes if I try to bulk update them using the admin form. This can't happen as "description" is different for every product, obviously.
So, can someone tell me how I might populate this attribute value with the value "new" for every product in my database?
Realistically, I can change this attribute value for the number of products that need a different value "used", but if the update could be filtered on SKU, I can make it work right first time. I think!
The programming approach is to save the following script in your Magento folder and execute it by visiting the address directly. It might be slow but that doesn't matter if it's only going to be run once and then deleted afterwards.
<?php
require 'app/Mage.php';
umask(0);
Mage::app();
$products = Mage::getResourceModel('catalog/product_collection');
foreach ($products as $product) {
// replace IS_NEW with a test perhaps using $product->getSku()
$product->setCondition(IS_NEW ? 'new' : 'used')
->save();
}
Not a programming answer so perhaps not suitable for Stack Overflow but there are a number of workarounds.
You could export all products to Excel, bulk update many rows at once then re-inport. Use Magmi if you have many products.
There are some extensions which let you update many attributes at once. This Mass Actions is expensive but gives you an idea what might be available if you search.
As much as I loathe desktop applications for web services there is Store Manager which specialises in bulk actions.

Resources