Tag: magento

Pass Magento 2 Certified Professional Developer Plus Exam

It’s been a long time, No new post publish because I was so busy with Magento 2 exams. I have passed 5 Magento 2 certifications. My latest certification was Magento 2 Certified Professional Developer Plus. Today I share my experience and how I prepared Magento 2 Certified Professional Developer Plus exam.

When I took the exam?
I took my Magento 2 Certified Professional Developer Plus exam on 31st December 2018.

How I start preparation?
Magento 2 Certified Professional Developer Plus exam related resource is not available so much. Also, this exam is so young. When Magento announce this exam, I start preparation. My Magento 2 Certified Professional Developer exam preparation help me a lot. I start digging the Magento 2 commerce feature. At this point, Magento 2 Certified Solution Specialist exam preparation helps me to Magento 2 commerce default functionality. I start practicing Staging, Segmentation, RMA, MessageQueue, Database Sharding, etc. feature. I digging how a feature works by coding.

Firstly I find out that area, which I am weak. Then I start that area. It was so much dedication because after full-time work, taking preparation is not easy. But I did that.

Who can take the exam?
Anyone who have 2 years working experience with Magento 2 commerce. Actually, you need hands-on experience with it. This exam is built on Magento 2 commerce only. So it is necessary to work with Magento 2 commerce and Magento 2 commerce knowledge.

How hard this exam compared to other exams, especially professional?
Well, I would say this is hard more than all exam. I see many great Magento developer fail their first attempt. You need so deep knowledge about Magento 2 commerce. So before taking exam you must revise all area (according to study guide) deeply.

How deep we need to study?
Well, it is sooo deep ๐Ÿ˜€ . For example: for a console command, you need to learn in detail. How you declare in di.xml which area you need to declare (global or frontend, or adminhtml) that, how you declare required/optional option, what is the common error and how to fix that, how to interact with commerce feature, etc. Same for all. It is must check how to interact with Magento 2 commerce which features that is common for community edition.

What is the passing score?

  • 60 multiple choice questions
  • 90 minutes to complete the exam
  • 62% or higher needed to pass

For more details check official site

Where can I find good resource?
Still devdocs is good resource that I have found. Also check every topic from study guide. Also follow my blog ๐Ÿ˜€ , I have a plan to discuss important topic one by one. Read use guide for default feature.

One important feature I have found for this exam is Security. This feature should include for Professional exam too. Security is so important when you build something for the merchant. So you must know how Magento 2 handle this stuff.

Feel free to reach me if you have any question regarding certification. I am active in Magento Slack, Magento StackExchange or through my blog.

Creating custom shipping method in magento

This tutorial is dedicated to Magento Certification. Let’s start.

NameSpace : MyPackage and Module: CustomShipping

Register the module

<!-- app/etc/modules/MyPackage_CustomShipping.xml -->
<?xml version="1.0"?>
<config>
    <modules>
        <MyPackage_CustomShipping>
            <active>true</active>
            <codePool>local</codePool>
            <depends>
                <Mage_Shipping />
            </depends>
        </MyPackage_CustomShipping>
    </modules>
</config>


Create the config

<!-- app/code/local/MyPackage/CustomShipping/etc/config.xml -->
<?xml version="1.0"?>
<config>
    <modules>
        <MyPackage_CustomShipping>
            <version>0.0.0.1</version>
        </MyPackage_CustomShipping>
    </modules>
    <global>
        <models>
            <customshipping>
                <class>MyPackage_CustomShipping_Model</class>
            </customshipping>
        </models>
    </global>
    <!-- Default configuration -->
    <default>
        <carriers>
            <customshipping>
                <active>0</active>
                <title>Custom Shipping</title>
                <name>Standard</name>
                <price>9</price>
                <!-- this model hold all logic of custom module -->
                <model>customshipping/carrier_customshipping</model>
                <sallowspecific>0</sallowspecific>
                <sort_order>0</sort_order>
            </customshipping>
        </carriers>
    </default>
</config>

Adapter model
To create our shipping carrier, we need to extend Mage_Shipping_Model_Carrier_Abstract, implement Mage_Shipping_Model_Carrier_Interface and add the required abstract methods.

The most important method is collectRates and getAllowedMethods. collectRates is the method that receives a shipping request, appends applicable shipping methods and returns a shipping result.

