среда, 25 марта 2015 г.

Magento Enterprise: Reward Points

В рамках подготовки к сертификации Magento Developer Plus хочу проанализировать работу модуля Enterprise_Reward. Вопросы, на которые я хочу опубликовать ответы взяты из документа по подготовке к сертификации:

○ Describe how to customize, extend, and troubleshoot the Enterprise Edition reward point system:
■ How do the features offered by the reward point system hook into other Magento modules?
■ Under which conditions may reward points be assigned?
■ Which steps are required to add new custom options to assign reward points?

В рамках первого вопроса предлагаю рассмотреть основные фичи модуля, и с какими модулями данный Enterprise_Rewards взаимодействует.

Прежде чем начать хочу сказать пару слов о том, как активировать модуль, чтобы с ним начать работать. Наиболее распространенная ошибка, с которой сталкиваются пользователи – это неверная настрока Reward Exchange Rates. Необходимо помнить что для работы модуля нужно установить два курса: «Points to Currency» и «Currency to Points». В противном случае модуль работать не будет и никаких наводящих подсказок не будет, что что-то не так.

Суть модуля заключается в том, что после определенных действий кастомера ему начисляются Reward Points, которые он может в последствии использовать для оплаты товаров в магазине, по курсу, остановленному в Reward Exchange Rates.

Итак, с какими модулями взаимодействует Enterprise_Reward. Для этого посмотрим в etc/config.xml
- Sales. В ордер добавляются поля base/reward_currency_amount_invoiced, base/reward_currency_amount_refunded, reward_points_balance_to_refund. Обновление баланса после placeOrder. Добавлен псевдо-метод оплаты на чекауте
- Quote. Добавляется в totals в квоте, инвойсе и creditMemo
- Newsletter. В случае подписки на новости добавляются поинты
- Paypal. Добавление reward points при оплате
- Customer. В админке и на фронте новый атрибут со значением reward points
, а также целый таб с настройками и историей изменения баланса.
Далее, в рамках второго вопроса, рассмотрим по каким условиям кастомерам могут начисляться reward points. По сути все эти условия находятся в system / configuration / reward points и хранятся в etc/system.xml.
Там мы обнаруживаем, что баллы могут начисляться по следующим событиям:
1. Place order (each or only first e.g.)
2. Registration
3. Newsletter subscribtion
4. Customer invitation (with limit)
5. Review (with limit)
6. Tag applying

Также можно посмотреть список ивентов, по которым начисляются поинты. Смотрим в etc/config.xml в ветке events.

Ну и в рамках третьего вопроса попробуем создать свое условие для начисления кастомеру Reward points. 

Поставим себе следующую задачу:
Необходимо начислять кастомеру Reward Points каждый раз, когда тот принимает участие в голосовании (модуль Mage_Poll)

Создаем xml для включения выключения модуля:
<?xml version="1.0"?><config>
    <modules>
        <Company_Rewards>
            <active>true</active>
            <codePool>local</codePool>
            <depends>
                <Enterprise_Reward />
            </depends>
        </Company_Rewards>
    </modules>
</config>

Поскольку наш модуль напрямую зависит от Enterprise_Reward – добавим depends
И файл конфига модуля в
local/Company/Rewards/etc/config.xml
<?xml version="1.0"?><config>
    <modules>
        <company_rewards>
            <version>0.0.1</version>
        </company_rewards>
    </modules>
    <global>
        <models>
            <company_rewards>
                <class>Company_Rewards_Model</class>
            </company_rewards>
        </models>
    </global>
</config>

Следующим шагом создадим etc/system.xml в который поместим поле для system/configuration. Основную часть возьмем из имеющегося конфига в Enterprise/Reward/etc/system.xml (см. ниже)
<?xml version="1.0"?><config>
    <sections>
        <enterprise_reward translate="label" module="enterprise_reward">
            <label>Reward Points</label>
            <class>separator-top</class>
            <tab>customer</tab>
            <sort_order>300</sort_order>
            <show_in_default>1</show_in_default>
            <show_in_website>1</show_in_website>
            <show_in_store>1</show_in_store>
            <groups>
                <points translate="label" module="enterprise_reward">
                    <label>Actions for Acquiring Reward Points by Customers</label>
                    <frontend_type>text</frontend_type>
                    <sort_order>20</sort_order>
                    <show_in_default>1</show_in_default>
                    <show_in_website>1</show_in_website>
                    <show_in_store>0</show_in_store>
                    <fields>
                        <!-- Сюда поместим новое поле -->
                    </fields>
                </points>
            </groups>
        </enterprise_reward>
    </sections>
</config>

Далее добавим в тег <fields> наше поле:
<poll translate="label comment">
    <label>Take part in poll</label>
    <frontend_type>text</frontend_type>
    <sort_order>25</sort_order>
    <show_in_default>1</show_in_default>
    <show_in_website>1</show_in_website>
    <show_in_store>0</show_in_store>
</poll>

Чтобы не забыть потом, предлагаю сохранить какое-нибудь значение в этом поле. Пусть это будет 23.
Далее если обратить внимание на структуру файла Enterprise_Reward_Model_Reward можно увидеть, что здесь проходит инициализация имеющихся reward_actions и их инициализация:



