News:

Looking for documentation? Take a look on our wiki

Main Menu

Recent posts

#1
I get an error from Virtuemart productdetails page:

/index.php?option=com_virtuemart&view=productdetails&task=recalculate&format=json&nosef=1&lang=nl-NL

This comes from accessing my product page.

Error message data:
E_ERROR:1 0: Illegal offset type in file: /administrator/components/com_virtuemart/models/product.php line: 1172

If I check the line it has something to do with the cache. The cache gives a lot of issues anyway, so if I can disable it ouright would be great

self::$_cacheOpt[$virtuemart_product_id] = $opt;
#2
Maybe this is a better idea to just add stock to the custom fields so when it reaches 0 it will not display. The value keeps in the database etc, so the administration of the orders won't be scrambled (see my previous post)

You can ofcourse work with child products, but I think it's a better user experience to just add a simple stock field for the custom fields.
#3
Templating & Layouts / Re: HTML5 extra attributes in ...
Last post by sandomatyas - Yesterday at 09:23:06 AM
Having an HTML5 pattern attribute somewhere here could be very useful. If I'm right, it could work quite similarly to how the placeholder attribute works. I think with a small effort, it could make the checkout UX much better by providing a customizable validation solution for shopper fields.

#4
Quote from: Milbo on Yesterday at 08:55:02 AMyes, that sounds like a plan. But I have no fast answer how todo it.
Ah that's a shame. I will try to find if I can somehow fix it myself by checking all the files, I hoped you could point me to the files itself.. I will just chekc the view files first, then the controller files and then the model files. Thanks for the reply.

EDIT:

So I checked the model first that removes the disabled custom fields from the product. I changed some code that does this:


