Jump to content

[Resolved] Default product option


rSanjoSEO

Recommended Posts

Thank you @Dirty Butter. I'm sorry, I'm spanish and my english is not very good!

I'm using CC version 6.1.5 with default skin.

I have created a product with different variants (serum with 15ml and 50ml format, for example); But when I access the product on the web I do not get marked either of the 2 options. I have made them mandatory and I have to select one, but I get the product with the default price and without marking any of the 2 options.

I understand that there should be some place to indicate, for example, by default, the product selected would be 15ml, letting me select the 50ml if it is the one I want.

Thank you very much.

Link to comment
Share on other sites

Hi @bsandall. I have updated the version and I think it has not been resolved.

When I access the product page there is no predefined option, or where I can preset it.

If I have a product with 2 options (for example boxes of 30 and 60 units), when accessing the product page, I do not see any of the 2 options pre-marked, and in addition, the price that comes out is the product price (which may be even different to both options).

What I said is if there is any way to indicate that when entering the product page, by default, one of the options is marked, and the price is updated to that option.

Thank you very much.

Link to comment
Share on other sites

I've updated to the latest version and cleared the cache, but it still does not appear to me.

Upgrade History

Versión CubeCart Fecha
6.1.6 Wednesday, 19 April 2017
6.1.5 Friday, 14 April 2017

I have not changed the skin.

2017-04-20.thumb.png.6c09c206c1a1b8213d2377c364b57c4f.png

Link to comment
Share on other sites

Goto Maintenance>Query Database and put this in the Query box and click Go.

DELETE FROM `CubeCart_filemanager` WHERE `filename` NOT REGEXP '(jpeg|jpg|gif|png)$' AND `type` = 1; #EOQ
ALTER TABLE `CubeCart_option_assign` ADD COLUMN `option_default` TINYINT(1) UNSIGNED NOT NULL DEFAULT 0 AFTER `set_enabled`; #EOQ
ALTER TABLE `CubeCart_option_assign` CHANGE `option_weight` `option_weight` DECIMAL(10,3)  NOT NULL  DEFAULT '0.00'; #EOQ

 

Link to comment
Share on other sites

Don't work!

First, I got an availability message from version 6.1.7 and updated it.

Then, I have executed the commands that you indicated to me by changing the names of the tables to those of my database:

Quote

DELETE FROM `cc_cubecart_filemanager` WHERE `filename` NOT REGEXP '(jpeg|jpg|gif|png)$' AND `type` = 1; #EOQ
ALTER TABLE `cc_cubecart_option_assign` ADD COLUMN `option_default` TINYINT(1) UNSIGNED NOT NULL DEFAULT 0 AFTER `set_enabled`; #EOQ
ALTER TABLE `cc_cubecart_option_assign` CHANGE `option_weight` `option_weight` DECIMAL(10,3)  NOT NULL  DEFAULT '0.00'; #EOQ

Affected rows: 1

I have cleared the cache data, but still, I do not see the default check.

Link to comment
Share on other sites

I think it still lacks a twist to the issue of product options.

In sections like "Best sellers", the product comes with its standard price. I guess it's meant to put the default product and add the price difference to the options, but the truth is that it is not the usual work like that.

Having a default price and then a different price for each option can create inconsistency in the information that is displayed to the customer.

sample.png.45d3ad466168b0be2ad0274faf414326.png

Still, I'm liking CubeCart as an alternative to other products like Prestashop.

I'm still in 6.1.6, but I'm still testing. I have to upload many products and I will surely do it directly on the database. I have notified Softaculous of the new update.

At the moment I want to know the tool well. I have worked with Magento and Prestashop and needed one that would allow me to handle 2 rates in a simple way. Prestashop does not and Magento is too heavy.

Thank you very much for your help.

Link to comment
Share on other sites

Unfortunately there isn't yet a way for CubeCart to automatically determine the correct price, and it would probably be computationally somewhat expensive to do so (i.e. the site would be slower to load).

You can avoid such a discrepancy, however, by setting the product's price to whatever the price is for the product with the default options selected.

So in the case of the screenshot above, you should set the price for 'Test Product' to 150 Euros and remove the sale price. The customer will then see the price as 150 Euros wherever the product may be displayed, and that is the price for the default version of the product.

Link to comment
Share on other sites

That is what I had thought to do to solve it.

But the problem lies in data redundancy and possible inconsistency. The logical thing would be that in products with options the default price option would be deactivated, and the price of the default option would be displayed.

Other applications do not have a product price, but always create at least one option (even if they do it internally)

Link to comment
Share on other sites

The problem with that is there is no guarantee that the store admins will set a default for all required options on every single product that has options. The ability to even set a default was only introduced in 6.1.6 and there are thousands of stores out there with tens or hundreds of thousands of products - I highly doubt everyone has had time to go through and set default options, and many stores might not even bother as it may not be something that is required for their business model.

That said, I do see what you are saying. Yes, the product price fields are redundant for the type of use case you have. CubeCart is not set up to efficiently query a price from a set of options, however, especially considering that option prices can be either absolute or cumulative. It would be a mess trying to determine prices for all of the products displayed on the home page or in a category, so CubeCart takes the route of having an easily retrievable price at the product level. This seems to me to be a good compromise for the sake of site speed and ease of use.

