Question

I created a Plugin for sending emails when the owner of the shop changes the customer's group in backend. I still need to add the group (discount) in the email. The problem is that when I access to a customer and change it's group it sends me around 16 emails, the function that sends the email is afterSetGroupId(); so i don't understand why it sends me too many emails.

Here is my code: Plugin SendDiscount.php

public function afterSetGroupId(\Magento\Customer\Api\Data\CustomerInterface $customer, $result)
    {
        //$groupId = $customer->getGroupId();
        //$this->sendYourCustomEmail($customer);


        /* Receiver Detail the person who is going to receive the info that user logged in*/
        $receiverInfo = [
            'name' => 'Admin',
            'email' => 'myemail@hotmail.com'
        ];

        $store = $this->storeManager->getStore();

       $templateParams = ['store' => $store, 'administrator_name' => $receiverInfo['name']];

        $transport = $this->transportBuilder->setTemplateIdentifier(
            'phpcuong_transactional_email_customer_group'
        )->setTemplateOptions(
            ['area' => 'frontend', 'store' => $store->getId()]
        )->addTo(
            $receiverInfo['email'], $receiverInfo['name']
        )->setTemplateVars(
            $templateParams
        )->setFrom(
            'general'
        )->getTransport();

        try {
            // Send an email
            $transport->sendMessage();
        } catch (\Exception $e) {
            // Write a log message whenever get errors
            $this->logger->critical($e->getMessage());
        }


    }

This is my di.xml located under etc/adminhtml

<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../../../lib/internal/Magento/Framework/ObjectManager/etc/config.xsd">
    <type name="\Magento\Customer\Api\Data\CustomerInterface">
        <plugin name="PHPCuong_CustomerGroupEmail_Plugin" type="PHPCuong\CustomerGroupEmail\Plugin\SendDiscount" sortOrder="10" disabled="false"  />
    </type>
</config>
Was it helpful?

Solution

To send an email when customer group changes, I will recommend using events instead of using plugin.

Why not recommending plugin for this kind of task ? Because we use plugin when we need to modify input/output of any function and we use event observer when we have to do some external operation on the data like logging the data into log files, sending the data to third party servers, etc.

I will share event/observer code here which you can use to send email when customer group changes.

etc/adminhtml/events.xml

<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Event/etc/events.xsd">
    <event name="customer_save_after_data_object">
        <observer name="amitshree_customer_save_after_data_object" instance="Amitshree\CustomerGroup\Observer\GroupChanged" />
    </event>
</config>

etc/email_templates.xml

<?xml version="1.0"?>

<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:module:Magento_Email:etc/email_templates.xsd">
    <template id="amitshree_customer_group_changed" label="Amitshree - Customer Group Change" file="group_changed.html" type="html" module="Amitshree_CustomerGroup" area="frontend"/>
</config>

Amitshree/CustomerGroup/Observer/GroupChanged.php

<?php

namespace Amitshree\CustomerGroup\Observer;

use Magento\Framework\Event\Observer as EventObserver;
use Magento\Framework\Event\ObserverInterface;
use Magento\Framework\Mail\Template\TransportBuilder;
use Magento\Framework\App\Config\ScopeConfigInterface;
use Magento\Store\Model\ScopeInterface;
use Magento\Customer\Api\GroupRepositoryInterface;

class GroupChanged implements ObserverInterface
{


    public function __construct(
        TransportBuilder $transportBuilder,
        ScopeConfigInterface $scopeConfig,
        GroupRepositoryInterface $groupRepository
    ){
        $this->transportBuilder = $transportBuilder;
        $this->scopeConfig = $scopeConfig;
        $this->groupRepository = $groupRepository;
    }