class Enterprise_Reward_Model_Reward extends Mage_Core_Model_Abstract
{
    //...
    const REWARD_ACTION_ADMIN               = 0;
    const REWARD_ACTION_ORDER               = 1;
    const REWARD_ACTION_REGISTER            = 2;
    //...

    protected function _construct()
    {
        parent::_construct();
        $this->_init('enterprise_reward/reward');
        self::$_actionModelClasses = self::$_actionModelClasses + array(
                self::REWARD_ACTION_ADMIN               => 'enterprise_reward/action_admin',
                self::REWARD_ACTION_ORDER               => 'enterprise_reward/action_order',
                self::REWARD_ACTION_REGISTER            => 'enterprise_reward/action_register',
        //...
    }
}


По сути наша задача сводится к тому, чтобы добавить новую константу REWARD_ACTION_POLL и добавить в массив self::$_actionModelClasses ключ/значение для нашего экшена.
Может не совсем правильный подход делать реврайты, но в этом случае он будет вполне безобидный, на мой взгляд. Возможно есть и другие способы как сделать, но я долго не исследовал данный момент.
Итак делаем реврайт, дополняя etc/config.xml внутри тега <models>
<enterprise_reward>
    <rewrite>
        <reward>Company_Rewards_Model_Rewrite_Reward_Reward</reward>
    </rewrite>
</enterprise_reward>

Для своего файла я выбрал именно такое имя:
{Vendor}_{Module}_Model_Rewrite_{Original_module_name}_{Original_file_name_including_path}
Итак создаем собственно этот файл:
|Rewards
|-etc
|--config.xml
|--system.xml
|-Model
|--Rewrite
|---Reward
|----Reward.php

Далее добавляем необходимую константу и реврайтим метод _construct()
class Company_Rewards_Model_Rewrite_Reward_Reward extends Enterprise_Reward_Model_Reward
{
    const REWARD_ACTION_POLL                 = 13;
   
    protected function _construct()
    {
        parent::_construct();
        self::$_actionModelClasses = self::$_actionModelClasses + array(
            self::REWARD_ACTION_POLL                 => 'company_rewards/action_poll',
        );
    }
}

Обратите внимание, что имя Action Model мы выбрали company_rewards, собственно её нужно будет и создать.
Одним из обязательных условий для создания этой модели является то, что мы должны пронаследовать один абстрактный метод.
abstract class Enterprise_Reward_Model_Action_Abstract extends Varien_Object
{
/**
 * Return action message for history log
 *
 * @param array $args Additional history data
 * @return string
 */abstract public function getHistoryMessage($args = array());

Создаем свою модель, и как видно выше ('company_rewards/action_poll') название её будет Company/Rewards/Model/Action/Poll.php
class Company_Rewards_Model_Action_Poll extends Enterprise_Reward_Model_Action_Abstract
{
    public function getPoints($websiteId)
    {
        return (int)Mage::helper('enterprise_reward')->getPointsConfig('poll', $websiteId);
    }

    public function getHistoryMessage($args = array())
    {
        return Mage::helper('enterprise_reward')->__('Took part in poll');
    }
}

Воспользуемся тут хелпером 'enterprise_reward', либо если хотите, можете создать свой, пронаследовавшись от него.
И последним штрихом будет собственно начисление этих Reward Points по событию. Поскольку мы выбрали «по результатам голосования в (Mage_Poll)», мы выбираем следующий ивент poll_vote_add и вешаем на него обсервер в etc/config.xml (после либо до <default>):

<frontend>
    <events>
        <poll_vote_add>
            <observers>
                <company_rewards_poll>
                    <type>singleton</type>
                    <class>company_rewards/observer</class>
                    <method>addPointsOnPollSubmit</method>
                </company_rewards_poll>
            </observers>
        </poll_vote_add>
    </events>
</frontend>

Создаем наш обсервер и финальная структура каталогов будет выглядеть так:
|Rewards
|-etc
|--config.xml
|--system.xml
|-Model
|--Actions
|---Poll.php
|--Rewrite
|---Reward
|----Reward.php
|--Observer.php

Код обсервера:
class Company_Rewards_Model_Observer
{
    public function addPointsOnPollSubmit($observer)
    {
        $poll = $observer->getPoll();
        $storeId = Mage::app()->getStore()->getStoreId();
        $websiteId = Mage::app()->getStore()->getWebsiteId();
        if (!Mage::helper('enterprise_reward')->isEnabledOnFront($websiteId)) {
            return $this;
        }
        $vote = $observer->getVote();
        if ($vote->getCustomerId()) {
            $reward = Mage::getModel('enterprise_reward/reward')
                ->setCustomerId($vote->getCustomerId())
                ->setStore($storeId)
                ->setAction(Company_Rewards_Model_Rewrite_Reward_Reward::REWARD_ACTION_POLL)
                ->setActionEntity($poll)
                ->updateRewardPoints();
        }
        return $this;
    }
}

Берем для аналогии из обсервера Enterprise_Reward_Model_Observer для любого из ивентов и подпиливаем под себя.

2 комментария:

  1. Thank you a lot. Google Translator helps me a bit, but this article is very good.

    ОтветитьУдалить
  2. If you have some questions - I can answer on them or translate this article partially

    ОтветитьУдалить