Jump to content

Real-time listening to the cart by the module - AJAX


mati7716

Recommended Posts

I created a module that displays to the customer the amount required for free delivery.

The module displays the missing values correctly, the problem is that when the customer increases the number of products in the basket, the module does not update in real time, only after restarting the page

Free shipping is over $50.
1. The customer adds a product to the cart for $20 and then goes to it
2. The customer is in the cart and a message is displayed that $30 is missing for free delivery.
3. The customer adds a second product to the cart while still in it (clicks the + button)
4. The module does not immediately change the value that the customer is missing $10, this is visible after refreshing the page (F5)

 

What should I do to make the module update in real time and not after refreshing the page?

 

Module code:

 

<?php
if (!defined('_PS_VERSION_')) {
    exit;
}

class FreeDeliveryIndicator extends Module
{
    public function __construct()
    {
        $this->name = 'freedeliveryindicator';
        $this->tab = 'shipping_logistics';
        $this->version = '1.0.0';
        $this->author = 'Name';
        $this->need_instance = 0;
        $this->ps_versions_compliancy = ['min' => '1.7', 'max' => _PS_VERSION_];
        $this->bootstrap = true;

        parent::__construct();

        $this->displayName = $this->l('Wskaźnik Darmowej Dostawy');
        $this->description = $this->l('Pokazuje klientom, ile brakuje do darmowej dostawy.');

        $this->confirmUninstall = $this->l('Czy na pewno chcesz odinstalować?');
    }

    public function install()
    {
        return parent::install() &&
            $this->registerHook('displayShoppingCartFooter') &&
            $this->registerHook('displayHeader') &&
            Configuration::updateValue('FREESHIPPINGLIMIT', 80);
    }

    public function uninstall()
    {
        Configuration::deleteByName('FREESHIPPINGLIMIT');
        return parent::uninstall();
    }

    public function getContent()
    {
        $output = null;

        if (Tools::isSubmit('submit'.$this->name)) {
            $freeShippingLimit = (float)Tools::getValue('FREESHIPPINGLIMIT');
            if (!$freeShippingLimit || empty($freeShippingLimit) || !Validate::isFloat($freeShippingLimit)) {
                $output .= $this->displayError($this->l('Invalid Configuration value'));
            } else {
                Configuration::updateValue('FREESHIPPINGLIMIT', $freeShippingLimit);
                $output .= $this->displayConfirmation($this->l('Settings updated'));
            }
        }
        return $output.$this->displayForm();
    }

    private function displayForm()
    {
        // Get default configuration value
        $default_limit = (float)Configuration::get('FREESHIPPINGLIMIT');

        // Build form
        $fields_form[0]['form'] = [
            'legend' => [
                'title' => $this->l('Settings'),
            ],
            'input' => [
                [
                    'type' => 'text',
                    'label' => $this->l('Free shipping limit'),
                    'name' => 'FREESHIPPINGLIMIT',
                    'size' => 7,
                    'required' => true,
                    'desc' => $this->l('Set the total amount for free shipping.'),
                ],
            ],
            'submit' => [
                'title' => $this->l('Save'),
                'class' => 'btn btn-default pull-right'
            ]
        ];

        $helper = new HelperForm();
        $helper->module = $this;
        $helper->name_controller = $this->name;
        $helper->token = Tools::getAdminTokenLite('AdminModules');
        $helper->currentIndex = AdminController::$currentIndex.'&configure='.$this->name;
        $helper->title = $this->displayName;
        $helper->submit_action = 'submit'.$this->name;
        $helper->fields_value['FREESHIPPINGLIMIT'] = $default_limit;

        return $helper->generateForm($fields_form);
    }

    public function hookDisplayHeader()
    {
        $this->context->controller->addCSS($this->_path.'views/css/progress-bar.css');
    $this->context->controller->addJS($this->_path.'views/js/front.js');
    }

    public function hookDisplayShoppingCartFooter($params)
    {
        $cart = $params['cart'];
        $total = $cart->getOrderTotal(true, Cart::BOTH_WITHOUT_SHIPPING);
        $freeShippingLimit = (float)Configuration::get('FREESHIPPINGLIMIT');
        $amountLeftForFreeShipping = max(0, $freeShippingLimit - $total);

        $progressPercentage = $total / $freeShippingLimit * 100;
        $progressPercentage = min(100, max(0, $progressPercentage));

        $this->context->smarty->assign([
            'amountLeftForFreeShipping' => $amountLeftForFreeShipping,
            'progressPercentage' => $progressPercentage,
        ]);

        return $this->display(__FILE__, 'views/templates/hook/indicator.tpl');
    }
}

Link to comment
Share on other sites

Hi.

Unfortunately, I can't see the TPL file and I don't know the id of the element for ajax update, so in short.

Module (update):

public function hookDisplayHeader()
{
    if ($this->context->controller->php_self == 'cart') {
        $this->context->controller->addCSS($this->_path.'views/css/progress-bar.css');
        $this->context->controller->addJS($this->_path.'views/js/front.js');
        $ajax = $this->context->shop->getBaseURL(true).'modules/'.$this->name.'/ajax/ajax.php?token='.Tools::encrypt($this->name.'/ajax.php');
        $jsDef = [
            'freedeliveryindicator_ajaxcart' => $ajax,
        ];
        Media::addJsDef($jsDef);
    }
} 