However, the potential for data inconsistency could be addressed by providing some method of auto-setting the product price based on the default options, e.g. when saving the product. Normal price would be easy, but how would you propose determining sale price? How about cost?

For my own store, I solved that issue by modifying the code to have a 'Price' and 'Sale Price' field for each entry in the options matrix. Non-required options can still modify those prices, but any required options I don't even bother setting price adjustments at the option level - just in the options matrix.

  • Like 1
Link to comment
Share on other sites

Only a few days ago I started with CubeCart. I still have a lot to know.

What you say is very reasonable. The simplest thing is to modify the skin so that it does not show the price, or to take it directly from the matrix.

I'm preparing a script for CubeCart to take data from my database directly, and with that I could avoid the possibility of redundancy.

I hope to be able to help soon as you are helping me now (even though I hardly speak English)

Link to comment
Share on other sites

You speak English well enough, mejor que hablo Español ;)

CubeCart makes an AJAX call via JavaScript (in `\skins\foundation\js\2.cubecart.js`) to format the price on the product page when options are selected. I modified that to instead query the database for the product data, including modifications from the options matrix.

There were quite a few changes involved, including to the database, but here is my code for sending and handling the AJAX call. You will of course need to modify it to match your database and code needs.

// in /skins/foundation/js/2.cubecart.js
// change any calls to the `price_inc_options` function to use this function instead
function specification_inc_options() {
    var options = [];
    $("[name^=productOptions]").each(function (index, element) {
        if (!$(this).val() || ($(this).is('input:radio') && $("input[name='" + element.name + "']:checked").length < 1)) {
        } else if ($(this).is('input:radio')) {
            // Prevent empty radio selections from adding multiple entries
            if (!$(this).is('input:radio') || $.inArray(element.name + '=0', options) === -1) {
                options.push(element.name + '=0');
            }
            if ($(this).is(':checked')) {
                options.push(element.name + '=' + $(this).val());
            }
        } else if ($(this).is('select')) {
            options.push(element.name + '=' + ($(this).find("option:selected").val()));
        } else if (($(this).is('textarea') || $(this).is('input:text')) && $(this).val() !== '') {
            // TODO options.push(element.name + '=' + $(this).val());
        } else { // include other product options, e.g. those with only 1 option
            options.push(element.name + '=' + $(this).val());
        }
    });
    if (options.length > 0) {
        var product_id = document.getElementById('product_id');
        if (product_id && product_id.tagName === 'INPUT') {
            options.push('product_id=' + product_id.value);
        }
        var action = $('form.add_to_basket').attr('action');
        var parts = action.split("?");
        action += (parts.length > 1 ? '&' : '?') + '_g=ajax_update_product_data&';
        options = options.join('&');
        $.ajax({
            url: action + options,
            cache: true,
            complete: function(returned) {
                var data = $.parseJSON(returned.responseText);
                for (var key in data) {
                    switch (key) {
                    case 'price':
                        $('#fbp').html(data[key]);
                    break;
                    case 'sale_price':
                        $('#ptp').html(data[key]);
                    break;
                    case 'use_stock_level':
                        var rows = $('table#product_spec_table tr');
                        if (data[key] == 1) {
                            rows.filter('#stock_level_row').show();
                            rows.filter('.hidden_row').remove();
                        } else {
                            rows.filter('#stock_level_row').hide();
                            if (rows.filter('.hidden_row').length == 0) {
                                rows.filter('#stock_level_row').after('<tr class="hide hidden_row"><td></td><td></td></tr>');
                            }
                        }
                    break;
                    case 'CTRL_SETTINGS':
                        if (data[key]['CTRL_ALLOW_PURCHASE'] && !data[key]['CATALOGUE_MODE']) {
                            if (data['set_enabled'] == 1) {
                                $('#allow_purchase').show();
                                $('#lead_time').show();
                            } else {
                                $('#allow_purchase').hide();
                                $('#lead_time').hide();
                            }
                            $('#login_to_view').hide();
                        } else {
                            $('#allow_purchase').hide();
                            $('#lead_time').hide();
                            if (data['set_enabled'] == 1 && data[key]['CTRL_HIDE_PRICES']) {
                                $('#login_to_view').show();
                            } else {
                                $('#login_to_view').hide();
                            }
                        }
                    break;
                    default: // update product specifications
                        var id = '#spec_' + key;
                        if (data.hasOwnProperty(key) && $(id).length) {
                            $(id).html(data[key]);
                        }
                    }
                }
                if (data['set_enabled'] == 1 && !data['CTRL_SETTINGS']['CTRL_HIDE_PRICES'] && data['CTRL_SETTINGS']['CTRL_OUT_OF_STOCK']) {
                    $('#out_of_stock').show();
                } else {
                    $('#out_of_stock').hide();
                }
                // Handle after loop so elements are properly displayed / hidden
                if (data['set_enabled'] == 1) {
                    $('#ptp').show();
                    if (data['ctrl_sale']) {
                        if ($('#fbp').length > 0) {
                            $('#fbp').show();
                            $('#ptp').addClass('sale_price');
                        }
                    } else {
                        $('#fbp').hide();
                        $('#ptp').removeClass('sale_price');
                    }
                    $('#combination_unavailable').hide();
                } else {
                    $('#fbp').hide();
                    $('#ptp').hide();
                    $('#combination_unavailable').show();
                }
            }
        });
    }
}