public function storeProductCustomfields($table, $datas, $id) {

vRequest::vmCheckToken('Invalid token in storeProductCustomfields');
//Sanitize id
$id = (int)$id;

//Table whitelist
$tableWhiteList = array('product','category','manufacturer');
if(!in_array($table,$tableWhiteList)) return false;

// Get old IDS
$db = JFactory::getDBO();
$db->setQuery( 'SELECT * FROM `#__virtuemart_'.$table.'_customfields` as `PC` WHERE `PC`.virtuemart_'.$table.'_id ='.$id );

$oldCustomfields = $db->loadAssocList('virtuemart_customfield_id');
$old_customfield_ids = array_keys($oldCustomfields);

if (!empty( $datas['field'])) {

foreach($datas['field'] as $key => $fields){

if(!empty($datas['field'][$key]['virtuemart_product_id']) and (int)$datas['field'][$key]['virtuemart_product_id']!=$id){
//vmdebug('The field is from the parent',$fields);
$fields['override'] = !empty($fields['override'])?(int)$fields['override']:0;
$fields['disabler'] = !empty($fields['disabler'])?(int)$fields['disabler']:0;

if($fields['override']!=0 or $fields['disabler']!=0){
if($fields['override']!=0){
$fields['override'] = $fields['virtuemart_customfield_id'];
}
if($fields['disabler']!=0){
$fields['disabler'] = $fields['virtuemart_customfield_id'];
}

if(!empty($fields['virtuemart_customfield_id']) and empty($oldCustomfields[$fields['virtuemart_customfield_id']]['virtuemart_customfield_id'])){
//vmdebug('It is set now as override, store it as clone, therefore set the virtuemart_customfield_id = 0');
$fields['virtuemart_customfield_id'] = 0;
}
}
else {
//vmdebug('there is no override/disabler set',$fields,$oldCustomfields[$fields['virtuemart_customfield_id']]);
//we do not store customfields inherited by the parent, therefore
$key = array_search($fields['virtuemart_customfield_id'], $old_customfield_ids );
if ($key !== false ){
unset( $old_customfield_ids[ $key ] );
}
continue;
}
}
else {
//vmdebug('The field is from the current product',$fields);
// if(empty($fields['override']) and empty($fields['disabler']) and !empty($fields['virtuemart_customfield_id']) and (!empty($oldCustomfields[$fields['virtuemart_customfield_id']]['disabler']) or !empty($oldCustomfields[$fields['virtuemart_customfield_id']]['override']) )){
// //vmdebug('Remove customfield override/disabler',$fields['virtuemart_customfield_id']);
// $old_customfield_ids[] = $fields['virtuemart_customfield_id'];
// }

//DONT REMOVE DISABLED FROM THE PRODUCT < CHANGES KUUBS
if(empty($fields['override']) and !empty($fields['virtuemart_customfield_id']) or !empty($oldCustomfields[$fields['virtuemart_customfield_id']]['override'])){
//vmdebug('Remove customfield override/disabler',$fields['virtuemart_customfield_id']);
$old_customfield_ids[] = $fields['virtuemart_customfield_id'];
}

}

if(!empty($fields['field_type']) and $fields['field_type']=='C' and !isset($datas['clone']) ){

$cM = VmModel::getModel('custom');
$c = $cM->getCustom($fields['virtuemart_custom_id'],'');

if(!empty($fields['set_matrix'])){

$productModel = VmModel::getModel ('product');
$avail = $productModel->getProductChildIds($id);

foreach($fields['selectoptions'] as $kv => $selectoptions){
if(!empty($selectoptions['values'])){
$values[$kv] = preg_split('/\r\n|\r|\n/', $selectoptions['values'],5);
}
}

vmdebug('my values',$values,$avail);

$parentCombo = $fields['options'][$id];
$myMatrix = array();
$size = 1;
//$parentMatrix = array();
//Yes, also this may get better written, but I am just happy that it works this way.
foreach ($values as $variantKey => $optArray) {
$size = $size * sizeof($optArray);
//$level++;
foreach ($optArray as $option) {
//vmdebug('myMatrix $k=>$option',$option);
if($variantKey==0){
$myMatrix[$option] = null;
//$parentMatrix[$parentCombo[0]] = null;
} else if($variantKey == 1){

$myMatrix = self::writeValuesToKeysAddValueArray($myMatrix,$option);

//$parentMatrix[$parentCombo[0]][$parentCombo[1]]= null;
} else if($variantKey == 2){
foreach($myMatrix as $k1 => &$option1){
$option1 = self::writeValuesToKeysAddValueArray($option1,$option);
}
//$parentMatrix[$parentCombo[0]][$parentCombo[1]][$parentCombo[2]]= null;
} else if($variantKey == 3){
foreach($myMatrix as $k1 => &$option1){
foreach($option1 as $k2 => &$option2){
$option2 = self::writeValuesToKeysAddValueArray($option2,$option);
}
}
//$parentMatrix[$parentCombo[0]][$parentCombo[1]][$parentCombo[2]][$parentCombo[3]]= null;
} else if($variantKey == 4){
foreach($myMatrix as $k1 => &$option1){
foreach($option1 as $k2 => &$option2){
foreach($option2 as $k3 => &$option3){
$option3 = self::writeValuesToKeysAddValueArray($option3,$option);
}
}
}
//$parentMatrix[$parentCombo[0]][$parentCombo[1]][$parentCombo[2]][$parentCombo[3]][$parentCombo[4]]= null;
}
}
}
vmdebug('myMatrix 3',$size,$myMatrix);

vmdebug('myMatrix orig $fields',$fields['options']);
$parentComboSerialized = serialize($parentCombo);
//reset($avail);
for((int)$i=0;$i<$size;$i++){
if(empty($avail)){
$childId = $productModel->createChild($id);
} else {
$childId = $avail[$i];
unset($avail[$i]);
}
vmdebug('$childId after unset'.$i,$childId,$avail);
$combo = self::writeCombos($myMatrix);

if(serialize($combo) == $parentComboSerialized){
$combo = self::writeCombos($myMatrix);
//vmdebug('myMatrix $combo equals $parentCombo',$combo, $parentCombo);
$size--;
} else {
//vmdebug('myMatrix $combo NOT equal',serialize($combo), $parentComboSerialized);
}
$fields['options'][$childId] = $combo;
}
vmdebug('myMatrix $fields',$fields['options'],$avail);

}
//The idea was here to store the images directly. Maybe just the ids.
/*if(!empty($c->withImage)){
$mediaM = VmModel::getModel('media');
$tablePM = $mediaM->getTable('product_medias');
foreach($fields['options'] as $prodId => $lvalue){
$images = $tablePM->load($prodId);
if(isset($images[0])){
$media = $mediaM->createMediaByIds($images[0]);
$fields['images'][$prodId] = $media[0]->getFileUrlThumb();
}

}
}*/

//Set tags on extra customfield
if(!empty($c->sCustomId)){

$sCustId = $c->sCustomId;
$labels = array();
foreach($fields['selectoptions'] as $k => $option){
if (is_object($option)) {
$option = Joomla\Utilities\ArrayHelper::fromObject($option);
}
if($option['voption'] == 'clabels' and !empty($option['clabel'])){
$labels[$k] = $option['clabel'];
}
}

foreach($fields['options'] as $prodId => $lvalue){

if($prodId == $id) continue;
$db->setQuery( 'SELECT `virtuemart_customfield_id` FROM `#__virtuemart_'.$table.'_customfields` as `PC` WHERE `PC`.virtuemart_'.$table.'_id ="'.$prodId.'" AND `virtuemart_custom_id`="'.(int)$sCustId.'" '  );
$strIds = $db->loadColumn();
$i=0;
foreach($lvalue as $k=>$value) {

if(!empty($labels[$k])) {
$ts = array();
$ts['field_type'] = 'S';
$ts['virtuemart_product_id'] = (int)$prodId;
$ts['virtuemart_custom_id'] = (int)$sCustId;
if(isset($strIds[$i])){
$ts['virtuemart_customfield_id'] = (int)$strIds[$i];
unset( $strIds[$i++] );
}
$ts['customfield_value'] = $value;

$tableCustomfields = $this->getTable($table.'_customfields');
$tableCustomfields->bindChecknStore($ts);
}
}

if(count($strIds)>0){
// delete old unused Customfields
$db->setQuery( 'DELETE FROM `#__virtuemart_'.$table.'_customfields` WHERE `virtuemart_customfield_id` in ("'.implode('","', $strIds ).'") ');
$db->execute();
}
}
}
//vmdebug('Executing',$id,$fields);
}

if (!empty($datas['customfield_params'][$key]) and !isset($datas['clone']) ) {
if (array_key_exists( $key,$datas['customfield_params'])) {
$fields = array_merge ((array)$fields, (array)$datas['customfield_params'][$key]);
}
}
$fields['virtuemart_'.$table.'_id'] = $id;

if(!empty($fields['field_type']) and ( $fields['field_type']=='RC' or $fields['field_type']=='R' ) and !isset($datas['clone']) ){
if(is_array($fields['customfield_value'])){
$fields['customfield_value'] = implode(',',$fields['customfield_value']);
}
}

$this->storeProductCustomfield('product', $fields);

$key = array_search($fields['virtuemart_customfield_id'], $old_customfield_ids );
if ($key !== false ) unset( $old_customfield_ids[ $key ] );

}
} else {
//vmdebug('storeProductCustomfields nothing to store');
}

vDispatcher::importVMPlugins('vmcustom');

//vmdebug('Delete $old_customfield_ids',$old_customfield_ids);

if ( count($old_customfield_ids) ) {
// call the plugins to delete their records
foreach ($old_customfield_ids as $old_customfield_id) {
vDispatcher::trigger('plgVmOnCustomfieldRemove', array($oldCustomfields[$old_customfield_id]));
}
// delete old unused Customfields
$db->setQuery( 'DELETE FROM `#__virtuemart_'.$table.'_customfields` WHERE `virtuemart_customfield_id` in ("'.implode('","', $old_customfield_ids ).'") ');
$db->execute();
//vmdebug('Deleted $old_customfield_ids',$old_customfield_ids);
}



if (isset($datas['customfield_params']) and is_array($datas['customfield_params'])) {
foreach ($datas['field'] as $key => $pfield ) {
if($pfield['field_type']=="E" and !empty($pfield['custom_element'])){
vDispatcher::directTrigger( 'vmcustom',$pfield['custom_element'], 'plgVmOnStoreProduct', array($datas, $datas['customfield_params'][$key], $old_customfield_ids, $key ));
}
}
}

}