<?php
//app/code/local/MyPackage/CustomShipping/Model/Carrier/Customshipping.php
class MyPackage_CustomShipping_Model_Carrier_Customshipping
    extends Mage_Shipping_Model_Carrier_Abstract
    implements Mage_Shipping_Model_Carrier_Interface
{
    protected $_code = 'customshipping';

    public function collectRates(Mage_Shipping_Model_Rate_Request $request)
    {

        return Mage::getModel('shipping/rate_result');
    }

    public function getAllowedMethods()
    {
        return array('custom_shipping'=>$this->getConfigData('name'));
    }
}

This is the skeleton for a shipping method class, it has no meaning if it has no shipping method.

Now creating meaningful of this method, suppose we use configure price from admin. Default method “Standard” and price is “9”.

<?php
//app/code/local/MyPackage/CustomShipping/Model/Carrier/Customshipping.php
class MyPackage_CustomShipping_Model_Carrier_Customshipping
    extends Mage_Shipping_Model_Carrier_Abstract
    implements Mage_Shipping_Model_Carrier_Interface
{
    protected $_code = 'customshipping';

    public function collectRates(Mage_Shipping_Model_Rate_Request $request)
    {
        if (!$this->getConfigFlag('active')) {
            return false;
        }

        $result = Mage::getModel('shipping/rate_result');
        $method = Mage::getModel('shipping/rate_result_method');

        $method->setCarrier('customshipping');
        $method->setCarrierTitle($this->getConfigData('title'));

        $method->setMethod('custom_shipping');
        $method->setMethodTitle($this->getConfigData('name'));

        $method->setPrice($this->getConfigData('price'));
        $method->setCost($this->getConfigData('price'));

        $result->append($method);

        return $result;
    }

    public function getAllowedMethods()
    {
        return array('custom_shipping'=>$this->getConfigData('name'));
    }
}

System Configuration

<!-- app/code/local/MyPackage/CustomShipping/etc/system.xml -->
<?xml version="1.0"?>
<config>
    <sections>
        <carriers>
            <groups>
                <customshipping translate="label">
                    <label>Custom Configurable Shipping</label>
                    <frontend_type>text</frontend_type>
                    <sort_order>2</sort_order>
                    <show_in_default>1</show_in_default>
                    <show_in_website>1</show_in_website>
                    <show_in_store>1</show_in_store>
                    <fields>
                        <active translate="label">
                            <label>Enabled</label>
                            <frontend_type>select</frontend_type>
                            <source_model>adminhtml/system_config_source_yesno</source_model>
                            <sort_order>1</sort_order>
                            <show_in_default>1</show_in_default>
                            <show_in_website>1</show_in_website>
                            <show_in_store>0</show_in_store>
                        </active>
                        <name translate="label">
                            <label>Method Name</label>
                            <frontend_type>text</frontend_type>
                            <sort_order>3</sort_order>
                            <show_in_default>1</show_in_default>
                            <show_in_website>1</show_in_website>
                            <show_in_store>1</show_in_store>
                        </name>
                        <price translate="label">
                            <label>Fixed Price</label>
                            <frontend_type>text</frontend_type>
                            <validate>validate-number validate-zero-or-greater</validate>
                            <sort_order>5</sort_order>
                            <show_in_default>1</show_in_default>
                            <show_in_website>1</show_in_website>
                            <show_in_store>0</show_in_store>
                        </price>
                        <sort_order translate="label">
                            <label>Sort Order</label>
                            <frontend_type>text</frontend_type>
                            <sort_order>100</sort_order>
                            <show_in_default>1</show_in_default>
                            <show_in_website>1</show_in_website>
                            <show_in_store>0</show_in_store>
                        </sort_order>
                        <title translate="label">
                            <label>Title</label>
                            <frontend_type>text</frontend_type>
                            <sort_order>2</sort_order>
                            <show_in_default>1</show_in_default>
                            <show_in_website>1</show_in_website>
                            <show_in_store>1</show_in_store>
                        </title>
                    </fields>
                </customshipping>
            </groups>
        </carriers>
    </sections>
</config>

This is simple shipping method module creation.
N.B: Inside shipping method model class, you should take care of following condition

1. $item->getHasChildren() && $item->isShipSeparately()
2. $item->getProduct()->isVirtual() == true
3. $item->getProduct()->isVirtual() || $item->getParentItem()
4. $item->getFreeShipping() == true

Happy Coding!

Add captcha to contact form in magento

If you need to add captcha in contacts page, you need to add this. So lets start how to add captcha in contacts page.
NameSpace : MyPackage and Module: MyModule

