4

Without using the Admin panel. I want to be able to change the price of an item in OpenCart on the product page.

Basically I have an Option called Bespoke/Custom: which is a text field. If the customer enters anything here I want to be able to change the price which I do already via jQuery and then I want that new hidden field with the price to override the cart price for this customer order

Is that possible? Is there an extension where can I allow the customer to enter their own price then I could hide this field and update via jQuery etc

This is reference to some other posts Using an alternate price field in OpenCart and also about this model link http://forum.opencart.com/viewtopic.php?t=36052 which shows where the main oop functions are but it is quite extensive to do it their

Community
  • 1
  • 1
TheBlackBenzKid
  • 26,324
  • 41
  • 139
  • 209
  • If I understand You right You want to let the user to insert his own price and use this one for calculation and checkout process? I'd suggest then to walk down through the checkout process (either manually following the code or using e.g. XDebug and Netbeans) to understand when and how the prices are loaded so that You could override that logic and use the custom price if provided. I'd recommend focusing on the `add-to-cart` part as the products and their data (options, prices) are stored within session - so Your custom price should be set for the products before they are added into the cart. – shadyyx Aug 15 '13 at 10:45
  • I have a hidden field on the page that has a "sale" custom price. Basically when they add or make changes to the page, this hidden field value gets updated with a new price. When they press add to checkout it should just checkout and add to cart as normal. – TheBlackBenzKid Aug 15 '13 at 13:12
  • "Checkout and add to cart as normal" is meant like with the original price unchanged? Or the original price should be changed with the price from the hidden input? If You want to change the price of the product with which it would be sold with that from a **hidden input**, then I would be more than happy to shop at that store ;-) – shadyyx Aug 15 '13 at 15:17
  • I want to be able to change the price with that hidden input. The hidden input value is secure and it is something we need setting up.. can you advice. Appreciate advice so far – TheBlackBenzKid Aug 16 '13 at 08:08
  • So You will then check whether the value set from the hidden input is the one that should be set? I believe I do not have to mention that with e.g. FireBug I am able to change the hidden input's value thus the price could be set to just e.g. `$1`... As I mentioned in the first comment - walk through the process of setting products into the cart as all the data (and prices) are then stored in a session - that's the point You should inject Your custom price value for the product. – shadyyx Aug 16 '13 at 08:56
  • Not concerned about Firebug as we will have other MySQL checks in place. I am going to try your solution below and have upped the rep for bounty since you have gone out your way. – TheBlackBenzKid Aug 19 '13 at 08:32

2 Answers2

6

OK, to point You the right direction this is how I would do this:

1. hidden input render
As You may know, in a catalog/view/theme/default/template/product/product.php there is AJAX request for adding product into the cart:

$('#button-cart').bind('click', function() {
    $.ajax({
        url: 'index.php?route=checkout/cart/add',
        type: 'post',
        data: $('.product-info input[type=\'text\'], .product-info input[type=\'hidden\'], .product-info input[type=\'radio\']:checked, .product-info input[type=\'checkbox\']:checked, .product-info select, .product-info textarea'),
        dataType: 'json',
                // ...
        });
});

If You look on the data parameter You'll see that all the inputs, selects, textareas etc. present in a .product-info div are populated and posted to PHP.

Therefore I'd render the hidden input with custom price value into that .product-info div to not have to modify the AJAX request at all. Let's say the name of that input will be custom_price.

2. The checkout/cart/add
Open up catalog/controller/checkout/cart.php and search for add method. Here all the magic should be done. After this part of code:

            if (isset($this->request->post['option'])) {
                $option = array_filter($this->request->post['option']);
            } else {
                $option = array();  
            }

I'd add this:

            if(isset($this->request->post['custom_price']) && $this->isCustomPriceValid($this->request->post['custom_price'])) {
                $custom_price = $this->request->post['custom_price'];
            } else {
                $custom_price = false;
            }

Implement the isCustomPriceValid() method to meet Your requirements...and advance to the last edit here - change this line:

$this->cart->add($this->request->post['product_id'], $quantity, $option);

to:

$this->cart->add($this->request->post['product_id'], $quantity, $option, $custom_price);

3. The cart
Now open up this file: system/library/cart.php and again search for the add method. You would have to change the definition of the method to this one:

