Email Notification Alerts for Product Delete in a Magento 2 Store

Email Notification Alerts for Product Delete in a Magento 2 Store
COMMENTS ()
Tweet

 

 

 

The e-commerce businesses sometimes get significant losses in their sale due to site’s misadministration, especially in cases, if more than one administrator is responsible for site administering. E.g.: If any of the admin user deletes the product intentionally or unintentionally and other admin user(s) remained unaware of his delete activity.

In production environment, unexpected deletion of any item(s) means losing of revenue and ultimately losing of site customer(s).

In production environment there must be such mechanism that triggers notifications or log all the events of product deletion like who delete the item(s)? at what time this activity was happened? What exactly item(s) were deleted?

Magento 2 (leading e-commerce system) logs such information of admin user(s) but do not trigger notification in case of any item deletion.

In this blog, we will develop module in Magento 2 system to send alerts over email to concerned addresses in case, any item(s) get deleted.

The screen-shots are attached, for over viewing module structure and functionality. We will cover each development part of the screen-shot.

 

SCREENSHOTS

 





 

MODULE STRUCTURE & IMPLEMENTATION

Step-1:

Create new module at following path:

app/code/Folio3/ProductDeleteNotificationsAlerts

 

Step-2:

Create required module files and folders:

app/code/Folio3/ProductDeleteNotificationsAlerts/registration.php

 

\Magento\Framework\Component\ComponentRegistrar::register(

\Magento\Framework\Component\ComponentRegistrar::MODULE,

‘Folio3_ProductDeleteNotificationsAlerts’,

__DIR__

);

app/code/Folio3/ProductDeleteNotificationsAlerts/etc/module.xml

<config xmlns:xsi=”http://www.w3.org/2001/XMLSchema-instance” xsi:noNamespaceSchemaLocation=”urn:magento:framework:Module/etc/module.xsd”>

<module name=”Folio3_ProductDeleteNotificationsAlerts” setup_version=”1.0.0″>

</module>

</config>

 

Step-3:

Create system.xml, responsible for showing text field under admin→stores→configuration→folio3→…CC Email(s).

We can add multiple comma separated emails addresses, to whom alert email will be sent.

app/code/Folio3/ProductDeleteNotificationsAlerts/etc/adminhtml/system.xml

 

<config xmlns:xsi=”http://www.w3.org/2001/XMLSchema-instance” xsi:noNamespaceSchemaLocation=”urn:magento:module:Magento_Config:etc/system_file.xsd”>

<system>

<tab id=”folio3″ translate=”label” sortOrder=”200″>

<label>Folio3</label>

</tab>

<section id=”alert” translate=”label” sortOrder=”150″ showInDefault=”1″ showInWebsite=”1″ showInStore=”1″>

<class>separator-top</class>

<label>Product Delete</label>

<tab>folio3</tab>

<resource>Folio_General::config_general</resource>

<group id=”delete” translate=”label” type=”text” sortOrder=”1″ showInDefault=”1″ showInWebsite=”1″ showInStore=”0″>

<label>Alert Product Delete</label>

<field id=”enable” translate=”label” type=”select” sortOrder=”1″ showInDefault=”1″ showInWebsite=”1″ showInStore=”0″>

<label>Is Enabled?</label>

<source_model>Magento\Config\Model\Config\Source\Yesno</source_model>

</field>

<field id=”cc” translate=”label” type=”textarea” sortOrder=”2″ showInDefault=”1″ showInWebsite=”1″ showInStore=”0″>

<label>CC Email(s)</label>

<comment><![CDATA[Email must be comma separated.]]></comment>

</field>

</group>

</section>

</system>

</config>

 

Step-4:

Define an email template code in file:

app/code/Folio3/ProductDeleteNotificationsAlerts/etc/email_templates.xml

 

<config xmlns:xsi=”http://www.w3.org/2001/XMLSchema-instance” xsi:noNamespaceSchemaLocation=”urn:magento:module:Magento_Email:etc/email_templates.xsd”>