Module configuration

<!-- app/etc/modules/MyPackage_MyModule.xml -->
<config>
    <modules>
        <MyPackage_MyModule>
            <active>true</active>
            <codePool>local</codePool>
        </MyPackage_MyModule>
    </modules>
</config>

Create config file for this module

<!-- app/code/local/MyPackage/MyModule/etc/config.xml -->
<?xml version="1.0"?>
<config>
    <modules>
        <MyPackage_MyModule>
            <version>0.0.0.1</version>
        </MyPackage_MyModule>
    </modules>
    <global>
        <models>
            <mymodule>
                <class>MyPackage_MyModule_Model</class>
            </mymodule>
        </models>
        <events>
            <controller_action_predispatch_contacts_index_post>
                <observers>
                    <mymodule>
                        <class>mymodule/observer</class>
                        <method>checkContacts</method>
                    </mymodule>
                </observers>
            </controller_action_predispatch_contacts_index_post>
        </events>
    </global>
    <default>
        <captcha>
            <frontend>
                <areas>
                    <contacts>
                        <label>Contacts Page</label>
                    </contacts>
                </areas>
            </frontend>
        </captcha>
        <customer>
            <captcha>
                <always_for>
                    <contacts>1</contacts>
                </always_for>
            </captcha>
        </customer>
    </default>
</config>

Create a observer

<?php
// app/code/local/MyPackage/MyModule/Model/Observer.php
class MyPackage_MyModule_Model_Observer
{
    public function checkContacts($observer){
        $formId = 'contacts';
        $captchaModel = Mage::helper('captcha')->getCaptcha($formId);
        if ($captchaModel->isRequired()) {
            $controller = $observer->getControllerAction();
            $word = $this->_getCaptchaString($controller->getRequest(), $formId);
            if (!$captchaModel->isCorrect($word)) {
                Mage::getSingleton('customer/session')->addError(Mage::helper('captcha')->__('Incorrect CAPTCHA.'));
                $controller->setFlag('', Mage_Core_Controller_Varien_Action::FLAG_NO_DISPATCH, true);
                $url =  Mage::getUrl('contacts');
                $controller->getResponse()->setRedirect($url);
            }
        }
        return $this;
    }
    /**
     * Get Captcha String
     *
     * @param Varien_Object $request
     * @param string $formId
     * @return string
     */
    protected function _getCaptchaString($request, $formId)
    {
        $captchaParams = $request->getPost(Mage_Captcha_Helper_Data::INPUT_NAME_FIELD_VALUE);
        return $captchaParams[$formId];
    }
}

Create a local.xml to your active theme inside layout folder

<?xml version="1.0"?>
<layout version="0.1.0">
    <contacts_index_index>
        <reference name="contactForm">
            <action method="setTemplate"><template>mymodule/contacts/form.phtml</template></action>
            <block type="core/text_list" name="form.additional.info">
                <block type="captcha/captcha" name="captcha">
                    <reference name="head">
                        <action method="addJs"><file>mage/captcha.js</file></action>
                    </reference>
                    <action method="setFormId"><formId>contacts</formId></action>
                    <action method="setImgWidth"><width>230</width></action>
                    <action method="setImgHeight"><width>50</width></action>
                </block>
            </block>
        </reference>
    </contacts_index_index>
</layout>

Now copy “contacts/form.phtml” to “mymodule/contacts/form.phtml”, add

 <?php echo $this->getChildHtml('form.additional.info'); ?>

to your requirement. example…

.....
<li class="wide">
                <label for="comment" class="required"><em>*</em><?php echo Mage::helper('contacts')->__('Comment') ?></label>
                <div class="input-box">
                    <textarea name="comment" id="comment" title="<?php echo Mage::helper('contacts')->__('Comment') ?>" class="required-entry input-text" cols="5" rows="3"></textarea>
                </div>
            </li>
            <?php echo $this->getChildHtml('form.additional.info'); ?>
        </ul>
....

Clear magento cache.

Now Go to System -> Configuration -> Customer Configuration -> Captcha. Select Contact Page and Save.

Happy Coding!

Keep product in the wishlist after adding to cart in magento

In Magento, after adding product from wishlist, they are completely remove from wishlist. If you need to keep this to wishlist after adding product and if it is fully control from admin, Then you need to code something. Today I will discuss about this topic that is depend on configuration so any time you can change it from admin.

Suppose NameSpace : MyPackage and Module : MyModule

