I ended up using musicliftsme answer. Here it is the complete code with an installer to update the salesrule table.
Module available here.
app/code/local/MB/Attributes/Block/Adminhtml/Edit/Tab/Main.php
<?php
/**
* Magento Enterprise Edition
*
* NOTICE OF LICENSE
*
* This source file is subject to the Magento Enterprise Edition License
* that is bundled with this package in the file LICENSE_EE.txt.
* It is also available through the world-wide-web at this URL:
* http://www.magentocommerce.com/license/enterprise-edition
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@magentocommerce.com so we can send you a copy immediately.
*
* DISCLAIMER
*
* Do not edit or add to this file if you wish to upgrade Magento to newer
* versions in the future. If you wish to customize Magento for your
* needs please refer to http://www.magentocommerce.com for more information.
*
* @category Mage
* @package Mage_Adminhtml
* @copyright Copyright (c) 2013 Magento Inc. (http://www.magentocommerce.com)
* @license http://www.magentocommerce.com/license/enterprise-edition
*/
/**
* Shopping Cart Price Rule General Information Tab
*
* @category Mage
* @package Mage_Adminhtml
* @author Magento Core Team <core@magentocommerce.com>
*/
class MB_Attributes_Block_Adminhtml_Edit_Tab_Main
extends Mage_Adminhtml_Block_Widget_Form
implements Mage_Adminhtml_Block_Widget_Tab_Interface
{
/**
* Prepare content for tab
*
* @return string
*/
public function getTabLabel()
{
return Mage::helper('salesrule')->__('Rule Information');
}
/**
* Prepare title for tab
*
* @return string
*/
public function getTabTitle()
{
return Mage::helper('salesrule')->__('Rule Information');
}
/**
* Returns status flag about this tab can be showed or not
*
* @return true
*/
public function canShowTab()
{
return true;
}
/**
* Returns status flag about this tab hidden or not
*
* @return true
*/
public function isHidden()
{
return false;
}
protected function _prepareForm()
{
$model = Mage::registry('current_promo_quote_rule');
$form = new Varien_Data_Form();
$form->setHtmlIdPrefix('rule_');
$fieldset = $form->addFieldset('base_fieldset',
array('legend' => Mage::helper('salesrule')->__('General Information'))
);
if ($model->getId()) {
$fieldset->addField('rule_id', 'hidden', array(
'name' => 'rule_id',
));
}
$fieldset->addField('product_ids', 'hidden', array(
'name' => 'product_ids',
));
$fieldset->addField('name', 'text', array(
'name' => 'name',
'label' => Mage::helper('salesrule')->__('Rule Name'),
'title' => Mage::helper('salesrule')->__('Rule Name'),
'required' => true,
));
$fieldset->addField('description', 'textarea', array(
'name' => 'description',
'label' => Mage::helper('salesrule')->__('Description'),
'title' => Mage::helper('salesrule')->__('Description'),
'style' => 'height: 100px;',
));
$fieldset->addField('is_active', 'select', array(
'label' => Mage::helper('salesrule')->__('Status'),
'title' => Mage::helper('salesrule')->__('Status'),
'name' => 'is_active',
'required' => true,
'options' => array(
'1' => Mage::helper('salesrule')->__('Active'),
'0' => Mage::helper('salesrule')->__('Inactive'),
),
));
if (!$model->getId()) {
$model->setData('is_active', '1');
}
if (Mage::app()->isSingleStoreMode()) {
$websiteId = Mage::app()->getStore(true)->getWebsiteId();
$fieldset->addField('website_ids', 'hidden', array(
'name' => 'website_ids[]',
'value' => $websiteId
));
$model->setWebsiteIds($websiteId);
} else {
$field = $fieldset->addField('website_ids', 'multiselect', array(
'name' => 'website_ids[]',
'label' => Mage::helper('salesrule')->__('Websites'),
'title' => Mage::helper('salesrule')->__('Websites'),
'required' => true,
'values' => Mage::getSingleton('adminhtml/system_store')->getWebsiteValuesForForm()
));
$renderer = $this->getLayout()->createBlock('adminhtml/store_switcher_form_renderer_fieldset_element');
$field->setRenderer($renderer);
}
$customerGroups = Mage::getResourceModel('customer/group_collection')->load()->toOptionArray();
$found = false;
foreach ($customerGroups as $group) {
if ($group['value']==0) {
$found = true;
}
}
if (!$found) {
array_unshift($customerGroups, array(
'value' => 0,
'label' => Mage::helper('salesrule')->__('NOT LOGGED IN'))
);
}
$fieldset->addField('customer_group_ids', 'multiselect', array(
'name' => 'customer_group_ids[]',
'label' => Mage::helper('salesrule')->__('Customer Groups'),
'title' => Mage::helper('salesrule')->__('Customer Groups'),
'required' => true,
'values' => Mage::getResourceModel('customer/group_collection')->toOptionArray(),
));
$couponTypeFiled = $fieldset->addField('coupon_type', 'select', array(
'name' => 'coupon_type',
'label' => Mage::helper('salesrule')->__('Coupon'),
'required' => true,
'options' => Mage::getModel('salesrule/rule')->getCouponTypes(),
));
$couponCodeFiled = $fieldset->addField('coupon_code', 'text', array(
'name' => 'coupon_code',
'label' => Mage::helper('salesrule')->__('Coupon Code'),
'required' => true,
));
$autoGenerationCheckbox = $fieldset->addField('use_auto_generation', 'checkbox', array(
'name' => 'use_auto_generation',
'label' => Mage::helper('salesrule')->__('Use Auto Generation'),
'note' => Mage::helper('salesrule')->__('If you select and save the rule you will be able to generate multiple coupon codes.'),
'onclick' => 'handleCouponsTabContentActivity()',
'checked' => (int)$model->getUseAutoGeneration() > 0 ? 'checked' : ''
));
$autoGenerationCheckbox->setRenderer(
$this->getLayout()->createBlock('adminhtml/promo_quote_edit_tab_main_renderer_checkbox')
);
$usesPerCouponFiled = $fieldset->addField('uses_per_coupon', 'text', array(
'name' => 'uses_per_coupon',
'label' => Mage::helper('salesrule')->__('Uses per Coupon'),
));
$fieldset->addField('uses_per_customer', 'text', array(
'name' => 'uses_per_customer',
'label' => Mage::helper('salesrule')->__('Uses per Customer'),
));
$dateFormatIso = Mage::app()->getLocale()->getDateFormat(Mage_Core_Model_Locale::FORMAT_TYPE_SHORT);
$fieldset->addField('from_date', 'date', array(
'name' => 'from_date',
'label' => Mage::helper('salesrule')->__('From Date'),
'title' => Mage::helper('salesrule')->__('From Date'),
'image' => $this->getSkinUrl('images/grid-cal.gif'),
'input_format' => Varien_Date::DATE_INTERNAL_FORMAT,
'format' => $dateFormatIso
));
$fieldset->addField('to_date', 'date', array(
'name' => 'to_date',
'label' => Mage::helper('salesrule')->__('To Date'),
'title' => Mage::helper('salesrule')->__('To Date'),
'image' => $this->getSkinUrl('images/grid-cal.gif'),
'input_format' => Varien_Date::DATE_INTERNAL_FORMAT,
'format' => $dateFormatIso
));
$fieldset->addField('sort_order', 'text', array(
'name' => 'sort_order',
'label' => Mage::helper('salesrule')->__('Priority'),
));
$fieldset->addField('featured', 'select', array(
'label' => Mage::helper('salesrule')->__('Featured'),
'title' => Mage::helper('salesrule')->__('Featured'),
'name' => 'featured',
'options' => array(
'1' => Mage::helper('salesrule')->__('Yes'),
'0' => Mage::helper('salesrule')->__('No'),
),
));
$fieldset->addField('is_rss', 'select', array(
'label' => Mage::helper('salesrule')->__('Public In RSS Feed'),
'title' => Mage::helper('salesrule')->__('Public In RSS Feed'),
'name' => 'is_rss',
'options' => array(
'1' => Mage::helper('salesrule')->__('Yes'),
'0' => Mage::helper('salesrule')->__('No'),
),
));
if(!$model->getId()){
//set the default value for is_rss feed to yes for new promotion
$model->setIsRss(1);
}
$form->setValues($model->getData());
$autoGenerationCheckbox->setValue(1);
if ($model->isReadonly()) {
foreach ($fieldset->getElements() as $element) {
$element->setReadonly(true, true);
}
}
//$form->setUseContainer(true);
$this->setForm($form);
// field dependencies
$this->setChild('form_after', $this->getLayout()->createBlock('adminhtml/widget_form_element_dependence')
->addFieldMap($couponTypeFiled->getHtmlId(), $couponTypeFiled->getName())
->addFieldMap($couponCodeFiled->getHtmlId(), $couponCodeFiled->getName())
->addFieldMap($autoGenerationCheckbox->getHtmlId(), $autoGenerationCheckbox->getName())
->addFieldMap($usesPerCouponFiled->getHtmlId(), $usesPerCouponFiled->getName())
->addFieldDependence(
$couponCodeFiled->getName(),
$couponTypeFiled->getName(),
Mage_SalesRule_Model_Rule::COUPON_TYPE_SPECIFIC)
->addFieldDependence(
$autoGenerationCheckbox->getName(),
$couponTypeFiled->getName(),
Mage_SalesRule_Model_Rule::COUPON_TYPE_SPECIFIC)
->addFieldDependence(
$usesPerCouponFiled->getName(),
$couponTypeFiled->getName(),
Mage_SalesRule_Model_Rule::COUPON_TYPE_SPECIFIC)
);
Mage::dispatchEvent('adminhtml_promo_quote_edit_tab_main_prepare_form', array('form' => $form));
return parent::_prepareForm();
}
}
app/code/local/MB/Attributes/etc/config.xml
<?xml version="1.0"?>
<config>
<modules>
<MB_Attributes>
<version>0.1.1</version>
</MB_Attributes>
</modules>
<global>
<blocks>
<adminhtml>
<rewrite>
<promo_quote_edit_tab_main>MB_Attributes_Block_Adminhtml_Edit_Tab_Main</promo_quote_edit_tab_main>
</rewrite>
</adminhtml>
</blocks>
<resources>
<mbattributes_setup>
<setup>
<module>MB_Attributes</module>
</setup>
<connection>
<use>core_setup</use>
</connection>
</mbattributes_setup>
</resources>
</global>
</config>
app/code/local/MB/Attributes/sql/mbattributes_setup/mysql4-install-0.1.1.php
<?php
$installer = $this;
$installer->startSetup();
$installer->getConnection()
->addColumn($installer->getTable('salesrule'),
'featured',
array(
'type' => Varien_Db_Ddl_Table::TYPE_SMALLINT,
'length' => 6,
'nullable' => false,
'default' => 0,
'comment' => 'Is featured'
)
);
$installer->endSetup();
app/etc/modules/MB_Attributes.xml
<?xml version="1.0"?>
<config>
<modules>
<MB_Attributes>
<active>true</active>
<codePool>local</codePool>
</MB_Attributes>
</modules>
</config>
Additional info:
When I tried to remove some of the methods from MB_Attributes_Block_Adminhtml_Edit_Tab_Main I got
[Mon May 18 15:26:34.805303 2015] [:error] [pid 19354] [client 127.0.0.1:37117] PHP Fatal error: Class MB_Attributes_Block_Adminhtml_Edit_Tab_Main contains 4 abstract methods and must therefore be declared abstract or implement the remaining methods (Mage_Adminhtml_Block_Widget_Tab_Interface::getTabLabel, Mage_Adminhtml_Block_Widget_Tab_Interface::getTabTitle, Mage_Adminhtml_Block_Widget_Tab_Interface::canShowTab, ...) in /var/www/wa/app/code/local/MB/Attributes/Block/Adminhtml/Edit/Tab/Main.php on line 252, referer: http://wa-dev.com/index.php/admin/promo_quote/index/key/ee3695e7425bea8ad8bef471e3262e74ee161ff8c10f8132cea80280496abe15/
Best Answer
This is actually not that difficult.
Have a look at
Mage_SalesRule_Model_Rule_Condition_Combine::getNewChildSelectOptions
You will see it builds an array of conditions as such:
and then fires an event, passing along an object called as
'additional'
it expects back
$additional->getConditions()
so, if you observer that event, you can populate the additional object with your own array of conditions.
In your observer some code like this will do:
Now your rule option is cleanly injected into the list of available rules.
The next step is to go create the model it will use. As can be seen from the code above, you will need to create the class
What that would extend is really up to the functionality you intend to use. If for example you intend to use product attributes in the validation, you would extend
Mage_SalesRule_Model_Rule_Condition_Product
so you can inherit all the functionality surrounding product validation.In your class, these methods are the important ones. Try not to extend methods if you don't need to, it is best to try re-use core code, which results in a lot more stability of your module.
asHtml()
: This holds the options that will be displayed when your rule is selected.validate
: This is where you'd place your logic to determine if the rule is valid. In the end it would simply result in bool.If you'd like to build a rule that has sub-rules, you'd extend the _combined salesrule classes, as for example:
Mage_SalesRule_Model_Rule_Condition_Product_Found
Look at the core code in sales rules. It has all the examples you need. To really understand what is going on, I highly suggest you used a debugger (I use xdebug) with an ide/editor that supports line-breaks. (I use netbeans) This way you can put breakpoints in the salsrule classes and follow the code flow as the rules are built. Make sit a lot easier.
Hope this helps.