we need an option in backend > attributes to set "timeout" for each product.
we want to display the timeout in view page.
something as below :
after the timeout ends, automaticlly Product status should become "Disable" in Backend.
we need an option in backend > attributes to set "timeout" for each product.
we want to display the timeout in view page.
something as below :
after the timeout ends, automaticlly Product status should become "Disable" in Backend.
For UI, you can use one of these FREE extensions:
Then setup a CRON for checking timeout
attribute and Disable product
credits for our boss: @R.S
From www.ecomdev.org (page no longer exist)
Introduction This article will help you to understand basic customizations for catalog products and performing custom cron jobs in Magento.
Functionality Before start the development you should imagine what it does and choose the functionality that fits all the requirements.
The requirements for the module are the following:
It should allow an admin user to specify the activation and expiration dates for a product.
It should check products for the specified dates and perform the following actions depend on the date types:
So the module development should follow these steps:
Create a custom attribute back-end model to allow storing date for datetime attribute (Magento native eav implementation removes the time part from a datetime string)
Create two attributes for a product, that might be fulfilled with activation and expiry dates and assign custom attribute backend model to them Create an event observer that should handle product edit block rendering to enable time specifying for the date fields Create a cron job that checks the activation and expiry dates for products and enables/disables them
Basic Structure
Now you know how it should work, so you can create a basic module structure.
The structure of the module should contain the following:
You should name the module before its structure creation. The module name consists of the module namespace and an internal module name separated by the underscore sign. So the name of this module will be “EcomDev_ScheduledProduct”, where “EcomDev” it’s my extension namespace.
First of all you should create the module bootstrap configuration file to enable your module. Bootstrap files located in “app/etc/modules” folder. The name of file should be the same as the module name. So you should create file “EcomDev_ScheduledProduct.xml”, the file structure should contain the module name, its code pool, activity state and dependence node for specifying of required modules. So it should be like the following:
<?xml version="1.0" encoding="UTF-8"?>
<config>
<modules>
<EcomDev_ScheduledProduct>
<active>true</active> <!-- the module activity state -->
<codePool>community</codePool> <!-- the module code pool -->
<depends>
<Mage_Catalog /> <!-- the module depends on Mage_Catalog module, so it mentioned here -->
</depends>
</EcomDev_ScheduledProduct>
</modules>
</config>
The module was specified to be placed in community code pool, so it should be placed in “app/code/community” folder and its path should be “app/code/community/EcomDev/ScheduledProduct”.
Now you should create the module configuration file, where you’ll specify the model namespace and setup script initialization statements.
Let’s create it: “app/code/community/EcomDev/ScheduledProduct/etc/config.xml”
<?xml version="1.0" encoding="UTF-8"?>
<config>
<modules>
<EcomDev_ScheduledProduct>
<version>1.0.0</version>
</EcomDev_ScheduledProduct>
</modules>
<global>
<models>
<ecomdev_scheduledproduct>
<!-- specification of model name space,
so we can call models like Mage::getModel('ecomdev_scheduledproduct/somemodelname') -->
<class>EcomDev_ScheduledProduct_Model</class>
</ecomdev_scheduledproduct>
</models>
<resources>
<!-- specifying of setup model and setup script path in sql folder -->
<ecomdev_scheduledproduct_setup>
<setup>
<module>EcomDev_ScheduledProduct</module>
<class>EcomDev_ScheduledProduct_Model_Mysql4_Setup</class>
</setup>
<connection>
<!-- use catalog connection to modify products -->
<use>catalog_setup</use>
</connection>
</ecomdev_scheduledproduct_setup>
</resources>
</global>
</config>
Attribute Backend Model Before creation of setup script you need to take care of datetime attribute backend model to specify it in setup. Create it in module “Model” folder. In this module you should call it “EcomDev_ScheduledProduct_Model_Attribute_Backend_Datetime”, the path “Attribute_Backend_Datetime” explains what the model does. In it you should override “beforeSave($object)”, “afterLoad($object)” and “formatDate($date)” methods to change the logic of your attributes storage. You might like also to add “compareDateToCurrent($date)” method to check activation or expiration date came true before product save. The model should be extended from “Mage_Eav_Model_Entity_Attribute_Backend_Datetime”. “app/code/community/EcomDev/ScheduledProduct/Model/Attribute/Backend/Datetime.php”
<?php
/**
* Expiry and Activation dates custom backend model
*
*/
class EcomDev_ScheduledProduct_Model_Attribute_Backend_Datetime extends Mage_Eav_Model_Entity_Attribute_Backend_Datetime
{
/**
* Activation date attribute code
*
* @var string
*/
const ATTRIBUTE_ACTIVATION_DATE = 'ecomdev_activation_date';
/**
* Expiry date attribute code
*
* @var string
*/
const ATTRIBUTE_EXPIRY_DATE = 'ecomdev_expiry_date';
/**
* Status attribute code
*
* @var string
*/
const ATTRIBUTE_STATUS = 'status';
/**
* Checks date to update product status
* on the save in the admin panel
*
* @param Mage_Catalog_Model_Product $object
* @return EcomDev_ScheduledProduct_Model_Attribute_Backend_Datetime
*/
public function beforeSave($object)
{
parent::beforeSave($object);
$code = $this->getAttribute()->getAttributeCode();
$compareResult = $this->compareDateToCurrent($object->getData($code));
if ($compareResult !== false) {
// If the date is set
if (($compareResult < 0 && $code == self::ATTRIBUTE_ACTIVATION_DATE) ||
($compareResult >= 0 && $code == self::ATTRIBUTE_EXPIRY_DATE)) {
// If the date is in the past and it's activation date
// or the date is in the future and it's expiry date,
// so the product should be deactivated
$object->setData(
self::ATTRIBUTE_STATUS,
Mage_Catalog_Model_Product_Status::STATUS_DISABLED
);
}
}
return $this;
}
/**
* Magento native function doesn't save
* the time part of date so the logic of retrieving is changed
*
* @param string|int $date
* @return string|null
*/
public function formatDate($date)
{
if (empty($date)) {
return null;
} elseif (!($date instanceof Zend_Date)) {
// Parse locale representation of the date, eg. parse user input from date field
$dateString = $date;
$usedDateFormat = Mage::app()->getLocale()->getDateTimeFormat(
Mage_Core_Model_Locale::FORMAT_TYPE_SHORT
);
// Instantiate date object in current locale
$date = Mage::app()->getLocale()->date();
$date->set($dateString, $usedDateFormat);
}
// Set system timezone for date object
$date->setTimezone(Mage_Core_Model_Locale::DEFAULT_TIMEZONE);
return $date->toString(Varien_Date::DATETIME_INTERNAL_FORMAT);
}
/**
* Compare date to current date
*
* Returns -1 if the date is in the past, and 1 if it's in the future,
* returns 0 if the dates are equal.
*
* @param string $date
* @return int
*/
public function compareDateToCurrent($date)
{
if (empty($date)) {
return false;
}
$compareDate = Mage::app()->getLocale()->date($date, Varien_Date::DATETIME_INTERNAL_FORMAT);
$currentDate = Mage::app()->getLocale()->date();
return $currentDate->compare($compareDate);
}
/**
* Converts timezone after object load, fixes issue in the core form element
*
* @param Mage_Core_Model_Abstract $object
* @return EcomDev_ScheduledProduct_Model_Attribute_Backend_Datetime
*/
public function afterLoad($object)
{
$code = $this->getAttribute()->getAttributeCode();
if ($object->getData($code) && !($object->getData($code) instanceof Zend_Date)) {
$date = Mage::app()->getLocale()->date();
$dateString = $object->getData($code);
$currentTimezone = $date->getTimezone();
$date->setTimezone(Mage_Core_Model_Locale::DEFAULT_TIMEZONE);
$date->set($dateString, Varien_Date::DATETIME_INTERNAL_FORMAT);
$date->setTimezone($currentTimezone);
$object->setData($code, $date);
}
return parent::afterLoad($object);
}
}
Setup Now you need to create setup model and setup script. In the configuration file, the setup model class name is “EcomDev_ScheduledProduct_Model_Mysql4_Setup”. The module extends the catalog functionality, so the module setup model extends from the catalog setup model. “app/code/community/EcomDev/ScheduledProduct/Model/Mysql4/Setup.php”
<?php
/**
* Setup model for scheduled product module, extended from catalog module setup
*/
class EcomDev_ScheduledProduct_Model_Mysql4_Setup extends Mage_Catalog_Model_Resource_Eav_Mysql4_Setup
{
}
And you need to create the setup script in “sql/ecomdev_scheduledproduct_setup” folder. The module version is 1.0.0 and it’s actually the first version, so you need to name it “mysql4-install-1.0.0.php”. This script should contain adding of the attributes to EAV. Also for this module we should add columns to “catalog_product_entity” table, because it will speed up the product mass status update process. “app/code/community/EcomDev/ScheduledProduct/sql/ecomdev_scheduledproduct_setup/mysql4-install-1.0.0.php”
<?php
/* @var $this EcomDev_ScheduledProduct_Model_Mysql4_Setup */
$this->startSetup();
// For performance reasons we should add this fields to main entity table
// Activation date column adding to product entity table
$this->getConnection()->addColumn(
$this->getTable('catalog/product'),
EcomDev_ScheduledProduct_Model_Attribute_Backend_Datetime::ATTRIBUTE_ACTIVATION_DATE,
'DATETIME DEFAULT NULL'
);
// Expiry date column adding to product entity table
$this->getConnection()->addColumn(
$this->getTable('catalog/product'),
EcomDev_ScheduledProduct_Model_Attribute_Backend_Datetime::ATTRIBUTE_EXPIRY_DATE,
'DATETIME DEFAULT NULL'
);
// Activation date attribute information adding to the product entity
$this->addAttribute(
'catalog_product',
EcomDev_ScheduledProduct_Model_Attribute_Backend_Datetime::ATTRIBUTE_ACTIVATION_DATE,
array(
'type' => 'static',
'input' => 'date',
'label' => 'Activation Date',
'global' => Mage_Catalog_Model_Resource_Eav_Attribute::SCOPE_GLOBAL,
'backend' => 'ecomdev_scheduledproduct/attribute_backend_datetime',
'visible' => 1,
'required' => 0,
'position' => 10,
'group' => 'Schedule Settings'
)
);
// Expiry date attribute information adding to the product entity
$this->addAttribute(
'catalog_product',
EcomDev_ScheduledProduct_Model_Attribute_Backend_Datetime::ATTRIBUTE_EXPIRY_DATE,
array(
'type' => 'static',
'input' => 'date',
'label' => 'Expiry Date',
'global' => Mage_Catalog_Model_Resource_Eav_Attribute::SCOPE_GLOBAL,
'backend' => 'ecomdev_scheduledproduct/attribute_backend_datetime',
'visible' => 1,
'required' => 0,
'position' => 20,
'group' => 'Schedule Settings'
)
);
$this->endSetup();
Event Observer After creation of the setup script and the back-end model, you need to take care about the input field rendering for the attributes, that’s why you need to observe “adminhtml_catalog_product_edit_prepare_form” event. So you should create “EcomDev_ScheduledProduct_Model_Observer” class with “observeProductEditFortInitialization(Varien_Event_Observer $observer)” method. It should check the form object for elements with the date attributes code and add datetime format to them if found any.
<?php
/**
* Observer for core events handling
*
*/
class EcomDev_ScheduledProduct_Model_Observer
{
/**
* Observes event 'adminhtml_catalog_product_edit_prepare_form'
* and adds custom format for date input
*
* @param Varien_Event_Observer $observer
* @return void
*/
public function observeProductEditFortInitialization(Varien_Event_Observer $observer)
{
$form = $observer->getEvent()->getForm();
$elementsToCheck = array(
EcomDev_ScheduledProduct_Model_Attribute_Backend_Datetime::ATTRIBUTE_ACTIVATION_DATE,
EcomDev_ScheduledProduct_Model_Attribute_Backend_Datetime::ATTRIBUTE_EXPIRY_DATE
);
foreach ($elementsToCheck as $elementCode) {
$element = $form->getElement($elementCode);
if (!$element) {
continue;
}
$element->setFormat(
Mage::app()->getLocale()->getDateTimeFormat(
Mage_Core_Model_Locale::FORMAT_TYPE_SHORT
)
);
$element->setTime(true);
}
}
}
Also you need to define your event observer in the module configuration file (config.xml):
<config>
<!-- here goes the code you've created before
...
...
-->
<adminhtml>
<events>
<adminhtml_catalog_product_edit_prepare_form>
<observers>
<ecomdev_scheduledproduct>
<type>singleton</type>
<model>ecomdev_scheduledproduct/observer</model>
<method>observeProductEditFortInitialization</method>
</ecomdev_scheduledproduct>
</observers>
</adminhtml_catalog_product_edit_prepare_form>
</events>
</adminhtml>
</config>
Cron Job When you’ve done with setting up the admin interface for your attributes you need to create a cron job that automatically activates/deactivates products. You can put the logic in “EcomDev_ScheduledProduct_Model_Observer” class, because realization of cron job processing calls is similar to event processing, except you wont get $observer argument.
<?php
/**
* Observer for core events handling and cron jobs processing
*
*/
class EcomDev_ScheduledProduct_Model_Observer
{
/*
* here goes the code you've created before
* ............
* ............
*/
/**
* Cron job for processing of scheduled products
*
* @return void
*/
public function cronProcessScheduledProducts()
{
$currentDate = Mage::app()->getLocale()->date()->toString(
Varien_Date::DATETIME_INTERNAL_FORMAT
);
$productModel = Mage::getModel('catalog/product');
/* @var $expiredProductsCollection Mage_Catalog_Model_Resource_Eav_Mysql4_Product_Collection */
// Prepare collection of scheduled for expiry but haven't yet deactivated products
$expiredProductsCollection = $productModel->getCollection()
// Add filter for expired but products haven't yet deactivated
->addFieldToFilter(
EcomDev_ScheduledProduct_Model_Attribute_Backend_Datetime::ATTRIBUTE_EXPIRY_DATE,
array(
'nnull' => 1, // Specifies that date shouldn't be empty
'lteq' => $currentDate // And lower than current date
)
)
->addFieldToFilter(
EcomDev_ScheduledProduct_Model_Attribute_Backend_Datetime::ATTRIBUTE_STATUS,
Mage_Catalog_Model_Product_Status::STATUS_ENABLED
);
// Retrieve product ids for deactivation
$expiredProductIds = $expiredProductsCollection->getAllIds();
unset($expiredProductsCollection);
if ($expiredProductIds) {
Mage::getSingleton('catalog/product_action')
->updateAttributes(
$expiredProductIds,
array('status' => Mage_Catalog_Model_Product_Status::STATUS_DISABLED),
Mage_Core_Model_App::ADMIN_STORE_ID
);
}
/* @var $expiredProductsCollection Mage_Catalog_Model_Resource_Eav_Mysql4_Product_Collection */
// Prepare collection of scheduled for activation but haven't yet activated products
$activatedProductsCollection = $productModel->getCollection()
->addFieldToFilter(
EcomDev_ScheduledProduct_Model_Attribute_Backend_Datetime::ATTRIBUTE_ACTIVATION_DATE,
array(
'nnull' => 1, // Specifies that date shouldn't be empty
'lteq' => $currentDate // And lower than current date
)
)
// Exclude expired products
->addFieldToFilter(
EcomDev_ScheduledProduct_Model_Attribute_Backend_Datetime::ATTRIBUTE_EXPIRY_DATE,
array(
array('null' => 1), // Specifies that date shouldn't be empty
array('gt' => $currentDate) // And greater than current date
)
)
->addFieldToFilter(
EcomDev_ScheduledProduct_Model_Attribute_Backend_Datetime::ATTRIBUTE_STATUS,
Mage_Catalog_Model_Product_Status::STATUS_DISABLED
);
// Retrieve product ids for activation
$activatedProductIds = $activatedProductsCollection->getAllIds();
unset($activatedProductsCollection);
if ($activatedProductIds) {
Mage::getSingleton('catalog/product_action')
->updateAttributes(
$activatedProductIds,
array('status' => Mage_Catalog_Model_Product_Status::STATUS_ENABLED),
Mage_Core_Model_App::ADMIN_STORE_ID
);
}
}
}
And of course you should define your cron job in the configuration file (config.xml):
<config>
<!-- here goes the code you've created before
...
...
-->
<crontab>
<jobs>
<ecomdev_scheduledproduct_process_schedule>
<schedule>
<!-- Schedule for every 5 minutes -->
<cron_expr>*/5 * * * *</cron_expr>
</schedule>
<run>
<model>ecomdev_scheduledproduct/observer::cronProcessScheduledProducts</model>
</run>
</ecomdev_scheduledproduct_process_schedule>
</jobs>
</crontab>
</config>
Result Now you should login to the admin panel, navigate “System -> Cache Management -> Flush Magento Cache” to enable your extension. You can find the fields you’ve created at “Catalog -> Manage Products -> Edit/Add Product” page in “Schedule Settings” tab. And don’t forget to setup Magento cron in your system crontab.
Conclusion Now you know how to create simple customization for catalog with using of cron jobs in Magento. The module presented here available at Magento Connect as free community extension: Scheduled Products