<template id=”folio_alert_product_delete” label=”Alert Product Delete” file=”product_delete.html” type=”html” module=”Folio3_ProductDeleteNotificationsAlerts” area=”adminhtml”/>

</config>

 

Step-5:

Create html template file (defined in above step) with following content:

app/code/Folio3/ProductDeleteNotificationsAlerts/view/frontend/email/product_delete.html

 

<!–@subject {{trans “Your %store_name” store_name=$store.getFrontendName()}} | {{trans “Notification Product Delete”}} @–>

<!–@vars {

“var data.admin_user”:”Admin User”,

“var data.sku”:”Product Sku”,

“var data.date_time”:”Date / Time”,

“var data.time_zone”:”Time-Zone”,

} @–>

{{template config_path=”design/email/header_template”}}

<table>

<tr>

<td>

<p>Following product(s) deleted by <strong>”{{trans “%admin_user” admin_user=$data.getAdminUser()}}”</strong>.</p>

</td>

</tr>

<tr>

<td>

<p>Product Sku(s): <strong>{{trans “%sku” sku=$data.getSku()}}</strong></p>

<p>Date / Time: <strong>{{trans “%date_time” date_time=$data.getDateTime()}}</strong></p>

<p>Time-Zone: <strong>{{trans “%time_zone” time_zone=$data.getTimeZone()}}</strong></p>

</td>

</tr>

</table>

{{template config_path=”design/email/footer_template”}}

 

Step-6:

Create and define plugin information. Once item(s) gets deleted, it’s all information gets flushed. This plugin will keep deleted sku(s) information in session.

app/code/Folio3/ProductDeleteNotificationsAlerts/etc/di.xml

 

<config xmlns:xsi=”http://www.w3.org/2001/XMLSchema-instance” xsi:noNamespaceSchemaLocation=”../../../../../lib/internal/Magento/Framework/ObjectManager/etc/config.xsd”>

<type name=”Magento\Ui\Component\MassAction\Filter”>

<plugin name=”folio_alert_delete_product” type=”Folio3\ProductDeleteNotificationsAlerts\Plugin\Ui\Component\MassAction\FilterPlugin” disabled=”false” />

</type>

</config>

 

Step-7:

Create FilterPlugin file, defined in above step:

app/code/Folio3/ProductDeleteNotificationsAlerts/Plugin/Ui/Component/FilterPlugin.php

 

use Magento\Framework\Data\Collection\AbstractDb;

namespace Folio3\ProductDeleteNotificationsAlerts\Plugin\Ui\Component\MassAction;

class FilterPlugin

{

protected $coreRegistry;

/**

* @param \Magento\Framework\Registry $coreRegistry

*/

public function __construct(

\Magento\Framework\Registry $coreRegistry

) {

$this->coreRegistry = $coreRegistry;

}

/**

* @param Collection $collection

* @return $collection

*/

public function afterGetCollection(

\Magento\Ui\Component\MassAction\Filter $subject,

$result,

$collection

) {

$itemIdSku = array();

/*

save item(s) sku in session,

reason: once item get deleted, item complete data will get flushed

*/

if(count($result->toArray())) {

foreach($result->toArray() as $eachItem){

if(isset($eachItem[‘sku’])) {

$itemIdSku[$eachItem[‘entity_id’]] = $eachItem[‘sku’];

}

}

}

if($this->coreRegistry->registry(‘folioProductDeleteNotificationsAlertsCount’)) {

$this->coreRegistry->unregister(‘folioProductDeleteNotificationsAlertsCount’);

}

$this->coreRegistry->register(‘folioProductDeleteNotificationsAlertsCount’, count($result));

if($this->coreRegistry->registry(‘folioProductDeleteNotificationsAlertsSkus’)) {

$this->coreRegistry->unregister(‘folioProductDeleteNotificationsAlertsSkus’);

}

$this->coreRegistry->register(‘folioProductDeleteNotificationsAlertsSkus’, $itemIdSku);

return $result;

}

}

 

