Got this code (in: app/code/local/Mage/Adminhtml/Block/Sales/Order/Grid.php):
protected function _prepareCollection()
{
$collection = Mage::getResourceModel($this->_getCollectionClass());
$collection->getSelect()->join('sales_flat_order_item', '`sales_flat_order_item`.order_id=`main_table`.entity_id', array('skus' => new Zend_Db_Expr('group_concat(`sales_flat_order_item`.sku SEPARATOR "<br>")')))->group('sales_flat_order_item.entity_id');
$collection->getSelect()->join('sales_flat_order_payment', 'main_table.entity_id = sales_flat_order_payment.parent_id',array('method'))->group('sales_flat_order_payment.parent_id');
$this->setCollection($collection);
return parent::_prepareCollection();
}
When I comment the line below COL 1 or COL 2 this works fine, but I want them to work both, how is this done? (if I use them at the same time I get an error: Integrity constraint violation: 1052 Column 'entity_id' in group statement is ambiguous)
UPDATE WITH ANSWER:
protected function _prepareCollection()
{
$collection = Mage::getResourceModel($this->_getCollectionClass());
$collection->getSelect()->join('sales_flat_order_item', '`sales_flat_order_item`.order_id=`main_table`.entity_id', array('skus' => new Zend_Db_Expr('group_concat(`sales_flat_order_item`.sku SEPARATOR "<br>")')));
$collection->getSelect()->join('sales_flat_order_payment', 'main_table.entity_id = sales_flat_order_payment.parent_id',array('method'))->group('main_table.entity_id');
$this->setCollection($collection);
return parent::_prepareCollection();
}
The answer is in the error, the table to apply the group to cannot be determined. You need to explicitly define the table:
...->group('sales_flat_order_item.entity_id');
echo your query by using echo (string) $collection->getSelect(); You will get a plain sql query here.
Fire that query in database and check, are you getting results the way you want.
Also last but not the least Group also create problem.
Have a look at below link
using group() breaks getSelectCountSql in magento
Related
I have two tables: leads and hts_patients. Both table has phone column and I want to list all leads that has no record on hts_patients table(foreign key is phone).
So far, I have tried this and it works but taking so much long time.
$countries = ['DE','TR'];
$dateS = Carbon::now()->startOfMonth()->subMonth(4);
$dateE = Carbon::now()->startOfMonth();
$leads = Lead::whereBetween('created_at',[$dateS,$dateE])->whereIn('visitor_country',$countries)
->select('id','name','phone','visitor_country','source','description','contact','created_at')->get();
$patient = HtsPatient::pluck('phone');
foreach ($leads as $key=>$item){
if (isset($item->phone)){
$data =$patient->where('phone',$item->phone)->first();
if (!empty($data)){
$leads->forget($key);
}
}
}
return view('poll.leadSecond',['leads' => $leads]);
Thing, that I want is probably something like this;
$countries = ['DE','TR'];
$dateS = Carbon::now()->startOfMonth()->subMonth(4);
$dateE = Carbon::now()->startOfMonth();
$leads = DB::table('leads')->join('hts_patients','hts_patients.phone', '=', 'leads.phone')
->whereBetween('leads.created_at',[$dateS,$dateE])->whereIn('leads.visitor_country',$countries)
->whereNotIn('phone', function($query) {
$query->select('phone')
->from('hts_patients');
})
->select('leads.id','leads.name','leads.phone','leads.visitor_country','leads.source','leads.description','leads.contact','leads.created_at')->get();
But it gives an error says
SQLSTATE[23000]: Integrity constraint violation: 1052 Column 'phone'
in IN/ALL/ANY subquery is ambiguous
Any help?
you have tow tables with column called 'phone', in your whereNotIn clause you should specify witch on you wants.
I think the result should be like:
->whereNotIn('leads.phone', function($query) {
$query->select('hts_patients.phone');
// ->from('hts_patients'); you do not need this 'from'
})
I want to join another table with customer grid condition will be custom attribute value and table column value.
I have added one custom attributes for customers, attribute name is affiliate_id, and my other table name is aff_accounts, I want to show the aff_accounts table's column in the customer grid.
Please help me.
Thanks
If you are facing any issue you can ask me.Try the below code:
protected function _prepareCollection() {
$collection = Mage::getResourceModel('customer/customer_collection')->addNameToSelect();
$collection->getSelect()->join(
array('e' => 'event'), 'e.customer_id=main_table.entity_id', array('e.status') // added 'e.status' in stead of 'status'
);
$this->setCollection($collection);
return parent::_prepareCollection();
}
Hope it will help you.
I am having seller_id field in my custom table sellerrequest as foreign key. Primary reference is in customer/customer_collection collection. I want to show the seller name in admin grid from the seller_id. I am not sure how to join both collections but I tried with -
$collection = Mage::getModel("wallets/sellerrequest")
->join(
'customer/customer_collection',
'seller_id=main_table.seller_id'
)
->getCollection();
but, it doesn't work. Is this wrong way? Any Help appreciated.
Thanks.
Try this
$collection = Mage::getModel("wallets/sellerrequest")->getCollection();
$collection->getSelect()->joinLeft(
array('cust' => $collection->getTable('customer/customer_collection')),
'cust.seller_id = main_table.seller_id');
Hope this may help.By the way I haven't tried it. But the same worked for me.See the data in the collection to check whether you get the correct data or not.
Here is another example that i have tried.
protected function _prepareCollection(){
$collection = Mage::getModel('children/children')->getCollection();
$collection->getSelect()->joinLeft('schools', 'schools.school_id = main_table.school_id', array('school_name'));
$collection->addFieldToFilter('main_table.customer_id', array('in' => $this->_getCustomer()->getId()));
$this->setCollection($collection);
return parent::_prepareCollection();
}
Here i have joined "schools" table to my children model.In my case the common key between tables is school_id. This worked for me,check this out and make some ammendments to meet your requirement.
may be someone knows how to filter product grid by returned value from renderer.
In Grid.php I have:
protected function _prepareCollection() {
$collection->joinField( 'qty', 'cataloginventory/stock_item', 'qty', 'product_id=entity_id', '{{table}}.stock_id=1', 'left' );
$collection->joinTable( 'cataloginventory/stock_item','product_id=entity_id', array("stock_status" => "is_in_stock", "plan") )
->addAttributeToSelect('stock_status')
->addAttributeToSelect('plan');
protected function _prepareColumns() {
$this->addColumn( 'qty',
array(
'header' => Mage::helper( 'catalog' )->__( 'Qty' ),
'width' => '30px',
'type' => 'number',
'index' => 'qty',
'renderer' => new TBT_Enhancedgrid_Block_Catalog_Product_Grid_Plan(),
) );
}
In Plan.php
public function render(Varien_Object $row) {
$value = $row->getData('qty');
if (is_numeric($value))
{
$value = round($value, 2);
}
$value1 = $row->getData('plan');
if (is_numeric($value1))
{
$value1 = round($value1, 2);
}
$value3 = $value/$value1;
$valuepr = number_format( $value3 * 100, 2 ) . '%';
return '<strong>К: </strong>'.$value. '<br/>'.'<strong>P: </strong>'.$value1.'<br/>'.'<strong>Z: </strong>'.$value2.'<br/>'.'<strong>Pr: </strong>'.$valuepr;
}
}
It works fine and display result I need, but how I can filter in grid by value, which have been get in $valuepr?
Thank you for your answers.
If you want to filter collection by $valuepr then it has to be in the collection itself. At the moment you are computing it outside of your collection in the render() method.
In order to do so, you would need to amend collection in the _prepareCollection() method. This could be similar to the following code (please note that I am not able to test this, so it is more a hint than a ready-to-go solution):
protected function _prepareCollection()
{
// current collection settings goes here
$collection->getSelect()
->columns(
array(
'value_pr' => new Zend_Db_Expr(
'ROUND(ROUND(table_prefix_1.qty, 2) / ROUND(table_prefix_2.plan, 2), 2)'
)
)
);
}
where table_prefix_1 is a prefix of first cataloginventory/stock_item table and table_prefix_2 is a prefix of second stock_item table. If you want to know what prefixes those tables have you can log the SQL query, e.g.:
Mage::log($collection->getSelect()->assemble(), null, 'sql.log');
// or
$collection->load(false, true);
The first one will log the SQL query into sql.log file. You will find it in var/log folder of your Magento instance. This, however will not work fine with EAV collections like products, categories or customers. That's why I provided second way of checking the SQL. You can provide 2 parameters into collection's load() method. First one is a flag tells whether to display the query before running it against database and second one is a flag which tells whether to log the query into system.log.
Please note that you can filter a grid column only by one value. You cannot filter column qty by quantity and value_pr at the same time. You have to decide which one you want to use. You can always make it into separate columns.
I hope this helps.
I am looking to add a column to the product grid (in the admin area to be clear) to display how many times this product has been sold. Here is what I have so far after piecing together from several other posts:
In app/code/local/Namespace/Qtysold/Block/Adminhtml/Catalog/Product/Grid.php
<?php
class Namespace_Qtysold_Block_Adminhtml_Catalog_Product_Grid extends Mage_Adminhtml_Block_Catalog_Product_Grid
{
/* Overwritten to be able to add custom columns to the product grid. Normally
* one would overwrite the function _prepareCollection, but it won't work because
* you have to call parent::_prepareCollection() first to get the collection.
*
* But since parent::_prepareCollection() also finishes the collection, the
* joins and attributes to select added in the overwritten _prepareCollection()
* are 'forgotten'.
*
* By overwriting setCollection (which is called in parent::_prepareCollection()),
* we are able to add the join and/or attribute select in a proper way.
*
*/
public function setCollection($collection)
{
/* #var $collection Mage_Catalog_Model_Resource_Product_Collection */
$store = $this->_getStore();
if ($store->getId() && !isset($this->_joinAttributes['qty_sold'])) {
$collection->joinAttribute(
'qty_sold',
'reports/product_collection',
'entity_id',
null,
'left',
$store->getId()
);
}
else {
$collection->addAttributeToSelect('qty_sold');
}
echo "<pre>";
var_dump((string) $collection->getSelect());
echo "</pre>";
parent::setCollection($collection);
}
protected function _prepareColumns()
{
$store = $this->_getStore();
$this->addColumnAfter('qty_sold',
array(
'header'=> Mage::helper('catalog')->__('Qty Sold'),
'type' => 'number',
'index' => 'qty_sold',
),
'price'
);
return parent::_prepareColumns();
}
}
A couple of things here. 1) $store->getId() returns 0 so it never goes into that first block in setCollection, is that correct behavior since it is the Admin area? 2) If I force the joinAttribute to run, it causes an exception (Invalid entity...) which is sort of expected since reports doesn't appear to really be an entity, but I'm not really clear on this whole entity business. 3) In other examples (like this one: http://www.creativemediagroup.net/creative-media-web-services/magento-blog/30-show-quantity-sold-on-product-page-magento) they use something like this:
$_productCollection = Mage::getResourceModel('reports/product_collection')
->addOrderedQty($from, $to, true)
->addAttributeToFilter('sku', $sku)
->setOrder('ordered_qty', 'desc')
->getFirstItem();
And I am not sure if there is any way to "join" with this reports/product_collection or if there is any way to recreate its "addOrderedQty" data?
This is on Magento 1.7. I can provide further details as needed. I am a beginner with Magento development so any help at all (including resources to learn) would be greatly appreciated. Thanks!
1) Admin Area does have the store ID = 0, so yes this will always be returned.
this will also mean your conditional always fails and never does any joining, it will just try and add the qty_sold to the collection, which of course will not work as it's not part of that entities data.
The issue is the joinAttribute method will only work on "Entites" (it depends on the classes used by the models you are trying to join), and as the reports/product collection isn't one of these you will have to join another way using methods like this:
join() or joinLeft()
with this kind of thing:
$collection->getSelect()
->join(
'customer_entity',
'main_table.customer_id = customer_entity.entity_id',
array('customer_name' => 'email')
);
Was also dealing with this issue and solved it as follows:
protected function _prepareCollection() {
// [...]
$collection = Mage::getModel('catalog/product')->getCollection();
// Add subquery join to sales_flat_order_item to get a SUM of how many times this product has been ordered
$totalOrderedQuery = Mage::getSingleton('core/resource')->getConnection('core_read')
->select()
->from('sales_flat_order_item', array('product_id', 'qty_ordered' => 'SUM(`qty_ordered`)'))
->group('product_id');
$collection->joinField('qty_ordered', $totalOrderedQuery, 'qty_ordered', 'product_id=entity_id', null, 'left');
// [...]
return parent::_prepareCollection();
}
Note the usage of $collection->joinField(), tried using the mentioned $collection->getSelect()->join(), but it gives all sorts of issues with sort orders and filtering due to the internal Magento data collection not recognizing the column as part of the data set.
Then in _prepareColumns you can simply add the column:
$this->addColumn('qty_ordered', array(
'header' => Mage::helper('xyz')->__('Total quantity ordered'),
'sortable' => true,
'width' => '10%',
'index' => 'qty_ordered',
));
You might want to add a renderer which checks and converts a NULL value to '0', otherwise you will end up with empty columns if the product hasn't been ordered yet (you could also fix this in the SELECT query by using IFNULL for qty_ordered).
I was able to achieve what I needed (though it is hardly perfect) thanks to that tip from Andrew. Here is my updated code for setCollection:
public function setCollection($collection)
{
/* #var $collection Mage_Catalog_Model_Resource_Product_Collection */
$store = $this->_getStore();
$collection->getSelect()->joinLeft(
array('oi' => 'sales_flat_order_item'),
'e.entity_id = oi.product_id',
array("qty_sold" => 'SUM(oi.qty_ordered)')
)->group('e.entity_id');
parent::setCollection($collection);
}
I was curious if any Magento developers see a serious flaw in this approach (I'm aware of some of the business logic such as not counting products that were canceled, etc) or recommendations for a better approach. Either way this is "good enough" for now and meets my needs, so I'll post in case others need it.