Now create a module configuration file,name is MyPackage_MyModule.xml and location is

app/etc/modules/MyPackage_MyModule.xml
<?xml version="1.0"?>
<config>
    <modules>
        <MyPackage_MyModule>
            <active>true</active>
            <codePool>local</codePool>
        </MyPackage_MyModule>
    </modules>
</config>

Create configuration file

app/code/local/MyPackage/MyModule/etc/config.xml
<?xml version="1.0"?>
<config>
    <modules>
        <MyPackage_MyModule>
            <version>0.0.0.1</version>
        </MyPackage_MyModule>
    </modules>
    <global>
        <helpers>
            <mymodule>
                <class>MyPackage_MyModule_Helper</class>
            </mymodule>
        </helpers>
    </global>
    <frontend>
        <routers>
            <wishlist>
                <args>
                    <modules>
                        <mypackage_mymodule before="Mage_Wishlist">MyPackage_MyModule</mypackage_mymodule>
                    </modules>
                </args>
            </wishlist>
        </routers>
    </frontend>
</config>

Create System Configuration file

app/code/local/MyPackage/MyModule/etc/system.xml
<config>
    <tabs>
        <mymodule translate="label" module="mymodule">
            <label>My Module</label>
            <sort_order>100</sort_order>
        </mymodule>
    </tabs>
    <sections>
        <mypackage_mymodule>
            <label>My Module Configuration</label>
            <sort_order>1</sort_order>
            <tab>mymodule</tab>
            <show_in_default>1</show_in_default>
            <show_in_website>1</show_in_website>
            <show_in_store>1</show_in_store>
            <groups>
                <configuration translate="label">
                    <label>Keep products in the wishlist after adding them to cart configuration</label>
                    <frontend_type>text</frontend_type>
                    <sort_order>2</sort_order>
                    <show_in_default>1</show_in_default>
                    <show_in_website>1</show_in_website>
                    <show_in_store>1</show_in_store>
                    <fields>
                        <keep_item translate="label">
                            <label>Keep item after adding them to cart</label>
                            <frontend_type>select</frontend_type>
                            <source_model>adminhtml/system_config_source_yesno</source_model>
                            <sort_order>2</sort_order>
                            <show_in_default>1</show_in_default>
                            <show_in_website>1</show_in_website>
                            <show_in_store>0</show_in_store>
                        </keep_item>
                    </fields>
                </configuration>
            </groups>
        </mypackage_mymodule>
    </sections>
</config>

Create ACL file

app/code/local/MyPackage/MyModule/etc/adminhtml.xml
<config>
    <acl>
        <resources>
            <admin>
                <children>
                    <system>
                        <children>
                            <config>
                                <children>
                                    <mypackage_mymodule translate="title" module="mymodule">
                                        <title>MyModule Section</title>
                                    </mypackage_mymodule>
                                </children>
                            </config>
                        </children>
                    </system>
                </children>
            </admin>
        </resources>
    </acl>
</config>

Create helper file

app/code/local/MyPackage/MyModule/Helper/Data.php
<?php
class MyPackage_MyModule_Helper_Data extends Mage_Core_Helper_Abstract
{

}

Now Create Controller file