public function hookDisplayShoppingCartFooter()
{
    $cart = new Cart($this->context->cart->id);
    $total = $cart->getOrderTotal(true, Cart::BOTH_WITHOUT_SHIPPING);
    $freeShippingLimit = (float)Configuration::get('FREESHIPPINGLIMIT');
    $amountLeftForFreeShipping = max(0, $freeShippingLimit - $total);

    $progressPercentage = $total / $freeShippingLimit * 100;
    $progressPercentage = min(100, max(0, $progressPercentage));

    $this->context->smarty->assign([
        'amountLeftForFreeShipping' => $amountLeftForFreeShipping,
        'progressPercentage' => $progressPercentage,
    ]);

    return $this->display(__FILE__, 'views/templates/hook/indicator.tpl');
}

 

AJAX PHP ($this->_path.'ajax/ajax.php'):

<?php
header("Access-Control-Allow-Origin: *");

include('../../../config/config.inc.php');
include('../../../init.php');

$module_name = 'freedeliveryindicator';

$token = pSQL(Tools::encrypt($module_name.'/ajax.php'));
$token_url = pSQL(Tools::getValue('token'));
$context = Context::getContext();

$module = Module::getInstanceByName($module_name);
$db = Db::getInstance();

if ($token != $token_url || !Module::isInstalled($module_name)) {
    echo($module->l('AJAX error'));
}


if ($module->active && Tools::getValue('action') == 'updateDisplayShoppingCartFooter') {
    $cart = new Cart($context->cart->id);
    $total = $cart->getOrderTotal(true, Cart::BOTH_WITHOUT_SHIPPING);
    $freeShippingLimit = (float)Configuration::get('FREESHIPPINGLIMIT');
    $amountLeftForFreeShipping = max(0, $freeShippingLimit - $total);

    $progressPercentage = $total / $freeShippingLimit * 100;
    $progressPercentage = min(100, max(0, $progressPercentage));

    $returnParams = array();
    $returnParams['amountLeftForFreeShipping'] = $amountLeftForFreeShipping;
    $returnParams['progressPercentage'] = $progressPercentage;

    echo json_encode($returnParams);
}

front.js (update):

$(document).ajaxStart(function() {
  if(typeof prestashop !== 'undefined') {
    prestashop.on(
        'updateCart',
        function (event) {
          if (event && event.reason && typeof event.resp !== 'undefined' && !event.resp.hasError) {
            updateDisplayShoppingCartFooter();
          }
        }
    );
  }
});

function updateDisplayShoppingCartFooter() {
  // call ajax function
  $.ajax({
    type: "POST",
    url: freedeliveryindicator_ajaxcart, // defined in module.php
    data: {
        action: 'updateDisplayShoppingCartFooter', // call action ajax.php
    },
    async: false,
    cache: false,
    dataType: 'json',
    success: function(data) {
      if (data !== '') { 
        if (data['amountLeftForFreeShipping'] !== '' && data['progressPercentage'] !== '') {
            // here update values in TPL file with element id or name ...
            $('#amountLeftForFreeShipping').text(data['amountLeftForFreeShipping']);
            $('#progressPercentage').attr('style', 'width:'+data['progressPercentage']+'%');
            if (data['progressPercentage'] < 100) {
                $('#freedeliveryindicator').show();
            } else {
                $('#freedeliveryindicator').hide();
            } 
        }  
      } 
    }
  });
}

 

Indicator.tpl (update):

<div id="freedeliveryindicator" style="{if $progressPercentage < 100}display:block;{else}display:none;{/if}">
    {if $amountLeftForFreeShipping > 0}
        <div class="free-delivery-info">
            {l s='Still missing' mod='freedeliveryindicator'} <span id="amountLeftForFreeShipping">{Tools::displayPrice($amountLeftForFreeShipping)}</span> {l s='for free delivery' mod='freedeliveryindicator'}
        </div>
        <div class="progress-bar-container">
            <div id="progressPercentage" class="progress-bar" style="width: {$progressPercentage}%;"></div>
        </div>
    {/if}
</div>

 

Edited by ps8moduly.cz
added indicator.tpl (see edit history)
Link to comment
Share on other sites

I updated the code according to your instructions, and the shopping cart does not work.

indicator.tpl ->

 

 

{if $amountLeftForFreeShipping > 0}
    <div class="free-delivery-info">
        Brakuje jeszcze {$amountLeftForFreeShipping} zł do darmowej dostawy
    </div>
    <div class="progress-bar-container">
        <div class="progress-bar" style="width: {$progressPercentage}%;">
        </div>
    </div>
{/if}
 

Link to comment
Share on other sites

Hi.
When I look in your module, none of the changes I gave you here exist.
There is no ajax.php file, no front.js, no modified hookDisplayHeader and more.

I also don't see a treatment for carriers where shipping will be free. It only calculates and displays the number remaining until free shipping. This must be stored in the delivery configuration.

obrazek.thumb.png.6c6adf788136ce1db791d79067a442ae.png

Edited by ps8moduly.cz (see edit history)
Link to comment
Share on other sites

It is necessary to understand that in the TPL you do not have the id of the elements that JavaScript should overwrite for you, and the values from the basket are not loaded correctly.

Here you have a module that does what you want, including translation and for different currencies (the default price in the e-shop is taken).

freedeliveryindicator.zip

Install the module normally and you will be amazed 😄
Don't forget to clear the cache, otherwise javascript won't load correctly.

Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
×
×
  • Create New...