I removed the part where it adds the product custom field to the old_custom_fields so it doesn't remove them in the query below. I tested it and it seems that it works correctly. But i'm not sure if this is correct. This doesn't show the []d checkbox, but at least it doesn't remove it from the product when you save the product with the disabled checkbox activated (still needs to use direct database to change the disabler value)

@Milbo, do you see anything wrong with this that will break other parts of Virtuemart?
#5
Quote from: Milbo on May 23, 2024, 21:35:45 PMIf you store a parent, which has the extra tab for children, than it takes this values for the children.

that works most time correctly, but if someone buys something meanwhile, it wont work 100%.

But that is a common problem for our stock feature.

Thanks Max, for now I added the logging. But there is one thing that bothers me in this logging that is that when you log it it will show that the child products get set to 0 and then after it somewhere else sets the child products back to it's current stock values again. But I'd like to log that as well, do you know where I can find it?
#6
yes, that sounds like a plan. But I have no fast answer how todo it.
#7
When you remove a custom field, it also removes them from database and thus from the already made orders itself. This makes it so custom fields where the customer paid for is not in the order itself anymore which is not good for order management.

This bug is already a long time here, and I think it's time to smash this one. I think I have the solution at hand.

- Enable the []d checkbox that is also on child products to disable custom fields for the parent
- Make sure to keep including them in the admin backend to not let virtuemart completely remove the custom field

