1078 lines
39 KiB
PHP
1078 lines
39 KiB
PHP
<?php
|
|
/**
|
|
* 2022 ECSoft
|
|
*
|
|
* NOTICE OF LICENSE
|
|
*
|
|
* This source file is subject to the Academic Free License (AFL 3.0)
|
|
* that is bundled with this package in the file LICENSE.txt.
|
|
* It is also available through the world-wide-web at this URL:
|
|
* http://opensource.org/licenses/afl-3.0.php
|
|
* If you did not receive a copy of the license and are unable to
|
|
* obtain it through the world-wide-web, please send an email
|
|
* to dev.ecsoft@gmail.com so we can send you a copy immediately.
|
|
*
|
|
* @author ECSoft <dev.ecsoft@gmail.com>
|
|
* @copyright 2022 ECSoft
|
|
* @license http://opensource.org/licenses/afl-3.0.php Academic Free License (AFL 3.0)
|
|
* International Registered Trademark & Property of ECSoft
|
|
*/
|
|
|
|
require_once dirname(__FILE__) . '/ua/EcsGtmProGtmParams.php';
|
|
require_once dirname(__FILE__) . '/ua/EcsGtmProRefund.php';
|
|
require_once dirname(__FILE__) . '/../EcsGtmProTools.php';
|
|
require_once dirname(__FILE__) . '/EcsGtmProProduct.php';
|
|
require_once dirname(__FILE__) . '/EcsGtmProDataLayer.php';
|
|
require_once dirname(__FILE__) . '/ga4/EcsGtmProDataLayerItem.php';
|
|
|
|
/**
|
|
* @property EcsGtmPro $module
|
|
*/
|
|
class EcsGtmProDataLayerManager
|
|
{
|
|
public $module;
|
|
protected $dlGenerated;
|
|
protected $remarketingGenerated;
|
|
protected $dataLayer;
|
|
|
|
protected $format;
|
|
protected $context;
|
|
|
|
protected $idLang;
|
|
protected $categoryTree;
|
|
protected $rootCategory;
|
|
protected $opc;
|
|
|
|
public function __construct($module, $format)
|
|
{
|
|
$this->module = $module;
|
|
$this->format = $format;
|
|
$this->context = Context::getContext();
|
|
$this->dataLayer = new EcsGtmProDataLayer($this);
|
|
}
|
|
|
|
public function isEE()
|
|
{
|
|
return in_array($this->format, array('gau', 'all'));
|
|
}
|
|
|
|
public function isGA4()
|
|
{
|
|
return in_array($this->format, array('ga4', 'all'));
|
|
}
|
|
|
|
public function toJson()
|
|
{
|
|
return $this->dataLayer->toJson();
|
|
}
|
|
|
|
public function addProductList($products, $list = null, $maxProducts = null, $type = null)
|
|
{
|
|
$i = 1;
|
|
if (is_array($products) && !empty($products)) {
|
|
foreach ($products as $p) {
|
|
if (is_array($list)) {
|
|
$list['index'] = $i++;
|
|
}
|
|
$this->dataLayer->addItem($p, $type, $list);
|
|
|
|
if ($maxProducts && $i > $maxProducts) {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
public function generateDataLayer()
|
|
{
|
|
if (!$this->dlGenerated) {
|
|
$controller = Tools::getValue('controller');
|
|
$this->dataLayer->pageCategory = $controller;
|
|
|
|
if (!$this->module->gtmConfig->userIdConfig->async) {
|
|
$this->addUserInfo($this->dataLayer);
|
|
}
|
|
|
|
if ($this->module->isOrderValidationPage()) {
|
|
$this->orderConfirmation();
|
|
} else {
|
|
if ($this->module->isOPC()) {
|
|
$controller = 'orderopc';
|
|
}
|
|
|
|
if ($this->module->isHomePage()) {
|
|
$this->homeDataLayer();
|
|
} elseif ($this->module->isProductPage()) {
|
|
$this->productDataLayer();
|
|
} elseif ($this->module->isCategoryPage()) {
|
|
$this->categoryDataLayer();
|
|
} elseif ($this->module->isSearchPage()) {
|
|
$this->searchResultDataLayer();
|
|
} elseif ($this->module->isCartPage() || $this->module->isOrderPage() || $this->module->isPaymentPage() || $this->module->isOPC()) {
|
|
$this->checkoutDataLayer($controller);
|
|
}
|
|
}
|
|
|
|
$this->dlGenerated = true;
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
protected function checkoutDataLayer($controller)
|
|
{
|
|
$step = $this->getCheckoutStep();
|
|
|
|
$cartProducts = $this->getCartProducts();
|
|
$this->addProductList($cartProducts, null, $this->module->gtmConfig->generalConfig->max_category, 'begin_checkout');
|
|
|
|
$this->dataLayer->setSubtotalsFromCart($this->context->cart);
|
|
$this->getCartRulesFromCart($this->context->cart);
|
|
|
|
if ($this->isEE()) {
|
|
$actionField = new stdClass();
|
|
$actionField->step = $step;
|
|
$this->dataLayer->event = "checkout";
|
|
if (!isset($this->dataLayer->ecommerce->checkout)) {
|
|
$this->dataLayer->ecommerce->checkout = new stdClass();
|
|
}
|
|
$this->dataLayer->ecommerce->checkout->actionField = $actionField;
|
|
}
|
|
|
|
if ($this->isGA4()) {
|
|
if ($this->module->isCartPage() || ($this->module->is16() && $step == 1)) {
|
|
$this->dataLayer->event = 'view_cart';
|
|
} else {
|
|
switch ($step) {
|
|
case 1:
|
|
$this->dataLayer->event = 'begin_checkout';
|
|
Context::getContext()->cookie->begin_checkout_triggered = 1;
|
|
break;
|
|
|
|
case 2:
|
|
$this->dataLayer->event = 'checkout_address';
|
|
|
|
if (empty(Context::getContext()->cookie->begin_checkout_triggered)) {
|
|
$this->preDataLayer = new self($this->module, $this->module->gtmConfig->generalConfig->format);
|
|
$this->preDataLayer->addProductList($cartProducts, null, $this->module->gtmConfig->generalConfig->max_category);
|
|
$this->preDataLayer->event = 'begin_checkout';
|
|
} else {
|
|
unset(Context::getContext()->cookie->begin_checkout_triggered);
|
|
}
|
|
break;
|
|
|
|
case 3:
|
|
$this->dataLayer->event = 'checkout_shipping';
|
|
break;
|
|
case 4:
|
|
$this->dataLayer->event = 'checkout_payment';
|
|
break;
|
|
default:
|
|
$this->dataLayer->event = 'checkout_step'.$step;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
protected function getCheckoutStep()
|
|
{
|
|
$step = 0;
|
|
|
|
if ($this->module->is17() || $this->module->is8x()) {
|
|
$checkoutProcess = $this->context->smarty->getTemplateVars('checkout_process');
|
|
if ($checkoutProcess) {
|
|
$checkoutProcessClass = new ReflectionObject($checkoutProcess);
|
|
$renderable = $checkoutProcessClass->getProperty('renderable');
|
|
$renderable->setAccessible(true);
|
|
$checkoutProcessAccess = $renderable->getValue($checkoutProcess);
|
|
$reflectionMethod = new ReflectionMethod('CheckoutProcess', 'getSteps');
|
|
$steps = $reflectionMethod->invoke($checkoutProcessAccess);
|
|
foreach ($steps as $k => $v) {
|
|
if ($v->isCurrent()) {
|
|
$step = $k;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
if (!$this->module->isOPC()) {
|
|
$step = Tools::getValue('controller') == 'payment' ? 4 : Tools::getValue('step', 0);
|
|
}
|
|
}
|
|
|
|
$step++;
|
|
|
|
if ($step > 4) {
|
|
$step = 4;
|
|
}
|
|
|
|
return $step;
|
|
}
|
|
|
|
public function getUserPostcodeFromCart()
|
|
{
|
|
$cart = $this->context->cart;
|
|
|
|
if (!Validate::isLoadedObject($cart) && Tools::getIsset('id_cart')) {
|
|
$cart = new Cart((int) Tools::getValue('id_cart'));
|
|
}
|
|
|
|
$cart_id = $cart->id;
|
|
|
|
// select id_customer from ps_orders where id_cart = $cart_id
|
|
$sql = 'SELECT id_customer FROM '._DB_PREFIX_.'orders WHERE id_cart = '.(int)$cart_id;
|
|
$id_customer = Db::getInstance()->getValue($sql);
|
|
|
|
// select postcode from ps_address where id_customer = $id_customer
|
|
$sql = 'SELECT postcode FROM '._DB_PREFIX_.'address WHERE id_customer = '.(int)$id_customer;
|
|
$postcode = Db::getInstance()->getValue($sql);
|
|
|
|
return $postcode;
|
|
}
|
|
|
|
public function getUserCountryFromCart()
|
|
{
|
|
$cart = $this->context->cart;
|
|
|
|
if (!Validate::isLoadedObject($cart) && Tools::getIsset('id_cart')) {
|
|
$cart = new Cart((int) Tools::getValue('id_cart'));
|
|
}
|
|
|
|
$cart_id = $cart->id;
|
|
|
|
// select id_customer from ps_orders where id_cart = $cart_id
|
|
$sql = 'SELECT id_customer FROM '._DB_PREFIX_.'orders WHERE id_cart = '.(int)$cart_id;
|
|
$id_customer = Db::getInstance()->getValue($sql);
|
|
|
|
// select id_country from ps_address where id_customer = $id_customer
|
|
$sql = 'SELECT id_country FROM '._DB_PREFIX_.'address WHERE id_customer = '.(int)$id_customer;
|
|
$id_country = Db::getInstance()->getValue($sql);
|
|
|
|
// select name from ps_country where id_country = $id_country
|
|
$sql = 'SELECT name FROM '._DB_PREFIX_.'country_lang WHERE id_country = '.(int)$id_country . ' AND id_lang = 1';
|
|
$country = Db::getInstance()->getValue($sql);
|
|
|
|
return $country;
|
|
}
|
|
|
|
public function getUserCityFromCart()
|
|
{
|
|
$cart = $this->context->cart;
|
|
|
|
if (!Validate::isLoadedObject($cart) && Tools::getIsset('id_cart')) {
|
|
$cart = new Cart((int) Tools::getValue('id_cart'));
|
|
}
|
|
|
|
$cart_id = $cart->id;
|
|
|
|
// select id_customer from ps_orders where id_cart = $cart_id
|
|
$sql = 'SELECT id_customer FROM '._DB_PREFIX_.'orders WHERE id_cart = '.(int)$cart_id;
|
|
$id_customer = Db::getInstance()->getValue($sql);
|
|
|
|
// select city from ps_address where id_customer = $id_customer
|
|
$sql = 'SELECT city FROM '._DB_PREFIX_.'address WHERE id_customer = '.(int)$id_customer;
|
|
$city = Db::getInstance()->getValue($sql);
|
|
|
|
return $city;
|
|
}
|
|
|
|
public function getUserAddress1FromCart()
|
|
{
|
|
$cart = $this->context->cart;
|
|
|
|
if (!Validate::isLoadedObject($cart) && Tools::getIsset('id_cart')) {
|
|
$cart = new Cart((int) Tools::getValue('id_cart'));
|
|
}
|
|
|
|
$cart_id = $cart->id;
|
|
|
|
// select id_customer from ps_orders where id_cart = $cart_id
|
|
$sql = 'SELECT id_customer FROM '._DB_PREFIX_.'orders WHERE id_cart = '.(int)$cart_id;
|
|
$id_customer = Db::getInstance()->getValue($sql);
|
|
|
|
// select address1 from ps_address where id_customer = $id_customer
|
|
$sql = 'SELECT address1 FROM '._DB_PREFIX_.'address WHERE id_customer = '.(int)$id_customer;
|
|
$address1 = Db::getInstance()->getValue($sql);
|
|
|
|
return $address1;
|
|
}
|
|
|
|
public function getUserLastNameFromCart()
|
|
{
|
|
$cart = $this->context->cart;
|
|
|
|
if (!Validate::isLoadedObject($cart) && Tools::getIsset('id_cart')) {
|
|
$cart = new Cart((int) Tools::getValue('id_cart'));
|
|
}
|
|
|
|
$cart_id = $cart->id;
|
|
|
|
// select id_customer from ps_orders where id_cart = $cart_id
|
|
$sql = 'SELECT id_customer FROM '._DB_PREFIX_.'orders WHERE id_cart = '.(int)$cart_id;
|
|
$id_customer = Db::getInstance()->getValue($sql);
|
|
|
|
// select lastname from ps_address where id_customer = $id_customer
|
|
$sql = 'SELECT lastname FROM '._DB_PREFIX_.'address WHERE id_customer = '.(int)$id_customer;
|
|
$lastname = Db::getInstance()->getValue($sql);
|
|
|
|
return $lastname;
|
|
}
|
|
|
|
public function getUserFirstNameFromCart()
|
|
{
|
|
$cart = $this->context->cart;
|
|
|
|
if (!Validate::isLoadedObject($cart) && Tools::getIsset('id_cart')) {
|
|
$cart = new Cart((int) Tools::getValue('id_cart'));
|
|
}
|
|
|
|
$cart_id = $cart->id;
|
|
|
|
// select id_customer from ps_orders where id_cart = $cart_id
|
|
$sql = 'SELECT id_customer FROM '._DB_PREFIX_.'orders WHERE id_cart = '.(int)$cart_id;
|
|
$id_customer = Db::getInstance()->getValue($sql);
|
|
|
|
// select firstname from ps_address where id_customer = $id_customer
|
|
$sql = 'SELECT firstname FROM '._DB_PREFIX_.'address WHERE id_customer = '.(int)$id_customer;
|
|
$firstname = Db::getInstance()->getValue($sql);
|
|
|
|
return $firstname;
|
|
}
|
|
|
|
public function getUserPhoneFromCart()
|
|
{
|
|
$cart = $this->context->cart;
|
|
|
|
if (!Validate::isLoadedObject($cart) && Tools::getIsset('id_cart')) {
|
|
$cart = new Cart((int) Tools::getValue('id_cart'));
|
|
}
|
|
|
|
$cart_id = $cart->id;
|
|
|
|
// select id_customer from ps_orders where id_cart = $cart_id
|
|
$sql = 'SELECT id_customer FROM '._DB_PREFIX_.'orders WHERE id_cart = '.(int)$cart_id;
|
|
$id_customer = Db::getInstance()->getValue($sql);
|
|
|
|
// select phone from ps_address where id_customer = $id_customer
|
|
$sql = 'SELECT phone FROM '._DB_PREFIX_.'address WHERE id_customer = '.(int)$id_customer;
|
|
$phone = Db::getInstance()->getValue($sql);
|
|
|
|
return $phone;
|
|
}
|
|
|
|
public function getUserEmailFromCart()
|
|
{
|
|
$cart = $this->context->cart;
|
|
|
|
if (!Validate::isLoadedObject($cart) && Tools::getIsset('id_cart')) {
|
|
$cart = new Cart((int) Tools::getValue('id_cart'));
|
|
}
|
|
|
|
$cart_id = $cart->id;
|
|
|
|
// select id_customer from ps_orders where id_cart = $cart_id
|
|
$sql = 'SELECT id_customer FROM '._DB_PREFIX_.'orders WHERE id_cart = '.(int)$cart_id;
|
|
$id_customer = Db::getInstance()->getValue($sql);
|
|
|
|
// select email from ps_address where id_customer = $id_customer
|
|
$sql = 'SELECT email FROM '._DB_PREFIX_.'customer WHERE id_customer = '.(int)$id_customer;
|
|
$email = Db::getInstance()->getValue($sql);
|
|
|
|
return $email;
|
|
}
|
|
|
|
protected function getCartProducts()
|
|
{
|
|
$products = array();
|
|
|
|
$cart = $this->context->cart;
|
|
|
|
if (!Validate::isLoadedObject($cart) && Tools::getIsset('id_cart')) {
|
|
$cart = new Cart((int) Tools::getValue('id_cart'));
|
|
}
|
|
|
|
if (Validate::isLoadedObject($cart)) {
|
|
$products = $cart->getProducts();
|
|
}
|
|
return $products;
|
|
}
|
|
|
|
public function homeDataLayer()
|
|
{
|
|
$this->dataLayer->pageCategory = false;
|
|
}
|
|
|
|
public function categoryDataLayer()
|
|
{
|
|
$list = array(
|
|
'name' => $this->getCategoryName((int) Tools::getValue('id_category')),
|
|
'id' => 'cat_'.(int) Tools::getValue('id_category')
|
|
);
|
|
|
|
$products = $this->getProductsFromSmarty();
|
|
$this->addProductList($products, $list, $this->module->gtmConfig->generalConfig->max_category, 'view_item_list');
|
|
}
|
|
|
|
public function productDataLayer()
|
|
{
|
|
$this->dataLayer->addItem($this->getDisplayedProduct(), 'view_item');
|
|
}
|
|
|
|
public function searchResultDataLayer()
|
|
{
|
|
$list = array(
|
|
'name' => 'Search Results',
|
|
'id' => 'search'
|
|
);
|
|
|
|
$products = $this->getProductsFromSmarty();
|
|
$this->addProductList($products, $list, $this->module->gtmConfig->generalConfig->max_category, 'search_results');
|
|
|
|
|
|
if ($this->module->is17() || $this->module->is8x()) {
|
|
$term = $this->context->smarty->getTemplateVars('search_string');
|
|
} else {
|
|
$term = $this->context->smarty->getTemplateVars('search_query');
|
|
}
|
|
|
|
$this->dataLayer->search_term = EcsGtmProTools::cleanString(htmlspecialchars($term));
|
|
|
|
$this->dataLayer->event = 'search';
|
|
}
|
|
|
|
public function productClick($id_product, $id_product_attribute)
|
|
{
|
|
$product = new Product($id_product);
|
|
$product->id_product_attribute = $id_product_attribute;
|
|
|
|
$dataLayer = new EcsGtmProDataLayer($this, $this->module->gtmConfig->generalConfig->format);
|
|
$dataLayer->addItem($product, 'view_item');
|
|
$dataLayer->event = 'select_item';
|
|
|
|
return $dataLayer;
|
|
}
|
|
|
|
public function orderConfirmation($id_cart = null, $force_resend = false)
|
|
{
|
|
if (!$id_cart) {
|
|
$id_cart = $this->getCartFromOrderConfirmation();
|
|
}
|
|
|
|
$this->generateOrderConfirmationFromCart($id_cart, $force_resend);
|
|
}
|
|
|
|
protected function getCartFromOrderConfirmation()
|
|
{
|
|
$id_cart = null;
|
|
|
|
if (isset($this->displayOrderConfirmationOrderObj['id_cart'])) {
|
|
$id_cart = (int) $this->displayOrderConfirmationOrderObj['id_cart'];
|
|
}
|
|
|
|
if (!$id_cart) {
|
|
$id_cart = (int)(Tools::getValue('id_cart'));
|
|
}
|
|
|
|
if (!$id_cart) {
|
|
$order_id = (int) Tools::getValue('id_order', Tools::getValue('order'));
|
|
$order = new Order($order_id);
|
|
if (Validate::isLoadedObject($order)) {
|
|
$id_cart = $order->id_cart;
|
|
}
|
|
}
|
|
|
|
return $id_cart;
|
|
}
|
|
|
|
public function addUserInfo($dataLayer = null)
|
|
{
|
|
if ($dataLayer == null) {
|
|
$dataLayer = $this->dataLayer;
|
|
}
|
|
if ($this->module->gtmConfig->userIdConfig->add_user_id) {
|
|
if (!empty($this->context->cookie->id_customer)) {
|
|
$dataLayer->userLogged = 1;
|
|
$dataLayer->userId = (string) $this->context->cookie->id_customer;
|
|
|
|
$customer = new Customer($dataLayer->userId);
|
|
if (Validate::isLoadedObject($customer)) {
|
|
$groups = $customer->getGroups();
|
|
$groupsName = array();
|
|
foreach ($groups as $id) {
|
|
$group = new Group($id);
|
|
if (Validate::isLoadedObject($group)) {
|
|
$groupsName[] = $group->name[(int)(Configuration::get('PS_LANG_DEFAULT'))];
|
|
}
|
|
}
|
|
$dataLayer->userGroups = $groupsName;
|
|
}
|
|
} elseif ($this->module->gtmConfig->userIdConfig->add_guest_id) {
|
|
$dataLayer->userLogged = 0;
|
|
|
|
if (!empty($this->context->cookie->id_guest)) {
|
|
$dataLayer->userId = "guest_".$this->context->cookie->id_guest;
|
|
} else {
|
|
if (empty($this->context->cookie->user_rand_id)) {
|
|
$this->context->cookie->user_rand_id = rand(100000, 999999);
|
|
}
|
|
$dataLayer->userId = "guest_".$this->context->cookie->user_rand_id;
|
|
}
|
|
}
|
|
}
|
|
|
|
return $dataLayer;
|
|
}
|
|
|
|
protected function getProductsFromSmarty()
|
|
{
|
|
$products = $this->context->smarty->getTemplateVars('products');
|
|
|
|
if ($this->module->is17() || $this->module->is8x()) {
|
|
if (!$products || !is_array($products)) {
|
|
$listing = $this->context->smarty->getTemplateVars('listing');
|
|
if (isset($listing['products'])) {
|
|
$products = $listing['products'];
|
|
}
|
|
}
|
|
if (!$products || !is_array($products)) {
|
|
$cart = $this->context->smarty->getTemplateVars('cart');
|
|
if (isset($cart['products'])) {
|
|
$products = $cart['products'];
|
|
}
|
|
}
|
|
}
|
|
|
|
return $products;
|
|
}
|
|
|
|
public function getCategoryNameHierarchy($category, $level)
|
|
{
|
|
if (!$this->rootCategory) {
|
|
$this->rootCategory = new Category($this->context->shop->id_category);
|
|
}
|
|
|
|
$depth = $level + (int)$this->rootCategory->level_depth;
|
|
|
|
if ($category->level_depth >= $depth) {
|
|
return $this->getCategoryName($category, $depth);
|
|
}
|
|
return null;
|
|
}
|
|
|
|
public function generateRemarketingParams()
|
|
{
|
|
if (!$this->remarketingGenerated) {
|
|
$controller = Tools::getValue('controller');
|
|
$this->dataLayer->google_tag_params = new EcsGtmProGtmParams();
|
|
$pagetype = $controller;
|
|
|
|
if ($this->module->isOrderValidationPage()) {
|
|
$pagetype = 'purchase';
|
|
$this->dataLayer->google_tag_params->ecomm_prodid = $this->remarketingGetProductIdsFromCart();
|
|
$this->dataLayer->google_tag_params->ecomm_totalvalue = (float) round($this->getTotalProductPriceFromCart(), _ECSGTMPRO_PRICE_DECIMAL_);
|
|
$this->dataLayer->google_tag_params->ecomm_totalvalue_tax_exc = (float) round($this->getTotalProductPriceFromCart(false), _ECSGTMPRO_PRICE_DECIMAL_);
|
|
|
|
// ecommerce user
|
|
$this -> dataLayer -> orderData -> userEmail = $this -> getUserEmailFromCart();
|
|
$this -> dataLayer -> orderData -> userPhone = $this -> getUserPhoneFromCart();
|
|
$this -> dataLayer -> orderData -> userFirstName = $this -> getUserFirstNameFromCart();
|
|
$this -> dataLayer -> orderData -> userLastName = $this -> getUserLastNameFromCart();
|
|
// address1
|
|
$this -> dataLayer -> orderData -> userAddress1 = $this -> getUserAddress1FromCart();
|
|
// city
|
|
$this -> dataLayer -> orderData -> userCity = $this -> getUserCityFromCart();
|
|
$this -> dataLayer -> orderData -> userRegion = '';
|
|
// country
|
|
$this -> dataLayer -> orderData -> userCountry = $this -> getUserCountryFromCart();
|
|
// postcode
|
|
$this -> dataLayer -> orderData -> userPostcode = $this -> getUserPostcodeFromCart();
|
|
} else {
|
|
if ($this->module->isOPC()) {
|
|
$controller = 'orderopc';
|
|
}
|
|
|
|
if ($this->module->isHomePage()) {
|
|
$pagetype = 'home';
|
|
} elseif ($this->module->isProductPage()) {
|
|
$product = $this->getDisplayedProduct();
|
|
if (Validate::isLoadedObject($product)) {
|
|
$this->dataLayer->google_tag_params->ecomm_prodid = EcsGtmProProduct::getInstance()->remarketingGetProductIdentifier($product);
|
|
$this->dataLayer->google_tag_params->ecomm_totalvalue = (float) round((float) Product::getPriceStatic($product->id, true, $product->id_product_attribute), _ECSGTMPRO_PRICE_DECIMAL_);
|
|
$this->dataLayer->google_tag_params->ecomm_totalvalue_tax_exc = (float) round((float) Product::getPriceStatic($product->id, false, $product->id_product_attribute), _ECSGTMPRO_PRICE_DECIMAL_);
|
|
$this->dataLayer->google_tag_params->ecomm_category = $this->getCategoryName($product->id_category_default);
|
|
}
|
|
} elseif ($this->module->isPaymentPage() || $this->module->isCartPage() || $this->module->isOPC()) {
|
|
$pagetype = 'cart';
|
|
$this->dataLayer->google_tag_params->ecomm_prodid = $this->remarketingGetProductIdsFromCart();
|
|
$this->dataLayer->google_tag_params->ecomm_totalvalue = (float) round($this->getTotalProductPriceFromCart(), _ECSGTMPRO_PRICE_DECIMAL_);
|
|
$this->dataLayer->google_tag_params->ecomm_totalvalue_tax_exc = (float) round($this->getTotalProductPriceFromCart(false), _ECSGTMPRO_PRICE_DECIMAL_);
|
|
} elseif ($this->module->isCategoryPage()) {
|
|
$this->dataLayer->google_tag_params->ecomm_category = $this->getCategoryName((int) Tools::getValue('id_category'));
|
|
} elseif ($this->module->isSearchPage()) {
|
|
$pagetype = 'searchresults';
|
|
} else {
|
|
$pagetype = 'other';
|
|
}
|
|
}
|
|
|
|
$this->dataLayer->google_tag_params->ecomm_pagetype = $pagetype;
|
|
$this->dataLayer->google_tag_params->removeNull();
|
|
$this->remarketingGenerated = true;
|
|
}
|
|
}
|
|
|
|
public function getCartActionDataLayer($idProduct, $ipa, $action, $qty)
|
|
{
|
|
if (!in_array($action, array('add', 'remove'))) {
|
|
return null;
|
|
}
|
|
|
|
$product = new Product($idProduct);
|
|
$product->id_product_attribute = $ipa;
|
|
$product->quantity = (int)$qty;
|
|
|
|
$dataLayer = new self($this->module, $this->module->gtmConfig->generalConfig->format);
|
|
$dataLayer->dataLayer->addItem($product, ($action == 'add') ? 'add_to_cart' : 'remove_from_cart');
|
|
|
|
return $dataLayer;
|
|
}
|
|
|
|
protected function getTotalProductPriceFromCart($includeTax = true, $mod = 'total')
|
|
{
|
|
$productTotal = 0.0;
|
|
|
|
$priceField = 'price';
|
|
if ($includeTax) {
|
|
$priceField = 'price_wt';
|
|
}
|
|
|
|
$products = $this->getCartProducts();
|
|
if (is_array($products) && count($products)) {
|
|
foreach ($products as $p) {
|
|
if (isset($p[$priceField])) {
|
|
$qty = 1;
|
|
if ($mod == 'total' && !empty($p['quantity'])) {
|
|
$qty = $p['quantity'];
|
|
}
|
|
|
|
$productTotal += $qty * ((float) $p[$priceField]);
|
|
}
|
|
}
|
|
}
|
|
|
|
return $productTotal;
|
|
}
|
|
|
|
protected function remarketingGetProductIdsFromCart()
|
|
{
|
|
$productsList = array();
|
|
|
|
$products = $this->getCartProducts();
|
|
if (is_array($products) && count($products)) {
|
|
foreach ($products as $product) {
|
|
$productID = EcsGtmProProduct::getInstance()->remarketingGetProductIdentifier($product);
|
|
if ($productID) {
|
|
$productsList[] = $productID;
|
|
}
|
|
}
|
|
}
|
|
|
|
return $productsList;
|
|
}
|
|
|
|
public function getCategoryName($category, $level = null)
|
|
{
|
|
$categoryName = '';
|
|
$categoryId = null;
|
|
$id_lang = $this->getDataLanguage();
|
|
|
|
if (!Validate::isLoadedObject($category)) {
|
|
$categoryId = (int) $category;
|
|
if ($categoryId) {
|
|
$category = new Category($categoryId);
|
|
}
|
|
}
|
|
|
|
if (!Validate::isLoadedObject($category)) {
|
|
return 'category not found ('.$categoryId.')';
|
|
}
|
|
|
|
if (!is_null($level)) {
|
|
while ($category->level_depth > $level) {
|
|
$category = new Category($category->id_parent);
|
|
}
|
|
}
|
|
|
|
switch ($this->module->gtmConfig->dataConfig->category_name) {
|
|
case 'link_rewrite':
|
|
$categoryName = !empty($category->link_rewrite) ? $category->link_rewrite : null;
|
|
break;
|
|
|
|
case 'id':
|
|
$categoryName = $category->id;
|
|
break;
|
|
|
|
default:
|
|
if (Validate::isLoadedObject($category)) {
|
|
if ($this->categoryTree && is_null($level)) {
|
|
$c_parents = $category->getParentsCategories($id_lang);
|
|
$c_parents_names = array();
|
|
foreach ($c_parents as $c_parent) {
|
|
if (!$c_parent['is_root_category']) {
|
|
$c_parents_names[] = $this->cleanString($c_parent['name']);
|
|
}
|
|
}
|
|
$c_parents_names = array_reverse($c_parents_names);
|
|
$categoryName = implode('/', $c_parents_names);
|
|
} else {
|
|
$categoryName = EcsGtmProTools::cleanString($category->getName());
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
|
|
$categoryName = trim($categoryName);
|
|
|
|
if (empty($categoryName)) {
|
|
$categoryName = 'Unknown category name';
|
|
}
|
|
|
|
return $categoryName;
|
|
}
|
|
|
|
public function getDataLanguage()
|
|
{
|
|
return $this->idLang ? $this->idLang : (int) $this->context->language->id;
|
|
}
|
|
|
|
public function generateGtmTag()
|
|
{
|
|
if (!$this->module->isAllowed()) {
|
|
return '';
|
|
}
|
|
|
|
$dataLayerJs = $this->toJson();
|
|
|
|
$preDataLayerJs = null;
|
|
if (is_object($this->module->preDataLayer)) {
|
|
$preDataLayerJs = $this->module->preDataLayer->toJson();
|
|
} else {
|
|
if (isset($this->context->cookie->preDataLayerJs)) {
|
|
$preDataLayerJs = Context::getContext()->cookie->preDataLayerJs;
|
|
unset($this->context->cookie->preDataLayerJs);
|
|
}
|
|
}
|
|
|
|
if ($this->module->isDebugMode()) {
|
|
if ($preDataLayerJs) {
|
|
$this->module->addDebug($preDataLayerJs);
|
|
}
|
|
|
|
$this->module->addDebug($dataLayerJs);
|
|
|
|
if ($this->module->gtmConfig->userIdConfig->async) {
|
|
$this->module->addDebug('<div>[ASYNC USER INFO]</div><div id="ecsgtmpro_debug_ajax">Loading user info datalayer...</div>');
|
|
}
|
|
}
|
|
|
|
if ($this->module->isOrderValidationPage()) {
|
|
$this->module->saveDataLayerInLog($dataLayerJs);
|
|
}
|
|
|
|
$params = array(
|
|
'generalConfig' => $this->module->gtmConfig->generalConfig,
|
|
'userIdConfig' => $this->module->gtmConfig->userIdConfig,
|
|
'preDataLayer' => $preDataLayerJs,
|
|
'dataLayer' => $dataLayerJs,
|
|
'asyncUrl' => $this->context->link->getModuleLink('ecsgtmpro', 'async', array('action' => 'user'), null, null, null, true),
|
|
'eventDlReady' => $this->module->eventDatalayerReady,
|
|
'debug' => $this->module->isDebugMode()
|
|
);
|
|
$this->context->smarty->assign($params);
|
|
|
|
return $params;
|
|
}
|
|
|
|
public function getDataLayer()
|
|
{
|
|
return $this->dataLayer;
|
|
}
|
|
|
|
public function generateOrderConfirmationCode()
|
|
{
|
|
$id_cart = (int)(Tools::getValue('id_cart'));
|
|
$orders = EcsGtmProTools::getOrdersByCartId((int)($id_cart));
|
|
|
|
if ($this->module->isDebugMode()) {
|
|
$this->module->addDebug("[greviewsGenerateOrderConfirmationCode]");
|
|
}
|
|
|
|
$gcrOrderParams = array();
|
|
$gcrOrderParams['merchant_id'] = $this->module->gcrConfig->merchant_id;
|
|
$gcrOrderParams['order_id'] = '';
|
|
$gcrOrderParams['customer_email'] = '';
|
|
$gcrOrderParams['delivery_country'] = '';
|
|
|
|
$deliveryDelay = (int) $this->module->gcrConfig->delivery_delay;
|
|
$gcrOrderParams['estimated_delivery_date'] = date('Y-m-d', strtotime($deliveryDelay . ' weekdays'));
|
|
|
|
|
|
$ordersList = array();
|
|
foreach ($orders as $id_order) {
|
|
$order = new Order($id_order);
|
|
|
|
if (Validate::isLoadedObject($order)) {
|
|
if ($order->current_state != Configuration::get('PS_OS_ERROR')) {
|
|
$ordersList[] = $id_order;
|
|
if (count($ordersList) == 1) {
|
|
$customer = $order->getCustomer();
|
|
if (Validate::isLoadedObject($customer)) {
|
|
$gcrOrderParams['customer_email'] = $customer->email;
|
|
}
|
|
|
|
$delivery_address = new Address($order->id_address_delivery);
|
|
if (Validate::isLoadedObject($delivery_address)) {
|
|
$gcrOrderParams['delivery_country'] = Country::getIsoById($delivery_address->id_country);
|
|
}
|
|
}
|
|
|
|
$ref = $order->reference;
|
|
if (empty($gcrOrderParams['order_id'])) {
|
|
$gcrOrderParams['order_id'] = $ref;
|
|
} else {
|
|
$ids = explode(',', $gcrOrderParams['order_id']);
|
|
if (!in_array($ref, $ids)) {
|
|
$ids[] = $ref;
|
|
$gcrOrderParams['order_id'] = implode(',', $ids);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
$this->context->smarty->assign(array(
|
|
'ecsGtmProGcr' => $gcrOrderParams
|
|
));
|
|
}
|
|
|
|
public function getCartAction($id_product, $id_product_attribute, $action, $qty)
|
|
{
|
|
if ($action != 'add' && $action != 'remove') {
|
|
return null;
|
|
}
|
|
|
|
$product = new Product($id_product);
|
|
$product->id_product_attribute = $id_product_attribute;
|
|
$product->quantity = (int) $qty;
|
|
|
|
$dataLayer = new self($this->module, $this->module->gtmConfig->generalConfig->format);
|
|
$dataLayer->dataLayer->addItem($product, ($action == 'add') ? 'add_to_cart' : 'remove_from_cart');
|
|
|
|
return $dataLayer;
|
|
}
|
|
|
|
public function addSubtotalsFromOrder($ecommerce, $order)
|
|
{
|
|
$revenue = (float) round($order->total_paid_tax_incl, _ECSGTMPRO_PRICE_DECIMAL_);
|
|
$tax = (float) round($order->total_paid_tax_incl - $order->total_paid_tax_excl, _ECSGTMPRO_PRICE_DECIMAL_);
|
|
$shipping = (float) round($order->total_shipping_tax_incl, _ECSGTMPRO_PRICE_DECIMAL_);
|
|
$discounts = (float) round($order->total_discounts_tax_incl, _ECSGTMPRO_PRICE_DECIMAL_);
|
|
|
|
if ($this->isEE()) {
|
|
$ecommerce->revenue = empty($ecommerce->revenue) ? $revenue : $ecommerce->revenue + $revenue;
|
|
}
|
|
if ($this->isGA4()) {
|
|
$ecommerce->value = empty($ecommerce->value) ? $revenue : $ecommerce->value + $revenue;
|
|
}
|
|
|
|
$ecommerce->tax = empty($ecommerce->tax) ? $tax : $ecommerce->tax + $tax;
|
|
$ecommerce->shipping = empty($ecommerce->shipping) ? $shipping : $ecommerce->shipping + $shipping;
|
|
$ecommerce->discounts = empty($ecommerce->discounts) ? $discounts : $ecommerce->discounts + $discounts;
|
|
|
|
if (empty($ecommerce->coupon)) {
|
|
$discounts = $order->getCartRules();
|
|
if (is_array($discounts) && count($discounts) > 0) {
|
|
$ecommerce->coupon = $discounts[0]['id_cart_rule'].'-'.$discounts[0]['name'];
|
|
}
|
|
}
|
|
}
|
|
|
|
public function getCartRulesFromCart($cart)
|
|
{
|
|
if (Validate::isLoadedObject($cart)) {
|
|
$cartRules = $cart->getCartRules();
|
|
if (is_array($cartRules) && count($cartRules) > 0) {
|
|
$this->dataLayer->coupon = $cartRules[0]['id_cart_rule'].'-'.$cartRules[0]['name'];
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
public function generateOrderConfirmationFromCart($idCart, $forceResend = false)
|
|
{
|
|
$orders = EcsGtmProTools::getOrdersByCartId($idCart);
|
|
|
|
$ecommerce = new stdClass();
|
|
$tx = null;
|
|
|
|
$lastOrder = null;
|
|
|
|
$ordersList = array();
|
|
foreach ($orders as $id_order) {
|
|
$order = new Order($id_order);
|
|
|
|
if (Validate::isLoadedObject($order)) {
|
|
if ($order->current_state != Configuration::get('PS_OS_ERROR') && ($forceResend || !EcsGtmProOrder::isSent($id_order, $order->id_shop))) {
|
|
$lastOrder = $order;
|
|
|
|
$ordersList[] = $id_order;
|
|
|
|
$this->module->createGtmOrder($id_order, $order->id_shop);
|
|
|
|
$this->module->orderValidationDetails[] = array('id_order' => $id_order);
|
|
|
|
$orderIdField = $this->module->orderIdField;
|
|
$currentRefOrder = $order->$orderIdField;
|
|
if (empty($tx)) {
|
|
$tx = (string) $currentRefOrder;
|
|
} else {
|
|
$ids = explode(',', $tx);
|
|
if (!in_array($currentRefOrder, $ids)) {
|
|
$ids[] = $currentRefOrder;
|
|
$tx = implode(',', $ids);
|
|
}
|
|
}
|
|
|
|
$this->addSubtotalsFromOrder($ecommerce, $order);
|
|
|
|
$products = $order->getProducts();
|
|
$this->addProductList($products, null, $this->module->gtmConfig->generalConfig->max_category, 'purchase');
|
|
}
|
|
}
|
|
}
|
|
|
|
if (Validate::isLoadedObject($lastOrder)) {
|
|
$pastOrders = EcsGtmProTools::countCustomerOtherOrders($lastOrder->id_customer, $lastOrder->reference);
|
|
$userInfo = new stdClass();
|
|
$userInfo->new = $pastOrders > 0 ? 0 : 1;
|
|
$userInfo->past_orders = $pastOrders;
|
|
$this->customer = $userInfo;
|
|
}
|
|
|
|
if (count($ordersList) > 0) {
|
|
if ($this->isEE()) {
|
|
$ecommerce->id = $tx;
|
|
$this->dataLayer->ecommerce->purchase->actionField = $ecommerce;
|
|
$this->dataLayer->event = "order_confirmation";
|
|
}
|
|
if ($this->isGA4()) {
|
|
$ecommerce->transaction_id = $tx;
|
|
$this->dataLayer->ecommerce->mergeObject($ecommerce);
|
|
$this->dataLayer->event = "purchase";
|
|
}
|
|
|
|
$callbackName = $forceResend ? 'orderresend' : 'orderconfirmation';
|
|
$this->dataLayer->eventCallback = $this->getCallback($callbackName, array(
|
|
'orders' => $ordersList,
|
|
'id_shop' => Context::getContext()->shop->id
|
|
));
|
|
}
|
|
}
|
|
|
|
public function getCallback($type, $params = array())
|
|
{
|
|
$callback = '';
|
|
|
|
$baseurl = $this->context->shop->getBaseURL(true);
|
|
if (empty($baseurl) || Tools::substr($baseurl, -1) != '/') {
|
|
$baseurl = $baseurl.'/';
|
|
}
|
|
$callbackUrl = $baseurl.'index.php?fc=module&module=ecsgtmpro&controller=callback';
|
|
$callbackParams = array();
|
|
|
|
$callbackParams['type'] = $type;
|
|
|
|
if (!is_null($params) && is_array($params) && count($params)) {
|
|
$callbackParams['params'] = $params;
|
|
}
|
|
|
|
if (count($callbackParams)) {
|
|
$callbackParams = urlencode(base64_encode(EcsGtmProTools::jsonEncode($callbackParams)));
|
|
$callbackUrl .= '&p='.$callbackParams;
|
|
$callback = 'function() {
|
|
var ajax = new XMLHttpRequest();
|
|
ajax.open("GET", "'.$callbackUrl.'", true);
|
|
ajax.send();
|
|
}';
|
|
|
|
$callback = preg_replace("/\r|\n/", "", $callback);
|
|
$callback = preg_replace('/\s+/', ' ', $callback);
|
|
}
|
|
|
|
return $callback;
|
|
}
|
|
|
|
protected function getDisplayedProduct()
|
|
{
|
|
$id = (int)Tools::getValue('id_product');
|
|
if (!$id) {
|
|
$smartyProduct = $this->context->smarty->getTemplateVars('product');
|
|
if (Validate::isLoadedObject($smartyProduct)) {
|
|
$id = (int)$smartyProduct->id;
|
|
}
|
|
}
|
|
$product = new Product($id);
|
|
|
|
if (Tools::getValue('id_product_attribute')) {
|
|
$product->id_product_attribute = (int) Tools::getValue('id_product_attribute');
|
|
} elseif (!isset($product->id_product_attribute)) {
|
|
$product->id_product_attribute = 0;
|
|
}
|
|
|
|
return $product;
|
|
}
|
|
|
|
public function generateRefund($order_id, $products = null)
|
|
{
|
|
$order = new Order($order_id);
|
|
if (!Validate::isLoadedObject($order)) {
|
|
return false;
|
|
}
|
|
|
|
$ecommerce = new stdClass();
|
|
if ($this->isEE()) {
|
|
$ecommerce->id = (string) $order->id;
|
|
}
|
|
if ($this->isGA4()) {
|
|
$ecommerce->transaction_id = (string) $order->id;
|
|
}
|
|
$this->addSubtotalsFromOrder($ecommerce, $order);
|
|
|
|
if ($products !== "all" && is_array($products) && count($products)) {
|
|
foreach ($products as $product_key => $qty) {
|
|
$productIdData = explode(',', $product_key);
|
|
$product = new Product($productIdData[0]);
|
|
$product->id_product_attribute = $productIdData[1];
|
|
$product->quantity = $qty;
|
|
$this->dataLayer->addItem($product, 'refund');
|
|
}
|
|
}
|
|
|
|
$this->dataLayer->eventCallback = $this->getCallback("orderrefund", array('order' => $order->id, 'id_shop' => $order->id_shop));
|
|
|
|
if ($this->isEE()) {
|
|
if (!isset($this->dataLayer->refund)) {
|
|
$this->dataLayer->refund = new EcsGtmProRefund();
|
|
}
|
|
$this->dataLayer->refund->actionField = $ecommerce;
|
|
$this->dataLayer->event = "order_refund";
|
|
}
|
|
|
|
if ($this->isGA4()) {
|
|
$this->dataLayer->ecommerce->mergeObject($ecommerce);
|
|
$this->dataLayer->event = "refund";
|
|
}
|
|
}
|
|
}
|