    /**
     * @param \Magento\Framework\Event\Observer $observer
     * @return void
     */
    public function execute(EventObserver $observer)
    {

        $customer = $observer->getCustomerDataObject();
        $customerOld = $observer->getOrigCustomerDataObject();
        $newGroupId = $customer->getGroupId();
        $oldGroupId = $customerOld->getGroupId();
        if ($newGroupId !== $oldGroupId) {
            $newGroup = $this->groupRepository->getById($newGroupId);
            $newGroupName = $newGroup->getCode();
            $oldGroup = $this->groupRepository->getById($oldGroupId);
            $oldGroupName = $oldGroup->getCode();
            $firstName = $customer->getFirstName();
            $customerEmail = $customer->getEmail();
            $groupVariables = [
                'first_name' => $firstName,
                'new_group' => $newGroupName,
                'old_group' => $oldGroupName
            ];


            $email = $this->scopeConfig->getValue('trans_email/ident_general/email',ScopeInterface::SCOPE_STORE);
            $name  = $this->scopeConfig->getValue('trans_email/ident_general/name',ScopeInterface::SCOPE_STORE);

            $postObject = new \Magento\Framework\DataObject();
            $postObject->setData($groupVariables);

            $transport = $this->transportBuilder
                ->setTemplateIdentifier('amitshree_customer_group_changed')
                ->setTemplateOptions(['area' => \Magento\Framework\App\Area::AREA_ADMINHTML, 'store' => \Magento\Store\Model\Store::DEFAULT_STORE_ID])
                ->setTemplateVars(['data' => $postObject])
                ->setFrom(['name' => $name,'email' => $email])
                ->addTo([$customerEmail])
                ->getTransport();

            $transport->sendMessage();
        }

        return $this;
    }
}

view/adminhtml/email/group_changed.html

<!--@subject {{trans "Customer group changed"}} @-->

Hello {{var data.first_name|raw}}, your customer group has been changed for {{store url=""}} from {{var data.old_group|raw}} to {{var data.new_group|raw}}.

OTHER TIPS

There are several places in your codebase call the setGroupId method and it's causing this issue. I would suggest using a different plugin to only send the email before saving the customer. Something like this:

di.xml

<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd">
    <type name="Magento\Customer\Model\ResourceModel\Customer">
        <plugin name="send_email_when_changing_group_id" type="PHPCuong\CustomerGroupEmail\Plugin\SendDiscount" />
    </type>
</config>

SendDiscount.php

    public function beforeSave(\Magento\Customer\Model\ResourceModel\Customer $subject, \Magento\Customer\Model\Customer $customer)
    {
        $oldGroupId = $customer->getOrigData('group_id');
        $newGroupId = $customer->getGroupId();

        if ($oldGroupId == $newGroupId) return [$customer];

        /* Receiver Detail the person who is going to receive the info that user logged in*/
        $receiverInfo = [
            'name' => 'Admin',
            'email' => 'myemail@hotmail.com'
        ];

        $store = $this->storeManager->getStore();

        $templateParams = ['store' => $store, 'administrator_name' => $receiverInfo['name']];

        $transport = $this->transportBuilder->setTemplateIdentifier(
            'phpcuong_transactional_email_customer_group'
        )->setTemplateOptions(
            ['area' => 'frontend', 'store' => $store->getId()]
        )->addTo(
            $receiverInfo['email'], $receiverInfo['name']
        )->setTemplateVars(
            $templateParams
        )->setFrom(
            'general'
        )->getTransport();

        try {
            // Send an email
            $transport->sendMessage();
        } catch (\Exception $e) {
            // Write a log message whenever get errors
            $this->logger->critical($e->getMessage());
        }

        return [$customer];
    }

Note: This is just a sample code and I haven't tested it yet.

The main reason of your problem is the setGroupId method, its purpose is to set group ID for customer model, not to save the group ID. That's why it's wrong to put your plugin after setGroupId, the method could be called 2398473 times while the group ID is not actually saved.

To resolve this, fire your code after customer save (which saved the data into db), not after set group ID (which only set data to model), then check if customer group ID is changed.

Since Magento's getOrigData() is broken at this moment (https://github.com/magento/magento2/issues/8788), you can do a workaround by using aroundSave:

app/code/Vendor/Module/etc/di.xml

<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd">
    <type name="Magento\Customer\Model\Customer">
        <plugin name="PHPCuong_CustomerGroupEmail_Plugin" type="Vendor\Module\Plugin\SendDiscount" sortOrder="10" disabled="false"  />
    </type>
</config>

app/code/Vendor/Module/Plugin/SendDiscount.php

namespace Vendor\Module\Plugin;

use Magento\Customer\Api\CustomerRepositoryInterface;
use Magento\Customer\Model\Customer;

class SendDiscount
{
    public function __construct(
        CustomerRepositoryInterface $customerRepository
    ) {
        $this->customerRepository = $customerRepository;
    }

    public function aroundSave(
        Customer $subject,
        \Closure $proceed
    ) {
        $oldCustomer = $this->customerRepository->getById($subject->getId());
        $result = $proceed();

        //Check if customer group is changed
        if ($oldCustomer->getGroupId() != $subject->getGroupId()) {
            //do your logic
        }

        return $result;
    }
}
Licensed under: CC-BY-SA with attribution
Not affiliated with magento.stackexchange
scroll top