diff --git a/Block/Promotion/Pixel/Code.php b/Block/Promotion/Pixel/Code.php
new file mode 100755
index 00000000..92e9fee4
--- /dev/null
+++ b/Block/Promotion/Pixel/Code.php
@@ -0,0 +1,646 @@
+storeManager = $context->getStoreManager();
+ $this->affirmPixelHelper = $affirmPixelHelper;
+ $this->coreRegistry = $coreRegistry;
+ $this->catalogHelper = $catalogHelper;
+ $this->taxConfig = $taxConfig;
+ $this->configProvider = $configProvider;
+ $this->checkoutSession = $checkoutSession;
+ parent::__construct($context, $data);
+ }
+
+ /**
+ * Render GA tracking scripts
+ *
+ * @return string
+ */
+ protected function _toHtml()
+ {
+ if (!$this->affirmPixelHelper->isTrackPixelEnabledConfig()) {
+ return '';
+ }
+
+ return parent::_toHtml();
+ }
+
+ /**
+ * Get options for
+ *
+ * @return string
+ */
+ public function getOptions()
+ {
+ $options = [];
+ $configProvider = $this->configProvider->getConfig();
+ if ($configProvider['payment'][ConfigProvider::CODE]) {
+ $config = $configProvider['payment'][ConfigProvider::CODE];
+ if ($config && isset($config['script']) && isset($config['apiKeyPublic'])) {
+ $options['script'] = $config['script'];
+ $options['public_api_key'] = $config['apiKeyPublic'];
+ }
+ }
+ return json_encode($options);
+ }
+
+ /**
+ * Returns product data needed for dynamic ads tracking.
+ *
+ * @return array
+ */
+ public function getProductData()
+ {
+ $p = $this->coreRegistry->registry('current_product');
+
+ $data = array();
+ if($p) {
+ $data['name'] = $this->affirmPixelHelper->escapeSingleQuotes($p->getName());
+ $data['productId'] = $this->affirmPixelHelper->escapeSingleQuotes($p->getSku());
+ $data['price'] = Util::formatToCents($this->formatPrice($this->getProductPrice($p)));
+ $data['currency'] = $this->getCurrentCurrencyCode();
+ }
+ return $data;
+ }
+
+ /**
+ * Returns cart data needed for tracking.
+ *
+ * @return array
+ */
+ public function getCartData()
+ {
+ $data = array();
+ $items = $this->checkoutSession->getQuote()->getAllVisibleItems();
+ if($items) {
+ foreach ($items as $item) {
+ $productData = array();
+ $productData['productId'] = $this->affirmPixelHelper->escapeSingleQuotes($item->getSku());
+ $productData['name'] = $this->affirmPixelHelper->escapeSingleQuotes($item->getName());
+ $productData['price'] = Util::formatToCents($item->getPrice());
+ $productData['currency'] = $this->getCurrentCurrencyCode();
+ $productData['quantity'] = $item->getQty();
+ $data[] = $productData;
+ }
+ }
+ return $data;
+ }
+
+ /**
+ * Returns quote data needed for checkout started tracking.
+ *
+ * @return array|null
+ */
+ public function getQuoteData()
+ {
+ $quote= $this->checkoutSession->getQuote();
+ $data = array();
+ if ($quote) {
+ $data['checkoutId'] = $quote->getId();
+ $data['currency'] = $quote->getQuoteCurrencyCode();
+ $data['total'] = Util::formatToCents($quote->getGrandTotal());
+ }
+ return $data;
+
+ }
+
+ /**
+ * Returns quote products data needed for checkout started tracking.
+ *
+ * @return array|null
+ */
+ public function getQuoteProductsData()
+ {
+ $quote= $this->checkoutSession->getQuote();
+ $data = array();
+ if ($quote) {
+ foreach ($quote->getAllVisibleItems() as $item) {
+ $productData = array();
+ $productData['productId'] = $this->affirmPixelHelper->escapeSingleQuotes($item->getSku());
+ $productData['name'] = $this->affirmPixelHelper->escapeSingleQuotes($item->getName());
+ $productData['price'] = Util::formatToCents($item->getPrice());
+ $productData['currency'] = $this->getCurrentCurrencyCode();
+ $productData['quantity'] = $item->getQty();
+ $data[] = $productData;
+ }
+ }
+ return $data;
+
+ }
+
+
+ /**
+ * Returns store object
+ *
+ * @return \Magento\Store\Model\Store
+ */
+ public function getStore()
+ {
+ if ($this->store === null) {
+ $this->store = $this->storeManager->getStore();
+ }
+
+ return $this->store;
+ }
+
+ /**
+ * Returns Store Id
+ *
+ * @return int
+ */
+ public function getStoreId()
+ {
+ if ($this->storeId === null) {
+ $this->storeId = $this->getStore()->getId();
+ }
+
+ return $this->storeId;
+ }
+
+ /**
+ * Returns base currency code
+ * (3 letter currency code like USD, GBP, EUR, etc.)
+ *
+ * @return string
+ */
+ public function getBaseCurrencyCode()
+ {
+ if ($this->baseCurrencyCode === null) {
+ $this->baseCurrencyCode = strtoupper(
+ $this->getStore()->getBaseCurrencyCode()
+ );
+ }
+
+ return $this->baseCurrencyCode;
+ }
+
+ /**
+ * Returns current currency code
+ * (3 letter currency code like USD, GBP, EUR, etc.)
+ *
+ * @return string
+ */
+ public function getCurrentCurrencyCode()
+ {
+ if ($this->currentCurrencyCode === null) {
+ $this->currentCurrencyCode = strtoupper(
+ $this->getStore()->getCurrentCurrencyCode()
+ );
+ }
+
+ return $this->currentCurrencyCode;
+ }
+
+ /**
+ * Returns flag based on "Stores > Cofiguration > Sales > Tax
+ * > Price Display Settings > Display Product Prices In Catalog"
+ * Returns 0 or 1 instead of 1, 2, 3.
+ *
+ * @return int
+ */
+ public function getDisplayTaxFlag()
+ {
+ if ($this->taxDisplayFlag === null) {
+ // Tax Display
+ // 1 - excluding tax
+ // 2 - including tax
+ // 3 - including and excluding tax
+ $flag = $this->taxConfig->getPriceDisplayType($this->getStoreId());
+
+ // 0 means price excluding tax, 1 means price including tax
+ if ($flag == 1) {
+ $this->taxDisplayFlag = 0;
+ } else {
+ $this->taxDisplayFlag = 1;
+ }
+ }
+
+ return $this->taxDisplayFlag;
+ }
+
+ /**
+ * Returns Stores > Cofiguration > Sales > Tax > Calculation Settings
+ * > Catalog Prices configuration value
+ *
+ * @return int
+ */
+ public function getCatalogTaxFlag()
+ {
+ // Are catalog product prices with tax included or excluded?
+ if ($this->taxCatalogFlag === null) {
+ $this->taxCatalogFlag = (int) $this->affirmPixelHelper->getConfig(
+ 'tax/calculation/price_includes_tax',
+ $this->getStoreId()
+ );
+ }
+
+ // 0 means excluded, 1 means included
+ return $this->taxCatalogFlag;
+ }
+
+ /**
+ * Returns product price.
+ *
+ * @param \Magento\Catalog\Model\Product $product
+ * @return string
+ */
+ public function getProductPrice($product)
+ {
+ $price = 0.0;
+
+ switch ($product->getTypeId()) {
+ case 'bundle':
+ $price = $this->getBundleProductPrice($product);
+ break;
+ case 'configurable':
+ $price = $this->getConfigurableProductPrice($product);
+ break;
+ case 'grouped':
+ $price = $this->getGroupedProductPrice($product);
+ break;
+ default:
+ $price = $this->getFinalPrice($product);
+ }
+
+ return $price;
+ }
+
+ /**
+ * Returns bundle product price.
+ *
+ * @param \Magento\Catalog\Model\Product $product
+ * @return string
+ */
+ public function getBundleProductPrice($product)
+ {
+ $includeTax = (bool) $this->getDisplayTaxFlag();
+
+ return $this->getFinalPrice(
+ $product,
+ $product->getPriceModel()->getTotalPrices(
+ $product,
+ 'min',
+ $includeTax,
+ 1
+ )
+ );
+ }
+
+ /**
+ * Returns configurable product price.
+ *
+ * @param \Magento\Catalog\Model\Product $product
+ * @return string
+ */
+ public function getConfigurableProductPrice($product)
+ {
+ if ($product->getFinalPrice() === 0) {
+ $simpleCollection = $product->getTypeInstance()
+ ->getUsedProducts($product);
+
+ foreach ($simpleCollection as $simpleProduct) {
+ if ($simpleProduct->getPrice() > 0) {
+ return $this->getFinalPrice($simpleProduct);
+ }
+ }
+ }
+
+ return $this->getFinalPrice($product);
+ }
+
+ /**
+ * Returns grouped product price.
+ *
+ * @param \Magento\Catalog\Model\Product $product
+ * @return string
+ */
+ public function getGroupedProductPrice($product)
+ {
+ $assocProducts = $product->getTypeInstance(true)
+ ->getAssociatedProductCollection($product)
+ ->addAttributeToSelect('price')
+ ->addAttributeToSelect('tax_class_id')
+ ->addAttributeToSelect('tax_percent');
+
+ $minPrice = INF;
+ foreach ($assocProducts as $assocProduct) {
+ $minPrice = min($minPrice, $this->getFinalPrice($assocProduct));
+ }
+
+ return $minPrice;
+ }
+
+ /**
+ * Returns final price.
+ *
+ * @param \Magento\Catalog\Model\Product $product
+ * @param string $price
+ * @return string
+ */
+ public function getFinalPrice($product, $price = null)
+ {
+ if ($price === null) {
+ $price = $product->getFinalPrice();
+ }
+
+ if ($price === null) {
+ $price = $product->getData('special_price');
+ }
+
+ $productType = $product->getTypeId();
+
+ // 1. Convert to current currency if needed
+
+ // Convert price if base and current currency are not the same
+ // Except for configurable products they already have currency converted
+ if (($this->getBaseCurrencyCode() !== $this->getCurrentCurrencyCode())
+ && $productType != 'configurable'
+ ) {
+ // Convert to from base currency to current currency
+ $price = $this->getStore()->getBaseCurrency()
+ ->convert($price, $this->getCurrentCurrencyCode());
+ }
+
+ // 2. Apply tax if needed
+
+ // Simple, Virtual, Downloadable products price is without tax
+ // Grouped products have associated products without tax
+ // Bundle products price already have tax included/excluded
+ // Configurable products price already have tax included/excluded
+ if ($productType != 'configurable' && $productType != 'bundle') {
+ // If display tax flag is on and catalog tax flag is off
+ if ($this->getDisplayTaxFlag() && !$this->getCatalogTaxFlag()) {
+ $price = $this->catalogHelper->getTaxPrice(
+ $product,
+ $price,
+ true,
+ null,
+ null,
+ null,
+ $this->getStoreId(),
+ false,
+ false
+ );
+ }
+ }
+
+ // Case when catalog prices are with tax but display tax is set to
+ // to exclude tax. Applies for all products except for bundle
+ if ($productType != 'bundle') {
+ // If display tax flag is off and catalog tax flag is on
+ if (!$this->getDisplayTaxFlag() && $this->getCatalogTaxFlag()) {
+ $price = $this->catalogHelper->getTaxPrice(
+ $product,
+ $price,
+ false,
+ null,
+ null,
+ null,
+ $this->getStoreId(),
+ true,
+ false
+ );
+ }
+ }
+
+ return $price;
+ }
+
+ /**
+ * Returns formated price.
+ *
+ * @param string $price
+ * @param string $currencyCode
+ * @return string
+ */
+ public function formatPrice($price, $currencyCode = '')
+ {
+ $formatedPrice = number_format($price, 2, '.', '');
+
+ if ($currencyCode) {
+ return $formatedPrice . ' ' . $currencyCode;
+ } else {
+ return $formatedPrice;
+ }
+ }
+
+ /**
+ * Returns is pixel placement for search query enabled
+ *
+ * @return bool
+ */
+ public function isSearchTrackPixelEnabled()
+ {
+ return $this->affirmPixelHelper->isSearchTrackPixelEnabledConfig();
+ }
+
+ /**
+ * Returns is pixel placement for product list page enabled
+ *
+ * @return bool
+ */
+ public function isProductListTrackPixelEnabled()
+ {
+ return $this->affirmPixelHelper->isProductListTrackPixelEnabledConfig();
+ }
+
+ /**
+ * Returns is pixel placement for product page enabled
+ *
+ * @return bool
+ */
+ public function isProductViewTrackPixelEnabled()
+ {
+ return $this->affirmPixelHelper->isProductViewTrackPixelEnabledConfig();
+ }
+
+ /**
+ * Returns is pixel placement for add to cart action enabled
+ *
+ * @return bool
+ */
+ public function isAddCartTrackPixelEnabled()
+ {
+ return $this->affirmPixelHelper->isAddCartTrackPixelEnabledConfig();
+ }
+
+ /**
+ * Returns is pixel placement for checkout start action enabled
+ *
+ * @return bool
+ */
+ public function isAddChkStartTrackPixelEnabled()
+ {
+ return $this->affirmPixelHelper->isAddChkStartTrackPixelEnabledConfig();
+ }
+
+ /**
+ * Returns category data needed for tracking.
+ *
+ * @return array
+ */
+ public function getCategoryData()
+ {
+ $_category = $this->coreRegistry->registry('current_category');
+ $data = array();
+ if ($_category) {
+ $data['categoryId'] = $_category->getId();
+ $data['categoryName'] = $_category->getName();
+ }
+ return $data;
+ }
+
+ /**
+ * get query string
+ *
+ * @return string
+ */
+ public function getQueryString()
+ {
+ return $this->getRequest()->getParam('q');
+ }
+}
diff --git a/Block/Promotion/Pixel/Confirm.php b/Block/Promotion/Pixel/Confirm.php
index b5724dcf..b8dbf46f 100644
--- a/Block/Promotion/Pixel/Confirm.php
+++ b/Block/Promotion/Pixel/Confirm.php
@@ -45,7 +45,7 @@
/**
* Class Confirm
*
- * @package Astound\Affirm\Block\Promotion
+ * @package Astound\Affirm\Block\Pixel
*/
class Confirm extends \Magento\Framework\View\Element\Template
{
@@ -142,7 +142,7 @@ public function getOrdersTrackingCode()
*/
protected function _toHtml()
{
- if (!$this->affirmPixelHelper->isAffirmAnalyticsAvailable()) {
+ if (!$this->affirmPixelHelper->isCheckoutSuccessPixelEnabledConfig()) {
return '';
}
@@ -163,7 +163,6 @@ public function getOptions()
if ($config && isset($config['script']) && isset($config['apiKeyPublic'])) {
$options['script'] = $config['script'];
$options['public_api_key'] = $config['apiKeyPublic'];
- $options['sessionId'] = ($this->getCustomerSessionId())? $this->getCustomerSessionId() : '';
}
}
return json_encode($options);
diff --git a/Helper/Pixel.php b/Helper/Pixel.php
index 5be48e20..9bd1d692 100644
--- a/Helper/Pixel.php
+++ b/Helper/Pixel.php
@@ -66,22 +66,110 @@ public function __construct(
$this->affirmPaymentConfig = $configAffirm;
}
+ public function getDateMicrotime()
+ {
+ $microtime = explode(' ', microtime());
+ $msec = $microtime[0];
+ $msecArray = explode('.', $msec);
+ $date = date('Y-m-d-H-i-s') . '-' . $msecArray[1];
+ return $date;
+ }
+
+ /**
+ * Returns is pixel enabled
+ *
+ * @return bool
+ */
+ public function isTrackPixelEnabledConfig()
+ {
+ return $this->affirmPaymentConfig->getPixelValue('enabled');
+ }
+
/**
- * Get pixel active status for confirm page
+ * Returns is pixel placement for search query enabled
*
+ * @return bool
+ */
+ public function isSearchTrackPixelEnabledConfig()
+ {
+ return $this->affirmPaymentConfig->getPixelValue('add_search');
+ }
+
+ /**
+ * Returns is pixel placement for product list page enabled
+ *
+ * @return bool
+ */
+ public function isProductListTrackPixelEnabledConfig()
+ {
+ return $this->affirmPaymentConfig->getPixelValue('add_product_list');
+ }
+
+ /**
+ * Returns is pixel placement for product page enabled
+ *
+ * @return bool
+ */
+ public function isProductViewTrackPixelEnabledConfig()
+ {
+ return $this->affirmPaymentConfig->getPixelValue('add_product_view');
+ }
+
+ /**
+ * Returns is pixel placement for add to cart action enabled
+ *
+ * @return bool
+ */
+ public function isAddCartTrackPixelEnabledConfig()
+ {
+ return $this->affirmPaymentConfig->getPixelValue('add_cart');
+ }
+
+ /**
+ * Returns is pixel placement for checkout start action enabled
+ *
+ * @return bool
+ */
+ public function isAddChkStartTrackPixelEnabledConfig()
+ {
+ return $this->affirmPaymentConfig->getPixelValue('add_checkout_start');
+ }
+
+
+ /**
+ * Returns is pixel placement for confirmation page enabled
+ *
+ * @return bool
+ */
+ public function isCheckoutSuccessPixelEnabledConfig()
+ {
+ return $this->affirmPaymentConfig->getPixelValue('add_checkout_success');
+ }
+
+ /**
+ * Add slashes to string and prepares string for javascript.
+ *
+ * @param string $str
* @return string
*/
- public function isAffirmAnalyticsAvailable()
+ public function escapeSingleQuotes($str)
{
- return $this->affirmPaymentConfig->getPixelValue('active_confirm');
+ return str_replace("'", "\'", $str);
}
- public function getDateMicrotime()
+ /**
+ * Based on provided configuration path returns configuration value.
+ *
+ * @param string $configPath
+ * @param string|int $scope
+ * @return string
+ */
+ public function getConfig($configPath, $scope = 'default')
{
- $microtime = explode(' ', microtime());
- $msec = $microtime[0];
- $msecArray = explode('.', $msec);
- $date = date('Y-m-d-H-i-s') . '-' . $msecArray[1];
- return $date;
+ return $this->scopeConfig->getValue(
+ $configPath,
+ \Magento\Store\Model\ScopeInterface::SCOPE_STORE,
+ $scope
+ );
}
}
diff --git a/composer.json b/composer.json
index 61dadc20..639bdd77 100644
--- a/composer.json
+++ b/composer.json
@@ -2,7 +2,7 @@
"name": "affirm/magento2",
"description": "Affirm's extension for the Magento 2 https://www.affirm.com/",
"type": "magento2-module",
- "version": "2.1.0",
+ "version": "2.1.1",
"license": [
"BSD-3-Clause"
],
diff --git a/etc/adminhtml/system.xml b/etc/adminhtml/system.xml
index 77f8e71c..a5dc0e3e 100644
--- a/etc/adminhtml/system.xml
+++ b/etc/adminhtml/system.xml
@@ -287,9 +287,40 @@
-
-
+
+
Magento\Config\Model\Config\Source\Yesno
+ Enable affirm tracking pixels. In addition to enabling this config, please do enable pixel for specific actions using config options listed below.
+
+
+
+ Magento\Config\Model\Config\Source\Yesno
+ Enable add to cart tracking
+
+
+
+ Magento\Config\Model\Config\Source\Yesno
+ Enable search tracking
+
+
+
+ Magento\Config\Model\Config\Source\Yesno
+ Enable product tracking
+
+
+
+ Magento\Config\Model\Config\Source\Yesno
+ Enable product list tracking
+
+
+
+ Magento\Config\Model\Config\Source\Yesno
+ Enable checkout start tracking
+
+
+
+ Magento\Config\Model\Config\Source\Yesno
+ Enable checkout success tracking
diff --git a/etc/module.xml b/etc/module.xml
index 3816f17c..01d7e127 100644
--- a/etc/module.xml
+++ b/etc/module.xml
@@ -10,7 +10,7 @@
*/
-->
-
+
diff --git a/view/frontend/layout/catalog_category_view.xml b/view/frontend/layout/catalog_category_view.xml
index 0c2c648b..80ab8b86 100644
--- a/view/frontend/layout/catalog_category_view.xml
+++ b/view/frontend/layout/catalog_category_view.xml
@@ -51,5 +51,13 @@
+
+
+