Playing with Dates in Magento

December 11, 2011  |  4 Comments  |  by Raj (MagePsycho)  |  Latest, Magento, PHP

Introduction

Being a PHP developer, you are no way hiding yourself from PHP’s date() function.
In case of Magento, it makes use of timezone which is configured from the backend (System > Configuration > General > Locale Options > Timezone) for formatting/displaying date/time.
And this makes the results obtained with the php’s date() function and the Magento’s one a bit different.
For example:
Normal PHP Way

$currentTimestamp = time();
echo $date = date('Y-m-d', $currentTimestamp); //2011-12-11 (current date of the server)

Magento Way

$currentTimestamp = Mage::getModel('core/date')->timestamp(time()); //Magento's timestamp function makes a usage of timezone and converts it to timestamp
echo $date = date('Y-m-d', $currentTimestamp); //The value may differ than above because of the timezone settings.

Since Magento is meant to be for multi-website / multi-lingual / multi-locale purpose, it’s always a good practice to format the date using Magento’s date/time function.
AFAIK, there is no need for conversion of date/time while inserting into the database. The formatting/conversion thing is only done at the frontend level for displaying purposes.

Some Useful Examples

1. Displaying current date

$currentTimestamp = Mage::getModel('core/date')->timestamp(time());
echo $currentDate = date('Y-m-d', $currentTimestamp);

OR

echo $currentDate = Mage::getModel('core/date')->date('Y-m-d');

2. Formatting any date in any format

$anyDate = '2011-12-11';
$dateTimestamp = Mage::getModel('core/date')->timestamp(strtotime($anyDate));
echo $currentDate = date('d.m.Y', $dateTimestamp);

OR

$anyDate = '2011-12-11';
echo $currentDate = Mage::getModel('core/date')->date('d.m.Y', strtotime($anyDate));

3. Predefined date formatting

$dateToFormat = '2011-12-11';
Mage::helper('core')->formatDate($dateToFormat, 'medium', false);

Note: Mage_Core_Helper_Data::format() has following arguments

/**
 * Format date using current locale options
 *
 * @param   date|Zend_Date|null $date in GMT timezone
 * @param   string $format (full, long, medium, short)
 * @param   bool $showTime
 * @return  string
 */
public function formatDate($date=null, $format='short', $showTime=false)
{
....
}

Hope this gave some info about Date/Time functionality available in Magento.
Thanks for reading!
Cheers!!

Adding new mass action to admin grid in Magento

December 5, 2011  |  6 Comments  |  by Raj (MagePsycho)  |  Latest, Magento

Introduction

You know Magento allows to have mass action on the selected grid listing items.
The purpose of mass action is obvious that it allows to have mass operation on the selected rows at once. Some popular mass action are: Delete, Update Status etc.

Mass Action (Sales > Order Grid)


This is an often requirement that you may need to add new mass action to sales, customer, products etc. So here i will be sharing the different ways for adding new mass action:

1. By Extending the Admin Grid:

For example purpose we will be using Sales Order Grid.
1.1 Use the following code in config.xml of your module (for example: app/code/local/MagePsycho/Newmodule/etc)

...
<global>
	<blocks>
		<adminhtml>
			<rewrite>
				<sales_order_grid>MagePsycho_Newmodule_Block_Sales_Order_Grid</sales_order_grid>
			</rewrite>
		</adminhtml>
	</blocks>	
</global>
...

1.2 Create a file: app/code/local/MagePsycho/Newmodule/Block/Sales/Order/Grid.php and paste the following code:

<?php
class MagePsycho_Newmodule_Block_Sales_Order_Grid extends Mage_Adminhtml_Block_Sales_Order_Grid
{	
	protected function _prepareMassaction()
    {
        parent::_prepareMassaction();
        
        // Append new mass action option 
        $this->getMassactionBlock()->addItem(
      		'newmodule',
            array('label' => $this->__('New Mass Action Title'), 
				  'url'   => $this->getUrl('newmodule/controller/action') //this should be the url where there will be mass operation
			)
        );
    }
}

1.3 That’s all. This will show up the new mass action in the drop-down of Sales > Order Grid.
Note: One of the major drawback of this feature is the compatibility issue with other extension which are extending the same Sales Order Grid class.

2. Using event: core_block_abstract_prepare_layout_before

2.1 Use the following xml code in config.xml:

<adminhtml>
	...
	<events>
		<core_block_abstract_prepare_layout_before>
			<observers>
				<newmodule_core_block_abstract_prepare_layout_before>
					<class>newmodule/observer</class>
					<method>addMassAction</method>
				</newmodule_core_block_abstract_prepare_layout_before>
			</observers>
		</core_block_abstract_prepare_layout_before>
	</events>
	...
</adminhtml>

2.2 Create a Model file: app/code/local/MagePsycho/Newmodule/Model/Observer.php and paste the following code:

<?php
class MagePsycho_Newmodule_Model_Observer
{
    public function addMassAction($observer)
    {
        $block = $observer->getEvent()->getBlock();
        if(get_class($block) =='Mage_Adminhtml_Block_Widget_Grid_Massaction'
            && $block->getRequest()->getControllerName() == 'sales_order')
        {
            $block->addItem('newmodule', array(
                'label' => 'New Mass Action Title',
                'url' => Mage::app()->getStore()->getUrl('newmodule/controller/action'),
            ));
        }
    }
}

2.3 That’s all.
Note: This is more upgrade proof method because we are not extending any core class but using event-observer method.
It’s always a best practice to use event-observer method whenever/wherever possible.

