From 8c29d75c63f0796a2538820d8d4de5045d011bc5 Mon Sep 17 00:00:00 2001
From: Ron Shenkerman <95565638+ronshenk@users.noreply.github.com>
Date: Thu, 14 Mar 2024 17:42:57 +0200
Subject: [PATCH] NAM-33982 collect email sms consent (#25)
* NAM-33982 add email and sms consent option
* NAM-33982 change text add default label
* NAM-33982 fix wrong name
* NAM-33982 check if customer exists
* NAM-33982 remove sms attribute from customer form
catch customer not found exception
---
Block/Adminhtml/Settings/Form.php | 62 ++++++++
Controller/Adminhtml/Settings/Index.php | 24 ++++
Helper/ConfigHelper.php | 52 +++++++
Model/Api/Data.php | 31 +++-
Observer/TriggerOrderPlacedFinished.php | 135 ++++++++++++++++++
Plugin/CheckoutLayoutPlugin.php | 83 +++++++++++
.../Data/AddCustomerSmsConsentAttribute.php | 128 +++++++++++++++++
composer.json | 2 +-
etc/di.xml | 3 +
etc/events.xml | 4 +
etc/extension_attributes.xml | 11 ++
etc/module.xml | 2 +-
view/adminhtml/templates/settings.phtml | 124 ++++++++++++++++
view/frontend/layout/checkout_index_index.xml | 5 +-
view/frontend/requirejs-config.js | 18 +++
.../js/action/set-billing-address-mixin.js | 32 +++++
.../action/set-shipping-information-mixin.js | 32 +++++
17 files changed, 743 insertions(+), 5 deletions(-)
create mode 100644 Observer/TriggerOrderPlacedFinished.php
create mode 100644 Plugin/CheckoutLayoutPlugin.php
create mode 100644 Setup/Patch/Data/AddCustomerSmsConsentAttribute.php
create mode 100644 etc/extension_attributes.xml
create mode 100644 view/frontend/requirejs-config.js
create mode 100644 view/frontend/web/js/action/set-billing-address-mixin.js
create mode 100644 view/frontend/web/js/action/set-shipping-information-mixin.js
diff --git a/Block/Adminhtml/Settings/Form.php b/Block/Adminhtml/Settings/Form.php
index 9dc4edf..0c59fdb 100644
--- a/Block/Adminhtml/Settings/Form.php
+++ b/Block/Adminhtml/Settings/Form.php
@@ -39,6 +39,12 @@ public function __construct(
$this->is_fpt_enabled = $configHelper->getWithFixedProductTax();
$this->is_cart_auto_coupon_enabled = $configHelper->isCartAutoCouponEnabled();
$this->is_aw_points_enabled = $configHelper->isAheadworksRewardPointsEnabled();
+ $this->email_consent_enabled = $configHelper->getValue(ConfigHelper::EMAIL_CONSENT_ENABLED);
+ $this->email_consent_checkbox_position = $configHelper->getValue(ConfigHelper::EMAIL_CONSENT_CHECKBOX_POSITION);
+ $this->email_consent_checkbox_lable_value = $configHelper->getValue(ConfigHelper::EMAIL_CONSENT_CHECKBOX_LABEL_VALUE);
+ $this->sms_consent_enabled = $configHelper->getValue(ConfigHelper::SMS_CONSENT_ENABLED);
+ $this->sms_consent_checkbox_position = $configHelper->getValue(ConfigHelper::SMS_CONSENT_CHECKBOX_POSITION);
+ $this->sms_consent_checkbox_lable_value = $configHelper->getValue(ConfigHelper::SMS_CONSENT_CHECKBOX_LABEL_VALUE);
$aw_service = $rewardPointsFactory->create();
if ($aw_service) {
$this->is_aw_points_plugin_exists = true;
@@ -132,4 +138,60 @@ public function getCartAutoCouponEnabled()
{
return $this->is_cart_auto_coupon_enabled;
}
+
+ /**
+ * @return int|mixed
+ */
+ public function getEmailConsentEnabled()
+ {
+ return $this->email_consent_enabled;
+ }
+
+ /**
+ * @return int|mixed
+ */
+ public function getEmailConsentCheckboxPosition()
+ {
+ return $this->email_consent_checkbox_position;
+ }
+
+ /**
+ * @return int|mixed
+ */
+ public function getEmailConsentCheckboxLabelValue()
+ {
+ return $this->email_consent_checkbox_lable_value;
+ }
+
+ /**
+ * @return int|mixed
+ */
+ public function getSMSConsentEnabled()
+ {
+ return $this->sms_consent_enabled;
+ }
+
+ /**
+ * @return int|mixed
+ */
+ public function getSMSConsentCheckboxPosition()
+ {
+ return $this->sms_consent_checkbox_position;
+ }
+
+ /**
+ * @return mixed
+ */
+ public function getSMSConsentCheckboxLabelValue()
+ {
+ return $this->sms_consent_checkbox_lable_value;
+ }
+
+ /**
+ * @return array
+ */
+ public function getFormFieldPositions()
+ {
+ return range(0 , 1000, 10);
+ }
}
diff --git a/Controller/Adminhtml/Settings/Index.php b/Controller/Adminhtml/Settings/Index.php
index 3335ca3..021864b 100644
--- a/Controller/Adminhtml/Settings/Index.php
+++ b/Controller/Adminhtml/Settings/Index.php
@@ -100,6 +100,30 @@ private function saveSettings($data)
$this->configHelper->setCustomerAddressType($data['customer_address']);
}
+ if (isset($data['email_consent'])) {
+ $this->configHelper->setValue(ConfigHelper::EMAIL_CONSENT_ENABLED, $data['email_consent'] == 1);
+ }
+
+ if (isset($data['email_consent_checkbox_position'])) {
+ $this->configHelper->setValue(ConfigHelper::EMAIL_CONSENT_CHECKBOX_POSITION, $data['email_consent_checkbox_position']);
+ }
+
+ if (isset($data['email_consent_checkbox_lable_value'])) {
+ $this->configHelper->setValue(ConfigHelper::EMAIL_CONSENT_CHECKBOX_LABEL_VALUE, $data['email_consent_checkbox_lable_value']);
+ }
+
+ if (isset($data['sms_consent'])) {
+ $this->configHelper->setValue(ConfigHelper::SMS_CONSENT_ENABLED, $data['sms_consent'] == 1);
+ }
+
+ if (isset($data['sms_consent_checkbox_position'])) {
+ $this->configHelper->setValue(ConfigHelper::SMS_CONSENT_CHECKBOX_POSITION, $data['sms_consent_checkbox_position']);
+ }
+
+ if (isset($data['sms_consent_checkbox_lable_value'])) {
+ $this->configHelper->setValue(ConfigHelper::SMS_CONSENT_CHECKBOX_LABEL_VALUE, $data['sms_consent_checkbox_lable_value']);
+ }
+
return true;
}
}
diff --git a/Helper/ConfigHelper.php b/Helper/ConfigHelper.php
index 8bd68b9..ca98106 100644
--- a/Helper/ConfigHelper.php
+++ b/Helper/ConfigHelper.php
@@ -32,6 +32,17 @@ class ConfigHelper
const ENABLE_AHEADWORKS_REWARD_POINTS = 'remarkety/mgconnector/aheadworks_reward_points';
const CUSTOMER_ADDRESS_TO_USE = 'remarkety/mgconnector/customer_address_to_use';
const CART_AUTO_COUPON_ENABLED = 'remarkety/mgconnector/cart_auto_coupon_enabled';
+ const EMAIL_CONSENT_ENABLED = 'remarkety/mgconnector/email_consent_enabled';
+ const EMAIL_CONSENT_CHECKBOX_POSITION = 'remarkety/mgconnector/email_consent_checkbox_position';
+ const EMAIL_CONSENT_CHECKBOX_LABEL_VALUE = 'remarkety/mgconnector/email_consent_checkbox_lable_value';
+ const SMS_CONSENT_ENABLED = 'remarkety/mgconnector/sms_consent_enabled';
+ const SMS_CONSENT_CHECKBOX_POSITION = 'remarkety/mgconnector/sms_consent_checkbox_position';
+ const SMS_CONSENT_CHECKBOX_LABEL_VALUE = 'remarkety/mgconnector/sms_consent_checkbox_lable_value';
+ /**
+ * should we get marketing consent saved in shopper attribute, if set to 0 then we don't get the data
+ * added this setting just in case we see performance degradation in production stores
+ */
+ const GET_SHOPPER_MARKETING_CONSENT = 'remarkety/mgconnector/get_shopper_marketing_consent';
const ASYNC_MODE_OFF = 0;
const ASYNC_MODE_ON = 1;
@@ -338,4 +349,45 @@ public function customerPendingConfirmation(Customer $customer)
$customer->getWebsiteId()
);
}
+
+ public function getEmailConsentEnabled()
+ {
+ return $this->_scopeConfig->getValue(self::EMAIL_CONSENT_ENABLED);
+ }
+
+ public function getEmailConsentCheckBoxPosition()
+ {
+ return $this->_scopeConfig->getValue(self::EMAIL_CONSENT_CHECKBOX_POSITION);
+ }
+
+
+ public function setValue($path, $value)
+ {
+ $this->configResource->saveConfig(
+ $path,
+ $value,
+ ScopeConfigInterface::SCOPE_TYPE_DEFAULT,
+ 0
+ );
+ $this->cacheTypeList->cleanType('config');
+ }
+
+ public function getValue($path)
+ {
+ return $this->_scopeConfig->getValue($path);
+ }
+
+ /**
+ * check if the setting to get shopper marketing consent attribute is set to disabled
+ * @return bool
+ */
+ public function shouldGetShopperConsentAttribute()
+ {
+ $getShopperMarketingConsent = $this->getValue(self::GET_SHOPPER_MARKETING_CONSENT);
+
+ if ($getShopperMarketingConsent === 0 || $getShopperMarketingConsent === '0') {
+ return false;
+ }
+ return true;
+ }
}
diff --git a/Model/Api/Data.php b/Model/Api/Data.php
index fff2734..0fd666b 100644
--- a/Model/Api/Data.php
+++ b/Model/Api/Data.php
@@ -610,6 +610,8 @@ public function getCustomers(
$pageSize = null;
$customerData = $this->_customerCollectionFactory->create();
+ $objectManager = \Magento\Framework\App\ObjectManager::getInstance();
+ $customerRepository = $objectManager->get('Magento\Customer\Api\CustomerRepositoryInterface');
if ($customer_id !== null) {
$customerData->addFieldToFilter('entity_id', $customer_id);
@@ -642,6 +644,7 @@ public function getCustomers(
$customerData->setPage($pageNumber, $pageSize);
}
$pos_id_attribute_code = $this->configHelper->getPOSAttributeCode();
+ $should_get_shopper_consent_data = $this->configHelper->shouldGetShopperConsentAttribute();
if (!empty($pos_id_attribute_code)) {
//make sure we get the POS id attribute
@@ -701,6 +704,18 @@ public function getCustomers(
if ($aw_rewards_integrate) {
$customers['rewards_points'] = $this->customerRewardPointsService->getCustomerRewardPointsBalance($customer->getId());
}
+
+ if ($should_get_shopper_consent_data) {
+ /**
+ * @var CustomerInterface $customerInterface
+ */
+ $customerInterface = $customerRepository->getById($customer->getId());
+ if ($customerInterface) {
+ $rm_sms_consent = $customerInterface->getCustomAttribute('rm_sms_consent');
+ $customers['rm_sms_consent'] = $rm_sms_consent ? $rm_sms_consent->getValue() : null;
+ }
+ }
+
$customerArray[] = $this->dataOverride->customer($customer, $customers);
}
$object = new DataObject();
@@ -780,6 +795,20 @@ public function getCustomerDataById($id = false)
if ($customerData->getId()) {
$customerArray = $this->mapCustomer($customerData, true);
+ $should_get_shopper_consent_data = $this->configHelper->shouldGetShopperConsentAttribute();
+ if ($should_get_shopper_consent_data) {
+ $objectManager = \Magento\Framework\App\ObjectManager::getInstance();
+
+ $customerRepository = $objectManager->get('Magento\Customer\Api\CustomerRepositoryInterface');
+ /**
+ * @var CustomerInterface $customerInterface
+ */
+ $customerInterface = $customerRepository->getById($id);
+ if ($customerInterface) {
+ $rm_sms_consent = $customerInterface->getCustomAttribute('rm_sms_consent');
+ $customerArray['rm_sms_consent'] = $rm_sms_consent ? $rm_sms_consent->getValue() : null;
+ }
+ }
}
return $customerArray;
}
@@ -1354,7 +1383,7 @@ public function setConfig($mage_store_id, $configName, $scope, $newValue)
*/
public function getVersion()
{
- return '2.8.0';
+ return '2.8.1';
}
/**
diff --git a/Observer/TriggerOrderPlacedFinished.php b/Observer/TriggerOrderPlacedFinished.php
new file mode 100644
index 0000000..8b76770
--- /dev/null
+++ b/Observer/TriggerOrderPlacedFinished.php
@@ -0,0 +1,135 @@
+subscriberFactory = $subscriberFactory;
+ }
+
+ /**
+ * @param Observer $observer
+ * @return void
+ */
+ public function execute(\Magento\Framework\Event\Observer $observer)
+ {
+ try {
+ $this->startTiming(self::class);
+ /**
+ * @var $order Order
+ */
+ $order = $observer->getEvent()->getDataByKey('order');
+
+ $rm_email_consent = null;
+ $rm_sms_consent = null;
+ $extensionAttributes = null;
+ $orderPlacedParams = json_decode($this->request->getContent(), true);
+ if (isset($orderPlacedParams['billingAddress']['extension_attributes'])) {
+ $extensionAttributes = $orderPlacedParams['billingAddress']['extension_attributes'];
+ } else if (isset($orderPlacedParams['billingAddress']['extensionAttributes'])) {
+ $extensionAttributes = $orderPlacedParams['billingAddress']['extensionAttributes'];
+ }
+
+ if ($extensionAttributes) {
+ if (isset($extensionAttributes['rm_email_consent']) && $extensionAttributes['rm_email_consent']) {
+ $rm_email_consent = true;
+ }
+
+ if (isset ($extensionAttributes['rm_sms_consent']) && $extensionAttributes['rm_sms_consent']) {
+ $rm_sms_consent = true;
+ }
+ }
+
+ if (!empty($rm_email_consent) || !empty($rm_sms_consent)) {
+ $email = $order->getCustomerEmail();
+ $customer = null;
+ $subscriber = $this->subscriberFactory->create()->loadByEmail($email);
+ try {
+ $customer = $this->customerRepository->get($email); // get by email and not by id since if the customer is not logged in we will not find him
+ } catch (\Exception $e) {}
+ if (!empty($rm_email_consent) && $subscriber) {
+ if ($customer) {
+ $subscriber->setCustomerId($customer->getId());
+ }
+ $subscriber->setStoreId($order->getStoreId());
+ $subscriber->setEmail($email);
+ $subscriber->setStatus(\Magento\Newsletter\Model\Subscriber::STATUS_SUBSCRIBED);
+ $subscriber->save();
+ }
+ if (!empty($rm_sms_consent)) {
+ if ($customer) {
+ $customer->setCustomAttribute('rm_sms_consent', $rm_sms_consent);
+ $this->customerRepository->save($customer);
+ }
+ }
+ }
+ $this->endTiming(self::class);
+ } catch (\Exception $ex) {
+ $this->logError($ex);
+ }
+ }
+}
diff --git a/Plugin/CheckoutLayoutPlugin.php b/Plugin/CheckoutLayoutPlugin.php
new file mode 100644
index 0000000..c15a55b
--- /dev/null
+++ b/Plugin/CheckoutLayoutPlugin.php
@@ -0,0 +1,83 @@
+remarketyConfigHelper = $remarketyConfigHelper;
+ $this->_customerSession = $customerSession;
+ }
+
+ public function afterProcess(\Magento\Checkout\Block\Checkout\LayoutProcessor $processor, $jsLayout){
+ $fields = [];
+ if($this->remarketyConfigHelper->getValue(ConfigHelper::EMAIL_CONSENT_ENABLED) == 1) {
+ $fields[] = [
+ 'id' => 'rm_email_consent',
+ 'label' => $this->remarketyConfigHelper->getValue(ConfigHelper::EMAIL_CONSENT_CHECKBOX_LABEL_VALUE) ?? 'Subscribe to receiving exclusive discounts via email',
+ 'sortOrder' => $this->remarketyConfigHelper->getValue(ConfigHelper::EMAIL_CONSENT_CHECKBOX_POSITION) ?? 900,
+ ];
+ }
+
+ if($this->remarketyConfigHelper->getValue(ConfigHelper::SMS_CONSENT_ENABLED) == 1) {
+ $fields[] = [
+ 'id' => 'rm_sms_consent',
+ 'label' => $this->remarketyConfigHelper->getValue(ConfigHelper::SMS_CONSENT_CHECKBOX_LABEL_VALUE) ?? 'Subscribe to receiving exclusive discounts via sms',
+ 'sortOrder' => $this->remarketyConfigHelper->getValue(ConfigHelper::SMS_CONSENT_CHECKBOX_POSITION) ?? 900,
+ ];
+ }
+
+ foreach ($fields as $key => $field) {
+ $newField = [
+ 'component' => 'Magento_Ui/js/form/element/abstract',
+ 'config' => [
+ 'id' => $field['id'],
+ 'customScope' => 'shippingAddress',
+ 'template' => 'ui/form/field',
+ 'elementTmpl' => 'ui/form/element/checkbox',
+ 'description' => $field['label'],
+ ],
+ 'dataScope' => 'shippingAddress.extension_attributes.' . $field['id'],
+ 'description' => $field['label'],
+ 'provider' => 'checkoutProvider',
+ 'validation' => [
+ 'required-entry' => false
+ ],
+ 'options' => [],
+ 'filterBy' => null,
+ 'customEntry' => null,
+ 'visible' => true,
+ 'id' => $field['id'],
+ 'sortOrder' => $field['sortOrder'],
+ 'value' => false,
+ ];
+
+ if ($this->_customerSession->isLoggedIn()) {
+ $jsLayout['components']['checkout']['children']['steps']['children']['shipping-step']
+ ['children']['shippingAddress']['children']['before-form']['children'][$field['id']] = $newField;
+ } else {
+ $jsLayout['components']['checkout']['children']['steps']['children']['shipping-step']
+ ['children']['shippingAddress']['children']['shipping-address-fieldset']['children'][$field['id']] = $newField;
+ }
+ }
+
+
+ return $jsLayout;
+ }
+}
diff --git a/Setup/Patch/Data/AddCustomerSmsConsentAttribute.php b/Setup/Patch/Data/AddCustomerSmsConsentAttribute.php
new file mode 100644
index 0000000..58e3ebe
--- /dev/null
+++ b/Setup/Patch/Data/AddCustomerSmsConsentAttribute.php
@@ -0,0 +1,128 @@
+moduleDataSetup = $moduleDataSetup;
+ $this->customerSetupFactory = $customerSetupFactory;
+ $this->attributeSetFactory = $attributeSetFactory;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function apply()
+ {
+ $this->moduleDataSetup->getConnection()->startSetup();
+
+ $this->createAttribute('rm_sms_consent', 'SMS marketing consent');
+ $this->moduleDataSetup->getConnection()->endSetup();
+ }
+
+ private function createAttribute($attributeCode, $label) {
+ /** @var CustomerSetup $customerSetup */
+ $customerSetup = $this->customerSetupFactory->create(['setup' => $this->moduleDataSetup]);
+ $customerEntity = $customerSetup->getEavConfig()->getEntityType(Customer::ENTITY);
+ $attributeSetId = $customerEntity->getDefaultAttributeSetId();
+
+ /** @var $attributeSet Set */
+ $attributeSet = $this->attributeSetFactory->create();
+ $attributeGroupId = $attributeSet->getDefaultGroupId($attributeSetId);
+ $customerSetup->addAttribute(
+ Customer::ENTITY,
+ $attributeCode,
+ [
+ 'label' => $label,
+ 'input' => 'boolean',
+ 'type' => 'int',
+ 'source' => '',
+ 'required' => false,
+ 'position' => 333,
+ 'visible' => true,
+ 'system' => false, // important !!
+ 'is_used_in_grid' => false,
+ 'is_visible_in_grid' => false,
+ 'is_filterable_in_grid' => false,
+ 'is_searchable_in_grid' => false,
+ 'backend' => ''
+ ]
+ );
+
+ $attribute = $customerSetup->getEavConfig()->getAttribute(Customer::ENTITY, $attributeCode);
+ $attribute->addData([
+ 'used_in_forms' => [
+ 'adminhtml_checkout'
+ ]
+ ]);
+ $attribute->addData([
+ 'attribute_set_id' => $attributeSetId,
+ 'attribute_group_id' => $attributeGroupId
+
+ ]);
+ $attribute->save();
+ }
+
+ public function revert()
+ {
+ $this->moduleDataSetup->getConnection()->startSetup();
+ /** @var CustomerSetup $customerSetup */
+ $customerSetup = $this->customerSetupFactory->create(['setup' => $this->moduleDataSetup]);
+ $customerSetup->removeAttribute(\Magento\Customer\Model\Customer::ENTITY, 'rm_sms_consent');
+
+ $this->moduleDataSetup->getConnection()->endSetup();
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getAliases()
+ {
+ return [];
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public static function getDependencies()
+ {
+ return [
+
+ ];
+ }
+}
diff --git a/composer.json b/composer.json
index fc4b2c3..cddb081 100644
--- a/composer.json
+++ b/composer.json
@@ -10,7 +10,7 @@
"lib-libxml": "*"
},
"type": "magento2-module",
- "version": "2.8.0",
+ "version": "2.8.1",
"license": [
"OSL-3.0",
"AFL-3.0"
diff --git a/etc/di.xml b/etc/di.xml
index fa98d86..502a09c 100644
--- a/etc/di.xml
+++ b/etc/di.xml
@@ -8,4 +8,7 @@