Rainforest

Sankuru

Implementeren, customiseren, uitbreiden, en troubleshooten van Joomla/Virtuemart

Views: 4833

Wij helpen met ...

Virtuemart
Joomfish
Andere extensies
SocialTwist Tell-a-Friend

Automatische vertaling

English Arabic Chinese (Simplified) German Japanese Russian Spanish



Hergebruik open source

Datgene wat U nodig hebt, bestaat vaak al, en dekt 80% van Uw behoeften. Wij zorgen voor de ontbrekende 20%.

Gratis offerte

Vraag vandaag nog gratis een offerte aan.

Virtuemart, configuring individual product units PDF Afdrukken E-mail
Waardering: / 2
SlechtZeer goed 
Geschreven door erik   
zaterdag 02 mei 2009 14:04
There are no translations available.

When adding a quantity of products, which has attributes, to the Virtuemart cart, all these products will be configured in exactly the same way. One way of working around this, consists in configuring one product at a time, and add them separately to the cart. This can be a bit cumbersome. I've modified a few Virtuemart files, in order to configure more than one product in the same product detail page.

When we use the default quantity box for the product, the user can click on the up and down arrow to increase or decrease the quantity he wants to order from the product. Each time he clicks on the up arrow, we will add new   fields, to configure the new item. Each time, he clicks on the down arrow, we will remove the configuration fields that belong to the last item.

The html for the quantity box is generated in the file: component/com_virtuemart/themes/<theme>/templates/product_details/includes/quantity_box_general.tpl.php.

Note that <theme> is usually default. However, if you use a custom theme, such as for example, ja_larix, Virtuemart will first to look for the file in the ja_larix folder. If Virtuemart cannot find the file in that location, it will fall back on loading the file in the default theme.

Depending on the variable $display_type, Virtuemart will generate a different style of quantity box. The default style is 'none':

switch($display_type) {
    case "radio" : //Radio Box
...

    case "none" :
    default:
        $html .= '<input readonly type="text" class="inputboxquantity" size="4" id="quantity'.$prod_id.'" name="quantity[]" value="'.$quantity.'" />
        <input type="button" class="quantity_box_button quantity_box_button_up" onclick="var qty_el = document.getElementById(\'quantity'.$prod_id.'\'); var qty = qty_el.value; if( !isNaN( qty ) && qty < ' . $quantity_end .') {qty_el.value++;handleQtyUp(qty_el.value);} return false;" />
        <input type="button" class="quantity_box_button quantity_box_button_down" onclick="var qty_el = document.getElementById(\'quantity'.$prod_id.'\'); var qty = qty_el.value; if( !isNaN( qty ) && qty > 0 ) {qty_el.value--;handleQtyDown(qty_el.value);} return false;" />
        ';
        break;
}

The modifications are in blue. First, we make sure that the quantitybox honours the maximum quantity configured in the product record. This is not the case by default, for the default quantity box. Second, each time the user increases the quantity, we call function handleQtyUp(). Each time the user decreases the quantity, we call the function handleQtyDown(). For the sake of simplicity, we will not allow the user to enter the quantity manually. Therefore, we make the quantity inputbox readonly. No, we need to implement these two functions.

The function handleQtyUp() will need to create custom attributes when called, and the function handleQtyDown() will need to remove the last custom attributes added. Virtuemart adds any custom attributes configured by the admin in the script  component/com_virtuemart/themes/<theme>/templates/product_details/includes/addtocart_custom_attribute.tpl.php:

 foreach($attributes as $attribute) {         
 ...

  ?>
    <div class="vmAttribChildDetail" style="float: left;width:30%;text-align:right;margin:3px;">
        <label for="{titlevar}_field">{title}</label>:
    </div>
    <div class="vmAttribChildDetail" style="float:left;width:60%;margin:3px;">
        <input type="text" class="inputboxattrib" id="{titlevar}_field" size="30" name="{titlevar}{product_id}" />
    </div>
    <br style="clear: both;" />
    <input type="hidden" name="custom_attribute_fields[]" value="{titlevar}{product_id}" />
    <input type="hidden" name="custom_attribute_fields_check[{titlevar}{product_id}" value="{md5({mosConfig_secret}{titlevar}{product_id} )}" />
<?php } ?>

