Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
149 changes: 149 additions & 0 deletions ViewModel/DataLayer.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
<?php
declare(strict_types=1);

namespace Salesfire\Salesfire\ViewModel;

use Magento\Catalog\Helper\Data\Proxy as TaxHelper;
use Magento\Checkout\Model\Session as CheckoutSession;;
use Magento\Framework\App\RequestInterface;
use Magento\Framework\Registry;
use Magento\Framework\View\Element\Block\ArgumentInterface;
use Salesfire\Formatter as SalesfireFormatter;
use Salesfire\Salesfire\Block\Script as SalesfireScript;
use Salesfire\Salesfire\Helper\Data as SalesfireHelper;
use Salesfire\Types\Product as SalesfireProductType;
use Salesfire\Types\Transaction as SalesfireTransactionType;

class DataLayer implements ArgumentInterface
{
/** @var TaxHelper */
private $taxHelper;

/** @var CheckoutSession $checkoutSession */
private $checkoutSession;

/** @var RequestInterface */
private $request;

/** @var Registry */
private $registry;

/** @var SalesfireHelper $helper */
private $helper;

public function __construct(
TaxHelper $taxHelper,
CheckoutSession $checkoutSession,
RequestInterface $request,
Registry $registry,
SalesfireHelper $helper
) {
$this->taxHelper = $taxHelper;
$this->checkoutSession = $checkoutSession;
$this->request = $request;
$this->registry = $registry;
$this->helper = $helper;
}

public function getSiteId()
{
return $this->helper->getSiteId();
}

public function getData()
{
if (!($siteId = $this->getSiteId())) {
return json_encode([]);
}

/**
* The logic is functionally-equivalent to the _toHtml() function of the custom Salesfire block class herein.
* Additional comments have been added to highlight specifically where customisations have been made.
* @see SalesfireScript::_toHtml()
*/

$formatter = new SalesfireFormatter($siteId);
$formatter->addPlatform('magento2');

if ($this->request->getFullActionName() == 'checkout_onepage_success'
&& $order = $this->checkoutSession->getLastRealOrder() // customisation: use checkout session directly rather than class-level helper function
) {
$transaction = new SalesfireTransactionType([
'id' => $order->getIncrementId(),
'shipping' => round((float)$order->getShippingAmount(), 2), // customisation: float type casting
'currency' => $order->getOrderCurrencyCode(),
'coupon' => $order->getCouponCode(),
]);

foreach ($order->getAllVisibleItems() as $product) {
$variant = '';
$options = $product->getProductOptions();
$parent_product_id = $product_id = $product->getProductId();

if ($product->getHasChildren()) {
foreach ($product->getChildrenItems() as $child) {
$product_id = $child->getProductId();
}
}

if (!empty($options) && !empty($options['attribute_info'])) {
$variant = implode(', ', array_map(function ($item) {
return $item['label'].': '.$item['value'];
}, $options['attribute_info']));
}

$quantity = $product->getQtyOrdered() ?? 1;
$pricing = $this->calculateItemPriceAndTax($product, $quantity);

$transaction->addProduct(new SalesfireProductType([
'sku' => $product_id,
'parent_sku' => $parent_product_id,
'name' => $product->getName(),
'price' => round((float)$pricing['price'], 2), // customisation: float type casting
'tax' => round((float)$pricing['tax'], 2), // customisation: float type casting
'quantity' => round((float)$quantity, 2), // customisation: float type casting
'variant' => $variant,
]));
}

$formatter->addTransaction($transaction);
}

if ($product = $this->registry->registry('product')) { // customisation: use registry directly rather than class-level helper function
// Calculate product tax
$price = round((float)$this->taxHelper->getTaxPrice($product, $product->getFinalPrice(), false), 2); // customisation: float type casting
$tax = round((float)$this->taxHelper->getTaxPrice($product, $product->getFinalPrice(), true), 2) - $price; // customisation: float type casting

$formatter->addProductView(new SalesfireProductType([
'sku' => $product->getId(),
'parent_sku' => $product->getId(),
'name' => $product->getName(),
'price' => $price,
'tax' => $tax,
]));
}

// customisation: return only the JSON as the template is responsible for pushing the data to the sfDataLayer
return $formatter->toJson();
}

/**
* This function has been copied as-is from the custom Salesfire block class, save for the function visibility which
* has been set to public rather than private for improved extensibility.
*/
public function calculateItemPriceAndTax($product, $quantity)
{
// Row totals represent all items in the order line (e.g., if qty=4, this is the total for all 4)
$rowTotal = $product->getRowTotal() ?: 0;
$rowTax = $product->getTaxAmount() ?: 0;

if ($quantity <= 0) {
return ['price' => 0, 'tax' => 0];
}

return [
'price' => $rowTotal / $quantity,
'tax' => $rowTax / $quantity,
];
}
}
23 changes: 23 additions & 0 deletions view/frontend/layout/hyva_default.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<?xml version="1.0"?>
<page xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/page_configuration.xsd">
<body>
<referenceBlock name="head.additional">
<block name="salesfire_script"
ifconfig="salesfire/general/is_enabled"
template="Salesfire_Salesfire::sfgetid.phtml"/>
<block name="salesfire_script.datalayer"
ifconfig="salesfire/general/is_enabled"
template="Salesfire_Salesfire::sf-datalayer.phtml"/>
<block name="salesfire_script.cdn"
ifconfig="salesfire/general/is_enabled"
template="Salesfire_Salesfire::sf-cdn.phtml">
<arguments>
<argument name="url" xsi:type="string">https://cdn.salesfire.co.uk/code/</argument>
<argument name="async" xsi:type="boolean">false</argument>
<argument name="defer" xsi:type="boolean">true</argument>
</arguments>
</block>
</referenceBlock>
</body>
</page>
32 changes: 32 additions & 0 deletions view/frontend/templates/sf-cdn.phtml
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
<?php
declare(strict_types=1);