app/code/local/MyPackage/MyModule/controllers/IndexController.php
<?php
require_once Mage::getModuleDir('controllers', 'Mage_Wishlist').DS.'IndexController.php';
class MyPackage_MyModule_IndexController extends Mage_Wishlist_IndexController
{
    /**
     * Add wishlist item to shopping cart and remove from wishlist
     *
     * If Product has required options - item removed from wishlist and redirect
     * to product view page with message about needed defined required options
     */
    public function cartAction()
    {
        if (!$this->_validateFormKey()) {
            return $this->_redirect('*/*');
        }
        $itemId = (int) $this->getRequest()->getParam('item');

        /* @var $item Mage_Wishlist_Model_Item */
        $item = Mage::getModel('wishlist/item')->load($itemId);
        if (!$item->getId()) {
            return $this->_redirect('*/*');
        }
        $wishlist = $this->_getWishlist($item->getWishlistId());
        if (!$wishlist) {
            return $this->_redirect('*/*');
        }

        // Set qty
        $qty = $this->getRequest()->getParam('qty');
        if (is_array($qty)) {
            if (isset($qty[$itemId])) {
                $qty = $qty[$itemId];
            } else {
                $qty = 1;
            }
        }
        $qty = $this->_processLocalizedQty($qty);
        if ($qty) {
            $item->setQty($qty);
        }

        /* @var $session Mage_Wishlist_Model_Session */
        $session    = Mage::getSingleton('wishlist/session');
        $cart       = Mage::getSingleton('checkout/cart');

        $redirectUrl = Mage::getUrl('*/*');

        try {
            $options = Mage::getModel('wishlist/item_option')->getCollection()
                    ->addItemFilter(array($itemId));
            $item->setOptions($options->getOptionsByItem($itemId));

            $buyRequest = Mage::helper('catalog/product')->addParamsToBuyRequest(
                $this->getRequest()->getParams(),
                array('current_config' => $item->getBuyRequest())
            );

            $item->mergeBuyRequest($buyRequest);
            $keepItem = Mage::getStoreConfig('mypackage_mymodule/configuration/keep_item');
            $keepItem = $keepItem?false:true;
            if ($item->addToCart($cart, $keepItem)) {
                $cart->save()->getQuote()->collectTotals();
            }

            $wishlist->save();
            Mage::helper('wishlist')->calculate();

            if (Mage::helper('checkout/cart')->getShouldRedirectToCart()) {
                $redirectUrl = Mage::helper('checkout/cart')->getCartUrl();
            } else if ($this->_getRefererUrl()) {
                $redirectUrl = $this->_getRefererUrl();
            }
            Mage::helper('wishlist')->calculate();
        } catch (Mage_Core_Exception $e) {
            if ($e->getCode() == Mage_Wishlist_Model_Item::EXCEPTION_CODE_NOT_SALABLE) {
                $session->addError($this->__('This product(s) is currently out of stock'));
            } else if ($e->getCode() == Mage_Wishlist_Model_Item::EXCEPTION_CODE_HAS_REQUIRED_OPTIONS) {
                Mage::getSingleton('catalog/session')->addNotice($e->getMessage());
                $redirectUrl = Mage::getUrl('*/*/configure/', array('id' => $item->getId()));
            } else {
                Mage::getSingleton('catalog/session')->addNotice($e->getMessage());
                $redirectUrl = Mage::getUrl('*/*/configure/', array('id' => $item->getId()));
            }
        } catch (Exception $e) {
            Mage::logException($e);
            $session->addException($e, $this->__('Cannot add item to shopping cart'));
        }

        Mage::helper('wishlist')->calculate();

        return $this->_redirectUrl($redirectUrl);
    }
}

Clear cache and configure from System -> Configuration -> My Module Configuration

Happy Coding!

How to create setup resources for magento 2

In magento 2 series if you miss previous article read from here. Today we discuss about magento setup resource. we ran our CREATE TABLE statements directly against the database or we can follow magento setup rule.

Creating Installer Script

app/code/SR/Weblog/Setup/InstallSchema.php
<?php

namespace SR\Weblog\Setup;

use Magento\Framework\Setup\InstallSchemaInterface;
use Magento\Framework\Setup\ModuleContextInterface;
use Magento\Framework\Setup\SchemaSetupInterface;

/**
 * @codeCoverageIgnore
 */
class InstallSchema implements InstallSchemaInterface
{
    /**
     * {@inheritdoc}
     * @SuppressWarnings(PHPMD.ExcessiveMethodLength)
     */
    public function install(SchemaSetupInterface $setup, ModuleContextInterface $context)
    {
        $installer = $setup;

        $installer->startSetup();

        $table = $installer->getConnection()->newTable(
            $installer->getTable('blog_posts')
        )->addColumn(
            'blogpost_id',
            \Magento\Framework\DB\Ddl\Table::TYPE_INTEGER,
            null,
            array('identity' => true, 'nullable' => false, 'primary' => true),
            'Blog Post ID'
        )->addColumn(
            'title',
            \Magento\Framework\DB\Ddl\Table::TYPE_TEXT,
            255,
            array('nullable' => false),
            'Title'
        )->addColumn(
            'content',
            \Magento\Framework\DB\Ddl\Table::TYPE_TEXT,
            '2M',
            array('nullable' => false),
            'Post'
        )->addColumn(
            'publish_date',
            \Magento\Framework\DB\Ddl\Table::TYPE_DATE,
            null,
            array(),
            'Publish Date'
        )->addColumn(
            'is_active',
            \Magento\Framework\DB\Ddl\Table::TYPE_SMALLINT,
            null,
            array(),
            'Active Status'
        )->addColumn(
            'created_at',
            \Magento\Framework\DB\Ddl\Table::TYPE_TIMESTAMP,
            null,
            array(),
            'Creation Time'
        )->addColumn(
            'update_time',
            \Magento\Framework\DB\Ddl\Table::TYPE_TIMESTAMP,
            null,
            array(),
            'Modification Time'
        )->setComment(
            'Weblog Table'
        );
        $installer->getConnection()->createTable($table);

        $installer->endSetup();

    }
}