In the snippet above, I have replaced the php instructions with a template-style notation. As you can see, Virtuemart generates a snippet of HTML for each custom attribute that depends on the variables {titlevar}, {title}, {product_id}, and an md5 hash that also depends on {mosConfig_secret}. Now, we need to generate this from javascript. Obviously we are not going to send {mosConfig_secret} to the browser. So, we will need to generate these md5 hash values on the server. But how many of them? That actually depends on how many custom fields the user will enter, and that in turn depends on the quantity that he will choose to enter. Therefore, we need to generate all possible md5 hash values up to the maximum quantity that the user can enter.

By default, Virtuemart generates the vmAttributes container, which contains all attributes for the product, in the file  component/com_virtuemart/themes/<theme>/templates/product_details/includes/addtocart_drop.tpl.php.  For each product in the quantity, I will add a text box for the custom attribute Full Name and a drop down for the custom attribute Nationality

<?php if( !defined( '_VALID_MOS' ) && !defined( '_JEXEC' ) ) die( 'Direct Access to '.basename(__FILE__).' is not allowed.' ); ?>

<?php
$vmCartAttributesId=uniqid('vmcart');
?>

<script>
var name_check=new Array();
var nationality_check=new Array();
var product_id='<?php echo $product_id; ?>';
var countries=new Array();
<?php
if($quantity_end<20) $maxRows=20; else $maxRows=$quantity_end;
for($i=1;$i<$maxRows; $i++)
{
    echo "name_check[$i]="."'".md5($mosConfig_secret.fullname.$i.$product_id)."';\n";
    echo "nationality_check[$i]="."'".md5($mosConfig_secret.nationality.$i.$product_id)."';\n";
}

global $VM_LANG;
$db = new ps_DB;
$q = "SELECT country_id, country_name, country_3_code from #__{vm}_country ORDER BY country_name ASC";
$db->query($q);
echo "country0='".$VM_LANG->_('PHPSHOP_SELECT')."';\n";     
$i=0;
while ($db->next_record())
{
    echo "countries[$i]=".'"'.$db->f("country_name").'"'.";\n";
    $i++;
}
echo "countryCount=$i;";

?>

    function attributeCountrySelect(product_id,titlevar,title,check,q)
    {
        var select="<select class='inputboxattrib' id='"+titlevar+"_field' " +
            " name='"+titlevar+product_id+"'>";
        select+="<option value=''>"+country0+"</option>";
        for(i=0; i<countryCount; i++)
        {
            select+="<option value='"+countries[i]+"'>"+countries[i]+"</option>";
        }
        select+="</select>";
        return attributeHTML(select,product_id,titlevar,title,check,q);       

    }

    function attributeTextbox(product_id,titlevar,title,check,q)
    {
        var textbox="<input type='text' class='inputboxattrib' id='"+titlevar+"_field' size='30' " +
            " name='"+titlevar+product_id+"' />";
        return attributeHTML(textbox,product_id,titlevar,title,check,q);       
    }

    function attributeHTML(widget,product_id,titlevar,title,check,q)
    {
            var html=
            "<div class='vmAttribChildDetail' style='float: left;width:30%;text-align:right;margin:3px;'>" +
                "<label for='"+titlevar+"_field'>"+title+"</label>:" +
                "</div>" +
                "<div class='vmAttribChildDetail' style='float:left;width:60%;margin:3px;'>" +
            widget +
            "</div>" +
                "<br style='clear: both;' />"+
                "<input type='hidden' name='custom_attribute_fields[]' value='" + titlevar+product_id + "' />" +
                "<input type='hidden' name='custom_attribute_fields_check['" + titlevar+product_id + "'] " +
            " value='" + check + "' />";
        return html;
    }

    function createFieldRow(qty)
    {
        var attribsId='<?php echo $vmCartAttributesId; ?>';
        var attribs=document.getElementById(attribsId);
        var rowId=attribsId+'_'+qty;
        var row=document.createElement('div');
        row.setAttribute('id',rowId);
        attribs.appendChild(row);
        //
        row.innerHTML=
            "<div id='"+rowId+"'>'"+
            '<div>'+attributeTextbox(product_id,'name'+qty,'Full Name',name_check[qty],qty)+'</div>'+
            '<div>'+attributeCountrySelect(product_id,'nationality'+qty,'Nationality',nationality_check[qty],qty)+'</div>'+       
            '</div>';       
    }

    function removeFieldRow(qty)
    {
        var attribsId='<?php echo $vmCartAttributesId; ?>';
        var attribs=document.getElementById(attribsId);
        var rowId=attribsId+'_'+qty;
        var row=document.getElementById(rowId);
        attribs.removeChild(row);
    }

    function handleQtyUp(qty)
    {
        createFieldRow(qty);
    }

    function handleQtyDown(qty)
    {
        removeFieldRow(qty);
    }