use Hyva\Theme\Model\ViewModelRegistry;
use Hyva\Theme\ViewModel\HyvaCsp;
use Magento\Framework\Escaper;
use Magento\Framework\View\Element\Template;
use Salesfire\Salesfire\ViewModel\DataLayer;

/** @var Escaper $escaper */
/** @var HyvaCsp $hyvaCsp */
/** @var Template $block */
if (!($url = $block->getData('url'))) {
return;
}

/** @var ViewModelRegistry $viewModels */
/** @var DataLayer $dataLayer */
$dataLayer = $viewModels->require(DataLayer::class);
$siteId = $dataLayer->getSiteId();

if (!$siteId) {
return;
}

$url .= $siteId . '.js';
?>
<script src="<?= $escaper->escapeUrl($url); ?>"
<?php if ($block->getData('async')): ?>async<?php endif; ?>
<?php if ($block->getData('defer')): ?>defer<?php endif; ?>>
</script>
<?php isset($hyvaCsp) && $hyvaCsp->registerInlineScript(); ?>
30 changes: 30 additions & 0 deletions view/frontend/templates/sf-datalayer.phtml
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
<?php
declare(strict_types=1);

use Hyva\Theme\Model\ViewModelRegistry;
use Hyva\Theme\ViewModel\HyvaCsp;
use Magento\Framework\Escaper;
use Magento\Framework\View\Element\Template;
use Salesfire\Salesfire\ViewModel\DataLayer;

/** @var Escaper $escaper */
/** @var Template $block */
/** @var HyvaCsp $hyvaCsp */
/** @var ViewModelRegistry $viewModels */
/** @var DataLayer $dataLayer */
$dataLayer = $viewModels->require(DataLayer::class);
$data = $dataLayer->getData();

if (!$data) {
return;
}
?>
<script>
window.addEventListener('DOMContentLoaded', () => {
sfDataLayer = window.sfDataLayer || [];

<?php /** @link https://developer.adobe.com/commerce/php/development/security/cross-site-scripting/#phtml-templates */ ?>
sfDataLayer.push(<?= /** @noEscape */ $data; ?>);
});
</script>
<?php isset($hyvaCsp) && $hyvaCsp->registerInlineScript(); ?>
42 changes: 42 additions & 0 deletions view/frontend/templates/sfgetid.phtml
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
<?php
declare(strict_types=1);

use Hyva\Theme\ViewModel\HyvaCsp;
use Magento\Framework\Escaper;
use Magento\Framework\View\Element\Template;

/** @var Escaper $escaper */
/** @var Template $block */
/** @var HyvaCsp $hyvaCsp */
?>
<script>
window.addEventListener('DOMContentLoaded', async () => {
let sfCuid = localStorage.getItem('sf_cuid') || null;

if (!sfCuid) {
sfCuid = await fetch(
`${BASE_URL}salesfire/ajax/sfgetid`,
{
method: 'GET',
headers: {
'Content-Type': 'application/json',
},
}).then(async response => await response.json())
.catch(error => {
console.error('Error: ' + error);
return null;
});
}

if (sfCuid) {
localStorage.setItem('sf_cuid', sfCuid);
window.sfDataLayer = window.sfDataLayer || [];
window.sfDataLayer.push({
session: {
id: sfCuid,
},
});
}
});
</script>
<?php isset($hyvaCsp) && $hyvaCsp->registerInlineScript(); ?>