Lastly, this is not the full working code, we have only tried to show how to add new mass action to the grid. The main mass operation on the selected items should be done in controller level which has been skipped from this article and can try of your own.

Thanks for reading.
Happy Coding!

Unzipping archive files using SSH

December 2, 2011  |  No Comments  |  by Raj (MagePsycho)  |  Latest, Linux

Extracting archive file depends on the type.
Here goes the list of extracting/unzipping command for various archive types:

1> Unzipping .zip file

unzip filename.zip

2> Unzipping .tar file

tar -xvf filename.tar

3> Unzipping .tar.gz or .tgz file

tar -zxvf filename.tar.gz
tar -zxvf filename.tgz

4> Unzipping .gz file

gunzip file.gz

5> Unzipping .bz2 file

bunzip2 file.bz2

Let me know if you have any unzipping command for new file type.

Thanks for reading.

Updating product qty in Magento in an easier & faster way

December 2, 2011  |  41 Comments  |  by Raj (MagePsycho)  |  Latest, Magento, Mysql

Introduction

Product Qty can be updated via default import profile though but this is very slow and requires lots of csv fields(besides sku & qty) for updating.
Today i am going to talk about updating product qty just by using csv with two fields: sku & qty(new) which is very fast enough even for thousands of products.

Steps:

1> Prepare CSV file(stocks.csv) with two fields: sku & qty and upload in the root of Magento installation.
You can see the snapshot how it should look like:
stocks.csv

2> Create a file: update_stocks.php in the root of magento installation and paste the following code:

<?php
/**
 * @author		MagePsycho <info@magepsycho.com>
 * @website		http://www.magepsycho.com
 * @category	Export / Import
 */
$mageFilename = 'app/Mage.php';
require_once $mageFilename;
Mage::setIsDeveloperMode(true);
ini_set('display_errors', 1);
umask(0);
Mage::app('admin');
Mage::register('isSecureArea', 1);
Mage::app()->setCurrentStore(Mage_Core_Model_App::ADMIN_STORE_ID);

set_time_limit(0);
ini_set('memory_limit','1024M');

/***************** UTILITY FUNCTIONS ********************/
function _getConnection($type = 'core_read'){
	return Mage::getSingleton('core/resource')->getConnection($type);
}

function _getTableName($tableName){
	return Mage::getSingleton('core/resource')->getTableName($tableName);
}

function _getAttributeId($attribute_code = 'price'){
	$connection = _getConnection('core_read');
	$sql = "SELECT attribute_id
				FROM " . _getTableName('eav_attribute') . "
			WHERE
				entity_type_id = ?
				AND attribute_code = ?";
	$entity_type_id = _getEntityTypeId();
	return $connection->fetchOne($sql, array($entity_type_id, $attribute_code));
}

function _getEntityTypeId($entity_type_code = 'catalog_product'){
	$connection = _getConnection('core_read');
	$sql		= "SELECT entity_type_id FROM " . _getTableName('eav_entity_type') . " WHERE entity_type_code = ?";
	return $connection->fetchOne($sql, array($entity_type_code));
}

function _checkIfSkuExists($sku){
	$connection = _getConnection('core_read');
	$sql		= "SELECT COUNT(*) AS count_no FROM " . _getTableName('catalog_product_entity') . "	WHERE sku = ?";
	$count		= $connection->fetchOne($sql, array($sku));
	if($count > 0){
		return true;
	}else{
		return false;
	}
}

function _getIdFromSku($sku){
	$connection = _getConnection('core_read');
	$sql		= "SELECT entity_id FROM " . _getTableName('catalog_product_entity') . " WHERE sku = ?";
	return $connection->fetchOne($sql, array($sku));
}

function _updateStocks($data){
	$connection		= _getConnection('core_write');
	$sku			= $data[0];
	$newQty			= $data[1];
	$productId		= _getIdFromSku($sku);
	$attributeId	= _getAttributeId();

	$sql			= "UPDATE " . _getTableName('cataloginventory_stock_item') . " csi,
					   " . _getTableName('cataloginventory_stock_status') . " css
	                   SET
					   csi.qty = ?,
					   csi.is_in_stock = ?,
	                   css.qty = ?,
					   css.stock_status = ?
					   WHERE
					   csi.product_id = ?
			           AND csi.product_id = css.product_id";
	$isInStock		= $newQty > 0 ? 1 : 0;
	$stockStatus	= $newQty > 0 ? 1 : 0;
	$connection->query($sql, array($newQty, $isInStock, $newQty, $stockStatus, $productId));
}
/***************** UTILITY FUNCTIONS ********************/

$csv				= new Varien_File_Csv();
$data				= $csv->getData('stocks.csv'); //path to csv
array_shift($data);

$message = '';
$count   = 1;
foreach($data as $_data){
	if(_checkIfSkuExists($_data[0])){
		try{
			_updateStocks($_data);
			$message .= $count . '> Success:: Qty (' . $_data[1] . ') of Sku (' . $_data[0] . ') has been updated. <br />';

		}catch(Exception $e){
			$message .=  $count .'> Error:: while Upating  Qty (' . $_data[1] . ') of Sku (' . $_data[0] . ') => '.$e->getMessage().'<br />';
		}
	}else{
		$message .=  $count .'> Error:: Product with Sku (' . $_data[0] . ') does\'t exist.<br />';
	}
	$count++;
}
echo $message;

3> Open your browser and run the following url:
http://your-magento-url/update_stocks.php
You will see how fast the qty of corresponding skus are updated.

Thanks for reading guys!!

Happy Importing!!