Step-8:

Create and define event “catalog_product_delete_after_done” configuration. This event will be triggered after deletion of any item(s).

app/code/Folio3/ProductDeleteNotificationsAlerts/etc/events.xml

 

<config xmlns:xsi=”http://www.w3.org/2001/XMLSchema-instance” xsi:noNamespaceSchemaLocation=”urn:magento:framework:Event/etc/events.xsd”>

<event name=”catalog_product_delete_after_done”>

<observer name=”folio_alert_product_delete” instance=”Folio3\ProductDeleteNotificationsAlerts\Observer\ProductDeleteNotificationsAlerts” />

</event>

</config>

 

Step-9 (final step):

Create an observer (defined in above step) with following code and logic.

This observer will be responsible for sending emails.

app/code/Folio3/ProductDeleteNotificationsAlerts/Observer/ProductDeleteNotificationsAlerts.php

 

namespace Folio3\ProductDeleteNotificationsAlerts\Observer;

use Magento\Framework\Event\ObserverInterface;

use Psr\Log\LoggerInterface as Logger;

use Magento\Framework\Translate\Inline\StateInterface;

use Magento\Contact\Model\ConfigInterface;

class ProductDeleteNotificationsAlerts implements ObserverInterface

{

protected $coreRegistry;

protected $context;

protected $request;

protected $transportBuilder;

protected $storeManager;

protected $logger;

protected $inlineTranslation;

protected $userContext;

protected $userFactory;

protected $timezone;

protected $scopeConfig;

protected $counterMassDelete = 0;

/**

* @param \Magento\Checkout\Model\Session $checkoutSession

* @param \Magento\Framework\Registry $coreRegistry

* @param \Magento\Framework\App\Action\Context $context

* @param \Magento\Framework\App\Request\Http $request

* @param \Magento\Framework\Mail\Template\TransportBuilder $transportBuilder

* @param \Magento\Store\Model\StoreManagerInterface $storeManager

* @param Logger $logger

* @param StateInterface $inlineTranslation

* @param ConfigInterface $contactsConfig

* @param \Magento\Authorization\Model\UserContextInterface $userContext

* @param \Magento\User\Model\UserFactory $userFactory

* @codeCoverageIgnore

*/

public function __construct(

\Magento\Framework\Registry $coreRegistry,

\Magento\Framework\App\Action\Context $context,

\Magento\Framework\App\Request\Http $request,

\Magento\Framework\Mail\Template\TransportBuilder $transportBuilder,

\Magento\Store\Model\StoreManagerInterface $storeManager,

Logger $logger,

StateInterface $inlineTranslation,

ConfigInterface $contactsConfig,

\Magento\Authorization\Model\UserContextInterface $userContext,

\Magento\User\Model\UserFactory $userFactory,

\Magento\Framework\Stdlib\DateTime\TimezoneInterface $timezone,

\Magento\Framework\App\Config\ScopeConfigInterface $scopeConfig

) {

$this->coreRegistry = $coreRegistry;

$this->context = $context;

$this->request = $request;

$this->transportBuilder = $transportBuilder;

$this->storeManager = $storeManager;

$this->logger = $logger;

$this->inlineTranslation = $inlineTranslation;

$this->contactsConfig = $contactsConfig;

$this->userContext = $userContext;

$this->userFactory = $userFactory;

$this->timezone = $timezone;

$this->scopeConfig = $scopeConfig;

}

/**

* @param \Magento\Framework\Event\Observer $observer

* @return void

*/

public function execute(\Magento\Framework\Event\Observer $observer)

{

$product = $observer->getProduct();

if (!$product) {

return $this;

}

/*

check module system->configuration

*/

if(!$this->scopeConfig->getValue(‘alert/delete/enable’, \Magento\Store\Model\ScopeInterface::SCOPE_STORE)) {

return $this;

}

$adminUsername = ”;

$ccEmails = ”;

$configTimezone = ”;

$ids = array();

$itemSkus = array();

$skus = array();

 

if($this->scopeConfig->getValue(‘alert/delete/cc’, \Magento\Store\Model\ScopeInterface::SCOPE_STORE)) {

$ccEmails = $this->scopeConfig->getValue(‘alert/delete/cc’, \Magento\Store\Model\ScopeInterface::SCOPE_STORE);

}

if($this->scopeConfig->getValue(‘general/locale/timezone’, \Magento\Store\Model\ScopeInterface::SCOPE_STORE)) {

$configZoneValue = $this->scopeConfig->getValue(‘general/locale/timezone’, \Magento\Store\Model\ScopeInterface::SCOPE_STORE);

$configTimezone = \IntlTimeZone::createTimeZone($configZoneValue)->getDisplayName();

}

if($this->userContext->getUserId()) {

$user = $this->userFactory->create()->load($this->userContext->getUserId());

$adminUsername = $user->getUsername();

}

/*

case-1:

product(s) deleted from under admin->catalog->product

*/

if($this->request->getParam(‘selected’)) {

$ids = $this->request->getParam(‘selected’);

$this->counterMassDelete++;

 

if($countDeletedItems = $this->coreRegistry->registry(‘folioProductDeleteNotificationsAlertsCount’)) {

/*

reason: the event triggers on every product delete

if mass delete more than 1 product(s),

multiple emails will be sent, on each delete trigger

fix:   set counter variable and executes email code only

if count matches with the deleted product(s) actual count

*/

if($this->counterMassDelete != $countDeletedItems) {

return $this;

}

}

if($itemSkus = $this->coreRegistry->registry(‘folioProductDeleteNotificationsAlertsSkus’)) {

foreach($ids as $eachId) {

if(isset($itemSkus[$eachId])) {

$skus[] = $itemSkus[$eachId];

}

}

}

}

/*

case-2:

product(s) deleted via product API

*/

else {

$skus[] = $product->getSku();

}

 

$postObject = new \Magento\Framework\DataObject();

$data = array();

$date = $this->timezone->date();

$dateTime = $date->format(‘Y-m-d h:i:s A’);

$data[‘sku’] = implode(‘, ‘,$skus);

$data[‘admin_user’] = $adminUsername;

$data[‘date_time’] = $dateTime;

$data[‘time_zone’] = $configTimezone;

$postObject->setData($data);

 

$this->inlineTranslation->suspend();

try {

 

if($ccEmails) {

$sentTo = array_merge(

array($this->contactsConfig->emailRecipient()),

explode(‘,’,$ccEmails)

);

}

else {

$sentTo = array(

$this->contactsConfig->emailRecipient()

);

}

 

$transport = $this->transportBuilder->setTemplateIdentifier(‘folio_alert_product_delete’)

->setTemplateOptions(

[

‘area’ => ‘frontend’,

‘store’ => $this->storeManager->getStore()->getStoreId()

]

)->setTemplateVars(

[

‘store’ => $this->storeManager->getStore(),

‘data’ => $postObject

]

)

->setFrom(‘general’)

->addTo($sentTo)

->setReplyTo(‘general’)

->getTransport();

 

$transport->sendMessage();

$this->inlineTranslation->resume();

}

catch (\Magento\Framework\Exception\MailException $e) {

$this->logger->critical($e);

}

 

return $this;

}

}

The full functional module has been uploaded at Magento-2 official site: https://marketplace.magento.com/

CALL

USA408 365 4638

VISIT

1301 Shoreway Road, Suite 160,

Belmont, CA 94002

Contact us

Whether you are a large enterprise looking to augment your teams with experts resources or an SME looking to scale your business or a startup looking to build something.
We are your digital growth partner.

Tel: +1 408 365 4638
Support: +1 (408) 512 1812