Run through command line “php bin/magento setup:upgrade” from the Magento root directory.

-> Check your database “blog_posts” table will be created. Check setup_module table a new row will be created which code is “weblog_setup’

Get a copy of this module? Download from here

Magento Certified Developer – Rendering (part 1)

From today I will start a series of Magento Certified Developer exam preparation, which completely follow the Certification Study Guide. So stay with me ๐Ÿ™‚ . I randomly pick a topic of Magento Rendering process, This is interesting to me. So start now.

Topic : 3- Rendering
From this topic approximately 7% of question available in exam.

Themes in Magento
Themes inside of a design package contain the actual files that determine the visual output and frontend functionality of your store. Magento themes contain templating information (layout files, template files, theme-specific translation files) and skinning information (CSS files, images, and theme-specific JavaScript files). A theme can belongs to only one design package. Themes are locate

app/design/area/package/theme_name

area: frontend/adminhtml/install
package: base(by default)/default(by default)/custom_package
theme_name: default/ custom_theme

So when you creating a new theme,it’s really good to create new package with new theme. Don’t change base/core file.. It’s really horrible for future update.

Register Custom Theme
Two ways you can register custom theme. That is
1. If you want your theme to be used โ€˜alwaysโ€™ as your store theme, you may tell Magento to use it from System => Configuration => Design
2. Another way to register theme form going System => Design, available this theme for all time or for certain period of time.

What is the difference between package and theme
Package : A design package is a collection of related themes.
Theme : A theme is a collection of template,layout file and js,css,images that’s create the visual experience of your store.

Theme must have one package and package has many theme with default one.

What happens if the requested file is missed in your theme/package
If a particular file is missed in a theme, there is are some fallback themes and packages where Magento will try to find it.
1. First location in the fallback chain is the default theme of the current package.
2. Second location is the base package default theme which exists in a stock Magento install.

You can also define a third point in the middle of these by defining a custom default theme (with a different name than โ€˜defaultโ€™) in your admin panel.

This enough for today. Next article I will discuss vastly. Good luck and Thank you!

Magento bundle products items – selection_id cannot be null?

In magento bundle product, when you save bundle item in website scope. It’s throw an error that is “SQLSTATE[23000]: Integrity constraint violation: 1048 Column ‘selection_id’ cannot be null”. To generate this error go to System -> Configuration -> Catalog -> Price . Select “Catalog Price Scope” to “Website”. Then Create a bundle product, Yes you can see this error. Any Idea? What’s wrong here? I think this is known issue from magento, this type of error comes from all version of magento.

How comes?
In magento, bundle items are save “catalog_product_bundle_selection” table. When you save this item as a scope of website label, then this will be related to another table called “catalog_product_bundle_selection_price”. Where selection_id column is a foreign key of “catalog_product_bundle_selection” table selection_id column. When you save this item as website label, it’s try to save “catalog_product_bundle_selection_price” first, That’s why this error comes.

What’s Solution
Solution is simple ๐Ÿ™‚ . Overwrite Mage_Bundle_Model_Selection model class and codes are look like

class Package_MyModule_Model_Selection extends Mage_Bundle_Model_Selection
{
    /**
     * Processing object before save data
     *
     * @return Mage_Bundle_Model_Selection
     */
    protected function _beforeSave()
    {
        // No code please
    }

    /**
     * Processing object after save data
     *
     * @return Mage_Bundle_Model_Selection
     */
    protected function _afterSave()
    {
        $storeId = Mage::registry('product')->getStoreId();
        if (!Mage::helper('catalog')->isPriceGlobal() && $storeId) {
            $this->setWebsiteId(Mage::app()->getStore($storeId)->getWebsiteId());

            $this->getResource()->saveSelectionPrice($this);

            if (!$this->getDefaultPriceScope()) {
                $this->unsSelectionPriceValue();
                $this->unsSelectionPriceType();
            }
        }
        parent::_afterSave();
    }
}

Happy Coding ๐Ÿ™‚