And then the processing of that AJAX request:

// in `cubecart.class.php` after `case 'ajax_price_format':` in the `loadPage` function
case 'ajax_update_product_data':
	$GLOBALS['debug']->supress();
	$product_id = filter_var($_GET['product_id'], FILTER_VALIDATE_INT);
	if (!is_int($product_id)) {
		die(json_encode(false));
	}
	$options = (isset($_GET['productOptions']) && is_array($_GET['productOptions']) ? $_GET['productOptions'] : false);
	$product = $GLOBALS['catalogue']->getProductData($product_id, 1, false, 10, 1, false, null);
	if ($product && $options) {
		// running totals of price modifiers for dealing with multiple absolute pricing options
		$product['price_total_modifier'] = 0.00;
		$product['option_price_ignoring_tax_modifier'] = 0.00;
		$product['price_optional_modifier'] = 0.00; // total price modifier of all non-matrix options
		// Modify product specifications based on each option
		$product['set_enabled'] = true; // default product, i.e. no options selected, should not show 'unavailable' message
		foreach ($options as $option_id => $option_data) {
			if (is_array($option_data)) {
				// Text option
				foreach ($option_data as $trash => $option_value) {
					if (($assign_id = $GLOBALS['db']->select('CubeCart_option_assign', false, array('product' => $product_id, 'option_id' => $option_id))) !== false) {
						$assign_id = $assign_id[0]['assign_id'];
					} else {
						$assign_id = 0;
					}
					$value = $GLOBALS['catalogue']->getOptionData((int)$option_id, $assign_id);
					if ($value) {
						Cart::updateProductDataWithOption($product, $value);
					}
				}
			} elseif (is_numeric($option_data)) {
				if (($value = $GLOBALS['catalogue']->getOptionData((int)$option_id, (int)$option_data)) !== false) {
					Cart::updateProductDataWithOption($product, $value);
				}
			}
		}
		// Apply option matrix modifiers, if any
		$options_identifier_string = $GLOBALS['catalogue']->defineOptionsIdentifier($options);
		$result = $GLOBALS['db']->select('CubeCart_option_matrix', 'product_id, set_enabled, price, sale_price, use_stock as use_stock_level, stock_level, product_code, upc, ean, jan, isbn', array('product_id' => $product_id, 'status' => 1, 'options_identifier' => $options_identifier_string));
		if ($result) {
			Cart::applyProductMatrix($product, $result[0]);
		}
	}
	// Finally, format product values for display
	if (is_array($product)) {
		if ($product['sale_price'] == 0 || $product['price'] < $product['sale_price']) {
			$product['sale_price'] = $product['price'];
		}
		$product['ctrl_sale'] = ($product['sale_price'] > 0 && $product['sale_price'] < $product['price'] ? true : false);
		$product['price'] = $GLOBALS['tax']->priceFormat($product['price']);
		$product['sale_price'] = $GLOBALS['tax']->priceFormat($product['sale_price']);
		// Format the following entries to 3-decimal precision
		$thousands = array('product_weight','product_length','product_height','product_width');
		foreach ($thousands as $key) {
			$product[$key] = sprintf('%.3F', $product[$key]);
		}
						
		// Add settings to determine which GUI elements to display / hide (replicates variables / logic in Catalogue#displayProduct)
		$product['CTRL_SETTINGS'] = array(
			'CATALOGUE_MODE'      => ($GLOBALS['config']->get('config', 'catalogue_mode') ? true : false),
			'CTRL_ALLOW_PURCHASE' => true,
			'CTRL_OUT_OF_STOCK'   => false,
			'CTRL_HIDE_PRICES'    => false
		);
		if ((bool)$product['use_stock_level']) {
			if ((int)$product['stock_level'] < 1) {
				$product['CTRL_SETTINGS']['CTRL_ALLOW_PURCHASE'] = (bool)$GLOBALS['config']->get('config', 'basket_out_of_stock_purchase');
				$product['CTRL_SETTINGS']['CTRL_OUT_OF_STOCK'] = true;
			}
		}
		if ($GLOBALS['session']->get('hide_prices')) {
			$product['CTRL_SETTINGS']['CTRL_ALLOW_PURCHASE'] = false;
			$product['CTRL_SETTINGS']['CTRL_HIDE_PRICES'] = true;
		}
	}
	die(json_encode($product));
break;

 

Link to comment
Share on other sites

Heh, yeah my JS isn't too hot either - lots of trial and error.

Just to note that my store I have added length, width and height to the products and product options. I also dynamically modify the product specification data displayed on the product page so that the product code and dimensions update based on the selected options.

In other words, some portions of the above code may be completely irrelevant to your store, but it will at least hopefully get you started. :P

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...