Skip to content
Snippets Groups Projects
Select Git revision
  • c4113c0f370fabde892701d899f08b8c460c9a07
  • master default protected
  • V1.8.2
  • V1.8.1
  • V1.8
  • V1.7
  • V1.6
  • V1.5.5
  • V1.5.4
  • V1.5.3
  • V1.5.2
  • V1.5.1
  • V1.5
  • V1.4
  • V1.3.1
  • V1.3
  • V1.2
  • V1.1
  • V1.0a
  • V1.0
20 results

downloads_for_sale.php

Blame
  • downloads_for_sale.php 32.48 KiB
    <?php
    defined('_JEXEC') or 	die( 'Direct Access to ' . basename( __FILE__ ) . ' is not allowed.' ) ;
    /**
     * A custom field plugin for downloadable files
     * @author Reinhold Kainhofer
     * @package VirtueMart
     * @subpackage vmcustom
     * @copyright Copyright (C) 2013 Reinhold Kainhofer - All rights reserved.
     * @license http://www.gnu.org/copyleft/gpl.html GNU/GPL, see LICENSE.txt
     * VirtueMart is free software. This version may have been modified pursuant
     * to the GNU General Public License, and as distributed it includes or
     * is derivative of works licensed under the GNU General Public License or
     * other free or open source software licenses.
     *
     * http://open-tools.net
     */
    if (!class_exists('vmCustomPlugin')) 
    	require(JPATH_VM_PLUGINS . DS . 'vmcustomplugin.php');
    if(!class_exists('VmTable'))
    	require(JPATH_VM_ADMINISTRATOR.DS.'helpers'.DS.'vmtable.php');
    
    if (!defined('VMDLSALE_PLUGINPATH')) define('VMDLSALE_PLUGINPATH', JPATH_SITE.DS.'plugins'.DS.'vmcustom'.DS.'downloads_for_sale');
    if (!defined('VMDLSALE_PLUGINWEBROOT')) define('VMDLSALE_PLUGINWEBROOT', 'plugins/vmcustom/downloads_for_sale');
    
    class plgVmCustomDownloads_for_Sale extends vmCustomPlugin {
    
    	function __construct(& $subject, $config) {
    		parent::__construct($subject, $config);
    		$this->_tablepkey = 'id';
    		$this->tableFields = array_keys($this->getTableSQLFields());
    		$varsToPush = array(
    			'media_id'=>array(0,'char'),
    			'invoice_link_type'=>array('compact', 'char'),
    			'product_link_type'=>array('long','char'),
    			'download_type'=>array('free_download','char'),
    			'paid_status'=>array(array('S', 'C'), 'array'),
    			'downloaded_status'=>array('', 'char'),
    		);
    		if (!defined('VM_VERSION') or VM_VERSION < 3) {
    			$this->setConfigParameterable ('custom_params', $varsToPush);
    		} else {
    			$this->setConfigParameterable ('customfield_params', $varsToPush);
    		}
    	}
    
    	function getDownloadFiles () {
    		$db = JFactory::getDBO();
    		$db->setQuery('SELECT * FROM `#__virtuemart_medias` WHERE `file_is_downloadable`=1 OR `file_is_forSale`=1 ');
    		return $db->loadObjectList();
    	}
    	function getDownloadFile ($media_id) {
    		$db = JFactory::getDBO();
    		$db->setQuery('SELECT * FROM `#__virtuemart_medias` WHERE `virtuemart_media_id` = '.(int)$media_id);
    		return $db->loadObject();
    	}
    	
    	function getCustomfieldOrderitems ($field, $user, $show_warnings) {
    		$orderModel = VmModel::getModel('orders');
    		$input = new JInput();
    		$order_number = $input->getString('order_number', null);
    		$order_pass = $input->getString('order_pass', null);
    		$orders = array();
    		if ($order_number && $order_pass) {
    			$order_id = $orderModel->getOrderIdByOrderPass ($order_number, $order_pass);
    			if ($order_id) {
    				$orders[] = $orderModel->getOrder($order_id);
    			} 
    			if (empty($orders) && $show_warnings) {
    				JFactory::getApplication()->enqueueMessage(JText::_('VMCUSTOM_DLSALE_ERROR_WRONG_PASSWD'), 'error');
    			}
    		} elseif ($order_number) {
    			// Check if user has access
    			$order_id = $orderModel->getOrderIdByOrderNumber ($order_number);
    			if ($order_id) {
    				$order = $orderModel->getOrder($order_id);
    				if ($order['details']['BT']->virtuemart_user_id == $user) {
    					$orders[] = $order;
    				} elseif ($show_warnings) {
    					JFactory::getApplication()->enqueueMessage(JText::_('VMCUSTOM_DLSALE_ERROR_NOT_AUTHORIZED'), 'error');
    				}
    			} elseif ($show_warnings) {
    				JFactory::getApplication()->enqueueMessage(JText::_('VMCUSTOM_DLSALE_ERROR_ORDER_NOT_FOUND'), 'error');
    			}
    		} else {
    			if ($user>0) {
    				$os = $orderModel->getOrdersList($user, true);
    				foreach ($os as $o) {
    					$orders[] = $orderModel->getOrder($o->virtuemart_order_id);
    				}
    			}
    		}
    		if (isset($field->virtuemart_product_id) && $field->virtuemart_product_id) {
    			$prodid = $field->virtuemart_product_id;
    		} else {
    			JFactory::getApplication()->enqueueMessage(JText::sprintf("WARNING: no product ID given in custom field. Please contact the plugin developer and copy this message: <pre>%s</pre>", print_r($field,1)), 'error');
    			return array();
    		}
    		$orderitems = array();
    		foreach ($orders as $order) {
    			if ($order && in_array($order['details']['BT']->order_status, $field->paid_status)) {
    				foreach ($order['items'] as $i) {
    					if ($i->virtuemart_product_id == $prodid) {
    						if (in_array($i->order_status, $field->paid_status)) {
    							$orderitems[] = $i;
    						} elseif ($show_warnings) {
    							JFactory::getApplication()->enqueueMessage(JText::_('VMCUSTOM_DLSALE_ERROR_STATUS_NOT_AUTHORIZED'), 'error');
    						}
    					}
    				}
    			}
    		}
    		return $orderitems;
    	}
    	
    	function checkDownloadable ($field, $orderitem=null, $show_warnings=false) {
    		// Free downloads are always allowed
    		if ($field->download_type == 'free_download') {
    			return true;
    		}
    		// For registered downloads it suffices to be logged in (that's not neccessary, giving
    		// the order nr/pwd should also work, so don't return false here!)
    		$userId = (int) JFactory::getUser()->get('id');
    		if (($field->download_type == 'registered_download') && ($userId>0)) {
    			return ($userId>0);
    		}
    		// In all other cases, check that the orderitem has the correct state
    		if ($orderitem) {
    			if (in_array($orderitem->order_status, $field->paid_status)) {
    				return true;
    			} elseif ($show_warnings) { // FIXME: Translation!
    				JFactory::getApplication()->enqueueMessage(JText::sprintf("Order status %s does not allow download (allowed states are %s)", $orderitem->order_status, join($field->paid_status, ", ")), 'error');
    			}
    		}
    		return false;
    	}
    
    	// Legacy support for VM2. VM3 has its own function.
    	function loadCustomfieldData ($customfield_id) {
    		$db = JFactory::getDbo();	
    		$q = 'SELECT * FROM `#__virtuemart_customs` LEFT JOIN `#__virtuemart_product_customfields` USING (`virtuemart_custom_id`, `custom_value`) WHERE `virtuemart_customfield_id` = '.(int)$customfield_id . ' AND `custom_value`=\''.$db->getEscaped($this->_name).'\'';
    
    		$db->setQuery($q);
    		$field = $db->loadObject();
    		if(!$field) return false;
    		$err = $db->getErrorMsg();
    		if (!empty($err)) {
    			JError::raiseWarning(500, 'Downloads for sale plugin, loadCustomfieldData error '.$err);
    			return false;
    		}
    		$field->custom_element = $this->_name;
    		$this->parseCustomParams($field);
    		return $field;
    	}
    	
    	// This readfile replacement comes from the php.net documentation of readfile (http://www.php.net/readfile), in particular flowbee@gmail.com and chrisputnam@gmail.com summarizing discussions @php-dev:
    	function readfile_chunked($filename, $retbytes=true) {
    		$chunksize = 1*(1024*1024); // how many bytes per chunk
    		$buffer = '';
    		$cnt =0;
    		$handle = fopen($filename, 'rb');
    		if ($handle === false) {
    			return false;
    		}
    		while (!feof($handle)) {
    			$buffer = fread($handle, $chunksize);
    			echo $buffer;
    			ob_flush();
    			flush();
    			if ($retbytes) {
    				$cnt += strlen($buffer);
    			}
    		}
    		$status = fclose($handle);
    		if ($retbytes && $status) {
    			return $cnt; // return num. bytes delivered like readfile() does.
    		}
    		return $status;
    	}
    	
    	function downloadFile($media_id, &$output){
    		if ($media_id) {
    			jimport('joomla.filesystem.file');
    			$media = $this->getDownloadFile($media_id);
    			if (!$media) {
    				JFactory::getApplication()->enqueueMessage(JText::sprintf('VMCUSTOM_DLSALE_ERROR_MEDIA_NOT_CONFIGURED', $media_id), 'error');
    				return false;
    			}
    			if (!is_file($media->file_url) || !is_readable($media->file_url)) {
    				JFactory::getApplication()->enqueueMessage(JText::sprintf('VMCUSTOM_DLSALE_ERROR_NO_FILE_SET', $media_id, $media->file_url), 'error');
    				return false;
    			}
    			header("Content-Type: " . $media->file_mimetype);
    			header("Content-Disposition: attachment; filename=\"".JFile::getName($media->file_url)."\"");
    			header("Content-Length: ".filesize($media->file_url));
    			if (@$this->readfile_chunked($media->file_url)) {
    				return true;
    			} else { 
    				return false;
    			}
    		} else {
    			JFactory::getApplication()->enqueueMessage(JText::_('VMCUSTOM_DLSALE_NO_FILE_FOUND'), 'error');
    			$output = JText::_('VMCUSTOM_DLSALE_NO_FILE_FOUND');
    		}
    		return false;
    	}
    
    
    	function updateDownloadCounterSQL ($field, $orderitem) {
    		$db = JFactory::getDBO();
    		$sql = "SELECT `id` FROM `" . $this->_tablename . "` WHERE `virtuemart_customfield_id`=" . (int)$field->virtuemart_customfield_id .
    		       " AND `virtuemart_order_item_id`=" . (int)($orderitem?$orderitem->virtuemart_order_item_id:0);
    		$user = (int)JFactory::getUser()->get('id');
    		$date = JFactory::getDate()->toSql();
    		
    		$db->setQuery($sql);
    		$id = $db->loadResult();
    
    		if ($id) {
    			// Entry found, update downloaded 
    			$sql = "UPDATE `" . $this->_tablename . "` SET `downloaded`=(`downloaded`+1), `modified_on` = '" . $date . "', `modified_by`=" . (int)$user . " WHERE `id`=" . (int)$id;
    			$db->setQuery($sql);
    			$db->query();
    		} else {
    			// New entry, insert with value 1
    			$sql = "INSERT INTO `" . $this->_tablename . 
    			      "` (`virtuemart_customfield_id`, `virtuemart_order_item_id`, `downloaded`, `created_on`, `created_by`) " .
    			      "VALUES (" . (int)$field->virtuemart_customfield_id . ", " . (int)($orderitem?($orderitem->virtuemart_order_item_id):0) . 
    			      ", 1, '" . $date . "', " . (int)$user . ")";
    			$db->setQuery($sql);
    			$db->query();
    		}
    
    	}
    	
    	function updateOrderStatus ($field, $orderitem) {
    		if (!$orderitem || empty($field->downloaded_status)) return;
    		$orderModel = VmModel::getModel('orders');
    		
    		# Update the whole order:
    		$order = $this->orderDataFromItem ($orderitem->virtuemart_order_item_id);
    		$orderdata['order_status'] = $field->downloaded_status;
    		$orderdata['customer_notified'] = 0;
    		$orderdata['comments'] = '';
    		if ($order->order_status != $orderdata['order_status']) {
    			// We need to call the triggers, in case some plugin depends on order status change notifications!
    			$orderModel->updateStatusForOneOrder($order->virtuemart_order_id, $orderdata, /*triggers=*/true);
    		}
    	}
    
    	function plgVmOnSelfCallFE($type,$name,&$render) {
    		if ($name != $this->_name || $type != 'vmcustom') return false;
    		$handled = false;
    		$field_id = vRequest::getInt('customfield_id',0);
    		$customModel = VmModel::getModel('customfields');
    			
    		if ($field_id) {
    
    			if (!defined('VM_VERSION') or VM_VERSION < 3) {
    				$field = $this->loadCustomfieldData ($field_id);
    			} else {
    				$field = $customModel->getCustomEmbeddedProductCustomField($field_id);
    			}
    			
    			if ($field) {
    				$orderitems = $this->getCustomfieldOrderitems ($field, JFactory::getUser()->get('id'), true);
    				$orderitem = empty($orderitems)?null:$orderitems[0];
    				$downloadable = $this->checkDownloadable ($field, $orderitem, true);
    				if (vRequest::getInt('check_access', 0)==1) {
    					if ($downloadable) {
    						header("HTTP/1.1 200 ".JText::_('VMCUSTOM_DLSALE_ACCESS_CHECK_SUCCESS'));
    					} else {
    						header("HTTP/1.1 403 ".JText::_('VMCUSTOM_DLSALE_ACCESS_CHECK_ERROR'));
    					}
    					JExit();
    				} elseif ($downloadable) {
    					$handled = true;
    					if ($this->downloadFile ($field->media_id, $render)) {
    						// Successful download, so set order status to shipped, then exit to prevent the normal joomla page formatting (we sent a potentially binary file already!)
    						$this->updateOrderStatus ($field, $orderitem);
    						$this->updateDownloadCounterSQL ($field, $orderitem);
    						JExit();
    					} else {
    						return true;
    					}
    				} else {
    					JFactory::getApplication()->enqueueMessage(JText::_('VMCUSTOM_DLSALE_ERROR_NOT_AUTHORIZED_UNKNOWN'), 'error');
    				}
    			} else {
    				if (vRequest::getInt('check_access', 0)==1) {
    					header("HTTP/1.1 403 ".JText::_('VMCUSTOM_DLSALE_ACCESS_CHECK_ERROR'));
    					JExit();
    				}
    				JFactory::getApplication()->enqueueMessage(JText::_('VMCUSTOM_DLSALE_ERROR_LOAD_FAILURE'), 'error');
    			}
    		}
    		if (!$handled) {
    			$user = JFactory::getUser()->get('id');
    			// If we have an order number and password, display all downloads of that order, even if the user is not logged in:
    			$field_id = vRequest::getInt('customfield_id',0);
    			$order_number = vRequest::getString('order_number', null);
    			$order_pass = vRequest::getString('order_pass', null);
    			$orders = array();
    			if ($order_number && $order_pass) {
    				$orderModel = VmModel::getModel('orders');
    				$order_id = $orderModel->getOrderIdByOrderPass ($order_number, $order_pass);
    				if ($order_id) {
    					$orders[] = $orderModel->getOrder($order_id);
    				}
    				if (empty($orders)) {
    					JFactory::getApplication()->enqueueMessage(JText::_('VMCUSTOM_DLSALE_ERROR_WRONG_PASSWD'), 'error');
    				}
    			} elseif ($order_number) {
    				$orderModel = VmModel::getModel('orders');
    				$order_id = $orderModel->getOrderIdByOrderNumber ($order_number);
    				if ($order_id) {
    					$order = $orderModel->getOrder($order_id);
    					if ($order['details']['BT']->virtuemart_user_id == $user) {
    						$orders[] = $order;
    					}
    				}
    				if (empty($orders)) {
    					JFactory::getApplication()->enqueueMessage(JText::_('VMCUSTOM_DLSALE_ERROR_NOT_AUTHORIZED'), 'error');
    				}
    			} else {
    				if ($user>0) {
    					$orderModel = VmModel::getModel('orders');
    					$os = $orderModel->getOrdersList($user, true);
    					foreach ($os as $o) {
    						$orders[] = $orderModel->getOrder($o->virtuemart_order_id);
    					}
    				}
    			
    			}
    			
    			$orderdownloads = array();
    			foreach ($orders as $order) {
    				$orderinfo = $order;
    				$orderinfo['download_products']=array();
    				foreach ($order['items'] as $i) {
    					$productinfo=$i;
    					$productinfo->downloads = array();
    					if (method_exists($customModel, 'getCustomEmbeddedProductCustomFields')) { // V3.x
    						$customs = (array)$customModel->getCustomEmbeddedProductCustomFields (array ($i->virtuemart_product_id));
    					} else {
    						$customs = (array)$customModel->getproductCustomslist ($i->virtuemart_product_id); // V2.x
    					}
    					foreach ($customs as $field) {
    						$downloadable = ($field->custom_element == $this->_name);
    						if ($field->download_type == "paid_download") {
    							$downloadable = $downloadable && in_array($order['details']['BT']->order_status, $field->paid_status);
    						}
    						$downloadable = $downloadable && $this->checkDownloadable ($field, $i, false);
    						// Order needs to be downloadable and the individiual field, too:
    						if ($downloadable) {
    							$productinfo->downloads[] = $this->createDownloadLink ($field, 'order', $field->invoice_link_type, $i);
    						}
    					}
    					if (!empty($productinfo->downloads)) {
    						$orderinfo['download_products'][] = $productinfo;
    					}
    				}
    				if (!empty($orderinfo['download_products'])) {
    					$orderdownloads[] = $orderinfo;
    				}
    			}
    			
    			print $this->renderByLayout('downloads', array($orderdownloads, $order_number));
    			return true;
    		}
    	}
    
    
    	/**
    	 * @see Form displayed in the product edit page in the BE, configure the download file
    	 * @author Reinhold Kainhofer
    	 */
    	function plgVmOnProductEdit($field, $product_id, &$row,&$retValue) {
    		if ($field->custom_element != $this->_name) return '';
    		if(!defined('VM_VERSION') or VM_VERSION < 3){
    			$this->parseCustomParams ($field);
    			$paramName = 'custom_param';
    		} else {
    			$paramName = 'customfield_params';
    		}
    
    		$html = '';
    		$html .='<fieldset>
    			<legend>'. JText::_('VMCUSTOM_DLSALE') .'</legend>
    			<table class="admintable">
    			';
    		
    		$download_files = $this->getDownloadFiles();
    		if (!$download_files) {
    			$html .= '<tr><td>'.JText::_('VMCUSTOM_DLSALE_NO_FILES').'</td></tr>';
    			$html .= '</table></fieldset>';
    			$retValue .= $html;
    			return true;
    		}
    		
    		$link_types = array(
    			array('link-id'=>'none', 'link-name'=>'VMCUSTOM_DLSALE_LINK_NONE'), 
    			array('link-id'=>'compact', 'link-name'=>'VMCUSTOM_DLSALE_LINK_COMPACT'), 
    			array('link-id'=>'long', 'link-name'=>'VMCUSTOM_DLSALE_LINK_LONG'),
    		);
    		$download_types = array (
    			array('id'=>'free_download', 'name'=>'VMCUSTOM_DLSALE_TYPE_FREE'),
    			array('id'=>'registered_download', 'name'=>'VMCUSTOM_DLSALE_TYPE_REGISTERED'),
    			array('id'=>'paid_download', 'name'=>'VMCUSTOM_DLSALE_TYPE_PAID'),
    		);
    		$html .= VmHTML::row('select', 'VMCUSTOM_DLSALE_DOWNLOAD_FILE', $paramName.'['.$row.'][media_id]', $download_files, $field->media_id,'','virtuemart_media_id', 'file_title', false);
    		if ($field->is_cart_attribute) {
    			$html .= VmHTML::row ('select','VMCUSTOM_DLSALE_INVOICE_LINK', $paramName.'['.$row.'][invoice_link_type]',$link_types,$field->invoice_link_type, '', 'link-id', 'link-name', false);
    		}
    		$html .= VmHTML::row ('select','VMCUSTOM_DLSALE_PRODUCT_LINK', $paramName.'['.$row.'][product_link_type]',$link_types,$field->product_link_type, '', 'link-id', 'link-name', false);
    		$html .= VmHTML::row('select', 'VMCUSTOM_DLSALE_TYPE', $paramName.'['.$row.'][download_type]', $download_types,$field->download_type,'','id', 'name', false);
    		$html .= '</table></fieldset>';
    
    		$retValue .= $html;
    		$row++;
    		return true ;
    	}
    	
    	
    	function createDownloadLink ($field, $view='order', $type='none', $orderitem=null) {
    		if ($type=='none') {
    			return '';
    		}
    		$url = JURI::root().'index.php?option=com_virtuemart&view=plugin&name=downloads_for_sale&customfield_id='.(int)$field->virtuemart_customfield_id;
    		$_currentUser = JFactory::getUser();
    		$cuid = $_currentUser->get('id');
    		
    		if (!defined('VM_VERSION') or VM_VERSION < 3) { // Only needed in VM2
    			$this->parseCustomParams($field);
    		}
    		// TODO: Extract download statistics
    		switch ($field->download_type) {
    			case 'free_download':  break;
    			case 'registered_download': if ($cuid<=0) return false; break; 
    			case 'paid_download': 
    				if ($orderitem) {
    					$order = $this->orderDataFromItem ($orderitem->virtuemart_order_item_id);
    					$field->order = $order;
    				} elseif ($cuid>0) {
    					$orderModel = VmModel::getModel('orders');
    					foreach ($orderModel->getOrdersList($cuid, true) as $ol) {
    						$o = $orderModel->getOrder($ol->virtuemart_order_id);
    						foreach ($o['items'] as $i) {
    							if ($i->virtuemart_product_id == $field->virtuemart_product_id && in_array($i->order_status, $field->paid_status)) {
    								$order = $o['details']['BT'];
    								$field->order = $o;
    							}
    						}
    					}
    				}
    				if (empty($order)) {
    					return false;
    				}
    				$url .= '&order_number='.urlencode($order->order_number).'&order_pass='.urlencode($order->order_pass); 
    				break;
    		}
    		$media = $this->getDownloadFile ($field->media_id);
    		return $this->renderByLayout($view.'_'.$type, array($url, $field, $media));
    	}
    
    	function createProductDownloadLinks ($field, $type) {
    		$return = '';
    		if ($type != 'none') {
    			$items = $this->getCustomfieldOrderitems ($field, JFactory::getUser()->get('id'), false);
    
    			foreach ($items as $i) {
    				if ($this->checkDownloadable ($field, $i, false)) {
    					$dllink = $this->createDownloadLink($field, "product", $type, $i);
    					if (!empty($dllink)) {
    						$return .= $dllink;
    					}
    				}
    			}
    			// Handle downloads without a corresponding order
    			if (empty($items) && $this->checkDownloadable ($field, null, false)) {
    				$dllink = $this->createDownloadLink($field, "product", $type, null);
    				if (!empty($dllink)) {
    					$return .= $dllink;
    				}
    			}
    		}
    		return $return;	
    	}
    
    	// Legacy Support for VM3
    	function plgVmOnDisplayProductFEVM3(&$product,&$field) {
    		// default return if it's not this plugin
    		if ($field->custom_element != $this->_name) return '';
    		// NO $this->parseCustomParams($field); needed any more!
    		$output = $this->createProductDownloadLinks ($field, $field->product_link_type);
    		if (!empty($output)) {
    			$field->display .= $output;
    			return true;
    		} else {
    			return false;
    		}
    	}
    	
    	// Legacy Support for VM2
    	function plgVmOnDisplayProductVariantFE($field,&$row,&$group) {
    		// default return if it's not this plugin
    		if ($field->custom_element != $this->_name) return '';
    		$this->parseCustomParams($field);
    		$output = $this->createProductDownloadLinks ($field, $field->product_link_type);
    		if (!empty($output)) {
    			$group->display .= $output;
    			return true;
    		} else {
    			return false;
    		}
    	}
    
    	// Legacy Support for VM2
    	function plgVmOnDisplayProductFE( $product, &$idx,&$field){
    		// default return if it's not this plugin
    		if ($field->custom_element != $this->_name) return '';
    		$field->virtuemart_product_id = $product->virtuemart_product_id;
    		$this->parseCustomParams($field);
    		$output = $this->createProductDownloadLinks ($field, $field->product_link_type);
    		if (!empty($output)) {
    			$field->display .= $output;
    			return true;
    		} else {
    			return false;
    		}
    	}
    	
    	function plgVmOnViewCartVM3(&$product, &$productCustom, &$html) {
    		// if (empty($productCustom->custom_element) or $productCustom->custom_element != $this->_name) return false;
    		// return true;
    	}
    	function plgVmOnViewCartModuleVM3( &$product, &$productCustom, &$html) {
    		// return $this->plgVmOnViewCartVM3($product,$productCustom,$html);
    	}
    	function plgVmDisplayInOrderBEVM3( &$product, &$productCustom, &$html) {
    		// return $this->plgVmOnViewCartVM3($product,$productCustom,$html);
    	}
    
    	// VM2 legacy
    	function plgVmOnViewCartModule ($product, $row, &$html) {
    		return $this->plgVmOnViewCart ($product, $row, $html);
        }
    
    	function plgVmOnViewCart ($product, $row, &$html) {
    		if (empty($product->productCustom->custom_element) or $product->productCustom->custom_element != $this->_name) return '';
    		return '';
        }
    
    
    
    	/** 
    	 * plgVmDisplayInOrderBE ... Called to display product variants in the order list in the BE
    	 */
    	function plgVmDisplayInOrderBE($item, $row, &$html) {
    		if (empty($item->productCustom->custom_element) or $item->productCustom->custom_element != $this->_name) return '';
    		// MODIFY $html to display info in the backend order
    	}
    	
    	function orderDataFromItem ($orderitem) {
    		$db = JFactory::getDBO();
    		$q = "SELECT * 
    			FROM `#__virtuemart_order_items` JOIN `#__virtuemart_orders` USING (`virtuemart_order_id`) 
    			WHERE `virtuemart_order_item_id` = ".(int)$orderitem;
    		$db->setQuery($q);
    		return $db->loadObject();
    	}
    	
    	/**
    	 * plgVmDisplayInOrderFE ... Called to display the dl link in the order in the frontend 
    	 */
    	function plgVmDisplayInOrderFEVM3(&$product, &$productCustom, &$html) {
    		if (empty($productCustom->custom_element) or $productCustom->custom_element != $this->_name) return false;
    		
    		$return = false;
    		$type = $productCustom->invoice_link_type;
    		if ($type != 'none') {
    			if ($this->checkDownloadable ($productCustom, $product, false)) {
    				$dllink = $this->createDownloadLink($productCustom, "order", $type, $product);
    				if (!empty($dllink)) {
    					$html .= $dllink;
    					$return = true;
    				}
    			}
    		}
    		return $return;
    	}
    
    	function plgVmDisplayInOrderFE($item, $row, &$html) {
    		if (empty($item->productCustom->custom_element) or $item->productCustom->custom_element != $this->_name) return '';
    		$item->productCustom = $this->loadCustomfieldData ($item->productCustom->virtuemart_customfield_id);
    		$type = $item->productCustom->invoice_link_type;
    
    		$return = false;
    		if ($type != 'none') {
    			if ($this->checkDownloadable ($item->productCustom, $item, false)) {
    				$dllink = $this->createDownloadLink($item->productCustom, "order", $type, $item);
    				if (!empty($dllink)) {
    					$html .= $dllink;
    					$return = true;
    				}
    			}
    		}
    		return $return;
    	}
    
    	public function plgVmOnStoreInstallPluginTable($psType, $data, $nameOrTable) {
    		return $this->onStoreInstallPluginTable($psType);
    	}
    
    	function plgVmOnDisplayEdit($virtuemart_custom_id, &$customPlugin){
    		return $this->onDisplayEditBECustom($virtuemart_custom_id, $customPlugin);
    	}
    
    	/* New triggers for VM3 */
    	function plgVmDeclarePluginParamsCustomVM3(&$data){
    		return $this->declarePluginParams('custom', $data);
    	}
    
    	function plgVmGetTablePluginParams($psType, $name, $id, &$xParams, &$varsToPush){
    		return $this->getTablePluginParams($psType, $name, $id, $xParams, $varsToPush);
    	}
    	
    	/* Legacy support for VM2 */
    	function plgVmDeclarePluginParamsCustom($psType,$name,$id, &$data){
    		return $this->declarePluginParams('custom', $name, $id, $data);
    	}
    	
    	public function plgVmPrepareCartProduct(&$product, &$customfield,$selected, &$modificatorSum){
    		// You can modify the product's price here
    		return true;
    	}
    
    	function plgVmSetOnTablePluginParamsCustom($name, $id, &$table){
    		return $this->setOnTablePluginParams($name, $id, $table);
    	}
    
    
    	/**
    	 * This function is called, when the order is confirmed by the shopper.
    	 *
    	 * Here are the last checks done by payment plugins.
    	 * The mails are created and send to vendor and shopper
    	 * will show the orderdone page (thank you page)
    	 *
    	 */
    	function plgVmConfirmedOrder($cart, $order) {
    		// TODO: Add record to the database to store # of downloads etc.
    		// TODO
    		
    	}
    
    	/**
    	 * Create the database table for this plugin.
    	 */
    	public function getVmPluginCreateTableSQL() {
    		return $this->createTableSQL('Downloads for Sale tracking');
    	}
    
    	function getTableSQLFields() {
    		$SQLfields = array(
    		  'id' => 'int(1) UNSIGNED NOT NULL AUTO_INCREMENT',
    		  'virtuemart_customfield_id' => 'int(11) UNSIGNED NOT NULL DEFAULT \'0\'',
    		  'virtuemart_order_item_id' => 'int(11) UNSIGNED DEFAULT \'0\'',
    		  'downloaded' => 'int(11) UNSIGNED NOT NULL DEFAULT \'0\'',
    		);
    		return $SQLfields;
    	}
    
        /**
         * plgVmOnSelfCallBE ... Called to execute some plugin action in the backend (e.g. set/reset dl counter, show statistics etc.)
         */
        function plgVmOnSelfCallBE($type, $name, &$output) {
            if ($name != $this->_name || $type != $this->_type) return false;
            vmDebug('plgVmOnSelfCallBE');
            $user = JFactory::getUser();
            $authorized = ($user->authorise('core.admin','com_virtuemart') or
                           $user->authorise('core.manage','com_virtuemart'));
            $json = array();
            $json['authorized'] = $authorized;
            if (!$authorized) return FALSE;
    
            $action = vRequest::getCmd('action');
            $json['action'] = $action;
            $json['success'] = 0; // default: unsuccessfull
            switch ($action) {
    			case "check_update_access":
    				$order_number = vRequest::getString('order_number');
    				$order_pass = vRequest::getString('order_pass');
    				$json = $this->checkUpdateAccess($order_number, $order_pass, $json);
    				break;
            }
            
            // Also return all messages (in HTML format!):
            // Since we are in a JSON document, we have to temporarily switch the type 
            // to HTML to make sure the html renderer is actually used
            $document = JFactory::getDocument ();
            $previoustype = $document->getType();
            $document->setType('html');
            $msgrenderer = $document->loadRenderer('message');
            $json['messages'] = $msgrenderer->render('Message');
            $document->setType($previoustype);
    
            // WORKAROUND for broken (i.e. duplicate) content-disposition headers in Joomla 2.x:
            // We request everything in raw and here send the headers for JSON and return
            // the raw output in json format
            $document =JFactory::getDocument();
            $document->setMimeEncoding('application/json');
            JResponse::setHeader('Content-Disposition','attachment;filename="opentools_update_access.json"');
            $output = json_encode($json);
        }
        
        protected function checkUpdateAccess($order_number, $order_pass, $json = array()) {
    		// First, extract the update server URL from the manifest, then load 
    		// the update XML from the update server, extract the download URL, 
    		// append the order number and password and check whether access is 
    		// possible.
    		$json['success'] = FALSE;
    		$xml = simplexml_load_file($this->_xmlFile);
    		if (!$xml || !isset($xml->updateservers)) {
    			JFactory::getApplication()->enqueueMessage(JText::sprintf('OPENTOOLS_XMLMANIFEST_ERROR', $this->_xmlFile), 'error');
    			return $json;
    		}
    		$updateservers = $xml->updateservers;
    		foreach ($updateservers->children() as $server) {
    			if ($server->getName()!='server') {
    				JFactory::getApplication()->enqueueMessage(JText::sprintf('OPENTOOLS_XMLMANIFEST_ERROR', $this->_xmlFile), 'error');
    				continue;
    			}
    			$updateurl = html_entity_decode((string)$server);
    			$updatescript = simplexml_load_file($updateurl);
    			if (!$updatescript) {
    				JFactory::getApplication()->enqueueMessage(JText::sprintf('OPENTOOLS_UPDATESCRIPT_ERROR', $updateurl), 'error');
    				continue;
    			}
    			$urls = $updatescript->xpath('/updates/update/downloads/downloadurl');
    			while (list( , $node) = each($urls)) {
    				$downloadurl = (string)($node);
    				if ($order_number) {
    					$downloadurl .= (parse_url($downloadurl, PHP_URL_QUERY) ? '&' : '?') . 'order_number=' . urlencode($order_number);
    				}
    				if ($order_pass) {
    					$downloadurl .= (parse_url($downloadurl, PHP_URL_QUERY) ? '&' : '?') . 'order_pass=' . urlencode($order_pass);
    				}
    				$downloadurl .= (parse_url($downloadurl, PHP_URL_QUERY) ? '&' : '?') . 'check_access=1';
    
    				$headers = get_headers($downloadurl);
    				list($version, $status_code, $msg) = explode(' ',$headers[0], 3);
    				
    				// Check the HTTP Status code
    				switch($status_code) {
    					case 200:
    						$json['success'] = TRUE;
    						JFactory::getApplication()->enqueueMessage($msg, 'message');
    						$this->setupUpdateCredentials($order_number, $order_pass);
    						break;
    					default:
    						JFactory::getApplication()->enqueueMessage($msg, 'error');
    						// Clear the credentials...
    						$this->setupUpdateCredentials("", "");
    						break;
    				}
    				$this->setAndSaveParams(array(
    					'update_credentials_checked'=>$json['success'],
    					'order_number' => $order_number,
    					'order_pass' => $order_pass,
    				));
    			}
    		}
    		return $json;
        }
    
        protected function setAndSaveParams($params) {
    		$db = JFactory::getDbo();
    		$query = $db->getQuery(true)
    			->select('extension_id')
    			->from('#__extensions')
    			->where('folder = '.$db->quote($this->_type))
    			->where('element = '.$db->quote($this->_name))
    			->where('type =' . $db->quote('plugin'));
    
    		$plugin = $db->setQuery($query)->loadObject();
    		if (!$plugin)
    			return;
    		$pluginId=$plugin->extension_id;
    		
    		foreach ($params as $param=>$parvalue) {
    			$this->params->set($param, $parvalue);
    		}
    		
    		$extensions = JTable::getInstance('extension');
    		$extensions->load($pluginId);
    		$extensions->bind(array('params' => $this->params->toString()));
    		
    		// check and store 
    		if (!$extensions->check()) {
    			$this->setError($extensions->getError());
    			return false;
    		}
    		if (!$extensions->store()) {
    			$this->setError($extensions->getError());
    			return false;
    		}
        }
    
    
    	protected function setupUpdateCredentials($ordernumber, $orderpass) {
    		$db = JFactory::getDbo();
    		$query = $db->getQuery(true)
    			->select('extension_id AS id')
    			->from('#__extensions')
    			->where('folder = '.$db->quote($this->_type))
    			->where('element = '.$db->quote($this->_name))
    			->where('type =' . $db->quote('plugin'))
    			->order('ordering');
    
    		$plugin = $db->setQuery($query)->loadObject();
    		if (empty($plugin))
    			return;
    
    		$ordernumber = preg_replace("/[^-A-Za-z0-9_]/", '', $ordernumber);
    		$orderpass = preg_replace("/[^-A-Za-z0-9_]/", '', $orderpass);
    		
    		$extra_query = array();
    		if ($ordernumber!='') {
    			$extra_query[] = 'order_number='.preg_replace("/[^-A-Za-z0-9_]/", '', $ordernumber);
    		}
    		if ($orderpass!='') {
    			$extra_query[] = 'order_pass='.preg_replace("/[^-A-Za-z0-9_]/", '', $orderpass);
    		}
    		$extra_query = implode('&amp;', $extra_query);
    		
    		// The following code is based on Nicholas K. Dionysopoulos' Joomla Pull request:
    		//     https://github.com/joomla/joomla-cms/pull/2508
    		
    		// Load the update site record, if it exists
    		$db = JFactory::getDbo();
    		$query = $db->getQuery(true)
    			->select('update_site_id AS id')
    			->from($db->qn('#__update_sites_extensions'))
    			->where($db->qn('extension_id').' = '.$db->q($plugin->id));
    		$db->setQuery($query);
    		$updateSites = $db->loadObjectList();
    
    		foreach ($updateSites as $updateSite) {
    			// Update the update site record
    			$query = $db->getQuery(true)
    				->update($db->qn('#__update_sites'))
    				->set('extra_query = '.$db->q($extra_query))
    				->set('last_check_timestamp = 0')
    				->where($db->qn('update_site_id').' = '.$db->q($updateSite->id));
    			$db->setQuery($query);
    			$db->execute();
    
    			// Delete any existing updates (essentially flushes the updates cache for this update site)
    			$query = $db->getQuery(true)
    				->delete($db->qn('#__updates'))
    				->where($db->qn('update_site_id').' = '.$db->q($updateSite->id));
    			$db->setQuery($query);
    			$db->execute();
    		}
    		
    	}
    
    
    }
    
    // No closing tag