5

I want to pass my custom_price changed via jQuery to my Observer in Magento 2 to have the correct price in my cart.

My /Observer/CustomPrice.php:

<?php
    namespace Vendor_Name\Module_Name\Observer;

    use Magento\Framework\Event\ObserverInterface;
    use Magento\Framework\App\RequestInterface;

    class CustomPrice implements ObserverInterface
    {
        public function execute(\Magento\Framework\Event\Observer $observer) {
            $item = $observer->getEvent()->getData('quote_item');         
            $item = ( $item->getParentItem() ? $item->getParentItem() : $item );
            $price = 123; // CUSTOM_PRICE variable HERE instead of "123"
            $item->setCustomPrice($price);
            $item->setOriginalCustomPrice($price);
            $item->getProduct()->setIsSuperMode(true);
        }

    }
?>

Excerpt of my JS script /view/frontend/web/product.js:

require([ 'jquery'], function($){
$(document).ready(function () {

//... price calculations
custom_price = price + product_attribute_value
$("#custom_price").html(custom_price);

};
};

Edit for completion: My etc/frontend/events.xml:

<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Event/etc/events.xsd">
    <event name="checkout_cart_product_add_after">
        <observer name="customprice" instance="Vendor_Name\Module_Name\Observer\CustomPrice" />
    </event>
</config>

My question is: How to replace the "123" value within the observer with my "custom_price" value from the jQuery calculations? (I know this is not the safest way to build up this thing on client site, but it should be fine since every price is getting checked manually after customer checkout).

Further comments:

  1. The Observer is working fine with "123"
  2. Using Magento 2.1.3

I also have a working extension for Magento 2.1 which does this without any Observer (only Controller/Cart/Add.php). I have still no clue how this is possible - trying to learn M2. After my update to 2.1.3 the functionality stopped working. An observer seems to be the right way to go for me. What do you think?


First attempt on Khoas answer: (Thanks for the fast reply!)

My /view/frontend/templates/block.phtml:

<form>
 <input type="hidden" name="custom_price" value="" id="custom_price_cal">
</form>

Excerpt of my JS Script /view/frontend/web/product.js:

require([ 'jquery'], function($){
$(document).ready(function () {

//... price calculations

var price =  90;
var product_attribute_value = 430;
custom_price = price + product_attribute_value;
console.log(custom_price);
$('#custom_price_cal').val(custom_price);

});
});

My /Observer/CustomPrice.php:

<?php

    namespace Vendor_Name\Module_Name\Observer;

    use Magento\Framework\Event\ObserverInterface;
    use Magento\Framework\App\RequestInterface;

    class CustomPrice implements ObserverInterface
    {
        public function __construct(
    \Magento\Framework\App\RequestInterface $request
    )
    {
        $this->_request = $request;
    }

        public function execute(\Magento\Framework\Event\Observer $observer) {
            $item = $observer->getEvent()->getData('quote_item');         
            $item = ( $item->getParentItem() ? $item->getParentItem() : $item );
            $price = $this->_request->getParam('custom_price');
            $item->setCustomPrice($price);
            $item->setOriginalCustomPrice($price);
            $item->getProduct()->setIsSuperMode(true);
        }

    }
?>

Making these changes the custom_price does not appear in cart right now. What am I missing out?


My /Controller/Cart/Add.php (how it has worked in 2.1)

<?php
/**
 *
 * Copyright © 2016 Magento. All rights reserved.
 * See COPYING.txt for license details.
 */
namespace Vendor_Name\Module_Name\Controller\Cart;

use Magento\Catalog\Api\ProductRepositoryInterface;
use Magento\Checkout\Model\Cart as CustomerCart;
use Magento\Framework\Exception\NoSuchEntityException;

/**
 * @SuppressWarnings(PHPMD.CouplingBetweenObjects)
 */
class Add extends \Magento\Checkout\Controller\Cart
{
    /**
     * @var ProductRepositoryInterface
     */
    protected $productRepository;

    /**
     * @param \Magento\Framework\App\Action\Context $context
     * @param \Magento\Framework\App\Config\ScopeConfigInterface $scopeConfig
     * @param \Magento\Checkout\Model\Session $checkoutSession
     * @param \Magento\Store\Model\StoreManagerInterface $storeManager
     * @param \Magento\Framework\Data\Form\FormKey\Validator $formKeyValidator
     * @param CustomerCart $cart
     * @param ProductRepositoryInterface $productRepository
     * @codeCoverageIgnore
     */
    public function __construct(
        \Magento\Framework\App\Action\Context $context,
        \Magento\Framework\App\Config\ScopeConfigInterface $scopeConfig,
        \Magento\Checkout\Model\Session $checkoutSession,
        \Magento\Store\Model\StoreManagerInterface $storeManager,
        \Magento\Framework\Data\Form\FormKey\Validator $formKeyValidator,
        CustomerCart $cart,
        ProductRepositoryInterface $productRepository
    ) {
        parent::__construct(
            $context,
            $scopeConfig,
            $checkoutSession,
            $storeManager,
            $formKeyValidator,
            $cart
        );
        $this->productRepository = $productRepository;
    }

    /**
     * Initialize product instance from request data
     *
     * @return \Magento\Catalog\Model\Product|false
     */
    protected function _initProduct()
    {
        $productId = (int)$this->getRequest()->getParam('product');
        if ($productId) {
            $storeId = $this->_objectManager->get('Magento\Store\Model\StoreManagerInterface')->getStore()->getId();
            try {
                return $this->productRepository->getById($productId, false, $storeId);
            } catch (NoSuchEntityException $e) {
                return false;
            }
        }
        return false;
    }

    /**
     * Add product to shopping cart action
     *
     * @return \Magento\Framework\Controller\Result\Redirect
     * @SuppressWarnings(PHPMD.CyclomaticComplexity)
     */
    public function execute()
    {
        if (!$this->_formKeyValidator->validate($this->getRequest())) {
            return $this->resultRedirectFactory->create()->setPath('*/*/');
        }

        $params = $this->getRequest()->getParams();
        $params['custom_price']= $params['custom_final_price'];
        try {
            if (isset($params['qty'])) {
                $filter = new \Zend_Filter_LocalizedToNormalized(
                    ['locale' => $this->_objectManager->get('Magento\Framework\Locale\ResolverInterface')->getLocale()]
                );
                $params['qty'] = $filter->filter($params['qty']);
            }

            $product = $this->_initProduct();
            $related = $this->getRequest()->getParam('related_product');

            /**
             * Check product availability
             */
            if (!$product) {
                return $this->goBack();
            }

            $this->cart->addProduct($product, $params);
            if (!empty($related)) {
                $this->cart->addProductsByIds(explode(',', $related));
            }

            $this->cart->save();

            /**
             * @todo remove wishlist observer \Magento\Wishlist\Observer\AddToCart
             */
            $this->_eventManager->dispatch(
                'checkout_cart_add_product_complete',
                ['product' => $product, 'request' => $this->getRequest(), 'response' => $this->getResponse()]
            );

            if (!$this->_checkoutSession->getNoCartRedirect(true)) {
                if (!$this->cart->getQuote()->getHasError()) {
                    $message = __(
                        'You added %1 to your shopping cart.',
                        $product->getName()
                    );
                    $this->messageManager->addSuccessMessage($message);
                }
                return $this->goBack(null, $product);
            }
        } catch (\Magento\Framework\Exception\LocalizedException $e) {
            if ($this->_checkoutSession->getUseNotice(true)) {
                $this->messageManager->addNotice(
                    $this->_objectManager->get('Magento\Framework\Escaper')->escapeHtml($e->getMessage())
                );
            } else {
                $messages = array_unique(explode("\n", $e->getMessage()));
                foreach ($messages as $message) {
                    $this->messageManager->addError(
                        $this->_objectManager->get('Magento\Framework\Escaper')->escapeHtml($message)
                    );
                }
            }

            $url = $this->_checkoutSession->getRedirectUrl(true);

            if (!$url) {
                $cartUrl = $this->_objectManager->get('Magento\Checkout\Helper\Cart')->getCartUrl();
                $url = $this->_redirect->getRedirectUrl($cartUrl);
            }

            return $this->goBack();

        } catch (\Exception $e) {
            $this->messageManager->addException($e, __('We can\'t add this item to your shopping cart right now.'));
            $this->_objectManager->get('Psr\Log\LoggerInterface')->critical($e);
            return $this->goBack();
        }
    }

    /**
     * Resolve response
     *
     * @param string $backUrl
     * @param \Magento\Catalog\Model\Product $product
     * @return $this|\Magento\Framework\Controller\Result\Redirect
     */
    protected function goBack($backUrl = null, $product = null)
    {
        if (!$this->getRequest()->isAjax()) {
            return parent::_goBack($backUrl);
        }

        $result = [];

        if ($backUrl || $backUrl = $this->getBackUrl()) {
            $result['backUrl'] = $backUrl;
        } else {
            if ($product && !$product->getIsSalable()) {
                $result['product'] = [
                    'statusText' => __('Out of stock')
                ];
            }
        }

        $this->getResponse()->representJson(
            $this->_objectManager->get('Magento\Framework\Json\Helper\Data')->jsonEncode($result)
        );
    }
}

I haven't done any changes here. Instead I've created " /Observer/CustomPrice.php" to make it work for Magento 2.1.3 which you see above. The /Controller/Cart/Add.php has been copied from "/vendor/magento/module-checkout/Controller/Cart/Add.php" and only one line had been added:

$params['custom_price']= $params['custom_final_price']; 

Solution for my issue on how to pass jQuery value to Observer (into my Mini-Cart):

<?php

    namespace FarbenGesell\Configuration\Observer;

    use Magento\Framework\Event\ObserverInterface;
    use Magento\Framework\App\RequestInterface;

    class CustomPrice implements ObserverInterface
    {
        public function __construct(
    \Magento\Framework\App\RequestInterface $request
    )
    {
        $this->_request = $request;
    }

        public function execute(\Magento\Framework\Event\Observer $observer) {
            $item = $observer->getEvent()->getData('quote_item');         
            $item = ( $item->getParentItem() ? $item->getParentItem() : $item );

            $custom_price = $this->_request->getParam('custom_final_cal');

            $price = $custom_price;
            $item->setCustomPrice($price);
            $item->setOriginalCustomPrice($price);
            $item->getProduct()->setIsSuperMode(true);
        }

    }
?>
3
  • Please remember to verify the price calculation server side. As it is written now the client can adversely modify the price client side and that is passed directly to the quote item.
    – Pmclain
    Commented Dec 24, 2016 at 13:05
  • Hi Pmclain. Thanks for pointing that out. This is very important indeed. I'm aware of this. Unfortunately I'm not able to implement this with the knowledge I have, as for now we verify the price manually after customer checkout.
    – eskaliert
    Commented Dec 24, 2016 at 13:16
  • The above attempt is also not working right now. Do you possibly have an idea why?
    – eskaliert
    Commented Dec 24, 2016 at 13:17

1 Answer 1

3

In your case, we need to pass your value to the request. The easiest way to this that we should add an hidden input to our form:

 <input type="hidden" name="custom_price" value="" id="custom_price_cal">

view/frontend/web/product.js

//Set the value to input
custom_price = price + product_attribute_value
$('#custom_price_cal').val(custom_price);

In your observer, we can the the param from request:

public function __construct(
    \Magento\Framework\App\RequestInterface $request
)
{
    $this->_request = $request;
}

 public function execute(\Magento\Framework\Event\Observer $observer) {
    $this->_request->getParam('custom_price');
    ......    
 }
11
  • Hey Khoa, thanks for your detailed reply. I will test this out and come back to you!
    – eskaliert
    Commented Dec 24, 2016 at 11:13
  • I've updated my question with "First attempt on Khoas answer: (Thanks for the fast reply!)".
    – eskaliert
    Commented Dec 24, 2016 at 11:35
  • Now, you can get the custom price in your observer? Commented Dec 25, 2016 at 13:44
  • Hi Khoa, no unfortunately not. It is showing the original price still. Have you checked my edit of my question above? This is how my code looks like right now. Do I have to change something in my "/Controller/Cart/Add.php" as well?
    – eskaliert
    Commented Dec 25, 2016 at 13:57
  • Did you get this param value is your controller? Commented Dec 25, 2016 at 13:59

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.