* @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('
[ASYNC USER INFO]
Loading user info datalayer...
'); } } 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"; } } }