You can set the disabler from the custom field to 1 in the database, this will disable the field but not remove them. BUT, the custom fields also won't display in the backend, which is a huge problem because if you save the parent product (which doens't display the disabled field) it will remove the custom field from the dataabase. My fixes would be to enable the []d checkbox, but also keep showing all the fields in the backend, even if it's disabled.

@Milbo
#8
I have problem:

The quantity, name, SKU of products (item) not show on orderdone, order infomation page (front end) Both on orders page  (backend)

Payment method: standad
Shipment by weight, zip
Testing on Xampp
 
-PHP-Version 8.2.12
-Joomla 5.1.0
- Virtuemart 4.2.12.11012

debug
Backend

1 vmdebug Show All Errors, PHP-Version 8.2.12
2 vmdebug 1 Language, default shoplanguage (VmConfig::$jDefLang): vi_vn vi-VN
3 vmdebug vmTime: time to load config param $lang=1 and iniLang=0 $exeTrig = 0 now = 1: 0.0204181671142578
4 vmdebug Set router vars Input Get, Post Var0:
5 vmdebug Set router vars self::$get, Post, self::$request Var0:

6 vmdebug Start used Ram 32M
7 vmdebug BE main controller with controller orders and task orders
8 vmdebug exeSortSearchListQuery my $limitStart 0 $limit 0 q Var0:
9 vmdebug exeSortSearchListQuery result Var0:
10 vmdebug Defining custom function convertfromcurrency
11 vmdebug Defining custom function converttocurrency
12 vmdebug exeSortSearchListQuery my $limitStart 0 $limit 30 q Var0:
13 vmdebug exeSortSearchListQuery result Var0:

14 vmdebug exeSortSearchListQuery my $limitStart 0 $limit 0 q Var0:

15 vmdebug exeSortSearchListQuery result Var0:

16 vmdebug Get user, using given id 292
17 vmdebug Get user id 292
18 vmdebug VmViewAdmin addTemplatePath vmadmin
19 vmdebug checkSafePathBase return cached C:\xampp\htdocs\matkinh\administrator\components\com_virtuemart\su4ULI2CtosK19K0cMemt\
20 vmdebug getPagesLinks Var0:
C:\xampp\htdocs\matkinh/administrator/templates/atum/html/pagination.php
21 vmdebug vmTime: "VirtueMartControllerOrders" Finished task orders: 0.609486103057861
22 vmdebug End used Ram 36M
23 vmdebug Peak memory peak 36M
 
Fronted
271 vmdebug Building segments from initial query: Var0:
Array
(
    [option] => com_virtuemart
    [view] => productdetails
    [manage] => 1
    [managing] => 0
    [Itemid] => 605
    [limitstart] => 0
    [virtuemart_product_id] => 1808
    [virtuemart_category_id] =>
    [lang] => vi-VN
)
272 vmdebug vmRouter case 'productdetails' Itemid
273 vmdebug Building segments from query, left: Var0:
Array
(
    [non_segmented_query] => Array
        (
            [option] => com_virtuemart
            [manage] => 1
            [Itemid] => 605
            [lang] => vi-VN
        )

    [segments] => Array
        (
           
  • => kinh-mat-rayban-rb3447-9001a5-53-detail
        )

)