public function add($product_id, $qty = 1, $option = array(), $custom_price = false) {

Before the last line of code within this method, add another one:
(this code was edited due to the comment from the OP)

    // ...

    if($custom_price) {
        if(!isset($this->session->data['cart']['custom_price'])) {
            $this->session->data['cart']['custom_price'] = array();
        }

        $this->session->data['cart']['custom_price'][$key] = $custom_price;
    }

    $this->data = array(); // <- last line
}

The last edit should be within the method getProducts() as this one is loading all the data from the DB and forwards them to other controllers for displaying purposes.

Now I don't know whether Your custom price should overwrite the price + options price or only the price, thus options price will be added to it, so I'd stick with the second choice as it is more descriptive and the first choice could be easily derived from my example.

Search for the line

$price = $product_query->row['price'];

and right after add

if(isset($this->session->data['cart']['custom_price'][$key])) {
    $price = $this->session->data['cart']['custom_price'][$key];
}

Now the price should be overwritten with the custom one. Check further that the price for the product is later set as:

$this->data[$key] = array(
    // ...
    'price'           => ($price + $option_price),
    // ...              
);

So if You'd like to overwrite the whole price with the custom one, add that condition right after that array like this (instead of after $price = ...;):

if(isset($this->session->data['cart']['custom_price'][$key])) {
    $this->data[$key]['price'] = $this->session->data['cart']['custom_price'][$key];
}

This should be it. I didn't test the code, It may or may not work with slight modifications. I was working with OC 1.5.5.1. This should only point You to the right direction (while believing the finish is not that far).

Enjoy!

shadyyx
  • 15,825
  • 6
  • 60
  • 95
  • +1 for all the detail but it doesn't work. I would appreciate if you could actually test and build this also interested in having this commercially installed in my site - or as a mod but the ability to add it via the core - please! Thanks so much so far but my price does not carry across! – M1th Aug 19 '13 at 09:52
  • 1
    @M1th Since we edited and added all the logic that should set the custom price into the session, anytime You call the method `system/library/cart.php::getProducts()` (or in other words You usually see it like `$this->cart->getProducts()`) - all the products from the session with already customized price are returned. This site, though often You'll find it this way, is not providing the *out of the box* solutions all the time - sometimes the answers will only push You the right way. This is also the best way how You can learn something on Your own. What actually does not work for You? – shadyyx Aug 19 '13 at 11:51
  • The price does not work. The new price gets carried across however on the cart page it does not show the new price for the item. Can you show exactly what like you place it after `$price = ...);` this is because there is more than one set of array options and I think that is why it does not update the cart or price.. – M1th Aug 19 '13 at 12:09
  • The problem is in `getProducts` in `system/library/cart.php` - anywhere inside this function you cannot call the session as it brings: `Notice: Undefined index: custom_price` as in I want to call `$this->session->data['cart']['custom_price'][$key]` – TheBlackBenzKid Aug 19 '13 at 13:44
  • @TheBlackBenzKid Then, firstly create that index - define it somewhere within `system/library/cart::add()` like: `if(!isset($this->session->data['cart']['custom_price'])) { $this->session->data['cart']['custom_price'] = array(); }` - this should be enough to not get the notice. Anyway, the notice is only saying the index is not existing, but it will still be created and used... Except maybe of the `headers already sent` warning... Check my edited answer - part **3. The Cart - add**... – shadyyx Aug 19 '13 at 15:23
  • Thanks. I did apply the changes and the header does disappear but the price is not updated on the cart. – TheBlackBenzKid Aug 20 '13 at 08:10
  • Hmm, I'm not sure then. I thought the solution should work. Are You sure the custom price value is pushed forward into the `system/library/cart.php` and `add()` and afterwards to `getProducts()` methods? I do not have time to implement this and to test it, I thought that any other developer could finalize this on his own... – shadyyx Aug 20 '13 at 09:46
  • I am sure.. I double checked and triple checked. I cannot seem to fix it as I more frontend. I have been at it for a few days. I even emailed you with regarding commercial work on this. – TheBlackBenzKid Aug 22 '13 at 08:09
2

-"This should only point You to the right direction (while believing the finish is not that far). via @shadyyx"

Thank you @shadyyx - for showing the correct approach... I managed to get it working and this is how:

if(isset($this->session->data['cart']['custom_price'][$key])) {
    $this->data[$key]['price'] = $this->session->data['cart']['custom_price'][$key];
} 

should be :

if(isset($this->session->data['custom_price'][$key])) {
    $this->data[$key]['price'] = $this->session->data['custom_price'][$key];
}

Thank you again and I hope somebody find this useful.

TheBlackBenzKid
  • 26,324
  • 41
  • 139
  • 209