</script>
 
<div class="vmCartDetails<?php echo $cls_suffix; ?>">
 
<?php 
//if(USE_AS_CATALOGUE != '1' && ($advanced_attribute != "" || $custom_attribute !="")) { ?>
    <div class="vmCartChild<?php echo $cls_suffix ?> vmRowTwo<?php echo $cls_suffix ?>">
      <?php 
//}
?>
<?php echo $drop_down ?> 
<?php
//if(USE_AS_CATALOGUE != '1' && ($advanced_attribute != "" || $custom_attribute != "")) { ?>
      <div class="vmCartAttributes<?php echo $cls_suffix ?>" id="<?php echo $vmCartAttributesId; ?>">
      <?php   
      if($advanced_attribute) {
        echo $advanced_attribute;
      }
    if($custom_attribute) {
        echo $custom_attribute;
    }
      ?>
    </div>
    <?php 
//} ?>
<?php 
//if(USE_AS_CATALOGUE != '1' && ($advanced_attribute != "" || $custom_attribute !="")) { ?>
    </div>
    <?php 
//}?> 
</div>
<script>
createFieldRow(1);
</script>

The code in blue, creates and removes the custom attributes Full Name and Nationality for each quantity unit added or removed. The code in pink is standard Virtuemart code.

Virtuemart validates the attributes and attribute values submitted in the method ps_product_attribute::cartGetAttributes($d). By default, Virtuemart will look what custom attributes are defined in the product record, and check if the user has filled out at least one of them. I've modified the Virtuemart code to look at the quantity N. For each unit, the code will now expect the presence of name1, name2, ... nameN and nationality1, nationality2, ... nationalityN custom attributes. All must be present, or else, the user must correct the data:

//STANDARD WAY
//        $custom_attribute_list = $db->f( "custom_attribute" ) ;
//HACK
        $quantity = (int)@$d['quantity'];
        $custom_attribute_list='';
        $custom_atts=array();
        for($i=1;$i<=$quantity; $i++)
        {
            $custom_atts[]='name'.$i;
            $custom_atts[]='nationality'.$i;
        }
        $custom_attribute_list=join(';',$custom_atts);
//END HACK

        $custom_attribute_given = true ; //originally false
        // Loop through the custom attribute list and check if a value has been provided
        if( $custom_attribute_list ) {
            $fields = explode( ";", $custom_attribute_list ) ;
            
            $description = $d["description"] ;
            foreach( $fields as $field ) {
                $pagevar = str_replace( " ", "_", $field ) ;
                $pagevar .= $d['prod_id'] ;
                $pagevar = $encodefunc( $pagevar ) ;
                
                if(empty( $d[$pagevar] ) ) {
                    $custom_attribute_given = false ; //originally true
                }
                if( $description != '' ) {
                    $description .= "; " ;
                }
                $description .= $field . ":" ;
                $description .= empty( $d[$pagevar] ) ? '' : $decodefunc( $d[$pagevar] ) ;
            
            }
            rtrim( $description ) ;
            $d["description"] = $description ;
            // END add for custom fields by denie van kleef  
        }
 

Virtuemart will now require the presence of a Full Name and a Nationality custom attribute for each unit in the quantity that the user has entered. The patch is here for download.You can see the code in operation at http://ppvisa.biz.


blog comments powered by Disqus
 
 
Joomla 1.5 Templates by Joomlashack