ADDTOCART click
My Memory Limit in MB 507Get user, using given id 0Get user id 0VmView loaded with overridesetCartIntoSession restart sessionsetActiveMenu Var0:

402
Var1:
402
setMenuItemId Var0:
Array
(
    [virtuemart_category_id] => Array
        (
            [44] => Array
                (
                   
  • => 257
                )

            [45] => Array
                (
                   
  • => 259
                )

            [52] => Array
                (
                   
  • => 260
                )

            [49] => Array
                (
                   
  • => 262
                )

            [43] => Array
                (
                   
  • => 266
                )

            [48] => Array
                (
                   
  • => 268
                )

            [46] => Array
                (
                   
  • => 270
                )

            [47] => Array
                (
                   
  • => 271
                )

            [23] => Array
                (
                   
  • => 528
                )

            [19] => Array
                (
                   
  • => 529
                )

            [34] => Array
                (
                   
  • => 533
                )

            [13] => Array
                (
                   
  • => 278
                )

            [32] => Array
                (
                   
  • => 534
                )

            [7] => Array
                (
                   
  • => 279
                )

            [30] => Array
                (
                   
  • => 535
                )

            [27] => Array
                (
                   
  • => 540
                )

            [26] => Array
                (
                   
  • => 487
                )

            [25] => Array
                (
                   
  • => 488
                )

            [11] => Array
                (
                   
  • => 495
                )

            [2] => Array
                (
                   
  • => 496
                )

            [12] => Array
                (
                   
  • => 497
                )

            [35] => Array
                (
                   
  • => 498
                )

            [36] => Array
                (
                   
  • => 500
                )

            [37] => Array
                (
                   
  • => 501
                )

            [3] => Array
                (
                   
  • => 503
                )

           
  • => Array
                (
                   
  • => 0
                )

        )

    [manufacturer] => 782
    [cart] => Array
        (
            [standard] => 530
        )

    [productdetails] => 275
    [virtuemart] => 605
    [virtuemart_manufacturer_id] => Array
        (
            [5] => 607
            [16] => 608
            [23] => 656
            [58] => 920
            [29] => 252
            [56] => 253
            [57] => 254
        )

)
Building segments from initial query: Var0:
Array
(
    [option] => com_virtuemart
    [view] => category
    [virtuemart_category_id] => 43
    [Itemid] => 402
    [lang] => vi-VN
)
my category build route Var0:
Array
(
    [option] => com_virtuemart
    [virtuemart_category_id] => 43
    [Itemid] => 402
    [lang] => vi-VN
)
category link segments Var0:
Array
(
    [option] => com_virtuemart
    [Itemid] => 266
    [lang] => vi-VN
)
Var1:
Array
(
)
Building segments from query, left: Var0:
Array
(
    [non_segmented_query] => Array
        (
            [option] => com_virtuemart
            [Itemid] => 266
            [lang] => vi-VN
        )

    [segments] => Array
        (
        )

)
My preprocess $Itemid Var0:
605
Building segments from initial query: Var0:
Array
(
    [option] => com_virtuemart
    [view] => cart
    [Itemid] => 605
    [lang] => vi-VN
)
Building segments from query, left: Var0:
Array
(
    [non_segmented_query] => Array
        (
            [option] => com_virtuemart
            [Itemid] => 605
            [lang] => vi-VN
        )

    [segments] => Array
        (
           
  • => cart
        )

)
EDITE Payment method page

Warning: openssl_decrypt(): IV passed is only 8 bytes long, cipher expects an IV of precisely 16 bytes, padding with \0 in C:\xampp\htdocs\matkinh\administrator\components\com_virtuemart\helpers\vmcrypt.php on line 87
#9
Thank you, Milbo. I did install the update last week and "that" part seems to be working fine. It's the error in the shopping cart (due to the type of captcha) that is a thorn in my side.
I decided I'd just put a message in the cart to log in before doing anything, or the user will get errors.
The problem with that is, no guest checkout.
#10
Because the prices are unnecessary complex, old vm1 stuff. Since vm2 it works a different way.

We have rules which works per categories, so using the "old parameters" just create more work than necessary.