Index: branches/5.3.x/units/affiliate_plans/affiliate_plans_event_handler.php
===================================================================
--- branches/5.3.x/units/affiliate_plans/affiliate_plans_event_handler.php	(revision 15670)
+++ branches/5.3.x/units/affiliate_plans/affiliate_plans_event_handler.php	(revision 15671)
@@ -1,127 +1,126 @@
 <?php
 /**
 * @version	$Id$
 * @package	In-Commerce
 * @copyright	Copyright (C) 1997 - 2009 Intechnic. All rights reserved.
 * @license	Commercial License
 * This software is protected by copyright law and international treaties.
 * Unauthorized reproduction or unlicensed usage of the code of this program,
 * or any portion of it may result in severe civil and criminal penalties,
 * and will be prosecuted to the maximum extent possible under the law
 * See http://www.in-portal.org/commercial-license for copyright notices and details.
 */
 
 	defined('FULL_PATH') or die('restricted access!');
 
 	class AffiliatePlansEventHandler extends kDBEventHandler {
 
 		/**
 		 * Apply any custom changes to list's sql query
 		 *
 		 * @param kEvent $event
 		 * @return void
 		 * @access protected
 		 * @see kDBEventHandler::OnListBuild()
 		 */
 		protected function SetCustomQuery(kEvent $event)
 		{
 			parent::SetCustomQuery($event);
 
 			if ( $event->Special == 'active' ) {
 				$object = $event->getObject();
 				/* @var $object kDBList */
 
 				$object->addFilter('active', '%1$s.Enabled = 1');
 			}
 		}
 
 		/**
 		 * Enter description here...
 		 *
 		 * @param kEvent $event
 		 */
 		function OnSetPrimary($event)
 		{
 			$object = $event->getObject();
 			$object->SetDBField('IsPrimary', 1);
 			$object->Update();
 		}
 
 		/**
 		 * Occurs before updating item
 		 *
 		 * @param kEvent $event
 		 * @return void
 		 * @access protected
 		 */
 		protected function OnBeforeItemUpdate(kEvent $event)
 		{
 			parent::OnBeforeItemUpdate($event);
 
 			$this->itemChanged($event);
 		}
 
 		/**
 		 * Occurs before creating item
 		 *
 		 * @param kEvent $event
 		 * @return void
 		 * @access protected
 		 */
 		protected function OnBeforeItemCreate(kEvent $event)
 		{
 			parent::OnBeforeItemCreate($event);
 
 			$this->itemChanged($event);
 		}
 
 		/**
 		 * Occurs before item is changed
 		 *
 		 * @param kEvent $event
 		 */
 		function itemChanged($event)
 		{
 			$object = $event->getObject();
 			/* @var $object kDBItem */
 
 			$live_table = $this->Application->getUnitOption($event->Prefix, 'TableName');
 			$plans_count = $this->Conn->GetOne('SELECT COUNT(*) FROM ' . $live_table);
 			if ( !$plans_count ) {
 				$object->SetDBField('IsPrimary', 1);
 			}
 
 			if ( $object->GetDBField('IsPrimary') && $object->Validate() ) {
 				$sql = 'UPDATE ' . $this->Application->getUnitOption($event->Prefix, 'TableName') . '
 						SET IsPrimary = 0';
 				$this->Conn->Query($sql);
 
-				$status_field = array_shift($this->Application->getUnitOption($event->Prefix, 'StatusField'));
-				$object->SetDBField($status_field, 1);
+				$object->SetDBField($object->getStatusField(), 1);
 			}
 		}
 
 		/**
 		 * Don't allow to delete primary affiliate plan
 		 *
 		 * @param kEvent $event
 		 * @param string $type
 		 * @return void
 		 * @access protected
 		 */
 		protected function customProcessing(kEvent $event, $type)
 		{
 			if ( $event->Name == 'OnMassDelete' && $type == 'before' ) {
 				$ids = $event->getEventParam('ids');
 
 				$sql = 'SELECT ' . $this->Application->getUnitOption($event->Prefix, 'IDField') . '
 						FROM ' . $this->Application->getUnitOption($event->Prefix, 'TableName') . '
 						WHERE IsPrimary = 1';
 				$primary_id = $this->Conn->GetOne($sql);
 
 				$ids = array_diff($ids, Array ($primary_id));
 
 				$event->setEventParam('ids', $ids);
 			}
 		}
 	}
\ No newline at end of file
Index: branches/5.3.x/units/gateways/gw_classes/atosorigin.php
===================================================================
--- branches/5.3.x/units/gateways/gw_classes/atosorigin.php	(revision 15670)
+++ branches/5.3.x/units/gateways/gw_classes/atosorigin.php	(revision 15671)
@@ -1,192 +1,192 @@
 <?php
 /**
 * @version	$Id$
 * @package	In-Commerce
 * @copyright	Copyright (C) 1997 - 2009 Intechnic. All rights reserved.
 * @license	Commercial License
 * This software is protected by copyright law and international treaties.
 * Unauthorized reproduction or unlicensed usage of the code of this program,
 * or any portion of it may result in severe civil and criminal penalties,
 * and will be prosecuted to the maximum extent possible under the law
 * See http://www.in-portal.org/commercial-license for copyright notices and details.
 */
 
 	require_once GW_CLASS_PATH.'/gw_base.php';
 
 	$class_name = 'kAtosOriginGW'; // for automatic installation
 
 	class kAtosOriginGW extends kGWBase
 	{
 		function InstallData()
 		{
 			$data = array(
 				'Gateway' => Array('Name' => 'Atos Origin', 'ClassName' => 'kAtosOriginGW', 'ClassFile' => 'atosorigin.php', 'RequireCCFields' => 0),
 				'ConfigFields' => Array(
 					'request_binary' => Array('Name' => 'API Request Executable', 'Type' => 'text', 'ValueList' => '', 'Default' => ''),
 					'response_binary' => Array('Name' => 'API Response Executable', 'Type' => 'text', 'ValueList' => '', 'Default' => ''),
 					'pathfile' => Array('Name' => 'Pathfile', 'Type' => 'text', 'ValueList' => '', 'Default' => ''),
 					'merchant_id' => Array('Name' => 'Merchant ID', 'Type' => 'text', 'ValueList' => '', 'Default' => ''),
 					'merchant_country' => Array('Name' => 'Merchant Country Code', 'Type' => 'text', 'ValueList' => '', 'Default' => ''),
 					'currency_code' => Array('Name' => 'Currency Code', 'Type' => 'text', 'ValueList' => '', 'Default' => '978'),
 					'shipping_control' => Array('Name' => 'Shipping Control', 'Type' => 'select', 'ValueList' => '3=la_CreditDirect,4=la_CreditPreAuthorize', 'Default' => '3'),
 				)
 			);
 			return $data;
 		}
 
 		/**
 		 * Returns payment form submit url
 		 *
 		 * @param Array $gw_params gateway params from payment type config
 		 * @return string
 		 */
 		function getFormAction($gw_params)
 		{
 			return $gw_params['submit_url'];
 		}
 
 		/**
 		 * Processed input data and convets it to fields understandable by gateway
 		 *
 		 * @param Array $item_data
 		 * @param Array $tag_params additional params for gateway passed through tag
 		 * @param Array $gw_params gateway params from payment type config
 		 * @return Array
 		 */
 		function getHiddenFields($item_data, $tag_params, $gw_params)
 		{
 			$params['pathfile'] = $gw_params['pathfile'];
 			$params['merchant_id'] = $gw_params['merchant_id'];
 			$params['merchant_country'] = $gw_params['merchant_country'];
 			$params['currency_code'] = $gw_params['currency_code'];
 			$params['currency_code'] = $gw_params['currency_code'];
 
 			$params['normal_return_url'] = $this->Application->HREF($tag_params['return_template'],'',Array('pass'=>'m'));
 			$params['cancel_return_url'] = $this->Application->HREF($tag_params['cancel_template'],'',Array('pass'=>'m'));
 			$params['automatic_response_url'] = $this->getNotificationUrl('units/gateways/gw_classes/notify_scripts/atosorigin_notify.php');
 
 			$txt_amount = sprintf("%.2f", $item_data['TotalAmount']);
 
 			$params['amount'] = str_replace( Array('.', ','), '', $txt_amount);
 			$params['caddie'] = $this->Application->GetSID() . ',' . MD5($item_data['OrderId']);
 			$params['order_id'] = $item_data['OrderId'];
-			$params['customer_ip_address'] = $_SERVER['REMOTE_ADDR'];
+			$params['customer_ip_address'] = $this->Application->getClientIp();
 			$params['customer_id'] = $item_data['PortalUserId'];
 
 			$billing_email = $item_data['BillingEmail'];
 			if (!$billing_email) {
 				$billing_email = $this->Conn->GetOne('	SELECT Email FROM '.$this->Application->getUnitOption('u', 'TableName').'
 											WHERE PortalUserId = '.$this->Application->RecallVar('user_id'));
 			}
 			$params['customer_email'] = $billing_email;
 
 			$params_str = '';
 			foreach ($params as $key => $val) {
 				$params_str .= ' '.$key . '="'.$val.'"';
 			}
 			$run_line = $gw_params['request_binary'].' '.$params_str;
 
 //			$run_line = escapeshellcmd($run_line);
 //			echo $run_line;
 
 			exec ($run_line, $rets);
 
 			$ret = $rets[0];
 
 			$ret = preg_replace('/^(.*)!!/is', '', $ret);
 			$ret = rtrim($ret, '!');
 
 			return '</form>'.$ret.'<form>';
 		}
 
 		function NeedPlaceButton($item_data, $tag_params, $gw_params)
 		{
 			return false;
 		}
 
 		function processNotification($gw_params)
 		{
 			$params['pathfile'] = $gw_params['pathfile'];
 			$params['message'] = $_POST['DATA'];
 
 			$params_str = '';
 			foreach ($params as $key => $val) {
 				$params_str .= ' '.$key . '="'.$val.'"';
 			}
 			$run_line = $gw_params['response_binary'].' '.$params_str;
 
 			exec ($run_line, $rets);
 			$ret = $rets[0];
 
 			$result = $this->parseGWResponce($ret, $gw_params);
 
 			list ($sid, $auth_code) = explode(',', $result['caddie']);
 			$session = $this->Application->recallObject('Session');
 			$session->SID = $sid;
 
 			$order_id = $this->Conn->GetOne('SELECT OrderId FROM '.TABLE_PREFIX.'Orders WHERE md5(OrderId) = '.$this->Conn->qstr($auth_code));
 			$this->Application->SetVar('ord_id', $order_id);
 			$order = $this->Application->recallObject('ord');
 			$order->Load($order_id);
 
 			return $result['response_code'] === '00' ? 1 : 0;
 		}
 
 		function parseGWResponce($str, $gw_params)
 		{
 			$response = explode ("!", $str);
 
 			$result = Array (
 				'code' => $response[1],
 				'error' => $response[2],
 				'merchant_id' => $response[3],
 				'merchant_country' => $response[4],
 				'amount' => $response[5],
 				'transaction_id' => $response[6],
 				'payment_means' => $response[7],
 				'transmission_date' => $response[8],
 				'payment_time' => $response[9],
 				'payment_date' => $response[10],
 				'response_code' => $response[11],
 				'payment_certificate' => $response[12],
 				'authorisation_id' => $response[13],
 				'currency_code' => $response[14],
 				'card_number' => $response[15],
 				'cvv_flag' => $response[16],
 				'cvv_response_code' => $response[17],
 				'bank_response_code' => $response[18],
 				'complementary_code' => $response[19],
 				'complementary_info' => $response[20],
 				'return_context' => $response[21],
 				'caddie' => $response[22],
 				'receipt_complement' => $response[23],
 				'merchant_language' => $response[24],
 				'language' => $response[25],
 				'customer_id' => $response[26],
 				'order_id' => $response[27],
 				'customer_email' => $response[28],
 				'customer_ip_address' => $response[29],
 				'capture_day' => $response[30],
 				'capture_mode' => $response[31],
 				'data' => $response[32],
 			);
 			$this->parsed_responce = $result;
 			return $result;
 		}
 
 		function getGWResponce()
 		{
 			return serialize($this->parsed_responce);
 		}
 
 		function getErrorMsg()
 		{
 			$msg = $this->parsed_responce['error'];
 			if (!$msg) {
 				if ($this->parsed_responce['response_code'] != '00') {
 					$msg = 'Transaction failed';
 				}
 			}
 			return $msg;
 		}
 	}
\ No newline at end of file
Index: branches/5.3.x/units/gateways/gw_classes/paypal_direct.php
===================================================================
--- branches/5.3.x/units/gateways/gw_classes/paypal_direct.php	(revision 15670)
+++ branches/5.3.x/units/gateways/gw_classes/paypal_direct.php	(revision 15671)
@@ -1,241 +1,241 @@
 <?php
 /**
 * @version	$Id$
 * @package	In-Commerce
 * @copyright	Copyright (C) 1997 - 2009 Intechnic. All rights reserved.
 * @license	Commercial License
 * This software is protected by copyright law and international treaties.
 * Unauthorized reproduction or unlicensed usage of the code of this program,
 * or any portion of it may result in severe civil and criminal penalties,
 * and will be prosecuted to the maximum extent possible under the law
 * See http://www.in-portal.org/commercial-license for copyright notices and details.
 */
 
 	require_once GW_CLASS_PATH.'/gw_base.php';
 
 	$class_name = 'kGWPaypalDirect'; // for automatic installation
 
 	class kGWPaypalDirect extends kGWBase
 	{
 		function InstallData()
 		{
 			$data = array(
 				'Gateway' => Array('Name' => 'PayPal Pro', 'ClassName' => 'kGWPaypalDirect', 'ClassFile' => 'paypal_direct.php', 'RequireCCFields' => 1),
 				'ConfigFields' => Array(
 					'submit_url' => Array('Name' => 'Submit URL', 'Type' => 'text', 'ValueList' => '', 'Default' => 'https://api-3t.paypal.com/nvp'),
 					'api_username' => Array('Name' => 'PayPal Pro API Username', 'Type' => 'text', 'ValueList' => '', 'Default' => ''),
 					'api_password' => Array('Name' => 'PayPal Pro API Password', 'Type' => 'text', 'ValueList' => '', 'Default' => ''),
 					'signature' => Array('Name' => 'PayPal Pro API Signature', 'Type' => 'text', 'ValueList' => '', 'Default' => ''),
 					'shipping_control' => Array('Name' => 'Shipping Control', 'Type' => 'select', 'ValueList' => '3=la_CreditDirect', 'Default' => '3'),
 				)
 			);
 			return $data;
 		}
 
 		function DirectPayment($item_data, $gw_params)
 		{
 			$post_fields = Array();
 			// -- Login Information --
 			$post_fields['METHOD']				=	'DoDirectPayment';
 			$post_fields['VERSION']				=	'52.0';
-			$post_fields['IPADDRESS']			=	$_SERVER['REMOTE_ADDR'];
+			$post_fields['IPADDRESS']			=	$this->Application->getClientIp();
 			$post_fields['USER']				=	$gw_params['api_username'];
 			$post_fields['PWD']					=	$gw_params['api_password'];
 			$post_fields['SIGNATURE']			=	$gw_params['signature'];
 			$post_fields['PAYMENTACTION']		=	'Sale';
 			$post_fields['AMT']					=	sprintf('%.2f', $item_data['TotalAmount']);
 
 			switch ($item_data['PaymentCardType']) {
 				case 1:
 					$post_fields['CREDITCARDTYPE'] = 'Visa';
 					break;
 				case 2:
 					$post_fields['CREDITCARDTYPE'] = 'MasterCard';
 					break;
 				case 3:
 					$post_fields['CREDITCARDTYPE'] = 'Amex';
 					break;
 				case 4:
 					$post_fields['CREDITCARDTYPE'] = 'Discover';
 					break;
 				default:
 					$this->parsed_responce['responce_reason_text'] = 'Invalid Credit Card Type';
 					return false;
 			}
 
 			$post_fields['ACCT']				=	$item_data['PaymentAccount'];
 			$date_parts = explode('/', $item_data['PaymentCCExpDate']);
 			$post_fields['EXPDATE']				=	$date_parts[0].'20'.$date_parts[1];
 			$post_fields['CVV2']				=	$item_data['PaymentCVV2'];
 
 			$names = explode(' ', $item_data['PaymentNameOnCard'], 2);
 			$post_fields['FIRSTNAME']			=	getArrayValue($names, 0);
 			$post_fields['LASTNAME']			=	getArrayValue($names, 1);
 
 			$post_fields['STREET']				=	$item_data['BillingAddress1'];
 			$post_fields['STREET2']				=	$item_data['BillingAddress2'];
 			$post_fields['CITY']				=	$item_data['BillingCity'];
 			$post_fields['STATE']				=	$item_data['BillingState'];
 
 			$cs_helper = $this->Application->recallObject('CountryStatesHelper');
 			/* @var $cs_helper kCountryStatesHelper */
 
 			$post_fields['COUNTRYCODE']			=	$cs_helper->getCountryIso( $item_data['BillingCountry'] );
 			$post_fields['ZIP']					=	$item_data['BillingZip'];
 			$post_fields['INVNUM']				=	$item_data['OrderNumber'];
 			$post_fields['CUSTOM']				=	$item_data['PortalUserId'];
 
 /*
 			$post_fields['x_encap_char']		=	$gw_params['encapsulate_char'];
 			$post_fields['x_relay_response']	=	'False';
 			$post_fields['x_type']				=	$gw_params['shipping_control'] == SHIPPING_CONTROL_PREAUTH ? 'AUTH_ONLY' : 'AUTH_CAPTURE';
 			$post_fields['x_login']				=	$gw_params['user_account'];
 			$post_fields['x_tran_key']			=	$gw_params['transaction_key'];
 
 			if( $this->IsTestMode() ) $post_fields['x_test_request'] = 'True';
 
 			// -- Payment Details --
 			$names = explode(' ', $item_data['PaymentNameOnCard'], 2);
 			$post_fields['x_first_name']		=	getArrayValue($names, 0);
 			$post_fields['x_last_name']			=	getArrayValue($names, 1);
 			$post_fields['x_amount']			=	sprintf('%.2f', $item_data['TotalAmount']);
 			$post_fields['x_company']			=	$item_data['BillingCompany'];
 			$post_fields['x_card_num']			=	$item_data['PaymentAccount'];
 			$post_fields['x_card_code']			=	$item_data['PaymentCVV2'];
 			$post_fields['x_exp_date']			=	$item_data['PaymentCCExpDate'];
 			$post_fields['x_address']			=	$item_data['BillingAddress1'].' '.$item_data['BillingAddress2'];
 			$post_fields['x_city']				=	$item_data['BillingCity'];
 			$post_fields['x_state']				=	$item_data['BillingState'];
 			$post_fields['x_zip']				=	$item_data['BillingZip'];
 
 			$recurring = getArrayValue($item_data, 'IsRecurringBilling') ? 'YES' : 'NO';
 			$post_fields['x_recurring_billing'] = $recurring;
 
 			$billing_email = $item_data['BillingEmail'];
 			if (!$billing_email) {
 				$billing_email = $this->Conn->GetOne('	SELECT Email FROM '.$this->Application->getUnitOption('u', 'TableName').'
 											WHERE PortalUserId = '.$this->Application->RecallVar('user_id'));
 			}
 			$post_fields['x_email'] = $billing_email;
 			$post_fields['x_phone'] = $item_data['BillingPhone'];
 			$post_fields['x_country']			=	$cs_helper->getCountryIso( $item_data['BillingCountry'] );
 
 			$post_fields['x_cust_id']			=	$item_data['PortalUserId'];
 			$post_fields['x_invoice_num']		=	$item_data['OrderNumber'];
 			$post_fields['x_description']		=	'Invoice #'.$item_data['OrderNumber'];
 			$post_fields['x_email_customer']	=	'FALSE';
 */
 //			echo '<pre>';
 //			print_r($post_fields);
 //			exit;
 
 			$curl_helper = $this->Application->recallObject('CurlHelper');
 			/* @var $curl_helper kCurlHelper */
 
 			$curl_helper->SetPostData($post_fields);
 			$this->gw_responce = $curl_helper->Send($gw_params['submit_url']);
 
 //			echo $this->gw_responce;
 //			exit;
 			$gw_responce = $this->parseGWResponce(null, $gw_params);
 			// gw_error_msg: $gw_response['responce_reason_text']
 			// gw_error_code: $gw_response['responce_reason_code']
 //			echo '<pre>';
 //			print_r($this->parsed_responce);
 //			exit;
 			return (isset($gw_responce['ACK']) && (substr($gw_responce['ACK'], 0, 7) == 'Success')) ? true : false;
 		}
 
 		/**
 		 * Perform SALE type transaction direct from php script wihtout redirecting to 3rd-party website
 		 *
 		 * @param Array $item_data
 		 * @param Array $gw_params
 		 * @return bool
 		 */
 /*
 		function Charge($item_data, $gw_params)
 		{
 			$gw_responce = unserialize( $item_data['GWResult1'] );
 
 			if( $item_data['PortalUserId'] != $gw_responce['customer_id'] ) return false;
 
 			if( ( strtolower($gw_responce['transaction_type']) == 'auth_only') )
 			{
 				$post_fields = Array();
 				// -- Login Information --
 				$post_fields['x_version']			=	'3.1';
 				$post_fields['x_delim_data']		=	'True';
 				$post_fields['x_encap_char']		=	$gw_params['encapsulate_char'];
 				$post_fields['x_relay_response']	=	'False';
 				$post_fields['x_type']				=	'PRIOR_AUTH_CAPTURE'; // $gw_params['shipping_control'] == SHIPPING_CONTROL_PREAUTH ? 'PRIOR_AUTH_CAPTURE' : 'AUTH_CAPTURE'; // AUTH_CAPTURE not fully impletemnted/needed here
 				$post_fields['x_login']				=	$gw_params['user_account'];
 				$post_fields['x_tran_key']			=	$gw_params['transaction_key'];
 				$post_fields['x_trans_id']			=	$gw_responce['transaction_id'];
 
 				if( $this->IsTestMode() ) $post_fields['x_test_request'] = 'True';
 
 				$curl_helper = $this->Application->recallObject('CurlHelper');
 
 				$curl_helper->SetPostData($post_fields);
 				$this->gw_responce = $curl_helper->Send($gw_params['submit_url']);
 
 				$gw_responce = $this->parseGWResponce(null, $gw_params);
 
 				// gw_error_msg: $gw_response['responce_reason_text']
 				// gw_error_code: $gw_response['responce_reason_code']
 				return (is_numeric($gw_responce['responce_code']) && $gw_responce['responce_code'] != 1 && !$this->IsTestMode()) ? false : true;
 			}
 			else
 			{
 				return true;
 			}
 		}
 */
 		/**
 		 * Parse previosly saved gw responce into associative array
 		 *
 		 * @param string $gw_responce
 		 * @param Array $gw_params
 		 * @return Array
 		 */
 		function parseGWResponce($gw_responce = null, $gw_params)
 		{
 			if( !isset($gw_responce) ) $gw_responce = $this->gw_responce;
 
 			if ($this->Application->isDebugMode()) {
 				$this->Application->Debugger->appendHTML('Curl Error #'.$GLOBALS['curl_errorno'].'; Error Message: '.$GLOBALS['curl_error']);
 
 				$this->Application->Debugger->appendHTML('Authorize.Net Responce:');
 				$this->Application->Debugger->dumpVars($gw_responce);
 			}
 
 			$a_responce = explode('&', $gw_responce);
 			$ret = Array();
 			foreach($a_responce as $field)
 			{
 				$pos = strpos($field, '=');
 				if ($pos) {
 					$ret[substr($field, 0, $pos)] = urldecode(substr($field, $pos + 1));
 				}
 			}
 			$this->parsed_responce = $ret;
 //			$ret['unparsed'] = $gw_responce;
 			return $ret;
 		}
 
 		function getGWResponce()
 		{
 			return serialize($this->parsed_responce);
 		}
 
 		function getErrorMsg()
 		{
 			return $this->parsed_responce['L_LONGMESSAGE0'];
 		}
 
 		function GetTestCCNumbers()
 		{
 			return array('370000000000002', '6011000000000012', '5424000000000015', '4007000000027', '4222222222222');
 		}
 	}
\ No newline at end of file
Index: branches/5.3.x/units/gateways/gw_classes/google_checkout.php
===================================================================
--- branches/5.3.x/units/gateways/gw_classes/google_checkout.php	(revision 15670)
+++ branches/5.3.x/units/gateways/gw_classes/google_checkout.php	(revision 15671)
@@ -1,940 +1,940 @@
 <?php
 /**
 * @version	$Id$
 * @package	In-Commerce
 * @copyright	Copyright (C) 1997 - 2009 Intechnic. All rights reserved.
 * @license	Commercial License
 * This software is protected by copyright law and international treaties.
 * Unauthorized reproduction or unlicensed usage of the code of this program,
 * or any portion of it may result in severe civil and criminal penalties,
 * and will be prosecuted to the maximum extent possible under the law
 * See http://www.in-portal.org/commercial-license for copyright notices and details.
 */
 
 	require_once GW_CLASS_PATH.'/gw_base.php';
 
 	$class_name = 'kGWGoogleCheckout'; // for automatic installation
 
 	class kGWGoogleCheckout extends kGWBase
 	{
 		var $gwParams = Array ();
 
 		function InstallData()
 		{
 			$data = array(
 				'Gateway' => Array('Name' => 'Google Checkout', 'ClassName' => 'kGWGoogleCheckout', 'ClassFile' => 'google_checkout.php', 'RequireCCFields' => 0),
 				'ConfigFields' => Array(
 					'submit_url' => Array('Name' => 'Submit URL', 'Type' => 'text', 'ValueList' => '', 'Default' => 'https://checkout.google.com/api/checkout/v2'),
 					'merchant_id' => Array('Name' => 'Google merchant ID', 'Type' => 'text', 'ValueList' => '', 'Default' => ''),
 					'merchant_key' => Array('Name' => 'Google merchant key', 'Type' => 'text', 'ValueList' => '', 'Default' => ''),
 					'shipping_control' => Array('Name' => 'Shipping Control', 'Type' => 'select', 'ValueList' => '3=la_CreditDirect,4=la_CreditPreAuthorize', 'Default' => 3),
 				)
 			);
 			return $data;
 		}
 
 		/**
 		 * Returns payment form submit url
 		 *
 		 * @param Array $gw_params gateway params from payment type config
 		 * @return string
 		 */
 		function getFormAction($gw_params)
 		{
 			return $gw_params['submit_url'].'/checkout/Merchant/'.$gw_params['merchant_id'];
 		}
 
 		/**
 		 * Processed input data and convets it to fields understandable by gateway
 		 *
 		 * @param Array $item_data current order fields
 		 * @param Array $tag_params additional params for gateway passed through tag
 		 * @param Array $gw_params gateway params from payment type config
 		 * @return Array
 		 */
 		function getHiddenFields($item_data, $tag_params, $gw_params)
 		{
 			$ret = Array();
 			$this->gwParams = $gw_params;
 
 			$cart_xml = $this->getCartXML($item_data);
 
 			$ret['cart'] = base64_encode($cart_xml);
     		$ret['signature'] = base64_encode( $this->CalcHmacSha1($cart_xml, $gw_params) );
 
 			return $ret;
 		}
 
 		function getCartXML($cart_fields)
 		{
 			// 1. prepare shopping cart content
 			$sql = 'SELECT *
 					FROM '.TABLE_PREFIX.'OrderItems oi
 					LEFT JOIN '.TABLE_PREFIX.'Products p ON p.ProductId = oi.ProductId
 					WHERE oi.OrderId = '.$cart_fields['OrderId'];
 			$order_items = $this->Conn->Query($sql);
 
 			$ml_formatter = $this->Application->recallObject('kMultiLanguage');
 			/* @var $ml_formatter kMultiLanguage */
 
 			$cart_xml = Array ();
 			foreach ($order_items as $order_item) {
 				$cart_xml[] = '	<item>
-					        		<item-name>'.htmlspecialchars($order_item['ProductName']).'</item-name>
-					        		<item-description>'.htmlspecialchars($order_item[$ml_formatter->LangFieldName('DescriptionExcerpt')]).'</item-description>'.
+					        		<item-name>'.htmlspecialchars($order_item['ProductName'], null, CHARSET).'</item-name>
+					        		<item-description>'.htmlspecialchars($order_item[$ml_formatter->LangFieldName('DescriptionExcerpt')], null, CHARSET).'</item-description>'.
 									$this->getPriceXML('unit-price', $order_item['Price']).'
 					        		<quantity>'.$order_item['Quantity'].'</quantity>
 								</item>';
 			}
 			$cart_xml = '<items>'.implode("\n", $cart_xml).'</items>';
 
 			// 2. add order identification info (for google checkout notification)
 			$cart_xml .= '	<merchant-private-data>
 								<session_id>'.$this->Application->GetSID().'</session_id>
 								<order_id>'.$cart_fields['OrderId'].'</order_id>
 							</merchant-private-data>';
 
 			// 3. add all shipping types (with no costs)
 			$sql = 'SELECT Name
 					FROM '.TABLE_PREFIX.'ShippingType
 					WHERE Status = '.STATUS_ACTIVE;
 			$shipping_types = $this->Conn->GetCol($sql);
 
 			$shipping_xml = '';
 			foreach ($shipping_types as $shipping_name) {
-				$shipping_xml .= '	<merchant-calculated-shipping name="'.htmlspecialchars($shipping_name).'">
+				$shipping_xml .= '	<merchant-calculated-shipping name="'.htmlspecialchars($shipping_name, null, CHARSET).'">
 										<price currency="USD">0.00</price>
 									</merchant-calculated-shipping>';
 			}
 
 			$use_ssl = substr($this->gwParams['submit_url'], 0, 8) == 'https://' ? true : null;
 			$shipping_url = $this->getNotificationUrl('units/gateways/gw_classes/notify_scripts/google_checkout_shippings.php', $use_ssl);
 
 			$shipping_xml = '<merchant-checkout-flow-support>
 								<shipping-methods>'.$shipping_xml.'</shipping-methods>
 					      		<merchant-calculations>
 					      			<merchant-calculations-url>'.$shipping_url.'</merchant-calculations-url>
 					      		</merchant-calculations>
 					    	</merchant-checkout-flow-support>';
 
 			$xml = '<checkout-shopping-cart xmlns="http://checkout.google.com/schema/2">
 					  <shopping-cart>'.$cart_xml.'</shopping-cart>
 					  <checkout-flow-support>'.$shipping_xml.'</checkout-flow-support>
 					</checkout-shopping-cart>';
 
 			return $xml;
 		}
 
 		/**
 		 * Returns price formatted as xml tag
 		 *
 		 * @param string $tag_name
 		 * @param float $price
 		 * @return string
 		 */
 		function getPriceXML($tag_name, $price)
 		{
 			$currency = $this->Application->RecallVar('curr_iso');
 			return '<'.$tag_name.' currency="'.$currency.'">'.sprintf('%.2f', $price).'</'.$tag_name.'>';
 		}
 
 	    /**
 	     * Calculates the cart's hmac-sha1 signature, this allows google to verify
 	     * that the cart hasn't been tampered by a third-party.
 	     *
 	     * {@link http://code.google.com/apis/checkout/developer/index.html#create_signature}
 	     *
 	     * @param string $data the cart's xml
 	     * @return string the cart's signature (in binary format)
 	     */
 	    function CalcHmacSha1($data, $gw_params) {
 	      $key = $gw_params['merchant_key'];
 	      $blocksize = 64;
 	      $hashfunc = 'sha1';
 	      if (mb_strlen($key) > $blocksize) {
 	        $key = pack('H*', $hashfunc($key));
 	      }
 	      $key = str_pad($key, $blocksize, chr(0x00));
 	      $ipad = str_repeat(chr(0x36), $blocksize);
 	      $opad = str_repeat(chr(0x5c), $blocksize);
 	      $hmac = pack(
 	                    'H*', $hashfunc(
 	                            ($key^$opad).pack(
 	                                    'H*', $hashfunc(
 	                                            ($key^$ipad).$data
 	                                    )
 	                            )
 	                    )
 	                );
 	      return $hmac;
 	    }
 
 	    /**
 	     * Returns XML request, that GoogleCheckout posts to notification / shipping calculation scripts
 	     *
 	     * @return string
 	     */
 	    function getRequestXML()
 	    {
 	    	$xml_data = $GLOBALS['HTTP_RAW_POST_DATA'];
 
 	    	if ( $this->Application->isDebugMode() ) {
 	    		$this->toLog($xml_data, 'xml_request.html');
 	    	}
 
 	    	return $xml_data;
 
 	    	// for debugging
 	    	/*return '<order-state-change-notification xmlns="http://checkout.google.com/schema/2"
 					    serial-number="c821426e-7caa-4d51-9b2e-48ef7ecd6423">
 					    <google-order-number>434532759516557</google-order-number>
 					    <new-financial-order-state>CHARGEABLE</new-financial-order-state>
 					    <new-fulfillment-order-state>NEW</new-fulfillment-order-state>
 					    <previous-financial-order-state>REVIEWING</previous-financial-order-state>
 					    <previous-fulfillment-order-state>NEW</previous-fulfillment-order-state>
 					    <timestamp>2007-03-19T15:06:29.051Z</timestamp>
 					</order-state-change-notification>';*/
 	    }
 
 	    /**
 	     * Processes notifications from google checkout
 	     *
 	     * @param Array $gw_params
 	     * @return int
 	     */
 		function processNotification($gw_params)
 		{
     		// parse xml & get order_id from there, like sella pay
     		$this->gwParams = $gw_params;
 
     		$xml_helper = $this->Application->recallObject('kXMLHelper');
     		/* @var $xml_helper kXMLHelper */
 
 			$root_node =& $xml_helper->Parse( $this->getRequestXML() );
     		/* @var $root_node kXMLNode */
 
     		$this->Application->XMLHeader();
 			define('DBG_SKIP_REPORTING', 1);
 
 			$order_approvable = false;
 
 			switch ($root_node->Name) {
 				case 'MERCHANT-CALCULATION-CALLBACK':
 					$xml_responce = $this->getShippingXML($root_node);
 					break;
 
 				case 'NEW-ORDER-NOTIFICATION':
 				case 'RISK-INFORMATION-NOTIFICATION':
 				case 'ORDER-STATE-CHANGE-NOTIFICATION':
 					// http://code.google.com/apis/checkout/developer/Google_Checkout_XML_API_Notification_API.html#new_order_notifications
 					list ($order_approvable, $xml_responce) = $this->getNotificationResponceXML($root_node);
 					break;
 			}
 
 			echo $xml_responce;
 
 			if ( $this->Application->isDebugMode() ) {
 				$this->toLog($xml_responce, 'xml_responce.html');
 			}
 
     		return $order_approvable ? 1 : 0;
 		}
 
 		/**
 	     * Writes XML requests and responces to a file
 	     *
 	     * @param string $xml_data
 	     * @param string $xml_file
 	     */
 	    function toLog($xml_data, $xml_file)
 	    {
 	    	$fp = fopen( (defined('RESTRICTED') ? RESTRICTED : FULL_PATH) . '/' . $xml_file, 'a' );
 			fwrite($fp, '--- ' . adodb_date('Y-m-d H:i:s') . ' ---' . "\n" . $xml_data);
 			fclose($fp);
 	    }
 
 		/**
 		 * Processes notification
 		 *
 		 * @param kXMLNode $root_node
 		 */
 		function getNotificationResponceXML(&$root_node)
 		{
 			// we can get notification type by "$root_node->Name"
 
 			$order_approvable = false;
 			switch ($root_node->Name) {
 				case 'NEW-ORDER-NOTIFICATION':
 					$order_approvable = $this->processNewOrderNotification($root_node);
 					break;
 
 				case 'RISK-INFORMATION-NOTIFICATION':
 					$order_approvable = $this->processRiskInformationNotification($root_node);
 					break;
 
 				case 'ORDER-STATE-CHANGE-NOTIFICATION':
 					$order_approvable = $this->processOrderStateChangeNotification($root_node);
 					break;
 			}
 
 
 
 			// !!! globally set order id, so gw_responce.php will not fail in setting TransactionStatus
 
 			// 1. receive new order notification
 			// put address & payment type in our order using id found in merchant-private-data (Make order status: Incomplete)
 
 			// 2. receive risk information
 			// don't know what to do, just mark order some how (Make order status: Incomplete)
 
 			// 3. receive status change notification to CHARGEABLE (Make order status: Pending)
 			// only mark order status
 
 			// 4. admin approves order
 			// make api call, that changes order state (fulfillment-order-state) to PROCESSING or DELIVERED (see manual)
 
 			// 5. admin declines order
 			// make api call, that changes order state (fulfillment-order-state) to WILL_NOT_DELIVER
 
 			// Before you ship the items in an order, you should ensure that you have already received the new order notification for the order,
 			// the risk information notification for the order and an order state change notification informing you that the order's financial
 			// state has been updated to CHARGEABLE
 
 			return Array ($order_approvable, '<notification-acknowledgment xmlns="http://checkout.google.com/schema/2" serial-number="'.$root_node->Attributes['SERIAL-NUMBER'].'" />');
 		}
 
 		/**
 		 * Returns shipping calculations and places part of shipping address into order (1st step)
 		 *
 		 * http://code.google.com/apis/checkout/developer/Google_Checkout_XML_API_Merchant_Calculations_API.html#Returning_Merchant_Calculation_Results
 		 *
 		 * @param kXMLNode $node
 		 * @return string
 		 */
 		function getShippingXML(&$root_node)
 		{
 			// 1. extract data from xml
 			$search_nodes = Array (
 				'SHOPPING-CART:MERCHANT-PRIVATE-DATA',
 				'CALCULATE:ADDRESSES:ANONYMOUS-ADDRESS',
 				'CALCULATE:SHIPPING',
 			);
 
 			foreach ($search_nodes as $search_string) {
 				$found_node =& $root_node;
 				/* @var $found_node kXMLNode */
 
 				$search_string = explode(':', $search_string);
 				foreach ($search_string as $search_node) {
 					$found_node =& $found_node->FindChild($search_node);
 				}
 
 				$node_data = Array ();
 				$sub_node =& $found_node->firstChild;
 				/* @var $sub_node kXMLNode */
 
 				do {
 					if ($found_node->Name == 'SHIPPING') {
 						$node_data[] = $sub_node->Attributes['NAME'];
 					}
 					else {
 						$node_data[$sub_node->Name] = $sub_node->Data;
 					}
 				} while ( ($sub_node =& $sub_node->NextSibling()) );
 
 
 				switch ($found_node->Name) {
 					case 'MERCHANT-PRIVATE-DATA':
 						$order_id = $node_data['ORDER_ID'];
 						$session_id = $node_data['SESSION_ID'];
 						break;
 
 					case 'ANONYMOUS-ADDRESS':
 						$address_info = $node_data;
 						$address_id = $found_node->Attributes['ID'];
 						break;
 
 					case 'SHIPPING':
 						$process_shippings = $node_data;
 						break;
 				}
 			}
 
 			// 2. update shipping address in order
 			$order = $this->Application->recallObject('ord', null, Array ('skip_autoload' => true));
 			/* @var $order OrdersItem */
 
 			$order->Load($order_id);
 
 			$shipping_address = Array (
 				'ShippingCity' => $address_info['CITY'],
 				'ShippingState' => $address_info['REGION'],
 				'ShippingZip' => $address_info['POSTAL-CODE'],
 			);
 
 			$cs_helper = $this->Application->recallObject('CountryStatesHelper');
 			/* @var $cs_helper kCountryStatesHelper */
 
 			$shipping_address['ShippingCountry'] = $cs_helper->getCountryIso($address_info['COUNTRY-CODE'], true);
 
 			$order->SetDBFieldsFromHash($shipping_address);
 			$order->Update();
 
 			// 3. get shipping rates based on given address
 
 			$shipping_types_xml = '';
 			$shipping_types = $this->getOrderShippings($order);
 
 			// add available shipping types
 			foreach ($shipping_types as $shipping_type) {
 				$shipping_name = $shipping_type['ShippingName'];
 				$processable_shipping_index = array_search($shipping_name, $process_shippings);
 				if ($processable_shipping_index !== false) {
-					$shipping_types_xml .= '<result shipping-name="'.htmlspecialchars($shipping_name).'" address-id="'.$address_id.'">
+					$shipping_types_xml .= '<result shipping-name="'.htmlspecialchars($shipping_name, null, CHARSET).'" address-id="'.$address_id.'">
 				    	        				<shipping-rate currency="USD">'.sprintf('%01.2f', $shipping_type['TotalCost']).'</shipping-rate>
 				        	    				<shippable>true</shippable>
 				        					</result>';
 
 					// remove available shipping type from processable list
 					unset($process_shippings[$processable_shipping_index]);
 				}
 			}
 
 			// add unavailable shipping types
 			foreach ($process_shippings as $shipping_name) {
-				$shipping_types_xml .= '<result shipping-name="'.htmlspecialchars($shipping_name).'" address-id="'.$address_id.'">
+				$shipping_types_xml .= '<result shipping-name="'.htmlspecialchars($shipping_name, null, CHARSET).'" address-id="'.$address_id.'">
 											<shipping-rate currency="USD">0.00</shipping-rate>
 				            				<shippable>false</shippable>
 				        				</result>';
 			}
 
 			$shipping_types_xml = '<?xml version="1.0" encoding="UTF-8"?>
 									<merchant-calculation-results xmlns="http://checkout.google.com/schema/2">
 				  						<results>'.$shipping_types_xml.'</results>
 									</merchant-calculation-results>';
 			return $shipping_types_xml;
 		}
 
 		/**
 		 * Places all information from google checkout into order (2nd step)
 		 *
 		 * @param kXMLNode $root_node
 		 */
 		function processNewOrderNotification(&$root_node)
 		{
 			// 1. extract data from xml
 			$search_nodes = Array (
 				'SHOPPING-CART:MERCHANT-PRIVATE-DATA',
 				'ORDER-ADJUSTMENT:SHIPPING:MERCHANT-CALCULATED-SHIPPING-ADJUSTMENT',
 				'BUYER-ID',
 				'GOOGLE-ORDER-NUMBER',
 				'BUYER-SHIPPING-ADDRESS',
 				'BUYER-BILLING-ADDRESS',
 			);
 
 			$user_address = Array ();
 			foreach ($search_nodes as $search_string) {
 				$found_node =& $root_node;
 				/* @var $found_node kXMLNode */
 
 				$search_string = explode(':', $search_string);
 				foreach ($search_string as $search_node) {
 					$found_node =& $found_node->FindChild($search_node);
 				}
 
 				$node_data = Array ();
 				if ($found_node->Children) {
 					$sub_node =& $found_node->firstChild;
 					/* @var $sub_node kXMLNode */
 
 					do {
 						$node_data[$sub_node->Name] = $sub_node->Data;
 					} while ( ($sub_node =& $sub_node->NextSibling()) );
 				}
 
 				switch ($found_node->Name) {
 					case 'MERCHANT-PRIVATE-DATA':
 						$order_id = $node_data['ORDER_ID'];
 						$session_id = $node_data['SESSION_ID'];
 						break;
 
 					case 'MERCHANT-CALCULATED-SHIPPING-ADJUSTMENT':
 						$shpipping_info = $node_data;
 						break;
 
 					case 'BUYER-ID':
 						$buyer_id = $found_node->Data;
 						break;
 
 					case 'GOOGLE-ORDER-NUMBER':
 						$google_order_number = $found_node->Data;
 						break;
 
 					case 'BUYER-SHIPPING-ADDRESS':
 						$user_address['Shipping'] = $node_data;
 						break;
 
 					case 'BUYER-BILLING-ADDRESS':
 						$user_address['Billing'] = $node_data;
 						break;
 				}
 			}
 
 			// 2. update shipping address in order
 			$order = $this->Application->recallObject('ord', null, Array ('skip_autoload' => true));
 			/* @var $order OrdersItem */
 
 			$order->Load($order_id);
 
 			if (!$order->isLoaded()) {
 				return false;
 			}
 
 			// 2.1. this is 100% notification from google -> mark order with such payment type
 			$order->SetDBField('PaymentType', $this->Application->GetVar('payment_type_id'));
 
 			$this->parsed_responce = Array (
 				'GOOGLE-ORDER-NUMBER' => $google_order_number,
 				'BUYER-ID' => $buyer_id
 			);
 
 			// 2.2. save google checkout order information (maybe needed for future notification processing)
 			$order->SetDBField('GWResult1', serialize($this->parsed_responce));
 			$order->SetDBField('GoogleOrderNumber', $google_order_number);
 
 			// 2.3. set user-selected shipping type
 			$shipping_types = $this->getOrderShippings($order);
 
 			foreach ($shipping_types as $shipping_type) {
 				if ($shipping_type['ShippingName'] == $shpipping_info['SHIPPING-NAME']) {
 					$order->SetDBField('ShippingInfo', serialize(Array (1 => $shipping_type))); // minimal package number is 1
 					$order->SetDBField('ShippingCost', $shipping_type['TotalCost']); // set total shipping cost
 					break;
 				}
 			}
 
 			// 2.4. set full shipping & billing address
 			$address_mapping = Array (
 				'CONTACT-NAME' => 'To',
 				'COMPANY-NAME' => 'Company',
 				'EMAIL' => 'Email',
 				'PHONE' => 'Phone',
 				'FAX' => 'Fax',
 				'ADDRESS1' => 'Address1',
 				'ADDRESS2' => 'Address2',
 				'CITY' => 'City',
 				'REGION' => 'State',
 				'POSTAL-CODE' => 'Zip',
 			);
 
 			$cs_helper = $this->Application->recallObject('CountryStatesHelper');
 			/* @var $cs_helper kCountryStatesHelper */
 
 			foreach ($user_address as $field_prefix => $address_details) {
 				foreach ($address_mapping as $src_field => $dst_field) {
 					$order->SetDBField($field_prefix.$dst_field, $address_details[$src_field]);
 				}
 
 				if (!$order->GetDBField($field_prefix.'Phone')) {
 					$order->SetDBField($field_prefix.'Phone', '-'); // required field
 				}
 
 				$order->SetDBField( $field_prefix.'Country', $cs_helper->getCountryIso($address_details['COUNTRY-CODE'], true) );
 			}
 
 			$order->SetDBField('OnHold', 1);
 			$order->SetDBField('Status', ORDER_STATUS_PENDING);
 
 			$order->Update();
 
 			// unlink order, that GoogleCheckout used from shopping cart on site
 			$sql = 'DELETE
 					FROM '.TABLE_PREFIX.'UserSessionData
 					WHERE VariableName = "ord_id" AND VariableValue = '.$order->GetID();
 			$this->Conn->Query($sql);
 
 			// simulate visiting shipping screen
 			$sql = 'UPDATE '.TABLE_PREFIX.'OrderItems
 					SET PackageNum = 1
 					WHERE OrderId = '.$order->GetID();
 			$this->Conn->Query($sql);
 
 			return false;
 		}
 
 		/**
 		 * Saves risk information in order record (3rd step)
 		 *
 		 * @param kXMLNode $root_node
 		 */
 		function processRiskInformationNotification(&$root_node)
 		{
 			// 1. extract data from xml
 			$search_nodes = Array (
 				'GOOGLE-ORDER-NUMBER',
 				'RISK-INFORMATION',
 			);
 
 			foreach ($search_nodes as $search_string) {
 				$found_node =& $root_node;
 				/* @var $found_node kXMLNode */
 
 				$search_string = explode(':', $search_string);
 				foreach ($search_string as $search_node) {
 					$found_node =& $found_node->FindChild($search_node);
 				}
 
 				$node_data = Array ();
 				if ($found_node->Children) {
 					$sub_node =& $found_node->firstChild;
 					/* @var $sub_node kXMLNode */
 
 					do {
 						$node_data[$sub_node->Name] = $sub_node->Data;
 					} while ( ($sub_node =& $sub_node->NextSibling()) );
 				}
 
 				switch ($found_node->Name) {
 					case 'GOOGLE-ORDER-NUMBER':
 						$google_order_number = $found_node->Data;
 						break;
 
 					case 'RISK-INFORMATION':
 						$risk_information = $node_data;
 						unset( $risk_information['BILLING-ADDRESS'] );
 						break;
 				}
 			}
 
 			// 2. update shipping address in order
 			$order = $this->Application->recallObject('ord', null, Array ('skip_autoload' => true));
 			/* @var $order OrdersItem */
 
 			$order->Load($google_order_number, 'GoogleOrderNumber');
 
 			if (!$order->isLoaded()) {
 				return false;
 			}
 
 			// 2.1. save risk information in order
 			$this->parsed_responce = unserialize($order->GetDBField('GWResult1'));
 			$this->parsed_responce = array_merge_recursive($this->parsed_responce, $risk_information);
 			$order->SetDBField('GWResult1', serialize($this->parsed_responce));
 
 			$order->Update();
 
 			return false;
 		}
 
 		/**
 		 * Perform PREAUTH/SALE type transaction direct from php script wihtout redirecting to 3rd-party website
 		 *
 		 * @param Array $item_data
 		 * @param Array $gw_params
 		 * @return bool
 		 */
 		function DirectPayment($item_data, $gw_params)
 		{
 			$this->gwParams = $gw_params;
 
 			if ($gw_params['shipping_control'] == SHIPPING_CONTROL_PREAUTH) {
 				// when shipping control is Pre-Authorize -> do nothing and charge when admin approves order
 				return true;
 			}
 
 			$this->_chargeOrder($item_data);
 
 			return false;
 		}
 
 		/**
 		 * Issue charge-order api call
 		 *
 		 * @param Array $item_data
 		 * @return bool
 		 */
 		function _chargeOrder($item_data)
 		{
 			$charge_xml = '	<charge-order xmlns="http://checkout.google.com/schema/2" google-order-number="'.$item_data['GoogleOrderNumber'].'">
 			    				<amount currency="USD">'.sprintf('%.2f', $item_data['TotalAmount']).'</amount>
 							</charge-order>';
 
 			$root_node =& $this->executeAPICommand($charge_xml);
 
     		$this->parsed_responce = unserialize($item_data['GWResult1']);
 
     		if ($root_node->Name == 'REQUEST-RECEIVED') {
 				$this->parsed_responce['FINANCIAL-ORDER-STATE'] = 'CHARGING';
 				return true;
     		}
 
     		return false;
 		}
 
 		/**
 		 * Perform SALE type transaction direct from php script wihtout redirecting to 3rd-party website
 		 *
 		 * @param Array $item_data
 		 * @param Array $gw_params
 		 * @return bool
 		 */
 		function Charge($item_data, $gw_params)
 		{
 			$this->gwParams = $gw_params;
 
 			if ($gw_params['shipping_control'] == SHIPPING_CONTROL_DIRECT) {
 				// when shipping control is Direct Payment -> do nothing and auto-charge on notification received
 				return true;
 			}
 
 			$this->_chargeOrder($item_data);
 
 			$order = $this->Application->recallObject('ord.-item', null, Array ('skip_autoload' => true));
 			/* @var $order OrdersItem */
 
 			$order->Load($item_data['OrderId']);
 			if (!$order->isLoaded()) {
 				return false;
 			}
 
 			$order->SetDBField('OnHold', 1);
 			$order->Update();
 
 			return false;
 		}
 
 		/**
 		 * Executes API command for order and returns result
 		 *
 		 * @param string $command_xml
 		 * @return kXMLNode
 		 */
 		function &executeAPICommand($command_xml)
 		{
 			$submit_url = $this->gwParams['submit_url'].'/request/Merchant/'.$this->gwParams['merchant_id'];
 
 			$curl_helper = $this->Application->recallObject('CurlHelper');
 			/* @var $curl_helper kCurlHelper */
 
 			$xml_helper = $this->Application->recallObject('kXMLHelper');
     		/* @var $xml_helper kXMLHelper */
 
 			$curl_helper->SetPostData($command_xml);
 			$auth_options = Array (
 				CURLOPT_USERPWD => $this->gwParams['merchant_id'].':'.$this->gwParams['merchant_key'],
 			);
 			$curl_helper->setOptions($auth_options);
 
 			$xml_responce = $curl_helper->Send($submit_url);
 
 			$root_node =& $xml_helper->Parse($xml_responce);
     		/* @var $root_node kXMLNode */
 
     		return $root_node;
 		}
 
 		/**
 		 * Marks order as pending, when it's google status becomes CHARGEABLE (4th step)
 		 *
 		 * @param kXMLNode $root_node
 		 */
 		function processOrderStateChangeNotification(&$root_node)
 		{
 			// 1. extract data from xml
 			$search_nodes = Array (
 				'GOOGLE-ORDER-NUMBER',
 				'NEW-FINANCIAL-ORDER-STATE',
 				'PREVIOUS-FINANCIAL-ORDER-STATE',
 			);
 
 			$order_state = Array ();
 			foreach ($search_nodes as $search_string) {
 				$found_node =& $root_node;
 				/* @var $found_node kXMLNode */
 
 				$search_string = explode(':', $search_string);
 				foreach ($search_string as $search_node) {
 					$found_node =& $found_node->FindChild($search_node);
 				}
 
 				switch ($found_node->Name) {
 					case 'GOOGLE-ORDER-NUMBER':
 						$google_order_number = $found_node->Data;
 						break;
 
 					case 'NEW-FINANCIAL-ORDER-STATE':
 						$order_state['new'] = $found_node->Data;
 						break;
 
 					case 'PREVIOUS-FINANCIAL-ORDER-STATE':
 						$order_state['old'] = $found_node->Data;
 						break;
 				}
 			}
 
 			// 2. update shipping address in order
 			$order = $this->Application->recallObject('ord', null, Array ('skip_autoload' => true));
 			/* @var $order OrdersItem */
 
 			$order->Load($google_order_number, 'GoogleOrderNumber');
 
 			if (!$order->isLoaded()) {
 				return false;
 			}
 
 			$state_changed = ($order_state['old'] != $order_state['new']);
 
 			if ($state_changed) {
 				$order_charged = ($order_state['new'] == 'CHARGED') && ($order->GetDBField('Status') == ORDER_STATUS_PENDING);
 
 				$this->parsed_responce = unserialize($order->GetDBField('GWResult1'));
 				$this->parsed_responce['FINANCIAL-ORDER-STATE'] = $order_state['new'];
 				$order->SetDBField('GWResult1', serialize($this->parsed_responce));
 
 				if ($order_charged) {
 					// when using Pre-Authorize
 					$order->SetDBField('OnHold', 0);
 				}
 
 				$order->Update();
 
 				if ($order_charged) {
 					// when using Pre-Authorize
 					$order_eh = $this->Application->recallObject('ord_EventHandler');
 					/* @var $order_eh OrdersEventHandler */
 
 					$order_eh->SplitOrder( new kEvent('ord:OnMassOrderApprove'), $order);
 				}
 			}
 
 			// update order record in "google_checkout_notify.php" only when such state change happens
 			$order_chargeable = ($order_state['new'] == 'CHARGEABLE') && $state_changed;
 
 			if ($order_chargeable) {
 				if ($this->gwParams['shipping_control'] == SHIPPING_CONTROL_PREAUTH) {
 					$order->SetDBField('OnHold', 0);
 					$order->Update();
 				}
 
 				$process_xml = '<process-order xmlns="http://checkout.google.com/schema/2" google-order-number="'.$order->GetDBField('GoogleOrderNumber').'"/>';
 				$root_node =& $this->executeAPICommand($process_xml);
 			}
 
 			return $order_chargeable;
 		}
 
 		/**
 		 * Retrieves shipping types available for given order
 		 *
 		 * @param OrdersItem $order
 		 * @return Array
 		 */
 		function getOrderShippings(&$order)
 		{
 			$weight_sql = 'IF(oi.Weight IS NULL, 0, oi.Weight * oi.Quantity)';
 
 			$query = '	SELECT
 							SUM(oi.Quantity) AS TotalItems,
 							SUM('.$weight_sql.') AS TotalWeight,
 							SUM(oi.Price * oi.Quantity) AS TotalAmount,
 							SUM(oi.Quantity) - SUM(IF(p.MinQtyFreePromoShipping > 0 AND p.MinQtyFreePromoShipping <= oi.Quantity, oi.Quantity, 0)) AS TotalItemsPromo,
 							SUM('.$weight_sql.') - SUM(IF(p.MinQtyFreePromoShipping > 0 AND p.MinQtyFreePromoShipping <= oi.Quantity, '.$weight_sql.', 0)) AS TotalWeightPromo,
 							SUM(oi.Price * oi.Quantity) - SUM(IF(p.MinQtyFreePromoShipping > 0 AND p.MinQtyFreePromoShipping <= oi.Quantity, oi.Price * oi.Quantity, 0)) AS TotalAmountPromo
 						FROM '.TABLE_PREFIX.'OrderItems oi
 						LEFT JOIN '.TABLE_PREFIX.'Products p ON oi.ProductId = p.ProductId
 						WHERE oi.OrderId = '.$order->GetID().' AND p.Type = 1';
 			$shipping_totals = $this->Conn->GetRow($query);
 
 			$this->Application->recallObject('ShippingQuoteEngine');
 			$quote_engine_collector = $this->Application->recallObject('ShippingQuoteCollector');
 			/* @var $quote_engine_collector ShippingQuoteCollector */
 
 			$shipping_quote_params = Array(
 				'dest_country'	=>	$order->GetDBField('ShippingCountry'),
 				'dest_state'	=>	$order->GetDBField('ShippingState'),
 				'dest_postal'	=>	$order->GetDBField('ShippingZip'),
 				'dest_city'		=>	$order->GetDBField('ShippingCity'),
 				'dest_addr1'	=>	'',
 				'dest_addr2'	=>	'',
 				'dest_name'		=>	'user-' . $order->GetDBField('PortalUserId'),
 				'packages' 		=>	Array(
 										Array(
 											'package_key'	=>	'package1',
 											'weight'		=>	$shipping_totals['TotalWeight'],
 											'weight_unit'	=>	'KG',
 											'length'		=>	'',
 											'width'			=>	'',
 											'height'		=>	'',
 											'dim_unit'		=>	'IN',
 											'packaging'		=>	'BOX',
 											'contents'		=>	'OTR',
 											'insurance'		=>	'0'
 										),
 									),
 				'amount'		=>	$shipping_totals['TotalAmount'],
 				'items'			=>	$shipping_totals['TotalItems'],
 				'limit_types' 	=> 	serialize(Array ('ANY')),
 
 				'promo_params'	=>	Array (
 					'items'		=>	$shipping_totals['TotalItemsPromo'],
 					'amount'	=>	$shipping_totals['TotalAmountPromo'],
 					'weight'	=>	$shipping_totals['TotalWeightPromo'],
 				),
 			);
 
 			return $quote_engine_collector->GetShippingQuotes($shipping_quote_params);
 		}
 
 		/**
 		 * Returns gateway responce from last operation
 		 *
 		 * @return string
 		 */
 		function getGWResponce()
 		{
 			return serialize($this->parsed_responce);
 		}
 
 		/**
 		 * Informs payment gateway, that order has been shipped
 		 *
 		 * http://code.google.com/apis/checkout/developer/Google_Checkout_XML_API_Order_Level_Shipping.html#Deliver_Order
 		 *
 		 * @param Array $item_data
 		 * @param Array $gw_params
 		 * @return bool
 		 */
 		function OrderShipped($item_data, $gw_params)
 		{
 			$this->gwParams = $gw_params;
 
 			$shipping_info = unserialize($item_data['ShippingInfo']);
 			if (getArrayValue($shipping_info, 'Code')) {
 				$traking_carrier = '<carrier>'.$item_data['Code'].'</carrier>';
 			}
 
 			if ($item_data['ShippingTracking']) {
 				$tracking_data = '<tracking-data>'.$traking_carrier.'
         							 <tracking-number>'.$item_data['ShippingTracking'].'</tracking-number>
         						  </tracking-data>';
 			}
 
 			$ship_xml = '	<deliver-order xmlns="http://checkout.google.com/schema/2" google-order-number="'.$item_data['GoogleOrderNumber'].'">
 								'.$traking_data.'
     							<send-email>true</send-email>
 							</deliver-order>';
 			$root_node =& $this->executeAPICommand($ship_xml);
 		}
 
 		/**
 		 * Informs payment gateway, that order has been declined
 		 *
 		 * @param Array $item_data
 		 * @param Array $gw_params
 		 * @return bool
 		 */
 		function OrderDeclined($item_data, $gw_params)
 		{
 
 		}
 	}
\ No newline at end of file
Index: branches/5.3.x/units/gateways/gw_classes/sella_guestpay.php
===================================================================
--- branches/5.3.x/units/gateways/gw_classes/sella_guestpay.php	(revision 15670)
+++ branches/5.3.x/units/gateways/gw_classes/sella_guestpay.php	(revision 15671)
@@ -1,163 +1,163 @@
 <?php
 /**
 * @version	$Id$
 * @package	In-Commerce
 * @copyright	Copyright (C) 1997 - 2009 Intechnic. All rights reserved.
 * @license	Commercial License
 * This software is protected by copyright law and international treaties.
 * Unauthorized reproduction or unlicensed usage of the code of this program,
 * or any portion of it may result in severe civil and criminal penalties,
 * and will be prosecuted to the maximum extent possible under the law
 * See http://www.in-portal.org/commercial-license for copyright notices and details.
 */
 
 	require_once GW_CLASS_PATH.'/gw_base.php';
 
 	$class_name = 'kSellaGuestPayGW'; // for automatic installation
 
 	class kSellaGuestPayGW extends kGWBase
 	{
 		function InstallData()
 		{
 			$data = array(
 				'Gateway' => Array('Name' => 'Sella/GuestPay', 'ClassName' => 'kSellaGuestPayGW', 'ClassFile' => 'sella_guestpay.php', 'RequireCCFields' => 0),
 				'ConfigFields' => Array(
 					'merchant_id' => Array('Name' => 'Merchant ID', 'Type' => 'text', 'ValueList' => '', 'Default' => ''),
 					'merchant_country' => Array('Name' => 'Merchant Country Code', 'Type' => 'text', 'ValueList' => '', 'Default' => ''),
 					'currency_code' => Array('Name' => 'Currency Code', 'Type' => 'text', 'ValueList' => '', 'Default' => '978'),
 					'language_code' => Array('Name' => 'Language Code', 'Type' => 'text', 'ValueList' => '', 'Default' => '2'),
 					'shipping_control' => Array('Name' => 'Shipping Control', 'Type' => 'select', 'ValueList' => '3=la_CreditDirect,4=la_CreditPreAuthorize', 'Default' => '3'),
 				)
 			);
 			return $data;
 		}
 
 		/**
 		 * Returns payment form submit url
 		 *
 		 * @param Array $gw_params gateway params from payment type config
 		 * @return string
 		 */
 		function getFormAction($gw_params)
 		{
 			return 'https://ecomm.sella.it/gestpay/pagam.asp';
 		}
 
 		/**
 		 * Processed input data and convets it to fields understandable by gateway
 		 *
 		 * @param Array $item_data
 		 * @param Array $tag_params additional params for gateway passed through tag
 		 * @param Array $gw_params gateway params from payment type config
 		 * @return Array
 		 */
 		function getHiddenFields($item_data, $tag_params, $gw_params)
 		{
 			$a = $gw_params['merchant_id'];
 			$params['PAY1_UICCODE'] = $gw_params['currency_code'];
 			$params['PAY1_AMOUNT'] = $item_data['TotalAmount'];
 			$params['PAY1_SHOPTRANSACTIONID'] = $item_data['OrderId'];
 			$params['PAY1_IDLANGUAGE'] = $gw_params['language_code'];
 			$params['CUSTOM_INFO'] = $this->Application->GetSID().','.MD5($item_data['OrderId']);
 
 			$separator = '*P1*';
 			$b = array();
 			foreach ($params as $key=>$val) {
 				$b[] = $key.'='.urlencode(trim($val));
 			}
 			//the last one is CUSTOMINFO according to GW specs, passing the atosorigin-style 'caddie'
 			$b = join($separator, $b);
 			$url = 'https://ecomm.sella.it/CryptHTTPS/Encrypt.asp?a='.$a.'&b='.$b.'&c=2.0';
 
 			$curl_helper = $this->Application->recallObject('CurlHelper');
 			/* @var $curl_helper kCurlHelper */
 
 			$res = $curl_helper->Send($url);
 
 			preg_match('/#cryptstring#(.*)#\/cryptstring#/', $res, $matches);
 			$b = $matches[1];
 
 			$res = '<input type="hidden" name="a" value="'.$a.'"><input type="hidden" name="b" value="'.$b.'">';
 			return $res;
 		}
 
 		function NeedPlaceButton($item_data, $tag_params, $gw_params)
 		{
 			return true;
 		}
 
 		function processNotification($gw_params)
 		{
 			$a = $gw_params['merchant_id'];
-			$b = $_REQUEST['b'];
+			$b = $_GET['b'];
 			$url = 'https://ecomm.sella.it/CryptHTTPS/Decrypt.asp?a='.$a.'&b='.$b.'&c=2.0';
 
 			$curl_helper = $this->Application->recallObject('CurlHelper');
 			/* @var $curl_helper kCurlHelper */
 
 			$ret = $curl_helper->Send($url);
 			$result = $this->parseGWResponce($ret, $gw_params);
 
 			list ($sid, $auth_code) = explode(',', $result['CUSTOM_INFO']);
 			$session = $this->Application->recallObject('Session');
 			$session->SID = $sid;
 
 			$order_id = $this->Conn->GetOne('SELECT OrderId FROM '.TABLE_PREFIX.'Orders WHERE md5(OrderId) = '.$this->Conn->qstr($auth_code));
 			$this->Application->SetVar('ord_id', $order_id);
 			$order = $this->Application->recallObject('ord');
 			$order->Load($order_id);
 
 			if ($this->Application->GetVar('sella_ok')) {
 				if ($result['PAY1_TRANSACTIONRESULT'] == 'OK') {
 					$this->Application->Redirect('in-commerce/checkout/checkout_success', null, '_FRONT_END_', 'index.php');
 				}
 				else {
 					$this->Application->SetVar('sella_error', 1);
 				}
 			}
 			if ($this->Application->GetVar('sella_error')) {
 				$this->Application->StoreVar('gw_error', $this->getErrorMsg());
 				$this->Application->Redirect('in-commerce/checkout/billing', null, '_FRONT_END_', 'index.php');
 			}
 
 			return $result['PAY1_TRANSACTIONRESULT'] == 'OK' ? 1 : 0;
 		}
 
 		function parseGWResponce($str, $gw_params)
 		{
 			if (preg_match('/#decryptstring#(.*)#\/decryptstring#/', $str, $matches)) {
 				$separator = '*P1*';
 				$pairs = explode($separator, $matches[1]);
 				foreach ($pairs as $a_pair) {
 					list($key, $val) = explode('=', $a_pair);
 					$result[$key] = $val;
 				}
 			}
 			elseif (preg_match('/#error#(.*)#\/error#/', $str, $matches))
 			{
 				$result['PAY1_ERRORDESCRIPTION'] = $matches[1];
 			}
 			else { //unknown error
 				$result['PAY1_ERRORDESCRIPTION'] = 'Unknown error';
 			}
 
 			$this->parsed_responce = $result;
 			return $result;
 		}
 
 		function getGWResponce()
 		{
 			return serialize($this->parsed_responce);
 		}
 
 		function getErrorMsg()
 		{
 			$msg = $this->parsed_responce['PAY1_ERRORDESCRIPTION'];
 			if (!$msg) {
 				if ($this->parsed_responce['response_code'] != 'OK') {
 					$msg = 'Transaction failed';
 				}
 			}
 			return $msg;
 		}
 	}
\ No newline at end of file
Index: branches/5.3.x/units/gateways/gw_classes/paybox.php
===================================================================
--- branches/5.3.x/units/gateways/gw_classes/paybox.php	(revision 15670)
+++ branches/5.3.x/units/gateways/gw_classes/paybox.php	(revision 15671)
@@ -1,182 +1,182 @@
 <?php
 /**
 * @version	$Id$
 * @package	In-Commerce
 * @copyright	Copyright (C) 1997 - 2009 Intechnic. All rights reserved.
 * @license	Commercial License
 * This software is protected by copyright law and international treaties.
 * Unauthorized reproduction or unlicensed usage of the code of this program,
 * or any portion of it may result in severe civil and criminal penalties,
 * and will be prosecuted to the maximum extent possible under the law
 * See http://www.in-portal.org/commercial-license for copyright notices and details.
 */
 
 	require_once GW_CLASS_PATH.'/gw_base.php';
 
 	$class_name = 'kPayboxGW'; // for automatic installation
 
 	class kPayboxGW extends kGWBase
 	{
 		function InstallData()
 		{
 			$data = array(
 				'Gateway' => Array('Name' => 'Paybox.com', 'ClassName' => 'kPayboxGW', 'ClassFile' => 'paybox.php', 'RequireCCFields' => 0),
 				'ConfigFields' => Array(
 					'binary' => Array('Name' => 'API Executable', 'Type' => 'text', 'ValueList' => '', 'Default' => ''),
 					'params_file' => Array('Name' => 'OPT Params File', 'Type' => 'text', 'ValueList' => '', 'Default' => ''),
 					'site_number' => Array('Name' => 'Site Number', 'Type' => 'text', 'ValueList' => '', 'Default' => ''),
 					'rank_number' => Array('Name' => 'Rank Number', 'Type' => 'text', 'ValueList' => '', 'Default' => ''),
 					'identity_number' => Array('Name' => 'Identity Number', 'Type' => 'text', 'ValueList' => '', 'Default' => ''),
 					'currency_code' => Array('Name' => 'Currency Code', 'Type' => 'text', 'ValueList' => '', 'Default' => '978'),
 					'shipping_control' => Array('Name' => 'Shipping Control', 'Type' => 'select', 'ValueList' => '3=la_CreditDirect,4=la_CreditPreAuthorize', 'Default' => '3'),
 				)
 			);
 			return $data;
 		}
 
 		/**
 		 * Returns payment form submit url
 		 *
 		 * @param Array $gw_params gateway params from payment type config
 		 * @return string
 		 */
 		function getFormAction($gw_params)
 		{
 			return $gw_params['submit_url'];
 		}
 
 		/**
 		 * Processed input data and convets it to fields understandable by gateway
 		 *
 		 * @param Array $item_data
 		 * @param Array $tag_params additional params for gateway passed through tag
 		 * @param Array $gw_params gateway params from payment type config
 		 * @return Array
 		 */
 		function getHiddenFields($item_data, $tag_params, $gw_params)
 		{
 			$params['PBX_MODE'] = $gw_params['params_file'] ? '34' : '4';
 			$params['PBX_OUTPUT'] = 'B';
 			$params['PBX_SITE'] = $gw_params['site_number'];
 			$params['PBX_RANG'] = $gw_params['rank_number'];
 			$params['PBX_IDENTIFIANT'] = $gw_params['identity_number'];
 			$params['PBX_OPT'] = $gw_params['params_file'];
 			$params['PBX_DEVISE'] = $gw_params['currency_code']; // 978 for the euro. 840 for the US dollar.
 
 			$params['PBX_RETOUR'] = 'amount:M;reference:R;trans:T;autorization:A;subscription:B;payment:P;card:C;trans_id:S;country:Y;error:E;expiration:D';
 
 			$params['PBX_EFFECTUE'] = $this->Application->HREF($tag_params['return_template'],'',Array('pass'=>'m'));
 			$params['PBX_REFUSE'] = $this->Application->HREF($tag_params['cancel_template'],'',Array('pass'=>'m'));
 
 			$txt_amount = sprintf("%.2f", $item_data['TotalAmount']);
 			$params['PBX_TOTAL'] = str_replace( Array('.', ','), '', $txt_amount);
 			$params['PBX_CMD'] = $this->Application->GetSID().','.MD5($item_data['OrderId']);
 
 			/*$params['order_id'] = $item_data['OrderId'];
-			$params['customer_ip_address'] = $_SERVER['REMOTE_ADDR'];
+			$params['customer_ip_address'] = $this->Application->getClientIp();
 			$params['customer_id'] = $item_data['PortalUserId'];*/
 
 			$billing_email = $item_data['BillingEmail'];
 			if (!$billing_email) {
 				$billing_email = $this->Conn->GetOne('	SELECT Email FROM '.$this->Application->getUnitOption('u', 'TableName').'
 											WHERE PortalUserId = '.$this->Application->RecallVar('user_id'));
 			}
 			$params['PBX_PORTEUR'] = $billing_email;
 
 			$params_str = '';
 			foreach ($params as $key => $val) {
 				$params_str .= ' '.$key . '="'.$val.'"';
 			}
 			$run_line = $gw_params['binary'].' '.$params_str;
 
 //			$run_line = escapeshellcmd($run_line);
 //			echo escapeshellcmd($run_line);
 
 			exec ($run_line, $rets);
 
 			$ret = implode("\n", $rets);
 
 			$ret = preg_replace('/^(.*)!!/is', '', $ret);
 			$ret = rtrim($ret, '!');
 
 			return '</form>'.$ret.'<form>';
 		}
 
 		function NeedPlaceButton($item_data, $tag_params, $gw_params)
 		{
 			return false;
 		}
 
 		function processNotification($gw_params)
 		{
 			$result = $this->Application->HttpQuery->GetParams();
 			$this->parsed_responce = $result;
 
 			list ($sid, $auth_code) = explode(',', $result['reference']);
 			$session = $this->Application->recallObject('Session');
 			$session->SID = $sid;
 
 			$order_id = $this->Conn->GetOne('SELECT OrderId FROM '.TABLE_PREFIX.'Orders WHERE md5(OrderId) = '.$this->Conn->qstr($auth_code));
 			$this->Application->SetVar('ord_id', $order_id);
 			$order = $this->Application->recallObject('ord');
 			$order->Load($order_id);
 
 			return $result['error'] === '00000' ? 1 : 0;
 		}
 
 		function parseGWResponce($str, $gw_params)
 		{
 			$response = explode ("!", $str);
 
 			$result = Array (
 				'code' => $response[1],
 				'error' => $response[2],
 				'merchant_id' => $response[3],
 				'merchant_country' => $response[4],
 				'amount' => $response[5],
 				'transaction_id' => $response[6],
 				'payment_means' => $response[7],
 				'transmission_date' => $response[8],
 				'payment_time' => $response[9],
 				'payment_date' => $response[10],
 				'response_code' => $response[11],
 				'payment_certificate' => $response[12],
 				'authorisation_id' => $response[13],
 				'currency_code' => $response[14],
 				'card_number' => $response[15],
 				'cvv_flag' => $response[16],
 				'cvv_response_code' => $response[17],
 				'bank_response_code' => $response[18],
 				'complementary_code' => $response[19],
 				'complementary_info' => $response[20],
 				'return_context' => $response[21],
 				'caddie' => $response[22],
 				'receipt_complement' => $response[23],
 				'merchant_language' => $response[24],
 				'language' => $response[25],
 				'customer_id' => $response[26],
 				'order_id' => $response[27],
 				'customer_email' => $response[28],
 				'customer_ip_address' => $response[29],
 				'capture_day' => $response[30],
 				'capture_mode' => $response[31],
 				'data' => $response[32],
 			);
 			$this->parsed_responce = $result;
 			return $result;
 		}
 
 		function getGWResponce()
 		{
 			return serialize($this->parsed_responce);
 		}
 
 		function getErrorMsg()
 		{
 			$msg = '';
 			if ($this->parsed_responce['response_code'] != '00000') {
 				$msg = 'Transaction failed';
 			}
 			return $msg;
 		}
 	}
\ No newline at end of file
Index: branches/5.3.x/units/gateways/gw_classes/ideal_nl.php
===================================================================
--- branches/5.3.x/units/gateways/gw_classes/ideal_nl.php	(revision 15670)
+++ branches/5.3.x/units/gateways/gw_classes/ideal_nl.php	(revision 15671)
@@ -1,170 +1,170 @@
 <?php
 /**
 * @version	$Id$
 * @package	In-Commerce
 * @copyright	Copyright (C) 1997 - 2009 Intechnic. All rights reserved.
 * @license	Commercial License
 * This software is protected by copyright law and international treaties.
 * Unauthorized reproduction or unlicensed usage of the code of this program,
 * or any portion of it may result in severe civil and criminal penalties,
 * and will be prosecuted to the maximum extent possible under the law
 * See http://www.in-portal.org/commercial-license for copyright notices and details.
 */
 
 /* http://www.ideal.nl/ gateway class */
 
 	require_once GW_CLASS_PATH.'/gw_base.php';
 
 	$class_name = 'kGWiDEALnl'; // for automatic installation
 
 	class kGWiDEALnl extends kGWBase
 	{
 
 		function InstallData()
 		{
 			$data = array(
 				'Gateway' => Array('Name' => 'iDEAL.nl', 'ClassName' => 'kGWiDEALnl', 'ClassFile' => 'ideal_nl.php', 'RequireCCFields' => 0),
 				'ConfigFields' => Array(
 					'partner_id' => Array('Name' => 'Partner ID', 'Type' => 'text', 'ValueList' => '', 'Default' => ''),
 					'request_url' => Array('Name' => 'Request URL', 'Type' => 'text', 'ValueList' => '', 'Default' => 'http://www.mollie.nl/xml/ideals'),
 					'shipping_control' => Array('Name' => 'Shipping Control', 'Type' => 'select', 'ValueList' => '3=la_CreditDirect,4=la_CreditPreAuthorize', 'Default' => '3'),
 				)
 			);
 			return $data;
 		}
 
 		/**
 		 * Processed input data and convets it to fields understandable by gateway
 		 *
 		 * @param Array $item_data
 		 * @param Array $tag_params additional params for gateway passed through tag
 		 * @param Array $gw_params gateway params from payment type config
 		 * @return Array
 		 */
 		function getHiddenFields($item_data, $tag_params, $gw_params)
 		{
 			$this->Application->StoreVar('gw_success_template',$tag_params['return_template']);
 			$this->Application->StoreVar('gw_cancel_template',$tag_params['cancel_template']);
 
 			$curl_helper = $this->Application->recallObject('CurlHelper');
 			/* @var $curl_helper kCurlHelper */
 
 			$banks = $curl_helper->Send($gw_params['request_url'].'?a=banklist');
 
 			$parser = $this->Application->recallObject('kXMLHelper');
 			/* @var $parser kXMLHelper */
 			$bank_data =& $parser->Parse($banks);
 
 			$bank_data->FindChild('response');
 			$banks = array();
 			foreach ($bank_data->Children as $a_child) {
 				if ($a_child->Name != 'BANK') continue;
 				$banks[$a_child->FindChildValue('bank_id')] = $a_child->FindChildValue('bank_name');
 			}
 
 			$ret = $this->Application->Phrase('lu_Select_iDEAL_bank').': <select name="ideal_nl_bank_id">';
 			foreach ($banks as $id => $name) {
 				$ret .= '<option value="'.$id.'">'.$name.'</option>';
 			}
 			$ret .= '</select>';
 			$ret .= '<input type="hidden" name="events[ord]" value="OnCompleteOrder" />'."\n";
 			return $ret;
 		}
 
 		function DirectPayment($item_data, $gw_params)
 		{
 			$fields = array();
 
 			$fields['a'] = 'fetch';
 			$fields['partnerid'] = $gw_params['partner_id'];
 			$txt_amount = sprintf("%.2f", $item_data['TotalAmount']);
 			$fields['amount'] = str_replace( Array('.', ','), '', $txt_amount);
 			$fields['bank_id'] = $this->Application->GetVar('ideal_nl_bank_id');
 			$fields['description'] = 'Invoice #'.$item_data['OrderNumber'];
 			$fields['returnurl'] = $this->getNotificationUrl() . '?order_id='.$item_data['OrderId'];
 			$fields['reporturl'] = $this->getNotificationUrl() . '?mode=report&order_id='.$item_data['OrderId'];
 
 			$curl_helper = $this->Application->recallObject('CurlHelper');
 			/* @var $curl_helper kCurlHelper */
 
 			$curl_helper->SetRequestData($fields);
 			$transaction_xml = $curl_helper->Send($gw_params['request_url']);
 
 			$parser = $this->Application->recallObject('kXMLHelper');
 			/* @var $parser kXMLHelper */
 			$trans_data =& $parser->Parse($transaction_xml);
 			$transaction_id = $trans_data->FindChildValue('transaction_id');
 			$url = $trans_data->FindChildValue('url');
 
 			if ($transaction_id && $url) {
 				$this->Application->Redirect('external:'.$url);
 			}
 			else {
 				$error_msg = $trans_data->FindChildValue('message');
 				$this->parsed_responce['XML'] = $transaction_xml;
 				$this->Application->SetVar('failure_template', $this->Application->RecallVar('gw_cancel_template'));
-				$this->parsed_responce['MESSAGE'] = $error_msg ? $error_msg : 'Unknown gateway error ('.htmlspecialchars($transaction_xml).')';
+				$this->parsed_responce['MESSAGE'] = $error_msg ? $error_msg : 'Unknown gateway error ('.htmlspecialchars($transaction_xml, null, CHARSET).')';
 				return false;
 			}
 
 			return true;
 		}
 
 		function getErrorMsg()
 		{
 			return $this->parsed_responce['MESSAGE'];
 		}
 
 		function getGWResponce()
 		{
 			return serialize($this->parsed_responce);
 		}
 
 		function processNotification($gw_params)
 		{
 			// silent mode
 			if ($this->Application->GetVar('mode') == 'report') {
 				$fields = array();
 
 				$fields['a'] = 'check';
 				$fields['partnerid'] = $gw_params['partner_id'];
 				$fields['transaction_id'] =  $this->Application->GetVar('transaction_id');
 				$fields['bank_id'] = $this->Application->GetVar('ideal_nl_bank_id');
 
 				$curl_helper = $this->Application->recallObject('CurlHelper');
 				/* @var $curl_helper kCurlHelper */
 
 				$curl_helper->SetRequestData($fields);
 				$check_xml = $curl_helper->Send($gw_params['request_url']);
 
 				$parser = $this->Application->recallObject('kXMLHelper');
 				/* @var $parser kXMLHelper */
 				$trans_data =& $parser->Parse($check_xml);
 
 				$response = $trans_data->FindChild('order');
 				foreach ($response->Children as $a_child) {
 					$this->parsed_responce[$a_child->Name] = $a_child->Data;
 				}
 				$this->parsed_responce['XML'] = $check_xml;
 
 				$result = $trans_data->FindChildValue('payed') == 'true' ? 1:0;
 				return $result;
 			}
 			else {
 				$order = $this->Application->recallObject('ord');
 				if ($order->GetDBField('Status') == ORDER_STATUS_INCOMPLETE) {
 					// error
 					$t = $this->Application->RecallVar('gw_cancel_template');
 					$this->parsed_responce = unserialize($order->GetDBField('GWResult1'));
 					$this->Application->StoreVar('gw_error', $this->getErrorMsg());
 					$this->Application->Redirect($t, array('pass'=>'m', 'm_cat_id'=>0));
 				}
 				else {
 					// ok
 					$t = $this->Application->RecallVar('gw_success_template');
 					$this->Application->Redirect($t, array('pass'=>'m', 'm_cat_id'=>0));
 
 				}
 			}
 		}
 	}
\ No newline at end of file
Index: branches/5.3.x/units/gateways/gw_classes/rightconnect.php
===================================================================
--- branches/5.3.x/units/gateways/gw_classes/rightconnect.php	(revision 15670)
+++ branches/5.3.x/units/gateways/gw_classes/rightconnect.php	(revision 15671)
@@ -1,224 +1,224 @@
 <?php
 /**
 * @version	$Id$
 * @package	In-Commerce
 * @copyright	Copyright (C) 1997 - 2009 Intechnic. All rights reserved.
 * @license	Commercial License
 * This software is protected by copyright law and international treaties.
 * Unauthorized reproduction or unlicensed usage of the code of this program,
 * or any portion of it may result in severe civil and criminal penalties,
 * and will be prosecuted to the maximum extent possible under the law
 * See http://www.in-portal.org/commercial-license for copyright notices and details.
 */
 
 	require_once GW_CLASS_PATH.'/gw_base.php';
 
 	class kGWRightConnect extends kGWBase
 	{
 
 	/*	function Install()
 		{
 			$query = "INSERT INTO `".TABLE_PREFIX."Gateways` ( `GatewayId` , `Name` , `ClassName` , `ClassFile` , `RequireCCFields` )
 								VALUES (
 									'', 'RightConnect', 'kGWRightConnect', 'rightconnect.php', '1'
 								)";
 			$this->Conn->Query($query);
 			$id = $this->Conn->getInsertID();
 
 			$query = "INSERT INTO `".TABLE_PREFIX."GatewayConfigFields` ( `GWConfigFieldId` , `SystemFieldName` , `FieldName` , `ElementType` , `ValueList` , `GatewayId` )
 								VALUES (
 								'', 'submit_url', 'Submit URL', 'text', '', '$id'
 								), (
 								'', 'user_account', 'User Account', 'text', '', '$id'
 								), (
 								'', 'password', 'User Account', 'text', '', '$id'
 								),
 								(
 								'', 'encapsulate_char', 'Encapsualte Char', 'text', '', '$id'
 								)";
 			$this->Conn->Query($query);
 		}*/
 
 		function DirectPayment($item_data, $gw_params)
 		{
 
 			/*$post_fields["card_holder"] = "test test";
 			$post_fields["cardtype"] = "Visa";
 			$post_fields["card_number"] = "4444333322221111";
 			$post_fields["cvv2"] = "123";
 			$post_fields["exp_mon"] = "05";
 			$post_fields["exp_year"] = "05";
 			$post_fields["address1"] = "test";
 			$post_fields["city"] = "test";
 			$post_fields["state"] = "CA";
 			$post_fields["zip"] = "90069";
 			$post_fields["country"] = "USA";
 			$post_fields["firstname"] = "test";
 			$post_fields["lastname"] = "test";
 			$post_fields["email"] = "customer@yourdomain.com";
 			$post_fields["merchant_account"] = "demo";
 			$post_fields["trans_amount"] = "8.98";
 			$post_fields["user1"] = "DELIM";
 			$post_fields["ALIAS"] = "www.yourdomain.com";
-			$post_fields["customer_ip"] = $_SERVER['REMOTE_ADDR'];
+			$post_fields["customer_ip"] = $this->Application->getClientIp();
 			$post_fields["ADMIN_EMAIL"] = "admin@yourdomain.com";*/
 
 
 			$post_fields = Array();
 			// -- Login Information --
 			//$post_fields['x_version']			=	'3.1';
 			$post_fields["user1"] = "DELIM";
 
 			//$post_fields['x_type']				=	$gw_params['shipping_control'] == SHIPPING_CONTROL_PREAUTH ? 'AUTH_ONLY' : 'AUTH_CAPTURE';
 
 			$post_fields['merchant_account']	=	$gw_params['user_account'];
 			$post_fields['merchant_pass']			=	$gw_params['password'];
 
 			if( $this->IsTestMode() ) $post_fields['x_test_request'] = 'True';
 
 			// -- Payment Details --
 			$names = explode(' ', $item_data['BillingTo'], 2);
 			$post_fields['firstname']		=	getArrayValue($names, 0);
 			$post_fields['lastname']			=	getArrayValue($names, 1);
 			$post_fields['trans_amount']			=	sprintf('%.2f', $item_data['TotalAmount']);
 
 			//$post_fields['x_company']			=	$item_data['BillingCompany'];
 
 			$post_fields['card_number']			=	$item_data['PaymentAccount'];
 			$post_fields['card_holder']			=	$item_data['PaymentNameOnCard'];
 			$post_fields['cvv2']			=	$item_data['PaymentCVV2'];
 
 			list($exp_mon,$exp_year) = explode('/', $item_data['PaymentCCExpDate']);
 			$post_fields['exp_mon']			=	$exp_mon;
 			$post_fields['exp_year']			=	$exp_year;
 
 			$post_fields['address1']			=	$item_data['BillingAddress1'];
 			$post_fields['address2']			=	$item_data['BillingAddress2'];
 			$post_fields['city']				=	$item_data['BillingCity'];
 			$post_fields['state']				=	$item_data['BillingState'];
 			$post_fields['zip']				=	$item_data['BillingZip'];
 
 			$post_fields['country']			=	$item_data['BillingCountry'];
 
 			$post_fields['user2']			=	$item_data['PortalUserId'];
 			$post_fields['user3']		=	$item_data['OrderNumber'];
 			$post_fields['customer_email']	=	'FALSE';
 
 			$post_fields['customer_addr'] = $item_data['OrderIP']; // according to fields list in doc
 			$post_fields['customer_ip'] = $item_data['OrderIP']; // according to example from doc
 			$post_fields["email"] = $item_data['BillingEmail'];
 			$post_fields["ADMIN_EMAIL"] = $this->Application->ConfigValue('DefaultEmailSender');
 
 			$curl_helper = $this->Application->recallObject('CurlHelper');
 			/* @var $curl_helper kCurlHelper */
 
 			$curl_helper->SetPostData($post_fields);
 			$this->gw_responce = $curl_helper->Send($gw_params['submit_url']);
 
 			$gw_responce = $this->parseGWResponce(null, $gw_params);
 
 			// gw_error_msg: $gw_response['responce_reason_text']
 			// gw_error_code: $gw_response['responce_reason_code']
 			return ($gw_responce['responce_code'] != 1) ? false : true;
 		}
 
 		/**
 		 * Captures Authorized transaction by transaction ID
 		 *
 		 * @param Array $item_data
 		 * @param Array $gw_params
 		 * @return bool
 		 */
 		function Charge($item_data, $gw_params)
 		{
 			return true;
 		}
 
 		/**
 		 * Parse previosly saved gw responce into associative array
 		 *
 		 * @param string $gw_responce
 		 * @param Array $gw_params
 		 * @return Array
 		 */
 		function parseGWResponce($gw_responce = null, $gw_params)
 		{
 			if( !isset($gw_responce) ) $gw_responce = $this->gw_responce;
 
 			$fields = Array(
 							'responce_code',  				// 0
 							'responce_sub_code',			// 1
 							'responce_reason_code',		// 2
 							'responce_reason_text',		// 3
 							'approval_code',					// 4
 							'avs_result_code',				// 5
 							'transaction_id',					// 6
 							'fraud_score',						// 7
 							'not_used8',							// 8
 							'amount',									// 9
 							'not_used10',							// 10
 							'transaction_type',				// 11
 							'not_used_customer_id',		// 12
 							'first_name',							// 13
 							'last_name',							// 14
 							'not_documented_empty_field', // 15 !!!!!!!!!!! DOES NOT MATCH DOCUMENTATION
 							'address',								// 16
 							'city',										// 17
 							'state',									// 18
 							'zip',										// 19
 							'country',								// 20
 							'phone',									// 21
 							'fax',										// 22
 							'email',									// 23
 							'ship_name',							// 24
 							'not_used25',							// 25
 							'not_used26',							// 26
 							'ship_address',						// 27
 							'ship_city',							// 28
 							'ship_state',							// 29
 							'ship_zip',								// 30
 							'ship_country',						// 31
 							'tax',										// 32
 							'not_used32',							// 33
 							'not_used33',							// 34
 							'not_used34',							// 35
 							'not_used35',							// 36
 							'not_used36',							// 37
 							'cvv_responce',						// 38
 							'receipt_number',					// 39
 							'passthru1',							// 40
 							'passthru2',							// 41
 							'passthru3',							// 42
 							'passthru4',							// 43
 							'passthru5',							// 44
 							'passthru6',							// 45
 							'passthru7',							// 46
 							'passthru8',							// 47
 							'passthru9',							// 48
 							'passthru10',							// 49
 							);
 
 			$encapsulate_char = $gw_params['encapsulate_char'];
 			if($encapsulate_char)
 			{
 				$ec_length = strlen($encapsulate_char);
 				$gw_responce = substr($gw_responce, $ec_length, $ec_length * -1);
 			}
 
 			$gw_responce = explode($encapsulate_char.','.$encapsulate_char, $gw_responce);
 			$ret = Array();
 			foreach($fields as $field_index => $field_name)
 			{
 				$ret[$field_name] = $gw_responce[$field_index];
 				unset($gw_responce[$field_index]);
 			}
 			$this->parsed_responce = $ret;
 			return kUtil::array_merge_recursive($ret, $gw_responce); // returns unparsed fields with they original indexes together with parsed ones
 		}
 
 		function getGWResponce()
 		{
 			return serialize($this->parsed_responce);
 		}
 
 	}
\ No newline at end of file
Index: branches/5.3.x/units/gateways/gw_tag_processor.php
===================================================================
--- branches/5.3.x/units/gateways/gw_tag_processor.php	(revision 15670)
+++ branches/5.3.x/units/gateways/gw_tag_processor.php	(revision 15671)
@@ -1,127 +1,127 @@
 <?php
 /**
 * @version	$Id$
 * @package	In-Commerce
 * @copyright	Copyright (C) 1997 - 2009 Intechnic. All rights reserved.
 * @license	Commercial License
 * This software is protected by copyright law and international treaties.
 * Unauthorized reproduction or unlicensed usage of the code of this program,
 * or any portion of it may result in severe civil and criminal penalties,
 * and will be prosecuted to the maximum extent possible under the law
 * See http://www.in-portal.org/commercial-license for copyright notices and details.
 */
 
 defined('FULL_PATH') or die('restricted access!');
 
 class GatewayTagProcessor extends kDBTagProcessor {
 
 	/**
 	 * Payment gateway config values for current payment type
 	 *
 	 * @var Array
 	 * @access private
 	 */
 	var $ConfigValues=Array();
 
 	/**
 	 * Payment type id for current gateway values
 	 *
 	 * @var int
 	 * @access private
 	 */
 	var $PaymentTypeID=0;
 
 
 	function initGWConfigValues()
 	{
 		$payment_type_id = $this->Application->GetVar('pt_id');
 		$GWConfigValue = $this->Application->recallObject('gwfv');
 
 		$sql = 'SELECT Value, GWConfigFieldId FROM '.$GWConfigValue->TableName.' WHERE PaymentTypeId = '.$payment_type_id;
 		$this->ConfigValues = $this->Conn->GetCol($sql,'GWConfigFieldId');
 	}
 
 	function gwConfigValue($params)
 	{
 		$object = $this->getObject($params);
 		/* @var $object kDBItem */
 
 		$id = $object->GetID();
 
 		$value = isset($this->ConfigValues[$id]) ? $this->ConfigValues[$id] : '';
 		if ( !array_key_exists('no_special', $params) || !$params['no_special'] ) {
-			$value = htmlspecialchars($value);
+			$value = htmlspecialchars($value, null, CHARSET);
 		}
 
 		if ( getArrayValue($params, 'checked') ) {
 			$value = ($value == 1) ? 'checked' : '';
 		}
 
 		return $value;
 	}
 
 	function PrintList($params)
 	{
 		$list = $this->Application->recallObject( $this->getPrefixSpecial(), $this->Prefix.'_List', $params);
 		$id_field = $this->Application->getUnitOption($this->Prefix,'IDField');
 
 		$list->Query();
 		$list->GoFirst();
 
 		$block_params=$this->prepareTagParams($params);
 		$block_params['name']=$params['block'];
 		$block_params['pass_params']='true';
 
 		$payment_type_object = $this->Application->recallObject('pt');
 
 		$o = '';
 
 		while (!$list->EOL())
 		{
 			$this->Application->SetVar( $this->getPrefixSpecial().'_id', $list->GetDBField($id_field) );
 
 			$display_style = $payment_type_object->GetDBField('GatewayId') == $list->GetDBField('GatewayId') ? 'table-row' : 'none';
 			$block_params['input_block'] = $params['input_block_prefix'].$list->GetDBField('ElementType');
 			$block_params['gateway_id'] = $list->GetDBField('GatewayId');
 			$block_params['display'] = $display_style;
 
 			$o .= $this->Application->ParseBlock($block_params, 1);
 
 			$list->GoNext();
 		}
 
 		return $o;
 	}
 
 	/**
 	 * Prints list a all possible field options
 	 *
 	 * @param Array $params
 	 * @return string
 	 * @access protected
 	 */
 	protected function PredefinedOptions($params)
 	{
 		$object = $this->getObject($params);
 		/* @var $object kDBItem */
 
 		$block_params = $this->prepareTagParams($params);
 		$block_params['name'] = $this->SelectParam($params, 'render_as,block');
 		$block_params['pass_params'] = 'true';
 
 		$o = '';
 		$value = $this->gwConfigValue($params);
 		$options = explode(',', $object->GetDBField('ValueList'));
 
 		foreach ($options as $key_val) {
 			list($key, $val) = explode('=', $key_val);
 			$block_params['key'] = $key;
 			$block_params['option'] = $val;
 			$block_params['selected'] = ($key == $value ? ' ' . $params['selected'] : '');
 			$block_params['PrefixSpecial'] = $this->getPrefixSpecial();
 			$o .= $this->Application->ParseBlock($block_params, 1);
 		}
 
 		return $o;
 	}
 }
\ No newline at end of file
Index: branches/5.3.x/units/downloads/download_helper.php
===================================================================
--- branches/5.3.x/units/downloads/download_helper.php	(revision 15670)
+++ branches/5.3.x/units/downloads/download_helper.php	(revision 15671)
@@ -1,77 +1,77 @@
 <?php
 /**
 * @version	$Id$
 * @package	In-Commerce
 * @copyright	Copyright (C) 1997 - 2009 Intechnic. All rights reserved.
 * @license	Commercial License
 * This software is protected by copyright law and international treaties.
 * Unauthorized reproduction or unlicensed usage of the code of this program,
 * or any portion of it may result in severe civil and criminal penalties,
 * and will be prosecuted to the maximum extent possible under the law
 * See http://www.in-portal.org/commercial-license for copyright notices and details.
 */
 
 	defined('FULL_PATH') or die('restricted access!');
 
 	class DownloadHelper extends kHelper {
 
 		function CheckAccess($file_id, $product_id)
 		{
 			$sql = 'SELECT FileAccessId FROM '.TABLE_PREFIX.'UserFileAccess
 							WHERE PortalUserId = '.$this->Application->RecallVar('user_id').'
 							AND ProductId = '.$product_id;
 			return $this->Conn->GetOne($sql);
 		}
 
 		function SendFile($file_id, $product_id)
 		{
 			$file_object = $this->Application->recallObject('file', null, Array('skip_autoload' => true));
 			/* @var $file_object kDBItem */
 
 			$sql = $file_id ?
 						'SELECT FileId, FilePath, RealPath, MIMEType FROM '.$this->Application->getUnitOption('file', 'TableName').'
 							WHERE FileId = '.$file_id :
 						'SELECT FileId, FilePath, RealPath, MIMEType FROM '.$this->Application->getUnitOption('file', 'TableName').'
 							WHERE ProductId = '.$product_id.' AND IsPrimary = 1';
 			$file_info = $this->Conn->GetRow($sql);
 
 			$field_options = $file_object->GetFieldOptions('RealPath');
 			$file_info['real_path'] = FULL_PATH.$field_options['upload_dir'].'/'.$file_info['RealPath'];
 			$file_info = $this->DoSendFile($file_info);
 			return $file_info;
 		}
 
 		function DoSendFile($file_info)
 		{
 			$this->Application->setContentType(kUtil::mimeContentType($file_info['real_path']), false);
 			header('Content-Disposition: attachment; filename="' . $file_info['FilePath'] . '"');
 			header('Content-Length: ' . filesize($file_info['real_path']));
 
 			$file_info['download_start'] = adodb_mktime();
 			readfile($file_info['real_path']);
 			flush();
 			$file_info['download_end'] = adodb_mktime(); // this is incorrect
 			define('SKIP_OUT_COMPRESSION', 1);
 			return $file_info;
 		}
 
 		function LogDownload($product_id, $file_info)
 		{
 			$down_object = $this->Application->recallObject('down', null, Array('skip_autoload' => true));
 			$user_object = $this->Application->recallObject('u.current');
 			$product_object = $this->Application->recallObject( 'p' );
 
 			$down_object->SetDBField('PortalUserId', $this->Application->RecallVar('user_id'));
 			$down_object->SetDBField('Username', $user_object->GetDBField('Username'));
 			$down_object->SetDBField('ProductId', $product_id);
 			$down_object->SetDBField('ProductName', $product_object->GetField('Name'));
 			$down_object->SetDBField('FileId', $file_info['FileId']);
 			$down_object->SetDBField('Filename', $file_info['FilePath']);
-			$down_object->SetDBField('IPAddress', $_SERVER['REMOTE_ADDR']);
+			$down_object->SetDBField('IPAddress', $this->Application->getClientIp());
 			$down_object->SetDBField('StartedOn_date', $file_info['download_start']);
 			$down_object->SetDBField('StartedOn_time', $file_info['download_start']);
 
 			$down_object->Create();
 		}
 
 	}
\ No newline at end of file
Index: branches/5.3.x/units/product_options/product_options_tag_processor.php
===================================================================
--- branches/5.3.x/units/product_options/product_options_tag_processor.php	(revision 15670)
+++ branches/5.3.x/units/product_options/product_options_tag_processor.php	(revision 15671)
@@ -1,175 +1,175 @@
 <?php
 /**
 * @version	$Id$
 * @package	In-Commerce
 * @copyright	Copyright (C) 1997 - 2009 Intechnic. All rights reserved.
 * @license	Commercial License
 * This software is protected by copyright law and international treaties.
 * Unauthorized reproduction or unlicensed usage of the code of this program,
 * or any portion of it may result in severe civil and criminal penalties,
 * and will be prosecuted to the maximum extent possible under the law
 * See http://www.in-portal.org/commercial-license for copyright notices and details.
 */
 
 defined('FULL_PATH') or die('restricted access!');
 
 class ProductOptionsTagProcessor extends kDBTagProcessor {
 
 	function ShowOptions($params)
 	{
 		$object = $this->getObject($params);
 		/* @var $object kDBItem */
 
 		$opt_helper = $this->Application->recallObject('kProductOptionsHelper');
 		/* @var $opt_helper kProductOptionsHelper */
 
 		$parsed = $opt_helper->ExplodeOptionValues($object->GetFieldValues());
 		if ( !$parsed ) {
 			return '';
 		}
 
 		$values = $parsed['Values'];
 		$conv_prices = $parsed['Prices'];
 		$conv_price_types = $parsed['PriceTypes'];
 
 		$options =& $this->GetOptions();
 
 		$mode = $this->SelectParam($params, 'mode');
 		$combination_prefix = $this->SelectParam($params, 'combination_prefix');
 		$combination_field = $this->SelectParam($params, 'combination_field');
 
 		if ( $mode == 'selected' ) {
 			$comb = $this->Application->recallObject($combination_prefix);
 			/* @var $comb kDBItem */
 
 			$options = unserialize($comb->GetDBField($combination_field));
 		}
 
 		$block_params['name'] = $params['render_as'];
 		$block_params['selected'] = '';
 		$block_params['pass_params'] = 1;
 
 		$lang = $this->Application->recallObject('lang.current');
 		/* @var $lang LanguagesItem */
 
 		$o = '';
 		$first_selected = false;
 
 		foreach ($values as $option) {
 //			list($val, $label) = explode('|', $option);
 			$val = $option;
 
 			if ( getArrayValue($params, 'js') ) {
 				$block_params['id'] = addslashes($val);
-				$block_params['value'] = htmlspecialchars($val);
+				$block_params['value'] = htmlspecialchars($val, null, CHARSET);
 			}
 			else {
-				$block_params['id'] = htmlspecialchars($val);
-				$block_params['value'] = htmlspecialchars($val);
+				$block_params['id'] = htmlspecialchars($val, null, CHARSET);
+				$block_params['value'] = htmlspecialchars($val, null, CHARSET);
 			}
 
 			if ( $conv_prices[$val] ) {
 				if ( $conv_price_types[$val] == '$' && !getArrayValue($params, 'js') && !getArrayValue($params, 'no_currency') ) {
 					$iso = $this->GetISO($params['currency']);
 					$value = sprintf("%.2f", $this->ConvertCurrency($conv_prices[$val], $iso));
 
 					$value = $this->AddCurrencySymbol($lang->formatNumber($value, 2), $iso, true); // true to force sign
 					$block_params['price'] = $value;
 					$block_params['price_type'] = '';
 					$block_params['sign'] = ''; //sign is included in the formatted value
 				}
 				else {
 					$block_params['price'] = isset($params['js']) ? $conv_prices[$val] : $lang->formatNumber($conv_prices[$val], 2);
 					$block_params['price_type'] = $conv_price_types[$val];
 					$block_params['sign'] = $conv_prices[$val] >= 0 ? '+' : '-';
 				}
 			}
 			else {
 				$block_params['price'] = '';
 				$block_params['price_type'] = '';
 				$block_params['sign'] = '';
 			}
 
 			/*if ($mode == 'selected') {
 				$selected = $combination[$object->GetID()] == $val;
 			}
 			else*/
 			$selected = false;
 
 			if ( !$options && isset($params['preselect_first']) && $params['preselect_first'] && !$first_selected ) {
 				$selected = true;
 				$first_selected = true;
 			}
 
 			if ( is_array($options) ) {
 				$option_value = array_key_exists($object->GetID(), $options) ? $options[$object->GetID()] : '';
 
 				if ( $object->GetDBField('OptionType') == OptionType::CHECKBOX ) {
-					$selected = is_array($option_value) && in_array(htmlspecialchars($val), $option_value);
+					$selected = is_array($option_value) && in_array(htmlspecialchars($val, null, CHARSET), $option_value);
 				}
 				else { // radio buttons ?
 					$selected = htmlspecialchars_decode($option_value) == $val;
 				}
 			}
 
 			if ( $selected ) {
 				if ( $mode == 'selected' ) {
 					if ( $object->GetDBField('OptionType') != OptionType::CHECKBOX ) {
 						$block_params['selected'] = ' selected="selected" ';
 					}
 					else {
 						$block_params['selected'] = ' checked="checked" ';
 					}
 				}
 				else {
 					switch ($object->GetDBField('OptionType')) {
 						case OptionType::DROPDOWN:
 							$block_params['selected'] = ' selected="selected" ';
 							break;
 						case OptionType::RADIO:
 						case OptionType::CHECKBOX:
 							$block_params['selected'] = ' checked="checked" ';
 							break;
 					}
 				}
 			}
 			else {
 				$block_params['selected'] = '';
 			}
 
 			$o .= $this->Application->ParseBlock($block_params);
 		}
 
 		return $o;
 	}
 
 	function &GetOptions()
 	{
 		$opt_data = $this->Application->GetVar('options');
 		$options = getArrayValue($opt_data, $this->Application->GetVar('p_id'));
 		if (!$options && $this->Application->GetVar('orditems_id')) {
 			$ord_item = $this->Application->recallObject('orditems.-opt', null, Array ('skip_autoload' => true));
 			/* @var $ord_item kDBItem */
 
 			$ord_item->Load($this->Application->GetVar('orditems_id'));
 			$item_data = unserialize($ord_item->GetDBField('ItemData'));
 			$options = getArrayValue($item_data, 'Options');
 		}
 		return $options;
 	}
 
 	function OptionData($params)
 	{
 		$object = $this->getObject($params);
 		/* @var $object kDBItem */
 
 		$options =& $this->GetOptions();
 
 		return getArrayValue($options, $object->GetID());
 	}
 
 	function ListOptions($params)
 	{
 		return $this->PrintList2($params);
 	}
 }
\ No newline at end of file
Index: branches/5.3.x/units/pricing/pricing_event_handler.php
===================================================================
--- branches/5.3.x/units/pricing/pricing_event_handler.php	(revision 15670)
+++ branches/5.3.x/units/pricing/pricing_event_handler.php	(revision 15671)
@@ -1,522 +1,522 @@
 <?php
 /**
 * @version	$Id$
 * @package	In-Commerce
 * @copyright	Copyright (C) 1997 - 2011 Intechnic. All rights reserved.
 * @license	Commercial License
 * This software is protected by copyright law and international treaties.
 * Unauthorized reproduction or unlicensed usage of the code of this program,
 * or any portion of it may result in severe civil and criminal penalties,
 * and will be prosecuted to the maximum extent possible under the law
 * See http://www.in-portal.org/commercial-license for copyright notices and details.
 */
 
 defined('FULL_PATH') or die('restricted access!');
 
 // include globals.php from current folder
-kUtil::includeOnce(MODULES_PATH  .'/in-commerce/units/pricing/globals.php');
+kUtil::includeOnce(MODULES_PATH . '/in-commerce/units/pricing/globals.php');
 
 class PricingEventHandler extends kDBEventHandler {
 
 	/**
 	 * Allows to override standard permission mapping
 	 *
 	 * @return void
 	 * @access protected
 	 * @see kEventHandler::$permMapping
 	 */
 	protected function mapPermissions()
 	{
 		parent::mapPermissions();
 
 		$permissions = Array (
 			'OnMoreBrackets' => Array ('subitem' => 'add|edit'),
 			'OnInfinity' => Array ('subitem' => 'add|edit'),
 			'OnArrange' => Array ('subitem' => 'add|edit'),
 			'OnDeleteBrackets' => Array ('subitem' => 'add|edit'),
 		);
 
 		$this->permMapping = array_merge($this->permMapping, $permissions);
 	}
 
 	/**
 	 * Define alternative event processing method names
 	 *
 	 * @return void
 	 * @see kEventHandler::$eventMethods
 	 * @access protected
 	 */
 	protected function mapEvents()
 	{
 		parent::mapEvents();	// ensure auto-adding of approve/decline and so on events
 
 		$brackets_events = Array(
 			'OnMoreBrackets' => 'PricingBracketsAction',
 			'OnArrange' => 'PricingBracketsAction',
 			'OnInfinity' => 'PricingBracketsAction',
 			'OnDeleteBrackets' => 'PricingBracketsAction',
 		);
 
 		$this->eventMethods = array_merge($this->eventMethods, $brackets_events);
 	}
 
 	function PricingBracketsAction($event)
 	{
 		$event->redirect=false;
 		$temp = $this->Application->GetVar($event->getPrefixSpecial(true));
 
 //		$object = $event->getObject();
 //		$formatter = $this->Application->recallObject('kFormatter');
 //		$temp = $formatter->TypeCastArray($temp, $object);
 
 		//uasort($temp, 'pr_bracket_comp');
 		$bracket = $this->Application->recallObject($event->getPrefixSpecial());
 		foreach($temp as $id => $record)
 		{
 			if( $record['MaxQty'] == '&#8734;' || $record['MaxQty'] == '∞')
 			{
 				$temp[$id]['MaxQty'] = -1;
 			}
 		}
 
 		$group_id = $this->Application->getVar('group_id');
 		if($group_id>0){
 			$where_group=' GroupId = '.$group_id.' ';
 		}
 		else {
 			$where_group= ' TRUE ';
 		}
 
 		switch ($event->Name)
 		{
 			case 'OnMoreBrackets':
 
 				$new_id = (int)$this->Conn->GetOne('SELECT MIN('.$bracket->IDField.') FROM '.$bracket->TableName);
 				if($new_id > 0) $new_id = 0;
 				do
 				{
 					$new_id--;
 				} while
 				($this->check_array($this->Application->GetVar($event->getPrefixSpecial(true)), 'PriceId', $new_id));
 
 
 				$last_max_qty = $this->Conn->GetOne('SELECT MAX(MaxQty) FROM '.$bracket->TableName.' WHERE '.$where_group);
 				$min_qty = $this->Conn->GetOne('SELECT MIN(MaxQty) FROM '.$bracket->TableName.' WHERE '.$where_group);
 
 				if ($min_qty==-1) $last_max_qty = -1;
 				if (!$last_max_qty) $last_max_qty=1;
 
 				for($i = $new_id; $i > $new_id - 5; $i--)
 				{
 					$temp[$i]['PriceId'] = $i;
 					$temp[$i]['MinQty'] = ($i == $new_id-4 && $last_max_qty != -1) ? $last_max_qty : '';
 					$temp[$i]['MaxQty'] = ($i == $new_id-4 && $last_max_qty != -1) ? -1 : '';
 					$temp[$i]['Price'] = '';
 					$temp[$i]['Cost'] = '';
 					$temp[$i]['Points'] = '';
 					$temp[$i]['Negotiated'] = '0';
 					$temp[$i]['IsPrimary'] = '0';
 					$temp[$i]['GroupId'] = $group_id;
 				}
 
 				$this->Application->SetVar($event->getPrefixSpecial(true), $temp);
 				$event->CallSubEvent('OnPreSaveBrackets');
 				break;
 
 			case 'OnArrange':
 				$temp=$this->OnArrangeBrackets($event, $temp, $bracket);
 				$this->Application->SetVar($event->getPrefixSpecial(true), $temp);
 				$event->CallSubEvent('OnPreSaveBrackets');
 				break;
 
 			case 'OnInfinity':
 				$temp=$this->OnArrangeBrackets($event, $temp, $bracket);
 				$this->Application->SetVar($event->getPrefixSpecial(true), $temp);
 				$event->CallSubEvent('OnPreSaveBrackets');
 
 				$infinite_exists = $this->Conn->GetOne('SELECT count(*) FROM '.$bracket->TableName.' WHERE MaxQty=-1 '.' AND '.$where_group);
 
 				if($infinite_exists==0){
 					reset($temp);
 					$last_bracket=end($temp);
 					$new_id = (int)$this->Conn->GetOne('SELECT MIN('.$bracket->IDField.') FROM '.$bracket->TableName);
 
 					$brackets_exist = (int)$this->Conn->GetOne('SELECT COUNT(*) FROM '.$bracket->TableName.' WHERE '.$where_group);
 
 					if($new_id > 0) $new_id = 0;
 					do
 					{
 						$new_id--;
 					} while
 					($this->check_array($this->Application->GetVar($event->getPrefixSpecial(true)), 'PriceId', $new_id));
 
 
 					$infinite_bracket['PriceId'] = $new_id;
 					$infinite_bracket['MinQty'] = ($brackets_exist>0)?$last_bracket['MaxQty']:1;
 					$infinite_bracket['MaxQty'] = '-1';
 					$infinite_bracket['Price'] = '';
 					$infinite_bracket['Cost'] = '';
 					$infinite_bracket['Points'] = '';
 					$infinite_bracket['Negotiated'] = '0';
 					$infinite_bracket['IsPrimary'] = '0';
 					$infinite_bracket['GroupId'] = $group_id;
 					$temp[$new_id]=$infinite_bracket;
 					reset($temp);
 				}
 
 				$this->Application->SetVar($event->getPrefixSpecial(true), $temp);
 				$event->CallSubEvent('OnPreSaveBrackets');
 				break;
 
 			case 'OnDeleteBrackets':
 				if ($group_id) {
 					$temp = ''; // delete all pricings from "pr_tang" var
 
 					$sql = 'DELETE FROM ' . $bracket->TableName . '
 							WHERE ProductId = ' . $this->Application->GetVar('p_id') . ' AND GroupId = ' . $group_id;
 					$this->Conn->Query($sql);
 				}
 				break;
 
 			default:
 		}
 
 		$this->Application->SetVar($event->getPrefixSpecial(true), $temp); // store pr_tang var
 	}
 
 	function OnPreSaveBrackets($event)
 	{
 		if( $this->Application->GetVar('pr_tang') ) {
 
 			$object = $event->getObject();
 			/* @var $object kDBItem */
 
 			$product_id = $this->Application->GetVar('p_id');
 			$group_id = $this->Application->getVar('group_id');
 
 			$sql = 'SELECT PriceId
 					FROM ' . $object->TableName . '
 					WHERE ProductId = ' . $product_id . ' ' . ($group_id? 'AND GroupId = ' . $group_id : '');
 			$stored_ids = $this->Conn->GetCol($sql);
 
 			$items_info = $this->Application->GetVar( $event->getPrefixSpecial(true) ); // get pr_tang var
 			uasort($items_info, 'pr_bracket_comp');
 
 			foreach ($items_info as $item_id => $field_values) {
 
 				if (in_array($item_id, $stored_ids)) { //if it's already exist
 					$object->Load($item_id);
 					$object->SetFieldsFromHash($field_values, $this->getRequestProtectedFields($field_values));
 
 					if (!$object->Validate()) {
 						unset($stored_ids[array_search($item_id, $stored_ids)]);
 						$event->redirect = false;
 						continue;
 					}
 					if( $object->Update($item_id) ) {
 						$event->status=kEvent::erSUCCESS;
 					}
 					else {
 						$event->status=kEvent::erFAIL;
 						$event->redirect=false;
 						break;
 					}
 					unset($stored_ids[array_search($item_id, $stored_ids)]);
 				}
 				else {
 					$object->Clear();
 					$object->SetFieldsFromHash($field_values, $this->getRequestProtectedFields($field_values));
 					$object->SetDBField('ProductId', $product_id);
 
 					if( $object->Create() ) {
 						$event->status=kEvent::erSUCCESS;
 					}
 				}
 			}
 
 			// delete
 			foreach ($stored_ids as $stored_id) {
 				$this->Conn->Query('DELETE FROM ' . $object->TableName . ' WHERE PriceId = ' . $stored_id);
 			}
 
 		}
 	}
 
 	/**
 	 * Apply custom processing to item
 	 *
 	 * @param kEvent $event
 	 * @param string $type
 	 * @return void
 	 * @access protected
 	 */
 	protected function customProcessing(kEvent $event, $type)
 	{
 		$bracket = $event->getObject();
 		/* @var $bracket kDBItem */
 
 		switch ($type) {
 			case 'before':
 				$bracket->SetDBField('ProductId', $this->Application->GetVar('p_id'));
 
 				if ( $bracket->GetDBField('MaxQty') == '&#8734;' || $bracket->GetDBField('MaxQty') == '∞' ) {
 					$bracket->SetDBField('MaxQty', -1);
 				}
 				break;
 		}
 	}
 
 	function OnArrangeBrackets($event, &$temp, &$bracket)
 	{
 		$temp_orig = $temp;
 		reset($temp);
 		if (is_array($temp))
 		{
 			// array to store max values (2nd column)
 			$end_values = Array();
 
 			// get minimal value of Min
 			$first_elem=current($temp);
 			$start = $first_elem['MinQty'];
 			if (!$start){
 				$start = 1;
 			}
 			foreach($temp as $id => $record)
 			{
 
 				/*
 				This 3-ifs logic fixes collision with invalid input values having
 				1 pricing record.
 				The logic is:
 				1) If we got Max less than Min, we set Min to 1 that gives us
 				integrity.
 				2) If we got equal values for Min and Max, we set range 1..Max like
 				in previous. But if Min was 1 and Max was 1 we set full range 1..infinity
 				3) If we got Max = 0 we just set it tom infinity because we can't
 				guess what user meant
 				*/
 
 				if (sizeof($temp) == 1 && $record['MinQty'] > ($record['MaxQty'] == -1 ? $record['MinQty']+1 : $record['MaxQty']) ){
 					$record['MinQty'] = 1;
 					$temp[$id]['MinQty'] = 1;
 					$start = 1;
 				}
 
 				if (sizeof($temp) == 1 && $record['MinQty'] == $record['MaxQty']){
 					if ($record['MaxQty'] == 1){
 						$record['MaxQty'] = -1;
 						$temp[$id]['MaxQty'] = -1;
 					}
 					else {
 						$record['MinQty'] = 1;
 						$temp[$id]['MinQty'] = 1;
 					}
 				}
 
 				if (sizeof($temp) == 1 && $record['MaxQty'] == 0){
 					$record['MaxQty'] = -1;
 					$temp[$id]['MaxQty'] = -1;
 				}
 
 				if(
 				// MAX is less than start
 				($record['MaxQty'] <= $start && $record['MaxQty'] != -1) ||
 				// Max is empty
 				!$record['MaxQty'] ||
 				// Max already defined in $end_values
 				(array_search($record['MaxQty'], $end_values) !== false)
 				) {	// then delete from brackets list
 					unset($temp[$id]);
 				}
 				else {	// this is when ok - add to end_values list
 					$end_values[] = $record['MaxQty'];
 				}
 			}
 
 			// sort brackets by 2nd column (Max values)
 			uasort($temp, 'pr_bracket_comp');
 			reset($temp);
 			$first_item=each($temp);
 			$first_item_key=$first_item['key'];
 
 			$group_id = $this->Application->getVar('group_id');
 
 
 			$default_group = $this->Application->ConfigValue('User_LoggedInGroup');
 			if($group_id>0){
 				$where_group=' AND GroupId = '.$group_id.' ';
 			}
 
 			$ids = $this->Conn->GetCol('SELECT PriceId FROM '.$bracket->TableName.' WHERE ProductId='.$this->Application->GetVar('p_id').' '.$where_group);
 			if(is_array($ids)) {
 				usort($ids, 'pr_bracket_id_sort');
 			}
 			$min_id = min( min($ids) - 1, -1 );
 
 
 			foreach($temp as $key => $record)
 			{
 				$temp[$key]['MinQty']=$start;
 				$temp[$key]['IsPrimary']=0;
 				$temp[$key]['GroupId']=$group_id;
 				$start=$temp[$key]['MaxQty'];
 
 			}
 			if ($temp[$first_item_key]['GroupId'] == $default_group) {
 				$temp[$first_item_key]['IsPrimary']=1;
 			}
 
 		}
 		return $temp;
 	}
 
 	/**
 	 * Set's price as primary for product
 	 *
 	 * @param kEvent $event
 	 */
 	function OnSetPrimary($event)
 	{
 		$object = $event->getObject( Array('skip_autoload' => true) );
 		$this->StoreSelectedIDs($event);
 		$ids=$this->getSelectedIDs($event);
 		if($ids)
 		{
 			$id = array_shift($ids);
 			$table_info = $object->getLinkedInfo();
 
 			$this->Conn->Query('UPDATE '.$object->TableName.' SET IsPrimary = 0 WHERE '.$table_info['ForeignKey'].' = '.$table_info['ParentId']);
 			$this->Conn->Query('UPDATE '.$object->TableName.' SET IsPrimary = 1 WHERE ('.$table_info['ForeignKey'].' = '.$table_info['ParentId'].') AND (PriceId = '.$id.')');
 		}
 		$event->SetRedirectParam('opener', 's');
 	}
 
 	/**
 	 * Resets primary mark for other prices of given product, when current pricing is primary
 	 *
 	 * @param kEvent $event
 	 * @return void
 	 * @access protected
 	 */
 	protected function OnBeforeItemUpdate(kEvent $event)
 	{
 		parent::OnBeforeItemUpdate($event);
 
 		$object = $event->getObject();
 		/* @var $object kDBItem */
 
 		if ( $object->GetDBField('IsPrimary') == 1 ) {
 			// make all prices non primary, when this one is
 			$sql = 'UPDATE ' . $object->TableName . '
 					SET IsPrimary = 0
 					WHERE (ProductId = ' . $object->GetDBField('ProductId') . ') AND (' . $object->IDField . ' <> ' . $object->GetID() . ')';
 			$this->Conn->Query($sql);
 		}
 	}
 
 	/**
 	 * Occurs before creating item
 	 *
 	 * @param kEvent $event
 	 * @return void
 	 * @access protected
 	 */
 	protected function OnBeforeItemCreate(kEvent $event)
 	{
 		parent::OnBeforeItemCreate($event);
 
 		$object = $event->getObject();
 		/* @var $object kDBItem */
 
 		$table_info = $object->getLinkedInfo($event->Special);
 
 		$table_info['ParentId'] = ($table_info['ParentId'] ? $table_info['ParentId'] : 0);
 
 		if ( $object->GetDBField('IsPrimary') == 1 ) {
 			$sql = 'UPDATE ' . $object->TableName . '
 					SET IsPrimary = 0
 					WHERE ' . $table_info['ForeignKey'] . ' = ' . $table_info['ParentId'];
 			$this->Conn->Query($sql);
 		}
 		else {
 			$sql = 'SELECT COUNT(*)
 					FROM ' . $object->TableName . '
 					WHERE ' . $table_info['ForeignKey'] . ' = ' . $table_info['ParentId'];
 			$prices_qty = $this->Conn->GetOne($sql);
 
 			if ( $prices_qty == 0 ) {
 				$object->SetDBField('IsPrimary', 1);
 			}
 		}
 	}
 
 	/**
 	 * Apply any custom changes to list's sql query
 	 *
 	 * @param kEvent $event
 	 * @return void
 	 * @access protected
 	 * @see kDBEventHandler::OnListBuild()
 	 */
 	protected function SetCustomQuery(kEvent $event)
 	{
 		$object = $event->getObject();
 		/* @var $object kDBList */
 
 		if ( $this->Application->isAdminUser ) {
 			return;
 		}
 
 		if ( $this->Application->ConfigValue('Comm_PriceBracketCalculation') == 1 ) {
 			$sql = 'SELECT PrimaryGroupId
 					FROM ' . TABLE_PREFIX . 'Users
 					WHERE PortalUserId = ' . $this->Application->GetVar('u_id');
 			$pricing_group = $this->Conn->GetOne($sql);
 
 			if ( $pricing_group ) {
 				$sql = 'SELECT COUNT(*)
 						FROM ' . TABLE_PREFIX . 'ProductsPricing
 						WHERE ProductId = ' . $this->Application->GetVar('p_id') . ' AND GroupId = ' . $pricing_group . ' AND Price IS NOT NULL';
 				$pricing_for_group_exists = $this->Conn->GetOne($sql);
 			}
 
 			if ( !$pricing_group || !$pricing_for_group_exists ) {
 				$pricing_group = $this->Application->ConfigValue('User_LoggedInGroup');
 			}
 		}
 		else {
 			$user_groups = $this->Application->RecallVar('UserGroups');
 
 			//$cheapest_group = $this->Conn->GetOne('SELECT GroupId FROM '.$object->TableName.' WHERE ProductId='.$this->Application->GetVar('p_id').' AND Price IS NOT NULL AND GroupId IN ('.$user_groups.') AND MinQty = 1 GROUP BY GroupId ORDER BY Price ASC');
 
 			$sql = 'SELECT PriceId, Price, GroupId
 					FROM ' . $object->TableName . '
 					WHERE ProductId = ' . $this->Application->GetVar('p_id') . ' AND Price IS NOT NULL AND GroupId IN (' . $user_groups . ')
 					ORDER BY GroupId ASC, MinQty ASC';
 			$effective_brackets = $this->Conn->Query($sql, 'PriceId');
 
 			$group_prices = array ();
 			$min_price = -1;
 			$cheapest_group = 0;
 
 			foreach ($effective_brackets as $bracket) {
 				if ( !isset($group_prices[$bracket['GroupId']]) ) {
 					$group_prices[$bracket['GroupId']] = $bracket['Price'];
 					if ( $bracket['Price'] < $min_price || $min_price == -1 ) {
 						$min_price = $bracket['Price'];
 						$cheapest_group = $bracket['GroupId'];
 					}
 				}
 			}
 
 			if ( !$cheapest_group ) {
 				$cheapest_group = $this->Application->ConfigValue('User_LoggedInGroup');
 			}
 
 			$pricing_group = $cheapest_group;
 		}
 
 		$object->addFilter('price_user_group', $object->TableName . '.GroupId=' . $pricing_group);
 	}
 
 }
\ No newline at end of file
Index: branches/5.3.x/units/brackets/brackets_tag_processor.php
===================================================================
--- branches/5.3.x/units/brackets/brackets_tag_processor.php	(revision 15670)
+++ branches/5.3.x/units/brackets/brackets_tag_processor.php	(revision 15671)
@@ -1,199 +1,202 @@
 <?php
 /**
 * @version	$Id$
 * @package	In-Commerce
 * @copyright	Copyright (C) 1997 - 2009 Intechnic. All rights reserved.
 * @license	Commercial License
 * This software is protected by copyright law and international treaties.
 * Unauthorized reproduction or unlicensed usage of the code of this program,
 * or any portion of it may result in severe civil and criminal penalties,
 * and will be prosecuted to the maximum extent possible under the law
 * See http://www.in-portal.org/commercial-license for copyright notices and details.
 */
 
 defined('FULL_PATH') or die('restricted access!');
 
 class BracketsTagProcessor extends kDBTagProcessor {
 
 	function Field($params)
 	{
 		$value = parent::Field($params);
+		$field = $this->SelectParam($params, 'name,field');
 
-		if ( ($params['field'] == 'Start' || $params['name'] == 'End') && $value == -1) {
+		if ( ($field == 'Start' || $field == 'End') && $value == -1 ) {
 			$value = '&#8734;';
 		}
 
 		return $value;
 	}
 
 	function ShowBracketsForm($params)
 	{
 		$shipping_object = $this->Application->recallObject('s');
+		/* @var $shipping_object kDBItem */
+
 		$default_start = ($shipping_object->GetDBField('Type') == 1) ? 0 : 1;
 
 		$brackets_helper = $this->Application->recallObject('BracketsHelper');
 		/* @var $brackets_helper kBracketsHelper */
 
 		$brackets_helper->InitHelper('Start', 'End', Array(), $default_start );
 
 		$br_object = $this->Application->recallObject( $this->getPrefixSpecial() );
 
 		$event = new kEvent($this->getPrefixSpecial(true) . ':OnArrange');
 		$br_data = $brackets_helper->getBrackets($event);
 		$linked_info = $br_object->getLinkedInfo($this->Special);
 
 		if (!$br_data) {
 			$sql = 	'SELECT * FROM '.$br_object->TableName.' WHERE '.$linked_info['ForeignKey'].' = '.$linked_info['ParentId'];
 			$brackets = $this->Conn->Query($sql, $br_object->IDField);
 
 			usort($brackets, Array(&$brackets_helper, 'compareBrackets'));
 
 			$dummy = $this->Application->recallObject($this->Prefix.'.-dummy', null, array('skip_autoload' => true));
 			/* @var $dummy kDBItem */
 
 			// performs number formatting
 			foreach($brackets as $id => $values)
 			{
 				foreach($values as $value_key=>$value_val){
 					$dummy->SetDBField($value_key, $value_val);
 					$brackets[$id][$value_key] = $dummy->GetField($value_key);
 				}
 			}
 
 			$br_data = $brackets;
 			$brackets_helper->setBrackets($event, $brackets);
 		}
 		else {
 			usort($br_data, Array(&$brackets_helper, 'compareBrackets'));
 			$br_data = $brackets_helper->formatBrackets($br_data);
 		}
 
 		$ret = '';
 		if ( is_array($br_data) ) {
 			$block_params = $this->prepareTagParams($params);
 			$block_params['IdField'] = $br_object->IDField;
 			$block_params['name'] = $params['block'];
 			$first = true;
 
 			$main_object = $this->Application->recallObject($linked_info['ParentPrefix'].'.'.$this->Special);
 //			$plan_type = $main_object->GetDBField('PlanType');
 //			$limits_format = ($plan_type == 2) ? '%d' : $br_object->getFieldOption('Start', 'format');
 
 			// this is needed to find next id
 			$br_data_copy = $br_data;
 			foreach($br_data as $id => $values)
 			{
 
 				foreach($values as $value_key => $value_val)
 				{
 					$block_params[$value_key] = $value_val;
 				}
 				reset($values);
 
 				next($br_data_copy);
 				$next_bracket = current($br_data_copy);
 
 //				$values['Start'] = sprintf($limits_format, $values['Start']);
 //				$values['End'] = sprintf($limits_format, $values['End']);
 
 				$block_params['id']	= $values[$br_object->IDField];
 				$block_params['min'] = ($id == -1) ? ($values['Start'] ? $values['Start'] : 0) : $values['Start'];
 				$block_params['max'] = ($values['End'] == -1) ? '&#8734;' : $values['End'];
 				$block_params['next_min_id'] = $next_bracket[$br_object->IDField];
 
 				$lang_object = $this->Application->recallObject('lang.current');
 				if($lang_object->GetDBField('UnitSystem') == 2 && $main_object->GetDBField('Type') == 1)
 				{
 					if($block_params['min'] === '')
 					{
 						$block_params['min_a'] = '';
 						$block_params['min_b'] = '';
 					}
 					else
 					{
 						list($block_params['min_a'], $block_params['min_b']) = kUtil::Kg2Pounds($block_params['min']);
 					}
 
 					if($block_params['max'] == '&#8734;')
 					{
 						$block_params['max_a'] = '&#8734;';
 						$block_params['max_b'] = '';
 					}
 					else
 					{
 						list($block_params['max_a'], $block_params['max_b']) = kUtil::Kg2Pounds($block_params['max']);
 					}
 				}
 
 				if($first)
 				{
 					$block_params['first'] = 1;
 					$first = false;
 				}
 				else
 				{
 					$block_params['first'] = 0;
 				}
 				$ret .= $this->Application->ParseBlock($block_params, 1);
 			}
 		}
 		return $ret;
 	}
 
 
 	/*
 	function ShowBracketsForm($params)
 	{
 		$br_object = $this->Application->recallObject( $this->getPrefixSpecial() );
 
 		$br_data = $this->Application->GetVar('br');
 
 		if(!$br_data)
 		{
 			$sql = 	'SELECT * FROM '.$br_object->TableName.
 					' WHERE ShippingTypeID = '.$this->Application->GetVar('s_id');
 			$brackets = $this->Conn->Query($sql, 'BracketId');
 			usort($brackets, 'bracket_comp');
 
 			$br_data = array_reverse($brackets);
 			$this->Application->SetVar('br', $br_data);
 		}
 		else
 		{
 			$br_data = array_reverse($br_data);
 		}
 
 		$ret = '';
 		if( is_array($br_data) )
 		{
 			$i = -count($br_data);
 			ksort($br_data);
 			foreach($br_data as $record)
 			{
 				$temp_sorted[$i] = $record;
 				$i++;
 			}
 			$br_data = array_reverse($temp_sorted, true);
 
 			$block_params['name'] = $params['block'];
 			$first = true;
 			foreach($br_data as $id => $values)
 			{
 				$block_params['id']	= $id;
 				$block_params['start']	= ($id == -1) ? ($values['Start'] ? $values['Start'] : 0) : $values['Start'];
 				$block_params['end'] = ($values['End'] == -1) ? '&infin;' : $values['End'];
 				if ($first)
 				{
 					$block_params['first'] = 1;
 					$first = false;
 				}
 				else
 				{
 					$block_params['first'] = 0;
 				}
 				$ret .= $this->Application->ParseBlock($block_params);
 			}
 		}
 		return $ret;
 	}*/
 }
\ No newline at end of file
Index: branches/5.3.x/units/affiliate_payments/affiliate_payments_config.php
===================================================================
--- branches/5.3.x/units/affiliate_payments/affiliate_payments_config.php	(revision 15670)
+++ branches/5.3.x/units/affiliate_payments/affiliate_payments_config.php	(revision 15671)
@@ -1,151 +1,151 @@
 <?php
 /**
 * @version	$Id$
 * @package	In-Commerce
 * @copyright	Copyright (C) 1997 - 2009 Intechnic. All rights reserved.
 * @license	Commercial License
 * This software is protected by copyright law and international treaties.
 * Unauthorized reproduction or unlicensed usage of the code of this program,
 * or any portion of it may result in severe civil and criminal penalties,
 * and will be prosecuted to the maximum extent possible under the law
 * See http://www.in-portal.org/commercial-license for copyright notices and details.
 */
 
 defined('FULL_PATH') or die('restricted access!');
 
 $config = Array (
 	'Prefix' => 'apayments',
 	'ItemClass' => Array ('class' => 'kDBItem', 'file' => '', 'build_event' => 'OnItemBuild'),
 	'ListClass' => Array ('class' => 'kDBList', 'file' => '', 'build_event' => 'OnListBuild'),
 	'EventHandlerClass' => Array ('class' => 'AffiliatePaymentsEventHandler', 'file' => 'affiliate_payments_event_handler.php', 'build_event' => 'OnBuild'),
 	'TagProcessorClass' => Array ('class' => 'AffiliatePaymentsTagProcessor', 'file' => 'affiliate_payments_tag_processor.php', 'build_event' => 'OnBuild'),
 	'AutoLoad' => true,
 
 	'AggregateTags' => Array (
 		Array (
 			'AggregateTo' => 'ord',
 			'AggregatedTagName' => 'InitPaymentsList',
 			'LocalTagName' => 'InitList',
 		),
 		Array (
 			'AggregateTo' => 'ord',
 			'AggregatedTagName' => 'ListPayments',
 			'LocalTagName' => 'ListPayments',
 		),
 		Array (
 			'AggregateTo' => 'ord',
 			'AggregatedTagName' => 'PaymentsPaginationBar',
 			'LocalTagName' => 'PaginationBar',
 		),
 		Array (
 			'AggregateTo' => 'ord',
 			'AggregatedTagName' => 'PaymentsCount',
 			'LocalTagName' => 'TotalRecords',
 		),
 	),
 
 	'QueryString' => Array (
 		1 => 'id',
 		2 => 'Page',
 		3 => 'PerPage',
 		4 => 'event',
 	),
 
 	'IDField' => 'AffiliatePaymentId',
 
 	'TitlePresets' => Array (
 		'payments_log' => Array (
 			'prefixes' => Array ('apayments.log_List'), 'format' => "!la_title_AffiliatePayments!",
 		),
 	),
 
 	'Sections' => Array (
 		'in-commerce:paymentlog' => Array (
 			'parent' => 'in-commerce',
 			'icon' => 'transactions',
 			'label' => 'la_tab_PaymentLog',
 			'url' => Array ('t' => 'in-commerce/payments/payments_list', 'pass' => 'm'),
 			'permissions' => Array ('view'),
 			'priority' => 6,
 			'type' => stTREE,
 		),
 	),
 
 	'TableName' => TABLE_PREFIX.'AffiliatePayments',
 
 	'ListSQLs' => Array (
 		'' => '	SELECT %1$s.* %2$s
 				FROM %1$s
 				LEFT JOIN '.TABLE_PREFIX.'Affiliates af ON %1$s.AffiliateId = af.AffiliateId
 				LEFT JOIN '.TABLE_PREFIX.'Users au ON af.PortalUserId = au.PortalUserId'
 	),
 
 	'CalculatedFields' => Array (
 		'' => Array (
 			'PortalUserId' => 'af.PortalUserId',
 		),
 		'log' => Array (
-			'Username' => 'au.Username',
+			'Username' => 'IF(au.Username = "", au.Email, au.Username)',
 			'PortalUserId' => 'af.PortalUserId',
 		),
 	),
 
 	'ForeignKey' => 'AffiliateId',
 	'ParentTableKey' => 'AffiliateId',
 	'ParentPrefix' => 'affil',
 	'AutoDelete' => true,
 	'AutoClone' => true,
 
 	'ListSortings' => Array (
 		'' => Array (
 			'Sorting' => Array ('PaymentDate' => 'desc'),
 		)
 	),
 
 	'Fields' => Array (
 		'AffiliatePaymentId' => Array ('type' => 'int', 'not_null' => 1, 'default' => 0),
-		'AffiliateId' => Array ('type' => 'int', 'formatter' => 'kLEFTFormatter', 'error_msgs' => Array ('invalid_option' => '!la_error_UserNotFound!'), 'options' => Array (0 => 'lu_None'), 'left_sql' => 'SELECT %s FROM '.TABLE_PREFIX.'Affiliates af LEFT JOIN '.TABLE_PREFIX.'Users pu ON pu.PortalUserId = af.PortalUserId WHERE `%s` = \'%s\'', 'left_key_field' => 'AffiliateId', 'left_title_field' => 'Username', 'not_null'=>1,'default'=>0),
+		'AffiliateId' => Array('type' => 'int','formatter' => 'kLEFTFormatter', 'error_msgs' => Array ('invalid_option' => '!la_error_UserNotFound!'), 'options' => Array (0 => 'lu_None'), 'left_sql' => 'SELECT %s FROM ' . TABLE_PREFIX . 'Affiliates af LEFT JOIN ' . TABLE_PREFIX . 'Users u ON u.PortalUserId = af.PortalUserId WHERE %s', 'left_key_field' => 'af.AffiliateId', 'left_title_field' => 'IF(u.Email = "", u.Username, u.Email)', 'not_null' => 1, 'default' => 0),
 		'PaymentDate' => Array ('type' => 'int', 'formatter' => 'kDateFormatter', 'default' => '#NOW#'),
 		'Amount' => Array ('type' => 'double', 'formatter' => 'kFormatter', 'format' => '%.02f', 'not_null' => '1', 'required'=>1, 'default' => '0.00'),
 		'Comment' => Array ('type' => 'string', 'formatter' => 'kFormatter', 'using_fck' => 1, 'default' => NULL),
 		'PaymentReference' => Array ('type' => 'string', 'not_null' => '1', 'default' => ''),
 		'PaymentTypeId' => Array ('type' => 'int', 'formatter' => 'kOptionsFormatter', 'options_sql' => 'SELECT Name, PaymentTypeId FROM '.TABLE_PREFIX.'AffiliatePaymentTypes WHERE Status = 1 ORDER BY IsPrimary DESC, Priority DESC, Name ASC', 'option_key_field' => 'PaymentTypeId', 'option_title_field' => 'Name', 'not_null' => 1, 'default' => 0),
 	),
 
 	'VirtualFields' => Array (
 		'Username' => Array ('type' => 'string', 'default' => ''),
 		'PortalUserId' => Array ('type' => 'int', 'default' => 0),
 	),
 
 	'Grids' => Array (
 		'Default' => Array (
 			'Icons' => Array (
 				'default' => 'icon16_item.png',
 				'module' => 'core',
 			),
 			'Fields' => Array (
 				'AffiliatePaymentId'=> Array ( 'title' => 'column:la_fld_Id', 'data_block' => 'grid_checkbox_td', 'filter_block' => 'grid_range_filter', 'width' => 60, ),
 				'PaymentDate' => Array ( 'filter_block' => 'grid_date_range_filter', 'width' => 140, ),
 				'Amount' => Array ( 'filter_block' => 'grid_range_filter'),
 				'Comment' => Array ( 'filter_block' => 'grid_like_filter', 'first_chars' => 50),
 				'PaymentTypeId' => Array ( 'title' => 'column:la_fld_PaymentType', 'filter_block' => 'grid_options_filter'),
 				'PaymentReference' => Array ( 'filter_block' => 'grid_like_filter', 'first_chars' => 50),
 			),
 		),
 		'Log' => Array (
 			'Icons' => Array (
 				'default' => 'icon16_item.png',
 				'module' => 'core',
 			),
 			'Fields' => Array (
 				'AffiliatePaymentId'=> Array ( 'title' => 'column:la_fld_Id', 'data_block' => 'grid_checkbox_td', 'filter_block' => 'grid_range_filter', 'width' => 60, ),
 				'Username' => Array ( 'data_block' => 'grid_userlink_td', 'filter_block' => 'grid_like_filter'),
 				'PaymentDate' => Array ( 'filter_block' => 'grid_date_range_filter', 'width' => 140, ),
 				'Amount' => Array ( 'data_block' => 'grid_currency_td', 'filter_block' => 'grid_range_filter'),
 				'Comment' => Array ( 'filter_block' => 'grid_like_filter', 'first_chars' => 50),
 				'PaymentTypeId' => Array ( 'title' => 'column:la_fld_PaymentType', 'filter_block' => 'grid_options_filter'),
 				'PaymentReference' => Array ( 'filter_block' => 'grid_like_filter', 'first_chars' => 50),
 			),
 		),
 	),
 );
\ No newline at end of file
Index: branches/5.3.x/units/destinations/dst_event_handler.php
===================================================================
--- branches/5.3.x/units/destinations/dst_event_handler.php	(revision 15670)
+++ branches/5.3.x/units/destinations/dst_event_handler.php	(revision 15671)
@@ -1,132 +1,134 @@
 <?php
 /**
 * @version	$Id$
 * @package	In-Commerce
 * @copyright	Copyright (C) 1997 - 2009 Intechnic. All rights reserved.
 * @license	Commercial License
 * This software is protected by copyright law and international treaties.
 * Unauthorized reproduction or unlicensed usage of the code of this program,
 * or any portion of it may result in severe civil and criminal penalties,
 * and will be prosecuted to the maximum extent possible under the law
 * See http://www.in-portal.org/commercial-license for copyright notices and details.
 */
 
 defined('FULL_PATH') or die('restricted access!');
 
 class DstEventHandler extends kDBEventHandler {
 
 	/**
 	 * Creates item from submit data
 	 *
 	 * @param kEvent $event
 	 * @return void
 	 * @access protected
 	 */
 	protected function OnCreate(kEvent $event)
 	{
 		$object = $event->getObject(Array ('skip_autoload' => true));
 		/* @var $object kDBItem */
 
 		// creates multiple db records from single request (OnCreate event only creates 1 record)
 		$items_info = $this->Application->GetVar($event->getPrefixSpecial(true));
 
 		if ( !$items_info ) {
 			return;
 		}
 
 		foreach ($items_info as $field_values) {
 			$object->SetFieldsFromHash($field_values, $this->getRequestProtectedFields($field_values));
 			$this->customProcessing($event, 'before');
 
 			if ( $object->Create() ) {
 				$this->customProcessing($event, 'after');
 				$event->status = kEvent::erSUCCESS;
 			}
 			else {
 				$event->status = kEvent::erFAIL;
 				$event->redirect = false;
 				$this->Application->SetVar($event->getPrefixSpecial() . '_SaveEvent', 'OnCreate');
 				$object->setID(0);
 			}
 		}
 	}
 
 	/**
 	 * Apply custom processing to item
 	 *
 	 * @param kEvent $event
 	 * @param string $type
 	 * @return void
 	 * @access protected
 	 */
 	protected function customProcessing(kEvent $event, $type)
 	{
 		if ( $type != 'before' ) {
 			return;
 		}
 
 		$object = $event->getObject();
 		/* @var $object kDBItem */
 
 		$events = $this->Application->GetVar('events');
 
 		if ( $events['z'] == 'OnUpdate' ) {
 			$object->SetDBField('ShippingZoneId', $this->Application->GetVar('z_id'));
 		}
 
 		$zone_object = $this->Application->recallObject('z');
 		/* @var $zone_object kDBItem */
 
 		if ( $zone_object->GetDBField('Type') == 3 ) {
 			$object->SetDBField('StdDestId', $this->Application->GetVar('ZIPCountry'));
 		}
 	}
 
 	 /**
 	 *
 	 *
 	 * @param kEvent $event
 	 */
 	function OnZoneUpdate($event) {
 
 		$object = $event->getObject();
 		/* @var $object kDBItem */
 
-		$zone_object = &$this->Application->recallObject('z');
+		$zone_object = $this->Application->recallObject('z');
+		/* @var $zone_object kDBItem */
+
 		$zone_id = (int)$zone_object->GetID();
 		$zone_type = $zone_object->GetDBField('Type');
 
 		$delete_zones_sql = 'DELETE FROM '.$object->TableName.' WHERE ShippingZoneId = '.$zone_id;
 		$this->Conn->Query($delete_zones_sql);
 
 		if ($zone_id != 0){
 			$delete_zones_sql = 'DELETE FROM '.$object->TableName.' WHERE ShippingZoneId = 0';
 			$this->Conn->Query($delete_zones_sql);
 		}
 
 		$selected_destinations = $this->Application->GetVar('selected_destinations');
 		$selected_destinations_array = explode(',', $selected_destinations);
 		$selected_destinations_array = array_unique($selected_destinations_array);
 		foreach ($selected_destinations_array as $key => $dest_id) {
 
 					if ($zone_object->GetDBField('Type') == 3){
 						list ($zone_dest_id, $dest_value) = explode('|', $dest_id);
 						$dest_id = $this->Application->GetVar('CountrySelector');
 					}
 					else {
 						$dest_value = '';
 					}
 
 					if ($dest_id > 0){
 						$object->SetDBField('ShippingZoneId', $zone_id);
 						$object->SetDBField('StdDestId', $dest_id);
 						$object->SetDBField('DestValue', $dest_value);
 						$object->Create();
 					}
 
 		}
 
 
 	}
 
 }
\ No newline at end of file
Index: branches/5.3.x/units/affiliate_payment_types/affiliate_payment_types_event_handler.php
===================================================================
--- branches/5.3.x/units/affiliate_payment_types/affiliate_payment_types_event_handler.php	(revision 15670)
+++ branches/5.3.x/units/affiliate_payment_types/affiliate_payment_types_event_handler.php	(revision 15671)
@@ -1,124 +1,123 @@
 <?php
 /**
 * @version	$Id$
 * @package	In-Commerce
 * @copyright	Copyright (C) 1997 - 2009 Intechnic. All rights reserved.
 * @license	Commercial License
 * This software is protected by copyright law and international treaties.
 * Unauthorized reproduction or unlicensed usage of the code of this program,
 * or any portion of it may result in severe civil and criminal penalties,
 * and will be prosecuted to the maximum extent possible under the law
 * See http://www.in-portal.org/commercial-license for copyright notices and details.
 */
 
 	defined('FULL_PATH') or die('restricted access!');
 
 	class AffiliatePaymentTypesEventHandler extends kDBEventHandler  {
 
 		/**
 		 * Lists only active affiliate payment types on Front-End
 		 *
 		 * @param kEvent $event
 		 * @return void
 		 * @access protected
 		 * @see kDBEventHandler::OnListBuild()
 		 */
 		protected function SetCustomQuery(kEvent $event)
 		{
 			parent::SetCustomQuery($event);
 
 			if ( !$this->Application->isAdmin ) {
 				$object = $event->getObject();
 				/* @var $object kDBList */
 
 				$object->addFilter('active', '%1$s.Status = ' . STATUS_ACTIVE);
 			}
 		}
 
 		/**
 		 * Enter description here...
 		 *
 		 * @param kEvent $event
 		 */
 		function OnSetPrimary($event)
 		{
 			$object = $event->getObject();
 			/* @var $object kDBItem */
 
 			$object->SetDBField('IsPrimary', 1);
 			$object->Update();
 		}
 
 
 		/**
 		 * Ensures, that user have only one "use as billing" / "use as shipping" address
 		 *
 		 * @param kEvent $event
 		 * @return void
 		 * @access protected
 		 */
 		protected function OnBeforeItemUpdate(kEvent $event)
 		{
 			parent::OnBeforeItemUpdate($event);
 
 			$this->itemChanged($event);
 		}
 
 		/**
 		 * Occurs before creating item
 		 *
 		 * @param kEvent $event
 		 * @return void
 		 * @access protected
 		 */
 		protected function OnBeforeItemCreate(kEvent $event)
 		{
 			parent::OnBeforeItemCreate($event);
 
 			$this->itemChanged($event);
 		}
 
 		/**
 		 * Occurs before item is changed
 		 *
 		 * @param kEvent $event
 		 */
 		function itemChanged($event)
 		{
 			$object = $event->getObject();
 			/* @var $object kDBItem */
 
 			if ( $object->GetDBField('IsPrimary') && $object->Validate() ) {
 				$sql = 'UPDATE ' . $this->Application->getUnitOption($event->Prefix, 'TableName') . '
 						SET IsPrimary = 0';
 				$this->Conn->Query($sql);
 
-				$status_field = array_shift( $this->Application->getUnitOption($event->Prefix, 'StatusField') );
-				$object->SetDBField($status_field, 1);
+				$object->SetDBField($object->getStatusField(), 1);
 			}
 		}
 
 		/**
 		 * Don't allow to delete primary affiliate payment type
 		 *
 		 * @param kEvent $event
 		 * @param string $type
 		 * @return void
 		 * @access protected
 		 */
 		protected function customProcessing(kEvent $event, $type)
 		{
 			if ( $event->Name == 'OnMassDelete' && $type == 'before' ) {
 				$ids = $event->getEventParam('ids');
 
 				$sql = 'SELECT ' . $this->Application->getUnitOption($event->Prefix, 'IDField') . '
 						FROM ' . $this->Application->getUnitOption($event->Prefix, 'TableName') . '
 						WHERE IsPrimary = 1';
 				$primary_id = $this->Conn->GetOne($sql);
 
 				$ids = array_diff($ids, Array ($primary_id));
 
 				$event->setEventParam('ids', $ids);
 			}
 		}
 	}
\ No newline at end of file
Index: branches/5.3.x/units/shipping_quote_engines/usps.php
===================================================================
--- branches/5.3.x/units/shipping_quote_engines/usps.php	(revision 15670)
+++ branches/5.3.x/units/shipping_quote_engines/usps.php	(revision 15671)
@@ -1,1339 +1,1339 @@
 <?php
 /**
 * @version	$Id$
 * @package	In-Commerce
 * @copyright	Copyright (C) 1997 - 2009 Intechnic. All rights reserved.
 * @license	Commercial License
 * This software is protected by copyright law and international treaties.
 * Unauthorized reproduction or unlicensed usage of the code of this program,
 * or any portion of it may result in severe civil and criminal penalties,
 * and will be prosecuted to the maximum extent possible under the law
 * See http://www.in-portal.org/commercial-license for copyright notices and details.
 */
 
 defined('FULL_PATH') or die('restricted access!');
 
 define('MODULE_SHIPPING_USPS_TEXT_TITLE', 'United States Postal Service');
 define('MODULE_SHIPPING_USPS_TEXT_DESCRIPTION', 'You will need to have registered an account with USPS. Click <a target="_blank" href="https://secure.shippingapis.com/registration/"><strong>HERE</strong></a> for registration details. USPS expects you to use pounds as weight measure for your products.');
 define('MODULE_SHIPPING_USPS_TEXT_ERROR', 'An error occured with the USPS shipping calculations.<br>If you prefer to use USPS as your shipping method, please contact the store owner.');
 define('MODULE_SHIPPING_USPS_TEXT_DAY', 'Day');
 define('MODULE_SHIPPING_USPS_TEXT_DAYS', 'Days');
 define('MODULE_SHIPPING_USPS_TEXT_WEEKS', 'Weeks');
 
 define('MODULE_SHIPPING_USPS_STATUS', 'True'); // Do you want to offer USPS shipping?
 define('MODULE_SHIPPING_USPS_SERVER', 'production'); // An account at USPS is needed to use the Production server // production  othervise value may be 'test'
 define('MODULE_SHIPPING_USPS_HANDLING', '0'); // Handling fee for this shipping method
 define('MODULE_SHIPPING_USPS_TAX_CLASS', '0'); // Use the following tax class on the shipping fee
 define('MODULE_SHIPPING_USPS_ZONE', '0'); // If a zone is selected, only enable this shipping method for that zone.
 define('MODULE_SHIPPING_USPS_SORT_ORDER', '0'); // Sort order of display.
 define('MODULE_SHIPPING_USPS_TYPES', 'PRIORITY, PARCEL'); //  EXPRESS, FIRST CLASS, BMP, MEDIA  'Select the domestic services to be offered:
 define('MODULE_SHIPPING_USPS_TYPES_INTL', 'EXPRESS MAIL INTERNATIONAL (EMS), EXPRESS MAIL INT, EXPRESS MAIL INT FLAT RATE ENV, PRIORITY MAIL INT, PRIORITY MAIL INT FLAT RATE ENV, PRIORITY MAILINT FLAT RATE BOX, FIRST-CLASS MAIL INT');//  'GLOBAL EXPRESS, GLOBAL EXPRESS NON-DOC RECT, GLOBAL EXPRESS NON-DOC NON-RECT,  Select the international services to be offered:
 define('MODULE_SHIPPING_USPS_OPTIONS', 'Display weight, Display transit time'); //
 
 //configuration values for insurance
 define('MODULE_SHIPPING_USPS_INS1', '1.65');// 'US/Canada insurance for totals $.01-$50.00
 define('MODULE_SHIPPING_USPS_INS2', '2.05');// 'US/Canada insurance for totals $50.01-$100
 define('MODULE_SHIPPING_USPS_INS3', '2.45');// 'US/Canada insurance for totals $100.01-$200
 define('MODULE_SHIPPING_USPS_INS4', '4.60');// 'US/Canada insurance for totals $200.01-$300
 define('MODULE_SHIPPING_USPS_INS5', '.90');// 'US/Canada insurance for every $100 over $300 (add)
 define('MODULE_SHIPPING_USPS_INS6', '2.40');//  'International insurance for totals $.01-$50.00
 define('MODULE_SHIPPING_USPS_INS7', '3.30');// 'International insurance for totals $50.01-$100
 define('MODULE_SHIPPING_USPS_INS8', '4.20');// 'International insurance for totals $100.01-$200
 define('MODULE_SHIPPING_USPS_INS9', '5.10');// 'International insurance for totals $200.01-$300
 define('MODULE_SHIPPING_USPS_INS10', '.90');// 'International insurance for every $100 over $300 (add)
 define('MODULE_SHIPPING_USPS_INSURE', 'True');// 'Insure packages shipped by USPS?
 define('MODULE_SHIPPING_USPS_INSURE_TAX', 'True');// 'Insure tax on packages shipped by USPS?
 
 class USPS extends ShippingQuoteEngine
 {
 	var $countries, $pounds, $ounces, $insurance_cost = 0, $shipping_origin_country, $store_first_name, $store_last_name, $company_name, $store_name, $store_address1, $store_address2, $store_city, $store_state, $store_zip5, $store_zip4, $store_phone, $usps_userid;
 	var $order = Array();
 	var $types = Array();
 	var $intl_types = Array();
 
 	/**
 	 * Path to a request log file
 	 *
 	 * @var string
 	 */
 	var $logFilePath = '';
 
 	/**
 	 * Creates USPS processing class
 	 *
 	 */
 	public function __construct()
 	{
 		parent::__construct();
 
 		$this->logFilePath = (defined('RESTRICTED') ? RESTRICTED : WRITEABLE . '/user_files') . '/usps.log';
 
         // EXPRESS, FIRST CLASS, PRIORITY, PARCEL, BMP, MEDIA
 		$this->types = Array(
 			'EXPRESS' => 'Express Mail',
 			'FIRST CLASS' => 'First Class Mail',
 			'PRIORITY' => 'Priority Mail',
 			'PARCEL' => 'Parcel Post',
 			'BPM' => 'Bound Printed Matter',
 			'MEDIA' => 'Media Mail'
 		);
 
 		$this->intl_types = Array(
 			// 'GLOBAL EXPRESS' => 'Global Express Guaranteed',
 			// 'GLOBAL EXPRESS NON-DOC RECT' => 'Global Express Guaranteed Non-Document Rectangular',
 			// 'GLOBAL EXPRESS NON-DOC NON-RECT' => 'Global Express Guaranteed Non-Document Non-Rectangular',
 			'EXPRESS MAIL INT' => 'Express Mail International (EMS)',
 			'EXPRESS MAIL INT FLAT RATE ENV' => 'Express Mail International (EMS) Flat Rate Envelope',
 			'PRIORITY MAIL INT' => 'Priority Mail International',
 			'PRIORITY MAIL INT FLAT RATE ENV' => 'Priority Mail International Flat Rate Envelope',
 			'PRIORITY MAIL INT FLAT RATE BOX' => 'Priority Mail International Flat Rate Box',
 			'FIRST-CLASS MAIL INT' => 'First-Class Mail International'
 		);
 
 		// get 2-symbol country code
 		$country = $this->Application->ConfigValue('Comm_Shipping_Country');
 
 		if ($country != '') {
 			$this->shipping_origin_country = $this->GetUSPSCountry($country, '');
 		}
 
 		$contact_name = trim($this->_prepare_xml_param($this->Application->ConfigValue('Comm_Contacts_Name')));
 		$split_pos = strpos($contact_name, ' ');
 		if ($split_pos === false) {
 			$this->store_first_name = $contact_name;
 			$this->store_last_name = '';
 		} else {
 			$this->store_first_name = substr($contact_name, 0, $split_pos);
 			$this->store_last_name = trim(substr($contact_name, $split_pos));
 		}
 		$this->company_name = $this->_prepare_xml_param($this->Application->ConfigValue('Comm_CompanyName'));
 		$this->store_name = $this->_prepare_xml_param($this->Application->ConfigValue('Comm_StoreName'));
 		$this->store_address1 = $this->_prepare_xml_param($this->Application->ConfigValue('Comm_Shipping_AddressLine1'));
 		$this->store_address2 = $this->_prepare_xml_param($this->Application->ConfigValue('Comm_Shipping_AddressLine2'));
 
 		if ($this->store_address2 == '') {
 			$this->store_address2 = $this->store_address1;
 			$this->store_address1 = '';
 		}
 
 		$this->store_city = $this->_prepare_xml_param($this->Application->ConfigValue('Comm_Shipping_City'));
 		$this->store_state = $this->_prepare_xml_param($this->Application->ConfigValue('Comm_Shipping_State'));
 		$zip = $this->_prepare_xml_param($this->Application->ConfigValue('Comm_Shipping_ZIP'));
 		$this->store_zip5 = substr($zip, 0, 5);
 		$this->store_zip4 = trim(substr($zip, 6), '-');
 		$this->store_phone = $this->_prepare_xml_param($this->Application->ConfigValue('Comm_Contacts_Phone'));
 
 		// get username and password fron config.
 		$a_params = $this->LoadParams();
 		$this->usps_userid = $a_params['AccountLogin'];
 
 		// Note by Erik: DO NOT CHANGE THIS ARRAY. It's values are sent to USPS service and any changes may impact class main functionality.
 		$this->countries = array(
 			'AF' => 'Afghanistan',
             'AL' => 'Albania',
             'DZ' => 'Algeria',
             'AD' => 'Andorra',
             'AO' => 'Angola',
             'AI' => 'Anguilla',
             'AG' => 'Antigua and Barbuda',
             'AR' => 'Argentina',
             'AM' => 'Armenia',
             'AW' => 'Aruba',
             'AU' => 'Australia',
             'AT' => 'Austria',
             'AZ' => 'Azerbaijan',
             'BS' => 'Bahamas',
         	'BH' => 'Bahrain',
             'BD' => 'Bangladesh',
             'BB' => 'Barbados',
             'BY' => 'Belarus',
             'BE' => 'Belgium',
             'BZ' => 'Belize',
             'BJ' => 'Benin',
             'BM' => 'Bermuda',
             'BT' => 'Bhutan',
             'BO' => 'Bolivia',
             'BA' => 'Bosnia-Herzegovina',
             'BW' => 'Botswana',
             'BR' => 'Brazil',
             'VG' => 'British Virgin Islands',
             'BN' => 'Brunei Darussalam',
             'BG' => 'Bulgaria',
             'BF' => 'Burkina Faso',
             'MM' => 'Burma',
             'BI' => 'Burundi',
             'KH' => 'Cambodia',
             'CM' => 'Cameroon',
             'CA' => 'Canada',
             'CV' => 'Cape Verde',
             'KY' => 'Cayman Islands',
             'CF' => 'Central African Republic',
             'TD' => 'Chad',
             'CL' => 'Chile',
             'CN' => 'China',
             'CX' => 'Christmas Island (Australia)',
             'CC' => 'Cocos Island (Australia)',
             'CO' => 'Colombia',
             'KM' => 'Comoros',
             'CG' => 'Congo (Brazzaville),Republic of the',
             'ZR' => 'Congo, Democratic Republic of the',
             'CK' => 'Cook Islands (New Zealand)',
             'CR' => 'Costa Rica',
             'CI' => 'Cote d\'Ivoire (Ivory Coast)',
             'HR' => 'Croatia',
             'CU' => 'Cuba',
             'CY' => 'Cyprus',
             'CZ' => 'Czech Republic',
             'DK' => 'Denmark',
             'DJ' => 'Djibouti',
             'DM' => 'Dominica',
             'DO' => 'Dominican Republic',
             'TP' => 'East Timor (Indonesia)',
             'EC' => 'Ecuador',
             'EG' => 'Egypt',
             'SV' => 'El Salvador',
             'GQ' => 'Equatorial Guinea',
             'ER' => 'Eritrea',
             'EE' => 'Estonia',
             'ET' => 'Ethiopia',
             'FK' => 'Falkland Islands',
             'FO' => 'Faroe Islands',
             'FJ' => 'Fiji',
             'FI' => 'Finland',
             'FR' => 'France',
             'GF' => 'French Guiana',
             'PF' => 'French Polynesia',
             'GA' => 'Gabon',
             'GM' => 'Gambia',
             'GE' => 'Georgia, Republic of',
             'DE' => 'Germany',
             'GH' => 'Ghana',
             'GI' => 'Gibraltar',
             'GB' => 'Great Britain and Northern Ireland',
             'GR' => 'Greece',
             'GL' => 'Greenland',
             'GD' => 'Grenada',
             'GP' => 'Guadeloupe',
             'GT' => 'Guatemala',
             'GN' => 'Guinea',
             'GW' => 'Guinea-Bissau',
             'GY' => 'Guyana',
             'HT' => 'Haiti',
             'HN' => 'Honduras',
             'HK' => 'Hong Kong',
             'HU' => 'Hungary',
             'IS' => 'Iceland',
             'IN' => 'India',
             'ID' => 'Indonesia',
             'IR' => 'Iran',
             'IQ' => 'Iraq',
             'IE' => 'Ireland',
             'IL' => 'Israel',
             'IT' => 'Italy',
             'JM' => 'Jamaica',
             'JP' => 'Japan',
             'JO' => 'Jordan',
             'KZ' => 'Kazakhstan',
             'KE' => 'Kenya',
             'KI' => 'Kiribati',
             'KW' => 'Kuwait',
             'KG' => 'Kyrgyzstan',
             'LA' => 'Laos',
             'LV' => 'Latvia',
             'LB' => 'Lebanon',
             'LS' => 'Lesotho',
             'LR' => 'Liberia',
             'LY' => 'Libya',
             'LI' => 'Liechtenstein',
             'LT' => 'Lithuania',
             'LU' => 'Luxembourg',
             'MO' => 'Macao',
             'MK' => 'Macedonia, Republic of',
             'MG' => 'Madagascar',
             'MW' => 'Malawi',
             'MY' => 'Malaysia',
             'MV' => 'Maldives',
             'ML' => 'Mali',
             'MT' => 'Malta',
             'MQ' => 'Martinique',
             'MR' => 'Mauritania',
             'MU' => 'Mauritius',
             'YT' => 'Mayotte (France)',
             'MX' => 'Mexico',
             'MD' => 'Moldova',
             'MC' => 'Monaco (France)',
             'MN' => 'Mongolia',
             'MS' => 'Montserrat',
             'MA' => 'Morocco',
             'MZ' => 'Mozambique',
             'NA' => 'Namibia',
             'NR' => 'Nauru',
             'NP' => 'Nepal',
             'NL' => 'Netherlands',
             'AN' => 'Netherlands Antilles',
             'NC' => 'New Caledonia',
             'NZ' => 'New Zealand',
             'NI' => 'Nicaragua',
             'NE' => 'Niger',
             'NG' => 'Nigeria',
             'KP' => 'North Korea (Korea, Democratic People\'s Republic of)',
             'NO' => 'Norway',
             'OM' => 'Oman',
             'PK' => 'Pakistan',
             'PA' => 'Panama',
             'PG' => 'Papua New Guinea',
             'PY' => 'Paraguay',
             'PE' => 'Peru',
             'PH' => 'Philippines',
             'PN' => 'Pitcairn Island',
             'PL' => 'Poland',
             'PT' => 'Portugal',
             'QA' => 'Qatar',
             'RE' => 'Reunion',
             'RO' => 'Romania',
             'RU' => 'Russia',
             'RW' => 'Rwanda',
             'SH' => 'Saint Helena',
             'KN' => 'Saint Kitts (St. Christopher and Nevis)',
             'LC' => 'Saint Lucia',
             'PM' => 'Saint Pierre and Miquelon',
             'VC' => 'Saint Vincent and the Grenadines',
             'SM' => 'San Marino',
             'ST' => 'Sao Tome and Principe',
             'SA' => 'Saudi Arabia',
             'SN' => 'Senegal',
             'YU' => 'Serbia-Montenegro',
             'SC' => 'Seychelles',
             'SL' => 'Sierra Leone',
             'SG' => 'Singapore',
             'SK' => 'Slovak Republic',
             'SI' => 'Slovenia',
             'SB' => 'Solomon Islands',
             'SO' => 'Somalia',
             'ZA' => 'South Africa',
             'GS' => 'South Georgia (Falkland Islands)',
             'KR' => 'South Korea (Korea, Republic of)',
             'ES' => 'Spain',
             'LK' => 'Sri Lanka',
             'SD' => 'Sudan',
             'SR' => 'Suriname',
             'SZ' => 'Swaziland',
             'SE' => 'Sweden',
             'CH' => 'Switzerland',
             'SY' => 'Syrian Arab Republic',
             'TW' => 'Taiwan',
             'TJ' => 'Tajikistan',
             'TZ' => 'Tanzania',
             'TH' => 'Thailand',
             'TG' => 'Togo',
             'TK' => 'Tokelau (Union) Group (Western Samoa)',
             'TO' => 'Tonga',
             'TT' => 'Trinidad and Tobago',
             'TN' => 'Tunisia',
             'TR' => 'Turkey',
             'TM' => 'Turkmenistan',
             'TC' => 'Turks and Caicos Islands',
             'TV' => 'Tuvalu',
             'UG' => 'Uganda',
             'UA' => 'Ukraine',
             'AE' => 'United Arab Emirates',
             'UY' => 'Uruguay',
             'UZ' => 'Uzbekistan',
             'VU' => 'Vanuatu',
             'VA' => 'Vatican City',
             'VE' => 'Venezuela',
             'VN' => 'Vietnam',
             'WF' => 'Wallis and Futuna Islands',
             'WS' => 'Western Samoa',
             'YE' => 'Yemen',
             'ZM' => 'Zambia',
             'ZW' => 'Zimbabwe'
         );
 
 		$this->countryinsure = array(
 			'AF' => 0,
             'AL' => 0,
             'DZ' => 2185,
             'AD' => 5000,
             'AO' => 0,
             'AI' => 415,
             'AG' => 60,
             'AR' => 5000,
             'AM' => 1350,
             'AW' => 830,
             'AU' => 3370,
             'AT' => 5000,
             'AZ' => 5000,
             'BS' => 2795,
             'BH' => 0,
             'BD' => 5000,
             'BB' => 220,
             'BY' => 1323,
             'BE' => 5000,
             'BZ' => 1600,
             'BJ' => 170,
             'BM' => 440,
             'BT' => 440,
             'BO' => 0,
             'BA' => 5000,
             'BW' => 145,
             'BR' => 5000,
             'VG' => 165,
             'BN' => 4405,
             'BG' => 1030,
             'BF' => 530,
             'MM' => 4045,
             'BI' => 790,
             'KH' => 0,
             'CM' => 5000,
             'CA' => 675,
             'CV' => 0,
             'KY' => 0,
             'CF' => 4405,
             'TD' => 440,
             'CL' => 0,
             'CN' => 1130,
             'CX' => 3370,
             'CC' => 3370,
             'CO' => 0,
             'KM' => 690,
             'CG' => 1685,
             'ZR' => 0,
             'CK' => 980,
             'CR' => 0,
             'CI' => 5000,
             'HR' => 5000,
             'CU' => 0,
             'CY' => 5000,
             'CZ' => 5000,
             'DK' => 5000,
             'DJ' => 880,
             'DM' => 0,
             'DO' => 0,
             'TP' => 0,
             'EC' => 0,
             'EG' => 1685,
             'SV' => 0,
             'GQ' => 0,
             'ER' => 0,
             'EE' => 2020,
             'ET' => 1000,
             'FK' => 510,
             'FO' => 5000,
             'FJ' => 600,
             'FI' => 5000,
             'FR' => 5000,
             'GF' => 5000,
             'PF' => 1015,
             'GA' => 485,
             'GM' => 2575,
             'GE' => 1350,
             'DE' => 5000,
             'GH' => 5000,
             'GI' => 5000,
             'GB' => 857,
             'GR' => 5000,
             'GL' => 5000,
             'GD' => 350,
             'GP' => 5000,
             'GT' => 0,
             'GN' => 875,
             'GW' => 21,
             'GY' => 10,
             'HT' => 0,
             'HN' => 0,
             'HK' => 5000,
             'HU' => 5000,
             'IS' => 5000,
             'IN' => 2265,
             'ID' => 0,
             'IR' => 0,
             'IQ' => 0,
             'IE' => 5000,
             'IL' => 0,
             'IT' => 5000,
             'JM' => 0,
             'JP' => 5000,
             'JO' => 0,
             'KZ' => 5000,
             'KE' => 815,
             'KI' => 0,
             'KW' => 1765,
             'KG' => 1350,
             'LA' => 0,
             'LV' => 1350,
             'LB' => 440,
             'LS' => 440,
             'LR' => 440,
             'LY' => 0,
             'LI' => 5000,
             'LT' => 5000,
             'LU' => 5000,
             'MO' => 4262,
             'MK' => 2200,
             'MG' => 675,
             'MW' => 50,
             'MY' => 1320,
             'MV' => 0,
             'ML' => 950,
             'MT' => 5000,
             'MQ' => 5000,
             'MR' => 635,
             'MU' => 270,
             'YT' => 5000,
             'MX' => 0,
             'MD' => 1350,
             'MC' => 5000,
             'MN' => 440,
             'MS' => 2200,
             'MA' => 5000,
             'MZ' => 0,
             'NA' => 4405,
             'NR' => 220,
             'NP' => 0,
             'NL' => 5000,
             'AN' => 830,
             'NC' => 1615,
             'NZ' => 980,
             'NI' => 440,
             'NE' => 810,
             'NG' => 205,
             'KP' => 0,
             'NO' => 0,
             'OM' => 575,
             'PK' => 270,
             'PA' => 0,
             'PG' => 445,
             'PY' => 0,
             'PE' => 0,
             'PH' => 270,
             'PN' => 0,
             'PL' => 1350,
             'PT' => 5000,
             'QA' => 2515,
             'RE' => 5000,
             'RO' => 5000,
             'RU' => 5000,
             'RW' => 0,
             'SH' => 170,
             'KN' => 210,
             'LC' => 400,
             'PM' => 5000,
             'VC' => 130,
             'SM' => 5000,
             'ST' => 440,
             'SA' => 0,
             'SN' => 865,
             'YU' => 5000,
             'SC' => 0,
             'SL' => 0,
             'SG' => 4580,
             'SK' => 5000,
             'SI' => 4400,
             'SB' => 0,
             'SO' => 440,
             'ZA' => 1760,
             'GS' => 510,
             'KR' => 5000,
             'ES' => 5000,
             'LK' => 35,
             'SD' => 0,
             'SR' => 535,
             'SZ' => 560,
             'SE' => 5000,
             'CH' => 5000,
             'SY' => 3080,
             'TW' => 1350,
             'TJ' => 1350,
             'TZ' => 230,
             'TH' => 1350,
             'TG' => 2190,
             'TK' => 295,
             'TO' => 515,
             'TT' => 930,
             'TN' => 2200,
             'TR' => 880,
             'TM' => 675,
             'TC' => 0,
             'TV' => 4715,
             'UG' => 0,
             'UA' => 5000,
             'AE' => 5000,
             'UY' => 0,
             'UZ' => 5000,
             'VU' => 0,
             'VA' => 5000,
             'VE' => 0,
             'VN' => 0,
             'WF' => 1615,
             'WS' => 295,
             'YE' => 0,
             'ZM' => 540,
             'ZW' => 600,
             'US' => 5000
     	);
 	}
 
 	function SetInsurance()
 	{
 		$this->insurance_cost = 0;
 
 		// Insurance module by Kevin Shelton
 		// divide the value of the order among the packages based on the order total or subtotal depending on whether or not you have configured to insure tax
 		$shipping_weight = $this->order['ShippingWeight'];
 		$shipping_num_boxes = $this->order['ShippingNumBoxes'];
 		$costperpkg = $this->order['SubTotal'] / $shipping_num_boxes;
 
 		// retrieve the maximum allowed insurance for the destination country and if the package value exceeds it then set package value to the maximum allowed
 
 		$maxins = $this->countryinsure[$this->order['ShippingCountry']];
 		if ($costperpkg > $maxins) $costperpkg = $maxins;
 
 		// if insurance not allowed for destination or insurance is turned off add nothing to shipping cost
 
 		if (($maxins == 0) || (MODULE_SHIPPING_USPS_INSURE == 'False')) {
 			$insurance = 0;
 		}
 		// US and Canada share the same insurance calculation (though not the same maximum)
 		else if (($this->order['ShippingCountry'] == 'US') || ($this->order['ShippingCountry'] == 'CA'))
 		{
 			if ($costperpkg<=50) {
 				$insurance=MODULE_SHIPPING_USPS_INS1;
 			}
 			else if ($costperpkg<=100) {
 				$insurance=MODULE_SHIPPING_USPS_INS2;
 			}
 			else if ($costperpkg<=200) {
 				$insurance=MODULE_SHIPPING_USPS_INS3;
 			}
 			else if ($costperpkg<=300) {
 				$insurance=MODULE_SHIPPING_USPS_INS4;
 			}
 			else {
 				$insurance = MODULE_SHIPPING_USPS_INS4 + ((ceil($costperpkg/100) -3) * MODULE_SHIPPING_USPS_INS5);
 			}
 		}
 		// if insurance allowed and is not US or Canada then calculate international insurance
 		else {
 			if ($costperpkg<=50) {
 			    $insurance=MODULE_SHIPPING_USPS_INS6;
 			}
 			else if ($costperpkg<=100) {
 			    $insurance=MODULE_SHIPPING_USPS_INS7;
 			}
 			else if ($costperpkg<=200) {
 			    $insurance=MODULE_SHIPPING_USPS_INS8;
 			}
 			else if ($costperpkg<=300) {
 			    $insurance=MODULE_SHIPPING_USPS_INS9;
 			}
 			else {
 			    $insurance = MODULE_SHIPPING_USPS_INS9 + ((ceil($costperpkg/100) - 3) * MODULE_SHIPPING_USPS_INS10);
 			}
 		}
 		// usps doesnt accept zero weight
 		$shipping_weight = ($shipping_weight < 0.1 ? 0.1 : $shipping_weight);
 		$shipping_pounds = floor ($shipping_weight);
 		$shipping_ounces = round(16 * ($shipping_weight - floor($shipping_weight)));
 		$this->_setWeight($shipping_pounds, $shipping_ounces);
 		// Added by Kevin Chen (kkchen@uci.edu); Fixes the Parcel Post Bug July 1, 2004
 		// Refer to http://www.usps.com/webtools/htm/Domestic-Rates.htm documentation
 		// Thanks Ryan
 		if($shipping_pounds > 35 || ($shipping_pounds == 0 && $shipping_ounces < 6)){
 			$this->_setMachinable('False');
 		}
 		else{
 			$this->_setMachinable('True');
 		}
 
 		$this->insurance_cost = $insurance;
 		// End Kevin Chen July 1, 2004
 	}
 
 	function _setService($service)
 	{
 		$this->service = $service;
 	}
 
 	function _setWeight($pounds, $ounces=0)
 	{
 		$this->pounds = $pounds;
 		$this->ounces = $ounces;
 	}
 
 	function _setContainer($container)
 	{
 		$this->container = $container;
 	}
 
 	function _setSize($size)
 	{
 		$this->size = $size;
 	}
 
 	function _setMachinable($machinable)
 	{
 		$this->machinable = $machinable;
 	}
 
 	function PhoneClean($phone)
 	{
 		$res = preg_replace('/[(]|[)]|[\-]|[ ]|[#]|[\.]|[a-z](.*)|[A-Z](.*)/g', '', $phone);
 		if ( strlen($res) > 10 ) {
 			$res = substr($res, 0, 10);
 		}
 		return $res != '' ? $res : $phone;
 	}
 
 	function GetQuote($method = '')
 	{
 		if ( isset($this->types[$method]) || in_array($method, $this->intl_types)) {
 			$this->_setService($method);
 		}
 		$this -> _setContainer('None');
 		$this -> _setSize('REGULAR');
 		$this -> SetInsurance(); // ???
 		if ($this->order['ShippingCountry'] == $this->shipping_origin_country) {
 			$request='<?xml version="1.0"?>';
 			// PASSWORD="'.$this->usps_password.'"
 			$request.= '<RateV3Request USERID="'.$this->usps_userid.'">';
 			$services_count = 0;
 			if (isset($this->service)) {
 				$this->types = array($this->service => $this->types[$this->service]);
 			}
 			$dest_zip = str_replace(' ', '', $this->order['ShippingZip']);
 			$dest_zip = substr($dest_zip, 0, 5);
 			reset($this->types);
 			$allowed_types = explode(", ", MODULE_SHIPPING_USPS_TYPES);
 
 	    	while (list($key, $value) = each($this->types))
 	    	{
 	 		 	if ( !in_array($key, $allowed_types) ) continue;
 				$request .= '<Package ID="'.$services_count.'">'.
 				          '<Service>'.$key.'</Service>'.
 				          '<ZipOrigination>'.$this->store_zip5.'</ZipOrigination>'.
 				          '<ZipDestination>'.$dest_zip.'</ZipDestination>'.
 				          '<Pounds>'.$this->pounds.'</Pounds>'.
 				          '<Ounces>'.$this->ounces.'</Ounces>'.
 				          '<Size>'.$this->size.'</Size>'.
 				          '<Machinable>'.$this->machinable.'</Machinable>'.
 				          '</Package>';
 	     	 	$services_count++;
 			}
 			$request .= '</RateV3Request>';
 			$api_query = 'RateV3';
 		}
 	  	else {
 			$request  = '<IntlRateRequest USERID="'.$this->usps_userid.'">'.
 			            '<Package ID="0">'.
 			            '<Pounds>'.$this->pounds.'</Pounds>'.
 			            '<Ounces>'.$this->ounces.'</Ounces>'.
 			            '<MailType>Package</MailType>'.
 			            '<Country>'.$this->countries[$this->order['ShippingCountry']].'</Country>'.
 			            '</Package>'.
 			            '</IntlRateRequest>';
 			$api_query = 'IntlRate';
 		}
 		$request = 'API='.$api_query.'&XML=' . urlencode($request);
 		$body = $this->PostQuery($request);
 		$body = str_replace(chr(146), '', $body); // for bad `
 
 		// check for errors
 		if (strpos($body, '<Error>') !== false) {
 			$errors = Array ();
 			preg_match_all('/<Number>(.*?)<\/Number>/s', $body, $error_numbers);
 			preg_match_all('/<Description>(.*?)<\/Description>/s', $body, $error_descriptions);
 
 			foreach ($error_numbers[1] as $index => $error_number) {
 				$errors[$index] = $error_descriptions[1][$index];
 				if ($this->Application->isDebugMode()) {
 					$errors[$index] .= ' (' . $error_number . ')';
 				}
 			}
 
 			$errors = array_unique($errors); // we may have same errors on many packages, so don't show duplicates
 			return Array('error' => implode('<br/>', $errors));
 		}
 
 		// parse response
 
 		$xml_helper = $this->Application->recallObject('kXMLHelper');
 		/* @var $xml_helper kXMLHelper */
 
 		$root_node =& $xml_helper->Parse($body);
 		/* @var $root_node kXMLNode */
 
 		$rates = Array();
 		// Domestic shipping
 		if ($this->order['ShippingCountry'] == $this->shipping_origin_country) {
 			$i = 0;
 			$postage_node =& $root_node->FindChild('Package');
 			do {
 				// $parcel_node =& $postage_node->firstChild;
 				$service = $postage_node->FindChildValue('MailService');
 				if ( $service != '' ) {
 					$i++;
 					$rates[$i] = Array();
 					$rates[$i]['Title'] = $service;
 					$rates[$i]['Rate'] = $this->insurance_cost + $postage_node->FindChildValue('Rate');
 				}
 			}
 			while ( $postage_node =& $postage_node->NextSibling());
 		}
 		else {
 			// for International Rates !!!
 		    $allowed_types = array();
 			foreach( explode(", ", MODULE_SHIPPING_USPS_TYPES_INTL) as $value ) {
 				$allowed_types[$value] = $this->intl_types[$value];
 			}
 			$i = 0;
 			$service_node =& $root_node->FindChild('Service');
 			do {
 				$service = trim($service_node->FindChildValue('SvcDescription'));
 				if( !in_array($service, $allowed_types) ) continue;
 				$i++;
 				if ( $service_node->FindChildValue('MaxWeight') >= $this->pounds ) {
 					$rates[$i] = Array();
 					$rates[$i]['Title'] = $service;
 					$rates[$i]['MaxDimensions'] = $service_node->FindChildValue('MaxDimensions');
 					$rates[$i]['MaxWeight'] = $service_node->FindChildValue('MaxWeight');
 					$rates[$i]['SvcCommitments'] = $service_node->FindChildValue('SvcCommitments');
 					$rates[$i]['Rate'] = $this->insurance_cost + $service_node->FindChildValue('Postage');
 				}
 			}
 			while ( $service_node =& $service_node->NextSibling());
 	  	}
 	  	// print_r($rates);
 	  	// die('here');
 		return $rates;
 	}
 
 	function PostOrder()
 	{
 		$request='';
 		$base_request = '';
 		$this->SetInsurance();
 		// $this->order['ShippingCountry'] = $this->GetUSPSCountry($this->order['ShippingCountry']);
 
 		// Domestic Order
 		if ($this->order['ShippingCountry'] == $this->shipping_origin_country) {
 
 			// $dest_zip = str_replace(' ', '', $this->order['ShippingZip5']);
 			$this->order['ShippingZip5'] = substr($this->order['ShippingZip5'], 0, 5);
 			$WeightInOunces = floor($this->pounds * 16 + $this->ounces);
 
 			$base_request ='
 			<Option>1</Option>
 			<ImageParameters></ImageParameters>
 			<FromName>'.$this->store_name.'</FromName>
 			<FromFirm>'.$this->company_name.'</FromFirm>
 			<FromAddress1>'.$this->store_address1.'</FromAddress1>
 			<FromAddress2>'.$this->store_address2.'</FromAddress2>
 			<FromCity>'.$this->store_city.'</FromCity>
 			<FromState>'.$this->store_state.'</FromState>
 			<FromZip5>'.$this->store_zip5.'</FromZip5>
 			<FromZip4>'.$this->store_zip4.'</FromZip4>
 			<ToName>'.$this->order['FirstName'].' '.$this->order['LastName'].'</ToName>
 			<ToFirm>'.$this->order['ShippingCompany'].'</ToFirm>
 			<ToAddress1>'.$this->order['ShippingAddress2'].'</ToAddress1>
 			<ToAddress2>'.$this->order['ShippingAddress1'].'</ToAddress2>
 			<ToCity>'.$this->order['ShippingCity'].'</ToCity>
 			<ToState>'.$this->order['ShippingState'].'</ToState>
 			<ToZip5>'.$this->order['ShippingZip5'].'</ToZip5>
 			<ToZip4>'.$this->order['ShippingZip4'].'</ToZip4>
 			<WeightInOunces>'.$WeightInOunces.'</WeightInOunces>
 			<ServiceType>'.$this->order['ShippingService'].'</ServiceType>
 			<ImageType>PDF</ImageType>
 			<LabelDate>'.date('m/d/Y',time()).'</LabelDate>
 			<CustomerRefNo></CustomerRefNo>
 			<AddressServiceRequested></AddressServiceRequested>
 			<SenderName></SenderName><SenderEMail></SenderEMail>
 			<RecipientName></RecipientName>
 			<RecipientEMail></RecipientEMail>
 			';
 
 			$api_query = 'DeliveryConfirmationV3';
 			$xml_request = 'DeliveryConfirmationV3.0Request';
 		}
 		else {
 
 			// International Order(s)
 			$shipping_service = strtolower($this->order['ShippingService']);
 
 		    $base_request = '<Option/>
 		    <ImageParameters/>
 		    <FromFirstName>'.$this->store_first_name.'</FromFirstName>
 		    <FromLastName>'.$this->store_last_name.'</FromLastName>
 		    <FromFirm>'.$this->company_name.'</FromFirm>
 		    <FromAddress1>'.$this->store_address1.'</FromAddress1>
 		    <FromAddress2>'.$this->store_address2.'</FromAddress2>
 		    <FromCity>'.$this->store_city.'</FromCity>
 		    <FromState>'.$this->store_state.'</FromState>
 		    <FromZip5>'.$this->store_zip5.'</FromZip5>
 		    <FromPhone>'.$this->PhoneClean($this->store_phone).'</FromPhone>
 		    <ToName>'.$this->order['FirstName'].' '.$this->order['LastName'].'</ToName>
 		    <ToFirm>'.$this->order['ShippingCompany'].'</ToFirm>
 		    <ToAddress1></ToAddress1>
 		    <ToAddress2>'.$this->order['ShippingAddress2'].'</ToAddress2>
 		    <ToAddress3>'.$this->order['ShippingAddress1'].'</ToAddress3>
 		    <ToCity>'.$this->order['ShippingCity'].'</ToCity>';
 		    if ( $this->order['ShippingProvince'] != '' ) {
 		    	$base_request.='
 		    	<ToProvince>'.$this->order['ShippingProvince'].'</ToProvince>';
 		    }
 		    $base_request.='
 		    <ToCountry>'.$this->countries[$this->order['ShippingCountry']].'</ToCountry>
 		    <ToPostalCode>'.$this->order['ShippingZip'].'</ToPostalCode>
 		    <ToPOBoxFlag>N</ToPOBoxFlag>
 		    <ToPhone>'.$this->PhoneClean($this->order['ShippingPhone']).'</ToPhone>
 		    <ToFax>'.$this->PhoneClean($this->order['ShippingFax']).'</ToFax>
 		    <ToEmail>'.$this->order['Email'].'</ToEmail>
 		    <ShippingContents>';
 
 		    // add items
 			foreach ( $this->order['Items'] as $k => $value ) {
 				 $base_request.='
 				 <ItemDetail>
 					<Description>Computer Parts</Description>
 					<Quantity>'.$value['Qty'].'</Quantity>
 					<Value>'.($value['Price'] * $value['Qty']).'</Value>
 					<NetPounds>'.$value['NetPounds'].'</NetPounds>
 					<NetOunces>'.$value['NetOunces'].'</NetOunces>
 					<HSTariffNumber>123456</HSTariffNumber>
 					<CountryOfOrigin>United States</CountryOfOrigin>
 				 </ItemDetail>';
 			}
 		    // end add items
 
 		    $base_request.='
 		    </ShippingContents>
 		    <GrossPounds>'.$this->pounds.'</GrossPounds>
 		    <GrossOunces>'.$this->ounces.'</GrossOunces>
 		    <ContentType>MERCHANDISE</ContentType>
 		    <Agreement>Y</Agreement>
 		    <InvoiceNumber>'.$this->order['InvoiceNumber'].'</InvoiceNumber>
 		    <ImageType>PDF</ImageType>
 		    <ImageLayout>ALLINONEFILE</ImageLayout>
 		    <LabelDate>'.date('m/d/Y',time()).'</LabelDate>
 		    ';
 
 			if (strpos($shipping_service, 'express') !== false) {
 				$xml_request = 'ExpressMailIntlRequest';
 				$api_query = 'ExpressMailIntl';
 			}
 			elseif (strpos($shipping_service, 'priority') !== false) {
 				$xml_request = 'PriorityMailIntlRequest';
 				$api_query = 'PriorityMailIntl';
 			}
 			else {
 				$xml_request = 'FirstClassMailIntlRequest';
 				$api_query = 'FirstClassMailIntl';
 			}
 		}
 
 		$request.= '<'.$xml_request.' USERID="'.$this->usps_userid.'">';
 		$request.= $base_request;
 		$request.= '</'.$xml_request.'>';
 
 		// die($request);
 
 		$request = 'API='.$api_query.'&XML='.urlencode($request);
 
 		$body = $this->PostQuery($request, 1);
 
 		// check for errors
 		if (strpos($body, '<Error>') !== false) {
 			$errors = Array ();
 			preg_match_all('/<Number>(.*?)<\/Number>/s', $body, $error_numbers);
 			preg_match_all('/<Description>(.*?)<\/Description>/s', $body, $error_descriptions);
 
 			foreach ($error_numbers[1] as $index => $error_number) {
 				$errors[$index] = Array ('error_number' => $error_number, 'error_description' => $error_descriptions[1][$index]);
 			}
 
 			// TODO: find a way to return other error messages in same package as well
 			return $errors[0];
 		}
 
 		// parse response
 		$xml_helper = $this->Application->recallObject('kXMLHelper');
 		$root_node =& $xml_helper->Parse($body);
 		/* @var $root_node kXMLNode */
 		$Postage = 0;
 
 		$label_file = $TrackingNumber = $PostnetBarCode = '';
 
 		// Domestic shipping
 		if ($this->order['ShippingCountry'] == $this->shipping_origin_country ) {
 			$delivery_node =& $root_node->FindChild('DeliveryConfirmationV3.0Response');
 			do {
 				$TrackingNumber = $delivery_node->FindChildValue('DeliveryConfirmationNumber');
 				$PostnetBarCode = $delivery_node->FindChildValue('Postnet');
 				$DeliveryConfirmationLabel = base64_decode($delivery_node->FindChildValue('DeliveryConfirmationLabel'));
 			}
 			while ( $delivery_node =& $delivery_node->NextSibling());
 		}
 		else {
 
 			if (strpos($shipping_service, 'express') !== false) {
 				$node_title = 'ExpressMailIntlResponse';
 			}
 			elseif (strpos($shipping_service, 'priority') !== false) {
 				$node_title = 'PriorityMailIntlResponse';
 			}
 			else {
  				$node_title = 'FirstClassMailIntlResponse';
 			}
 
 			$delivery_node =& $root_node->FindChild($node_title);
 			$PostnetBarCode = $delivery_node->FindChildValue('BarcodeNumber');
 			$Postage = $delivery_node->FindChildValue('Postage');
 			$DeliveryConfirmationLabel = base64_decode($delivery_node->FindChildValue('LabelImage'));
 
 		}
 
 		if ( $TrackingNumber != '' ) {
 			$label_file = USPS_LABEL_FOLDER.$TrackingNumber.".pdf";
 		}
 		elseif ( $PostnetBarCode != '' ) {
 			$label_file = USPS_LABEL_FOLDER.$PostnetBarCode.".pdf";
 		}
 
 		if ( $label_file != '' ) {
 			$file_helper = $this->Application->recallObject('FileHelper');
 			/* @var $file_helper FileHelper */
 
 			$file_helper->CheckFolder(USPS_LABEL_FOLDER);
 
 			if (!$handle = fopen($label_file, 'a')) echo "Cannot open file ($label_file)";
 			if ( @fwrite($handle, $DeliveryConfirmationLabel) === FALSE) echo "Cannot write to file ($label_file)";
 		}
 
 		return array('TrackingNumber' => $TrackingNumber, 'PostnetBarCode' => $PostnetBarCode, 'Postage' => $Postage);
 	}
 
 	function GetUSPSCountry($country, $default = 'US')
 	{
 		$cs_helper = $this->Application->recallObject('CountryStatesHelper');
 		/* @var $cs_helper kCountryStatesHelper */
 
 		$country = $cs_helper->getCountryIso($country);
 
 		return $country == '' ? $default : $country;
 	}
 
 	function GetShippingQuotes($params = null)
 	{
 		$weights = kUtil::Kg2Pounds($params['packages']['0']['weight']);
 		$weight = '';
 		$weight = $weights[0];
 		if ( $weights[1] != '' ) {
 			$weight.='.'.$weights[1];
 		}
 		$country = $this->GetUSPSCountry($params['dest_country']);
 
 		$this->order = Array();
 		$this->order['ShippingWeight'] = $weight;
 		$this->order['ShippingNumBoxes'] = 1;
 		$this->order['ShippingZip'] = $params['dest_postal'];
 		$this->order['SubTotal'] = $params['amount'];
 		$this->order['ShippingCountry'] = $country;
 
 		$shipping_types = Array();
 		$rates = $this->GetQuote();
 
 		if ( !isset($rates['error']) ) {
 			$this->Application->RemoveVar('sqe_error');
 
 			$i = 1;
 			foreach ($rates as $k => $rate ) {
 				 $shipping_types['USPS_'.$i] = Array(
 		            'ShippingId' => 'USPS_'.$i,
 		            'TotalCost' => $rate['Rate'],
 		            'ShippingName' => $rate['Title'],
 		            'Type' => '1',
 		            'CODFlat' => '0',
 		            'CODPercent' => '0',
 		            'PortalGroups' => ',15,',
 		            'InsuranceFee' => '',
 		            'COD' => '0',
 		            'SelectedOnly' => '0',
 		            'Code' => $rate['Title']
 				 );
 				 $i++;
 			}
 		}
 		else {
 			// for Front-End (shipping screen) and Admin (Shipping Tab on editing order)
 			$this->Application->StoreVar('sqe_error', $rates['error']);
 		}
 
 		$this->Application->StoreVar('current_usps_shipping_types', serialize($shipping_types));
 		return $shipping_types;
 	}
 
 	function TrackOrder($TrackingNumber='')
 	{
 		if ( $TrackingNumber != '' ) {
 			// http://testing.shippingapis.com/ShippingAPITest.dll?API=TrackV2&XML=<TrackFieldRequest USERID="402INTEC7634"><TrackID ID="EJ958083578US"></TrackID></TrackFieldRequest>
 
 			$request = '<TrackRequest USERID="'.$this->usps_userid.'"><TrackID ID="'.$TrackingNumber.'"></TrackID></TrackRequest>';
 			$api_query = 'TrackV2';
 			$request = 'API='.$api_query.'&XML='.urlencode($request);
 			$body = $this->PostQuery($request);
 
 			// check for errors
 			if (strpos($body, '<Error>') !== false) {
 				$errors = Array ();
 				preg_match_all('/<Number>(.*?)<\/Number>/s', $body, $error_numbers);
 				preg_match_all('/<Description>(.*?)<\/Description>/s', $body, $error_descriptions);
 
 				foreach ($error_numbers[1] as $index => $error_number) {
 					$errors[$index] = $error_descriptions[1][$index];
 					if ($this->Application->isDebugMode()) {
 						$errors[$index] .= ' (' . $error_number . ')';
 					}
 				}
 
 				$errors = array_unique($errors); // we may have same errors on many packages, so don't show duplicates
 				return Array('error' => implode('<br/>', $errors));
 			}
 
 			$xml_helper = $this->Application->recallObject('kXMLHelper');
 			$root_node =& $xml_helper->Parse($body);
 			/* @var $root_node kXMLNode */
 
 			// Tracking Shipping
 			$delivery_node =& $root_node->FindChild('TrackInfo');
 			$TrackSummary = $delivery_node->FindChildValue('TrackSummary');
 			// echo ' TrackSummary ('.$TrackingNumber.') = '.$TrackSummary.'<br>';
 
 			return strpos($TrackSummary, 'delivered') !== false ? 1 : 0;
 		}
 		else
 			return false;
 	}
 
 	function ProcessTrackOrders()
 	{
 		$sql = sprintf('SELECT `OrderId`, `ShippingTracking` FROM %s WHERE `Status` > 3 AND `Delivered` = 0', TABLE_PREFIX.'Orders');
 		$orders = $this->Application->Conn->Query($sql);
 		foreach ( $orders as $k => $order ) {
 			// try to track order
 			if ( $order['ShippingTracking'] != '' && $this->TrackOrder($order['ShippingTracking']) ) {
 				$update_order = sprintf("UPDATE %s SET `Delivered` = 1 WHERE %s = %s",
 					TABLE_PREFIX.'Orders',
 					$this->Application->getUnitOption('ord', 'IDField'),
 					$order[$this->Application->getUnitOption('ord', 'IDField')]
 				);
 				$this->Application->Conn->Query($update_order);
 			}
 		}
 	}
 
 	function PostQuery($request, $secure=0)
 	{
 		switch (MODULE_SHIPPING_USPS_SERVER) {
 			case 'production':
 				$usps_server = $secure > 0 ? 'https://secure.shippingapis.com' : 'http://production.shippingapis.com' ;
 			    $api_dll = 'ShippingAPI.dll';
 			break;
 
 			case 'test':
 				$usps_server = $secure > 0 ? 'https://secure.shippingapis.com' : 'http://testing.shippingapis.com';
 				$api_dll = 'ShippingAPITest.dll';
 			break;
 		}
 
 		$curl = curl_init();
 		curl_setopt($curl, CURLOPT_URL, $usps_server.'/'.$api_dll.'?'.$request);
 		curl_setopt($curl, CURLOPT_HEADER, 0);
 		curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
 		$body = curl_exec($curl);
 		curl_close($curl);
 
 		if ($this->logFilePath) {
 			$fp = fopen($this->logFilePath, 'a');
 
 			if ($fp) {
 				$request_url = sprintf("Date %s : IP %s\n\nPost\n\n%s\n\nReplay\n\n%s\n\n",
 			   		adodb_date('m/d/Y H:i:s'),
-			   		$_SERVER['REMOTE_ADDR'],
+					$this->Application->getClientIp(),
 			   		$usps_server . '/' . $api_dll . '?' . urldecode($request),
 			   		$body
 			   	);
 
 			   	fwrite($fp, $request_url);
 			   	fclose($fp);
 			}
 		}
 
 		return $body;
 	}
 
 	/**
 	 * Returns available shipping types
 	 *
 	 * @return Array
 	 * @todo Get possible shipping types based on MODULE_SHIPPING_USPS_TYPES and MODULE_SHIPPING_USPS_TYPES_INTL consntants
 	 */
 	function GetAvailableTypes()
 	{
 		return Array (
 			Array (
 				'_ClassName' => get_class($this),
 				'_Id' => 'USPS',
 				'_Name' => 'USPS (Default)'
 			)
 		);
 	}
 
 	function LoadParams()
 	{
 		$sql = 'SELECT Properties FROM '.$this->Application->getUnitOption('sqe', 'TableName').'
 				WHERE ClassName="USPS"';
 		$params = $this->Conn->GetOne($sql);
 
 		return unserialize($params);
 	}
 
 	function _prepare_xml_param($value) {
 		return strip_tags($value);
 	}
 
 	/**
 	 * Returns virtual field names, that will be saved as properties
 	 *
 	 * @return Array
 	 */
 	function GetEngineFields()
 	{
 		return Array ('AccountLogin');
 	}
 
 	/**
 	 * Creates new USPS order
 	 *
 	 * @param OrdersItem $object
 	 * @param bool $dry_run
 	 * @return Array
 	 */
 	function MakeOrder(&$object, $dry_run = false)
 	{
 		$ShippingInfo = unserialize($object->GetDBField('ShippingInfo'));
 		$ShippingCode = $USPSMethod = '';
 		$ShippingCountry = $this->GetUSPSCountry($object->GetDBField('ShippingCountry'));
 
 		$UserName = explode(" ", $object->GetDBField('ShippingTo'));
 
 		$item_table = TABLE_PREFIX.'OrderItems';
 		if ($this->Application->isAdminUser) {
 			// this strange contraption actually uses temp table from object (when in temp mode)
 			$order_table = $object->TableName;
 			$item_table = str_replace('Orders', 'OrderItems', $order_table);
 		}
 
 		$sOrder = Array (
 			'FirstName' => $UserName[0],
 			'LastName' => $UserName[1],
 			'ShippingCompany' => $object->GetDBField('ShippingCompany'),
 			'ShippingAddress1' => $object->GetDBField('ShippingAddress1'),
 			'ShippingAddress2' => $object->GetDBField('ShippingAddress2'),
 			'ShippingCity' => $object->GetDBField('ShippingCity'),
 			'ShippingZip' => $object->GetDBField('ShippingZip'),
 			'ShippingCountry' => $ShippingCountry,
 			'ShippingPhone' => $this->PhoneClean($object->GetDBField('ShippingPhone')),
 			'ShippingFax' =>  $this->PhoneClean($object->GetDBField('ShippingFax')),
 			'ShippingNumBoxes' => '1',
 		);
 
 		$sql = 'SELECT SUM(`Quantity` * `Weight`)
 				FROM ' . $item_table . '
 				WHERE ' . $object->IDField . ' = ' . $object->GetID();
 		$weight = $this->Application->Conn->GetOne($sql);
 
 		$f_weight = kUtil::Kg2Pounds($weight);
 		$sOrder['ShippingWeight'] = $f_weight[0].'.'.$f_weight[1];
 
 		foreach ($ShippingInfo as $k => $ShippingRow) {
 			$ShippingCode = $ShippingRow['Code'];
 		}
 
 		if ( $object->GetDBField('ShippingCountry') == 'USA' ) {
 			$sOrder['ShippingState'] = $object->GetDBField('ShippingState');
 			$USPSMethod = $ShippingCode;
 			unset($sOrder['ShippingZip']);
 
 			$sOrder['ShippingZip5'] = substr(trim($object->GetDBField('ShippingZip')), 0, 5);
 			$sOrder['ShippingZip4'] = '';
 			$sOrder['SubTotal'] = $object->GetDBField('SubTotal');
 		}
 		else {
 			$USPSMethod = array_search($ShippingCode, $this->intl_types);
 			$sOrder['ShippingProvince'] = '';
 
 			if ( $ShippingCountry == 'CA' ) {
 				$sOrder['ShippingProvince'] = $object->GetField('ShippingState');
 			}
 
 			// add items
 			$sql = 'SELECT `Quantity`, `Weight`, `Price`
 					FROM ' . $item_table . '
 					WHERE ' . $object->IDField . ' = ' . $object->GetID();
 			$order_items = $this->Application->Conn->Query($sql);
 
 			$i = 1;
 			$Items = Array();
 
 			foreach ($order_items as $k => $order_item) {
 				$p_weight = Array();
 				$p_weight = kUtil::Kg2Pounds($order_item['Weight']);
 				$Items[$i] = Array('Qty' => $order_item['Quantity'], 'Price' => $order_item['Price'], 'NetPounds' => $p_weight[0], 'NetOunces' => $p_weight[1]);
 				$i++;
 			}
 
 			$sOrder['Items'] = $Items;
 			$sOrder['InvoiceNumber'] = $object->GetDBField('OrderNumber');
 		}
 
 		$sOrder['ShippingService'] = $USPSMethod;
 
 		// make USPS order
 		$this->order = $sOrder;
 		$usps_data = $this->PostOrder();
 
 		// if errors
 		if ( array_key_exists('error_number', $usps_data) ) {
 			return $usps_data;
 		}
 
 		if ( array_key_exists('Postage', $usps_data) ) {
 			$ShippingPrice = '';
 			$ShippingPrice = $usps_data['Postage'];
 		}
 
 		$ShippingTracking = '';
 
 		if ( isset($usps_data['TrackingNumber']) && $usps_data['TrackingNumber'] != '' ) {
 			$ShippingTracking = $usps_data['TrackingNumber'];
 		}
 
 		if ( isset($usps_data['PostnetBarCode']) && $usps_data['PostnetBarCode'] != '' && $ShippingTracking == '' ) {
 			$ShippingTracking = $usps_data['PostnetBarCode'];
 		}
 
 		if ($dry_run == false) {
 			$object->SetDBField('ShippingTracking', $ShippingTracking);
 			$object->Update();
 		}
 		else {
 			$full_path = USPS_LABEL_FOLDER . $ShippingTracking . ".pdf";
 
 			if (file_exists($full_path)) {
 				unlink($full_path);
 			}
 		}
 
 		return $usps_data;
 	}
 }
\ No newline at end of file
Index: branches/5.3.x/units/payment_type/payment_type_event_handler.php
===================================================================
--- branches/5.3.x/units/payment_type/payment_type_event_handler.php	(revision 15670)
+++ branches/5.3.x/units/payment_type/payment_type_event_handler.php	(revision 15671)
@@ -1,295 +1,295 @@
 <?php
 /**
 * @version	$Id$
 * @package	In-Commerce
 * @copyright	Copyright (C) 1997 - 2009 Intechnic. All rights reserved.
 * @license	Commercial License
 * This software is protected by copyright law and international treaties.
 * Unauthorized reproduction or unlicensed usage of the code of this program,
 * or any portion of it may result in severe civil and criminal penalties,
 * and will be prosecuted to the maximum extent possible under the law
 * See http://www.in-portal.org/commercial-license for copyright notices and details.
 */
 
 defined('FULL_PATH') or die('restricted access!');
 
 class PaymentTypeEventHandler extends kDBEventHandler
 {
 	/**
 	 * Define alternative event processing method names
 	 *
 	 * @return void
 	 * @see kEventHandler::$eventMethods
 	 * @access protected
 	 */
 	protected function mapEvents()
 	{
 		parent::mapEvents();
 
 		$common_events = Array (
 			'OnMassApprove'=>'iterateItems',
 			'OnMassDecline'=>'OnMassDecline',
 			'OnMassMoveUp'=>'iterateItems',
 			'OnMassMoveDown'=>'iterateItems',
 		);
 
 		$this->eventMethods = array_merge($this->eventMethods, $common_events);
 	}
 
 	/**
 	 * Allows to override standard permission mapping
 	 *
 	 * @return void
 	 * @access protected
 	 * @see kEventHandler::$permMapping
 	 */
 	protected function mapPermissions()
 	{
 		parent::mapPermissions();
 
 		$permissions = Array (
 			'OnItemBuild' => Array ('self' => true),
 		);
 
 		$this->permMapping = array_merge($this->permMapping, $permissions);
 	}
 
 	/**
 	 * Set's new category as primary for product
 	 *
 	 * @param kEvent $event
 	 */
 	function OnSetPrimary($event)
 	{
 		$object = $event->getObject( Array('skip_autoload' => true) );
 		$this->StoreSelectedIDs($event);
 		$ids=$this->getSelectedIDs($event);
 		if($ids)
 		{
 			$id = array_shift($ids);
 			$table_info = $object->getLinkedInfo();
 
 			$this->Conn->Query('UPDATE '.$object->TableName.' SET IsPrimary = 0 ');
 			$this->Conn->Query('UPDATE '.$object->TableName.' SET IsPrimary = 1, Status = 1 WHERE PaymentTypeId = '.$id.' ');
 		}
 		$event->SetRedirectParam('opener', 's');
 	}
 
 	function OnMassDecline($event)
 	{
 		$object = $event->getObject(Array ('skip_autoload' => true));
 		/* @var $object kDBItem */
 
 		$this->StoreSelectedIDs($event);
 		$ids = $this->getSelectedIDs($event);
 
 		if ( $ids ) {
-			$status_field = array_shift($this->Application->getUnitOption($event->Prefix, 'StatusField'));
+			$status_field = $object->getStatusField();
 
 			foreach ($ids as $id) {
 				$object->Load($id);
 
 				if ( !$object->GetDBField("IsPrimary") ) {
 					$object->SetDBField($status_field, 0);
 				}
 
 				if ( $object->Update() ) {
 					$event->status = kEvent::erSUCCESS;
 					$event->SetRedirectParam('opener', 's');
 				}
 				else {
 					$event->status = kEvent::erFAIL;
 					$event->redirect = false;
 					break;
 				}
 			}
 		}
 	}
 
 	/**
 	 * Occurs before updating item
 	 *
 	 * @param kEvent $event
 	 * @return void
 	 * @access protected
 	 */
 	protected function OnBeforeItemUpdate(kEvent $event)
 	{
 		parent::OnBeforeItemUpdate($event);
 
 		$object = $event->getObject();
 		/* @var $object kDBItem */
 
-		$status_field = array_shift( $this->Application->getUnitOption($event->Prefix, 'StatusField') );
+		$status_field = $object->getStatusField();
 
 		if ( $object->GetDBField('IsPrimary') == 1 && $object->GetDBField($status_field) == 0 ) {
 			$object->SetDBField($status_field, 1);
 		}
 
 		$this->convertGroups($event);
 	}
 
 	/**
 	 * Occurs before creating item
 	 *
 	 * @param kEvent $event
 	 * @return void
 	 * @access protected
 	 */
 	protected function OnBeforeItemCreate(kEvent $event)
 	{
 		parent::OnBeforeItemCreate($event);
 
 		$this->convertGroups($event);
 	}
 
 	/**
 	 * Disable delete on primary payment type
 	 *
 	 * @param kEvent $event
 	 * @param string $type
 	 * @return void
 	 * @access protected
 	 */
 	protected function customProcessing(kEvent $event, $type)
 	{
 		if ( $event->Name == 'OnMassDelete' && $type == 'before' ) {
 			$object = $event->getObject();
 			/* @var $object kDBItem */
 
 			$ids_ok = Array ();
 			$ids = $event->getEventParam('ids');
 
 			foreach ($ids as $id) {
 				$object->Load($id);
 
 				if ( $object->GetDBField('IsPrimary') ) {
 					$this->Application->StoreVar('pt_delete_error', '1');
 				}
 				else {
 					$ids_ok[] = $id;
 				}
 			}
 
 			$event->setEventParam('ids', $ids_ok);
 		}
 	}
 
 	/**
 	 * Saves content of temp table into live and
 	 * redirects to event' default redirect (normally grid template)
 	 *
 	 * @param kEvent $event
 	 * @return void
 	 * @access protected
 	 */
 	protected function OnSave(kEvent $event)
 	{
 		$this->Application->StoreVar('check_unused_currencies', 1);
 
 		parent::OnSave($event);
 	}
 
 	/**
 	 * Sets default payment type group
 	 *
 	 * @param kEvent $event
 	 * @return void
 	 * @access protected
 	 */
 	protected function OnAfterConfigRead(kEvent $event)
 	{
 		parent::OnAfterConfigRead($event);
 
 		$default_group = $this->Application->ConfigValue('User_LoggedInGroup');
 
 		$fields = $this->Application->getUnitOption($event->Prefix, 'Fields');
 		$fields['PortalGroups']['default'] = ','.$default_group.',';
 		$this->Application->setUnitOption($event->Prefix, 'Fields', $fields);
 	}
 
 	/**
 	 * Earlier version of group selector control needs such conversion (also used in shipping)
 	 *
 	 * @param kEvent $event
 	 */
 	function convertGroups($event)
 	{
 		$object = $event->getObject();
 
 		$selected_groups = $object->GetDBField('PortalGroups');
 		if ($selected_groups) {
 			$selected_groups = str_replace('|', ',', $selected_groups);
 			$selected_groups = ','.trim($selected_groups, ',').',';
 			$object->SetDBField('PortalGroups', $selected_groups);
 		}
 	}
 
 	/**
 	 * Returns ID of current item to be edited
 	 * by checking ID passed in get/post as prefix_id
 	 * or by looking at first from selected ids, stored.
 	 * Returned id is also stored in Session in case
 	 * it was explicitly passed as get/post
 	 *
 	 * @param kEvent $event
 	 * @return int
 	 * @access public
 	 */
 	public function getPassedID(kEvent $event)
 	{
 		if ( $event->Special == 'auto-ord' ) {
 			$main_object = $this->Application->recallObject('ord');
 			/* @var $main_object kDBItem */
 
 			return $main_object->GetDBField('PaymentType');
 		}
 		elseif ( substr($event->Special, 0, 3) == 'gw-' ) {
 			// returns first matched enabled payment type
 			return Array (
 				'Status' => STATUS_ACTIVE,
 				TABLE_PREFIX . 'Gateways.Name' => $event->getEventParam('gateway')
 			);
 		}
 
 		return parent::getPassedID($event);
 	}
 
 	/**
 	 * Apply any custom changes to list's sql query
 	 *
 	 * @param kEvent $event
 	 * @return void
 	 * @access protected
 	 * @see kDBEventHandler::OnListBuild()
 	 */
 	protected function SetCustomQuery(kEvent $event)
 	{
 		parent::SetCustomQuery($event);
 
 		$object = $event->getObject();
 		/* @var $object kDBList */
 
 		if ( in_array($event->Special, Array ('enabled', 'selected', 'available')) || !$this->Application->isAdminUser ) {
 			// "enabled" special or Front-End
 			$object->addFilter('enabled_filter', '%1$s.Status = ' . STATUS_ACTIVE);
 		}
 
 		// site domain payment type picker
 		if ( $event->Special == 'selected' || $event->Special == 'available' ) {
 			$edit_picker_helper = $this->Application->recallObject('EditPickerHelper');
 			/* @var $edit_picker_helper EditPickerHelper */
 
 			$edit_picker_helper->applyFilter($event, 'PaymentTypes');
 		}
 
 		// apply domain-based payment type filtering
 		$payment_types = $this->Application->siteDomainField('PaymentTypes');
 
 		if ( strlen($payment_types) ) {
 			$payment_types = explode('|', substr($payment_types, 1, -1));
 			$object->addFilter('domain_filter', '%1$s.PaymentTypeId IN (' . implode(',', $payment_types) . ')');
 		}
 	}
 
 }
\ No newline at end of file
Index: branches/5.3.x/units/manufacturers/manufacturers_config.php
===================================================================
--- branches/5.3.x/units/manufacturers/manufacturers_config.php	(revision 15670)
+++ branches/5.3.x/units/manufacturers/manufacturers_config.php	(revision 15671)
@@ -1,136 +1,136 @@
 <?php
 /**
 * @version	$Id$
 * @package	In-Commerce
 * @copyright	Copyright (C) 1997 - 2009 Intechnic. All rights reserved.
 * @license	Commercial License
 * This software is protected by copyright law and international treaties.
 * Unauthorized reproduction or unlicensed usage of the code of this program,
 * or any portion of it may result in severe civil and criminal penalties,
 * and will be prosecuted to the maximum extent possible under the law
 * See http://www.in-portal.org/commercial-license for copyright notices and details.
 */
 
 defined('FULL_PATH') or die('restricted access!');
 
 $config = Array (
 	'Prefix' => 'manuf',
 	'ItemClass' => Array ('class' => 'kDBItem', 'file' => '', 'build_event' => 'OnItemBuild'),
 	'ListClass' => Array ('class' => 'kDBList', 'file' => '', 'build_event' => 'OnListBuild'),
 	'EventHandlerClass' => Array ('class' => 'ManufacturersEventHandler', 'file' => 'manufacturers_event_handler.php', 'build_event' => 'OnBuild'),
 	'TagProcessorClass' => Array ('class' => 'ManufacturersTagProcessor', 'file' => 'manufacturers_tag_processor.php', 'build_event' => 'OnBuild'),
 	'AutoLoad' => true,
 
 	'QueryString' => Array (
 		1 => 'id',
 		2 => 'Page',
 		3 => 'PerPage',
 		4 => 'event',
 		5 => 'mode',
 	),
 
 	'IDField' => 'ManufacturerId',
 	'TableName' => TABLE_PREFIX.'Manufacturers',
 
 	'TitlePresets' => Array (
 		'default' => Array (
 			'new_status_labels' => Array ('manuf' => '!la_title_AddingManufacturer!'),
 			'edit_status_labels' => Array ('manuf' => '!la_title_EditingManufacturer!'),
 		),
 		'manuf_list' => Array (
 			'prefixes' => Array ('manuf_List'), 'format' => "!la_title_Manufacturers!",
 		),
 		'manuf_edit' => Array (
 			'prefixes' => Array ('manuf'),
 			'new_titlefield' => Array ('manuf' => '!la_title_NewManufacturer!'),
 			'format' => "#manuf_status# '#manuf_titlefield#' - !la_title_General!",
 		),
 	),
 
 	'PermSection' => Array ('main' => 'in-commerce:manufacturers'),
 
 	'Sections' => Array (
 		'in-commerce:manufacturers' => Array (
 			'parent' => 'in-commerce',
 			'icon' => 'manufacturers',
 			'label' => 'la_tab_Manufacturers',
 			'url' => Array ('t' => 'in-commerce/manufacturers/manufacturers_list', 'pass' => 'm'),
 			'permissions' => Array ('view', 'add', 'edit', 'delete'),
 			'priority' => 4,
 			'type' => stTREE,
 		),
 	),
 
 	'TitleField' => 'Name', // field, used in bluebar when editing existing item
 
 	'ListSQLs' => Array (
 		'' => '	SELECT *
 				FROM %s',
 	),
 
 	'ListSortings' => Array (
 		'' => Array (
 			'Sorting' => Array ('Name' => 'asc'),
 		)
 	),
 
 	'Fields' => Array (
 		'ManufacturerId' => Array ('type' => 'int', 'not_null' => 1, 'default' => 0,),
 		'Name' => Array ('type' => 'string', 'not_null' => '1', 'default' => '', 'required' =>true, 'max_len' =>255),
 		'Description' => Array ('type' => 'string', 'formatter' => 'kFormatter', 'using_fck' => 1, 'default' => NULL),
 		'URL' => Array ('type' => 'string', 'not_null' => '1', 'default' => '', 'max_len' =>255),
 		'Logo' => Array (
 			'type' => 'string',
 			'formatter' => 'kPictureFormatter',
 			'max_size' => MAX_UPLOAD_SIZE, 'upload_dir' => IMAGES_PATH.'manufacturers/',
-			'file_types' => '*.jpg;*.gif;*.png', 'files_description' => '!la_hint_ImageFiles!',
+			'file_types' => '*.jpg;*.jpeg;*.gif;*.png;*.bmp', 'files_description' => '!la_hint_ImageFiles!',
 			'multiple' => false, 'thumb_format' => 'resize:100x100',
 			'max_len' => 255, 'not_null' => 1, 'default' => ''
 		),
 		'IsPopular' => Array (
 			'type' => 'int',
 			'formatter' => 'kOptionsFormatter',
 			'options' => Array (0 => 'la_No', 1 => 'la_Yes'), 'use_phrases' => 1,
 			'not_null' => 1, 'default' => 0,
 		),
 		'Email' => Array ('type' => 'string', 'formatter' => 'kFormatter', 'regexp' => '/^(' . REGEX_EMAIL_USER . '@' . REGEX_EMAIL_DOMAIN . ')$/i', 'sample_value' => 'email@domain.com', 'default' => null, 'error_msgs' => Array ('invalid_format' => '!la_invalid_email!') ),
 		'Phone' => Array ('type' => 'string', 'default' => null),
 		'Fax' => Array ('type' => 'string', 'default' => null),
 		'Address1' => Array ('type' => 'string', 'default' => null),
 		'Address2' => Array ('type' => 'string', 'default' => null),
 		'City' => Array ('type' => 'string', 'default' => null),
 		'State' => Array ('type' => 'string', 'formatter' => 'kOptionsFormatter', 'options' => Array (), 'option_key_field' => 'DestAbbr', 'option_title_field' => 'Translation', 'default' => null),
 		'Zip' => Array ('type' => 'string', 'default' => null),
 		'Country' => Array (
 			'type' => 'string',
 			'formatter' => 'kOptionsFormatter',
 			'options_sql' => '	SELECT IF(l%2$s_Name = "", l%3$s_Name, l%2$s_Name) AS Name, IsoCode
 								FROM '.TABLE_PREFIX.'CountryStates
 								WHERE Type = ' . DESTINATION_TYPE_COUNTRY . '
 								ORDER BY Name',
 			'option_key_field' => 'IsoCode', 'option_title_field' => 'Name', 'default' => null
 		),
 	),
 
 	'Grids' => Array (
 		'Default' => Array (
 			'Icons' => Array (
 				'default' => 'icon16_item.png',
 				0 => 'icon16_disabled.png',
 				1 => 'icon16_item.png',
 				'module' => 'core',
 			),
 			'Fields' => Array (
 				'ManufacturerId' => Array ('title' => 'column:la_fld_Id', 'data_block' => 'grid_checkbox_td', 'filter_block' => 'grid_range_filter', 'width' => 60, ),
 				'Name' => Array ('title' => 'la_col_ManufacturerName', 'filter_block' => 'grid_like_filter', 'width' => 200, ),
 				'IsPopular' => Array ('title' => 'la_col_IsPopular', 'filter_block' => 'grid_options_filter', 'width' => 100, ),
 				'URL' => Array ('filter_block' => 'grid_like_filter', 'width' => 250, ),
 			),
 		),
 	),
 
 	'ConfigMapping' => Array (
 		'PerPage' => 'Comm_Perpage_Manufacturers',
 		'ShortListPerPage' => 'Comm_Perpage_Manufacturers_Short',
 	),
 );
\ No newline at end of file
Index: branches/5.3.x/units/shipping/shipping_tag_processor.php
===================================================================
--- branches/5.3.x/units/shipping/shipping_tag_processor.php	(revision 15670)
+++ branches/5.3.x/units/shipping/shipping_tag_processor.php	(revision 15671)
@@ -1,323 +1,337 @@
 <?php
 /**
 * @version	$Id$
 * @package	In-Commerce
 * @copyright	Copyright (C) 1997 - 2009 Intechnic. All rights reserved.
 * @license	Commercial License
 * This software is protected by copyright law and international treaties.
 * Unauthorized reproduction or unlicensed usage of the code of this program,
 * or any portion of it may result in severe civil and criminal penalties,
 * and will be prosecuted to the maximum extent possible under the law
 * See http://www.in-portal.org/commercial-license for copyright notices and details.
 */
 
 defined('FULL_PATH') or die('restricted access!');
 
+// include globals.php from current folder
+kUtil::includeOnce(MODULES_PATH . '/in-commerce/units/pricing/globals.php');
+
 class ShippingTagProcessor extends kDBTagProcessor {
 
 	function CostInputSize($params)
 	{
 		$object = $this->Application->recallObject( $this->getPrefixSpecial() );
 		$prec_before_sep = $object->GetDBField('PrecisionBeforeSep');
 		$prec_after_sep = $object->GetDBField('PrecisionAfterSep');
 		return $prec_before_sep + $prec_after_sep + 1 + ($prec_before_sep > 3 ? 1:0);
 	}
 
 	function ShowCostsTable($params)
 	{
 		$object = $this->Application->recallObject( $this->getPrefixSpecial() );
 		$zones_object = $this->Application->recallObject('z');
 		$brackets_object = $this->Application->recallObject('br');
 
 		$costs_object = $this->Application->recallObject('sc');
 		/* @var $costs_object kDBItem */
 
 		$main_processor = $this->Application->recallObject('m_TagProcessor');
 
 		$zones_sql = 'SELECT * FROM '.$zones_object->TableName.' WHERE ShippingTypeID='.$this->Application->GetVar('s_id').' ORDER BY Name ASC';
 		$brackets_sql = 'SELECT * FROM '.$brackets_object->TableName.' WHERE ShippingTypeID='.$this->Application->GetVar('s_id').' ORDER BY Start ASC';
 
 		$sql = 'SELECT * FROM '.$costs_object->TableName;
 		$costs_array = $this->Conn->Query($sql, 'ShippingCostId');
 
 		$zones = $this->Conn->Query($zones_sql, 'ZoneID');
 		$brackets = $this->Conn->Query($brackets_sql, 'BracketId');
 
 		$oddevenparam['odd'] = 'table-color1';
 		$oddevenparam['even'] = 'table-color2';
 
 		if(!$zones || !$brackets)
 		{
 			return '<tr class="'.$main_processor->Odd_Even($oddevenparam).'"><td>'.$this->Application->Phrase('la_NoZonesOrBrackets').'</td></tr>';
 		}
 
 		uasort($brackets, 'bracket_comp');
 
 		if( $this->Application->GetLinkedVar('CostsTableAligment') )
 		{
 			$column_items = $brackets;
 			$column_object =& $brackets_object;
 			$column_params['header_caption'] = 'bracket_caption';
 			$column_params['IdField'] = 'BracketId';
 			$column_params['prefix'] = 'br';
 
 			$row_items = $zones;
 			$row_object =& $zones_object;
 			$row_params['header_caption'] = 'zone_caption';
 			$row_params['IdField'] = 'ZoneID';
 			$row_params['prefix'] = 'z';
 		}
 		else
 		{
 			$column_items = $zones;
 			$column_object =& $zones_object;
 			$column_params['header_caption'] = 'zone_caption';
 			$column_params['IdField'] = 'ZoneID';
 			$column_params['prefix'] = 'z';
 
 			$row_items = $brackets;
 			$row_object =& $brackets_object;
 			$row_params['header_caption'] = 'bracket_caption';
 			$row_params['IdField'] = 'BracketId';
 			$row_params['prefix'] = 'br';
 		}
 
 		$costs_table = '<tr class="'.$main_processor->Odd_Even($oddevenparam).'"><td>&nbsp;</td>';
 
 		foreach($column_items as $id => $record)
 		{
 			$column_object->Load($id);
 			$head_row_params = $column_params;
 			$head_row_params['name'] = 'column_header';
 			$costs_table .= $this->Application->ParseBlock($head_row_params);
 		}
 		$costs_table .= '</tr>';
 
 		$cost_ids = Array();
 		foreach($row_items as $id =>$record)
 		{
 			$costs_table .= '<tr class="'.$main_processor->Odd_Even($oddevenparam).'">';
 			$row_object->Load($id);
 			$head_row_params = $row_params;
 			$head_row_params['name'] = 'row_header';
 			$costs_table .= $this->Application->ParseBlock($head_row_params);
 			foreach($column_items as $col_id => $col_record)
 			{
 				$res = false;
 
 				foreach($costs_array as $cost_id => $cost_record)
 				{
 					if($cost_record[$row_params['IdField']] == $id && $cost_record[$column_params['IdField']] == $col_id)
 					{
 						$costs_object->SetDBFieldsFromHash($cost_record);
 						$res = true;
 						break;
 					}
 				}
 
 				if($res == false)
 				{
 					$costs_object->Clear();
 					$sql = 'SELECT MIN(ShippingCostId) FROM '.$costs_object->TableName;
 					$new_id = $cost_ids ? min( $this->Conn->GetOne($sql) - 1, min($cost_ids) - 1 ) : 0;
 					$costs_object->SetDBField( 'ShippingCostId', $new_id );
 					$cost_ids[] = $new_id;
 				}
 				$column_object->Load($col_id);
 				$costs_object->SetID($costs_object->GetDBField('ShippingCostId'));
 				$cost_cell_params['name'] = 'cost_cell';
 
 				$costs_table .= $this->Application->ParseBlock($cost_cell_params);
 			}
 			$costs_table .= '</tr>';
 		}
 		return $costs_table;
 	}
 
 	function HiddenSelection($params)
 	{
 		// $object = $this->getPrefixSpecial();
 
 		$zones = $this->Application->GetVar('z');
 		$brackets = $this->Application->GetVar('br');
 
 		$ret = '';
 		foreach($zones as $id => $record)
 		{
 			$ret .= '<input type="hidden" name="z['.$id.'][ZoneID]" value="'.$id.'">'."\n";
 		}
 		foreach ($brackets as $id => $record)
 		{
 			$ret .= '<input type="hidden" name="br['.$id.'][BracketId]" value="'.$id.'">'."\n";
 		}
 		return $ret;
 	}
 
 	function Order_PrintShippingTypes($params)
 	{
 		$weight = $this->Application->Parser->GetParam('weight_metric');
 		$items = $this->Application->Parser->GetParam('items');
 		$amount = $this->Application->Parser->GetParam('amount');
 		$selected_id = $this->Application->Parser->GetParam('selected_id');
 		$package_id = $this->Application->Parser->GetParam('package_num');
 
 		// free promo shipping params if applicable, if not then the same as standard
 		$promo_items = $this->Application->Parser->GetParam('promo_items');
 		$promo_amount = $this->Application->Parser->GetParam('promo_amount');
 		$promo_weight = $this->Application->Parser->GetParam('promo_weight_metric');
 
 		$user_country_id = $this->Application->Parser->GetParam('user_country_id');
 		$user_state_id = $this->Application->Parser->GetParam('user_state_id');
 		$user_zip = $this->Application->Parser->GetParam('user_zip');
 		$user_city = $this->Application->Parser->GetParam('user_city');
 		$user_addr1 = $this->Application->Parser->GetParam('user_addr1');
 		$user_addr2 = $this->Application->Parser->GetParam('user_addr2');
 		$user_name = $this->Application->Parser->GetParam('user_name');
 
 		$limit_types = $this->Application->Parser->GetParam('limit_types');
 
 		$this->Application->recallObject('ShippingQuoteEngine'); // TODO: why call this here?
 
 		$quote_engine_collector = $this->Application->recallObject('ShippingQuoteCollector');
 		/* @var $quote_engine_collector ShippingQuoteCollector */
 
 		$shipping_quote_params = Array (
 			'dest_country'	=>	$user_country_id,
 			'dest_state'	=>	$user_state_id,
 			'dest_postal'	=>	$user_zip,
 			'dest_city'		=>	$user_city,
 			'dest_addr1'	=>	$user_addr1,
 			'dest_addr2'	=>	$user_addr2,
 			'dest_name'		=>	$user_name,
 			'packages' 		=>	Array (
 				Array (
 					'package_key'	=>	'package1',
 					'weight'		=>	$weight,
 					'weight_unit'	=>	'KG',
 					'length'		=>	'',
 					'width'			=>	'',
 					'height'		=>	'',
 					'dim_unit'		=>	'IN',
 					'packaging'		=>	'BOX',
 					'contents'		=>	'OTR',
 					'insurance'		=>	'0'
 				),
 			),
 			'amount'		=>	$amount,
 			'items'			=>	$items,
 			'limit_types' 	=> 	$limit_types,
 			'promo_params'	=>	Array (
 				'items'		=>	$promo_items,
 				'amount'	=>	$promo_amount,
 				'weight'	=>	$promo_weight,
 			)
 		);
 
 		$shipping_types = $quote_engine_collector->GetShippingQuotes($shipping_quote_params);
 
 		$last_shippings = $this->Application->RecallVar('LastShippings');
 		if ( $last_shippings ) {
 			$last_shippings = unserialize($last_shippings);
 		}
 
 		$order_object = $this->Application->recallObject('ord');
 		/* @var $order_object OrdersItem */
 
 		$original_shipping = $order_object->GetDBField('ShippingInfo');
 		$original_shipping = unserialize($original_shipping);
 		$shipping_type_keys = array_keys($shipping_types);
 
 		if(	getArrayValue($original_shipping, $package_id, 'ShippingId') &&
 			( $this->Application->isAdminUser || in_array( $original_shipping[$package_id]['ShippingId'], $shipping_type_keys ) ) )
 		{
 			$original_shipping = $original_shipping[$package_id];
 			$key = $original_shipping['ShippingId'];
 			$shipping_types[$key]['TotalCost'] = $this->Application->isAdminUser ? $original_shipping['TotalCost'] : $shipping_types[$key]['TotalCost'];
 			$shipping_types[$key]['ShippingName'] = $this->Application->isAdminUser ? 'Original: '.$original_shipping['ShippingName'] : $shipping_types[$key]['ShippingName'];
 			$shipping_types[$key]['ShippingId'] = $key;
 			$selected_id = $key;
 		}
 
 		$last_shippings[$package_id] = $shipping_types;
 		if ( $this->Application->isAdminUser && $key ) {
 			$orig_name = ltrim($last_shippings[$package_id][$key]['ShippingName'], 'Original: ');
 			$last_shippings[$package_id][$key]['ShippingName'] = $orig_name;
 		}
 		$this->Application->StoreVar('LastShippings', serialize($last_shippings));
 
 		$o = '';
 		$def_block_params = Array();
 		$def_block_params['name'] = $this->SelectParam($params, 'render_as,block');
 
 		if ( !count($shipping_types) ) {
 			$this->Application->SetVar('ItemShipmentsExists', 0);
 
 			return '';
 		}
 
 		$lang = $this->Application->recallObject('lang.current');
 		/* @var $lang LanguagesItem */
 
 		foreach ($shipping_types as $shipping_type) {
 			if ( isset($shipping_type['InsuranceFee']) ) {
 				$shipping_type['TotalCost'] += $shipping_type['InsuranceFee'];
 			}
 
 			$shipping_type['ShippingFree'] = ($shipping_type['TotalCost'] == 0) ? 1 : 0;
 
 			$iso = $this->GetISO($params['currency']);
 			$amount = $this->ConvertCurrency($shipping_type['TotalCost'], $iso);
 			$amount = $lang->formatNumber($amount, 2);
 			$shipping_type['TotalCost'] = $this->AddCurrencySymbol($amount, $iso);
 
 			$block_params = array_merge($def_block_params, $shipping_type);
 			$block_params['selected'] = $shipping_type['ShippingId'] == $selected_id ? 'selected' : '';
 
 			if ( isset($params['selected_only']) && $block_params['selected'] == '' ) {
 				continue;
 			}
 
 			$o .= $this->Application->ParseBlock($block_params);
 		}
 
 		return $o;
 	}
 
 	function AvailableTypes($params)
 	{
 		$quote_engine_collector = $this->Application->recallObject('ShippingQuoteCollector');
 		/* @var $quote_engine_collector ShippingQuoteCollector */
 
 		$types = $quote_engine_collector->GetAvailableShippingTypes();
 
 		$o;
 		foreach ($types as $a_type)
 		{
 			$block_params = $a_type;
 			$block_params['name']	= $params['render_as'];
 			$o .= $this->Application->ParseBlock($block_params);
 		}
 		return $o;
 	}
 
-	function ListGroups($params)
+	protected function ListGroups($params)
 	{
-
 		$object = $this->getObject($params);
+		/* @var $object kDBItem */
+
+		$o = '';
 		$selected = trim($object->GetDBField('PortalGroups'), ',');
 		$selected_arr = explode(',', $selected);
-		$all_groups = $this->Conn->Query('SELECT GroupId, Name FROM '.TABLE_PREFIX.'UserGroups ORDER BY NAME', 'GroupId');
 
-		$o = '';
-		foreach ($all_groups as $a_group)
-		{
+		$sql = 'SELECT GroupId, Name
+				FROM ' . TABLE_PREFIX . 'UserGroups
+				ORDER BY Name';
+		$all_groups = $this->Conn->Query($sql, 'GroupId');
+
+		$mode = array_key_exists('mode', $params) ? $params['mode'] : false;
+
+		foreach ($all_groups as $a_group) {
 			$is_selected = in_array($a_group['GroupId'], $selected_arr);
-			$continue = $params['mode'] == 'selected' ? !$is_selected : $is_selected;
-			if ($continue) continue;
+			$continue = $mode == 'selected' ? !$is_selected : $is_selected;
+
+			if ( $continue ) {
+				continue;
+			}
+
 			$block_params = $a_group;
-			$block_params['name']	= $params['render_as'];
+			$block_params['name'] = $params['render_as'];
 			$o .= $this->Application->ParseBlock($block_params);
 		}
+
 		return $o;
 	}
 }
\ No newline at end of file
Index: branches/5.3.x/units/taxes/taxes_event_handler.php
===================================================================
--- branches/5.3.x/units/taxes/taxes_event_handler.php	(revision 15670)
+++ branches/5.3.x/units/taxes/taxes_event_handler.php	(revision 15671)
@@ -1,252 +1,253 @@
 <?php
 /**
 * @version	$Id$
 * @package	In-Commerce
 * @copyright	Copyright (C) 1997 - 2009 Intechnic. All rights reserved.
 * @license	Commercial License
 * This software is protected by copyright law and international treaties.
 * Unauthorized reproduction or unlicensed usage of the code of this program,
 * or any portion of it may result in severe civil and criminal penalties,
 * and will be prosecuted to the maximum extent possible under the law
 * See http://www.in-portal.org/commercial-license for copyright notices and details.
 */
 
 defined('FULL_PATH') or die('restricted access!');
 
 class TaxesEventHandler extends kDBEventHandler {
 
 	/**
 	 * Allows to override standard permission mapping
 	 *
 	 * @return void
 	 * @access protected
 	 * @see kEventHandler::$permMapping
 	 */
 	protected function mapPermissions()
 	{
 		parent::mapPermissions();
 
 		$permissions = Array(
 			'OnTypeChange'		=>	Array('self' => 'add|edit'),
 			'OnCountryChange'	=>	Array('self' => 'add|edit'),
 		);
 
 		$this->permMapping = array_merge($this->permMapping, $permissions);
 	}
 
 	/**
 	 * Define alternative event processing method names
 	 *
 	 * @return void
 	 * @see kEventHandler::$eventMethods
 	 * @access protected
 	 */
 	protected function mapEvents()
 	{
 		parent::mapEvents();	// ensure auto-adding of approve/decine and so on events
 
 		$zones_events = Array (
 			'OnAddLocation'		=>	'DestinationAction',
 			'OnRemoveLocation'	=>	'DestinationAction',
 			'OnLoadZoneForm'	=>	'DestinationAction',
 			/*'OnCountryChange'	=>	'DestinationAction',*/
 			'OnNew'				=>	'DestinationAction'
 		);
 
 		$this->eventMethods = array_merge($this->eventMethods, $zones_events);
 	}
 
 	/**
 	 * Apply custom processing to item
 	 *
 	 * @param kEvent $event
 	 * @param string $type
 	 * @return void
 	 * @access protected
 	 */
 	protected function customProcessing(kEvent $event, $type)
 	{
 		$zone_object = $event->getObject();
 		/* @var $zone_object kDBItem */
 
 		if ( $type == 'after' ) {
 			$dst_object = $this->Application->recallObject('taxdst');
 			/* @var $dst_object kDBItem */
 
 			if ( $event->Name == 'OnUpdate' ) {
 				$sql = 'DELETE FROM ' . $dst_object->TableName . '
 						WHERE TaxZoneId = ' . $zone_object->GetID();
 				$this->Conn->Query($sql);
 			}
 			else {
 				$temp = $this->Application->GetVar('taxdst', Array ());
 
 				foreach ($temp as $key => $value) {
 					$temp[$key]['TaxZoneId'] = $zone_object->GetID();
 				}
 
 				$this->Application->SetVar('taxdst', $temp);
 			}
 
 			$this->Application->HandleEvent(new kEvent('taxdst:OnCreate'));
 		}
 	}
 
 	/**
 	 * Enter description here...
 	 *
 	 * @param kEvent $event
 	 */
 	function OnTypeChange($event)
 	{
 		$this->Application->DeleteVar('taxdst');
 		$event->CallSubEvent('OnPreSave');
 		$event->redirect = false;
 	}
 
 	/**
 	 * Enter description here...
 	 *
 	 * @param kEvent $event
 	 */
 	function DestinationAction($event)
 	{
 		$event->redirect = false;
 
 		$items_info = $this->Application->GetVar( $event->getPrefixSpecial(true) );
 		if($items_info)
 		{
 			foreach($items_info as $item_id => $field_values)
 			{
 				// this is to receive $item_id
 			}
 		}
 
 		$object = $event->getObject( Array('skip_autoload' => true) );
 		$object->Load($item_id);
 
 		$object->SetFieldsFromHash($field_values);
 		$object->SetDBField('TaxZoneID', $item_id);
 
 		$destination = $this->Application->recallObject('taxdst');
 		$tax_object = $this->Application->recallObject('tax');
 
 		switch($event->Name)
 		{
 			case 'OnAddLocation':
 
 				$temp = $this->Application->GetVar('taxdst');
 				$zip = $this->Application->GetVar('zip_input') ? $this->Application->GetVar('zip_input') : $this->Application->GetVar('zip_dropdown');
 				$exist=0;
 
 				switch ($object->GetDBField('Type'))
 				{
 					case 1:
 						$location_id = $this->Application->GetVar('country');
 						break;
 					case 2:
 						$location_id = $this->Application->GetVar('state');
 						break;
 					default:
 						$location_id = $this->Application->GetVar('StatesCountry');
 						foreach($temp as $temp_id => $temp_val){
 							if ($temp_val['DestValue']==$zip){
 								$exist=1;
 								break;
 							}
 						}
 				}
 
 				if ($exist == 0){
 					$new_id = (int)$this->Conn->GetOne('SELECT MIN('.$destination->IDField.') FROM '.$destination->TableName);
 
 					if($new_id > 0) $new_id = 0;
 					do
 					{
 						$new_id--;
 					} while ($this->check_array($this->Application->GetVar('taxdst'), 'TaxZoneDestId', $new_id));
 
 
 
 
 					if( ($location_id && !$this->check_array($temp, 'StdDestId', $location_id)) ||
 							($zip && !$this->check_array($temp, 'DestValue', $zip)) )
 					{
 
 						if($tax_object->GetDBField('Type') == 3 && $zip ==''){
 							continue;
 						}
 
 						$temp[$new_id]['TaxZoneDestId'] = $new_id;
 						$temp[$new_id]['StdDestId'] = $location_id;
 						$temp[$new_id]['DestValue'] = $zip ? $zip : '';
 
 						$this->Application->SetVar('taxdst', $temp);
 					}
 				}
 				break;
 
 			case 'OnRemoveLocation':
 
 				$temp = $this->Application->GetVar('taxdst');
 				$selected_destinations = explode(',', $this->Application->GetVar('selected_destinations'));
 				foreach ($selected_destinations as $dest)
 				{
 					unset( $temp[$dest] );
 					if (strlen($dest)>0){
 						$sql = 'DELETE FROM '.$destination->TableName.' WHERE TaxZoneDestId ='.$dest;
 						$this->Conn->Query($sql);
 					}
 				}
 				$this->Application->SetVar('taxdst', $temp);
 
 				break;
 
 			case 'OnLoadZoneForm':
 
 				$sql = 'SELECT * FROM '.$destination->TableName.' WHERE TaxZoneId='.$item_id;
 				$res = $this->Conn->Query($sql);
 				$temp = Array();
 				foreach ($res as $dest_record)
 				{
 					$temp[$dest_record['TaxZoneDestId']]['TaxZoneDestId'] = $dest_record['TaxZoneDestId'];
 					$temp[$dest_record['TaxZoneDestId']]['StdDestId'] = $dest_record['StdDestId'];
 					$temp[$dest_record['TaxZoneDestId']]['DestValue'] = $dest_record['DestValue'];
 				}
 				$this->Application->SetVar('taxdst', $temp);
 				//$object = $event->getObject();
 				//$object->SetDBField('ShippingTypeID', $this->Application->GetVar('s_id'));
 
 				break;
 
 			case 'OnNew':
 
 				//$object = $event->getObject();
 				//$object->SetDBField('ShippingTypeID', $this->Application->GetVar('s_id'));
 				break;
 
 			case 'OnCountryChange':
 
 				$this->Application->DeleteVar('taxdst');
 
 				break;
 
 			default:
 		}
 
 		$event->CallSubEvent("OnPreSave");
 	}
 
 	function OnCountryChange($event)
 	{
-		$destinations = &$this->Application->recallObject('taxdst');
+		$destinations = $this->Application->recallObject('taxdst');
+		/* @var $destinations kDBItem */
 
 		$queryDel="DELETE FROM ".$destinations->TableName." WHERE TaxZoneId=".(int)$this->Application->GetVar('tax_id');
 		$this->Conn->Query($queryDel);
 
 		$this->Application->DeleteVar('taxdst');
 		$event->CallSubEvent('OnPreSave');
 		$event->redirect = false;
 	}
 
 }
\ No newline at end of file
Index: branches/5.3.x/units/coupons/coupons_config.php
===================================================================
--- branches/5.3.x/units/coupons/coupons_config.php	(revision 15670)
+++ branches/5.3.x/units/coupons/coupons_config.php	(revision 15671)
@@ -1,181 +1,182 @@
 <?php
 /**
 * @version	$Id$
 * @package	In-Commerce
 * @copyright	Copyright (C) 1997 - 2009 Intechnic. All rights reserved.
 * @license	Commercial License
 * This software is protected by copyright law and international treaties.
 * Unauthorized reproduction or unlicensed usage of the code of this program,
 * or any portion of it may result in severe civil and criminal penalties,
 * and will be prosecuted to the maximum extent possible under the law
 * See http://www.in-portal.org/commercial-license for copyright notices and details.
 */
 
 defined('FULL_PATH') or die('restricted access!');
 
 $config = Array (
 	'Prefix' => 'coup',
 	'ItemClass' => Array ('class' => 'kDBItem', 'file' => '', 'build_event' => 'OnItemBuild'),
 	'ListClass' => Array ('class' => 'kDBList', 'file' => '', 'build_event' => 'OnListBuild'),
 	'EventHandlerClass' => Array ('class' => 'CouponsEventHandler', 'file' => 'coupons_event_handler.php', 'build_event' => 'OnBuild'),
 	'TagProcessorClass' => Array ('class' => 'CouponsTagProcessor', 'file' => 'coupons_tag_processor.php', 'build_event' => 'OnBuild'),
 
 	'AutoLoad' => true,
 
 	'QueryString' => Array (
 		1 => 'id',
 		2 => 'Page',
 		3 => 'PerPage',
 		4 => 'event',
 		5 => 'mode',
 	),
 
 	'IDField' => 'CouponId',
 	'StatusField' => Array ('Status'),
 	'TitleField' => 'Name',
 	'TableName' => TABLE_PREFIX.'ProductsCoupons',
 	'SubItems' => Array ('coupi'),
 
 	'TitlePresets' => Array (
 		'default' => Array (
 			'new_status_labels' => Array ('coup' => '!la_title_Adding_Coupon!'),
 			'edit_status_labels' => Array ('coup' => '!la_title_Editing_Coupon!'),
 			'new_titlefield' => Array ('coup' => '!la_title_New_Coupon!'),
 		),
 
 		'coupons_list' => Array (
 			'prefixes' => Array ('coup_List'), 'format' => "!la_title_Coupons!",
 		),
 
 		'coupons_edit' => Array (
 			'prefixes' => Array ('coup'),
 			'format' => "#coup_status# '#coup_titlefield#' - !la_title_General!",
 		),
 
 		'coupons_items' => Array (
 			'prefixes' => Array ('coup', 'coupi_List'),
 			'format' => "#coup_status# '#coup_titlefield#' - !la_title_CouponItems!",
 		),
 
 		'coupons_clone' => Array (
 			'prefixes' => Array ('coup'), 'format' => "!la_CloneCoupon!",
 		),
 
 		'coupon_selector' => Array ('format' => '!la_title_CouponSelector!'),
 	),
 
 	'EditTabPresets' => Array (
 		'Default' => Array (
 			'general' => Array ('title' => 'la_tab_General', 't' => 'in-commerce/discounts/coupon_edit', 'priority' => 1),
 			'items' => Array ('title' => 'la_tab_CouponsItems', 't' => 'in-commerce/discounts/coupon_items', 'priority' => 2),
 		),
 	),
 
 	'PermSection' => Array ('main' => 'in-commerce:coupons'),
 
 	'Sections' => Array (
 		'in-commerce:coupons' => Array (
 			'parent' => 'in-commerce:discounts_folder',
 			'icon' => 'discounts_coupons',
 			'label' => 'la_tab_Coupons',
 			'url' => Array ('t' => 'in-commerce/discounts/coupons_list', 'pass' => 'm'),
 			'permissions' => Array ('view', 'add', 'edit', 'delete', 'advanced:approve', 'advanced:decline'),
 			'priority' => 3.2, // <parent_priority>.<own_priority>, because this section replaces parent in tree
 			'type' => stTAB,
 		),
 	),
 
 	'ListSQLs' => Array (
 		'' => '	SELECT %1$s.* %2$s
 				FROM %1$s',
 	),
 
 	'ListSortings' => Array (
 		'' => Array (
 			'Sorting' => Array ('Name' => 'asc'),
 		)
 	),
 
 	'Fields' => Array (
 		'CouponId' => Array ('type' => 'int', 'not_null' => 1, 'default' => 0),
 		'Status' => Array (
 				'type' => 'int', 'formatter' => 'kOptionsFormatter',
 				'options' => Array ( 1 => 'la_Enabled', 2 => 'la_Used', 0 => 'la_Disabled' ),
 				'use_phrases' => 1, 'not_null' => 1, 'default' => 1
 		),
 		'Name' => Array ( 'type' =>'string', 'required' => 1, 'default' => null, 'max_len' => 255),
 		'Code' => Array (
 				'type' => 'string', 'required' => 1, 'default' => null,
 				'max_len' => 255, 'unique' => Array ('Code'),
 		),
 		'Expiration' => Array ('type' => 'int', 'formatter' => 'kDateFormatter', 'default' => null,),
 		'GroupId' => Array ('type' => 'int', 'default' => null, ),
 		'Type' => Array (
 				'type' => 'int', 'formatter' => 'kOptionsFormatter', 'use_phrases' => 1,
 				'options' => Array ( 1 => 'la_Flat', 2 => 'la_Percent'/*, 3 => 'la_FreeShipping'*/),
 				'not_null' => 1, 'default' => 1,
 		 ),
 		'Amount' => Array ('type' => 'double', 'default' => null),
 		'LastUsedBy' => Array (
-			'type' => 'int', 'formatter' => 'kLEFTFormatter',
+			'type' => 'int',
+			'formatter' => 'kLEFTFormatter',
 			'error_msgs' => Array ('invalid_option' => '!la_error_UserNotFound!'),
 			'options' => Array (USER_ROOT => 'root', USER_GUEST => 'Guest'),
-			'left_sql' => 'SELECT %s FROM ' . TABLE_PREFIX . 'Users
-								WHERE `%s` = \'%s\'', 'left_key_field' => 'PortalUserId',
-			'left_title_field' => 'Username', 'required' => 0, 'default' => null,
+			'left_sql' => 'SELECT %s FROM ' . TABLE_PREFIX . 'Users WHERE %s',
+			'left_key_field' => 'PortalUserId', 'left_title_field' => USER_TITLE_FIELD,
+			'required' => 0, 'default' => null,
 		),
 		'LastUsedOn' => Array ('type' => 'int', 'formatter' => 'kDateFormatter', 'default' => NULL),
 		'NumberOfUses' => Array ('type' => 'int', 'default' => 1),
 	),
 
 	'VirtualFields' => Array (
 		'CouponCount' => Array ('type' => 'int', 'min_value_inc' => 1, 'default' => 1),
 		'DefaultExpiration' => Array ('type' => 'int', 'formatter' => 'kDateFormatter', 'default' => NULL),
 	),
 
 	'Grids' => Array (
 		'Default' => Array (
 			'Icons' => Array (
 				'default' => 'icon16_item.png',
 				0 => 'icon16_disabled.png',
 				1 => 'icon16_item.png',
 				2 => 'icon16_pending.png',
 				'module' => 'core',
 			),
 			'Fields' => Array (
 				'CouponId' => Array ('title' => 'column:la_fld_Id', 'data_block' => 'grid_checkbox_td', 'filter_block' => 'grid_range_filter', 'width' => 60, ),
 				'Name' => Array ('filter_block' => 'grid_like_filter', 'width' => 150, ),
 				'Code' => Array ('title' => 'column:la_fld_CouponCode', 'filter_block' => 'grid_like_filter', 'width' => 100, ),
 				'Expiration' => Array ('filter_block' => 'grid_date_range_filter', 'width' => 145, ),
 				'Type' => Array ('filter_block' => 'grid_options_filter', 'width' => 100, ),
 				'Status' => Array ('filter_block' => 'grid_options_filter', 'width' => 100, ),
 				'Amount' => Array ('filter_block' => 'grid_range_filter', 'width' => 100, ),
 				'LastUsedBy' => Array ('filter_block' => 'grid_like_filter', 'width' => 140, ),
 				'LastUsedOn' => Array ('filter_block' => 'grid_date_range_filter', 'width' => 140, ),
 				'NumberOfUses' => Array ('filter_block' => 'grid_range_filter', 'width' => 130, ),
 			),
 		),
 		'Radio' => Array (
 			'Icons' => Array (
 				'default' => 'icon16_item.png',
 				0 => 'icon16_disabled.png',
 				1 => 'icon16_item.png',
 				2 => 'icon16_pending.png',
 				'module' => 'core',
 			),
 			'Selector' => 'radio',
 			'Fields' => Array (
 				'CouponId' => Array ('title' => 'column:la_fld_Id', 'data_block' => 'grid_radio_td', 'filter_block' => 'grid_range_filter', 'width' => 60, ),
 				'Name' => Array ('filter_block' => 'grid_like_filter', 'width' => 150, ),
 				'Code' => Array ('title' => 'column:la_fld_CouponCode', 'filter_block' => 'grid_like_filter', 'width' => 100, ),
 				'Expiration' => Array ('filter_block' => 'grid_date_range_filter', 'width' => 145, ),
 				'Type' => Array ('filter_block' => 'grid_options_filter', 'width' => 100, ),
 				'Status' => Array ('filter_block' => 'grid_options_filter', 'width' => 100, ),
 				'Amount' => Array ('filter_block' => 'grid_range_filter', 'width' => 100, ),
 				'LastUsedBy' => Array ('filter_block' => 'grid_like_filter', 'width' => 140, ),
 				'LastUsedOn' => Array ('filter_block' => 'grid_date_range_filter', 'width' => 140, ),
 				'NumberOfUses' => Array ('filter_block' => 'grid_range_filter', 'width' => 130, ),
 			),
 		),
 	),
 );
\ No newline at end of file
Index: branches/5.3.x/units/zones/zones_event_handler.php
===================================================================
--- branches/5.3.x/units/zones/zones_event_handler.php	(revision 15670)
+++ branches/5.3.x/units/zones/zones_event_handler.php	(revision 15671)
@@ -1,275 +1,276 @@
 <?php
 /**
 * @version	$Id$
 * @package	In-Commerce
 * @copyright	Copyright (C) 1997 - 2009 Intechnic. All rights reserved.
 * @license	Commercial License
 * This software is protected by copyright law and international treaties.
 * Unauthorized reproduction or unlicensed usage of the code of this program,
 * or any portion of it may result in severe civil and criminal penalties,
 * and will be prosecuted to the maximum extent possible under the law
 * See http://www.in-portal.org/commercial-license for copyright notices and details.
 */
 
 defined('FULL_PATH') or die('restricted access!');
 
 class ZonesEventHandler extends kDBEventHandler {
 
 	/**
 	 * Allows to override standard permission mapping
 	 *
 	 * @return void
 	 * @access protected
 	 * @see kEventHandler::$permMapping
 	 */
 	protected function mapPermissions()
 	{
 		parent::mapPermissions();
 
 		$permissions = Array(
 			'OnTypeChange'		=>	Array('subitem' => 'add|edit'),
 			'OnCountryChange'	=>	Array('subitem' => 'add|edit'),
 			'OnLoadZoneForm'	=>	Array('subitem' => 'add|edit'),
 		);
 
 		$this->permMapping = array_merge($this->permMapping, $permissions);
 	}
 
 	/**
 	 * Define alternative event processing method names
 	 *
 	 * @return void
 	 * @see kEventHandler::$eventMethods
 	 * @access protected
 	 */
 	protected function mapEvents()
 	{
 		parent::mapEvents();	// ensure auto-adding of approve/decline and so on events
 
 		$zones_events = Array(
 			'OnAddLocation'		=>	'DestinationAction',
 			'OnRemoveLocation'	=>	'DestinationAction',
 			'OnLoadZoneForm'	=>	'DestinationAction',
 			/*'OnCountryChange'	=>	'DestinationAction',*/
 		);
 
 		$this->eventMethods = array_merge($this->eventMethods, $zones_events);
 	}
 
 	/**
 	 * Apply custom processing to item
 	 *
 	 * @param kEvent $event
 	 * @param string $type
 	 * @return void
 	 * @access protected
 	 */
 	protected function customProcessing(kEvent $event, $type)
 	{
 		$zone_object = $event->getObject();
 		/* @var $zone_object kDBItem */
 
 		switch ($type) {
 			case 'before':
 				if ( $event->Name == 'OnCreate' ) {
 					$zone_object->SetDBField('ShippingTypeID', $this->Application->GetVar('s_id'));
 				}
 				break;
 
 			case 'after':
 				$dst_object = $this->Application->recallObject('dst');
 				/* @var $dst_object kDBItem */
 
 				if ( $event->Name == 'OnUpdate' ) {
 					$sql = 'DELETE FROM ' . $dst_object->TableName . '
 							WHERE ShippingZoneId = ' . $zone_object->GetID();
 					$this->Conn->Query($sql);
 				}
 				else {
 					$temp = $this->Application->GetVar('dst', Array ());
 					foreach ($temp as $key => $value) {
 						$temp[$key]['ShippingZoneId'] = $zone_object->GetID();
 					}
 					$this->Application->SetVar('dst', $temp);
 				}
 
 				$this->Application->HandleEvent(new kEvent('dst:OnCreate'));
 				break;
 		}
 	}
 
 	/**
 	 * Enter description here...
 	 *
 	 * @param kEvent $event
 	 */
 	function OnTypeChange($event)
 	{
 		$this->Application->DeleteVar('dst');
 
 		$event->CallSubEvent($this->Application->GetVar('z_OriginalSaveEvent'));
 		$event->redirect = false;
 	}
 
 	/**
 	 * Enter description here...
 	 *
 	 * @param kEvent $event
 	 */
 	function DestinationAction($event)
 	{
 		$event->redirect = false;
 
 		$items_info = $this->Application->GetVar( $event->getPrefixSpecial(true) );
 		if($items_info)
 		{
 			foreach($items_info as $item_id => $field_values)
 			{
 				// this is to receive $item_id
 			}
 		}
 
 		$object = $event->getObject( Array('skip_autoload' => true) );
 		$object->Load($item_id);
 
 		$object->SetFieldsFromHash($field_values);
 		$object->SetDBField('ZoneID', $item_id);
 
 		$destination = $this->Application->recallObject('dst');
 
 		switch($event->Name)
 		{
 			case 'OnAddLocation':
 				$new_id = (int)$this->Conn->GetOne('SELECT MIN('.$destination->IDField.') FROM '.$destination->TableName);
 				if($new_id > 0) $new_id = 0;
 				do
 				{
 					$new_id--;
 				} while ($this->check_array($this->Application->GetVar('dst'), 'ZoneDestId', $new_id));
 
 				switch ($object->GetDBField('Type'))
 				{
 					case 1:
 						$location_id = $this->Application->GetVar('country');
 						break;
 					case 2:
 						$location_id = $this->Application->GetVar('state');
 						break;
 					default:
 						$location_id = '';
 				}
 
 				$temp = $this->Application->GetVar('dst');
 				$zip = $this->Application->GetVar('zip_input') ? $this->Application->GetVar('zip_input') : $this->Application->GetVar('zip_dropdown');
 
 				if( ($location_id && !$this->check_array($temp, 'StdDestId', $location_id)) ||
 						($zip && !$this->check_array($temp, 'DestValue', $zip)) )
 				{
 					$temp[$new_id]['ZoneDestId'] = $new_id;
 					$temp[$new_id]['StdDestId'] = $location_id;
 					$temp[$new_id]['DestValue'] = $zip ? $zip : '';
 
 					$this->Application->SetVar('dst', $temp);
 				}
 				break;
 
 			case 'OnRemoveLocation':
 
 				$temp = $this->Application->GetVar('dst');
 				$selected_destinations = explode(',', $this->Application->GetVar('selected_destinations'));
 				foreach ($selected_destinations as $dest)
 				{
 					unset( $temp[$dest] );
 				}
 				$this->Application->SetVar('dst', $temp);
 
 				break;
 
 			case 'OnLoadZoneForm':
 
 				$sql = 'SELECT * FROM '.$destination->TableName.' WHERE ShippingZoneId='.$item_id;
 				$res = $this->Conn->Query($sql);
 				$temp = Array();
 				foreach ($res as $dest_record)
 				{
 					$temp[$dest_record['ZoneDestId']]['ZoneDestId'] = $dest_record['ZoneDestId'];
 					$temp[$dest_record['ZoneDestId']]['StdDestId'] = $dest_record['StdDestId'];
 					$temp[$dest_record['ZoneDestId']]['DestValue'] = $dest_record['DestValue'];
 				}
 				$this->Application->SetVar('dst', $temp);
 				$object = $event->getObject();
 				$object->SetDBField('ShippingTypeID', $this->Application->GetVar('s_id'));
 				$this->Application->StoreVar('zone_mode'.$this->Application->GetVar('m_wid'), 'edit');
 
 				break;
 
 			/*case 'OnNew':
 				$object = $event->getObject();
 				$object->SetDBField('ShippingTypeID', $this->Application->GetVar('s_id'));
 				break;*/
 
 			case 'OnCountryChange':
 
 				$this->Application->DeleteVar('dst');
 
 				break;
 
 			default:
 		}
 	}
 
 	function OnCountryChange($event)
 	{
-		$destinations = &$this->Application->recallObject('dst');
+		$destinations = $this->Application->recallObject('dst');
+		/* @var $destinations kDBItem */
 
 		$queryDel="DELETE FROM ".$destinations->TableName." WHERE ShippingZoneId=".$this->Application->GetVar($event->Prefix.'_id');
 		$this->Conn->Query($queryDel);
 
 		$this->Application->DeleteVar('dst');
 
 		$event->CallSubEvent($this->Application->GetVar('z_OriginalSaveEvent'));
 		$event->redirect = false;
 	}
 
 	/**
 	 * Cancels kDBItem Editing/Creation
 	 *
 	 * @param kEvent $event
 	 * @return void
 	 * @access protected
 	 */
 	protected function OnCancel(kEvent $event)
 	{
 		parent::OnCancel($event);
 
-		$dst_object = &$this->Application->recallObject('dst');
+		$dst_object = $this->Application->recallObject('dst');
 		/* @var $dst_object kDBItem */
 
 		$sql = 'DELETE FROM ' . $dst_object->TableName . '
 				WHERE ShippingZoneId = 0';
 		$this->Conn->Query($sql);
 
 		// if cancelling after create
 		if ( $this->Application->RecallVar('zone_mode' . $this->Application->GetVar('m_wid')) == 'create' ) {
 			$zone = $event->getObject();
 			/* @var $zone kDBItem */
 
 			$zone->Delete();
 		}
 	}
 
 	/**
 	 * Prepares new kDBItem object
 	 *
 	 * @param kEvent $event
 	 * @return void
 	 * @access protected
 	 */
 	protected function OnNew(kEvent $event)
 	{
 		parent::OnNew($event);
 
 		$this->Application->StoreVar('zone_mode' . $this->Application->GetVar('m_wid'), 'create');
 	}
 
 }
\ No newline at end of file
Index: branches/5.3.x/units/orders/orders_event_handler.php
===================================================================
--- branches/5.3.x/units/orders/orders_event_handler.php	(revision 15670)
+++ branches/5.3.x/units/orders/orders_event_handler.php	(revision 15671)
@@ -1,3984 +1,4003 @@
 <?php
 /**
 * @version	$Id$
 * @package	In-Commerce
 * @copyright	Copyright (C) 1997 - 2009 Intechnic. All rights reserved.
 * @license	Commercial License
 * This software is protected by copyright law and international treaties.
 * Unauthorized reproduction or unlicensed usage of the code of this program,
 * or any portion of it may result in severe civil and criminal penalties,
 * and will be prosecuted to the maximum extent possible under the law
 * See http://www.in-portal.org/commercial-license for copyright notices and details.
 */
 
 defined('FULL_PATH') or die('restricted access!');
 
 class OrdersEventHandler extends kDBEventHandler
 {
 
 	/**
 	 * Checks user permission to execute given $event
 	 *
 	 * @param kEvent $event
 	 * @return bool
 	 * @access public
 	 */
 	public function CheckPermission(kEvent $event)
 	{
 		if ( !$this->Application->isAdminUser ) {
 			if ( $event->Name == 'OnCreate' ) {
 				// user can't initiate custom order creation directly
 				return false;
 			}
 
 			$user_id = $this->Application->RecallVar('user_id');
 			$items_info = $this->Application->GetVar($event->getPrefixSpecial(true));
 			if ( $items_info ) {
 				// when POST is present, then check when is beeing submitted
 				$order_session_id = $this->Application->RecallVar($event->getPrefixSpecial(true) . '_id');
 
 				$order_dummy = $this->Application->recallObject($event->Prefix . '.-item', null, Array ('skip_autoload' => true));
 				/* @var $order_dummy OrdersItem */
 
 				foreach ($items_info as $id => $field_values) {
 					if ( $order_session_id != $id ) {
 						// user is trying update not his order, even order from other guest
 						return false;
 					}
 
 					$order_dummy->Load($id);
 
 					// session_id matches order_id from submit
 					if ( $order_dummy->GetDBField('PortalUserId') != $user_id ) {
 						// user performs event on other user order
 						return false;
 					}
 
-					$status_field = array_shift($this->Application->getUnitOption($event->Prefix, 'StatusField'));
+					$status_field = $order_dummy->getStatusField();
+
 					if ( isset($field_values[$status_field]) && $order_dummy->GetDBField($status_field) != $field_values[$status_field] ) {
 						// user can't change status by himself
 						return false;
 					}
 
 					if ( $order_dummy->GetDBField($status_field) != ORDER_STATUS_INCOMPLETE ) {
 						// user can't edit orders being processed
 						return false;
 					}
 
 					if ( $event->Name == 'OnUpdate' ) {
 						// all checks were ok -> it's user's order -> allow to modify
 						return true;
 					}
 				}
 			}
 		}
 
 		if ( $event->Name == 'OnQuietPreSave' ) {
 			$section = $event->getSection();
 
 			if ( $this->isNewItemCreate($event) ) {
 				return $this->Application->CheckPermission($section . '.add', 1);
 			}
 			else {
 				return $this->Application->CheckPermission($section . '.add', 1) || $this->Application->CheckPermission($section . '.edit', 1);
 			}
 		}
 
 		return parent::CheckPermission($event);
 	}
 
 	/**
 	 * Allows to override standard permission mapping
 	 *
 	 * @return void
 	 * @access protected
 	 * @see kEventHandler::$permMapping
 	 */
 	protected function mapPermissions()
 	{
 		parent::mapPermissions();
 
 		$permissions = Array (
 			// admin
 			'OnRecalculateItems'	=>	Array('self' => 'add|edit'),
 			'OnResetToUser'			=>	Array('self' => 'add|edit'),
 			'OnResetToBilling'		=>	Array('self' => 'add|edit'),
 			'OnResetToShipping'		=>	Array('self' => 'add|edit'),
 			'OnMassOrderApprove'	=>	Array('self' => 'advanced:approve'),
 			'OnMassOrderDeny'		=>	Array('self' => 'advanced:deny'),
 			'OnMassOrderArchive'	=>	Array('self' => 'advanced:archive'),
 			'OnMassPlaceOrder'		=>	Array('self' => 'advanced:place'),
 			'OnMassOrderProcess'	=>	Array('self' => 'advanced:process'),
 			'OnMassOrderShip'		=>	Array('self' => 'advanced:ship'),
 			'OnResetToPending'		=>	Array('self' => 'advanced:reset_to_pending'),
 			'OnLoadSelected'		=>	Array('self' => 'view'),	// print in this case
 			'OnGoToOrder'			=>	Array('self' => 'view'),
 
 			// front-end
 			'OnViewCart'			=>	Array('self' => true),
 			'OnAddToCart'			=>	Array('self' => true),
 			'OnRemoveFromCart'		=>	Array('self' => true),
 			'OnUpdateCart'			=>	Array('self' => true),
 			'OnUpdateCartJSON'		=>	Array('self' => true),
 			'OnUpdateItemOptions'	=>	Array('self' => true),
 			'OnCleanupCart'			=>	Array('self' => true),
 			'OnContinueShopping'	=>	Array('self' => true),
 			'OnCheckout'			=>	Array('self' => true),
 			'OnSelectAddress'		=>	Array('self' => true),
 			'OnProceedToBilling'	=>	Array('self' => true),
 			'OnProceedToPreview'	=>	Array('self' => true),
 			'OnCompleteOrder'		=>	Array('self' => true),
 			'OnUpdateAjax'			=>	Array('self' => true),
 
 			'OnRemoveCoupon'		=>	Array('self' => true),
 			'OnRemoveGiftCertificate'		=>	Array('self' => true),
 
 			'OnCancelRecurring'		=>	Array('self' => true),
 			'OnAddVirtualProductToCart'		=>	Array('self' => true),
 			'OnItemBuild'		=>	Array('self' => true),
 			'OnDownloadLabel' 	=>  Array('self' => true, 'subitem' => true),
 		);
 
 		$this->permMapping = array_merge($this->permMapping, $permissions);
 	}
 
 	/**
 	 * Define alternative event processing method names
 	 *
 	 * @return void
 	 * @see kEventHandler::$eventMethods
 	 * @access protected
 	 */
 	protected function mapEvents()
 	{
 		parent::mapEvents();
 
 		$common_events = Array (
 			'OnResetToUser'		=>	'OnResetAddress',
 			'OnResetToBilling'	=>	'OnResetAddress',
 			'OnResetToShipping'	=>	'OnResetAddress',
 
 			'OnMassOrderProcess'	=>	'MassInventoryAction',
 			'OnMassOrderApprove'	=>	'MassInventoryAction',
 			'OnMassOrderDeny'		=>	'MassInventoryAction',
 			'OnMassOrderArchive'	=>	'MassInventoryAction',
 			'OnMassOrderShip'		=>	'MassInventoryAction',
 
 			'OnOrderProcess'	=>	'InventoryAction',
 			'OnOrderApprove'	=>	'InventoryAction',
 			'OnOrderDeny'		=>	'InventoryAction',
 			'OnOrderArchive'	=>	'InventoryAction',
 			'OnOrderShip'		=>	'InventoryAction',
 		);
 
 		$this->eventMethods = array_merge($this->eventMethods, $common_events);
 	}
 
 	/* ======================== FRONT ONLY ======================== */
 
 	function OnQuietPreSave($event)
 	{
 		$object = $event->getObject();
 		/* @var $object kDBItem */
 
 		$object->IgnoreValidation = true;
 		$event->CallSubEvent('OnPreSave');
 		$object->IgnoreValidation = false;
 	}
 
 	/**
 	 * Sets new address to order
 	 *
 	 * @param kEvent $event
 	 */
 	function OnSelectAddress($event)
 	{
 		if ($this->Application->isAdminUser) {
 			return ;
 		}
 
 		$object = $event->getObject();
 		/* @var $object OrdersItem */
 
 		$shipping_address_id = $this->Application->GetVar('shipping_address_id');
 		$billing_address_id = $this->Application->GetVar('billing_address_id');
 
 		if ($shipping_address_id || $billing_address_id) {
 			$cs_helper = $this->Application->recallObject('CountryStatesHelper');
 			/* @var $cs_helper kCountryStatesHelper */
 
 			$address = $this->Application->recallObject('addr.-item','addr', Array('skip_autoload' => true));
 			/* @var $address AddressesItem */
 
 			$addr_list = $this->Application->recallObject('addr', 'addr_List', Array('per_page'=>-1, 'skip_counting'=>true) );
 			/* @var $addr_list AddressesList */
 
 			$addr_list->Query();
 		}
 
 		if ($shipping_address_id > 0) {
 			$addr_list->CopyAddress($shipping_address_id, 'Shipping');
 			$address->Load($shipping_address_id);
 			$address->MarkAddress('Shipping');
 
 			$cs_helper->PopulateStates($event, 'ShippingState', 'ShippingCountry');
 			$object->setRequired('ShippingState', false);
 		}
 		elseif ($shipping_address_id == -1) {
 			$object->ResetAddress('Shipping');
 		}
 
 		if ($billing_address_id > 0) {
 			$addr_list->CopyAddress($billing_address_id, 'Billing');
 			$address->Load($billing_address_id);
 			$address->MarkAddress('Billing');
 
 			$cs_helper->PopulateStates($event, 'BillingState', 'BillingCountry');
 			$object->setRequired('BillingState', false);
 		}
 		elseif ($billing_address_id == -1) {
 			$object->ResetAddress('Billing');
 		}
 
 		$event->redirect = false;
 
 		$object->IgnoreValidation = true;
 		$this->RecalculateTax($event);
 		$object->Update();
 	}
 
 	/**
 	 * Updates order with registred user id
 	 *
 	 * @param kEvent $event
 	 */
 	function OnUserCreate($event)
 	{
 		if( !($event->MasterEvent->status == kEvent::erSUCCESS) ) return false;
 
 		$ses_id = $this->Application->RecallVar('front_order_id');
 		if($ses_id)
 		{
 			$this->updateUserID($ses_id, $event);
 			$this->Application->RemoveVar('front_order_id');
 		}
 	}
 
 	/**
 	 * Updates shopping cart with logged-in user details
 	 *
 	 * @param kEvent $event
 	 * @return void
 	 * @access protected
 	 */
 	protected function OnUserLogin($event)
 	{
 		if ( ($event->MasterEvent->status != kEvent::erSUCCESS) || kUtil::constOn('IS_INSTALL') ) {
 			// login failed OR login during installation
 			return;
 		}
 
 		$ses_id = $this->Application->RecallVar('ord_id');
 
 		if ( $ses_id ) {
 			$this->updateUserID($ses_id, $event);
 		}
 
 		$user_id = $this->Application->RecallVar('user_id');
 		$affiliate_id = $this->isAffiliate($user_id);
 
 		if ( $affiliate_id ) {
 			$this->Application->setVisitField('AffiliateId', $affiliate_id);
 		}
 
 		$event->CallSubEvent('OnRecalculateItems');
 	}
 
 	/**
 	 * Puts ID of just logged-in user into current order
 	 *
 	 * @param int $order_id
 	 * @param kEvent $event
 	 * @return void
 	 */
 	function updateUserID($order_id, $event)
 	{
 		$user = $this->Application->recallObject('u.current');
 		/* @var $user UsersItem */
 
 		$affiliate_id = $this->isAffiliate( $user->GetID() );
 
 		$fields_hash = Array (
 			'PortalUserId' => $user->GetID(),
 			'BillingEmail' => $user->GetDBField('Email'),
 		);
 
 		if ( $affiliate_id ) {
 			$fields_hash['AffiliateId'] = $affiliate_id;
 		}
 
 		$id_field = $this->Application->getUnitOption($event->Prefix, 'IDField');
 		$table_name = $this->Application->getUnitOption($event->Prefix, 'TableName');
 
 		$this->Conn->doUpdate($fields_hash, $table_name, $id_field . ' = ' . $order_id);
 
 		$object = $event->getObject();
 		/* @var $object kDBItem */
 
 		// set user id to object, since it will be used during order update from OnRecalculateItems event
 		$object->SetDBField('PortalUserId', $user->GetID());
 	}
 
 	function isAffiliate($user_id)
 	{
 		$affiliate_user = $this->Application->recallObject('affil.-item', null, Array('skip_autoload' => true) );
 		/* @var $affiliate_user kDBItem */
 
 		$affiliate_user->Load($user_id, 'PortalUserId');
 
 		return $affiliate_user->isLoaded() ? $affiliate_user->GetDBField('AffiliateId') : 0;
 	}
 
 	/**
 	 * Charge order
 	 *
 	 * @param OrdersItem $order
 	 * @return Array
 	 */
 	function ChargeOrder(&$order)
 	{
 		$gw_data = $order->getGatewayData();
 
 		$this->Application->registerClass( $gw_data['ClassName'], GW_CLASS_PATH.'/'.$gw_data['ClassFile'] );
 		$gateway_object = $this->Application->recallObject( $gw_data['ClassName'] );
 		/* @var $gateway_object kGWBase */
 
 		$payment_result = $gateway_object->DirectPayment($order->GetFieldValues(), $gw_data['gw_params']);
 		$sql = 'UPDATE %s SET GWResult1 = %s WHERE %s = %s';
 		$sql = sprintf($sql, $order->TableName, $this->Conn->qstr($gateway_object->getGWResponce()), $order->IDField, $order->GetID() );
 		$this->Conn->Query($sql);
 		$order->SetDBField('GWResult1', $gateway_object->getGWResponce() );
 
 		return array('result'=>$payment_result, 'data'=>$gateway_object->parsed_responce, 'gw_data' => $gw_data, 'error_msg'=>$gateway_object->getErrorMsg());
 	}
 
 	/**
 	 * Returns parameters, used to send order-related e-mails
 	 *
 	 * @param OrdersItem $order
 	 * @return array
 	 */
 	function OrderEmailParams(&$order)
 	{
 		$billing_email = $order->GetDBField('BillingEmail');
-		$user_email = $this->Conn->GetOne('	SELECT Email FROM '.$this->Application->getUnitOption('u', 'TableName').'
-											WHERE PortalUserId = '.$order->GetDBField('PortalUserId'));
-		$email_params = Array();
-		$email_params['_user_email'] = $user_email; //for use when shipping vs user is required in InventoryAction
-		$email_params['to_email'] = $billing_email ? $billing_email : $user_email;
-		$email_params['to_name'] = $order->GetDBField('BillingTo');
-		return $email_params;
+
+		$sql = 'SELECT Email
+				FROM ' . $this->Application->getUnitOption('u', 'TableName') . '
+				WHERE PortalUserId = ' . $order->GetDBField('PortalUserId');
+		$user_email = $this->Conn->GetOne($sql);
+
+		$ret = Array (
+			'_user_email' => $user_email, // for use when shipping vs user is required in InventoryAction
+			'to_name' => $order->GetDBField('BillingTo'),
+			'to_email' => $billing_email ? $billing_email : $user_email,
+		);
+
+		return $ret;
 	}
 
 	function PrepareCoupons($event, &$order)
 	{
 		$order_items = $this->Application->recallObject('orditems.-inv','orditems_List',Array('skip_counting'=>true,'per_page'=>-1) );
 		/* @var $order_items kDBList */
 
 		$order_items->linkToParent($order->Special);
 		$order_items->Query();
 		$order_items->GoFirst();
 
 		$assigned_coupons = array();
 		$coup_handler = $this->Application->recallObject('coup_EventHandler');
 		foreach($order_items->Records as $product_item)
 		{
 			if ($product_item['ItemData']) {
 				$item_data = unserialize($product_item['ItemData']);
 				if (isset($item_data['AssignedCoupon']) && $item_data['AssignedCoupon']) {
 					$coupon_id = $item_data['AssignedCoupon'];
 					// clone coupon, get new coupon ID
 					$coupon = $this->Application->recallObject('coup',null,array('skip_autload' => true));
 					/* @var $coupon kDBItem */
 					$coupon->Load($coupon_id);
 					if (!$coupon->isLoaded()) continue;
 
 					$coup_handler->SetNewCode($coupon);
 					$coupon->NameCopy();
 					$coupon->SetDBField('Name', $coupon->GetDBField('Name').' (Order #'.$order->GetField('OrderNumber').')');
 					$coupon->Create();
 
 					// add coupon code to array
 					array_push($assigned_coupons, $coupon->GetDBField('Code'));
 				}
 			}
 		}
 
 		/* @var $order OrdersItem */
 		if ($assigned_coupons) {
 			$comments = $order->GetDBField('AdminComment');
 			if ($comments) $comments .= "\r\n";
 			$comments .= "Issued coupon(s): ". join(',', $assigned_coupons);
 			$order->SetDBField('AdminComment', $comments);
 			$order->Update();
 		}
 
 		if ($assigned_coupons) $this->Application->SetVar('order_coupons', join(',', $assigned_coupons));
 	}
 
 	/**
 	 * Completes order if possible
 	 *
 	 * @param kEvent $event
 	 * @return bool
 	 */
 	function OnCompleteOrder($event)
 	{
 		$this->LockTables($event);
 		if ( !$this->CheckQuantites($event) ) {
 			return;
 		}
 
 		$this->ReserveItems($event);
 
 		$order = $event->getObject();
 		/* @var $order OrdersItem */
 
 		$charge_result = $this->ChargeOrder($order);
 
 		if (!$charge_result['result']) {
 			$this->FreeItems($event);
 			$this->Application->StoreVar('gw_error', $charge_result['error_msg']);
 
 			//$this->Application->StoreVar('gw_error', getArrayValue($charge_result, 'data', 'responce_reason_text') );
 			$event->redirect = $this->Application->GetVar('failure_template');
 			$event->SetRedirectParam('m_cat_id', 0);
 			if ($event->Special == 'recurring') { // if we set failed status for other than recurring special the redirect will not occur
 				$event->status = kEvent::erFAIL;
 			}
 			return false;
 		}
 
 		// call CompleteOrder events for items in order BEFORE SplitOrder (because ApproveEvents are called there)
 		$order_items = $this->Application->recallObject('orditems.-inv','orditems_List',Array('skip_counting'=>true,'per_page'=>-1) );
 		/* @var $order_items kDBList */
 
 		$order_items->linkToParent($order->Special);
 		$order_items->Query(true);
 		$order_items->GoFirst();
 
 		foreach($order_items->Records as $product_item)
 		{
 			if (!$product_item['ProductId']) continue; // product may have been deleted
 			$this->raiseProductEvent('CompleteOrder', $product_item['ProductId'], $product_item);
 		}
 
 		$shipping_control = getArrayValue($charge_result, 'gw_data', 'gw_params', 'shipping_control');
 		if ($event->Special != 'recurring') {
 			if ($shipping_control && $shipping_control != SHIPPING_CONTROL_PREAUTH ) {
 				// we have to do it here, because the coupons are used in the e-mails
 				$this->PrepareCoupons($event, $order);
 			}
 
-			$this->Application->EmailEventUser('ORDER.SUBMIT', $order->GetDBField('PortalUserId'), $this->OrderEmailParams($order));
-			$this->Application->EmailEventAdmin('ORDER.SUBMIT');
+			$this->Application->emailUser('ORDER.SUBMIT', null, $this->OrderEmailParams($order));
+			$this->Application->emailAdmin('ORDER.SUBMIT');
 		}
 
 		if ($shipping_control === false || $shipping_control == SHIPPING_CONTROL_PREAUTH ) {
 			$order->SetDBField('Status', ORDER_STATUS_PENDING);
 			$order->Update();
 		}
 		else {
 			$this->SplitOrder($event, $order);
 		}
 
 		if (!$this->Application->isAdminUser) {
 			// for tracking code
 			$this->Application->StoreVar('last_order_amount', $order->GetDBField('TotalAmount'));
 			$this->Application->StoreVar('last_order_number', $order->GetDBField('OrderNumber'));
 			$this->Application->StoreVar('last_order_customer', $order->GetDBField('BillingTo'));
 			$this->Application->StoreVar('last_order_user', $order->GetDBField('Username'));
 
 			$event->redirect = $this->Application->GetVar('success_template');
 			$event->SetRedirectParam('m_cat_id', 0);
 		}
 		else
 		{
 //			$event->CallSubEvent('OnSave');
 		}
 
 		$order_id = $order->GetId();
 		$order_idfield = $this->Application->getUnitOption('ord','IDField');
 		$order_table = $this->Application->getUnitOption('ord','TableName');
 		$original_amount = $order->GetDBField('SubTotal') + $order->GetDBField('ShippingCost') + $order->GetDBField('VAT') + $order->GetDBField('ProcessingFee') + $order->GetDBField('InsuranceFee') - $order->GetDBField('GiftCertificateDiscount');
 		$sql = 'UPDATE '.$order_table.'
 				SET OriginalAmount = '.$original_amount.'
 				WHERE '.$order_idfield.' = '.$order_id;
 		$this->Conn->Query($sql);
 
 		$this->Application->StoreVar('front_order_id', $order_id);
 		$this->Application->RemoveVar('ord_id');
 		$this->Application->Session->SetCookie('shop_cart_cookie', '', strtotime('-1 month'));
 	}
 
 	/**
 	 * Set billing address same as shipping
 	 *
 	 * @param kEvent $event
 	 */
 	function setBillingAddress($event)
 	{
 		$object = $event->getObject();
 		/* @var $object OrdersItem */
 
 		if ( $object->HasTangibleItems() ) {
 			if ( $this->Application->GetVar('same_address') ) {
 				// copy shipping address to billing
 				$items_info = $this->Application->GetVar($event->getPrefixSpecial(true));
 				list($id, $field_values) = each($items_info);
 
 				$address_fields = Array (
 					'To', 'Company', 'Phone', 'Fax', 'Email',
 					'Address1', 'Address2', 'City', 'State',
 					'Zip', 'Country'
 				);
 
 				foreach ($address_fields as $address_field) {
 					$items_info[$id]['Billing' . $address_field] = $object->GetDBField('Shipping' . $address_field);
 				}
 
 				$this->Application->SetVar($event->getPrefixSpecial(true), $items_info);
 			}
 		}
 	}
 
 	/**
 	 * Enter description here...
 	 *
 	 * @param kEvent $event
 	 */
 	function OnProceedToPreview($event)
 	{
 		$this->setBillingAddress($event);
 
 		$event->CallSubEvent('OnUpdate');
 		$event->redirect = $this->Application->GetVar('preview_template');
 	}
 
 
 	function OnViewCart($event)
 	{
 		$this->StoreContinueShoppingLink();
 		$event->redirect = $this->Application->GetVar('viewcart_template');
 	}
 
 	function OnContinueShopping($event)
 	{
 		$order_helper = $this->Application->recallObject('OrderHelper');
 		/* @var $order_helper OrderHelper */
 
 		$template = $this->Application->GetVar('continue_shopping_template');
 
 		$event->redirect = $order_helper->getContinueShoppingTemplate($template);
 	}
 
 	/**
 	 * Enter description here...
 	 *
 	 * @param kEvent $event
 	 */
 	function OnCheckout($event)
 	{
 		$this->OnUpdateCart($event);
 		if ( !$event->getEventParam('RecalculateChangedCart') ) {
 			$object = $event->getObject();
 			/* @var $object OrdersItem */
 
 			if ( !$object->HasTangibleItems() ) {
 				$object->SetDBField('ShippingTo', '');
 				$object->SetDBField('ShippingCompany', '');
 				$object->SetDBField('ShippingPhone', '');
 				$object->SetDBField('ShippingFax', '');
 				$object->SetDBField('ShippingEmail', '');
 				$object->SetDBField('ShippingAddress1', '');
 				$object->SetDBField('ShippingAddress2', '');
 				$object->SetDBField('ShippingCity', '');
 				$object->SetDBField('ShippingState', '');
 				$object->SetDBField('ShippingZip', '');
 				$object->SetDBField('ShippingCountry', '');
 				$object->SetDBField('ShippingType', 0);
 				$object->SetDBField('ShippingCost', 0);
 				$object->SetDBField('ShippingCustomerAccount', '');
 				$object->SetDBField('ShippingTracking', '');
 				$object->SetDBField('ShippingDate', 0);
 				$object->SetDBField('ShippingOption', 0);
 				$object->SetDBField('ShippingInfo', '');
 				$object->Update();
 			}
 
 			$event->redirect = $this->Application->GetVar('next_step_template');
 
 			$order_id = $this->Application->GetVar('order_id');
 
 			if ( $order_id !== false ) {
 				$event->SetRedirectParam('ord_id', $order_id);
 			}
 		}
 	}
 
 	/**
 	 * Restores order from cookie
 	 *
 	 * @param kEvent $event
 	 * @return void
 	 * @access protected
 	 */
 	protected function OnRestoreOrder(kEvent $event)
 	{
 		if ( $this->Application->isAdmin || $this->Application->RecallVar('ord_id') ) {
 			// admin OR there is an active order -> don't restore from cookie
 			return;
 		}
 
 		$shop_cart_cookie = $this->Application->GetVarDirect('shop_cart_cookie', 'Cookie');
 
 		if ( !$shop_cart_cookie ) {
 			return;
 		}
 
 		$user_id = $this->Application->RecallVar('user_id');
 
 		$sql = 'SELECT OrderId
 				FROM ' . TABLE_PREFIX . 'Orders
 				WHERE (OrderId = ' . (int)$shop_cart_cookie . ') AND (Status = ' . ORDER_STATUS_INCOMPLETE . ') AND (PortalUserId = ' . $user_id . ')';
 		$order_id = $this->Conn->GetOne($sql);
 
 		if ( $order_id ) {
 			$this->Application->StoreVar('ord_id', $order_id);
 		}
 	}
 
 	/**
 	 * Redirect user to Billing checkout step
 	 *
 	 * @param kEvent $event
 	 */
 	function OnProceedToBilling($event)
 	{
 		$items_info = $this->Application->GetVar($event->getPrefixSpecial(true));
 		if ( $items_info ) {
 			list($id, $field_values) = each($items_info);
 
 			$object = $event->getObject();
 			/* @var $object kDBItem */
 
 			$payment_type_id = $object->GetDBField('PaymentType');
 
 			if ( !$payment_type_id ) {
 				$default_type = $this->_getDefaultPaymentType();
 
 				if ( $default_type ) {
 					$field_values['PaymentType'] = $default_type;
 					$items_info[$id] = $field_values;
 					$this->Application->SetVar($event->getPrefixSpecial(true), $items_info);
 				}
 			}
 		}
 
 		$event->CallSubEvent('OnUpdate');
 		$event->redirect = $this->Application->GetVar('next_step_template');
 	}
 
 	/**
 	 * Removes reoccurring mark from the order
 	 *
 	 * @param kEvent $event
 	 * @return void
 	 */
 	protected function OnCancelRecurring($event)
 	{
 		$order = $event->getObject();
 		/* @var $order OrdersItem */
 
 		$order->SetDBField('IsRecurringBilling', 0);
 		$order->Update();
 
 		if ( $this->Application->GetVar('cancelrecurring_ok_template') ) {
 			$event->redirect = $this->Application->GetVar('cancelrecurring_ok_template');
 		}
 	}
 
 	/**
 	 * Occurs after updating item
 	 *
 	 * @param kEvent $event
 	 * @return void
 	 * @access protected
 	 */
 	protected function OnAfterItemUpdate(kEvent $event)
 	{
 		parent::OnAfterItemUpdate($event);
 
 		$object = $event->getObject();
 		/* @var $object OrdersItem */
 
 		$cvv2 = $object->GetDBField('PaymentCVV2');
 
 		if ( $cvv2 !== false ) {
 			$this->Application->StoreVar('CVV2Code', $cvv2);
 		}
 	}
 
 
 	/**
 	 * Updates kDBItem
 	 *
 	 * @param kEvent $event
 	 * @return void
 	 * @access protected
 	 */
 	protected function OnUpdate(kEvent $event)
 	{
 		$this->setBillingAddress($event);
 
 		parent::OnUpdate($event);
 
 		if ($this->Application->isAdminUser) {
 			return ;
 		}
 		else {
 			$event->SetRedirectParam('opener', 's');
 		}
 
 		if ($event->status == kEvent::erSUCCESS) {
 			$this->createMissingAddresses($event);
 		}
 		else {
 			// strange: recalculate total amount on error
 			$object = $event->getObject();
 			/* @var $object OrdersItem */
 
 			$object->SetDBField('TotalAmount', $object->getTotalAmount());
 		}
 	}
 
 	/**
 	 * Creates new address
 	 *
 	 * @param kEvent $event
 	 */
 	function createMissingAddresses($event)
 	{
 		if ( !$this->Application->LoggedIn() ) {
 			return ;
 		}
 
 		$object = $event->getObject();
 		/* @var $object kDBItem */
 
 		$addr_list = $this->Application->recallObject('addr', 'addr_List', Array ('per_page' => -1, 'skip_counting' => true));
 		/* @var $addr_list kDBList */
 
 		$addr_list->Query();
 
 		$address_dummy = $this->Application->recallObject('addr.-item', null, Array ('skip_autoload' => true));
 		/* @var $address_dummy AddressesItem */
 
 		$address_prefixes = Array ('Billing', 'Shipping');
 		$address_fields = Array (
 			'To', 'Company', 'Phone', 'Fax', 'Email', 'Address1',
 			'Address2', 'City', 'State', 'Zip', 'Country'
 		);
 
 		foreach ($address_prefixes as $address_prefix) {
 			$address_id = $this->Application->GetVar(strtolower($address_prefix) . '_address_id');
 
 			if ( !$this->Application->GetVar('check_' . strtolower($address_prefix) . '_address') ) {
 				// form type doesn't match check type, e.g. shipping check on billing form
 				continue;
 			}
 
 			if ( $address_id > 0 ) {
 				$address_dummy->Load($address_id);
 			}
 			else {
 				$address_dummy->SetDBField('PortalUserId', $this->Application->RecallVar('user_id'));
 			}
 
 			foreach ($address_fields as $address_field) {
 				$address_dummy->SetDBField($address_field, $object->GetDBField($address_prefix . $address_field));
 			}
 
 			$address_dummy->MarkAddress($address_prefix, false);
 
 			$ret = ($address_id > 0) ? $address_dummy->Update() : $address_dummy->Create();
 		}
 	}
 
 	/**
 	 * Updates shopping cart content
 	 *
 	 * @param kEvent $event
 	 * @return void
 	 * @access protected
 	 */
 	protected function OnUpdateCart($event)
 	{
 		$this->Application->HandleEvent(new kEvent('orditems:OnUpdate'));
 
 		$event->CallSubEvent('OnRecalculateItems');
 	}
 
 	/**
 	 * Updates cart and returns various info in JSON format
 	 *
 	 * @param kEvent $event
 	 */
 	function OnUpdateCartJSON($event)
 	{
 		if ( $this->Application->GetVar('ajax') != 'yes' ) {
 			return;
 		}
 
 		$object = $event->getObject();
 		/* @var $object kDBItem */
 
 		// 1. delete given order item by id
 		$delete_id = $this->Application->GetVar('delete_id');
 
 		if ( $delete_id !== false ) {
 			$sql = 'DELETE FROM ' . TABLE_PREFIX . 'OrderItems
 					WHERE OrderId = ' . $object->GetID() . ' AND OrderItemId = ' . (int)$delete_id;
 			$this->Conn->Query($sql);
 		}
 
 		// 2. remove coupon
 		$remove = $this->Application->GetVar('remove');
 
 		if ( $remove == 'coupon' ) {
 			$this->RemoveCoupon($object);
 			$object->setCheckoutError(OrderCheckoutErrorType::COUPON, OrderCheckoutError::COUPON_REMOVED);
 		}
 		elseif ( $remove == 'gift_certificate' ) {
 			$this->RemoveGiftCertificate($object);
 			$object->setCheckoutError(OrderCheckoutErrorType::GIFT_CERTIFICATE, OrderCheckoutError::GC_REMOVED);
 		}
 
 		// 3. update product quantities and recalculate all discounts
 		$this->Application->HandleEvent(new kEvent('orditems:OnUpdate'));
 		$event->CallSubEvent('OnRecalculateItems');
 
 		// 4. remove "orditems" object of kDBItem class, since getOrderInfo uses kDBList object under same prefix
 		$this->Application->removeObject('orditems');
 
 		$order_helper = $this->Application->recallObject('OrderHelper');
 		/* @var $order_helper OrderHelper */
 
 		$event->status = kEvent::erSTOP;
 		$currency = $this->Application->GetVar('currency', 'selected');
 
 		echo json_encode( $order_helper->getOrderInfo($object, $currency) );
 	}
 
 	/**
 	 * Adds item to cart
 	 *
 	 * @param kEvent $event
 	 */
 	function OnAddToCart($event)
 	{
 		$this->StoreContinueShoppingLink();
 
 		$qty = $this->Application->GetVar('qty');
 		$options = $this->Application->GetVar('options');
 
 		// multiple or options add
 		$items = Array();
 		if (is_array($qty)) {
 			foreach ($qty as $item_id => $combinations)
 			{
 				if (is_array($combinations)) {
 					foreach ($combinations as $comb_id => $comb_qty) {
 						if ($comb_qty == 0) continue;
 						$items[] = array('item_id' => $item_id, 'qty' => $comb_qty, 'comb' => $comb_id);
 					}
 				}
 				else {
 					$items[] = array('item_id' => $item_id, 'qty' => $combinations);
 				}
 			}
 		}
 
 		if (!$items) {
 			if (!$qty || is_array($qty)) $qty = 1;
 			$item_id = $this->Application->GetVar('p_id');
 			if (!$item_id) return ;
 			$items = array(array('item_id' => $item_id, 'qty' => $qty));
 		}
 
 		// remember item data passed to event when called
 		$default_item_data = $event->getEventParam('ItemData');
 		$default_item_data = $default_item_data ? unserialize($default_item_data) : Array();
 
 		foreach ($items as $an_item) {
 			$item_id = $an_item['item_id'];
 			$qty = $an_item['qty'];
 			$comb = getArrayValue($an_item, 'comb');
 
 			$item_data = $default_item_data;
 
 			$product = $this->Application->recallObject('p', null, Array('skip_autoload' => true));
 			/* @var $product ProductsItem */
 
 			$product->Load($item_id);
 
 			$event->setEventParam('ItemData', null);
 
 			if ($product->GetDBField('AssignedCoupon')) {
 				$item_data['AssignedCoupon'] = $product->GetDBField('AssignedCoupon');
 			}
 
 			// 1. store options information OR
 			if ($comb) {
 				$combination = $this->Conn->GetOne('SELECT Combination FROM '.TABLE_PREFIX.'ProductOptionCombinations WHERE CombinationId = '.$comb);
 				$item_data['Options'] = unserialize($combination);
 			}
 			elseif (is_array($options)) {
 				$item_data['Options'] = $options[$item_id];
 			}
 
 			// 2. store subscription information OR
 			if( $product->GetDBField('Type') == 2 )	// subscriptions
 			{
 				$item_data = $this->BuildSubscriptionItemData($item_id, $item_data);
 			}
 
 			// 3. store package information
 			if( $product->GetDBField('Type') == 5 )	// package
 			{
 				$package_content_ids = $product->GetPackageContentIds();
 
 				$product_package_item = $this->Application->recallObject('p.-packageitem');
 				/* @var $product_package_item ProductsItem */
 
 				$package_item_data = array();
 
 				foreach ($package_content_ids as $package_item_id){
 					$product_package_item->Load($package_item_id);
 					$package_item_data[$package_item_id] = array();
 					if( $product_package_item->GetDBField('Type') == 2 )	// subscriptions
 					{
 						$package_item_data[$package_item_id] = $this->BuildSubscriptionItemData($package_item_id, $item_data);
 					}
 				}
 
 				$item_data['PackageContent'] = $product->GetPackageContentIds();
 				$item_data['PackageItemsItemData'] = $package_item_data;
 			}
 
 			$event->setEventParam('ItemData', serialize($item_data));
 			// 1 for PacakgeNum when in admin - temporary solution to overcome splitting into separate sub-orders
 			// of orders with items added through admin when approving them
 			$this->AddItemToOrder($event, $item_id, $qty, $this->Application->isAdminUser ? 1 : null);
 		}
 		if ($event->status == kEvent::erSUCCESS && !$event->redirect) {
 			$event->SetRedirectParam('pass', 'm');
 			$event->SetRedirectParam('pass_category', 0); //otherwise mod-rewrite shop-cart URL will include category
 			$event->redirect = true;
 		}
 		else {
 			if ($this->Application->isAdminUser) {
 				$event->SetRedirectParam('opener', 'u');
 			}
 		}
 	}
 
 	/**
 	 * Returns table prefix from event (temp or live)
 	 *
 	 * @param kEvent $event
 	 * @return string
 	 * @todo Needed? Should be refactored (by Alex)
 	 */
 	function TablePrefix(kEvent $event)
 	{
 		return $this->UseTempTables($event) ? $this->Application->GetTempTablePrefix('prefix:' . $event->Prefix) . TABLE_PREFIX : TABLE_PREFIX;
 	}
 
 	/**
 	 * Check if required options are selected & selected option combination is in stock
 	 *
 	 * @param kEvent $event
 	 * @param Array $options
 	 * @param int $product_id
 	 * @param int $qty
 	 * @param int $selection_mode
 	 * @return bool
 	 */
 	function CheckOptions($event, &$options, $product_id, $qty, $selection_mode)
 	{
 		// 1. check for required options
 		$selection_filter = $selection_mode == 1 ? ' AND OptionType IN (1,3,6) ' : '';
 		$req_options = $this->Conn->GetCol('SELECT ProductOptionId FROM '.TABLE_PREFIX.'ProductOptions WHERE ProductId = '.$product_id.' AND Required = 1 '.$selection_filter);
 		$result = true;
 		foreach ($req_options as $opt_id) {
 			if (!getArrayValue($options, $opt_id)) {
 				$this->Application->SetVar('opt_error', 1); //let the template know we have an error
 				$result = false;
 			}
 		}
 
 		// 2. check for option combinations in stock
 		$comb_salt = $this->OptionsSalt($options, true);
 		if ($comb_salt) {
 			// such option combination is defined explicitly
 			$poc_table = $this->Application->getUnitOption('poc', 'TableName');
 			$sql = 'SELECT Availability
 					FROM '.$poc_table.'
 					WHERE CombinationCRC = '.$comb_salt;
 			$comb_availble = $this->Conn->GetOne($sql);
 
 			// 2.1. check if Availability flag is set, then
 			if ($comb_availble == 1) {
 				// 2.2. check for quantity in stock
 				$table = Array();
 				$table['poc'] = $this->Application->getUnitOption('poc', 'TableName');
 				$table['p'] = $this->Application->getUnitOption('p', 'TableName');
 				$table['oi'] = $this->TablePrefix($event).'OrderItems';
 
 				$object = $event->getObject();
 				$ord_id = $object->GetID();
 
 				// 2.3. check if some amount of same combination & product are not already in shopping cart
 				$sql = 'SELECT '.
 								$table['p'].'.InventoryStatus,'.
 								$table['p'].'.BackOrder,
 								IF('.$table['p'].'.InventoryStatus = 2, '.$table['poc'].'.QtyInStock, '.$table['p'].'.QtyInStock) AS QtyInStock,
 								IF('.$table['oi'].'.OrderItemId IS NULL, 0, '.$table['oi'].'.Quantity) AS Quantity
 						FROM '.$table['p'].'
 						LEFT JOIN '.$table['poc'].' ON
 								'.$table['p'].'.ProductId = '.$table['poc'].'.ProductId
 						LEFT JOIN '.$table['oi'].' ON
 								('.$table['oi'].'.OrderId = '.$ord_id.') AND
 								('.$table['oi'].'.OptionsSalt = '.$comb_salt.') AND
 								('.$table['oi'].'.ProductId = '.$product_id.') AND
 								('.$table['oi'].'.BackOrderFlag = 0)
 						WHERE '.$table['poc'].'.CombinationCRC = '.$comb_salt;
 				$product_info = $this->Conn->GetRow($sql);
 
 				if ($product_info['InventoryStatus']) {
 					$backordering = $this->Application->ConfigValue('Comm_Enable_Backordering');
 					if (!$backordering || $product_info['BackOrder'] == 0) {
 						// backordering is not enabled generally or for this product directly, then check quantities in stock
 						if ($qty + $product_info['Quantity'] > $product_info['QtyInStock']) {
 							$this->Application->SetVar('opt_error', 2);
 							$result = false;
 						}
 					}
 				}
 			}
 			elseif ($comb_availble !== false) {
 				$this->Application->SetVar('opt_error', 2);
 				$result = false;
 			}
 		}
 
 		if ($result) {
 			$event->status = kEvent::erSUCCESS;
 			$shop_cart_template = $this->Application->GetVar('shop_cart_template');
 			$event->redirect = $this->Application->isAdminUser || !$shop_cart_template ? true : $shop_cart_template;
 		}
 		else {
 			$event->status = kEvent::erFAIL;
 		}
 		return $result;
 	}
 
 	/**
 	 * Enter description here...
 	 *
 	 * @param kEvent $event
 	 */
 	function OnUpdateItemOptions($event)
 	{
 		$opt_data = $this->Application->GetVar('options');
 		$options = getArrayValue($opt_data, $this->Application->GetVar('p_id'));
 
 		if (!$options) {
 			$qty_data = $this->Application->GetVar('qty');
 			$comb_id = key(getArrayValue($qty_data, $this->Application->GetVar('p_id')));
 			$options = unserialize($this->Conn->GetOne('SELECT Combination FROM '.TABLE_PREFIX.'ProductOptionCombinations WHERE CombinationId = '.$comb_id));
 		}
 
 		if (!$options) return;
 
 		$ord_item = $this->Application->recallObject('orditems.-opt', null, Array ('skip_autoload' => true));
 		/* @var $ord_item kDBItem */
 
 		$ord_item->Load($this->Application->GetVar('orditems_id'));
 
 		// assuming that quantity cannot be changed during order item editing
 		if (!$this->CheckOptions($event, $options, $ord_item->GetDBField('ProductId'), 0, $ord_item->GetDBField('OptionsSelectionMode'))) return;
 
 		$item_data = unserialize($ord_item->GetDBField('ItemData'));
 		$item_data['Options'] = $options;
 		$ord_item->SetDBField('ItemData', serialize($item_data));
 		$ord_item->SetDBField('OptionsSalt', $this->OptionsSalt($options));
 		$ord_item->Update();
 		$event->CallSubEvent('OnRecalculateItems');
 		if ($event->status == kEvent::erSUCCESS && $this->Application->isAdminUser) {
 			$event->SetRedirectParam('opener', 'u');
 		}
 	}
 
 	function BuildSubscriptionItemData($item_id, $item_data)
 	{
 		$products_table = $this->Application->getUnitOption('p', 'TableName');
 		$products_idfield = $this->Application->getUnitOption('p', 'IDField');
 		$sql = 'SELECT AccessGroupId FROM %s WHERE %s = %s';
 		$item_data['PortalGroupId'] = $this->Conn->GetOne( sprintf($sql, $products_table, $products_idfield, $item_id) );
 
 		$pricing_table = $this->Application->getUnitOption('pr', 'TableName');
 		$pricing_idfield = $this->Application->getUnitOption('pr', 'IDField');
 
 		/* TODO check on implementation
 		$sql = 'SELECT AccessDuration, AccessUnit, DurationType, AccessExpiration FROM %s WHERE %s = %s';
 		*/
 
 		$sql = 'SELECT * FROM %s WHERE %s = %s';
 		$pricing_id = $this->GetPricingId($item_id, $item_data);
 		$item_data['PricingId'] = $pricing_id;
 
 		$pricing_info = $this->Conn->GetRow( sprintf($sql, $pricing_table, $pricing_idfield, $pricing_id ) );
 		$unit_secs = Array(1 => 1, 2 => 60, 3 => 3600, 4 => 86400, 5 => 604800, 6 => 2592000, 7 => 31536000);
 
 		/* TODO check on implementation (code from customization healtheconomics.org)
 		$item_data['DurationType'] = $pricing_info['DurationType'];
 		$item_data['AccessExpiration'] = $pricing_info['AccessExpiration'];
 		*/
 
 		$item_data['Duration'] = $pricing_info['AccessDuration'] * $unit_secs[ $pricing_info['AccessUnit'] ];
 
 		return $item_data;
 	}
 
 	/**
 	 * Enter description here...
 	 *
 	 * @param kEvent $event
 	 */
 	function OnApplyCoupon($event)
 	{
 		$code = $this->Application->GetVar('coupon_code');
 
 		if ($code == '') {
 			return ;
 		}
 
 		$object = $event->getObject();
 		/* @var $object OrdersItem */
 
 		$coupon = $this->Application->recallObject('coup', null, Array ('skip_autoload' => true));
 		/* @var $coupon kDBItem */
 
 		$coupon->Load($code, 'Code');
 
 		if ( !$coupon->isLoaded() ) {
 			$event->status = kEvent::erFAIL;
 			$object->setCheckoutError(OrderCheckoutErrorType::COUPON, OrderCheckoutError::COUPON_CODE_INVALID);
 			$event->redirect = false; // check!!!
 
 			return ;
 		}
 
 		$expire_date = $coupon->GetDBField('Expiration');
 		$number_of_use = $coupon->GetDBField('NumberOfUses');
 		if ( $coupon->GetDBField('Status') != 1 || ($expire_date && $expire_date < adodb_mktime()) ||
 			(isset($number_of_use) && $number_of_use <= 0))
 		{
 			$event->status = kEvent::erFAIL;
 			$object->setCheckoutError(OrderCheckoutErrorType::COUPON, OrderCheckoutError::COUPON_CODE_EXPIRED);
 			$event->redirect = false;
 
 			return ;
 		}
 
 		$last_used = adodb_mktime();
 		$coupon->SetDBField('LastUsedBy', $this->Application->RecallVar('user_id'));
 		$coupon->SetDBField('LastUsedOn_date', $last_used);
 		$coupon->SetDBField('LastUsedOn_time', $last_used);
 
 
 		if ( isset($number_of_use) ) {
 			$coupon->SetDBField('NumberOfUses', $number_of_use - 1);
 
 			if ($number_of_use == 1) {
 				$coupon->SetDBField('Status', 2);
 			}
 		}
 
 		$coupon->Update();
 
 		$this->Application->setUnitOption('ord', 'AutoLoad', true);
 		$order = $this->Application->recallObject('ord');
 		/* @var $order OrdersItem */
 
 		$order->SetDBField('CouponId', $coupon->GetDBField('CouponId'));
 		$order->SetDBField('CouponName', $coupon->GetDBField('Name')); // calculated field
 
 		$order->Update();
 
 		$object->setCheckoutError(OrderCheckoutErrorType::COUPON, OrderCheckoutError::COUPON_APPLIED);
 //		OnApplyCoupon is called as hook for OnUpdateCart/OnCheckout, which calls OnRecalcualate themself
 	}
 
 	/**
 	 * Removes coupon from order
 	 *
 	 * @param kEvent $event
 	 * @deprecated
 	 */
 	function OnRemoveCoupon($event)
 	{
 		$object = $event->getObject();
 		/* @var $object OrdersItem */
 
 		$this->RemoveCoupon($object);
 		$object->setCheckoutError(OrderCheckoutErrorType::COUPON, OrderCheckoutError::COUPON_REMOVED);
 
 		$event->CallSubEvent('OnRecalculateItems');
 	}
 
 	/**
 	 * Removes coupon from a given order
 	 *
 	 * @param OrdersItem $object
 	 */
 	function RemoveCoupon(&$object)
 	{
 		$coupon = $this->Application->recallObject('coup', null, Array('skip_autoload' => true));
 		/* @var $coupon kDBItem */
 
 		$coupon->Load( $object->GetDBField('CouponId') );
 
 		if ( $coupon->isLoaded() ) {
 			$coupon->SetDBField('NumberOfUses', $coupon->GetDBField('NumberOfUses') + 1);
 			$coupon->SetDBField('Status', STATUS_ACTIVE);
 			$coupon->Update();
 		}
 
 		$object->SetDBField('CouponId', 0);
 		$object->SetDBField('CouponName', ''); // calculated field
 		$object->SetDBField('CouponDiscount', 0);
 	}
 
 	/**
 	 * Enter description here...
 	 *
 	 * @param kEvent $event
 	 */
 	function OnAddVirtualProductToCart($event)
 	{
 		$l_info = $this->Application->GetVar('l');
 		if($l_info)
 		{
 			foreach($l_info as $link_id => $link_info) {}
 			$item_data['LinkId'] = $link_id;
 			$item_data['ListingTypeId'] = $link_info['ListingTypeId'];
 		}
 		else
 		{
 			$link_id = $this->Application->GetVar('l_id');
 			$sql = 'SELECT ResourceId FROM '.$this->Application->getUnitOption('l', 'TableName').'
 					WHERE LinkId = '.$link_id;
 			$sql = 'SELECT ListingTypeId FROM '.$this->Application->getUnitOption('ls', 'TableName').'
 					WHERE ItemResourceId = '.$this->Conn->GetOne($sql);
 			$item_data['LinkId'] = $link_id;
 			$item_data['ListingTypeId'] = $this->Conn->GetOne($sql);
 		}
 
 		$sql = 'SELECT VirtualProductId FROM '.$this->Application->getUnitOption('lst', 'TableName').'
 				WHERE ListingTypeId = '.$item_data['ListingTypeId'];
 		$item_id = $this->Conn->GetOne($sql);
 
 		$event->setEventParam('ItemData', serialize($item_data));
 		$this->AddItemToOrder($event, $item_id);
 
 		$shop_cart_template = $this->Application->GetVar('shop_cart_template');
 
 		if ( $shop_cart_template ) {
 			$event->redirect = $shop_cart_template;
 		}
 
 		// don't pass unused info to shopping cart, brokes old mod-rewrites
 		$event->SetRedirectParam('pass', 'm'); // not to pass link id
 		$event->SetRedirectParam('m_cat_id', 0); // not to pass link id
 	}
 
 	function OnRemoveFromCart($event)
 	{
 		$ord_item_id = $this->Application->GetVar('orditems_id');
 		$ord_id = $this->getPassedID($event);
 		$this->Conn->Query('DELETE FROM '.TABLE_PREFIX.'OrderItems WHERE OrderId = '.$ord_id.' AND OrderItemId = '.$ord_item_id);
 		$this->OnRecalculateItems($event);
 	}
 
 	function OnCleanupCart($event)
 	{
 		$object = $event->getObject();
 
 		$sql = 'DELETE FROM '.TABLE_PREFIX.'OrderItems
 				WHERE OrderId = '.$this->getPassedID($event);
 		$this->Conn->Query($sql);
 
 		$this->RemoveCoupon($object);
 		$this->RemoveGiftCertificate($object);
 
 		$this->OnRecalculateItems($event);
 	}
 
 	/**
 	 * Returns order id from session or last used
 	 *
 	 * @param kEvent $event
 	 * @return int
 	 * @access public
 	 */
 	public function getPassedID(kEvent $event)
 	{
 		$event->setEventParam('raise_warnings', 0);
 		$passed = parent::getPassedID($event);
 
 		if ( $this->Application->isAdminUser ) {
 			// work as usual in admin
 			return $passed;
 		}
 
 		if ( $event->Special == 'last' ) {
 			// return last order id (for using on thank you page)
 			$order_id = $this->Application->RecallVar('front_order_id');
 
 			return $order_id > 0 ? $order_id : FAKE_ORDER_ID; // FAKE_ORDER_ID helps to keep parent filter for order items set in "kDBList::linkToParent"
 		}
 
 		$ses_id = $this->Application->RecallVar($event->getPrefixSpecial(true) . '_id');
 
 		if ( $passed && ($passed != $ses_id) ) {
 			// order id given in url doesn't match our current order id
 			$sql = 'SELECT PortalUserId
 					FROM ' . TABLE_PREFIX . 'Orders
 					WHERE OrderId = ' . $passed;
 			$user_id = $this->Conn->GetOne($sql);
 
 			if ( $user_id == $this->Application->RecallVar('user_id') ) {
 				// current user is owner of order with given id -> allow him to view order details
 				return $passed;
 			}
 			else {
 				// current user is not owner of given order -> hacking attempt
 				$this->Application->SetVar($event->getPrefixSpecial() . '_id', 0);
 				return 0;
 			}
 		}
 
 		// not passed or equals to ses_id
 		return $ses_id > 0 ? $ses_id : FAKE_ORDER_ID; // FAKE_ORDER_ID helps to keep parent filter for order items set in "kDBList::linkToParent"
 	}
 
 	/**
 	 * Load item if id is available
 	 *
 	 * @param kEvent $event
 	 * @return void
 	 * @access protected
 	 */
 	protected function LoadItem(kEvent $event)
 	{
 		$id = $this->getPassedID($event);
 
 		if ( $id == FAKE_ORDER_ID ) {
 			// if we already know, that there is no such order,
 			// then don't run database query, that will confirm that
 
 			$object = $event->getObject();
 			/* @var $object kDBItem */
 
 			$object->Clear($id);
 			return;
 		}
 
 		parent::LoadItem($event);
 	}
 
 	/**
 	 * Creates new shopping cart
 	 *
 	 * @param kEvent $event
 	 */
 	function _createNewCart($event)
 	{
 		$object = $event->getObject( Array('skip_autoload' => true) );
 		/* @var $object kDBItem */
 
 		$this->setNextOrderNumber($event);
 		$object->SetDBField('Status', ORDER_STATUS_INCOMPLETE);
 		$object->SetDBField('VisitId', $this->Application->RecallVar('visit_id') );
 
 		// get user
 		if ( $this->Application->LoggedIn() ) {
 			$user = $this->Application->recallObject('u.current');
 			/* @var $user UsersItem */
 
 			$user_id = $user->GetID();
 			$object->SetDBField('BillingEmail', $user->GetDBField('Email'));
 		}
 		else {
 			$user_id = USER_GUEST;
 		}
 
 		$object->SetDBField('PortalUserId', $user_id);
 
 		// get affiliate
 		$affiliate_id = $this->isAffiliate($user_id);
 		if ( $affiliate_id ) {
 			$object->SetDBField('AffiliateId', $affiliate_id);
 		}
 		else {
 			$affiliate_storage_method = $this->Application->ConfigValue('Comm_AffiliateStorageMethod');
 
 			if ( $affiliate_storage_method == 1 ) {
 				$object->SetDBField('AffiliateId', (int)$this->Application->RecallVar('affiliate_id'));
 			}
 			else {
 				$object->SetDBField('AffiliateId', (int)$this->Application->GetVar('affiliate_id'));
 			}
 		}
 
 		// get payment type
 		$default_type = $this->_getDefaultPaymentType();
 
 		if ( $default_type ) {
 			$object->SetDBField('PaymentType', $default_type);
 		}
 
 		// vat setting
 		$object->SetDBField('VATIncluded', $this->Application->ConfigValue('OrderVATIncluded'));
 
 		$created = $object->Create();
 
 		if ( $created ) {
 			$id = $object->GetID();
 
 			$this->Application->SetVar($event->getPrefixSpecial(true) . '_id', $id);
 			$this->Application->StoreVar($event->getPrefixSpecial(true) . '_id', $id);
 			$this->Application->Session->SetCookie('shop_cart_cookie', $id, strtotime('+1 month'));
 
 			return $id;
 		}
 
 		return 0;
 	}
 
 	/**
 	 * Returns default payment type for order
 	 *
 	 * @return int
 	 */
 	function _getDefaultPaymentType()
 	{
 		$default_type = $this->Application->siteDomainField('PrimaryPaymentTypeId');
 
 		if (!$default_type) {
 			$sql = 'SELECT PaymentTypeId
 					FROM ' . TABLE_PREFIX . 'PaymentTypes
 					WHERE IsPrimary = 1';
 			$default_type = $this->Conn->GetOne($sql);
 		}
 
 		return $default_type;
 	}
 
 	function StoreContinueShoppingLink()
 	{
 		$this->Application->StoreVar('continue_shopping', 'external:'.PROTOCOL.SERVER_NAME.$this->Application->RecallVar('last_url'));
 	}
 
 	/**
 	 * Sets required fields for order, based on current checkout step
 	 * !!! Do not use switch here, since all cases may be on the same form simultaneously
 	 *
 	 * @param kEvent $event
 	 */
 	function SetStepRequiredFields($event)
 	{
 		$order = $event->getObject();
 		/* @var $order OrdersItem */
 
 		$cs_helper = $this->Application->recallObject('CountryStatesHelper');
 		/* @var $cs_helper kCountryStatesHelper */
 
 		$items_info = $this->Application->GetVar($event->getPrefixSpecial(true));
 		if ($items_info) {
 			// updated address available from SUBMIT -> use it
 			list($id, $field_values) = each($items_info);
 		}
 		else {
 			// no updated address -> use current address
 			$field_values = Array (
 				'ShippingCountry' => $order->GetDBField('ShippingCountry'),
 				'BillingCountry' => $order->GetDBField('BillingCountry'),
 				'PaymentType' => $order->GetDBField('PaymentType'),
 			);
 		}
 
 		// shipping address required fields
 		if ($this->Application->GetVar('check_shipping_address')) {
 			$has_tangibles = $order->HasTangibleItems();
 			$req_fields = array('ShippingTo', 'ShippingAddress1', 'ShippingCity', 'ShippingZip', 'ShippingCountry', /*'ShippingPhone',*/ 'BillingEmail');
 			$order->setRequired($req_fields, $has_tangibles);
 			$order->setRequired('ShippingState', $cs_helper->CountryHasStates( $field_values['ShippingCountry'] ));
 		}
 
 		// billing address required fields
 		if ($this->Application->GetVar('check_billing_address')) {
 			$req_fields = array('BillingTo', 'BillingAddress1', 'BillingCity', 'BillingZip', 'BillingCountry', 'BillingPhone', 'BillingEmail');
 			$order->setRequired($req_fields);
 			$order->setRequired('BillingState', $cs_helper->CountryHasStates( $field_values['BillingCountry'] ));
 		}
 
 		$check_cc = $this->Application->GetVar('check_credit_card');
 
 		if ( $check_cc && ($field_values['PaymentType'] == $order->GetDBField('PaymentType')) ) {
 			// cc check required AND payment type was not changed during SUBMIT
 			if ( $this->Application->isAdminUser ) {
 				$req_fields = Array (/*'PaymentCardType',*/ 'PaymentAccount', /*'PaymentNameOnCard',*/ 'PaymentCCExpDate');
 			}
 			else {
 				$req_fields = Array (/*'PaymentCardType',*/ 'PaymentAccount', /*'PaymentNameOnCard',*/ 'PaymentCCExpDate', 'PaymentCVV2');
 			}
 
 			$order->setRequired($req_fields);
 		}
 	}
 
 	/**
 	 * Set's order's user_id to user from session or Guest otherwise
 	 *
 	 * @param kEvent $event
 	 */
 	function CheckUser($event)
 	{
 		if ($this->Application->isAdminUser || defined('GW_NOTIFY')) {
 			// don't check for user in order while processing payment
 			// gateways, because they can do cross-domain ssl redirects
 			return;
 		}
 
 		$order = $event->getObject();
 		/* @var $order OrdersItem */
 
 		$ses_user = $this->Application->RecallVar('user_id');
 
 		if ( $order->GetDBField('PortalUserId') != $ses_user ) {
 			if ( $ses_user == 0 ) {
 				$ses_user = USER_GUEST;
 			}
 
 			$order->SetDBField('PortalUserId', $ses_user);
 			// since CheckUser is called in OnBeforeItemUpdate, we don't need to call udpate here, just set the field
 		}
 	}
 
 	/* ======================== ADMIN ONLY ======================== */
 
 	/**
 	 * Prepare temp tables for creating new item
 	 * but does not create it. Actual create is
 	 * done in OnPreSaveCreated
 	 *
 	 * @param kEvent $event
 	 * @return void
 	 * @access protected
 	 */
 	protected function OnPreCreate(kEvent $event)
 	{
 		parent::OnPreCreate($event);
 
 		$object = $event->getObject();
 		/* @var $object kDBItem */
 
 		$this->setNextOrderNumber($event);
 
-		$object->SetDBField('OrderIP', $_SERVER['REMOTE_ADDR']);
+		$object->SetDBField('OrderIP', $this->Application->getClientIp());
 
 		$order_type = $this->getTypeBySpecial( $this->Application->GetVar('order_type') );
 		$object->SetDBField('Status', $order_type);
 	}
 
 	/**
 	 * When cloning orders set new order number to them
 	 *
 	 * @param kEvent $event
 	 * @return void
 	 * @access protected
 	 */
 	protected function OnBeforeClone(kEvent $event)
 	{
 		parent::OnBeforeClone($event);
 
 		$object = $event->getObject();
 		/* @var $object OrdersItem */
 
 		if ( substr($event->Special, 0, 9) == 'recurring' ) {
 			$object->SetDBField('SubNumber', $object->getNextSubNumber());
 			$object->SetDBField('OriginalAmount', 0); // needed in this case ?
 		}
 		else {
 			$this->setNextOrderNumber($event);
 			$object->SetDBField('OriginalAmount', 0);
 		}
 		$object->SetDBField('OrderDate', adodb_mktime());
 		$object->UpdateFormattersSubFields();
 		$object->SetDBField('GWResult1', '');
 		$object->SetDBField('GWResult2', '');
 	}
 
 	function OnReserveItems($event)
 	{
 		$order_items = $this->Application->recallObject('orditems.-inv','orditems_List',Array('skip_counting'=>true,'per_page'=>-1) );
 		/* @var $order_items kDBList */
 
 		$order_items->linkToParent('-inv');
 		// force re-query, since we are updateing through orditem ITEM, not the list, and
 		// OnReserveItems may be called 2 times when fullfilling backorders through product edit - first time
 		// from FullFillBackorders and second time from OnOrderProcess
 		$order_items->Query(true);
 		$order_items->GoFirst();
 
 		// query all combinations used in this order
 
 
 		$product_object = $this->Application->recallObject('p', null, Array('skip_autoload' => true));
 		/* @var $product_object kCatDBItem */
 
 		$product_object->SwitchToLive();
 
 		$order_item = $this->Application->recallObject('orditems.-item', null, Array('skip_autoload' => true));
 		/* @var $order_item kDBItem */
 
 		$combination_item = $this->Application->recallObject('poc.-item', null, Array('skip_autoload' => true));
 		/* @var $combination_item kDBItem */
 
 		$combinations = $this->queryCombinations($order_items);
 
 		$event->status = kEvent::erSUCCESS;
 		while (!$order_items->EOL()) {
 			$rec = $order_items->getCurrentRecord();
 			$product_object->Load( $rec['ProductId'] );
 			if (!$product_object->GetDBField('InventoryStatus')) {
 				$order_items->GoNext();
 				continue;
 			}
 
 			$inv_object =& $this->getInventoryObject($product_object, $combination_item, $combinations[ $rec['ProductId'].'_'.$rec['OptionsSalt'] ]);
 
 			$lack = $rec['Quantity'] - $rec['QuantityReserved'];
 			if ($lack > 0) {
 				// reserve lack or what is available (in case if we need to reserve anything, by Alex)
 				$to_reserve = min($lack, $inv_object->GetDBField('QtyInStock') - $product_object->GetDBField('QtyInStockMin'));
 
 			if ($to_reserve < $lack) $event->status = kEvent::erFAIL; // if we can't reserve the full lack
 
 			//reserve in order
 			$order_item->SetDBFieldsFromHash($rec);
 			$order_item->SetDBField('QuantityReserved', $rec['QuantityReserved'] + $to_reserve);
 			$order_item->SetId($rec['OrderItemId']);
 			$order_item->Update();
 
 			//update product - increase reserved, decrease in stock
 				$inv_object->SetDBField('QtyReserved', $inv_object->GetDBField('QtyReserved') + $to_reserve);
 				$inv_object->SetDBField('QtyInStock', $inv_object->GetDBField('QtyInStock') - $to_reserve);
 				$inv_object->SetDBField('QtyBackOrdered', $inv_object->GetDBField('QtyBackOrdered') - $to_reserve);
 				$inv_object->Update();
 
 				if ($product_object->GetDBField('InventoryStatus') == 2) {
 					// inventory by options, then restore changed combination values back to common $combinations array !!!
 					$combinations[ $rec['ProductId'].'_'.$rec['OptionsSalt'] ] = $inv_object->GetFieldValues();
 				}
 			}
 			$order_items->GoNext();
 		}
 		return true;
 	}
 
 	function OnOrderPrint($event)
 	{
 		$event->SetRedirectParam('opener', 's');
 	}
 
 	/**
 	 * Processes order each tab info resetting to other tab info / to user info
 	 *
 	 * @param kEvent $event
 	 * @access public
 	 */
 	function OnResetAddress($event)
 	{
 		$to_tab = $this->Application->GetVar('to_tab');
 		$from_tab = substr($event->Name, strlen('OnResetTo'));
 
 		// load values from db
 		$object = $event->getObject();
 		/* @var $object kDBItem */
 
 		// update values from submit
 		$field_values = $this->getSubmittedFields($event);
 		$object->SetFieldsFromHash($field_values, $this->getRequestProtectedFields($field_values));
 
 		$this->DoResetAddress($object, $from_tab, $to_tab);
 
 		$object->Update();
 		$event->redirect = false;
 	}
 
 	/**
 	 * Processes item selection from popup item selector
 	 *
 	 * @todo Is this called ? (by Alex)
 	 * @param kEvent $event
 	 */
 	function OnProcessSelected($event)
 	{
 		$selected_ids = $this->Application->GetVar('selected_ids');
 		$product_ids = $selected_ids['p'];
 
 		if ($product_ids) {
 			$product_ids = explode(',', $product_ids);
 
 			// !!! LOOK OUT - Adding items to Order in admin is handled in order_ITEMS_event_handler !!!
 			foreach ($product_ids as $product_id) {
 				$this->AddItemToOrder($event, $product_id);
 			}
 		}
 
 		$event->SetRedirectParam('opener', 'u');
 	}
 
 	function OnMassPlaceOrder($event)
 	{
 		$object = $event->getObject( Array('skip_autoload' => true) );
 		$ids = $this->StoreSelectedIDs($event);
 
 		if($ids)
 		{
 			foreach($ids as $id)
 			{
 				$object->Load($id);
 				$this->DoPlaceOrder($event);
 			}
 		}
 		$event->status = kEvent::erSUCCESS;
 
 	}
 
 
 
 	/**
 	 * Universal
 	 * Checks if QtyInStock is enough to fullfill backorder (Qty - QtyReserved in order)
 	 *
 	 * @param int $ord_id
 	 * @return bool
 	 */
 	function ReadyToProcess($ord_id)
 	{
 		$poc_table = $this->Application->getUnitOption('poc', 'TableName');
 		$query = '	SELECT SUM(IF( IF('.TABLE_PREFIX.'Products.InventoryStatus = 2, '.$poc_table.'.QtyInStock, '.TABLE_PREFIX.'Products.QtyInStock) - '.TABLE_PREFIX.'Products.QtyInStockMin >= ('.TABLE_PREFIX.'OrderItems.Quantity - '.TABLE_PREFIX.'OrderItems.QuantityReserved), 0, 1))
 							FROM '.TABLE_PREFIX.'OrderItems
 					LEFT JOIN '.TABLE_PREFIX.'Products ON '.TABLE_PREFIX.'Products.ProductId = '.TABLE_PREFIX.'OrderItems.ProductId
 					LEFT JOIN '.$poc_table.' ON ('.$poc_table.'.CombinationCRC = '.TABLE_PREFIX.'OrderItems.OptionsSalt) AND ('.$poc_table.'.ProductId = '.TABLE_PREFIX.'OrderItems.ProductId)
 							WHERE OrderId = '.$ord_id.'
 							GROUP BY OrderId';
 
 		// IF (IF(InventoryStatus = 2, poc.QtyInStock, p.QtyInStock) - QtyInStockMin >= (Quantity - QuantityReserved), 0, 1
 		return ($this->Conn->GetOne($query) == 0);
 	}
 
 	/**
 	 * Return all option combinations used in order
 	 *
 	 * @param kDBList $order_items
 	 * @return Array
 	 */
 	function queryCombinations(&$order_items)
 	{
 		// 1. collect combination crc used in order
 		$combinations = Array();
 		while (!$order_items->EOL()) {
 			$row = $order_items->getCurrentRecord();
 			if ($row['OptionsSalt'] == 0) {
 				$order_items->GoNext();
 				continue;
 			}
 			$combinations[] = '(poc.ProductId = '.$row['ProductId'].') AND (poc.CombinationCRC = '.$row['OptionsSalt'].')';
 			$order_items->GoNext();
 		}
 		$order_items->GoFirst();
 		$combinations = array_unique($combinations); // if same combination+product found as backorder & normal order item
 
 		if ($combinations) {
 			// 2. query data about combinations
 			$poc_table = $this->Application->getUnitOption('poc', 'TableName');
 			$sql = 'SELECT CONCAT(poc.ProductId, "_", poc.CombinationCRC) AS CombinationKey, poc.*
 					FROM '.$poc_table.' poc
 					WHERE ('.implode(') OR (', $combinations).')';
 
 			return $this->Conn->Query($sql, 'CombinationKey');
 		}
 
 		return Array();
 	}
 
 	/**
 	 * Returns object to perform inventory actions on
 	 *
 	 * @param ProductsItem $product current product object in order
 	 * @param kDBItem $combination combination dummy object
 	 * @param Array $combination_data pre-queried combination data
 	 * @return kDBItem
 	 */
 	function &getInventoryObject(&$product, &$combination, $combination_data)
 	{
 		if ($product->GetDBField('InventoryStatus') == 2) {
 			// inventory by option combinations
 			$combination->SetDBFieldsFromHash($combination_data);
 			$combination->setID($combination_data['CombinationId']);
 			$change_item =& $combination;
 		}
 		else {
 			// inventory by product ifself
 			$change_item =& $product;
 		}
 
 		return $change_item;
 	}
 
 	/**
 	 * Approve order ("Pending" tab)
 	 *
 	 * @param kDBList $order_items
 	 * @return int new status of order if any
 	 */
 	function approveOrder(&$order_items)
 	{
 		$product_object = $this->Application->recallObject('p', null, Array('skip_autoload' => true));
 		$order_item = $this->Application->recallObject('orditems.-item', null, Array('skip_autoload' => true));
 		$combination_item = $this->Application->recallObject('poc.-item', null, Array('skip_autoload' => true));
 
 		$combinations = $this->queryCombinations($order_items);
 
 		while (!$order_items->EOL()) {
 			$rec = $order_items->getCurrentRecord();
 
 			$order_item->SetDBFieldsFromHash($rec);
 			$order_item->SetId($rec['OrderItemId']);
 			$order_item->SetDBField('QuantityReserved', 0);
 			$order_item->Update();
 
 			$product_object->Load( $rec['ProductId'] );
 			if (!$product_object->GetDBField('InventoryStatus')) {
 				// if no inventory info is collected, then skip this order item
 				$order_items->GoNext();
 				continue;
 			}
 
 			$inv_object =& $this->getInventoryObject($product_object, $combination_item, $combinations[ $rec['ProductId'].'_'.$rec['OptionsSalt'] ]);
 
 			// decrease QtyReserved by amount of product used in order
 			$inv_object->SetDBField('QtyReserved', $inv_object->GetDBField('QtyReserved') - $rec['Quantity']);
 			$inv_object->Update();
 
 			if ($product_object->GetDBField('InventoryStatus') == 2) {
 				// inventory by options, then restore changed combination values back to common $combinations array !!!
 				$combinations[ $rec['ProductId'].'_'.$rec['OptionsSalt'] ] = $inv_object->GetFieldValues();
 			}
 
 			$order_items->GoNext();
 		}
 		return true;
 	}
 
 	/**
 	 * Restores reserved items in the order
 	 *
 	 * @param kDBList $order_items
 	 * @return bool
 	 */
 	function restoreOrder(&$order_items)
 	{
 		$product_object = $this->Application->recallObject('p', null, Array('skip_autoload' => true));
 		/* @var $product_object kCatDBItem */
 
 		$product_object->SwitchToLive();
 
 		$order_item = $this->Application->recallObject('orditems.-item', null, Array('skip_autoload' => true));
 		/* @var $order_item kDBItem */
 
 		$combination_item = $this->Application->recallObject('poc.-item', null, Array('skip_autoload' => true));
 		/* @var $combination_item kDBItem */
 
 		$combinations = $this->queryCombinations($order_items);
 
 		while( !$order_items->EOL() )
 		{
 			$rec = $order_items->getCurrentRecord();
 
 			$product_object->Load( $rec['ProductId'] );
 			if (!$product_object->GetDBField('InventoryStatus')) {
 				// if no inventory info is collected, then skip this order item
 				$order_items->GoNext();
 				continue;
 			}
 
 			$inv_object =& $this->getInventoryObject($product_object, $combination_item, $combinations[ $rec['ProductId'].'_'.$rec['OptionsSalt'] ]);
 
 			// cancelling backorderd qty if any
 			$lack = $rec['Quantity'] - $rec['QuantityReserved'];
 			if ($lack > 0 && $rec['BackOrderFlag'] > 0) { // lack should have been recorded as QtyBackOrdered
 				$inv_object->SetDBField('QtyBackOrdered', $inv_object->GetDBField('QtyBackOrdered') - $lack);
 			}
 
 			// canceling reservation in stock
 			$inv_object->SetDBField('QtyReserved', $inv_object->GetDBField('QtyReserved') - $rec['QuantityReserved']);
 			// putting remaining freed qty back to stock
 			$inv_object->SetDBField('QtyInStock', $inv_object->GetDBField('QtyInStock') + $rec['QuantityReserved']);
 			$inv_object->Update();
 
 			$product_h = $this->Application->recallObject('p_EventHandler');
 			/* @var $product_h ProductsEventHandler */
 
 			if ($product_object->GetDBField('InventoryStatus') == 2) {
 				// inventory by options, then restore changed combination values back to common $combinations array !!!
 				$combinations[ $rec['ProductId'].'_'.$rec['OptionsSalt'] ] = $inv_object->GetFieldValues();
 
 				// using freed qty to fulfill possible backorders
 				$product_h->FullfillBackOrders($product_object, $inv_object->GetID());
 			}
 			else {
 				// using freed qty to fulfill possible backorders
 				$product_h->FullfillBackOrders($product_object, 0);
 			}
 
 			$order_item->SetDBFieldsFromHash($rec);
 			$order_item->SetId($rec['OrderItemId']);
 			$order_item->SetDBField('QuantityReserved', 0);
 			$order_item->Update();
 
 			$order_items->GoNext();
 		}
 
 		return true;
 	}
 
 	/**
 	 * Approve order + special processing
 	 *
 	 * @param kEvent $event
 	 */
 	function MassInventoryAction($event)
 	{
 		if ( $this->Application->CheckPermission('SYSTEM_ACCESS.READONLY', 1) ) {
 			$event->status = kEvent::erFAIL;
 			return;
 		}
 
 		// process order products
 		$object = $this->Application->recallObject($event->Prefix . '.-inv', null, Array ('skip_autoload' => true));
 		/* @var $object kDBItem */
 
 		$ids = $this->StoreSelectedIDs($event);
 
 		if ( $ids ) {
 			foreach ($ids as $id) {
 				$object->Load($id);
 				$this->InventoryAction($event);
 			}
 		}
 	}
 
 	function InventoryAction($event)
 	{
 		if ($this->Application->CheckPermission('SYSTEM_ACCESS.READONLY', 1)) {
 			$event->status = kEvent::erFAIL;
 			return;
 		}
 
 		$event_status_map = Array(
 			'OnMassOrderApprove'	=> ORDER_STATUS_TOSHIP,
 			'OnOrderApprove' 		=> ORDER_STATUS_TOSHIP,
 			'OnMassOrderDeny'		=> ORDER_STATUS_DENIED,
 			'OnOrderDeny'			=> ORDER_STATUS_DENIED,
 			'OnMassOrderArchive'	=> ORDER_STATUS_ARCHIVED,
 			'OnOrderArchive'		=> ORDER_STATUS_ARCHIVED,
 			'OnMassOrderShip' 		=> ORDER_STATUS_PROCESSED,
 			'OnOrderShip' 			=> ORDER_STATUS_PROCESSED,
 			'OnMassOrderProcess' 	=> ORDER_STATUS_TOSHIP,
 			'OnOrderProcess' 		=> ORDER_STATUS_TOSHIP,
 		);
 
 		$order_items = $this->Application->recallObject('orditems.-inv','orditems_List',Array('skip_counting'=>true,'per_page'=>-1) );
 		/* @var $order_items kDBList */
 
 		$order_items->linkToParent('-inv');
 		$order_items->Query();
 		$order_items->GoFirst();
 
 		$object = $this->Application->recallObject($event->Prefix.'.-inv');
 		/* @var $object OrdersItem */
 
 		if ($object->GetDBField('OnHold')) {
 			// any actions have no effect while on hold
 			return ;
 		}
 
 		// save original order status
 		$original_order_status = $object->GetDBField('Status');
 
 		// preparing new status, but not setting it yet
 		$object->SetDBField('Status', $event_status_map[$event->Name]);
 
 		$set_new_status = false;
 		$event->status = kEvent::erSUCCESS;
 
 		$email_params = $this->OrderEmailParams($object);
 
 		switch ($event->Name) {
 			case 'OnMassOrderApprove':
 			case 'OnOrderApprove':
 				$set_new_status = false; //on successful approve order will be split and new orders will have new statuses
 
 				if ($object->GetDBField('ChargeOnNextApprove')) {
 					$charge_info = $this->ChargeOrder($object);
 					if (!$charge_info['result']) {
 						break;
 					}
 
 					// removing ChargeOnNextApprove
 					$object->SetDBField('ChargeOnNextApprove', 0);
 					$sql = 'UPDATE '.$object->TableName.' SET ChargeOnNextApprove = 0 WHERE '.$object->IDField.' = '.$object->GetID();
 					$this->Conn->Query($sql);
 				}
 
 				// charge user for order in case if we user 2step charging (e.g. AUTH_ONLY + PRIOR_AUTH_CAPTURE)
 				$gw_data = $object->getGatewayData();
 
 				$this->Application->registerClass( $gw_data['ClassName'], GW_CLASS_PATH.'/'.$gw_data['ClassFile'] );
 				$gateway_object = $this->Application->recallObject( $gw_data['ClassName'] );
 				/* @var $gateway_object kGWBase */
 
 				$charge_result = $gateway_object->Charge($object->GetFieldValues(), $gw_data['gw_params']);
 				$sql = 'UPDATE %s SET GWResult2 = %s WHERE %s = %s';
 				$sql = sprintf($sql, $object->TableName, $this->Conn->qstr($gateway_object->getGWResponce()), $object->IDField, $object->GetID() );
 				$this->Conn->Query($sql);
 				$object->SetDBField('GWResult2', $gateway_object->getGWResponce() );
 
 				if ($charge_result) {
 					$product_object = $this->Application->recallObject('p', null, Array('skip_autoload' => true));
 					/* @var $product_object ProductsItem */
 
 					foreach ($order_items->Records as $product_item) {
 						if (!$product_item['ProductId']) {
 							 // product may have been deleted
 							continue;
 						}
 						$product_object->Load($product_item['ProductId']);
 						$hits = floor( $product_object->GetDBField('Hits') ) + 1;
 						$sql = 'SELECT MAX(Hits) FROM '.$this->Application->getUnitOption('p', 'TableName').'
 								WHERE FLOOR(Hits) = '.$hits;
 						$hits = ( $res = $this->Conn->GetOne($sql) ) ? $res + 0.000001 : $hits;
 						$product_object->SetDBField('Hits', $hits);
 						$product_object->Update();
 
 						/*$sql = 'UPDATE '.$this->Application->getUnitOption('p', 'TableName').'
 								SET Hits = Hits + '.$product_item['Quantity'].'
 								WHERE ProductId = '.$product_item['ProductId'];
 						$this->Conn->Query($sql);*/
 					}
 
 					$this->PrepareCoupons($event, $object);
 					$this->SplitOrder($event, $object);
-					if ($object->GetDBField('IsRecurringBilling') != 1) {
-						$this->Application->EmailEventUser('ORDER.APPROVE', $object->GetDBField('PortalUserId'), $email_params);
+
+					if ( $object->GetDBField('IsRecurringBilling') != 1 ) {
+						$this->Application->emailUser('ORDER.APPROVE', null, $email_params);
 
 						// Mask credit card with XXXX
-						if ($this->Application->ConfigValue('Comm_MaskProcessedCreditCards')) {
+						if ( $this->Application->ConfigValue('Comm_MaskProcessedCreditCards') ) {
 							$this->maskCreditCard($object, 'PaymentAccount');
 							$set_new_status = 1;
 						}
 					}
 				}
 
 				break;
 
 			case 'OnMassOrderDeny':
 			case 'OnOrderDeny':
 				foreach ($order_items->Records as $product_item) {
 					if (!$product_item['ProductId']) {
 						 // product may have been deleted
 						continue;
 					}
 					$this->raiseProductEvent('Deny', $product_item['ProductId'], $product_item);
 				}
 
-				if ( ($original_order_status != ORDER_STATUS_INCOMPLETE ) && ($event->Name == 'OnMassOrderDeny' || $event->Name == 'OnOrderDeny') ) {
-					$this->Application->EmailEventUser('ORDER.DENY', $object->GetDBField('PortalUserId'), $email_params);
+				if ( ($original_order_status != ORDER_STATUS_INCOMPLETE) && ($event->Name == 'OnMassOrderDeny' || $event->Name == 'OnOrderDeny') ) {
+					$this->Application->emailUser('ORDER.DENY', null, $email_params);
 
 					// inform payment gateway that order was declined
 					$gw_data = $object->getGatewayData();
 
 					if ( $gw_data ) {
-						$this->Application->registerClass( $gw_data['ClassName'], GW_CLASS_PATH . '/' . $gw_data['ClassFile'] );
-						$gateway_object = $this->Application->recallObject( $gw_data['ClassName'] );
+						$this->Application->registerClass($gw_data['ClassName'], GW_CLASS_PATH . '/' . $gw_data['ClassFile']);
+						$gateway_object = $this->Application->recallObject($gw_data['ClassName']);
 
 						$gateway_object->OrderDeclined($object->GetFieldValues(), $gw_data['gw_params']);
 					}
 				}
 
 				// !!! LOOK HERE !!!
 				// !!!! no break !!!! here on purpose!!!
 			case 'OnMassOrderArchive':
 			case 'OnOrderArchive':
 				// it's critical to update status BEFORE processing items because
 				// FullfillBackorders could be called during processing and in case
 				// of order denial/archive fullfill could reserve the qtys back for current backorder
 				$object->Update();
 				$this->restoreOrder($order_items);
 				$set_new_status = false; // already set
 				break;
 
 			case 'OnMassOrderShip':
 			case 'OnOrderShip':
 				$ret = Array ();
 				$shipping_info = $object->GetDBField('ShippingInfo');
 
 				if ($shipping_info) {
 					$quote_engine_collector = $this->Application->recallObject('ShippingQuoteCollector');
 					/* @var $quote_engine_collector ShippingQuoteCollector */
 
 					$shipping_info = unserialize($shipping_info);
 					$sqe_class_name = $quote_engine_collector->GetClassByType($shipping_info, 1);
 				}
 
 				// try to create usps order
 				if (($object->GetDBField('ShippingType') == 0) && ($sqe_class_name !== false)) {
 					$shipping_quote_engine = $this->Application->recallObject($sqe_class_name);
 					/* @var $shipping_quote_engine ShippingQuoteEngine */
 
 					$ret = $shipping_quote_engine->MakeOrder($object);
 				}
 
 				if ( !array_key_exists('error_number', $ret) ) {
 					$set_new_status = $this->approveOrder($order_items);
 
-	//				$set_new_status = $this->shipOrder($order_items);
+//					$set_new_status = $this->shipOrder($order_items);
 					$object->SetDBField('ShippingDate', adodb_mktime());
 					$object->UpdateFormattersSubFields();
 
 					$shipping_email = $object->GetDBField('ShippingEmail');
 					$email_params['to_email'] = $shipping_email ? $shipping_email : $email_params['_user_email'];
-					$this->Application->EmailEventUser('ORDER.SHIP', $object->GetDBField('PortalUserId'), $email_params);
+					$this->Application->emailUser('ORDER.SHIP', null, $email_params);
 
 					// inform payment gateway that order was shipped
 					$gw_data = $object->getGatewayData();
 
-					$this->Application->registerClass( $gw_data['ClassName'], GW_CLASS_PATH.'/'.$gw_data['ClassFile'] );
-					$gateway_object = $this->Application->recallObject( $gw_data['ClassName'] );
+					$this->Application->registerClass($gw_data['ClassName'], GW_CLASS_PATH . '/' . $gw_data['ClassFile']);
+					$gateway_object = $this->Application->recallObject($gw_data['ClassName']);
 
 					$gateway_object->OrderShipped($object->GetFieldValues(), $gw_data['gw_params']);
 				}
 				else {
 					$sqe_errors = $this->Application->RecallVar('sqe_errors');
 					$sqe_errors = $sqe_errors ? unserialize($sqe_errors) : Array ();
 					$sqe_errors[ $object->GetField('OrderNumber') ] = $ret['error_description'];
 
 					$this->Application->StoreVar('sqe_errors', serialize($sqe_errors));
 				}
 				break;
 
 			case 'OnMassOrderProcess':
 			case 'OnOrderProcess':
-				if ($this->ReadyToProcess($object->GetID())) {
+				if ( $this->ReadyToProcess($object->GetID()) ) {
 					$event->CallSubEvent('OnReserveItems');
-					if ($event->status == kEvent::erSUCCESS) $set_new_status = true;
-					$this->Application->EmailEventUser('BACKORDER.PROCESS', $object->GetDBField('PortalUserId'), $email_params);
-				} else {
+
+					if ( $event->status == kEvent::erSUCCESS ) {
+						$set_new_status = true;
+					}
+
+					$this->Application->emailUser('BACKORDER.PROCESS', null, $email_params);
+				}
+				else {
 					$event->status = kEvent::erFAIL;
 				}
 				break;
 		}
 
-		if ($set_new_status) {
+		if ( $set_new_status ) {
 			$object->Update();
 		}
 	}
 
 	/**
 	 * Hides last 4 digits from credit card number
 	 *
 	 * @param OrdersItem $object
 	 * @param string $field
 	 */
 	function maskCreditCard(&$object, $field)
 	{
 		$value = $object->GetDBField($field);
 		$value = preg_replace('/'.substr($value, -4).'$/', str_repeat('X', 4), $value);
 		$object->SetDBField($field, $value);
 	}
 
 	/**
 	 * Set next available order number
 	 *
 	 * @param kEvent $event
 	 */
 	function setNextOrderNumber($event)
 	{
 		$object = $event->getObject();
 		/* @var $object OrdersItem */
 
 		$sql = 'SELECT MAX(Number)
 				FROM ' . $this->Application->GetLiveName($object->TableName);
 		$next_order_number = $this->Conn->GetOne($sql) + 1;
 
 		$next_order_number = max($next_order_number, $this->Application->ConfigValue('Comm_Next_Order_Number'));
 		$this->Application->SetConfigValue('Comm_Next_Order_Number', $next_order_number + 1);
 
 		$object->SetDBField('Number', $next_order_number);
 		$object->SetDBField('SubNumber', 0);
 
 		// set virtual field too
 		$number_format = (int)$this->Application->ConfigValue('Comm_Order_Number_Format_P');
 		$sub_number_format = (int)$this->Application->ConfigValue('Comm_Order_Number_Format_S');
 		$order_number = sprintf('%0' . $number_format . 'd', $next_order_number) . '-' . str_repeat('0', $sub_number_format);
 
 		$object->SetDBField('OrderNumber', $order_number);
 	}
 
 	/**
 	 * Set's new order address based on another address from order (e.g. billing from shipping)
 	 *
 	 * @param unknown_type $object
 	 * @param unknown_type $from
 	 * @param unknown_type $to
 	 */
 	function DoResetAddress(&$object, $from, $to)
 	{
 		$fields = Array('To','Company','Phone','Fax','Email','Address1','Address2','City','State','Zip','Country');
 
 		if ($from == 'User') {
 			// skip these fields when coping from user, because they are not present in user profile
 			$tmp_fields = array_flip($fields);
 //			unset($tmp_fields['Company'], $tmp_fields['Fax'], $tmp_fields['Address2']);
 			$fields = array_flip($tmp_fields);
 		}
 
 		// apply modification
 		foreach ($fields as $field_name) {
 			$object->SetDBField($to.$field_name, $object->GetDBField($from.$field_name));
 		}
 	}
 
 	/**
 	 * Set's status incomplete to all cloned orders
 	 *
 	 * @param kEvent $event
 	 * @return void
 	 * @access protected
 	 */
 	protected function OnAfterClone(kEvent $event)
 	{
 		parent::OnAfterClone($event);
 
 		$id = $event->getEventParam('id');
 		$table = $this->Application->getUnitOption($event->Prefix, 'TableName');
 		$id_field = $this->Application->getUnitOption($event->Prefix, 'IDField');
 
 		// set cloned order status to Incomplete
 		$sql = 'UPDATE ' . $table . '
 				SET Status = 0
 				WHERE ' . $id_field . ' = ' . $id;
 		$this->Conn->Query($sql);
 	}
 
 
 	/* ======================== COMMON CODE ======================== */
 
 	/**
 	 * Split one timestamp field into 2 virtual fields
 	 *
 	 * @param kEvent $event
 	 * @return void
 	 * @access protected
 	 */
 	protected function OnAfterItemLoad(kEvent $event)
 	{
 		parent::OnAfterItemLoad($event);
 
 		$object = $event->getObject();
 		/* @var $object kDBItem */
 
 		// get user fields
 		$user_id = $object->GetDBField('PortalUserId');
 
 		if ( $user_id ) {
 			$sql = 'SELECT *, CONCAT(FirstName,\' \',LastName) AS UserTo
 					FROM ' . TABLE_PREFIX . 'Users
 					WHERE PortalUserId = ' . $user_id;
 			$user_info = $this->Conn->GetRow($sql);
 
 			$fields = Array(
 				'UserTo'=>'UserTo','UserPhone'=>'Phone','UserFax'=>'Fax','UserEmail'=>'Email',
 				'UserAddress1'=>'Street','UserAddress2'=>'Street2','UserCity'=>'City','UserState'=>'State',
 				'UserZip'=>'Zip','UserCountry'=>'Country','UserCompany'=>'Company'
 			);
 
 			foreach ($fields as $object_field => $user_field) {
 				$object->SetDBField($object_field, $user_info[$user_field]);
 			}
 		}
 
 		$object->SetDBField('PaymentCVV2', $this->Application->RecallVar('CVV2Code'));
 
 		$cs_helper = $this->Application->recallObject('CountryStatesHelper');
 		/* @var $cs_helper kCountryStatesHelper */
 
 		$cs_helper->PopulateStates($event, 'ShippingState', 'ShippingCountry');
 		$cs_helper->PopulateStates($event, 'BillingState', 'BillingCountry');
 
 		$this->SetStepRequiredFields($event);
 
 		// needed in OnAfterItemUpdate
 		$this->Application->SetVar('OriginalShippingOption', $object->GetDBField('ShippingOption'));
 	}
 
 	/**
 	 * Processes states
 	 *
 	 * @param kEvent $event
 	 * @return void
 	 * @access protected
 	 */
 	protected function OnBeforeItemCreate(kEvent $event)
 	{
 		parent::OnBeforeItemCreate($event);
 
 		$cs_helper = $this->Application->recallObject('CountryStatesHelper');
 		/* @var $cs_helper kCountryStatesHelper */
 
 		$cs_helper->PopulateStates($event, 'ShippingState', 'ShippingCountry');
 		$cs_helper->PopulateStates($event, 'BillingState', 'BillingCountry');
 	}
 
 	/**
 	 * Processes states
 	 *
 	 * @param kEvent $event
 	 * @return void
 	 * @access protected
 	 */
 	protected function OnBeforeItemUpdate(kEvent $event)
 	{
 		parent::OnBeforeItemUpdate($event);
 
 		$object = $event->getObject();
 		/* @var $object OrdersItem */
 
 		$old_payment_type = $object->GetOriginalField('PaymentType');
 		$new_payment_type = $object->GetDBField('PaymentType');
 
 		if ( $new_payment_type != $old_payment_type ) {
 			// payment type changed -> check that it's allowed
 			$available_payment_types = $this->Application->siteDomainField('PaymentTypes');
 
 			if ( $available_payment_types ) {
 				if ( strpos($available_payment_types, '|' . $new_payment_type . '|') === false ) {
 					// payment type isn't allowed in site domain
 					$object->SetDBField('PaymentType', $old_payment_type);
 				}
 			}
 		}
 
 		$cs_helper = $this->Application->recallObject('CountryStatesHelper');
 		/* @var $cs_helper kCountryStatesHelper */
 
 		$cs_helper->PopulateStates($event, 'ShippingState', 'ShippingCountry');
 		$cs_helper->PopulateStates($event, 'BillingState', 'BillingCountry');
 
 		if ( $object->HasTangibleItems() ) {
 			$cs_helper->CheckStateField($event, 'ShippingState', 'ShippingCountry', false);
 		}
 
 		$cs_helper->CheckStateField($event, 'BillingState', 'BillingCountry', false);
 
 		if ( $object->GetDBField('Status') > ORDER_STATUS_PENDING ) {
 			return ;
 		}
 
 		$this->CheckUser($event);
 
 		if ( !$object->GetDBField('OrderIP') ) {
-			$object->SetDBField('OrderIP', $_SERVER['REMOTE_ADDR']);
+			$object->SetDBField('OrderIP', $this->Application->getClientIp());
 		}
 
 		$shipping_option = $this->Application->GetVar('OriginalShippingOption');
 		$new_shipping_option = $object->GetDBField('ShippingOption');
 
 		if ( $shipping_option != $new_shipping_option ) {
 			$this->UpdateShippingOption($event);
 		}
 		else {
 			$this->UpdateShippingTypes($event);
 		}
 		$this->RecalculateProcessingFee($event);
 		$this->UpdateShippingTotal($event);
 		$this->RecalculateGift($event);
 
 		// guess fields from "One Step Checkout" form
 		if ( $object->GetDBField('PaymentAccount') ) {
 			$order_helper = $this->Application->recallObject('OrderHelper');
 			/* @var $order_helper OrderHelper */
 
 			$object->SetDBField('PaymentCardType', $order_helper->getCreditCartType($object->GetDBField('PaymentAccount')));
 		}
 		else {
 			$object->SetDBField('PaymentCardType', '');
 		}
 
 		if ( !$object->GetDBField('PaymentNameOnCard') ) {
 			$object->SetDBField('PaymentNameOnCard', $object->GetDBField('BillingTo'));
 		}
 
 		if ( is_object($event->MasterEvent) && $event->MasterEvent->Name == 'OnUpdateAjax' && $this->Application->GetVar('create_account') && $object->Validate() ) {
 			$this->createAccountFromOrder($event);
 		}
 	}
 
 	/**
 	 * Creates user account
 	 *
 	 * @param kEvent $event
 	 * @return void
 	 * @access protected
 	 */
 	protected function createAccountFromOrder($event)
 	{
 		$order = $event->getObject();
 		/* @var $order OrdersItem */
 
 		$order_helper = $this->Application->recallObject('OrderHelper');
 		/* @var $order_helper OrderHelper */
 
 		$user_fields = $order_helper->getUserFields($order);
 		$user_fields['Password'] = $order->GetDBField('UserPassword_plain');
 		$user_fields['VerifyPassword'] = $order->GetDBField('VerifyUserPassword_plain');
 
 		if ( $order->GetDBField('PortalUserId') == USER_GUEST ) {
 			// will also auto-login user when created
 			$this->Application->SetVar('u_register', Array (USER_GUEST => $user_fields));
 			$this->Application->HandleEvent(new kEvent('u.register:OnCreate'));
 		}
 		else {
 			$user = $this->Application->recallObject('u.current');
 			/* @var $user UsersItem */
 
 			$user->SetFieldsFromHash($user_fields);
 			if ( !$user->Update() ) {
 				$order->SetError('BillingEmail', $user->GetErrorPseudo('Email'));
 			}
 		}
 	}
 
 	/**
 	 * Apply any custom changes to list's sql query
 	 *
 	 * @param kEvent $event
 	 * @return void
 	 * @access protected
 	 * @see kDBEventHandler::OnListBuild()
 	 */
 	protected function SetCustomQuery(kEvent $event)
 	{
 		parent::SetCustomQuery($event);
 
 		$object = $event->getObject();
 		/* @var $object kDBList */
 
 		$types = $event->getEventParam('types');
 		if ( $types == 'myorders' || $types == 'myrecentorders' ) {
 			$user_id = $this->Application->RecallVar('user_id');
 			$object->addFilter('myitems_user1', '%1$s.PortalUserId = ' . $user_id);
 			$object->addFilter('myitems_user2', '%1$s.PortalUserId > 0');
 			$object->addFilter('Status', '%1$s.Status != 0');
 		}
 		else if ($event->Special == 'returns') {
 //			$object->addFilter('returns_filter',TABLE_PREFIX.'Orders.Status = '.ORDER_STATUS_PROCESSED.' AND (
 //				SELECT SUM(ReturnType)
 //				FROM '.TABLE_PREFIX.'OrderItems oi
 //				WHERE oi.OrderId = '.TABLE_PREFIX.'Orders.OrderId
 //			) > 0');
 			$object->addFilter('returns_filter', TABLE_PREFIX . 'Orders.Status = ' . ORDER_STATUS_PROCESSED . ' AND ' . TABLE_PREFIX . 'Orders.ReturnTotal > 0');
 		}
 		else if ( $event->Special == 'user' ) {
 			$user_id = $this->Application->GetVar('u_id');
 			$object->addFilter('user_filter', '%1$s.PortalUserId = ' . $user_id);
 		}
 		else {
 			$special = $event->Special ? $event->Special : $this->Application->GetVar('order_type');
 			if ( $special != 'search' ) {
 				// don't filter out orders by special in case of search tab
 				$object->addFilter('status_filter', '%1$s.Status=' . $this->getTypeBySpecial($special));
 			}
 
 			if ( $event->getEventParam('selected_only') ) {
 				$ids = $this->StoreSelectedIDs($event);
 				$object->addFilter('selected_filter', '%1$s.OrderId IN (' . implode(',', $ids) . ')');
 			}
 		}
 	}
 
 	function getTypeBySpecial($special)
 	{
 		$special2type = Array('incomplete'=>0,'pending'=>1,'backorders'=>2,'toship'=>3,'processed'=>4,'denied'=>5,'archived'=>6);
 		return $special2type[$special];
 	}
 
 	function getSpecialByType($type)
 	{
 		$type2special = Array(0=>'incomplete',1=>'pending',2=>'backorders',3=>'toship',4=>'processed',5=>'denied',6=>'archived');
 		return $type2special[$type];
 	}
 
 	function LockTables($event)
 	{
 		$read = Array();
 		$write_lock = '';
 		$read_lock = '';
 		$write = Array('Orders','OrderItems','Products');
 		foreach ($write as $tbl) {
 			$write_lock .= TABLE_PREFIX.$tbl.' WRITE,';
 		}
 		foreach ($read as $tbl) {
 			$read_lock .= TABLE_PREFIX.$tbl.' READ,';
 		}
 		$write_lock = rtrim($write_lock, ',');
 		$read_lock = rtrim($read_lock, ',');
 		$lock = trim($read_lock.','.$write_lock, ',');
 		//$this->Conn->Query('LOCK TABLES '.$lock);
 	}
 
 	/**
 	 * Checks shopping cart products quantities
 	 *
 	 * @param kEvent $event
 	 * @return bool
 	 */
 	function CheckQuantites($event)
 	{
 		if ( $this->OnRecalculateItems($event) ) { // if something has changed in the order
 			if ( $this->Application->isAdminUser ) {
 				if ( $this->UseTempTables($event) ) {
 					$event->redirect = 'in-commerce/orders/orders_edit_items';
 				}
 			}
 			else {
 				$event->redirect = $this->Application->GetVar('viewcart_template');
 			}
 
 			return false;
 		}
 
 		return true;
 	}
 
 	function DoPlaceOrder($event)
 	{
 		$order = $event->getObject();
 
 		$table_prefix = $this->TablePrefix($event);
 
 		$this->LockTables($event);
 
 		if (!$this->CheckQuantites($event)) return false;
 
 		//everything is fine - we could reserve items
 		$this->ReserveItems($event);
 		$this->SplitOrder($event, $order);
 		return true;
 	}
 
 	function &queryOrderItems($event, $table_prefix)
 	{
 		$order = $event->getObject();
 		$ord_id = $order->GetId();
 
 		// TABLE_PREFIX and $table_prefix are NOT the same !!!
 		$poc_table = $this->Application->getUnitOption('poc', 'TableName');
 		$query = '	SELECT
 							 BackOrderFlag, '.
 							 $table_prefix.'OrderItems.OrderItemId, '.
 							 $table_prefix.'OrderItems.Quantity, '.
 							 $table_prefix.'OrderItems.QuantityReserved,
 							 IF('.TABLE_PREFIX.'Products.InventoryStatus = 2, '.$poc_table.'.QtyInStock, '.TABLE_PREFIX.'Products.QtyInStock) AS QtyInStock, '.
 							 TABLE_PREFIX.'Products.QtyInStockMin, '.
 							 $table_prefix.'OrderItems.ProductId, '.
 							 TABLE_PREFIX.'Products.InventoryStatus,'.
 							 $table_prefix.'OrderItems.OptionsSalt AS CombinationCRC
 					FROM '.$table_prefix.'OrderItems
 					LEFT JOIN '.TABLE_PREFIX.'Products ON '.TABLE_PREFIX.'Products.ProductId = '.$table_prefix.'OrderItems.ProductId
 					LEFT JOIN '.$poc_table.' ON ('.$poc_table.'.CombinationCRC = '.$table_prefix.'OrderItems.OptionsSalt) AND ('.$poc_table.'.ProductId = '.$table_prefix.'OrderItems.ProductId)
 					WHERE OrderId = '.$ord_id.' AND '.TABLE_PREFIX.'Products.Type = 1
 					ORDER BY BackOrderFlag ASC';
 
 		$items = $this->Conn->Query($query);
 		return $items;
 	}
 
 	function ReserveItems($event)
 	{
 		$table_prefix = $this->TablePrefix($event);
 		$items =& $this->queryOrderItems($event, $table_prefix);
 
 		foreach ($items as $an_item) {
 			if (!$an_item['InventoryStatus']) {
 				$to_reserve = $an_item['Quantity'] - $an_item['QuantityReserved'];
 			}
 			else {
 				if ($an_item['BackOrderFlag'] > 0) { // we don't need to reserve if it's backordered item
 					$to_reserve = 0;
 				}
 				else {
 					$to_reserve = min($an_item['Quantity']-$an_item['QuantityReserved'], $an_item['QtyInStock']-$an_item['QtyInStockMin']); //it should be equal, but just in case
 				}
 
 				$to_backorder = $an_item['BackOrderFlag'] > 0 ? $an_item['Quantity']-$an_item['QuantityReserved'] : 0;
 			}
 
 			if ($to_backorder < 0) $to_backorder = 0; //just in case
 			$query = '	UPDATE '.$table_prefix.'OrderItems
 						SET QuantityReserved = IF(QuantityReserved IS NULL, '.$to_reserve.', QuantityReserved + '.$to_reserve.')
 						WHERE OrderItemId = '.$an_item['OrderItemId'];
 			$this->Conn->Query($query);
 
 			if (!$an_item['InventoryStatus']) continue;
 
 			$update_clause = '	QtyInStock = QtyInStock - '.$to_reserve.',
 							  	QtyReserved = QtyReserved + '.$to_reserve.',
 								QtyBackOrdered = QtyBackOrdered + '.$to_backorder;
 
 			if ($an_item['InventoryStatus'] == 1) {
 				// inventory by product, then update it's quantities
 				$query = '	UPDATE '.TABLE_PREFIX.'Products
 							SET '.$update_clause.'
 								WHERE ProductId = '.$an_item['ProductId'];
 			}
 			else {
 				// inventory = 2 -> by product option combinations
 				$poc_idfield = $this->Application->getUnitOption('poc', 'IDField');
 				$poc_table = $this->Application->getUnitOption('poc', 'TableName');
 				$query = '	UPDATE '.$poc_table.'
 							SET '.$update_clause.'
 							WHERE (ProductId = '.$an_item['ProductId'].') AND (CombinationCRC = '.$an_item['CombinationCRC'].')';
 			}
 			$this->Conn->Query($query);
 		}
 	}
 
 	function FreeItems($event)
 	{
 		$table_prefix = $this->TablePrefix($event);
 		$items =& $this->queryOrderItems($event, $table_prefix);
 
 		foreach ($items as $an_item) {
 				$to_free = $an_item['QuantityReserved'];
 
 				if ($an_item['InventoryStatus']) {
 				if ($an_item['BackOrderFlag'] > 0) { // we don't need to free if it's backordered item
 					$to_free = 0;
 				}
 
 				// what's not reserved goes to backorder in stock for orderitems marked with BackOrderFlag
 				$to_backorder_free = $an_item['BackOrderFlag'] > 0 ? $an_item['Quantity'] - $an_item['QuantityReserved'] : 0;
 				if ($to_backorder_free < 0) $to_backorder_free = 0; //just in case
 
 				$update_clause = '	QtyInStock = QtyInStock + '.$to_free.',
 								  	QtyReserved = QtyReserved - '.$to_free.',
 							  		QtyBackOrdered = QtyBackOrdered - '.$to_backorder_free;
 
 				if ($an_item['InventoryStatus'] == 1) {
 					// inventory by product
 					$query = '	UPDATE '.TABLE_PREFIX.'Products
 								SET '.$update_clause.'
 									WHERE ProductId = '.$an_item['ProductId'];
 				}
 				else {
 					// inventory by option combinations
 					$poc_idfield = $this->Application->getUnitOption('poc', 'IDField');
 					$poc_table = $this->Application->getUnitOption('poc', 'TableName');
 					$query = '	UPDATE '.$poc_table.'
 								SET '.$update_clause.'
 								WHERE (ProductId = '.$an_item['ProductId'].') AND (CombinationCRC = '.$an_item['CombinationCRC'].')';
 				}
 
 					$this->Conn->Query($query);
 				}
 
 			$query = '	UPDATE '.$table_prefix.'OrderItems
 						SET QuantityReserved = IF(QuantityReserved IS NULL, 0, QuantityReserved - '.$to_free.')
 									WHERE OrderItemId = '.$an_item['OrderItemId'];
 				$this->Conn->Query($query);
 		}
 	}
 
 	/**
 	 * Enter description here...
 	 *
 	 * @param kEvent $event
 	 * @param OrdersItem $object
 	 */
 	function SplitOrder($event, &$object)
 	{
 		$affiliate_event = new kEvent('affil:OnOrderApprove');
 		$affiliate_event->setEventParam('Order_PrefixSpecial', $object->getPrefixSpecial() );
 		$this->Application->HandleEvent($affiliate_event);
 
 		$table_prefix = $this->TablePrefix($event);
 		$order =& $object;
 		$ord_id = $order->GetId();
 
 		$shipping_option = $order->GetDBField('ShippingOption');
 		$backorder_select = $shipping_option == 0 ? '0' : 'oi.BackOrderFlag';
 
 
 		// setting PackageNum to 0 for Non-tangible items, for tangibles first package num is always 1
 		$query = '	SELECT oi.OrderItemId
 					FROM ' . $table_prefix . 'OrderItems oi
 					LEFT JOIN ' . TABLE_PREFIX . 'Products p ON p.ProductId = oi.ProductId
 					WHERE p.Type > 1 AND oi.OrderId = ' . $ord_id;
 		$non_tangibles = $this->Conn->GetCol($query);
 
 		if ($non_tangibles) {
 			$query = '	UPDATE ' . $table_prefix . 'OrderItems
 						SET PackageNum = 0
 						WHERE OrderItemId IN (' . implode(',', $non_tangibles) . ')';
 			$this->Conn->Query($query);
 		}
 
 		// grouping_data:
 		// 0 => Product Type
 		// 1 => if NOT tangibale and NOT downloadable - OrderItemId,
 		//			2 => ProductId
 		// 3 => Shipping PackageNum
 		$query = 'SELECT
 					'.$backorder_select.' AS BackOrderFlagCalc,
 					PackageNum,
 					ProductName,
 					ShippingTypeId,
 					CONCAT('.TABLE_PREFIX.'Products.Type,
 						"_",
 						IF ('.TABLE_PREFIX.'Products.Type NOT IN ('.PRODUCT_TYPE_DOWNLOADABLE.','.PRODUCT_TYPE_TANGIBLE.'),
 							CONCAT(OrderItemId, "_", '.TABLE_PREFIX.'Products.ProductId),
 							""),
 						"_",
 						PackageNum
 						) AS Grouping,
 					SUM(Quantity) AS TotalItems,
 					SUM('.$table_prefix.'OrderItems.Weight*Quantity) AS TotalWeight,
 					SUM(Price * Quantity) AS TotalAmount,
 					SUM(QuantityReserved) AS TotalReserved,
 					'.TABLE_PREFIX.'Products.Type AS ProductType
 				FROM '.$table_prefix.'OrderItems
 				LEFT JOIN '.TABLE_PREFIX.'Products
 					ON '.TABLE_PREFIX.'Products.ProductId = '.$table_prefix.'OrderItems.ProductId
 				WHERE OrderId = '.$ord_id.'
 				GROUP BY BackOrderFlagCalc, Grouping
 				ORDER BY BackOrderFlagCalc ASC, PackageNum ASC, ProductType ASC';
 
 		$sub_orders = $this->Conn->Query($query);
 
 		$processed_sub_orders = Array();
 
 		// in case of recurring billing this will not be 0 as usual
 		//$first_sub_number = ($event->Special == 'recurring') ? $object->getNextSubNumber() - 1 : 0;
 		$first_sub_number = $object->GetDBField('SubNumber');
 
 		$next_sub_number = $first_sub_number;
 		$group = 1;
 
 		$order_has_gift = $order->GetDBField('GiftCertificateDiscount') > 0 ? 1 : 0;
 
 		$skip_types = Array (PRODUCT_TYPE_TANGIBLE, PRODUCT_TYPE_DOWNLOADABLE);
 		foreach ($sub_orders as $sub_order_data) {
 			$sub_order = $this->Application->recallObject('ord.-sub'.$next_sub_number, 'ord');
 			/* @var $sub_order OrdersItem */
 
 			if ($this->UseTempTables($event) && $next_sub_number == 0) {
 				$sub_order =& $order;
 			}
 			$sub_order->SetDBFieldsFromHash($order->GetFieldValues());
 			$sub_order->SetDBField('SubNumber', $next_sub_number);
 			$sub_order->SetDBField('SubTotal', $sub_order_data['TotalAmount']);
 
 			$grouping_data = explode('_', $sub_order_data['Grouping']);
 			$named_grouping_data['Type'] = $grouping_data[0];
 
 			if (!in_array($named_grouping_data['Type'], $skip_types)) {
 				$named_grouping_data['OrderItemId'] = $grouping_data[1];
 				$named_grouping_data['ProductId'] = $grouping_data[2];
 				$named_grouping_data['PackageNum'] = $grouping_data[3];
 			}
 			else {
 				$named_grouping_data['PackageNum'] = $grouping_data[2];
 			}
 
 			if ($named_grouping_data['Type'] == PRODUCT_TYPE_TANGIBLE) {
 				$sub_order->SetDBField('ShippingCost', getArrayValue( unserialize($order->GetDBField('ShippingInfo')), $sub_order_data['PackageNum'], 'TotalCost') );
 				$sub_order->SetDBField('InsuranceFee', getArrayValue( unserialize($order->GetDBField('ShippingInfo')), $sub_order_data['PackageNum'], 'InsuranceFee') );
 				$sub_order->SetDBField('ShippingInfo', serialize(Array(1 => getArrayValue( unserialize($order->GetDBField('ShippingInfo')), $sub_order_data['PackageNum']))));
 			}
 			else {
 				$sub_order->SetDBField('ShippingCost', 0);
 				$sub_order->SetDBField('InsuranceFee', 0);
 				$sub_order->SetDBField('ShippingInfo', ''); //otherwise orders w/o shipping wills still have shipping info!
 			}
 
 			$amount_percent = $sub_order->getTotalAmount() * 100 / $order->getTotalAmount();
 			// proportional affiliate commission splitting
 			if ($order->GetDBField('AffiliateCommission') > 0) {
 				$sub_order->SetDBField('AffiliateCommission', $order->GetDBField('AffiliateCommission') * $amount_percent / 100 );
 			}
 
 			$amount_percent = ($sub_order->GetDBField('SubTotal') + $sub_order->GetDBField('ShippingCost')) * 100 / ($order->GetDBField('SubTotal') + $order->GetDBField('ShippingCost'));
 			if ($order->GetDBField('ProcessingFee') > 0) {
 				$sub_order->SetDBField('ProcessingFee', round($order->GetDBField('ProcessingFee') * $amount_percent / 100, 2));
 			}
 
 			$sub_order->RecalculateTax();
 
 			$original_amount = $sub_order->GetDBField('SubTotal') + $sub_order->GetDBField('ShippingCost') + $sub_order->GetDBField('VAT') + $sub_order->GetDBField('ProcessingFee') + $sub_order->GetDBField('InsuranceFee') - $sub_order->GetDBField('GiftCertificateDiscount');
 			$sub_order->SetDBField('OriginalAmount', $original_amount);
 
 			if ($named_grouping_data['Type'] == 1 && ($sub_order_data['BackOrderFlagCalc'] > 0
 					||
 					($sub_order_data['TotalItems'] != $sub_order_data['TotalReserved'])) ) {
 				$sub_order->SetDBField('Status', ORDER_STATUS_BACKORDERS);
 
 				if ($event->Special != 'recurring') { // just in case if admin uses tangible backordered products in recurring orders
-					$this->Application->EmailEventUser('BACKORDER.ADD', $sub_order->GetDBField('PortalUserId'), $this->OrderEmailParams($sub_order));
-		    		$this->Application->EmailEventAdmin('BACKORDER.ADD');
+					$this->Application->emailUser('BACKORDER.ADD', null, $this->OrderEmailParams($sub_order));
+		    		$this->Application->emailAdmin('BACKORDER.ADD');
 				}
 			}
 			else {
 				switch ($named_grouping_data['Type']) {
 					case PRODUCT_TYPE_DOWNLOADABLE:
 						$sql = 'SELECT oi.*
 								FROM '.TABLE_PREFIX.'OrderItems oi
 								LEFT JOIN '.TABLE_PREFIX.'Products p ON p.ProductId = oi.ProductId
 								WHERE (OrderId = %s) AND (p.Type = '.PRODUCT_TYPE_DOWNLOADABLE.')';
 						$downl_products = $this->Conn->Query( sprintf($sql, $ord_id) );
 						$product_ids = Array();
 						foreach ($downl_products as $downl_product) {
 							$this->raiseProductEvent('Approve', $downl_product['ProductId'], $downl_product, $next_sub_number);
 							$product_ids[] = $downl_product['ProductId'];
 						}
 						break;
 
 					case PRODUCT_TYPE_TANGIBLE:
 						$sql = 'SELECT '.$backorder_select.' AS BackOrderFlagCalc, oi.*
 								FROM '.TABLE_PREFIX.'OrderItems oi
 								LEFT JOIN '.TABLE_PREFIX.'Products p ON p.ProductId = oi.ProductId
 								WHERE (OrderId = %s) AND (BackOrderFlagCalc = 0) AND (p.Type = '.PRODUCT_TYPE_TANGIBLE.')';
 
 							$products = $this->Conn->Query( sprintf($sql, $ord_id) );
 							foreach ($products as $product) {
 								$this->raiseProductEvent('Approve', $product['ProductId'], $product, $next_sub_number);
 							}
 						break;
 
 					default:
 						$order_item_fields = $this->Conn->GetRow('SELECT * FROM '.TABLE_PREFIX.'OrderItems WHERE OrderItemId = '.$named_grouping_data['OrderItemId']);
 						$this->raiseProductEvent('Approve', $named_grouping_data['ProductId'], $order_item_fields, $next_sub_number);
 						break;
 				}
 
 				$sub_order->SetDBField('Status', $named_grouping_data['Type'] == PRODUCT_TYPE_TANGIBLE ? ORDER_STATUS_TOSHIP : ORDER_STATUS_PROCESSED);
 			}
 
 			if ($next_sub_number == $first_sub_number) {
 				$sub_order->SetId($order->GetId());
 				$sub_order->Update();
 			}
 			else {
 				$sub_order->Create();
 			}
 
 			switch ($named_grouping_data['Type']) {
 				case PRODUCT_TYPE_TANGIBLE:
 					$query = 'UPDATE '.$table_prefix.'OrderItems SET OrderId = %s WHERE OrderId = %s AND PackageNum = %s';
 					$query = sprintf($query, $sub_order->GetId(), $ord_id, $sub_order_data['PackageNum']);
 					break;
 
 				case PRODUCT_TYPE_DOWNLOADABLE:
 					$query = 'UPDATE '.$table_prefix.'OrderItems SET OrderId = %s WHERE OrderId = %s AND ProductId IN (%s)';
 					$query = sprintf($query, $sub_order->GetId(), $ord_id, implode(',', $product_ids) );
 					break;
 
 				default:
 					$query = 'UPDATE '.$table_prefix.'OrderItems SET OrderId = %s WHERE OrderId = %s AND OrderItemId = %s';
 					$query = sprintf($query, $sub_order->GetId(), $ord_id, $named_grouping_data['OrderItemId']);
 					break;
 			}
 
 			$this->Conn->Query($query);
 
 			if ($order_has_gift) {
 				// gift certificate can be applied only after items are assigned to suborder
 				$sub_order->RecalculateGift($event);
 				$original_amount = $sub_order->GetDBField('SubTotal') + $sub_order->GetDBField('ShippingCost') + $sub_order->GetDBField('VAT') + $sub_order->GetDBField('ProcessingFee') + $sub_order->GetDBField('InsuranceFee') - $sub_order->GetDBField('GiftCertificateDiscount');
 				$sub_order->SetDBField('OriginalAmount', $original_amount);
 				$sub_order->Update();
 			}
 
 			$processed_sub_orders[] = $sub_order->GetID();
 
 			$next_sub_number++;
 			$group++;
 		}
 
 		foreach ($processed_sub_orders as $sub_id) {
 			// update DiscountTotal field
 			$sql = 'SELECT SUM(ROUND(FlatPrice-Price,2)*Quantity) FROM '.$table_prefix.'OrderItems WHERE OrderId = '.$sub_id;
 			$discount_total = $this->Conn->GetOne($sql);
 
 			$sql = 'UPDATE '.$sub_order->TableName.'
 					SET DiscountTotal = '.$this->Conn->qstr($discount_total).'
 					WHERE OrderId = '.$sub_id;
 			$this->Conn->Query($sql);
 		}
 	}
 
 	/**
 	 * Call products linked event when spefcfic action is made to product in order
 	 *
 	 * @param string $event_type type of event to get from product ProcessingData = {Approve,Deny,CompleteOrder}
 	 * @param int $product_id ID of product to gather processing data from
 	 * @param Array $order_item_fields OrderItems table record fields (with needed product & order in it)
 	 */
 	function raiseProductEvent($event_type, $product_id, $order_item_fields, $next_sub_number=null)
 	{
 		$sql = 'SELECT ProcessingData
 				FROM '.TABLE_PREFIX.'Products
 				WHERE ProductId = '.$product_id;
 		$processing_data = $this->Conn->GetOne($sql);
 		if ($processing_data) {
 			$processing_data = unserialize($processing_data);
 			$event_key = getArrayValue($processing_data, $event_type.'Event');
 			// if requested type of event is defined for product, only then process it
 			if ($event_key) {
 				$event = new kEvent($event_key);
 				$event->setEventParam('field_values', $order_item_fields);
 				$event->setEventParam('next_sub_number', $next_sub_number);
 				$this->Application->HandleEvent($event);
 			}
 		}
 	}
 
 	function OptionsSalt($options, $comb_only=false)
 	{
 		$helper = $this->Application->recallObject('kProductOptionsHelper');
 		return $helper->OptionsSalt($options, $comb_only);
 	}
 
 	/**
 	 * Enter description here...
 	 *
 	 * @param kEvent $event
 	 * @param int $item_id
 	 */
 	function AddItemToOrder($event, $item_id, $qty = null, $package_num = null)
 	{
 		if (!isset($qty)) {
 			$qty = 1;
 		}
 
 		// Loading product to add
 		$product = $this->Application->recallObject('p.toadd', null, Array('skip_autoload' => true));
 		/* @var $product kDBItem */
 
 		$product->Load($item_id);
 
 		$object = $this->Application->recallObject('orditems.-item', null, Array('skip_autoload' => true));
 		/* @var $object kDBItem */
 
 		$order = $this->Application->recallObject('ord');
 		/* @var $order kDBItem */
 
 		if (!$order->isLoaded() && !$this->Application->isAdmin) {
 			// no order was created before -> create one now
 			if ($this->_createNewCart($event)) {
 				$this->LoadItem($event);
 			}
 		}
 
 		if (!$order->isLoaded()) {
 			// was unable to create new order
 			return false;
 		}
 
 		$item_data = $event->getEventParam('ItemData');
 		$item_data = $item_data ? unserialize($item_data) : Array ();
 		$options = getArrayValue($item_data, 'Options');
 
 		if ( !$this->CheckOptions($event, $options, $item_id, $qty, $product->GetDBField('OptionsSelectionMode')) ) {
 			return;
 		}
 
 		$manager = $this->Application->recallObject('OrderManager');
 		/* @var $manager OrderManager */
 
 		$manager->setOrder($order);
 		$manager->addProduct($product, $event->getEventParam('ItemData'), $qty, $package_num);
 
 		$this->Application->HandleEvent(new kEvent('ord:OnRecalculateItems'));
 	}
 
 	/**
 	 * Enter description here...
 	 *
 	 * @param kEvent $event
 	 */
 	function UpdateShippingTotal($event)
 	{
 		if ( $this->Application->GetVar('ebay_notification') == 1 ) {
 			// TODO: get rid of this "if"
 			return;
 		}
 
 		$object = $event->getObject();
 		/* @var $object OrdersItem */
 
 		$shipping_total = $insurance_fee = 0;
 		$shipping_info = $object->GetDBField('ShippingInfo') ? unserialize($object->GetDBField('ShippingInfo')) : false;
 
 		if ( is_array($shipping_info) ) {
 			foreach ($shipping_info as $a_shipping) {
 //				$id_elements = explode('_', $a_shipping['ShippingTypeId']);
 				$shipping_total += $a_shipping['TotalCost'];
 				$insurance_fee += $a_shipping['InsuranceFee'];
 			}
 		}
 
 		$object->SetDBField('ShippingCost', $shipping_total);
 		$object->SetDBField('InsuranceFee', $insurance_fee);
 		// no need to update, it will be called in calling method
 
 		$this->RecalculateTax($event);
 	}
 
 	/**
 	 * Recompile shopping cart, splitting or grouping orders and backorders depending on total quantities.
 	 * First it counts total qty for each ProductId, and then creates order for available items
 	 * and backorder for others. It also updates the sub-total for the order
 	 *
 	 * @param kEvent $event
 	 * @return bool Returns true if items splitting/grouping were changed
 	 */
 	function OnRecalculateItems($event)
 	{
 		if (is_object($event->MasterEvent) && ($event->MasterEvent->status != kEvent::erSUCCESS)) {
 			// e.g. master order update failed, don't recalculate order products
 			return ;
 		}
 
 		$order = $event->getObject();
 		/* @var $order OrdersItem */
 
 		if ( !$order->isLoaded() ) {
 			$this->LoadItem($event); // try to load
 		}
 
 		$ord_id = (int)$order->GetID();
 
 		if ( !$order->isLoaded() ) return; //order has not been created yet
 
 		if( $order->GetDBField('Status') != ORDER_STATUS_INCOMPLETE )
 		{
 			return;
 		}
 
 		$manager = $this->Application->recallObject('OrderManager');
 		/* @var $manager OrderManager */
 
 		$manager->setOrder($order);
 		$result = $manager->calculate();
 
 		if ( $order->GetDBField('CouponId') && $order->GetDBField('CouponDiscount') == 0 ) {
 			$this->RemoveCoupon($order);
 			$order->setCheckoutError(OrderCheckoutErrorType::COUPON, OrderCheckoutError::COUPON_REMOVED_AUTOMATICALLY);
 		}
 
 		if ( $result ) {
 			$this->UpdateShippingOption($event);
 		}
 
 		$this->UpdateShippingTotal($event);
 
 		$this->RecalculateProcessingFee($event);
 		$this->RecalculateTax($event);
 		$this->RecalculateGift($event);
 
 		if ( $event->Name != 'OnAfterItemUpdate' ) {
 			$order->Update();
 		}
 
 		$event->setEventParam('RecalculateChangedCart', $result);
 
 		if ( is_object($event->MasterEvent) ) {
 			$event->MasterEvent->setEventParam('RecalculateChangedCart', $result);
 		}
 
 		/*if ( $result && !getArrayValue($event->redirect_params, 'checkout_error') ) {
 			$event->SetRedirectParam('checkout_error', OrderCheckoutError::STATE_CHANGED);
 		}*/
 
 		if ( $result && is_object($event->MasterEvent) && $event->MasterEvent->Name == 'OnUserLogin' ) {
 			$shop_cart_template = $this->Application->GetVar('shop_cart_template');
 
 			if ( $shop_cart_template && is_object($event->MasterEvent->MasterEvent) ) {
 //				$event->MasterEvent->MasterEvent->SetRedirectParam('checkout_error', OrderCheckoutError::CHANGED_AFTER_LOGIN);
 				$event->MasterEvent->MasterEvent->redirect = $shop_cart_template;
 			}
 		}
 
 		return $result;
 	}
 
 /*	function GetShippingCost($user_country_id, $user_state_id, $user_zip, $weight, $items, $amount, $shipping_type)
 	{
 		$this->Application->recallObject('ShippingQuoteEngine');
 		$shipping_h = $this->Application->recallObject('CustomShippingQuoteEngine');
 		$query = $shipping_h->QueryShippingCost($user_country_id, $user_state_id, $user_zip, $weight, $items, $amount, $shipping_type);
 		$cost = $this->Conn->GetRow($query);
 		return $cost['TotalCost'];
 	}*/
 
 	/**
 	 * Return product pricing id for given product, if not passed - return primary pricing ID
 	 *
 	 * @param int $product_id ProductId
 	 * @return float
 	 */
 	function GetPricingId($product_id, $item_data)	{
 
 		if (!is_array($item_data)) {
 			$item_data = unserialize($item_data);
 		}
 		$price_id = getArrayValue($item_data, 'PricingId');
 		if (!$price_id) {
 		$price_id = $this->Application->GetVar('pr_id');
 		}
 		if (!$price_id){
 			$price_id = $this->Conn->GetOne('SELECT PriceId FROM '.TABLE_PREFIX.'ProductsPricing WHERE ProductId='.$product_id.' AND IsPrimary=1');
 		}
 		return $price_id;
 	}
 
 	function UpdateShippingOption($event)
 	{
 		$object = $event->getObject();
 		$shipping_option = $object->GetDBField('ShippingOption');
 
 		if($shipping_option == '') return;
 
 		$table_prefix = $this->TablePrefix($event);
 
 		if ($shipping_option == 1 || $shipping_option == 0) { // backorder separately
 			$query = 'UPDATE '.$table_prefix.'OrderItems SET BackOrderFlag = 1 WHERE OrderId = '.$object->GetId().' AND BackOrderFlag > 1';
 			$this->Conn->Query($query);
 		}
 		if ($shipping_option == 2) {
 			$query = 'SELECT * FROM '.$table_prefix.'OrderItems WHERE OrderId = '.$object->GetId().' AND BackOrderFlag >= 1 ORDER By ProductName asc';
 			$items = $this->Conn->Query($query);
 			$backorder_flag = 2;
 			foreach ($items as $an_item) {
 				$query = 'UPDATE '.$table_prefix.'OrderItems SET BackOrderFlag = '.$backorder_flag.' WHERE OrderItemId = '.$an_item['OrderItemId'];
 				$this->Conn->Query($query);
 				$backorder_flag++;
 			}
 		}
 	}
 
 	/**
 	 * Updates shipping types
 	 *
 	 * @param kEvent $event
 	 * @return bool
 	 */
 	function UpdateShippingTypes($event)
 	{
 		$object = $event->getObject();
 		/* @var $object OrdersItem */
 
 		$ord_id = $object->GetID();
 
 		$order_info = $this->Application->GetVar('ord');
 		$shipping_ids = getArrayValue($order_info, $ord_id, 'ShippingTypeId');
 
 		if (!$shipping_ids) {
 			return;
 		}
 
 		$ret = true;
 		$shipping_types = Array();
 		$last_shippings = unserialize( $this->Application->RecallVar('LastShippings') );
 
 		$template = $this->Application->GetVar('t');
 		$shipping_templates = Array ('in-commerce/checkout/shipping', 'in-commerce/orders/orders_edit_shipping');
 
 		$quote_engine_collector = $this->Application->recallObject('ShippingQuoteCollector');
 		/* @var $quote_engine_collector ShippingQuoteCollector */
 
 		foreach ($shipping_ids as $package => $id) {
 			// try to validate
 			$shipping_types[$package] = $last_shippings[$package][$id];
 			$sqe_class_name = $quote_engine_collector->GetClassByType($shipping_types, $package);
 
 			if (($object->GetDBField('ShippingType') == 0) && ($sqe_class_name !== false) && in_array($template, $shipping_templates)) {
 				$shipping_quote_engine = $this->Application->recallObject($sqe_class_name);
 				/* @var $shipping_quote_engine ShippingQuoteEngine */
 
 				// USPS related part
 				// TODO: remove USPS condition from here
 				// set first of found shippings just to check if any errors are returned
 				$current_usps_shipping_types = unserialize($this->Application->RecallVar('current_usps_shipping_types'));
 				$object->SetDBField('ShippingInfo', serialize( Array($package => $current_usps_shipping_types[$id])) );
 
 				$sqe_data = $shipping_quote_engine->MakeOrder($object, true);
 
 				if ( $sqe_data ) {
 					if ( !isset($sqe_data['error_number']) ) {
 						// update only international shipping
 						if ( $object->GetDBField('ShippingCountry') != 'USA') {
 							$shipping_types[$package]['TotalCost'] = $sqe_data['Postage'];
 						}
 					}
 					else {
 						$ret = false;
 						$this->Application->StoreVar('sqe_error', $sqe_data['error_description']);
 					}
 				}
 
 				$object->SetDBField('ShippingInfo', '');
 			}
 		}
 
 		$object->SetDBField('ShippingInfo', serialize($shipping_types));
 
 		return $ret;
 	}
 
 	/*function shipOrder(&$order_items)
 	{
 		$product_object = $this->Application->recallObject('p', null, Array('skip_autoload' => true));
 		$order_item = $this->Application->recallObject('orditems.-item');
 
 		while( !$order_items->EOL() )
 		{
 			$rec = $order_items->getCurrentRecord();
 
 			$order_item->SetDBFieldsFromHash($rec);
 			$order_item->SetId($rec['OrderItemId']);
 			$order_item->SetDBField('QuantityReserved', 0);
 			$order_item->Update();
 
 			$order_items->GoNext();
 		}
 		return true;
 	}*/
 
 	function RecalculateTax($event)
 	{
 		$object = $event->getObject();
 		/* @var $object OrdersItem */
 
 		if ($object->GetDBField('Status') > ORDER_STATUS_PENDING) {
 			return;
 		}
 
 		$object->RecalculateTax();
 	}
 
 	function RecalculateProcessingFee($event)
 	{
 		$object = $event->getObject();
 
 		// Do not reset processing fee while orders are being split (see SplitOrder)
 		if (preg_match("/^-sub/", $object->Special)) return;
 		if ($object->GetDBField('Status') > ORDER_STATUS_PENDING) return; //no changes for orders other than incomple or pending
 
 		$pt = $object->GetDBField('PaymentType');
 		$processing_fee = $this->Conn->GetOne('SELECT ProcessingFee FROM '.$this->Application->getUnitOption('pt', 'TableName').' WHERE PaymentTypeId = '.$pt);
 		$object->SetDBField( 'ProcessingFee', $processing_fee );
 		$this->UpdateTotals($event);
 	}
 
 	function UpdateTotals($event)
 	{
 		$object = $event->getObject();
 		/* @var $object OrdersItem */
 
 		$object->UpdateTotals();
 	}
 
 	/*function CalculateDiscount($event)
 	{
 		$object = $event->getObject();
 
 		$coupon = $this->Application->recallObject('coup', null, Array('skip_autoload' => true));
 		if(!$coupon->Load( $object->GetDBField('CouponId'), 'CouponId' ))
 		{
 			return false;
 		}
 
 		$sql = 'SELECT Price * Quantity AS Amount, ProductId FROM '.$this->Application->getUnitOption('orditems', 'TableName').'
 				WHERE OrderId = '.$object->GetDBField('OrderId');
 		$orditems = $this->Conn->GetCol($sql, 'ProductId');
 
 		$sql = 'SELECT coupi.ItemType, p.ProductId FROM '.$this->Application->getUnitOption('coupi', 'TableName').' coupi
 				LEFT JOIN '.$this->Application->getUnitOption('p', 'TableName').' p
 				ON coupi.ItemResourceId = p.ResourceId
 				WHERE CouponId = '.$object->GetDBField('CouponId');
 		$discounts = $this->Conn->GetCol($sql, 'ProductId');
 
 		$discount_amount = 0;
 
 		foreach($orditems as $product_id => $amount)
 		{
 			if(isset($discounts[$product_id]) || array_search('0', $discounts, true) !== false)
 			{
 				switch($coupon->GetDBField('Type'))
 				{
 					case 1:
 						$discount_amount += $coupon->GetDBField('Amount') < $amount ? $coupon->GetDBField('Amount') : $amount;
 					break;
 					case 2:
 						$discount_amount += $amount * $coupon->GetDBField('Amount') / 100;
 					break;
 					default:
 				}
 				break;
 			}
 		}
 
 		$object->SetDBField('CouponDiscount', $discount_amount);
 		return $discount_amount;
 	}*/
 
 	/**
 	 * Jumps to selected order in order's list from search tab
 	 *
 	 * @param kEvent $event
 	 */
 	function OnGoToOrder($event)
 	{
-		$id = array_shift( $this->StoreSelectedIDs($event) );
+		$id = current($this->StoreSelectedIDs($event));
 
 		$id_field = $this->Application->getUnitOption($event->Prefix,'IDField');
 		$table = $this->Application->getUnitOption($event->Prefix,'TableName');
 
 		$sql = 'SELECT Status FROM %s WHERE %s = %s';
 
 		$order_status = $this->Conn->GetOne( sprintf($sql, $table, $id_field, $id) );
 
 		$prefix_special = $event->Prefix.'.'.$this->getSpecialByType($order_status);
 
 		$orders_list = $this->Application->recallObject($prefix_special, $event->Prefix.'_List', Array('per_page'=>-1) );
 		/* @var $orders_list kDBList */
 
 		$orders_list->Query();
 
 		foreach ($orders_list->Records as $row_num => $record) {
 			if ( $record[$id_field] == $id ) {
 				break;
 			}
 		}
 
 		$per_page = $this->getPerPage( new kEvent($prefix_special.':OnDummy') );
 		$page = ceil( ($row_num+1) / $per_page );
 
 		$this->Application->StoreVar($prefix_special.'_Page', $page);
 		$event->redirect = 'in-commerce/orders/orders_'.$this->getSpecialByType($order_status).'_list';
 	}
 
 	/**
 	 * Reset's any selected order state to pending
 	 *
 	 * @param kEvent $event
 	 */
 	function OnResetToPending($event)
 	{
 		$object = $event->getObject( Array('skip_autoload' => true) );
 		/* @var $object kDBItem */
 
 		$items_info = $this->Application->GetVar($event->getPrefixSpecial(true));
 
 		if ( $items_info ) {
 			foreach ($items_info as $id => $field_values) {
 				$object->Load($id);
 				$object->SetDBField('Status', ORDER_STATUS_PENDING);
 
 				if ( $object->Update() ) {
 					$event->status = kEvent::erSUCCESS;
 				}
 				else {
 					$event->status = kEvent::erFAIL;
 					$event->redirect = false;
 					break;
 				}
 			}
 		}
 	}
 
 	/**
 	 * Creates list from items selected in grid
 	 *
 	 * @param kEvent $event
 	 */
 	function OnLoadSelected($event)
 	{
 		$event->setPseudoClass('_List');
 		$object = $event->getObject( Array('selected_only' => true) );
 		$event->redirect = false;
 	}
 
 	/**
 	 * Return orders list, that will expire in time specified
 	 *
 	 * @param int $pre_expiration timestamp
 	 * @return Array
 	 */
 	function getRecurringOrders($pre_expiration)
 	{
 		$ord_table = $this->Application->getUnitOption('ord', 'TableName');
 		$ord_idfield = $this->Application->getUnitOption('ord', 'IDField');
 
 		$processing_allowed = Array(ORDER_STATUS_PROCESSED, ORDER_STATUS_ARCHIVED);
 		$sql = 'SELECT '.$ord_idfield.', PortalUserId, GroupId, NextCharge
 				FROM '.$ord_table.'
 				WHERE (IsRecurringBilling = 1) AND (NextCharge < '.$pre_expiration.') AND Status IN ('.implode(',', $processing_allowed).')';
 		return $this->Conn->Query($sql, $ord_idfield);
 	}
 
 	/**
 	 * [SCHEDULED TASK] Checks what orders should expire and renew automatically (if such flag set)
 	 *
 	 * @param kEvent $event
 	 */
 	function OnCheckRecurringOrders($event)
 	{
 		$skip_clause = Array();
 		$ord_table = $this->Application->getUnitOption($event->Prefix, 'TableName');
 		$ord_idfield = $this->Application->getUnitOption($event->Prefix, 'IDField');
 
 		$pre_expiration = adodb_mktime() + $this->Application->ConfigValue('Comm_RecurringChargeInverval') * 3600 * 24;
 		$to_charge = $this->getRecurringOrders($pre_expiration);
 		if ($to_charge) {
 			$order_ids = Array();
 			foreach ($to_charge as $order_id => $record) {
 				// skip virtual users (e.g. root, guest, etc.) & invalid subscriptions (with no group specified, no next charge, but Recurring flag set)
 				if (!$record['PortalUserId'] || !$record['GroupId'] || !$record['NextCharge']) continue;
 
 				$order_ids[] = $order_id;
 				// prevent duplicate user+group pairs
 				$skip_clause[ 'PortalUserId = '.$record['PortalUserId'].' AND GroupId = '.$record['GroupId'] ] = $order_id;
 			}
 
 			// process only valid orders
 			$temp_handler = $this->Application->recallObject($event->Prefix.'_TempHandler', 'kTempTablesHandler');
 			$cloned_order_ids = $temp_handler->CloneItems($event->Prefix, 'recurring', $order_ids);
 			$order =&  $this->Application->recallObject($event->Prefix.'.recurring', null, Array('skip_autoload' => true));
 			foreach ($cloned_order_ids as $order_id) {
 				$order->Load($order_id);
 				$this->Application->HandleEvent($complete_event, $event->Prefix.'.recurring:OnCompleteOrder' );
 
 				if ($complete_event->status == kEvent::erSUCCESS) {
 					//send recurring ok email
-					$this->Application->EmailEventUser('ORDER.RECURRING.PROCESSED', $order->GetDBField('PortalUserId'), $this->OrderEmailParams($order));
-					$this->Application->EmailEventAdmin('ORDER.RECURRING.PROCESSED');
+					$this->Application->emailUser('ORDER.RECURRING.PROCESSED', null, $this->OrderEmailParams($order));
+					$this->Application->emailAdmin('ORDER.RECURRING.PROCESSED');
 				}
 				else {
 					//send Recurring failed event
 					$order->SetDBField('Status', ORDER_STATUS_DENIED);
 					$order->Update();
-					$this->Application->EmailEventUser('ORDER.RECURRING.DENIED', $order->GetDBField('PortalUserId'), $this->OrderEmailParams($order));
-					$this->Application->EmailEventAdmin('ORDER.RECURRING.DENIED');
+					$this->Application->emailUser('ORDER.RECURRING.DENIED', null, $this->OrderEmailParams($order));
+					$this->Application->emailAdmin('ORDER.RECURRING.DENIED');
 				}
 			}
 
 			// remove recurring flag from all orders found, not to select them next time script runs
 			$sql = 'UPDATE '.$ord_table.'
 					SET IsRecurringBilling = 0
 					WHERE '.$ord_idfield.' IN ('.implode(',', array_keys($to_charge)).')';
 			$this->Conn->Query($sql);
 		}
 
 		if ( !is_object($event->MasterEvent) ) {
 			// not called as hook
 			return ;
 		}
 
 		$pre_expiration = adodb_mktime() + $this->Application->ConfigValue('User_MembershipExpirationReminder') * 3600 * 24;
 		$to_charge = $this->getRecurringOrders($pre_expiration);
 
 		foreach ($to_charge as $order_id => $record) {
 			// skip virtual users (e.g. root, guest, etc.) & invalid subscriptions (with no group specified, no next charge, but Recurring flag set)
 			if (!$record['PortalUserId'] || !$record['GroupId'] || !$record['NextCharge']) continue;
 
 			// prevent duplicate user+group pairs
 			$skip_clause[ 'PortalUserId = '.$record['PortalUserId'].' AND GroupId = '.$record['GroupId'] ] = $order_id;
 		}
 		$skip_clause = array_flip($skip_clause);
 
 		$event->MasterEvent->setEventParam('skip_clause', $skip_clause);
 	}
 
 
 	function OnGeneratePDF($event)
 	{
 		$this->OnLoadSelected($event);
 
 		$this->Application->InitParser();
 		$o = $this->Application->ParseBlock(array('name'=>'in-commerce/orders/orders_pdf'));
 
 		$file_helper = $this->Application->recallObject('FileHelper');
 		/* @var $file_helper FileHelper */
 
 		$file_helper->CheckFolder(EXPORT_PATH);
 
 		$htmlFile = EXPORT_PATH . '/tmp.html';
 		$fh = fopen($htmlFile, 'w');
 		fwrite($fh, $o);
 		fclose($fh);
 //		return;
 
 
 //		require_once (FULL_PATH.'html2pdf/PDFEncryptor.php');
 
 		// Full path to the file to be converted
 //		$htmlFile = dirname(__FILE__) . '/test.html';
 
 		// The default domain for images that use a relative path
 		// (you'll need to change the paths in the test.html page
 		// to an image on your server)
 		$defaultDomain = DOMAIN;
 		// Full path to the PDF we are creating
 		$pdfFile = EXPORT_PATH . '/tmp.pdf';
 		// Remove old one, just to make sure we are making it afresh
 		@unlink($pdfFile);
 
 
 		$pdf_helper = $this->Application->recallObject('kPDFHelper');
 		$pdf_helper->FileToFile($htmlFile, $pdfFile);
 		return ;
 
 		// DOM PDF VERSION
 		/*require_once(FULL_PATH.'/dompdf/dompdf_config.inc.php');
 		$dompdf = new DOMPDF();
 		$dompdf->load_html_file($htmlFile);
 		if ( isset($base_path) ) {
 		  $dompdf->set_base_path($base_path);
 		}
 		$dompdf->set_paper($paper, $orientation);
 		$dompdf->render();
 		file_put_contents($pdfFile, $dompdf->output());
 		return ;*/
 
 		// Instnatiate the class with our variables
 		require_once (FULL_PATH.'/html2pdf/HTML_ToPDF.php');
 		$pdf = new HTML_ToPDF($htmlFile, $defaultDomain, $pdfFile);
 		$pdf->setHtml2Ps('/usr/bin/html2ps');
 		$pdf->setPs2Pdf('/usr/bin/ps2pdf');
 		$pdf->setGetUrl('/usr/local/bin/curl -i');
 		// Set headers/footers
 		$pdf->setHeader('color', 'black');
 		$pdf->setFooter('left', '');
 		$pdf->setFooter('right', '$D');
 
 		$pdf->setDefaultPath(BASE_PATH.'/kernel/admin_templates/');
 
 		$result = $pdf->convert();
 
 		// Check if the result was an error
 		if (PEAR::isError($result)) {
 		    $this->Application->ApplicationDie($result->getMessage());
 		}
 		else {
 			$download_url = rtrim($this->Application->BaseURL(), '/') . EXPORT_BASE_PATH . '/tmp.pdf';
 		    echo "PDF file created successfully: $result";
 		    echo '<br />Click <a href="' . $download_url . '">here</a> to view the PDF file.';
 		}
 	}
 
 	/**
 	 * Occurs, when config was parsed, allows to change config data dynamically
 	 *
 	 * @param kEvent $event
 	 * @return void
 	 * @access protected
 	 */
 	protected function OnAfterConfigRead(kEvent $event)
 	{
 		parent::OnAfterConfigRead($event);
 
 		if (defined('IS_INSTALL') && IS_INSTALL) {
 			return ;
 		}
 
 		$order_number = (int)$this->Application->ConfigValue('Comm_Order_Number_Format_P');
 		$order_sub_number = (int)$this->Application->ConfigValue('Comm_Order_Number_Format_S');
 
 		$calc_fields = $this->Application->getUnitOption($event->Prefix, 'CalculatedFields');
 		foreach ($calc_fields as $special => $fields) {
 			$calc_fields[$special]['OrderNumber'] = str_replace('6', $order_number, $calc_fields[$special]['OrderNumber']);
 			$calc_fields[$special]['OrderNumber'] = str_replace('3', $order_sub_number, $calc_fields[$special]['OrderNumber']);
 		}
 		$this->Application->setUnitOption($event->Prefix, 'CalculatedFields', $calc_fields);
 
 		$fields = $this->Application->getUnitOption($event->Prefix, 'Fields');
 		$fields['Number']['format'] = str_replace('%06d', '%0'.$order_number.'d', $fields['Number']['format']);
 		$fields['SubNumber']['format'] = str_replace('%03d', '%0'.$order_sub_number.'d', $fields['SubNumber']['format']);
 
 		$site_helper = $this->Application->recallObject('SiteHelper');
 		/* @var $site_helper SiteHelper */
 
 		$fields['BillingCountry']['default'] = $site_helper->getDefaultCountry('Billing');
 		$fields['ShippingCountry']['default'] = $site_helper->getDefaultCountry('Shipping');
 
 		if (!$this->Application->isAdminUser) {
 			$user_groups = explode(',', $this->Application->RecallVar('UserGroups'));
 			$default_group = $this->Application->ConfigValue('User_LoggedInGroup');
 			if (!in_array($default_group, $user_groups)){
 				$user_groups[] = $default_group;
 			}
 
 			$sql_part = '';
 
 			// limit payment types by domain
 			$payment_types = $this->Application->siteDomainField('PaymentTypes');
 
 			if (strlen($payment_types)) {
 				$payment_types = explode('|', substr($payment_types, 1, -1));
 				$sql_part .= ' AND PaymentTypeId IN (' . implode(',', $payment_types) . ')';
 			}
 
 			// limit payment types by user group
 			$sql_part .= ' AND (PortalGroups LIKE "%%,'.implode(',%%" OR PortalGroups LIKE "%%,', $user_groups).',%%")';
 
 			$fields['PaymentType']['options_sql'] = str_replace(
 				'ORDER BY ',
 				$sql_part . ' ORDER BY ',
 				$fields['PaymentType']['options_sql']
 			);
 		}
 
 		$this->Application->setUnitOption($event->Prefix, 'Fields', $fields);
+
+		$user_forms = $this->Application->getUnitOption('u', 'Forms');
+
+		$virtual_fields = $this->Application->getUnitOption($event->Prefix, 'VirtualFields');
+		$virtual_fields['UserPassword']['hashing_method'] = $user_forms['default']['Fields']['PasswordHashingMethod']['default'];
+		$this->Application->setUnitOption($event->Prefix, 'VirtualFields', $virtual_fields);
 	}
 
 	/**
 	 * Allows configuring export options
 	 *
 	 * @param kEvent $event
 	 * @return void
 	 * @access protected
 	 */
 	protected function OnBeforeExportBegin(kEvent $event)
 	{
 		parent::OnBeforeExportBegin($event);
 
 		$options = $event->getEventParam('options');
 
 		$items_list = $this->Application->recallObject($event->Prefix . '.' . $this->Application->RecallVar('export_oroginal_special'), $event->Prefix . '_List');
 		/* @var $items_list kDBList */
 
 		$items_list->SetPerPage(-1);
 
 		if ( $options['export_ids'] != '' ) {
 			$items_list->AddFilter('export_ids', $items_list->TableName . '.' . $items_list->IDField . ' IN (' . implode(',', $options['export_ids']) . ')');
 		}
 
 		$options['ForceCountSQL'] = $items_list->getCountSQL($items_list->GetSelectSQL(true, false));
 		$options['ForceSelectSQL'] = $items_list->GetSelectSQL();
 
 		$event->setEventParam('options', $options);
 
 		$object = $this->Application->recallObject($event->Prefix . '.export');
 		/* @var $object kDBItem */
 
 		$object->SetField('Number', 999999);
 		$object->SetField('SubNumber', 999);
 	}
 
 	/**
 	 * Returns specific to each item type columns only
 	 *
 	 * @param kEvent $event
 	 * @return Array
 	 * @access protected
 	 */
 	public function getCustomExportColumns(kEvent $event)
 	{
 		$columns = parent::getCustomExportColumns($event);
 
 		$new_columns = Array (
 			'__VIRTUAL__CustomerName' => 'CustomerName',
 			'__VIRTUAL__TotalAmount' => 'TotalAmount',
 			'__VIRTUAL__AmountWithoutVAT' =>	'AmountWithoutVAT',
 			'__VIRTUAL__SubtotalWithDiscount' =>	'SubtotalWithDiscount',
 			'__VIRTUAL__SubtotalWithoutDiscount' =>	'SubtotalWithoutDiscount',
 			'__VIRTUAL__OrderNumber' => 'OrderNumber',
 		);
 
 		return array_merge($columns, $new_columns);
 	}
 
 	/**
 	 * Saves content of temp table into live and
 	 * redirects to event' default redirect (normally grid template)
 	 *
 	 * @param kEvent $event
 	 * @return void
 	 * @access protected
 	 */
 	protected function OnSave(kEvent $event)
 	{
 		parent::OnSave($event);
 
 		if ( $event->status != kEvent::erSUCCESS ) {
 			return ;
 		}
 
 		$copied_ids = unserialize($this->Application->RecallVar($event->Prefix . '_copied_ids' . $this->Application->GetVar('wid'), serialize(Array ())));
 
 		foreach ($copied_ids as $id) {
 			$an_event = new kEvent($this->Prefix . ':Dummy');
 			$this->Application->SetVar($this->Prefix . '_id', $id);
 			$this->Application->SetVar($this->Prefix . '_mode', ''); // this is to fool ReserveItems to use live table
 			$this->ReserveItems($an_event);
 		}
 	}
 
 	/**
 	 * Occurs before an item is copied to live table (after all foreign keys have been updated)
 	 * Id of item being copied is passed as event' 'id' param
 	 *
 	 * @param kEvent $event
 	 * @return void
 	 * @access protected
 	 */
 	protected function OnBeforeCopyToLive(kEvent $event)
 	{
 		parent::OnBeforeCopyToLive($event);
 
 		$id = $event->getEventParam('id');
 		$copied_ids = unserialize($this->Application->RecallVar($event->Prefix . '_copied_ids' . $this->Application->GetVar('wid'), serialize(array ())));
 		array_push($copied_ids, $id);
 
 		$this->Application->StoreVar($event->Prefix . '_copied_ids' . $this->Application->GetVar('wid'), serialize($copied_ids));
 	}
 
 	/**
 	 * Checks, that currently loaded item is allowed for viewing (non permission-based)
 	 *
 	 * @param kEvent $event
 	 * @return bool
 	 * @access protected
 	 */
 	protected function checkItemStatus(kEvent $event)
 	{
 		if ( $this->Application->isAdminUser ) {
 			return true;
 		}
 
 		$object = $event->getObject();
 		/* @var $object kDBItem */
 
 		if ( !$object->isLoaded() ) {
 			return true;
 		}
 
 		return $object->GetDBField('PortalUserId') == $this->Application->RecallVar('user_id');
 	}
 
 	// ===== Gift Certificates Related =====
 	/**
 	 * Enter description here...
 	 *
 	 * @param kEvent $event
 	 */
 	function OnApplyGiftCertificate($event)
 	{
 		$code = $this->Application->GetVar('giftcert_code');
 
 		if ( $code == '' ) {
 			return;
 		}
 
 		$object = $event->getObject();
 		/* @var $object OrdersItem */
 
 		$gift_certificate = $this->Application->recallObject('gc', null, Array ('skip_autoload' => true));
 		/* @var $gift_certificate kDBItem */
 
 		$gift_certificate->Load($code, 'Code');
 
 		if ( !$gift_certificate->isLoaded() ) {
 			$event->status = kEvent::erFAIL;
 			$object->setCheckoutError(OrderCheckoutErrorType::GIFT_CERTIFICATE, OrderCheckoutError::GC_CODE_INVALID);
 			$event->redirect = false; // check!!!
 
 			return;
 		}
 
 		$debit = $gift_certificate->GetDBField('Debit');
 		$expire_date = $gift_certificate->GetDBField('Expiration');
 
 		if ( $gift_certificate->GetDBField('Status') != 1 || ($expire_date && $expire_date < adodb_mktime()) || ($debit <= 0) ) {
 			$event->status = kEvent::erFAIL;
 			$object->setCheckoutError(OrderCheckoutErrorType::GIFT_CERTIFICATE, OrderCheckoutError::GC_CODE_EXPIRED);
 			$event->redirect = false;
 
 			return;
 		}
 
 		$object->SetDBField('GiftCertificateId', $gift_certificate->GetDBField('GiftCertificateId'));
 		$object->Update();
 
 		$object->setCheckoutError(OrderCheckoutErrorType::GIFT_CERTIFICATE, OrderCheckoutError::GC_APPLIED);
 	}
 
 	/**
 	 * Removes gift certificate from order
 	 *
 	 * @param kEvent $event
 	 * @deprecated
 	 */
 	function OnRemoveGiftCertificate($event)
 	{
 		$object = $event->getObject();
 		/* @var $object OrdersItem */
 
 		$this->RemoveGiftCertificate($object);
 		$object->setCheckoutError(OrderCheckoutErrorType::GIFT_CERTIFICATE, OrderCheckoutError::GC_REMOVED);
 
 		$event->CallSubEvent('OnRecalculateItems');
 	}
 
 	function RemoveGiftCertificate(&$object)
 	{
 		$object->RemoveGiftCertificate();
 	}
 
 	function RecalculateGift($event)
 	{
 		$object = $event->getObject();
 		/* @var $object OrdersItem */
 
 		if ($object->GetDBField('Status') > ORDER_STATUS_PENDING) {
 			return ;
 		}
 		$object->RecalculateGift($event);
 	}
 
 	function GetWholeOrderGiftCertificateDiscount($gift_certificate_id)
 	{
 		if (!$gift_certificate_id) {
 			return 0;
 		}
 
 		$sql = 'SELECT Debit
 				FROM '.TABLE_PREFIX.'GiftCertificates
 				WHERE GiftCertificateId = '.$gift_certificate_id;
 		return $this->Conn->GetOne($sql);
 	}
 
 	/**
 	 * Downloads shipping tracking bar code, that was already generated by USPS service
 	 *
 	 * @param kEvent $event
 	 */
 	function OnDownloadLabel($event)
 	{
 		$event->status = kEvent::erSTOP;
 		ini_set('memory_limit', '300M');
 		ini_set('max_execution_time', '0');
 
 		$object = $event->getObject();
 		/* @var $object kDBItem */
 
 		$file = $object->GetDBField('ShippingTracking') . '.pdf';
 		$full_path = USPS_LABEL_FOLDER . $file;
 
 		if ( !file_exists($full_path) || !is_file($full_path) ) {
 			return;
 		}
 
 		$this->Application->setContentType(kUtil::mimeContentType($full_path), false);
 		header('Content-Disposition: attachment; filename="' . $file . '"');
 		readfile($full_path);
 	}
 
 	/**
 	 * Occurs before validation attempt
 	 *
 	 * @param kEvent $event
 	 * @return void
 	 * @access protected
 	 */
 	protected function OnBeforeItemValidate(kEvent $event)
 	{
 		parent::OnBeforeItemValidate($event);
 
 		$create_account = $this->Application->GetVar('create_account');
 
 		$object = $event->getObject();
 		/* @var $object kDBItem */
 
 		$required_fields = Array ('UserPassword', 'UserPassword_plain', 'VerifyUserPassword', 'VerifyUserPassword_plain');
 		$object->setRequired($required_fields, $create_account);
 
 		$billing_email = $object->GetDBField('BillingEmail');
 
 		if ( $create_account && $object->GetDBField('PortalUserId') == USER_GUEST && $billing_email ) {
 			// check that e-mail available
 			$sql = 'SELECT PortalUserId
 					FROM ' . TABLE_PREFIX . 'Users
 					WHERE Email = ' . $this->Conn->qstr($billing_email);
 			$user_id = $this->Conn->GetOne($sql);
 
 			if ( $user_id ) {
 				$object->SetError('BillingEmail', 'unique');
 			}
 		}
 	}
 
 	/**
 	 * Performs order update and returns results in format, needed by FormManager
 	 *
 	 * @param kEvent $event
 	 */
 	function OnUpdateAjax($event)
 	{
 		$ajax_form_helper = $this->Application->recallObject('AjaxFormHelper');
 		/* @var $ajax_form_helper AjaxFormHelper */
 
 		$ajax_form_helper->transitEvent($event, 'OnUpdate');
 	}
 }
\ No newline at end of file
Index: branches/5.3.x/units/orders/orders_config.php
===================================================================
--- branches/5.3.x/units/orders/orders_config.php	(revision 15670)
+++ branches/5.3.x/units/orders/orders_config.php	(revision 15671)
@@ -1,589 +1,589 @@
 <?php
 /**
 * @version	$Id$
 * @package	In-Commerce
 * @copyright	Copyright (C) 1997 - 2009 Intechnic. All rights reserved.
 * @license	Commercial License
 * This software is protected by copyright law and international treaties.
 * Unauthorized reproduction or unlicensed usage of the code of this program,
 * or any portion of it may result in severe civil and criminal penalties,
 * and will be prosecuted to the maximum extent possible under the law
 * See http://www.in-portal.org/commercial-license for copyright notices and details.
 */
 
 defined('FULL_PATH') or die('restricted access!');
 
 $config = Array (
 	'Prefix' => 'ord',
 	'ItemClass' => Array ('class' => 'OrdersItem', 'file' => 'orders_item.php', 'build_event' => 'OnItemBuild'),
 	'ListClass' => Array ('class' => 'kDBList', 'file' => '', 'build_event' => 'OnListBuild'),
 	'EventHandlerClass' => Array ('class' => 'OrdersEventHandler', 'file' => 'orders_event_handler.php', 'build_event' => 'OnBuild'),
 	'TagProcessorClass' => Array ('class' => 'OrdersTagProcessor', 'file' => 'orders_tag_processor.php', 'build_event' => 'OnBuild'),
 	'ValidatorClass' => 'OrderValidator',
 
 	'AutoLoad' => true,
 
 	'RegisterClasses' => Array (
 		Array ('pseudo' => 'OrderCalculator', 'class' => 'OrderCalculator', 'file' => 'order_calculator.php', 'build_event' => ''),
 		Array ('pseudo' => 'OrderManager', 'class' => 'OrderManager', 'file' => 'order_manager.php', 'build_event' => ''),
 		Array ('pseudo' => 'OrderValidator', 'class' => 'OrderValidator', 'file' => 'order_validator.php', 'build_event' => ''),
 	),
 
 	'Hooks' => Array (
 		Array (
 			'Mode' => hAFTER,
 			'Conditional' => false,
 			'HookToPrefix' => 'ord',
 			'HookToSpecial' => '',
 			'HookToEvent' => Array ( 'OnPreSave' ),
 			'DoPrefix' => '',
 			'DoSpecial' => '',
 			'DoEvent' => 'OnRecalculateItems',
 		),
 
 		Array (
 			'Mode' => hBEFORE,
 			'Conditional' => false,
 			'HookToPrefix' => '',
 			'HookToSpecial' => '',
 			'HookToEvent' => Array ( 'OnUpdateCart', 'OnUpdateCartJSON', 'OnCheckout' ),
 			'DoPrefix' => '',
 			'DoSpecial' => '',
 			'DoEvent' => 'OnApplyCoupon',
 		),
 
 		Array (
 			'Mode' => hBEFORE,
 			'Conditional' => false,
 			'HookToPrefix' => '',
 			'HookToSpecial' => '',
 			'HookToEvent' => Array ( 'OnUpdateCart', 'OnUpdateCartJSON', 'OnCheckout' ),
 			'DoPrefix' => '',
 			'DoSpecial' => '',
 			'DoEvent' => 'OnApplyGiftCertificate',
 		),
 
 		Array (
 			'Mode' => hAFTER,
 			'Conditional' => false,
 			'HookToPrefix' => 'u',
 			'HookToSpecial' => '',
 			'HookToEvent' => Array ( 'OnCreate' ),
 			'DoPrefix' => '',
 			'DoSpecial' => '',
 			'DoEvent' => 'OnUserCreate',
 		),
 
 		Array (
 			'Mode' => hBEFORE,
 			'Conditional' => false,
 			'HookToPrefix' => 'u',
 			'HookToSpecial' => '',
 			'HookToEvent' => Array ('OnCheckExpiredMembership'),
 			'DoPrefix' => '',
 			'DoSpecial' => '',
 			'DoEvent' => 'OnCheckRecurringOrders',
 		),
 
 		Array (
 			'Mode' => hAFTER,
 			'Conditional' => false,
 			'HookToPrefix' => 'u',
 			'HookToSpecial' => '',
 			'HookToEvent' => Array ( 'OnAfterLogin' ),
 			'DoPrefix' => '',
 			'DoSpecial' => '',
 			'DoEvent' => 'OnUserLogin',
 		),
 
 		Array (
 			'Mode' => hBEFORE, // before because OnInpLogin is called after real in-portal login and uses data from hooks
 			'Conditional' => false,
 			'HookToPrefix' => 'u',
 			'HookToSpecial' => '',
 			'HookToEvent' => Array ( 'OnInpLogin' ),
 			'DoPrefix' => '',
 			'DoSpecial' => '',
 			'DoEvent' => 'OnUserLogin',
 		),
 		Array (
 			'Mode' => hAFTER,
 			'Conditional' => false,
 			'HookToPrefix' => 'adm',
 			'HookToSpecial' => '*',
 			'HookToEvent' => Array ('OnStartup'),
 			'DoPrefix' => '',
 			'DoSpecial' => '',
 			'DoEvent' => 'OnRestoreOrder',
 		),
 	),
 
 	'AggregateTags' => Array (
 		Array (
 			'AggregateTo' => 'orditems',
 			'AggregatedTagName' => 'LinkRemoveFromCart',
 			'LocalTagName' => 'Orditems_LinkRemoveFromCart',
 		),
 		Array (
 			'AggregateTo' => 'orditems',
 			'AggregatedTagName' => 'ProductLink',
 			'LocalTagName' => 'Orderitems_ProductLink',
 		),
 		Array (
 			'AggregateTo' => 'orditems',
 			'AggregatedTagName' => 'ProductExists',
 			'LocalTagName' => 'Orderitems_ProductExists',
 		),
 	),
 
 	'QueryString' => Array (
 		1 => 'id',
 		2 => 'Page',
 		3 => 'PerPage',
 		4 => 'event',
 		5 => 'mode',
 	),
 
 	'IDField' => 'OrderId',
 	'StatusField' => Array ('Status'),	// field, that is affected by Approve/Decline events
 
 	'ViewMenuPhrase' => 'la_title_Orders',
 	'CatalogTabIcon' => 'icon16_item.png',
 
 	'TitleField' => 'OrderNumber',
 
 	'TitlePresets' => Array (
 		'default' => Array (
 			'new_status_labels' => Array ('ord' => '!la_title_Adding_Order!'),
 			'edit_status_labels' => Array ('ord' => '!la_title_Editing_Order!'),
 			'new_titlefield' => Array ('ord' => '!la_title_New_Order!'),
 		),
 
 		'orders_incomplete' => Array (
 			'prefixes' => Array ('ord.incomplete_List'), 'format' => "!la_title_IncompleteOrders!",
 		),
 
 		'orders_pending' => Array (
 			'prefixes' => Array ('ord.pending_List'), 'format' => "!la_title_PendingOrders!",
 		),
 
 		'orders_backorders' => Array (
 			'prefixes' => Array ('ord.backorders_List'), 'format' => "!la_title_BackOrders!",
 		),
 
 		'orders_toship' => Array (
 			'prefixes' => Array ('ord.toship_List'), 'format' => "!la_title_OrdersToShip!",
 		),
 
 		'orders_processed' => Array (
 			'prefixes' => Array ('ord.processed_List'), 'format' => "!la_title_OrdersProcessed!",
 		),
 
 		'orders_returns' => Array (
 			'prefixes' => Array ('ord.returns_List'), 'format' => "!la_title_OrdersReturns!",
 		),
 
 		'orders_denied' => Array (
 			'prefixes' => Array ('ord.denied_List'), 'format' => "!la_title_OrdersDenied!",
 		),
 
 		'orders_archived' => Array (
 			'prefixes' => Array ('ord.archived_List'), 'format' => "!la_title_OrdersArchived!",
 		),
 
 		'orders_search' => Array (
 			'prefixes' => Array ('ord.search_List'), 'format' => "!la_title_OrdersSearch!",
 		),
 
 		'orders_edit_general' => Array ('prefixes' => Array ('ord'), 'format' => "#ord_status# '#ord_titlefield#' - !la_title_General!"),
 		'orders_edit_billing' => Array ('prefixes' => Array ('ord'), 'format' => "#ord_status# '#ord_titlefield#' - !la_title_OrderBilling!"),
 		'orders_edit_shipping' => Array ('prefixes' => Array ('ord'), 'format' => "#ord_status# '#ord_titlefield#' - !la_title_OrderShipping!"),
 		'orders_edit_items' => Array ('prefixes' => Array ('ord', 'orditems_List'), 'format' => "#ord_status# '#ord_titlefield#' - !la_title_OrderItems!"),
 		'orders_edit_preview' => Array ('prefixes' => Array ('ord'), 'format' => "#ord_status# '#ord_titlefield#' - !la_title_OrderPreview!"),
 
 		'orders_gw_result' => Array ('prefixes' => Array ('ord'), 'format' => "!la_title_OrderGWResult!"),
 
 		'orders_export' => Array ('format' => '!la_title_OrdersExport!'),
 
 		'orders_product_edit' => Array ('format' => '!la_title_Editing_Order_Item!'),
 	),
 
 	'EditTabPresets' => Array (
 		'Default' => Array (
 			'general' => Array ('title' => 'la_tab_General', 't' => 'in-commerce/orders/orders_edit', 'priority' => 1),
 			'items' => Array ('title' => 'la_tab_Items', 't' => 'in-commerce/orders/orders_edit_items', 'priority' => 2),
 			'shipping' => Array ('title' => 'la_tab_Shipping', 't' => 'in-commerce/orders/orders_edit_shipping', 'priority' => 3),
 			'billing' => Array ('title' => 'la_tab_Billing', 't' => 'in-commerce/orders/orders_edit_billing', 'priority' => 4),
 			'preview' => Array ('title' => 'la_tab_Preview', 't' => 'in-commerce/orders/orders_edit_preview', 'priority' => 5),
 		),
 	),
 
 	'PermSection' => Array ('main' => 'in-commerce:orders'),
 
 	'Sections' => Array (
 		'in-commerce:orders' => Array (
 			'parent' => 'in-commerce',
 			'icon' => 'in-commerce:orders',
 			'label' => 'la_tab_Orders',
 			'url' => Array ('t' => 'in-commerce/orders/orders_pending_list', 'pass' => 'm'),
 			'permissions' => Array ('view', 'add', 'edit', 'delete', 'advanced:approve', 'advanced:deny', 'advanced:archive', 'advanced:place', 'advanced:process', 'advanced:ship', 'advanced:reset_to_pending'),
 			'priority' => 1,
 			'type' => stTREE,
 		),
 	),
 
 	'SectionAdjustments' => Array (
 		'in-portal:visits' => Array (
 			'url' => Array ('t' => 'in-commerce/visits/visits_list_incommerce', 'pass' => 'm'),
 		),
 	),
 
 	'StatisticsInfo' => Array (
 		'pending' => Array (
 			'icon' => 'core:icon16_item.png',
 			'label' => 'la_title_Orders',
 			'js_url' => "#url#",
 			'url' => Array ('t' => 'in-commerce/orders/orders_pending_list', 'pass' => 'm'),
 			'status' => ORDER_STATUS_PENDING,
 		),
 	),
 
 	'TableName' => TABLE_PREFIX . 'Orders',
 
 	'CalculatedFields' => Array (
 		'' => Array (
-			'CustomerName' => 'IF( ISNULL(u.Username), IF (%1$s.PortalUserId = ' . USER_ROOT . ', \'root\', IF (%1$s.PortalUserId = ' . USER_GUEST . ', \'Guest\', \'n/a\')), CONCAT(u.FirstName,\' \',u.LastName) )',
-			'Username' => 'IF( ISNULL(u.Username),\'root\',u.Username)',
+			'CustomerName' => 'IF( ISNULL(u.Username), IF (%1$s.PortalUserId = ' . USER_ROOT . ', "root", IF (%1$s.PortalUserId = ' . USER_GUEST . ', "Guest", "n/a")), CONCAT(u.FirstName," ",u.LastName) )',
+			'Username' => 'IF( ISNULL(u.Username),"root",IF(u.Username = "", u.Email, u.Username))',
 			'OrderNumber' => 'CONCAT(LPAD(Number,6,"0"),\'-\',LPAD(SubNumber,3,"0") )',
 			'SubtotalWithoutDiscount' => '(SubTotal + DiscountTotal)',
 			'SubtotalWithDiscount' => '(SubTotal)',
 			'AmountWithoutVAT' => '(SubTotal+IF(ShippingTaxable=1, ShippingCost, 0)+IF(ProcessingTaxable=1, ProcessingFee, 0)-IF(VATIncluded=1,VAT,0))',
 			'TotalAmount' => 'SubTotal+ShippingCost+IF(VATIncluded=1,0,VAT)+ProcessingFee+InsuranceFee-GiftCertificateDiscount',
 			'CouponCode' => 'pc.Code',
 			'CouponName' => 'pc.Name',
-			'AffiliateUser' => 'IF( LENGTH(au.Username),au.Username,\'!la_None!\')',
+			'AffiliateUser' => 'IF(au.PortalUserId IS NULL, "!la_None!", IF(au.Username = "", au.Email, au.Username))',
 			'AffiliatePortalUserId' => 'af.PortalUserId',
 			'GiftCertificateCode' => 'gc.Code',
 			'GiftCertificateRecipient' => 'gc.Recipient',
 			'ShippingSubTotal' => '%1$s.ShippingCost + %1$s.InsuranceFee',
 		),
 
 		'myorders' => Array (
 			'OrderNumber' => 'CONCAT(LPAD(Number,6,"0"),\'-\',LPAD(SubNumber,3,"0") )',
 			'SubtotalWithoutDiscount' => '(SubTotal + DiscountTotal)',
 			'SubtotalWithDiscount' => '(SubTotal)',
 			'AmountWithoutVAT' => '(SubTotal+IF(ShippingTaxable=1, ShippingCost, 0)+IF(ProcessingTaxable=1, ProcessingFee, 0)-IF(VATIncluded=1,VAT,0))',
 			'TotalAmount' => 'SubTotal+ShippingCost+IF(VATIncluded=1,0,VAT)+ProcessingFee+InsuranceFee-GiftCertificateDiscount',
 			/*'ItemsCount' => 'COUNT(%1$s.OrderId)',*/
 			'ShippingSubTotal' => '%1$s.ShippingCost + %1$s.InsuranceFee',
 		),
 	),
 	// %1$s - table name of object
 	// %2$s - calculated fields
 	'ListSQLs' => Array (
 		'' => '	SELECT %1$s.* %2$s
 				FROM %1$s
 				LEFT JOIN '.TABLE_PREFIX.'Users u ON %1$s.PortalUserId = u.PortalUserId
 				LEFT JOIN '.TABLE_PREFIX.'ProductsCoupons pc ON %1$s.CouponId = pc.CouponId
 				LEFT JOIN '.TABLE_PREFIX.'GiftCertificates gc ON %1$s.GiftCertificateId = gc.GiftCertificateId
 				LEFT JOIN '.TABLE_PREFIX.'Affiliates af ON %1$s.AffiliateId = af.AffiliateId
 				LEFT JOIN '.TABLE_PREFIX.'Users au ON af.PortalUserId = au.PortalUserId',
 
 		'myorders' => '	SELECT %1$s.* %2$s
 						FROM %1$s
 						LEFT JOIN '.TABLE_PREFIX.'Users u ON %1$s.PortalUserId = u.PortalUserId',
 //						LEFT JOIN '.TABLE_PREFIX.'OrderItems ON %1$s.OrderId = '.TABLE_PREFIX.'OrderItems.OrderId',
 	),
 
 	'SubItems' => Array ('orditems'),
 
 	'ListSortings' => Array (
 		'' => Array (
 			'Sorting' => Array ('OrderDate' => 'desc'),
 		)
 	),
 
 	'Fields' => Array (
 		'OrderId' => Array ('type' => 'int', 'not_null' => 1, 'default' => 0, 'filter_type' => 'equals'),
 		'Number' => Array ('type' => 'int', 'required' =>1, 'formatter' => 'kFormatter', 'unique' =>Array ('SubNumber'), 'format' => '%06d', 'max_value_inc'>999999, 'not_null' => 1, 'default' => 0),
 		'SubNumber' => Array ('type' => 'int', 'required' =>1, 'formatter' => 'kFormatter', 'unique' =>Array ('Number'), 'format' => '%03d', 'max_value_inc'>999, 'not_null' => 1, 'default' => 0),
 		'Status' => Array ('type' => 'int', 'formatter' => 'kOptionsFormatter', 'options' =>Array (0=> 'la_Incomplete',1=> 'la_Pending',2=> 'la_BackOrders',3=> 'la_ToShip',4=> 'la_Processed',5=> 'la_Denied',6=> 'la_Archived'), 'use_phrases' =>1, 'not_null' => 1, 'default' => 0, 'filter_type' => 'equals'),
 		'OnHold' => Array (
 			'type' => 'int',
 			'formatter' => 'kOptionsFormatter',
 			'options' => Array (0 => 'la_No', 1 => 'la_Yes'), 'use_phrases' => 1,
 			'not_null' => 1, 'default' => 0,
 		),
 		'OrderDate' => Array ('type' => 'int', 'formatter' => 'kDateFormatter', 'required' => 1, 'default' => '#NOW#'),
-		'PortalUserId' =>Array ('type' => 'int', 'formatter' => 'kLEFTFormatter', 'error_msgs' => Array ('invalid_option' => '!la_error_UserNotFound!'), 'options' =>Array (USER_ROOT => 'root', USER_GUEST => 'Guest'), 'left_sql' => 'SELECT %s FROM '.TABLE_PREFIX.'Users WHERE `%s` = \'%s\'', 'left_key_field' => 'PortalUserId', 'left_title_field' => 'Username', 'required' =>1, 'not_null' =>1, 'default' =>-1),
+		'PortalUserId' => Array ('type' => 'int', 'formatter' => 'kLEFTFormatter', 'error_msgs' => Array ('invalid_option' => '!la_error_UserNotFound!'), 'options' => Array (USER_ROOT => 'root', USER_GUEST => 'Guest'), 'left_sql' => 'SELECT %s FROM ' . TABLE_PREFIX . 'Users WHERE %s', 'left_key_field' => 'PortalUserId', 'left_title_field' => USER_TITLE_FIELD, 'required' => 1, 'not_null' => 1, 'default' => -1),
 		'OrderIP' => Array ('type' => 'string', 'not_null' => 1, 'default' => '', 'filter_type' => 'like'),
 		'UserComment' => Array ('type' => 'string', 'formatter' => 'kFormatter', 'using_fck' => 1, 'default' => NULL),
 		'AdminComment' => Array ('type' => 'string', 'formatter' => 'kFormatter', 'using_fck' => 1, 'default' => NULL),
 		'BillingTo' => Array ('type' => 'string', 'not_null' => 1, 'default' => ''),
 		'BillingCompany' => Array ('type' => 'string', 'not_null' => 1, 'default' => ''),
 		'BillingPhone' => Array ('type' => 'string', 'not_null' => 1, 'default' => ''),
 		'BillingFax' => Array ('type' => 'string', 'not_null' => 1, 'default' => ''),
 		'BillingEmail' => Array (
 			'type' => 'string',
 			'formatter' => 'kFormatter',
 			'regexp' => '/^(' . REGEX_EMAIL_USER . '@' . REGEX_EMAIL_DOMAIN . ')$/i',
 			'error_msgs' => Array ('invalid_format' => '!la_invalid_email!', 'unique' => '!lu_email_already_exist!'),
 			'not_null' => 1, 'default' => '',
 		),
 		'BillingAddress1' => Array ('type' => 'string', 'not_null' => 1, 'default' => ''),
 		'BillingAddress2' => Array ('type' => 'string', 'not_null' => 1, 'default' => ''),
 		'BillingCity' => Array ('type' => 'string', 'not_null' => 1, 'default' => ''),
 		'BillingState' => Array (
 			'type' => 'string',
 			'formatter' => 'kOptionsFormatter',
 			'options' => Array (),
 			'option_key_field' => 'DestAbbr',
 			'option_title_field' => 'Translation',
 			'not_null' => 1, 'default' => '',
 		),
 		'BillingZip' => Array ('type' => 'string', 'not_null' => 1, 'default' => ''),
 		'BillingCountry' => Array (
 			'type' => 'string',
 			'formatter' => 'kOptionsFormatter',
 			'options_sql' => '	SELECT IF(l%2$s_Name = "", l%3$s_Name, l%2$s_Name) AS Name, IsoCode
 								FROM '.TABLE_PREFIX.'CountryStates
 								WHERE Type = ' . DESTINATION_TYPE_COUNTRY . '
 								ORDER BY Name',
 			'option_key_field' => 'IsoCode', 'option_title_field' => 'Name',
 			'not_null' => 1, 'default' => 'USA'
 		),
 		'VAT' => Array ('type' => 'float', 'formatter' => 'kFormatter', 'not_null' =>1, 'default' => '0', 'format' => '%01.2f'),
 		'VATPercent' => Array ('type' => 'float', 'formatter' => 'kFormatter', 'not_null' =>1, 'default' => '0', 'format' => '%01.3f'),
 		'VATIncluded' => Array (
 			'type' => 'int',
 			'formatter' => 'kOptionsFormatter',
 			'options' => Array (0 => 'la_No', 1 => 'la_Yes'), 'use_phrases' => 1,
 			'not_null' => 1, 'default' => 0,
 		),
 		'PaymentType' => Array (
 			'type' => 'int',
 			'formatter' => 'kOptionsFormatter',
 			'options_sql' => 'SELECT IF(l%2$s_Description <> "", l%2$s_Description, l%3$s_Description) AS Description, PaymentTypeId
 								FROM ' . TABLE_PREFIX . 'PaymentTypes
 								WHERE Status = 1
 								ORDER BY Priority DESC, Name ASC',
 			'option_key_field' => 'PaymentTypeId', 'option_title_field' => 'Description',
 			'not_null' => 1, 'default' => 0
 		),
 
 		'PaymentAccount' => Array ('type' => 'string', 'not_null' => 1, 'cardtype_field' => 'PaymentCardType', 'default' => '', 'filter_type' => 'like'),
 		'PaymentNameOnCard' => Array ('type' => 'string', 'not_null' => 1, 'default' => ''),
 		'PaymentCCExpDate' => Array ('type' => 'string', 'formatter' => 'kCCDateFormatter', 'month_field' => 'PaymentCCExpMonth', 'year_field' => 'PaymentCCExpYear', 'not_null' => 1, 'default' => ''),
 		'PaymentCardType' => Array ('type' => 'string', 'not_null' => 1, 'formatter' => 'kOptionsFormatter', 'options' => Array ('' => '', '1' => 'Visa', '2' => 'Mastercard', '3' => 'Amex', '4' => 'Discover', '5' => 'Diners Club', '6' => 'JBC'), 'default' => ''),
 		'PaymentExpires' => Array ('type' => 'int', 'formatter' => 'kDateFormatter', 'default' => '#NOW#'),
 		'ShippingTo' => Array ('type' => 'string', 'not_null' => 1, 'default' => ''),
 		'ShippingCompany' => Array ('type' => 'string', 'not_null' => 1, 'default' => ''),
 		'ShippingPhone' => Array ('type' => 'string', 'not_null' => 1, 'default' => ''),
 		'ShippingFax' => Array ('type' => 'string', 'not_null' => 1, 'default' => ''),
 		'ShippingEmail' => Array (
 			'type' => 'string',
 			'formatter' => 'kFormatter',
 			'regexp' => '/^(' . REGEX_EMAIL_USER . '@' . REGEX_EMAIL_DOMAIN . ')$/i',
 			'error_msgs' => Array ('invalid_format' => '!la_invalid_email!'),
 			'not_null' => 1, 'default' => '',
 		),
 		'ShippingAddress1' => Array ('type' => 'string', 'not_null' => 1, 'default' => ''),
 		'ShippingAddress2' => Array ('type' => 'string', 'not_null' => 1, 'default' => ''),
 		'ShippingCity' => Array ('type' => 'string', 'not_null' => 1, 'default' => ''),
 		'ShippingState' => Array (
 			'type' => 'string', 'formatter' => 'kOptionsFormatter',
 									'options' => Array (),
 									'option_key_field' => 'DestAbbr', 'option_title_field' => 'Translation',
 									'not_null' => 1, 'default' => ''),
 		'ShippingZip' => Array ('type' => 'string', 'not_null' => 1, 'default' => ''),
 		'ShippingCountry' => Array (
 			'type' => 'string', 'formatter' => 'kOptionsFormatter',
 			'options_sql' => '	SELECT IF(l%2$s_Name = "", l%3$s_Name, l%2$s_Name) AS Name, IsoCode
 								FROM '.TABLE_PREFIX.'CountryStates
 								WHERE Type = ' . DESTINATION_TYPE_COUNTRY . '
 								ORDER BY Name',
 			'option_key_field' => 'IsoCode', 'option_title_field' => 'Name',
 			'not_null' => 1, 'default' => 'USA'
 		),
 		'ShippingType' => Array (
 			'type' => 'int',
 			'formatter' => 'kOptionsFormatter',
 			'options_sql' => 'SELECT %s
 									FROM ' . TABLE_PREFIX . 'ShippingType
 								WHERE Status = 1',
 			'option_key_field' => 'ShippingID',
 			'option_title_field' => 'Name',
 			'not_null' => 1, 'default' => 0,
 		),
 		'ShippingCost' => Array ('type' => 'double', 'formatter' => 'kFormatter', 'format' => '%01.2f', 'not_null' => 1, 'default' => '0.00'),
 		'ShippingCustomerAccount' => Array ('type' => 'string', 'not_null' => 1, 'default' => ''),
 		'ShippingTracking' => Array ('type' => 'string', 'not_null' => 1, 'default' => ''),
 		'ShippingDate' => Array ('type' => 'int', 'formatter' => 'kDateFormatter', 'default' => null),
 		'SubTotal' => Array ('type' => 'float', 'formatter' => 'kFormatter', 'format' => '%01.2f', 'not_null' => 1, 'default' => '0.00'),
 		'ReturnTotal' => Array ('type' => 'float', 'formatter' => 'kFormatter', 'format' => '%01.2f', 'not_null' => 1, 'default' => '0.00'),
 		'CostTotal' => Array ('type' => 'float', 'formatter' => 'kFormatter', 'format' => '%01.2f', 'not_null' => 1, 'default' => '0.00'),
 		'OriginalAmount' => Array ('type' => 'float', 'formatter' => 'kFormatter', 'format' => '%01.2f', 'not_null' => 1, 'default' => '0.00'),
 		'ShippingOption' => Array (
 			'type' => 'int',
 			'formatter' => 'kOptionsFormatter',
 			'options' => Array (
 				0 => 'la_ship_all_together', 1 => 'la_ship_backorder_separately', 2 => 'la_ship_backorders_upon_avail',
 			),
 			'use_phrases' => 1, 'not_null' => 1, 'default' => 0,
 		),
 		'ShippingGroupOption' => Array (
 			'type' => 'int',
 			'formatter' => 'kOptionsFormatter', 'use_phrases' => 1,
 			'options' => Array (0 => 'la_opt_AutoGroupShipments', 1 => 'la_opt_ManualGroupShipments'),
 			'not_null' => 1, 'default' => 0,
 		),
 		'GiftCertificateId' => Array ('type' => 'int', 'default' => null),
 		'GiftCertificateDiscount' => Array ('type' => 'float', 'formatter' => 'kFormatter', 'format' => '%01.2f', 'not_null' => 1, 'default' => '0.00',),
 		'ShippingInfo' => Array ('type' => 'string', 'default' => NULL),
 		'CouponId' => Array ('type' => 'int', 'default' => null),
 		'CouponDiscount' => Array ('type' => 'float', 'not_null' => 1, 'default' => '0.00', 'formatter' => 'kFormatter', 'format' => '%01.2f'),
 		'DiscountTotal' => Array ('type' => 'float', 'not_null' => 1, 'default' => '0.00', 'formatter' => 'kFormatter', 'format' => '%01.2f'),
 		'TransactionStatus' => Array (
 			'type' => 'int',
 			'formatter' => 'kOptionsFormatter',
 			'options' => Array (0 => 'la_opt_Invalid', 1 => 'la_opt_Verified', 2 => 'la_opt_Penging'),
 			'use_phrases' =>1, 'not_null' => 1, 'default' => 2,
 		),
 		'GWResult1' => Array ('type' => 'string', 'formatter' => 'kSerializedFormatter', 'default' => NULL),
 		'GWResult2' => Array ('type' => 'string', 'formatter' => 'kSerializedFormatter', 'default' => NULL),
 		'AffiliateId' => Array ('type' => 'int', 'formatter' => 'kLEFTFormatter', 'error_msgs' => Array ('invalid_option' => '!la_error_UserNotFound!'),  'options' => Array (0 => 'lu_None'), 'left_sql' => 'SELECT %s FROM '.TABLE_PREFIX.'Affiliates af LEFT JOIN '.TABLE_PREFIX.'Users pu ON pu.PortalUserId = af.PortalUserId WHERE `%s` = \'%s\'', 'left_key_field' => 'AffiliateId', 'left_title_field' => 'Username', 'not_null' =>1, 'default' =>0),
 		'VisitId' => Array ('type' => 'int', 'not_null' => 1, 'default' => 0),
 		'AffiliateCommission' => Array ('type' => 'double', 'formatter' => 'kFormatter', 'format' => '%.02f', 'not_null' => 1, 'default' => '0.0000'),
 		'ProcessingFee' => Array ('type' => 'double', 'formatter' => 'kFormatter', 'format' => '%.02f', 'not_null' => '0', 'default' => '0.0000'),
 		'InsuranceFee' => Array ('type' => 'float', 'formatter' => 'kFormatter', 'format' => '%01.2f', 'not_null' => 1, 'default' => '0.00'),
 		'ShippingTaxable' => Array ('type' => 'int', 'not_null' => 0, 'default' => 0),
 		'ProcessingTaxable' => Array ('type' => 'int', 'not_null' => 0, 'default' => 0),
 		'IsRecurringBilling' => Array (
 			'type' => 'int',
 			'formatter' => 'kOptionsFormatter',
 			'options' => Array (0 => 'la_No', 1 => 'la_Yes',), 'use_phrases' => 1,
 			'default' => 0, 'not_null' => 1,
 		),
 		'ChargeOnNextApprove' => Array (
 			'type' => 'int',
 			'formatter' => 'kOptionsFormatter',
 			'options' => Array (0 => 'la_No', 1 => 'la_Yes',), 'use_phrases' => 1,
 			'default' => 0, 'not_null' => 1,
 		),
 		'NextCharge' => Array ('type' => 'int', 'formatter' => 'kDateFormatter', 'default' => null),
 		'GroupId' => Array ('type' => 'int', 'not_null' => 1, 'default' => 0),
 		'GoogleOrderNumber' => Array ('type' => 'string', 'default' => NULL), // MySQL BIGINT UNSIGNED = 8 Bytes, PHP int = 4 Bytes -> threat as string
 	),
 
 	'VirtualFields' => Array (
 		'CustomerName' => Array ('type' => 'string', 'default' => '', 'filter_type' => 'like'),
 		'TotalAmount' => Array ('type' => 'float', 'formatter' => 'kFormatter', 'format' => '%01.2f', 'default' => '0.00'),
 		'AmountWithoutVAT' => Array ('type' => 'float', 'formatter' => 'kFormatter', 'format' => '%01.2f', 'default' => '0.00'),
 		'SubtotalWithDiscount' => Array ('type' => 'float', 'formatter' => 'kFormatter', 'format' => '%01.2f', 'default' => '0.00'),
 		'SubtotalWithoutDiscount' => Array ('type' => 'float', 'formatter' => 'kFormatter', 'format' => '%01.2f', 'default' => '0.00'),
 		'ShippingSubTotal' => Array ('type' => 'float', 'formatter' => 'kFormatter', 'format' => '%01.2f', 'default' => '0.00'),
 		'OrderNumber' => Array ('type' => 'string', 'default' => '', 'filter_type' => 'like'),
 		'CouponCode' => Array ('type' => 'string', 'default' => ''),
 		'CouponName' => Array ('type' => 'string', 'default' => ''),
 		'GiftCertificateCode' => Array ('type' => 'string', 'default' => ''),
 		'GiftCertificateRecipient' => Array ('type' => 'string', 'default' => ''),
 
 		// for ResetToUser
 		'UserTo' => Array ('type' => 'string', 'default' => ''),
 		'UserCompany' => Array ('type' => 'string', 'default' => ''),
 		'UserPhone' => Array ('type' => 'string', 'default' => ''),
 		'UserFax' => Array ('type' => 'string', 'default' => ''),
 		'UserEmail' => Array ('type' => 'string', 'default' => ''),
 		'UserAddress1' => Array ('type' => 'string', 'default' => ''),
 		'UserAddress2' => Array ('type' => 'string', 'default' => ''),
 		'UserCity' => Array ('type' => 'string', 'default' => ''),
 		'UserState' => Array ('type' => 'string', 'default' => ''),
 		'UserZip' => Array ('type' => 'string', 'default' => ''),
 		'UserCountry' => Array ('type' => 'string', 'default' => ''),
 
 		// for Search
 		'Username' => Array ('type' => 'string', 'filter_type' => 'like', 'default' => ''),
 		'HasBackOrders' => Array ('type' => 'int', 'default' => 0),
 		'PaymentCVV2' => Array ('type' => 'string', 'default' => ''),
 		'AffiliateUser' => Array ('type' => 'string', 'filter_type' => 'like', 'default' => ''),
 		'AffiliatePortalUserId' => Array ('type' => 'int', 'default' => 0),
 
 		// export related fields: begin
 		'ExportFormat' => Array ('type' => 'int', 'formatter' => 'kOptionsFormatter', 'options' => Array (1 => 'CSV', /*2 => 'XML'*/), 'default' => 1),
 		'ExportFilename' => Array ('type' => 'string', 'default' => ''),
 		'FieldsSeparatedBy' => Array ('type' => 'string', 'default' => ', '),
 		'FieldsEnclosedBy' => Array ('type' => 'string', 'default' => '"'),
 		'LineEndings' => Array ('type' => 'int', 'formatter' => 'kOptionsFormatter', 'options' => Array (1 => 'Windows', 2 => 'UNIX'), 'default' => 1),
 		'LineEndingsInside' => Array ('type' => 'int', 'formatter' => 'kOptionsFormatter', 'options' => Array (1 => 'CRLF', 2 => 'LF'), 'default' => 2),
 		'IncludeFieldTitles' => Array (
 			'type' => 'int',
 			'formatter' => 'kOptionsFormatter',
 			'options' => Array (0 => 'la_No', 1 => 'la_Yes'),
 			'use_phrases' => 1, 'default' => 1,
 		),
 		'ExportColumns' => Array ('type' => 'string', 'formatter' => 'kOptionsFormatter', 'options' => Array (), 'default' => ''),
 		'AvailableColumns' => Array ('type' => 'string', 'formatter' => 'kOptionsFormatter', 'options' => Array (), 'default' => ''),
 		'ExportPresets' => Array ('type' => 'string', 'formatter' => 'kOptionsFormatter', 'options' => Array (), 'default' => ''),
 		'ExportSavePreset' => Array (
 			'type' => 'int',
 			'formatter' => 'kOptionsFormatter',
 			'options' => Array (0 => 'la_No', 1 => 'la_Yes'),
 			'use_phrases' => 1, 'default' => 0,
 		),
 		'ExportPresetName' => Array ('type' => 'string', 'default' => ''),
 		// export related fields: end
 
 		// for "one step checkout"
 		'UserPassword' => Array (
 			'type' => 'string',
 			'formatter' => 'kPasswordFormatter', 'encryption_method' => 'md5', 'verify_field' => 'VerifyUserPassword',
 			'skip_empty' => 1, 'default' => 'd41d8cd98f00b204e9800998ecf8427e'
 		),
 
 		// for "Shipping Info" step during Checkout
 		'ShippingTypeId' => Array ('type' => 'array', 'default' => ''),
 	),
 	'Grids' => Array (
 		'Default' => Array (
 			'Icons' => Array (
 				'default' => 'icon16_item.png',
 				1 => 'icon16_pending.png',
 				5 => 'icon16_disabled.png',
 				'module' => 'core',
 			),
 
 			'Fields' => Array (
 				'OrderId' => Array ('title' => 'column:la_fld_Id', 'data_block' => 'grid_checkbox_td', 'filter_block' => 'grid_range_filter', 'width' => 70, ),
 				'OrderNumber' => Array ( 'data_block' => 'grid_ordernumber_td', 'filter_block' => 'grid_like_filter', 'width' => 100, ),
 				'OrderDate' => Array ( 'title' => 'la_col_OrderDate', 'data_block' => 'grid_checkbox_td', 'filter_block' => 'grid_date_range_filter', 'width' => 140, ),
 				'CustomerName' => Array ( 'title' => 'la_col_CustomerName', 'data_block' => 'grid_userlink_td', 'user_field' => 'PortalUserId', 'filter_block' => 'grid_like_filter', 'width' => 140, ),
 				'PaymentType' => Array ( 'data_block' => 'grid_billinglink_td', 'filter_block' => 'grid_options_filter', 'width' => 140, ),
 				'TotalAmount' => Array ( 'data_block' => 'grid_previewlink_td', 'filter_block' => 'grid_range_filter', 'width' => 140, ),
 				'AffiliateUser' => Array ( 'data_block' => 'grid_userlink_td', 'user_field' => 'AffiliatePortalUserId', 'filter_block' => 'grid_like_filter', 'width' => 140, ),
 				'OnHold' => Array ('filter_block' => 'grid_options_filter', 'width' => 100, ),
 			),
 		),
 
 		'Search' => Array (
 			'Icons' => Array (
 				'default' => 'icon16_item.png',
 				1 => 'icon16_pending.png',
 				5 => 'icon16_disabled.png',
 				'module' => 'core',
 			),
 			'Fields' => Array (
 				'OrderId' => Array ('title' => 'column:la_fld_Id', 'data_block' => 'grid_checkbox_td', 'filter_block' => 'grid_range_filter', 'width' => 70, ),
 				'OrderNumber' => Array ('data_block' => 'grid_ordernumber_td', 'filter_block' => 'grid_like_filter', 'width' => 100, ),
 				'Status' => Array ('filter_block' => 'grid_options_filter', 'filter_block' => 'grid_options_filter', 'width' => 100, ),
 				'OrderDate' => Array ('title' => 'la_col_OrderDate', 'filter_block' => 'grid_date_range_filter', 'width' => 140, ),
 				'CustomerName' => Array ('title' => 'la_col_CustomerName', 'data_block' => 'grid_userlink_td', 'user_field' => 'PortalUserId', 'filter_block' => 'grid_like_filter'),
 				'PaymentType' => Array ('data_block' => 'grid_billinglink_td', 'filter_block' => 'grid_options_filter'),
 				'TotalAmount' => Array ('data_block' => 'grid_previewlink_td', 'filter_block' => 'grid_range_filter'),
 				'AffiliateUser' => Array ('data_block' => 'grid_userlink_td', 'user_field' => 'AffiliatePortalUserId', 'filter_block' => 'grid_user_like_filter'),
 				'OrderIP' => Array ('filter_block' => 'grid_like_filter'),
 				'Username' => Array ('filter_block' => 'grid_user_like_filter'),
 				'PaymentAccount' => Array ('title' => 'column:la_fld_CreditCardNumber', 'filter_block' => 'grid_like_filter'),
 			),
 		),
 	),
 );
\ No newline at end of file
Index: branches/5.3.x/units/orders/orders_tag_processor.php
===================================================================
--- branches/5.3.x/units/orders/orders_tag_processor.php	(revision 15670)
+++ branches/5.3.x/units/orders/orders_tag_processor.php	(revision 15671)
@@ -1,1713 +1,1653 @@
 <?php
 /**
 * @version	$Id$
 * @package	In-Commerce
 * @copyright	Copyright (C) 1997 - 2009 Intechnic. All rights reserved.
 * @license	Commercial License
 * This software is protected by copyright law and international treaties.
 * Unauthorized reproduction or unlicensed usage of the code of this program,
 * or any portion of it may result in severe civil and criminal penalties,
 * and will be prosecuted to the maximum extent possible under the law
 * See http://www.in-portal.org/commercial-license for copyright notices and details.
 */
 
 	defined('FULL_PATH') or die('restricted access!');
 
 	class OrdersTagProcessor extends kDBTagProcessor
 	{
 
 		/**
 		 * Print location using only filled in fields
 		 *
 		 * @param Array $params
 		 * @access public
 		 */
 		function PrintLocation($params)
 		{
 			$object = $this->getObject($params);
 
 			$type = getArrayValue($params,'type');
 			if($type == 'Company')
 			{
 				return $this->PrintCompanyLocation($params);
 			}
 			$fields = Array('City','State','Zip','Country');
 
 			$ret = '';
 			foreach($fields as $field)
 			{
 				$value = $object->GetField($type.$field);
 				if ($field == 'Country' && $value) $ret .= '<br/>';
 				if($value) $ret .= $value.', ';
 			}
 			return rtrim($ret,', ');
 		}
 
 		function PrintCompanyLocation($params)
 		{
 			$ret = '';
 			$fields = Array ('City','State','ZIP','Country');
 
 			foreach ($fields as $field) {
 				$value = $this->Application->ConfigValue('Comm_'.$field);
 				if ($field == 'Country') {
 					$current_language = $this->Application->GetVar('m_lang');
 					$primary_language = $this->Application->GetDefaultLanguageId();
 
 					$sql = 'SELECT IF(l' . $current_language . '_Name = "", l' . $primary_language . '_Name, l' . $current_language . '_Name)
 							FROM ' . TABLE_PREFIX . 'CountryStates
 							WHERE IsoCode = ' . $this->Conn->qstr($value);
 					$value = $this->Conn->GetOne($sql);
 				}
 
 				if ($field == 'Country' && $value) {
 					$ret .= '<br/>';
 				}
 
 				if ($value) {
 					$ret .= $value.', ';
 				}
 			}
 
 			return rtrim($ret,', ');
 		}
 
 		function Orditems_LinkRemoveFromCart($params)
 		{
 			return $this->Application->HREF($this->Application->GetVar('t'), '', Array('pass' => 'm,orditems,ord', 'ord_event' => 'OnRemoveFromCart', 'm_cat_id'=>0));
 		}
 
 		function Orderitems_ProductLink($params)
 		{
 			$object = $this->Application->recallObject('orditems');
 
 			$url_params = Array (
 				'p_id' =>  $object->GetDBField('ProductId'),
 				'pass' => 'm,p',
 			);
 
 			return $this->Application->HREF($params['template'], '', $url_params);
 		}
 
 		function Orderitems_ProductExists($params)
 		{
 			$object = $this->Application->recallObject('orditems');
 			return $object->GetDBField('ProductId') > 0;
 		}
 
 		function PrintCart($params)
 		{
 			$o = '';
 
 			$params['render_as'] = $params['item_render_as'];
 			$tag_params = array_merge($params, Array ('per_page' => -1));
 
 			$o_items = $this->Application->ProcessParsedTag(rtrim('orditems.' . $this->Special, '.'), 'PrintList', $tag_params);
 
 			if ( $o_items ) {
 				if ( isset($params['header_render_as']) ) {
 					$cart_params = array ('name' => $params['header_render_as']);
 					$o .= $this->Application->ParseBlock($cart_params);
 				}
 
 				$o .= $o_items;
 
 				if ( isset($params['footer_render_as']) ) {
 					$cart_params = array ('name' => $params['footer_render_as']);
 					$o .= $this->Application->ParseBlock($cart_params);
 				}
 			}
 			elseif ( isset($params['empty_cart_render_as']) ) {
 				$cart_params = array ('name' => $params['empty_cart_render_as']);
 				$o = $this->Application->ParseBlock($cart_params);
 			}
 
 			return $o;
 		}
 
 		function ShopCartForm($params)
 		{
 			return $this->Application->ProcessParsedTag('m', 'ParseBlock', 	array_merge($params, Array(
 					'name' => 'kernel_form', 'PrefixSpecial'=>'ord'
 			)) );
 		}
 
 		function BackOrderFlag($params)
 		{
 			$object = $this->Application->recallObject('orditems');
 			return $object->GetDBField('BackOrderFlag');
 		}
 
 		function OrderIcon($params)
 		{
 			$object = $this->Application->recallObject('orditems');
 			if ($object->GetDBField('BackOrderFlag') == 0) {
 				return $params['ordericon'];
 			} else {
 				return $params['backordericon'];
 			}
 		}
 
 		function Status($params)
 		{
 			$status_map = Array(
 				'incomplete' => ORDER_STATUS_INCOMPLETE,
 				'pending' => ORDER_STATUS_PENDING,
 				'backorder' => ORDER_STATUS_BACKORDERS,
 				'toship' => ORDER_STATUS_TOSHIP,
 				'processed' => ORDER_STATUS_PROCESSED,
 				'denied' => ORDER_STATUS_DENIED,
 				'archived' => ORDER_STATUS_ARCHIVED,
 			);
 
 			$object = $this->getObject($params);
 			$status = $object->GetDBField('Status');
 
 			$result = true;
 			if (isset($params['is'])) {
 				$result = $result && ($status == $status_map[$params['is']]);
 			}
 			if (isset($params['is_not'])) {
 				$result = $result && ($status != $status_map[$params['is_not']]);
 			}
 			return $result;
 		}
 
 		function ItemsInCart($params)
 		{
 			$object = $this->getObject($params);
 			/* @var $object kDBItem */
 
 			if ( $object->GetDBField('Status') != ORDER_STATUS_INCOMPLETE || $object->GetID() == FAKE_ORDER_ID ) {
 				return 0;
 			}
 
 			$object = $this->Application->recallObject('orditems', 'orditems_List');
 			/* @var $object kDBList */
 
 			$object->Query();
 
 			return array_sum($object->GetCol('Quantity')); // $object->GetRecordsCount();
 		}
 
 		function CartNotEmpty($params)
 		{
 			$object = $this->getObject($params);
 
 			if ($object->GetDBField('Status') != ORDER_STATUS_INCOMPLETE || $object->GetID() == FAKE_ORDER_ID) {
 				return 0;
 			}
 
 			$order_id = $this->Application->RecallVar('ord_id');
 			if ($order_id) {
 				$sql = 'SELECT COUNT(*)
 						FROM ' . TABLE_PREFIX . 'OrderItems
 						WHERE OrderId = ' . $order_id;
 				return $this->Conn->GetOne($sql);
 			}
 
 			return 0;
 		}
 
 		function CartIsEmpty($params)
 		{
 			return $this->CartNotEmpty($params) ? false : true;
 		}
 
 		function CartHasBackorders($params = Array ())
 		{
 			$object = $this->getObject($params);
 
 			$sql = 'SELECT COUNT(*)
 					FROM ' . TABLE_PREFIX . 'OrderItems
 					WHERE OrderId = ' . $object->GetID() . '
 					GROUP BY BackOrderFlag';
 			$different_types = $this->Conn->GetCol($sql);
 
 			return count($different_types) > 1;
 		}
 
 		function PrintShippings($params)
 		{
 			$o = '';
 			$limitations_cache = Array ();
 
 			$object = $this->getObject($params);
 			/* @var $object kDBItem */
 
 			$ord_id = $object->GetID();
 			$oi_table = $this->Application->getUnitOption('orditems', 'TableName');
 
 			if ( $object->IsTempTable() ) {
 				$oi_table = $this->Application->GetTempName($oi_table, 'prefix:' . $object->Prefix);
 			}
 
 			list ($split_shipments, $limit_types) = $this->GetShippingLimitations($ord_id);
 
 			foreach ($split_shipments as $group => $data) {
 				$sql = 'UPDATE ' . $oi_table . '
 						SET SplitShippingGroup = ' . $group . '
 						WHERE ProductId IN (' . implode(',', $data['Products']) . ')';
 				$this->Conn->Query($sql);
 
 				$limitations_cache[$group] = $data['Types'];
 			}
 
 
 			$shipping_group_option = $object->GetDBField('ShippingGroupOption');
 			$shipping_group_select = $shipping_group_option == ORDER_GROUP_SHIPPMENTS_AUTO ? '0' : 'oi.SplitShippingGroup';
 
 			if ( count($split_shipments) > 1 ) {
 				// different shipping limitations apply
 				$this->Application->SetVar('shipping_limitations_apply', 1);
 
 				if ( $limit_types == 'NONE' ) {
 					// order can't be shipped with single shipping type
 					$shipping_group_option = ORDER_GROUP_SHIPPMENTS_MANUAL;
 					$shipping_group_select = 'oi.SplitShippingGroup';
 					$this->Application->SetVar('shipping_limitations_apply', 2);
 				}
 			}
 			else {
 				$this->Application->SetVar('shipping_limitations_apply', 0);
 			}
 
 
 
 
 			$shipping_option = $object->GetDBField('ShippingOption');
 
 			$weight_sql = 'IF(oi.Weight IS NULL, 0, oi.Weight * oi.Quantity)';
 
 			$sql = 'SELECT
 						' . ($shipping_option == ORDER_SHIP_ALL_TOGETHER ? '0' : 'oi.BackOrderFlag') . ' AS BackOrderFlagCalc,
 						oi.ProductName,
 						oi.ShippingTypeId,
 
 						SUM(oi.Quantity) AS TotalItems,
 						SUM(' . $weight_sql . ') AS TotalWeight,
 						SUM(oi.Price * oi.Quantity) AS TotalAmount,
 
 						SUM(oi.Quantity) - SUM(IF(p.MinQtyFreePromoShipping > 0 AND p.MinQtyFreePromoShipping <= oi.Quantity, oi.Quantity, 0)) AS TotalItemsPromo,
 						SUM(' . $weight_sql . ') - SUM(IF(p.MinQtyFreePromoShipping > 0 AND p.MinQtyFreePromoShipping <= oi.Quantity, ' . $weight_sql . ', 0)) AS TotalWeightPromo,
 						SUM(oi.Price * oi.Quantity) - SUM(IF(p.MinQtyFreePromoShipping > 0 AND p.MinQtyFreePromoShipping <= oi.Quantity, oi.Price * oi.Quantity, 0)) AS TotalAmountPromo,
 
 						' . $shipping_group_select . ' AS SplitShippingGroupCalc
 					FROM ' . $oi_table . ' oi
 					LEFT JOIN ' . TABLE_PREFIX . 'Products p ON oi.ProductId = p.ProductId
 					WHERE oi.OrderId = ' . $ord_id . ' AND p.Type = ' . PRODUCT_TYPE_TANGIBLE . '
 					GROUP BY BackOrderFlagCalc, SplitShippingGroupCalc
 					ORDER BY BackOrderFlagCalc ASC, SplitShippingGroupCalc ASC';
 			$shipments = $this->Conn->Query($sql);
 
 
 
 
 
 
 			$block_params = Array ();
 			$block_params['name'] = $this->SelectParam($params, 'render_as,block');
 			$block_params['user_country_id'] = $object->GetDBField('ShippingCountry');
 			$block_params['user_state_id'] = $object->GetDBField('ShippingState');
 			$block_params['user_zip'] = $object->GetDBField('ShippingZip');
 			$block_params['user_city'] = $object->GetDBField('ShippingCity');
 			$block_params['user_addr1'] = $object->GetDBField('ShippingAddress1');
 			$block_params['user_addr2'] = $object->GetDBField('ShippingAddress2');
 			$block_params['user_name'] = $object->GetDBField('ShippingTo');
 
 			$group = 1;
 			foreach ($shipments as $shipment) {
 				$where = Array ('OrderId = ' . $ord_id);
 
 				if ( $shipping_group_option == ORDER_GROUP_SHIPPMENTS_MANUAL ) {
 					$where[] = 'SplitShippingGroup = ' . $shipment['SplitShippingGroupCalc'];
 				}
 
 				if ( $shipping_option != ORDER_SHIP_ALL_TOGETHER ) {
 					$where[] = 'BackOrderFlag = ' . $shipment['BackOrderFlagCalc'];
 				}
 
 				$sql = 'UPDATE ' . $oi_table . '
 						SET PackageNum = ' . $group . '
 						WHERE ' . implode(' AND ', $where);
 				$this->Conn->Query($sql);
 
 				$group++;
 			}
 
 
 			$group = 1;
 			$this->Application->RemoveVar('LastShippings');
 			$this->Application->SetVar('ShipmentsExists', 1);
 
 			foreach ($shipments as $shipment) {
 				$block_params['package_num'] = $group;
 				$block_params['limit_types'] = $shipping_group_option == ORDER_GROUP_SHIPPMENTS_AUTO ? $limit_types : $limitations_cache[ $shipment['SplitShippingGroupCalc'] ];
 
 				$this->Application->SetVar('ItemShipmentsExists', 1); // also set from Order_PrintShippingTypes tag
 
 				switch ( $shipment['BackOrderFlagCalc'] ) {
 					case 0:
 						if ( $this->CartHasBackOrders() && $shipping_option == ORDER_SHIP_ALL_TOGETHER ) {
 							$block_params['shipment'] = $this->Application->Phrase('lu_all_available_backordered');
 						}
 						else {
 							$block_params['shipment'] = $this->Application->Phrase('lu_ship_all_available');;
 						}
 						break;
 
 					case 1:
 						$block_params['shipment'] = $this->Application->Phrase('lu_ship_all_backordered');;
 						break;
 
 					default:
 						$block_params['shipment'] = $this->Application->Phrase('lu_ship_backordered');
 						break;
 				}
 
 				$block_params['promo_weight_metric'] = $shipment['TotalWeightPromo'];
 				$block_params['promo_amount'] = $shipment['TotalAmountPromo'];
 				$block_params['promo_items'] = $shipment['TotalItemsPromo'];
 
 				$block_params['weight_metric'] = $shipment['TotalWeight'];
 				$block_params['weight'] = $shipment['TotalWeight'];
 
 				if ( $block_params['weight_metric'] == '' ) {
 					$block_params['weight'] = $this->Application->Phrase('lu_NotAvailable');
 				}
 				else {
 					$block_params['weight'] = $this->_formatWeight( $block_params['weight'] );
 				}
 
 
 				$block_params['items'] = $shipment['TotalItems'];
 
 				$amount = $this->ConvertCurrency($shipment['TotalAmount'], $this->GetISO( $params['currency'] ));
 				$amount = sprintf("%.2f", $amount);
 
 				$block_params['amount'] = $shipment['TotalAmount'];
 				$block_params['field_name'] = $this->InputName( Array('field' => 'ShippingTypeId') ) . '[' . $group . ']';
 
 				$parsed_block = $this->Application->ParseBlock($block_params);
 
 				if ( $this->Application->GetVar('ItemShipmentsExists') ) {
 					$o .= $parsed_block;
 				}
 				else {
 					$this->Application->SetVar('ShipmentsExists', 0);
 
 					if ( getArrayValue($params, 'no_shipments_render_as') ) {
 						$block_params['name'] = $params['no_shipments_render_as'];
 
 						return $this->Application->ParseBlock($block_params);
 					}
 				}
 
 				$group++;
 			}
 
 			if ( getArrayValue($params, 'table_header_render_as') ) {
 				$o = $this->Application->ParseBlock(Array ('name' => $params['table_header_render_as'])) . $o;
 			}
 
 			if ( getArrayValue($params, 'table_footer_render_as') ) {
 				$o .= $this->Application->ParseBlock(Array ('name' => $params['table_footer_render_as']));
 			}
 
 			return $o;
 		}
 
 		/**
 		 * Checks, that all given address fields are valid
 		 *
 		 * @param Array $params
 		 * @return bool
 		 */
 		function AddressValid($params)
 		{
 			$object = $this->getObject($params);
 			/* @var $object kDBItem */
 
 			$address_type = isset($params['type']) ? strtolower($params['type']) : 'shipping';
 			$address_type = ucfirst($address_type);
 
 			$check_fields = Array ('Address1', 'City', 'Zip', 'Country');
 
 			foreach ($check_fields as $check_field) {
 				if ( $object->GetDBField($address_type . $check_field) == '' ) {
 					return false;
 				}
 			}
 
 			return true;
 		}
 
 		function GetShippingLimitations($ord_id)
 		{
 			$limit_types = false;
 			$types_index = $split_shipments = $cat_limitations = Array ();
 
 			$sql = 'SELECT p.ShippingLimitation, p.ShippingMode, oi.ProductId AS ProductId
 					FROM ' . TABLE_PREFIX . 'Products p
 					LEFT JOIN ' . TABLE_PREFIX . 'OrderItems AS oi ON oi.ProductId = p.ProductId
 					WHERE oi.OrderId = ' . $ord_id . ' AND p.Type = ' . PRODUCT_TYPE_TANGIBLE;
 			$limitations = $this->Conn->Query($sql, 'ProductId');
 
 			// group products by shipping type range and calculate intersection of all types available for ALL products
 			// the intersection calculation is needed to determine if the order can be shipped with single type or not
 
 			if ($limitations) {
 				foreach ($limitations as $product_id => $row) {
 					// if shipping types are limited - get the types
 					$types = $row['ShippingLimitation'] != '' ? explode('|', substr($row['ShippingLimitation'], 1, -1)) : Array ('ANY');
 
 					// if shipping is NOT limited to selected types (default - so products with no limitations at all also counts)
 					if ($row['ShippingMode'] == PRODUCT_SHIPPING_MODE_ANY_AND_SELECTED) {
 						array_push($types, 'ANY'); // can be shipped with ANY (literally) type
 						$types = array_unique($types);
 					}
 
 					//adding product id to split_shipments group by types range
 					$i = array_search(serialize($types), $types_index);
 					if ($i === false) {
 						$types_index[] = serialize($types);
 						$i = count($types_index) - 1;
 					}
 
 					$split_shipments[$i]['Products'][] = $product_id;
 					$split_shipments[$i]['Types'] = serialize($types);
 
 					if ($limit_types === false) {
 						// it is false only when we process first item with limitations
 						$limit_types = $types; // initial scope
 					}
 
 					// this is to avoid ANY intersect CUST_1 = (), but allows ANY intersect CUST_1,ANY = (ANY)
 					if ( in_array('ANY', $limit_types) && !in_array('ANY', $types) ) {
 						array_splice($limit_types, array_search('ANY', $limit_types), 1, $types);
 					}
 
 					// this is to avoid CUST_1 intersect ANY = (), but allows CUST_1 intersect CUST_1,ANY = (ANY)
 					if ( !in_array('ANY', $limit_types) && in_array('ANY', $types) ) {
 						array_splice($types, array_search('ANY', $types), 1, $limit_types);
 					}
 
 					$limit_types = array_intersect($limit_types, $types);
 				}
 
 				$limit_types = count($limit_types) > 0 ? serialize(array_unique($limit_types)) : 'NONE';
 			}
 
 			return Array ($split_shipments, $limit_types);
 		}
 
 		function PaymentTypeForm($params)
 		{
 			$object = $this->getObject($params);
 
 			$payment_type_id = $object->GetDBField('PaymentType');
 			if($payment_type_id)
 			{
 				$this->Application->SetVar('pt_id', $payment_type_id);
 				$block_params['name'] = $this->SelectParam($params, $this->UsingCreditCard($params) ? 'cc_render_as,block_cc' : 'default_render_as,block_default' );
 				return $this->Application->ParseBlock($block_params);
 			}
 			return '';
 		}
 
 		/**
 		 * Returns true in case if credit card was used as payment type for order
 		 *
 		 * @param Array $params
 		 * @return bool
 		 */
 		function UsingCreditCard($params)
 		{
 			$object = $this->getObject($params);
 
 			$pt = $object->GetDBField('PaymentType');
 
 			if (!$pt) {
 				$pt = $this->Conn->GetOne('SELECT PaymentTypeId FROM '.TABLE_PREFIX.'PaymentTypes WHERE IsPrimary = 1');
 				$object->SetDBField('PaymentType', $pt);
 			}
 
 			$pt_table = $this->Application->getUnitOption('pt','TableName');
 			$sql = 'SELECT GatewayId FROM %s WHERE PaymentTypeId = %s';
 			$gw_id = $this->Conn->GetOne( sprintf( $sql, $pt_table, $pt ) );
 
 			$sql = 'SELECT RequireCCFields FROM %s WHERE GatewayId = %s';
 
 			return $this->Conn->GetOne( sprintf($sql, TABLE_PREFIX.'Gateways', $gw_id) );
 		}
 
 		function PaymentTypeDescription($params)
 		{
 			return $this->Application->ProcessParsedTag('pt', 'Field', 	array_merge($params, Array(
 					'field' => 'Description'
 			)) );
 		}
 
 		function PaymentTypeInstructions($params)
 		{
 			return $this->Application->ProcessParsedTag('pt', 'Field', 	array_merge($params, Array(
 					'field' => 'Instructions'
 			)) );
 		}
 
 		function PrintMonthOptions($params)
 		{
 			$object = $this->getObject($params);
 
 			$date = explode('/', $object->GetDBField($params['date_field_name']));
 			if (!$date || sizeof($date) != 2) {
 				$date=array("", "");
 			}
 			$o = '';
 			$params['name'] = $params['block'];
 			for ($i = 1; $i <= 12; $i++) {
 				$month_str = str_pad($i, 2, "0", STR_PAD_LEFT);
 				if ($date[0] == $month_str) {
 					$params['selected'] = ' selected';
 				}else {
 					$params['selected'] = '';
 				}
 
 				$params['mm'] = $month_str;
 				$o .= $this->Application->ParseBlock($params);
 			}
 			return $o;
 		}
 
 		function PrintYearOptions($params)
 		{
 			$object = $this->getObject($params);
 			$value = $object->GetDBField( $params['field'] );
 
 			$block_params = $this->prepareTagParams($params);
 			$block_params['name'] = $this->SelectParam($params, 'render_as,block');
 
 			$o = '';
 			$this_year = adodb_date('y');
 
 			for($i = $this_year; $i <= $this_year + 10; $i++)
 			{
 				$year_str = str_pad($i, 2, '0', STR_PAD_LEFT);
 				$block_params['selected'] = ($value == $year_str) ? $params['selected'] : '';
 				$block_params['key'] = $year_str;
 				$block_params['option'] = $year_str;
 				$o .= $this->Application->ParseBlock($block_params);
 			}
 			return $o;
 		}
 
 		function PrintMyOrders($params)
 		{
 
 		}
 
 		/**
 		 * Checks, that order data can be editied based on it's status
 		 *
 		 * @param Array $params
 		 * @return bool
 		 */
 		function OrderEditable($params)
 		{
 			$id_field = $this->Application->getUnitOption($this->Prefix, 'IDField');
 			$table_name = $this->Application->getUnitOption($this->Prefix, 'TableName');
 
 			if ($this->Application->IsTempMode($this->Prefix, $this->Special)) {
 				$table_name = $this->Application->GetTempName($table_name, 'prefix:' . $this->Prefix);
 			}
 
 			// use direct select here (not $this->getObject) because this tag is
 			// used even before "combined_header" block is used (on "orders_edit_items" template)
 			$sql = 'SELECT Status, PaymentType
 					FROM ' . $table_name . '
 					WHERE ' . $id_field . ' = ' . $this->Application->GetVar( $this->getPrefixSpecial() . '_id' );
 			$order_data = $this->Conn->GetRow($sql);
 
 			if (!$order_data) {
 				// new order adding, when even not in database
 				return true;
 			}
 
 			switch ($order_data['Status']) {
 				case ORDER_STATUS_INCOMPLETE:
 					$ret = true;
 					break;
 
 				case ORDER_STATUS_PENDING:
 				case ORDER_STATUS_BACKORDERS:
 					$sql = 'SELECT PlacedOrdersEdit
 							FROM ' . $this->Application->getUnitOption('pt', 'TableName') . '
 							WHERE ' . $this->Application->getUnitOption('pt', 'IDField') . ' = ' . $order_data['PaymentType'];
 					$ret = $this->Conn->GetOne($sql);
 					break;
 
 				default:
 					$ret = false;
 					break;
 			}
 
 			return $ret;
 		}
 
 		function CheckoutSteps($params)
 		{
 			$steps = explode(',', $params['steps']);
 			foreach ($steps as $key => $item)
 			{
 				$templates[$key] = trim($item);
 			}
 
 			$templates = explode(',', $params['templates']);
 			foreach ($templates as $key => $item)
 			{
 				$templates[$key] = trim($item);
 			}
 			$total_steps = count($templates);
 			$t = $this->Application->GetVar('t');
 
 			$o = '';
 			$block_params = array();
 			$i = 0;
 			$passed_current = preg_match("/".preg_quote($templates[count($templates)-1], '/')."/", $t);
 			foreach ($steps as $step => $name)
 			{
 				if (preg_match("/".preg_quote($templates[$step], '/')."/", $t)) {
 					$block_params['name'] = $this->SelectParam($params, 'current_step_render_as,block_current_step');
 					$passed_current = true;
 				}
 				else {
 					$block_params['name'] = $passed_current ? $this->SelectParam($params, 'render_as,block') : $this->SelectParam($params, 'passed_step_render_as,block_passed_step');
 				}
 				$block_params['title'] = $this->Application->Phrase($name);
 				$block_params['template'] = $templates[$i];
 				$block_params['template_link'] = $this->Application->HREF($templates[$step], '', Array('pass'=>'m'));
 				$block_params['next_step_template'] = isset($templates[$i + 1]) ? $templates[$i + 1] : '';
 				$block_params['number'] = $i + 1;
 				$i++;
 				$o.= $this->Application->ParseBlock($block_params, 1);
 			}
 			return $o;
 		}
 
 		function ShowOrder($params)
 		{
 
 			$order_params = $this->prepareTagParams($params);
 //			$order_params['Special'] = 'myorders';
 //			$order_params['PrefixSpecial'] = 'ord.myorders';
 			$order_params['name'] = $this->SelectParam($order_params, 'render_as,block');
 //			$this->Application->SetVar('ord.myorders_id', $this->Application->GetVar('ord_id'));
 
 			$object = $this->getObject($params);
 			if (!$object->GetDBField('OrderId')) {
 				return;
 			}
 			return $this->Application->ParseBlock($order_params);
 		}
 
 		function BuildListSpecial($params)
 		{
 			if ($this->Special != '') {
 				return $this->Special;
 			}
 
 			$list_unique_key = $this->getUniqueListKey($params);
 			if ($list_unique_key == '') {
 				return parent::BuildListSpecial($params);
 			}
 
 			return crc32($list_unique_key);
 		}
 
 		function ListOrders($params)
 		{
 			$o = '';
 			$params['render_as'] = $params['item_render_as'];
 
 			$o_orders = $this->PrintList2($params);
 
 			if ($o_orders) {
 				$orders_params = array('name' => $params['header_render_as']);
 				$o  = $this->Application->ParseBlock($orders_params);
 				$o .= $o_orders;
 
 			} else {
 				$orders_params = array('name' => $params['empty_myorders_render_as']);
 				$o = $this->Application->ParseBlock($orders_params);
 			}
 
 			return $o;
 
 		}
 
 		function HasRecentOrders($params)
 		{
 			$per_page = $this->SelectParam($params, 'per_page,max_items');
 			if ($per_page !== false) {
 				$params['per_page'] = $per_page;
 			}
 
 			return (int)$this->TotalRecords($params) > 0 ? 1 : 0;
 		}
 
 		function ListOrderItems($params)
 		{
 			$prefix_special = rtrim('orditems.'.$this->Special, '.');
 			return $this->Application->ProcessParsedTag($prefix_special, 'PrintList', 	array_merge($params, Array(
 					'per_page' => -1
 			)) );
 		}
 
 
 		function OrdersLink(){
 			$params['pass']='m,ord';
 			$main_processor = $this->Application->recallObject('m_TagProcessor');
 			return $main_processor->Link($params);
 		}
 
 
 
 		function PrintAddresses($params)
 		{
 			$object = $this->getObject($params);
 
 			$address_list = $this->Application->recallObject('addr','addr_List', Array('per_page'=>-1, 'skip_counting'=>true) );
 			$address_list->Query();
 
 			$address_id = $this->Application->GetVar($params['type'].'_address_id');
 			if (!$address_id) {
 				$sql = 'SELECT '.$address_list->IDField.'
 						FROM '.$address_list->TableName.'
 						WHERE PortalUserId = '.$object->GetDBField('PortalUserId').' AND LastUsedAs'.ucfirst($params['type']).' = 1';
 				$address_id = (int)$this->Conn->GetOne($sql);
 			}
 
 			$ret = '';
 			$block_params = $this->prepareTagParams($params);
 			$block_params['name'] = $this->SelectParam($params, 'render_as,block');
 
 			$address_list->GoFirst();
 			while (!$address_list->EOL()) {
 
 				$selected = ($address_list->GetID() == $address_id);
 				if ($selected && $address_list->GetDBField('IsProfileAddress')) {
 					$this->Application->SetVar($this->Prefix.'_IsProfileAddress', true);
 				}
 
 				$block_params['key'] = $address_list->GetID();
 				$block_params['value'] = $address_list->GetDBField('ShortAddress');
 				$block_params['selected'] = $selected ? ' selected="selected"' : '';
 
 				$ret .= $this->Application->ParseBlock($block_params, 1);
 				$address_list->GoNext();
 			}
 
 			return $ret;
 		}
 
 		function PrefillRegistrationFields($params)
 		{
 			if ( $this->Application->GetVar('fields_prefilled') ) {
 				return false;
 			}
 
 			if ( isset($params['user_prefix']) ) {
 				$user = $this->Application->recallObject($params['user_prefix']);
 				/* @var $user kDBItem */
 			}
 			else {
 				$user = $this->Application->recallObject('u', null, Array ('skip_autoload' => true));
 				/* @var $user kDBItem */
 			}
 
 			$order = $this->Application->recallObject($this->Prefix . '.last');
 			/* @var $order OrdersItem */
 
 			$order_helper = $this->Application->recallObject('OrderHelper');
 			/* @var $order_helper OrderHelper */
 
 			$user_fields = $order_helper->getUserFields($order, $params['type'] == 'billing' ? 'Billing' : 'Shipping');
 
 			foreach ($user_fields as $field => $value) {
 				if ( !$user->GetDBField($field) ) {
 					$user->SetDBField($field, $value);
 				}
 			}
 
 			$cs_helper = $this->Application->recallObject('CountryStatesHelper');
 			/* @var $cs_helper kCountryStatesHelper */
 
 			$cs_helper->PopulateStates(new kEvent('u:OnBuild'), 'State', 'Country');
 		}
 
 		function UserLink($params)
 		{
 			$object = $this->getObject($params);
 			$user_id = $object->GetDBField( $params['user_field'] );
 
 			if ($user_id) {
 				$url_params =  Array (
 					'm_opener' => 'd',
 					'u_mode' => 't',
 					'u_event' => 'OnEdit',
 					'u_id' => $user_id,
 					'pass' => 'all,u',
 					'no_pass_through' => 1,
 				);
 
 				return $this->Application->HREF($params['edit_template'], '', $url_params);
 			}
 		}
 
 		function UserFound($params)
 		{
 			$virtual_users = Array(USER_ROOT, USER_GUEST, 0);
 			$object = $this->getObject($params);
 			return !in_array( $object->GetDBField( $params['user_field'] ) , $virtual_users );
 		}
 
 		/**
 		 * Returns a link for editing order
 		 *
 		 * @param Array $params
 		 * @return string
 		 */
 		function OrderLink($params)
 		{
 			$object = $this->getObject($params);
 
 			$url_params = Array (
 				'm_opener' => 'd',
 				$this->Prefix.'_mode' => 't',
 				$this->Prefix.'_event' => 'OnEdit',
 				$this->Prefix.'_id' => $object->GetID(),
 				'pass' => 'all,'.$this->Prefix,
 				'no_pass_through' => 1,
 			);
 
 			return $this->Application->HREF($params['edit_template'], '', $url_params);
 		}
 
 		function HasOriginalAmount($params)
 		{
 			$object = $this->getObject($params);
 			$original_amount = $object->GetDBField('OriginalAmount');
 			return $original_amount && ($original_amount != $object->GetDBField('TotalAmount') );
 		}
 
 		/**
 		 * Returns true, when order has tangible items
 		 *
 		 * @param Array $params
 		 * @return bool
 		 *
 		 * @todo This is copy from OrdersItem::HasTangibleItems. Copy to helper (and create it) and use here.
 		 */
 		function OrderHasTangibleItems($params)
 		{
 			$object = $this->getObject($params);
 			if ($object->GetID() == FAKE_ORDER_ID) {
 				return false;
 			}
 
 			$sql = 'SELECT COUNT(*)
 					FROM '.TABLE_PREFIX.'OrderItems orditems
 					LEFT JOIN '.TABLE_PREFIX.'Products p ON p.ProductId = orditems.ProductId
 					WHERE (orditems.OrderId = '.$object->GetID().') AND (p.Type = '.PRODUCT_TYPE_TANGIBLE.')';
 			return $this->Conn->GetOne($sql) ? true : false;
 		}
 
 		function ShipmentsExists($params)
 		{
 			return $this->Application->GetVar('ShipmentsExists') ? 1 : 0;
 		}
 
 		function Field($params)
 		{
 			$value = parent::Field($params);
 			$field = $this->SelectParam($params,'name,field');
 			if( ($field == 'PaymentAccount') && getArrayValue($params,'masked') )
 			{
 				$value = str_repeat('X',12).substr($value,-4);
 			}
 			return $value;
 		}
 
 		function CartHasError($params)
 		{
 			return $this->Application->RecallVar('checkout_errors');
 		}
 
 		function CheckoutError($params)
 		{
 			$errors = $this->Application->RecallVar('checkout_errors');
 
 			if ( !$errors ) {
 				return '';
 			}
 
-//			$this->Application->RemoveVar('checkout_errors');
+			$this->Application->RemoveVar('checkout_errors');
 			$errors = unserialize($errors);
 
 			if ( isset($errors[OrderCheckoutErrorType::COUPON]) ) {
 				$mapping = Array (
 					OrderCheckoutError::COUPON_APPLIED => 'coupon_applied',
 					OrderCheckoutError::COUPON_REMOVED => 'code_removed',
 					OrderCheckoutError::COUPON_REMOVED_AUTOMATICALLY => 'code_removed_automatically',
 					OrderCheckoutError::COUPON_CODE_INVALID => 'invalid_code',
 					OrderCheckoutError::COUPON_CODE_EXPIRED => 'code_expired',
 				);
 
 				$error_phrase = $mapping[ $errors[OrderCheckoutErrorType::COUPON] ];
 			}
 			elseif ( isset($errors[OrderCheckoutErrorType::GIFT_CERTIFICATE]) ) {
 				$mapping = Array (
 					OrderCheckoutError::GC_APPLIED => 'gift_certificate_applied',
 					OrderCheckoutError::GC_REMOVED => 'gc_code_removed',
 					OrderCheckoutError::GC_REMOVED_AUTOMATICALLY => 'gc_code_removed_automatically',
 					OrderCheckoutError::GC_CODE_INVALID => 'invalid_gc_code',
 					OrderCheckoutError::GC_CODE_EXPIRED => 'gc_code_expired',
 
 				);
 
 				$error_phrase = $mapping[ $errors[OrderCheckoutErrorType::GIFT_CERTIFICATE] ];
 			}
 			else {
 				$mapping = Array (
 					OrderCheckoutError::QTY_UNAVAILABLE => 'qty_unavailable',
 					OrderCheckoutError::QTY_OUT_OF_STOCK => 'outofstock',
 					OrderCheckoutError::QTY_CHANGED_TO_MINIMAL => 'min_qty',
 				);
 
 				foreach ($errors as $error_type => $error_code) {
 					if ( isset($mapping[$error_code]) ) {
 						$error_phrase = $mapping[$error_code];
 						break;
 					}
 				}
 
 				if ( !isset($error_phrase) ) {
 					$error_phrase = 'state_changed'; // 'changed_after_login'
 				}
 			}
 
 			return $this->Application->Phrase( $params[$error_phrase] );
 		}
 
 		/**
 		 * Returns checkout errors in JSON format
 		 *
 		 * @param Array $params
 		 * @return string
 		 */
 		function PrintOrderInfo($params)
 		{
 			$order_helper = $this->Application->recallObject('OrderHelper');
 			/* @var $order_helper OrderHelper */
 
 			$object = $this->getObject($params);
 			/* @var $object kDBItem */
 
 			$currency = isset($params['currency']) ? $params['currency'] : 'selected';
 
 			return json_encode( $order_helper->getOrderInfo($object, $currency) );
 		}
 
 		/**
 		 * Returns currency mark (%s is $amount placemark)
 		 *
 		 * @param Array $params
 		 * @return string
 		 */
 		function CurrencyMask($params)
 		{
 			$iso = $this->GetISO( $params['currency'] );
 
 			return $this->AddCurrencySymbol('%s', $iso);
 		}
 
 		function CheckoutErrorNew($params)
 		{
 			$errors = $this->Application->RecallVar('checkout_errors');
 
 			if ( !$errors ) {
 				return '';
 			}
 
 //			$this->Application->RemoveVar('checkout_errors');
 			$errors = unserialize($errors);
 
 			$reflection = new ReflectionClass('OrderCheckoutErrorType');
 			$error_types = $reflection->getConstants();
 
 			$reflection = new ReflectionClass('OrderCheckoutError');
 			$error_codes = $reflection->getConstants();
 
 			$ret = Array ();
 
 			foreach ($errors as $error_type => $error_code) {
 				$error_type = explode(':', $error_type);
 
 				$error_explained = '<strong>' . array_search($error_type[0], $error_types) . '</strong>';
 
 				if ( $error_type[0] == OrderCheckoutErrorType::PRODUCT ) {
 					$error_explained .= ' (ProductId = <strong>' . $error_type[1] . '</strong>; OptionsSalt: <strong>' . $error_type[2] . '</strong>; BackOrderFlag: ' . $error_type[3] . '; Field: <strong>' . $error_type[4] . '</strong>)';
 				}
 
 				$error_explained .= ' - <strong>' . array_search($error_code, $error_codes) . '</strong>';
 				$ret[] = $error_explained;
 			}
 
 			return implode('<br/>', $ret);
 		}
 
 		function GetFormAction($params)
 		{
 			$object = $this->getObject($params);
 			/* @var $object OrdersItem */
 
 			$gw_data = $object->getGatewayData( isset($params['payment_type_id']) ? $params['payment_type_id'] : null );
 			$this->Application->registerClass( $gw_data['ClassName'], GW_CLASS_PATH.'/'.$gw_data['ClassFile'] );
 
 			$gateway_object = $this->Application->recallObject( $gw_data['ClassName'] );
 			/* @var $gateway_object kGWBase */
 
 			return $gateway_object->getFormAction($gw_data['gw_params']);
 		}
 
 		function GetFormHiddenFields($params)
 		{
 			$object = $this->getObject($params);
 			/* @var $object OrdersItem */
 
 			$gw_data = $object->getGatewayData( isset($params['payment_type_id']) ? $params['payment_type_id'] : null );
 			$this->Application->registerClass( $gw_data['ClassName'], GW_CLASS_PATH.'/'.$gw_data['ClassFile'] );
 
 			$gateway_object = $this->Application->recallObject( $gw_data['ClassName'] );
 			/* @var $gateway_object kGWBase */
 
 			$tpl = '<input type="hidden" name="%s" value="%s" />'."\n";
 			$hidden_fields = $gateway_object->getHiddenFields($object->GetFieldValues(), $params, $gw_data['gw_params']);
 
 			if ( !is_array($hidden_fields) ) {
 				return $hidden_fields;
 			}
 
 			$ret = '';
 
 			foreach ($hidden_fields as $hidden_name => $hidden_value) {
 				$ret .= sprintf($tpl, $hidden_name, $hidden_value);
 			}
 
 			return $ret;
 		}
 
 		function NeedsPlaceButton($params)
 		{
 			$object = $this->getObject($params);
 			/* @var $object OrdersItem */
 
 			$gw_data = $object->getGatewayData( isset($params['payment_type_id']) ? $params['payment_type_id'] : null );
 			$this->Application->registerClass( $gw_data['ClassName'], GW_CLASS_PATH.'/'.$gw_data['ClassFile'] );
 
 			$gateway_object = $this->Application->recallObject( $gw_data['ClassName'] );
 			/* @var $gateway_object kGWBase */
 
 			return $gateway_object->NeedPlaceButton($object->GetFieldValues(), $params, $gw_data['gw_params']);
 		}
 
 		function HasGatewayError($params)
 		{
 			return $this->Application->RecallVar('gw_error');
 		}
 
 		function ShowGatewayError($params)
 		{
 			$ret = $this->Application->RecallVar('gw_error');
 			$this->Application->RemoveVar('gw_error');
 			return $ret;
 		}
 
 		function ShippingType($params)
 		{
 			$object = $this->getObject($params);
 			/* @var $object kDBItem */
 
 			$shipping_info = unserialize($object->GetDBField('ShippingInfo'));
 
 			if ( count($shipping_info) > 1 ) {
 				return $this->Application->Phrase('lu_MultipleShippingTypes');
 			}
 
 			if ( $shipping_info ) {
 				$shipping_info = array_shift($shipping_info);
 
 				return $shipping_info['ShippingName'];
 			}
 
 			return '';
 		}
 
 		function DiscountHelpLink($params)
 		{
 			$params['pass'] = 'all,orditems';
 			$params['m_cat_id'] = 0;
 			$m_tag_processor = $this->Application->recallObject('m_TagProcessor');
 			return $m_tag_processor->Link($params);
 		}
 
 		function DiscountField($params)
 		{
 			$orditems = $this->Application->recallObject( 'orditems' );
 			$item_data = $orditems->GetDBField('ItemData');
 			if(!$item_data) return '';
 			$item_data = unserialize($item_data);
 			$discount_prefix = ($item_data['DiscountType'] == 'coupon') ? 'coup' : 'd';
 
 			$discount = $this->Application->recallObject($discount_prefix, null, Array('skip_autoload' => true));
 			if(!$discount->isLoaded())
 			{
 				$discount->Load($item_data['DiscountId']);
 			}
 			return $discount->GetField( $this->SelectParam($params, 'field,name') );
 		}
 
 		function HasDiscount($params)
 		{
 			$object = $this->getObject($params);
 			return (float)$object->GetDBField('DiscountTotal') ? 1 : 0;
 		}
 
 		/**
 		 * Allows to check if required product types are present in order
 		 *
 		 * @param Array $params
 		 */
 		function HasProductType($params)
 		{
 			$product_types = Array('tangible' => 1, 'subscription' => 2, 'service' => 3, 'downloadable' => 4, 'package' => 5, 'gift' => 6);
 			$object = $this->getObject($params);
 
 			$sql = 'SELECT COUNT(*)
 					FROM '.TABLE_PREFIX.'OrderItems oi
 					LEFT JOIN '.TABLE_PREFIX.'Products p ON p.ProductId = oi.ProductId
 					WHERE (oi.OrderId = '.$object->GetID().') AND (p.Type = '.$product_types[ $params['type'] ].')';
 			return $this->Conn->GetOne($sql);
 		}
 
 		function PrintSerializedFields($params)
 		{
 			$object = $this->getObject($params);
 			$field = $this->SelectParam($params, 'field');
 			if (!$field) $field = $this->Application->GetVar('field');
 			$data = unserialize($object->GetDBField($field));
 
 			$o = '';
 			$block_params['name'] = $params['render_as'];
 			foreach ($data as $field => $value) {
 				$block_params['field'] = $field;
 				$block_params['value'] = $value;
 				$o .= $this->Application->ParseBlock($block_params);
 			}
 			return $o;
 		}
 
-		function OrderProductEmail($params)
-		{
-			$order = $this->Application->recallObject('ord');
-			$orditems = $this->Application->recallObject('orditems');
-
-			$sql = 'SELECT ResourceId
-					FROM '.TABLE_PREFIX.'Products
-					WHERE ProductId = '.$orditems->GetDBField('ProductId');
-			$resource_id = $this->Conn->GetOne($sql);
-
-			$ml_formatter = $this->Application->recallObject('kMultiLanguage');
-			$custom_fields = $this->Application->getUnitOption('p', 'CustomFields');
-			$custom_name = $ml_formatter->LangFieldName('cust_'.array_search($params['msg_custom_field'], $custom_fields));
-
-			$sql = 'SELECT '.$custom_name.'
-					FROM '.$this->Application->getUnitOption('p-cdata', 'TableName').'
-					WHERE ResourceId = '.$resource_id;
-			$message_template = $this->Conn->GetOne($sql);
-
-			if (!$message_template || trim($message_template) == '') {
-				// message template missing
-				return ;
-			}
-
-			$from_name = strip_tags($this->Application->ConfigValue('Site_Name'));
-			$from_email = $this->Application->ConfigValue('DefaultEmailSender');
-
-			$to_name = $order->GetDBField('BillingTo');
-			$to_email = $order->GetDBField('BillingEmail');
-			if (!$to_email) {
-				// billing email is empty, then use user's email
-				$sql = 'SELECT Email
-						FROM '.$this->Application->getUnitOption('u', 'TableName').'
-						WHERE PortalUserId = '.$order->GetDBField('PortalUserId');
-				$to_email = $this->Conn->GetOne($sql);
-			}
-
-			$esender = $application->recallObject('EmailSender.-product');
-			/* @var $esender kEmailSendingHelper */
-
-			$esender->SetFrom($from_email, $from_name);
-			$esender->AddTo($to_email, $to_name);
-
-			$email_events_eh = $this->Application->recallObject('emailevents_EventHandler');
-			/* @var $email_events_eh EmailEventsEventsHandler */
-
-			list ($message_headers, $message_body) = $email_events_eh->ParseMessageBody($message_template, Array());
-			if (!trim($message_body)) {
-				// message body missing
-				return false;
-			}
-
-			foreach ($message_headers as $header_name => $header_value) {
-				$esender->SetEncodedHeader($header_name, $header_value);
-			}
-
-			$esender->SetHTML($message_body);
-			$esender->Deliver();
-		}
-
 		/**
 		 * Prints order totals
 		 *
 		 * @param Array $params
 		 * @return string
 		 * @access protected
 		 */
 		protected function PrintTotals($params)
 		{
 			$object = $this->getObject($params);
 			/* @var $object OrdersItem */
 
 			if ( isset($params['element_order']) ) {
 				// TODO: implement
 			}
 			else {
 				// default element order
 				$element_order = Array (
 					'products' => 1, 'return' => 4, 'sub_total' => 5, 'discount' => 6,
 					'vat' => 7, 'shipping' => 8, 'processing' => 9,
 				);
 
 				// show shipping & processing costs before tax, when they are taxable
 				if ( $object->GetDBField('ShippingTaxable') ) {
 					$element_order['shipping'] = 2;
 				}
 
 				if ( $object->GetDBField('ProcessingTaxable') ) {
 					$element_order['processing'] = 3;
 				}
 			}
 
 			$totals = Array ();
 
 			if ( abs($object->GetDBField('SubTotal') - $object->GetDBField('AmountWithoutVAT')) > 0.01 ) {
 				$totals[] = 'products';
 			}
 
 			if ( $this->OrderHasTangibleItems($params) ) {
 				$totals[] = 'shipping';
 			}
 
 			if ( $object->GetDBField('ProcessingFee') > 0 ) {
 				$totals[] = 'processing';
 			}
 
 			if ( $object->GetDBField('ReturnTotal') > 0 ) {
 				$totals[] = 'return';
 			}
 
 			if ( $this->HasDiscount($params) ) {
 				$totals[] = 'discount';
 			}
 
 			$totals[] = 'sub_total';
 
 			if ( $object->GetDBField('VAT') > 0 ) {
 				$totals[] = 'vat';
 			}
 
 			$o = '';
 			asort($element_order, SORT_NUMERIC);
 
 			$block_params = $this->prepareTagParams($params);
 
 			foreach ($element_order as $type => $order) {
 				$element = getArrayValue($params, $type . '_render_as');
 
 				if ( !in_array($type, $totals) || !$element ) {
 					continue;
 				}
 
 				$block_params['name'] = $element;
 
 				$o .= $this->Application->ParseBlock($block_params);
 			}
 
 			return $o;
 		}
 
 		function ShowDefaultAddress($params)
 		{
 			$address_type = ucfirst($params['type']);
 			if ($this->Application->GetVar('check_'.strtolower($address_type).'_address')) {
 				// form type doesn't match check type, e.g. shipping check on billing form
 				return '';
 			}
 
 			// for required field highlighting on form when no submit made
 			$this->Application->SetVar('check_'.strtolower($address_type).'_address', 'true');
 			/*if ((strtolower($address_type) == 'billing') && $this->UsingCreditCard($params)) {
 				$this->Application->SetVar('check_credit_card', 'true');
 			}*/
 
 			$this->Application->HandleEvent(new kEvent('ord:SetStepRequiredFields'));
 
 			$user_id = $this->Application->RecallVar('user_id');
 			$sql = 'SELECT AddressId
 					FROM '.TABLE_PREFIX.'Addresses
 					WHERE PortalUserId = '.$user_id.' AND LastUsedAs'.$address_type.' = 1';
 			$address_id = $this->Conn->GetOne($sql);
 			if (!$address_id) {
 				return '';
 			}
 
 			$addr_list = $this->Application->recallObject('addr', 'addr_List', Array('per_page'=>-1, 'skip_counting'=>true) );
 			$addr_list->Query();
 
 			$object = $this->getObject();
 			if (!$addr_list->CheckAddress($object->GetFieldValues(), $address_type)) {
 				$addr_list->CopyAddress($address_id, $address_type);
 			}
 		}
 
 		function IsProfileAddress($params)
 		{
 			$object = $this->getObject($params);
 			$address_type = ucfirst($params['type']);
 			return $object->IsProfileAddress($address_type);
 		}
 
 		function HasPayPalSubscription($params)
 		{
 			$object = $this->getObject($params);
 
 			$sql = 'SELECT COUNT(*)
 					FROM '.TABLE_PREFIX.'OrderItems oi
 					LEFT JOIN '.TABLE_PREFIX.'Products p ON p.ProductId = oi.ProductId
 					WHERE (oi.OrderId = '.$object->GetID().') AND (p.PayPalRecurring = 1)';
 			return $this->Conn->GetOne($sql);
 
 		}
 
 		function GetPayPalSubscriptionForm($params)
 		{
 			$object = $this->getObject($params);
 			$gw_data = $object->getGatewayData($params['payment_type_id']);
 
 			$this->Application->registerClass( $gw_data['ClassName'], GW_CLASS_PATH.'/'.$gw_data['ClassFile'] );
 			$gateway_object = $this->Application->recallObject( $gw_data['ClassName'] );
 
 
 			$sql = 'SELECT oi.*
 					FROM '.TABLE_PREFIX.'OrderItems oi
 					LEFT JOIN '.TABLE_PREFIX.'Products p ON p.ProductId = oi.ProductId
 					WHERE (oi.OrderId = '.$object->GetID().') AND (p.PayPalRecurring = 1)';
 			$order_item = $this->Conn->GetRow($sql);
 			$order_item_data =  unserialize($order_item['ItemData']);
 
 			$cycle = ceil($order_item_data['Duration'] / 86400);
 			$cycle_units = 'D';
 
 			$item_data = $object->GetFieldValues();
 			$item_data['item_name'] = $order_item['ProductName'];
 			$item_data['item_number'] = $order_item['OrderItemId'];
 			$item_data['custom'] = $order_item['OrderId'];
 			$item_data['a1'] = '';
 			$item_data['p1'] = '';
 			$item_data['t1'] = '';
 			$item_data['a2'] = '';
 			$item_data['p2'] = '';
 			$item_data['t2'] = '';
 			$item_data['a3'] = $order_item['Price']; //rate
 			$item_data['p3'] = $cycle; //cycle
 			$item_data['t3'] = $cycle_units; //cycle units D (days), W (weeks), M (months), Y (years)
 			$item_data['src'] = '1'; // Recurring payments. If set to 1, the payment will recur unless your customer cancels the subscription before the end of the billing cycle.
 			$item_data['sra'] = '1'; // Reattempt on failure. If set to 1, and the payment fails, the payment will be reattempted two more times. After the third failure, the subscription will be cancelled.
 			$item_data['srt'] = ''; // Recurring Times. This is the number of payments which will occur at the regular rate.
 
 			$hidden_fields = $gateway_object->getSubscriptionFields($item_data, $params, $gw_data['gw_params']);
 
 			$ret = '';
 			if (!is_array($hidden_fields)) {
 				return $hidden_fields;
 			}
 			$tpl = '<input type="hidden" name="%s" value="%s" />'."\n";
 			foreach($hidden_fields as $hidden_name => $hidden_value)
 			{
 				$ret .= sprintf($tpl, $hidden_name, $hidden_value);
 			}
 			return $ret;
 		}
 
 		function UserHasPendingOrders($params)
 		{
 			$sql = 'SELECT OrderId FROM '.$this->Application->getUnitOption($this->Prefix, 'TableName').'
 							WHERE PortalUserId = '.$this->Application->RecallVar('user_id').'
 							AND Status = '.ORDER_STATUS_PENDING;
 			return $this->Conn->GetOne($sql) ? 1 : 0;
 		}
 
 		function AllowAddAddress($params)
 		{
 			$user = $this->Application->recallObject('u.current');
 
 			if ($user->GetDBField('cust_shipping_addr_block')) return false;
 
 			$address_list = $this->Application->recallObject('addr','addr_List', Array('per_page'=>-1, 'skip_counting'=>true) );
 			$address_list->Query();
 
 			$max = $this->Application->ConfigValue('MaxAddresses');
 
 			return $max <= 0 ? true : $address_list->GetRecordsCount() < $max;
 		}
 
 		/**
 		 * Creates link for removing coupon or gift certificate
 		 *
 		 * @param Array $params
 		 * @return string
 		 */
 		function RemoveCouponLink($params)
 		{
 			$type = strtolower($params['type']);
 			$url_params = Array (
 				'pass' => 'm,ord',
 				'ord_event' => ($type == 'coupon') ? 'OnRemoveCoupon' : 'OnRemoveGiftCertificate',
 				'm_cat_id' => 0,
 			);
 
 			return $this->Application->HREF('', '', $url_params);
 		}
 
 		/**
 		 * Calculates total weight of items in shopping cart
 		 *
 		 * @param Array $params
 		 * @return float
 		 */
 		function TotalOrderWeight($params)
 		{
 			$object = $this->getObject($params);
 			/* @var $object kDBItem */
 
 			$sql = 'SELECT SUM( IF(oi.Weight IS NULL, 0, oi.Weight * oi.Quantity) )
 					FROM '.TABLE_PREFIX.'OrderItems oi
 					WHERE oi.OrderId = '.$object->GetID();
 			$total_weight = $this->Conn->GetOne($sql);
 
 			if ($total_weight == '') {
 				// zero weight -> return text about it
 				return $this->Application->Phrase('lu_NotAvailable');
 			}
 
 			return $this->_formatWeight($total_weight);
 		}
 
 		function _formatWeight($weight)
 		{
 			$regional = $this->Application->recallObject('lang.current');
 			/* @var $regional kDBItem */
 
 			switch ( $regional->GetDBField('UnitSystem') ) {
 				case 1:
 					// metric system -> add kg sign
 					$weight .= ' ' . $this->Application->Phrase('lu_kg');
 					break;
 
 				case 2:
 					// uk system -> convert to pounds
 					list ($pounds, $ounces) = kUtil::Kg2Pounds($weight);
 
 					$weight = $pounds . ' ' . $this->Application->Phrase('lu_pounds') . ' ' . $ounces . ' ' . $this->Application->Phrase('lu_ounces');
 					break;
 			}
 
 			return $weight;
 		}
 
 		function InitCatalogTab($params)
 		{
 			$tab_params['mode'] = $this->Application->GetVar('tm'); // single/multi selection possible
 			$tab_params['special'] = $this->Application->GetVar('ts'); // use special for this tab
 			$tab_params['dependant'] = $this->Application->GetVar('td'); // is grid dependant on categories grid
 
 			// set default params (same as in catalog)
 			if ($tab_params['mode'] === false) $tab_params['mode'] = 'multi';
 			if ($tab_params['special'] === false) $tab_params['special'] = '';
 			if ($tab_params['dependant'] === false) $tab_params['dependant'] = 'yes';
 
 			// pass params to block with tab content
 			$params['name'] = $params['render_as'];
 			$params['prefix'] = trim($this->Prefix.'.'.($tab_params['special'] ? $tab_params['special'] : $this->Special), '.');
 			$params['cat_prefix'] = trim('c.'.($tab_params['special'] ? $tab_params['special'] : $this->Special), '.');
 			$params['tab_mode'] = $tab_params['mode'];
 			$params['grid_name'] = ($tab_params['mode'] == 'multi') ? $params['default_grid'] : $params['radio_grid'];
 			$params['tab_dependant'] = $tab_params['dependant'];
 			$params['show_category'] = $tab_params['special'] == 'showall' ? 1 : 0; // this is advanced view -> show category name
 
 			// use $pass_params to be able to pass 'tab_init' parameter from m_ModuleInclude tag
 			return $this->Application->ParseBlock($params, 1);
 		}
 
 		/**
 		 * Checks if required payment method is available
 		 *
 		 * @param Array $params
 		 * @return bool
 		 */
 		function HasPaymentGateway($params)
 		{
 			static $payment_types = Array ();
 
 			$gw_name = $params['name'];
 			if (!array_key_exists($gw_name, $payment_types)) {
 				$sql = 'SELECT pt.PaymentTypeId, pt.PortalGroups
 						FROM '.TABLE_PREFIX.'PaymentTypes pt
 						LEFT JOIN '.TABLE_PREFIX.'Gateways g ON pt.GatewayId = g.GatewayId
 						WHERE (g.Name = '.$this->Conn->qstr($params['name']).') AND (pt.Status = '.STATUS_ACTIVE.')';
 				$payment_types[$gw_name] = $this->Conn->GetRow($sql);
 			}
 
 			if (!$payment_types[$gw_name]) {
 				return false;
 			}
 
 			$pt_groups = explode(',', substr($payment_types[$gw_name]['PortalGroups'], 1, -1));
 			$user_groups = explode(',', $this->Application->RecallVar('UserGroups'));
 
 			return array_intersect($user_groups, $pt_groups) ? $payment_types[$gw_name]['PaymentTypeId'] : false;
 		}
 
 		function DisplayPaymentGateway($params)
 		{
 			$payment_type_id = $this->HasPaymentGateway($params);
 			if (!$payment_type_id) {
 				return '';
 			}
 
 			$object = $this->getObject($params);
 			/* @var $object OrdersItem */
 
 			$gw_data = $object->getGatewayData($payment_type_id);
 
 			$block_params = $gw_data['gw_params'];
 			$block_params['name'] = $params['render_as'];
 			$block_params['payment_type_id'] = $payment_type_id;
 
 			return $this->Application->ParseBlock($block_params);
 		}
 
 		/**
 		 * Checks, that USPS returned valid label
 		 *
 		 * @param Array $params
 		 * @return bool
 		 */
 		function USPSLabelFound($params)
 		{
 			$object = $this->getObject($params);
 			/* @var $object kDBItem */
 
 			$full_path = USPS_LABEL_FOLDER . $object->GetDBField( $params['field'] ) . '.pdf';
 
 			return file_exists($full_path) && is_file($full_path);
 		}
 
 		/**
 		 * Prints SQE errors from session
 		 *
 		 * @param Array $params
 		 * @return string
 		 */
 		function PrintSQEErrors($params)
 		{
 			$sqe_errors = $this->Application->RecallVar('sqe_errors');
 
 			if (!$sqe_errors) {
 				return '';
 			}
 
 			$o = '';
 			$block_params = $this->prepareTagParams($params);
 			$block_params['name'] = $params['render_as'];
 			$sqe_errors = unserialize($sqe_errors);
 
 			foreach ($sqe_errors as $order_number => $error_description) {
 				$block_params['order_number'] = $order_number;
 				$block_params['error_description'] = $error_description;
 
 				$o .= $this->Application->ParseBlock($block_params);
 			}
 
 			$this->Application->RemoveVar('sqe_errors');
 
 			return $o;
 		}
 
 		/**
 		 * Creates a continue shopping link
 		 *
 		 * @param Array $params
 		 * @return string
 		 * @access protected
 		 */
 		protected function ContinueShoppingLink($params)
 		{
 			$order_helper = $this->Application->recallObject('OrderHelper');
 			/* @var $order_helper OrderHelper */
 
 			if ( isset($params['template']) ) {
 				$template = $params['template'];
 				unset($params['template']);
 			}
 			else {
 				$template = '';
 			}
 
 			return $this->Application->HREF($order_helper->getContinueShoppingTemplate($template), '', $params);
 		}
 
 		/**
 		 * Checks that billing address and shipping address are the same
 		 *
 		 * @param Array $params
 		 * @return string
 		 * @access protected
 		 */
 		protected function AddressesTheSame($params)
 		{
 			$object = $this->getObject($params);
 			/* @var $object kDBItem */
 
 			$address_fields = Array ('To', 'Company', 'Address1', 'Address2', 'City', 'Country', 'State', 'Zip');
 
 			foreach ($address_fields as $address_field) {
 				if ( $object->GetDBField('Shipping' . $address_field) != $object->GetDBField('Billing' . $address_field) ) {
 					return false;
 				}
 			}
 
 			return true;
 		}
 	}
\ No newline at end of file
Index: branches/5.3.x/units/products/products_tag_processor.php
===================================================================
--- branches/5.3.x/units/products/products_tag_processor.php	(revision 15670)
+++ branches/5.3.x/units/products/products_tag_processor.php	(revision 15671)
@@ -1,856 +1,861 @@
 <?php
 /**
 * @version	$Id$
 * @package	In-Commerce
 * @copyright	Copyright (C) 1997 - 2009 Intechnic. All rights reserved.
 * @license	Commercial License
 * This software is protected by copyright law and international treaties.
 * Unauthorized reproduction or unlicensed usage of the code of this program,
 * or any portion of it may result in severe civil and criminal penalties,
 * and will be prosecuted to the maximum extent possible under the law
 * See http://www.in-portal.org/commercial-license for copyright notices and details.
 */
 
 defined('FULL_PATH') or die('restricted access!');
 
 class ProductsTagProcessor extends kCatDBTagProcessor {
 
 	function Rating($params)
 	{
 		$object = $this->getObject($params);
 		$rating = round($object->GetDBField('CachedRating') );
 
 		$o = '';
 		for ($i = 0; $i < $rating; $i++) {
 			$o .= $this->Application->ParseBlock( Array('name' => $this->SelectParam($params, 'star_on_render_as,block_star_on')) );
 		}
 
 		for ($i = 0; $i < 5 - $rating; $i++) {
 			$o .= $this->Application->ParseBlock( Array('name' => $this->SelectParam($params, 'star_off_render_as,block_star_off')) );
 		}
 
 		return $o;
 	}
 
 	function NewMark($params)
 	{
 		$object = $this->getObject($params);
 		$o = '';
 		if($object->GetDBField('IsNew'))
 		{
 			$o .= $this->Application->ParseBlock( Array('name' => $this->SelectParam($params, 'render_as,block')) );
 		}
 		return $o;
 	}
 
 	function HotMark($params)
 	{
 		$object = $this->getObject($params);
 		$o = '';
 		if($object->GetDBField('IsHot'))
 		{
 			$o .= $this->Application->ParseBlock( Array('name' => $this->SelectParam($params, 'render_as,block')) );
 		}
 		return $o;
 	}
 
 	function TopSellerMark($params)
 	{
 		return $this->HotMark($params);
 	}
 
 	function PopMark($params)
 	{
 		$object = $this->getObject($params);
 		$o = '';
 		if($object->GetDBField('IsPop'))
 		{
 			$o .= $this->Application->ParseBlock( Array('name' => $this->SelectParam($params, 'render_as,block')) );
 		}
 		return $o;
 	}
 
 	function EdPickMark($params)
 	{
 		$object = $this->getObject($params);
 		$o = '';
 		if($object->GetDBField('EditorsPick'))
 		{
 			$o .= $this->Application->ParseBlock( Array('name' => $this->SelectParam($params, 'render_as,block')) );
 		}
 		return $o;
 	}
 
 	/**
 	 * Parses block only if item is favorite
 	 *
 	 * @param Array $params
 	 * @return string
 	 * @deprecated used only in default,onlinestore
 	 */
 	function FavoriteMark($params)
 	{
 		if ($this->IsFavorite($params)) {
 			return $this->Application->ParseBlock( Array( 'name' => $this->SelectParam($params, 'render_as,block') ) );
 		}
 
 		return '';
 	}
 
 	function CurrentCategory($params)
 	{
 		$sql = "SELECT Name
 				FROM " . TABLE_PREFIX . "Categories
 				WHERE CategoryId=" . $this->Application->GetVar("m_cat_id");
 
 		return $this->Conn->GetOne($sql);
 	}
 
 	function RateForm($params)
 	{
 		$params['name'] = $this->SelectParam($params, 'render_as,block');
 		$labels = explode(',', $params['labels']);
 		$o = '';
 		$star_block = $this->SelectParam($params, 'star_render_as,star_block');
 		for($i = 5; $i >= 0; $i--)
 		{
 			$params['rating'] = $i;
 			$params['label'] = $this->Application->Phrase($labels[5 - $i]);
 			$params['stars'] = '';
 			for($j = $i; $j > 0; $j--)
 			{
 				$params['stars'] .= $this->Application->ParseBlock(Array('name' => $star_block));
 			}
 			$o .= $this->Application->ParseBlock($params);
 		}
 		return $o;
 	}
 
 	/**
 	 * Parses block for changing favorite status
 	 *
 	 * @param Array $params
 	 * @return string
 	 * @deprecated used only in default,onlinestore
 	 */
 	function FavoriteToggle($params)
 	{
 		$block_params = Array ();
 		$block_names = $this->IsFavorite($params) ? 'remove_favorite_render_as,block_remove_favorite' : 'add_favorite_render_as,block_add_favorite';
 		$block_params['name'] = $this->SelectParam($params, $block_names);
 		$params['template'] = $params[$this->IsFavorite($params) ? 'template_on_remove' : 'template_on_add'];
 
 		$remove_params = Array (
 			'remove_favorite_render_as', 'block_remove_favorite', 'add_to_wish_list_render_as', 'block_add_to_wish_list',
 			'add_favorite_render_as', 'block_add_favorite', 'remove_from_wish_list_render_as', 'block_remove_from_wish_list',
 			'template_on_remove', 'template_on_add'
 		);
 
 		foreach ($params as $param_name => $param_value) {
 			if (in_array($param_name, $remove_params)) {
 				unset($params[$param_name]);
 			}
 		}
 
 		$block_params['wish_list_toggle_link'] = $this->FavoriteToggleLink($params);
 		return $this->Application->ParseBlock($block_params);
 	}
 
 	function WishListToggleLink($params)
 	{
 		$params['block_add_favorite'] = $this->SelectParam($params, 'add_to_wish_list_render_as,block_add_to_wish_list');
 		$params['block_remove_favorite'] = $this->SelectParam($params, 'remove_from_wish_list_render_as,block_remove_from_wish_list');
 
 		return $this->FavoriteToggle($params);
 	}
 
 	function AddReviewLink($params)
 	{
 		$o = $this->Application->ParseBlock( Array('name' => $this->SelectParam($params, 'render_as,block')) );
 		return $o;
 	}
 
 	function ListProducts($params)
 	{
 		return $this->PrintList2($params);
 	}
 
 	function ListRelatedProducts($params)
 	{
-//		$related = &$this->Application->recallObject('rel');
+//		$related = $this->Application->recallObject('rel');
+
 		return $this->PrintList2($params);
 	}
 
 	function BuildListSpecial($params)
 	{
 		if ($this->Special != '') return $this->Special;
 		if ( isset($params['parent_cat_id']) ) {
 			$parent_cat_id = $params['parent_cat_id'];
 		}
 		else {
 			$parent_cat_id = $this->Application->GetVar('c_id');
 			if (!$parent_cat_id) {
 				$parent_cat_id = $this->Application->GetVar('m_cat_id');
 			}
 		}
 
 		if ( isset($params['manufacturer']) ) {
 			$manufacturer = $params['manufacturer'];
 		}
 		else {
 			$manufacturer = $this->Application->GetVar('manuf_id');
 		}
 
 		$recursive = isset($params['recursive']);
 
 		$list_unique_key = $this->getUniqueListKey($params).$recursive;
 		if ($list_unique_key == '') {
 			return parent::BuildListSpecial($params);
 		}
 
 		return crc32($parent_cat_id.$list_unique_key.$manufacturer);
 	}
 
 	function ProductList($params)
 	{
 		if($params['shortlist'])
 		{
 			$params['per_page'] = $this->Application->ConfigValue('Comm_Perpage_Products_Short');
 		}
 		$object = $this->Application->recallObject( $this->getPrefixSpecial() , $this->Prefix.'_List', $params );
 
 		switch($params['ListType'])
 		{
 			case 'favorites':
 				return $this->PrintList($params);
 				break;
 			case 'search':
 
 			default:
 				if(isset($params['block']))
 				{
 					return $this->PrintList($params);
 				}
 				else
 				{
 					$params['block'] = $params['block_main'];
 					$params['row_start_block'] = $params['block_row_start'];
 					$params['row_end_block'] = $params['block_row_end'];
 					return $this->PrintList2($params);
 				}
 		}
 	}
 
 	/**
 	 * Adds product to recently viewed list (only in case, when not already there)
 	 *
 	 * @param Array $params
 	 */
 	function AddToRecent($params)
 	{
 		$recent_products = $this->Application->RecallVar('recent_products');
 		if (!$recent_products) {
 			$recent_products = Array();
 		}
 		else {
 			$recent_products = unserialize($recent_products);
 		}
 
 		$product_id = $this->Application->GetVar('p_id');
 		if (!in_array($product_id, $recent_products)) {
 			array_push($recent_products, $product_id);
 			$this->Application->StoreVar('recent_products', serialize($recent_products));
 		}
 	}
 
 	function SearchMoreLink($params)
 	{
 		$object =& $this->GetList($params);
 		$o = '';
 		if($object->GetPerPage() < $this->SearchResultsCount())
 		{
 			$o = $this->Application->ParseBlock( Array('name' => $params['block']) );
 		}
 		return $o;
 	}
 
 	function AddToCartLink($params)
 	{
 		$object = $this->getObject($params);
 
 		if ($object->GetDBField('HasRequiredOptions')) {
 			$t = $params['product_template'];
 			if (!$t) {
 				$theme = $this->Application->recallObject('theme.current');
 				if ($theme->GetDBField('Name') == 'onlinestore') {
 					$t = 'in-commerce/product/details';
 				}
 				elseif ($theme->GetDBField('Name') == 'default') {
 					$t = 'in-commerce/product';
 				}
 			}
 			$link_params = Array('m_cat_id' => $object->GetDBField('CategoryId'), 'pass' => 'm,p');
 		}
 		else {
 			$t = $params['template'];
 			$link_params = Array('m_cat_id' => $object->GetDBField('CategoryId'), 'pass' => 'm,p,ord', 'ord_event' => 'OnAddToCart');
 		}
 
 		$this->Application->SetVar('p_id', $this->Application->GetVar($this->getPrefixSpecial().'_id'));
 		return $this->Application->HREF($t, '', $link_params);
 	}
 
 	function SearchResultsCount($params)
 	{
 		$search_results_table = TABLE_PREFIX.'ses_'.$this->Application->GetSID().'_'.TABLE_PREFIX.'Search';
 		$sql = '	SELECT COUNT(ResourceId)
 					FROM '.$search_results_table.'
 					WHERE ItemType=11';
 		return $this->Conn->GetOne($sql);
 	}
 
 	function DetailsLink($params)
 	{
 		$this->Application->SetVar( $this->Prefix.'_id', $this->Application->GetVar($this->getPrefixSpecial().'_id') );
 		$ret = $this->Application->HREF('in-commerce/details', '', Array('pass' => 'all,p'));
 		return $ret;
 	}
 
 	function ProductLink($params)
 	{
 		return $this->ItemLink($params, 'product');
 	}
 
 	function ProductFileLink($params)
 	{
 		// 'p_id'=>'0',  ??
 		$params = array_merge($params,  Array('pass'=>'all,m,p,file.downl'));
 		$product_id = getArrayValue($params,'product_id');
 		if (!$product_id) {
 			$product_id = $this->Application->GetVar($this->Prefix.'_id');
 		}
 		$params['p_id'] = $product_id;
 
 		$product = $this->Application->recallObject($this->getPrefixSpecial());
 		$params['m_cat_id'] = $product->GetDBField('CategoryId');
 
 		$main_processor = $this->Application->recallObject('m_TagProcessor');
 		return $main_processor->T($params);
 	}
 
 	function GetMarkedVal($params)
 	{
 		$list =& $this->GetList($params);
 
 		return $this->Application->RecallVar($list->getPrefixSpecial().$params['name']);
 	}
 
 	function SortingOptions($params)
 	{
 		$list =& $this->GetList($params);
 
 		$sorting_field_selected = $this->Application->RecallVar($list->getPrefixSpecial() . $params['sorting_select_name']);
 
 		if ( !$sorting_field_selected ) {
 			$sorting_field_selected = $this->Application->ConfigValue('product_OrderProductsBy');
 		}
 
 		$sql = 'SELECT ValueList
 				FROM ' . TABLE_PREFIX . 'SystemSettings
 				WHERE VariableName = "product_OrderProductsBy"';
 		$field_list_plain = $this->Conn->GetOne($sql);
 
 		$field_list = explode(',', $field_list_plain);
 
 		$o = '';
 		$option_params = $this->prepareTagParams($params);
 
 		foreach ($field_list as $field) {
 			list($fieldname, $fieldlabel) = explode('=', $field);
 
 			$option_params['fieldname'] = $fieldname;
 			$option_params['fieldlabel'] = $this->Application->Phrase($fieldlabel);
 			$option_params['name'] = $params['block_options'];
 			$option_params['selected'] = $fieldname == $sorting_field_selected ? 'selected' : '';
 
 			$o .= $this->Application->ParseBlock($option_params);
 		}
 
 		return $o;
 	}
 
 	function SortingDirectionOptions($params)
 	{
 		$list =& $this->GetList($params);
 
 		$sorting_dir_selected = $this->Application->RecallVar($list->getPrefixSpecial() . $params['sorting_select_name']);
 
 		if ( !$sorting_dir_selected ) {
 			$sorting_dir_selected = $this->Application->ConfigValue('product_OrderProductsByDir');
 		}
 
 		$o = '';
 
 		$field_list = array ('asc' => 'lu_Ascending', 'desc' => 'lu_Descending');
 		$option_params = $this->prepareTagParams($params);
 
 		foreach ($field_list as $fieldname => $fieldlabel) {
 			$option_params['fieldname'] = $fieldname;
 			$option_params['fieldlabel'] = $this->Application->Phrase($fieldlabel);
 			$option_params['name'] = $params['block_options'];
 			$option_params['selected'] = $fieldname == $sorting_dir_selected ? 'selected' : '';
 
 			$o .= $this->Application->ParseBlock($option_params);
 		}
 
 		return $o;
 	}
 
 	function ErrorMessage($params)
 	{
 		if( $this->Application->GetVar('keywords_too_short') )
 		{
 			$ret = $this->Application->ParseBlock(Array('name' => $this->SelectParam($params, 'keywords_too_short_render_as,block_keywords_too_short')));
 		}
 		elseif( $this->Application->GetVar('adv_search_error') )
 		{
 			$ret = $this->Application->ParseBlock(Array('name' => $this->SelectParam($params, 'adv_search_error_render_as,block_adv_search_error')));
 		}
 		else
 		{
 			$ret = $this->Application->ParseBlock(Array('name' => $this->SelectParam($params, 'no_found_render_as,block_no_found')));
 		}
 		return $ret;
 	}
 
 	function ListReviews($params)
 	{
 		$review_tag_processor = $this->Application->recallObject('rev.product_TagProcessor');
 		return $review_tag_processor->PrintList($params);
 	}
 
 	function ReviewCount($params)
 	{
 		$review_tag_processor = $this->Application->recallObject('rev.product_TagProcessor');
 		return $review_tag_processor->TotalRecords($params);
 	}
 
 	function InitList($params){
 
 		$passed_manuf_id = $this->Application->GetVar('manuf_id');
 		if ($passed_manuf_id && !isset($params['manufacturer'])){
 			$params['manufacturer'] = $passed_manuf_id;
 		}
 		parent::InitList($params);
 
 	}
 
 	/**
 	 * Builds link to manufacturer page
 	 *
 	 * @param Array $params
 	 * @return string
 	 */
 	function ManufacturerLink($params)
 	{
 		if ( array_key_exists('manufacturer_id', $params) ) {
 			// use direct manufacturer from tag
 			$params['manuf_id'] = $params['manufacturer_id'];
 			unset($params['manufacturer_id']);
 		}
 		else {
 			// use product's manufacturer
 			$object = $this->getObject($params);
 			$item_manufacturer_id = $object->GetDBField('ManufacturerId');
 
 			if ($item_manufacturer_id){
 				$params['manuf_id'] = $item_manufacturer_id;
 			}
 		}
 
 		$params['pass'] = 'm,manuf';
 		$params['m_cat_id'] = 0;
 		return $this->Application->ProcessParsedTag('m', 'Link', $params);
 	}
 
 	function AlreadyReviewed($params)
 	{
 		$rev_tag_processor = $this->Application->recallObject('rev_TagProcessor');
 		return $rev_tag_processor->AlreadyReviewed($params);
 	}
 
 	function PrepareSearchResults($params)
 	{
 		$names_mapping = $this->Application->GetVar('NamesToSpecialMapping', Array ());
 
 		if($this->Application->GetVar('search_type') == 'advanced' || !getArrayValue($names_mapping, $this->Prefix, 'search_results'))
 		{
 			$params = Array('list_name'		=>	'search_results',
 							'types'			=>	'search',
 							'parent_cat_id'	=>	'any',
 							'recursive'		=>	'true',
 							'per_page'		=>	'short_list'
 						);
 			$this->InitList($params);
 		}
 		return '';
 	}
 
 	function Available($params)
 	{
 		$object = $this->getObject($params);
 		/* @var $object kDBItem */
 
 		if ( !$object->GetDBField('InventoryStatus') ) {
 			return true;
 		}
 
 		$backordering = $this->Application->ConfigValue('Comm_Enable_Backordering');
 
 		if ( $object->GetDBField('InventoryStatus') == 2 ) {
 			$poc_table = $this->Application->getUnitOption('poc', 'TableName');
 			$sql = 'SELECT SUM(IF(QtyInStock > ' . $object->GetDBField('QtyInStockMin') . ', 1, 0))
 					FROM ' . $poc_table . '
 					WHERE (ProductId = ' . $object->GetID() . ') AND (Availability = 1)';
 			$stock_available = $this->Conn->GetOne($sql) > 0; // at least one option combination present
 		}
 		else {
 			$stock_available = $object->GetDBField('QtyInStock') > $object->GetDBField('QtyInStockMin');
 		}
 
 		$prod_backordering = $object->GetDBField('BackOrder');
 
 		if ( $stock_available ) {
 			return true;
 		}
 
 		// stock is NOT available:
 		if ( !$backordering || $prod_backordering == 0 ) {
 			// if backordering is generaly disabled or disabled for product (Never)
 			return false;
 		}
 
 		// backordering enabled; (auto or always mode)
 		return true;
 	}
 
 	function IsSubscription($params)
 	{
-		$object = &$this->Application->recallObject($this->getPrefixSpecial());
+		$object = $this->getObject($params);
+		/* @var $object kDBItem */
+
 		return ($object->GetDBField('Type') == 2);
 	}
 
 	function IsTangible($params)
 	{
-		$object = &$this->Application->recallObject($this->getPrefixSpecial());
+		$object = $this->getObject($params);
+		/* @var $object kDBItem */
+
 		return ($object->GetDBField('Type') == 1);
 	}
 
 	function HasFiles($params)
 	{
 		$sql = 'SELECT COUNT(FileId) FROM '.$this->Application->getUnitOption('file', 'TableName').'
 				WHERE ProductId = '.$this->Application->GetVar('p_id').' AND Status = 1';
 		return $this->Conn->GetOne($sql) ? 1 : 0;
 	}
 
 	function UniqueFileName($params)
 	{
 		$file_object = $this->Application->recallObject('file.downl');
 		return ($file_object->GetDBField('Name') &&
 				$file_object->GetDBField('Name') != $file_object->GetDBField('FilePath'))
 			? 1 : 0;
 	}
 
 	function FileDownload($params)
 	{
 		$file_id = $this->Application->GetVar('file.downl_id');
 		$product_id =	$file_id ? $this->Conn->GetOne('SELECT ProductId
 														FROM '.$this->Application->getUnitOption('file', 'TableName').'
 														WHERE FileId = '.$file_id) :
 						$this->Application->GetVar($this->getPrefixSpecial().'_id');
 
 		$download_helper_class = $this->Application->getUnitOption($this->Prefix, 'DownloadHelperClass');
 
 		if (!$download_helper_class) {
 			$download_helper_class = 'DownloadHelper';
 		}
 		$download_helper = $this->Application->recallObject($download_helper_class);
 		if (!$download_helper->CheckAccess($file_id, $product_id)) {
 			$this->Application->ApplicationDie('File Access permission check failed!');
 		}
 		$file_info = $download_helper->SendFile($file_id, $product_id);
 		$download_helper->LogDownload($product_id, $file_info);
 
 		define('DBG_SKIP_REPORTING', 1);
 		$this->Application->ApplicationDie();
 	}
 
 	function PictureLink($params)
 	{
 		if (getArrayValue($params, 'picture_list')) {
 			$params['img_id'] = $this->Application->GetVar('img_id');
 			$params['pass'] = 'all,p,img';
 			unset($params['picture_list']);
 		}
 		else {
 			$params['pass'] = 'all,p';
 		}
 		return $this->Application->ProcessParsedTag('m', 'Link', $params);
 	}
 
 	function ShouldListOptions($params)
 	{
 		$object = $this->getObject($params);
 
 		$req_filter = '';
 		if (getArrayValue($params, 'required_only')) {
 			$req_filter = ' AND Required = 1';
 		}
 
 		$query = 'SELECT COUNT(*) FROM '.TABLE_PREFIX.'ProductOptions WHERE ProductId = '.$object->GetID().$req_filter;
 		$res = $this->Conn->GetOne($query);
 		return $res > 0;
 	}
 
 	function CountOptions($params)
 	{
 		$object = $this->getObject($params);
 
 		$query = 'SELECT COUNT(*) FROM '.TABLE_PREFIX.'ProductOptions WHERE ProductId = '.$object->GetID();
 		$res = $this->Conn->GetOne($query);
 
 		$max = $this->SelectParam($params, 'greater');
 		if (!$max) $max = 0;
 
 		return $res > $max;
 	}
 
 	function OptionsUpdateMode($params)
 	{
 		return $this->Application->GetVar('orditems_id') !== false;
 	}
 
 	function OptionsHaveError($params)
 	{
 		return $this->Application->GetVar('opt_error') > 0;
 	}
 
 	function OptionsError($params)
 	{
 		switch ($this->Application->GetVar('opt_error')) {
 			case 1:
 				return $this->Application->Phrase($params['required']);
 			case 2:
 				return $this->Application->Phrase($params['not_available']);
 		}
 	}
 
 	function ListShippingTypes($params)
 	{
 		$quote_engine_collector = $this->Application->recallObject('ShippingQuoteCollector');
 		/* @var $quote_engine_collector ShippingQuoteCollector */
 
 		$types = $quote_engine_collector->GetAvailableShippingTypes();
 
 		$object = $this->getObject($params);
 		$selected = $object->GetDBField('ShippingLimitation');
 		$selected = explode('|', substr($selected, 1, -1));
 
 		$o = '';
 		foreach ($types as $a_type)
 		{
 			$is_selected = in_array($a_type['_Id'], $selected);
 			$continue = $params['mode'] == 'selected' ? !$is_selected : $is_selected;
 			if ($continue) continue;
 			$block_params = $a_type;
 			$block_params['name']	= $params['render_as'];
 			$o .= $this->Application->ParseBlock($block_params);
 		}
 		return $o;
 	}
 
 	function PageLink($params)
 	{
 		$manufacturer_id = $this->Application->GetVar('manuf_id');
 		if ($manufacturer_id) {
 			$params['pass'] = 'm,'.$this->getPrefixSpecial().',manuf';
 		}
 
 		return parent::PageLink($params);
 	}
 
 	/**
 	 * Calculate savings based on price & market price relationship
 	 *
 	 * @param Array $params
 	 * @return int
 	 */
 	function Savings($params)
 	{
 		$object = $this->getObject($params);
 		/* @var $object kDBItem */
 
 		$price = $object->GetDBField('Price');
 		$msrp = $object->GetDBField('MSRP');
 
 		$value = 0;
 		if (isset($params['type']) && ($params['type'] == 'percent')) {
 			if ($msrp > 0) {
 				return 100 - round($price * 100 / $msrp);
 			}
 		}
 		else {
 			if ($msrp > $price) {
 				$value = $msrp - $price;
 			}
 		}
 
 		if (isset($params['currency'])) {
 			$lang = $this->Application->recallObject('lang.current');
 			/* @var $lang LanguagesItem */
 
 			$iso = $this->GetISO($params['currency']);
 			$value = $this->ConvertCurrency($value, $iso);
 			$value = $lang->formatNumber( sprintf('%.2f', $value) );
 			$value = $this->AddCurrencySymbol($value, $iso);
 		}
 
 		return $value;
 	}
 
 	/**
 	 * Hides permission tab, when it's not allowed by configuration settings
 	 *
 	 * @param Array $params
 	 */
 	function ModifyUnitConfig($params)
 	{
 		$edit_tab_presets = $this->Application->getUnitOption($this->Prefix, 'EditTabPresets');
 		$edit_tab_preset = $edit_tab_presets['Default'];
 
 		$object = $this->getObject($params);
 		/* @var $object kDBItem */
 
 		$product_type = $object->GetDBField('Type');
 
 		if ($product_type != PRODUCT_TYPE_TANGIBLE) {
 			unset($edit_tab_preset['inventory']);
 		}
 
 		if ($product_type == PRODUCT_TYPE_SUBSCRIPTION) {
 			unset($edit_tab_preset['options']);
 		}
 		else {
 			unset($edit_tab_preset['access_and_pricing']);
 		}
 
 		if ($product_type != PRODUCT_TYPE_TANGIBLE && $product_type != PRODUCT_TYPE_PACKAGE) {
 			unset($edit_tab_preset['pricing']);
 		}
 		else {
 			unset($edit_tab_preset['pricing2']);
 		}
 
 		if ($product_type != PRODUCT_TYPE_DOWNLOADABLE) {
 			unset($edit_tab_preset['files_and_pricing']);
 		}
 
 		if ($product_type != PRODUCT_TYPE_PACKAGE) {
 			unset($edit_tab_preset['package_content']);
 		}
 
 		$edit_tab_presets['Default'] = $edit_tab_preset;
 		$this->Application->setUnitOption($this->Prefix, 'EditTabPresets', $edit_tab_presets);
 	}
 
 	/**
 	 * Checks, that current product is in compare products list
 	 *
 	 * @param Array $params
 	 * @return string
 	 * @access protected
 	 */
 	protected function InCompare($params)
 	{
 		$object = $this->getObject($params);
 		/* @var $object kDBItem */
 
 		$products = $this->Application->GetVarDirect('compare_products', 'Cookie');
 		$products = $products ? explode('|', $products) : Array ();
 
 		return in_array($object->GetID(), $products);
 	}
 
 	/**
 	 * Checks, that one more product can be added to comparison list
 	 *
 	 * @param Array $params
 	 * @return string
 	 * @access protected
 	 */
 	protected function ComparePossible($params)
 	{
 		$products = $this->Application->GetVarDirect('compare_products', 'Cookie');
 		$products = $products ? explode('|', $products) : Array ();
 
 		return count($products) < $this->Application->ConfigValue('MaxCompareProducts');
 	}
 
 	/**
 	 * Checks if given field is filled for at least one product in comparison page
 	 *
 	 * @param Array $params
 	 * @return string
 	 * @access protected
 	 */
 	protected function HasCompareField($params)
 	{
 		$object =& $this->GetList($params);
 
 		$object->GoFirst();
 		$field = $this->SelectParam($params, 'name,field');
 
 		while ( !$object->EOL() ) {
 			if ( $object->GetField($field) ) {
 				// don't use GetCol, since it fails to process ML fields
 				return true;
 			}
 
 			$object->GoNext();
 		}
 
 		return false;
 	}
 
 	/**
 	 * Builds link to product compare page
 	 *
 	 * @param Array $params
 	 * @return string
 	 * @access protected
 	 */
 	protected function CompareLink($params)
 	{
 		$params['continue'] = urlencode($this->Application->HREF('__default__', '', Array ('pass_category' => 1)));
 
 		return $this->Application->ProcessParsedTag('m', 'Link', $params);
 	}
 
 	/**
 	 * Builds link to continue website browsing from compare products page
 	 *
 	 * @param Array $params
 	 * @return string
 	 * @access protected
 	 */
 	protected function ContinueLink($params)
 	{
 		$url = $this->Application->GetVar('continue');
 
 		if ( isset($params['redirect']) && $params['redirect'] ) {
 			$this->Application->Redirect('external:' . $url);
 		}
 
 		return $url;
 	}
 }
\ No newline at end of file
Index: branches/5.3.x/units/products/products_event_handler.php
===================================================================
--- branches/5.3.x/units/products/products_event_handler.php	(revision 15670)
+++ branches/5.3.x/units/products/products_event_handler.php	(revision 15671)
@@ -1,1593 +1,1595 @@
 <?php
 /**
 * @version	$Id$
 * @package	In-Commerce
 * @copyright	Copyright (C) 1997 - 2009 Intechnic. All rights reserved.
 * @license	Commercial License
 * This software is protected by copyright law and international treaties.
 * Unauthorized reproduction or unlicensed usage of the code of this program,
 * or any portion of it may result in severe civil and criminal penalties,
 * and will be prosecuted to the maximum extent possible under the law
 * See http://www.in-portal.org/commercial-license for copyright notices and details.
 */
 
 defined('FULL_PATH') or die('restricted access!');
 
 class ProductsEventHandler extends kCatDBEventHandler {
 
 	/**
 	 * Allows to override standard permission mapping
 	 *
 	 * @return void
 	 * @access protected
 	 * @see kEventHandler::$permMapping
 	 */
 	protected function mapPermissions()
 	{
 		parent::mapPermissions();
 
 		$permissions = Array(
 			// front
 			'OnCancelAction'		=>	Array('self' => true),
 			'OnRateProduct'			=>	Array('self' => true),
 			'OnClearRecent'			=>	Array('self' => true),
 			'OnRecommendProduct'	=>	Array('self' => true),
 			'OnAddToCompare'		=>	Array('self' => true),
 			'OnRemoveFromCompare'	=>	Array('self' => true),
 			'OnCancelCompare'		=>	Array('self' => true),
 
 			// admin
 			'OnQtyAdd'			=>	Array('self' => 'add|edit'),
 			'OnQtyRemove'		=>	Array('self' => 'add|edit'),
 			'OnQtyOrder'		=>	Array('self' => 'add|edit'),
 			'OnQtyReceiveOrder'	=>	Array('self' => 'add|edit'),
 			'OnQtyCancelOrder'	=>	Array('self' => 'add|edit'),
 		);
 
 		$this->permMapping = array_merge($this->permMapping, $permissions);
 	}
 
 	/**
 	 * Define alternative event processing method names
 	 *
 	 * @return void
 	 * @see kEventHandler::$eventMethods
 	 * @access protected
 	 */
 	protected function mapEvents()
 	{
 		parent::mapEvents();	// ensure auto-adding of approve/decine and so on events
 
 		$product_events = Array (
 			'OnQtyAdd'=>'InventoryAction',
 			'OnQtyRemove'=>'InventoryAction',
 			'OnQtyOrder'=>'InventoryAction',
 			'OnQtyReceiveOrder'=>'InventoryAction',
 			'OnQtyCancelOrder'=>'InventoryAction',
 		);
 
 		$this->eventMethods = array_merge($this->eventMethods, $product_events);
 	}
 
 	/**
 	 * Sets default processing data for subscriptions
 	 *
 	 * @param kEvent $event
 	 * @return void
 	 * @access protected
 	 */
 	protected function OnBeforeItemCreate(kEvent $event)
 	{
 		parent::OnBeforeItemCreate($event);
 
 		$object = $event->getObject();
 		/* @var $object kDBItem */
 
 		$product_approve_events = Array (
 			2 => 'p:OnSubscriptionApprove',
 			4 => 'p:OnDownloadableApprove',
 			5 => 'p:OnPackageApprove'
 		);
 
 		$product_type = $object->GetDBField('Type');
 
 		$type_found = in_array($product_type, array_keys($product_approve_events));
 
 		if ( $type_found && !$object->GetDBField('ProcessingData') ) {
 			$processing_data = Array ('ApproveEvent' => $product_approve_events[$product_type]);
 			$object->SetDBField('ProcessingData', serialize($processing_data));
 		}
 	}
 
 	/**
 	 * Process product count manipulations
 	 *
 	 * @param kEvent $event
 	 * @access private
 	 */
 	function InventoryAction($event)
 	{
 		$object = $event->getObject();
 		/* @var $object kDBItem */
 
 		$field_values = $this->getSubmittedFields($event);
 		$object->SetFieldsFromHash($field_values, $this->getRequestProtectedFields($field_values));
 
 		if ($object->GetDBField('InventoryStatus') == 2) {
 			// inventory by options (use first selected combination in grid)
-			$combination_id = array_shift( array_keys( $this->Application->GetVar('poc_grid') ) );
+			$combinations = $this->Application->GetVar('poc_grid');
+			list ($combination_id, ) = each($combinations);
 		}
 		else {
 			// inventory by product
 			$combination_id = 0;
 		}
 
 		// save id of selected option combination & preselect it in grid
 		$this->Application->SetVar('combination_id', $combination_id);
 
 		$this->ScheduleInventoryAction($event->Name, $object->GetId(), $object->GetDBField('Qty'), $combination_id);
 
 		$object->Validate();
 
 		if ( !$object->GetErrorPseudo('Qty') ){
 			// only update, when no error on that field
 			$this->modifyInventory($event->Name, $object, $object->GetDBField('Qty'), $combination_id);
 		}
 
 		$object->SetDBField('Qty', null);
 		$event->redirect = false;
 	}
 
 	/**
 	 * Perform inventory action on supplied object
 	 *
 	 * @param string $action event name which is actually called by user
 	 * @param ProductsItem $product
 	 * @param int $qty
 	 * @param int $combination_id
 	 */
 	function modifyInventory($action, &$product, $qty, $combination_id)
 	{
 		if ($product->GetDBField('InventoryStatus') == 2) {
 			// save inventory changes to option combination instead of product
 			$object = $this->Application->recallObject('poc.-item', null, Array('skip_autoload' => true));
 			$object->Load($combination_id);
 		}
 		elseif ($combination_id > 0) {
 			// combination id present, but not inventory by combinations => skip
 			return false;
 		}
 		elseif ($product->GetDBField('InventoryStatus') == 1) {
 			// save inventory changes to product
 			$object =& $product;
 		}
 		else {
 			// product has inventory actions, but don't use inventory => skip
 			return false;
 		}
 
 		if (!$object->isLoaded()) {
 			// product/combination in action doesn't exist in database by now
 			return false;
 		}
 
 		switch ($action) {
 			case 'OnQtyAdd':
 				$object->SetDBField('QtyInStock', $object->GetDBField('QtyInStock') + $qty);
 				break;
 
 			case 'OnQtyRemove':
 				if ($object->GetDBField('QtyInStock') < $qty) {
 					$qty = $object->GetDBField('QtyInStock');
 				}
 				$object->SetDBField('QtyInStock', $object->GetDBField('QtyInStock') - $qty);
 				break;
 
 			case 'OnQtyOrder':
 				$object->SetDBField('QtyOnOrder', $object->GetDBField('QtyOnOrder') + $qty);
 				break;
 
 			case 'OnQtyReceiveOrder':
 				$object->SetDBField('QtyOnOrder', $object->GetDBField('QtyOnOrder') - $qty);
 				$object->SetDBField('QtyInStock', $object->GetDBField('QtyInStock') + $qty);
 				break;
 
 			case 'OnQtyCancelOrder':
 				$object->SetDBField('QtyOnOrder', $object->GetDBField('QtyOnOrder') - $qty);
 				break;
 		}
 
 		return $object->Update();
 	}
 
 	function ScheduleInventoryAction($action, $prod_id, $qty, $combination_id = 0)
 	{
 		$inv_actions = $this->Application->RecallVar('inventory_actions');
 		if (!$inv_actions) {
 			$inv_actions = Array();
 		}
 		else {
 			$inv_actions = unserialize($inv_actions);
 		}
 
 		array_push($inv_actions, Array('action' => $action, 'product_id' => $prod_id, 'combination_id' => $combination_id, 'qty' => $qty));
 
 		$this->Application->StoreVar('inventory_actions', serialize($inv_actions));
 	}
 
 	function RealInventoryAction($action, $prod_id, $qty, $combination_id)
 	{
 		$product = $this->Application->recallObject('p.liveitem', null, Array('skip_autoload' => true));
 		$product->SwitchToLive();
 		$product->Load($prod_id);
 
 		$this->modifyInventory($action, $product, $qty, $combination_id);
 	}
 
 	function RunScheduledInventoryActions($event)
 	{
 		$inv_actions = $this->Application->GetVar('inventory_actions');
 		if (!$inv_actions) {
 			return;
 		}
 		$inv_actions = unserialize($inv_actions);
 
 		$products = array();
 		foreach($inv_actions as $an_action) {
 			$this->RealInventoryAction($an_action['action'], $an_action['product_id'], $an_action['qty'], $an_action['combination_id']);
 			array_push($products, $an_action['product_id'].'_'.$an_action['combination_id']);
 		}
 
 		$products = array_unique($products);
 		if ($products) {
 			$product_obj = $this->Application->recallObject('p.liveitem', null, Array('skip_autoload' => true));
 			$product_obj->SwitchToLive();
 			foreach ($products as $product_key) {
 				list($prod_id, $combination_id) = explode('_', $product_key);
 			$product_obj->Load($prod_id);
 				$this->FullfillBackOrders($product_obj, $combination_id);
 			}
 		}
 	}
 
 	/**
 	 * In case if products arrived into inventory and they are required by old (non processed) orders, then use them (products) in that orders
 	 *
 	 * @param ProductsItem $product
 	 * @param int $combination_id
 	 */
 	function FullfillBackOrders(&$product, $combination_id)
 	{
 		if ( !$this->Application->ConfigValue('Comm_Process_Backorders_Auto') ) return;
 
 		if ($combination_id && ($product->GetDBField('InventoryStatus') == 2)) {
 			// if combination id present and inventory by combinations
 			$poc_idfield = $this->Application->getUnitOption('poc', 'IDField');
 			$poc_tablename = $this->Application->getUnitOption('poc', 'TableName');
 			$sql = 'SELECT QtyInStock
 					FROM '.$poc_tablename.'
 					WHERE '.$poc_idfield.' = '.$combination_id;
 			$stock_qty = $this->Conn->GetOne($sql);
 		}
 		else {
 			// inventory by product
 			$stock_qty = $product->GetDBField('QtyInStock');
 		}
 
 		$qty = (int) $stock_qty - $product->GetDBField('QtyInStockMin');
 		$prod_id = $product->GetID();
 		if ($prod_id <= 0 || !$prod_id || $qty <= 0) return;
 
 		//selecting up to $qty backorders with $prod_id where full qty is not reserved
 		$query = 'SELECT '.TABLE_PREFIX.'Orders.OrderId
 							FROM '.TABLE_PREFIX.'OrderItems
 					LEFT JOIN '.TABLE_PREFIX.'Orders ON '.TABLE_PREFIX.'Orders.OrderId = '.TABLE_PREFIX.'OrderItems.OrderId
 					WHERE (ProductId = '.$prod_id.') AND (Quantity > QuantityReserved) AND (Status = '.ORDER_STATUS_BACKORDERS.')
 							GROUP BY '.TABLE_PREFIX.'Orders.OrderId
 							ORDER BY OrderDate ASC
 							LIMIT 0,'.$qty; //assuming 1 item per order - minimum possible
 
 		$orders = $this->Conn->GetCol($query);
 
 		if (!$orders) return;
 
 		$order = $this->Application->recallObject('ord.-inv', null, Array('skip_autoload' => true));
 		foreach ($orders as $ord_id) {
 			$order->Load($ord_id);
 
-			$this->Application->EmailEventAdmin('BACKORDER.FULLFILL');
+			$this->Application->emailAdmin('BACKORDER.FULLFILL');
 
 			//reserve what's possible in any case
 			$event = new kEvent('ord:OnReserveItems');
 			$this->Application->HandleEvent($event);
 
 			if ( $event->status == kEvent::erSUCCESS ) { //
 				//in case the order is ready to process - process it
 				$this->Application->HandleEvent($event, 'ord:OnOrderProcess');
 			}
 		}
 	}
 
 	/**
 	 * Occurs before an item is deleted from live table when copying from temp
 	 * (temp handler deleted all items from live and then copy over all items from temp)
 	 * Id of item being deleted is passed as event' 'id' param
 	 *
 	 * @param kEvent $event
 	 * @return void
 	 * @access protected
 	 */
 	protected function OnBeforeDeleteFromLive(kEvent $event)
 	{
 		parent::OnBeforeDeleteFromLive($event);
 
 		$product = $this->Application->recallObject($event->Prefix . '.itemlive', null, Array ('skip_autoload' => true));
 		/* @var $product kCatDBItem */
 
 		$product->SwitchToLive();
 		$id = $event->getEventParam('id');
 
 		if ( !$product->Load($id) ) {
 			// this will make sure New product will not be overwritten with empty data
 			return ;
 		}
 
 		$temp = $this->Application->recallObject($event->Prefix . '.itemtemp', null, Array ('skip_autoload' => true));
 		/* @var $temp kCatDBItem */
 
 		$temp->SwitchToTemp();
 		$temp->Load($id);
 
 		$temp->SetDBFieldsFromHash($product->GetFieldValues(), null, Array ('QtyInStock', 'QtyReserved', 'QtyBackOrdered', 'QtyOnOrder'));
 		$temp->Update();
 	}
 
 	/**
 	 * Removes any information about current/selected ids
 	 * from Application variables and Session
 	 *
 	 * @param kEvent $event
 	 * @return void
 	 * @access protected
 	 */
 	protected function clearSelectedIDs(kEvent $event)
 	{
 		parent::clearSelectedIDs($event);
 
 		$this->Application->SetVar('inventory_actions', $this->Application->RecallVar('inventory_actions'));
 		$this->Application->RemoveVar('inventory_actions');
 	}
 
 	/**
 	 * Saves content of temp table into live and
 	 * redirects to event' default redirect (normally grid template)
 	 *
 	 * @param kEvent $event
 	 * @return void
 	 * @access protected
 	 */
 	protected function OnSave(kEvent $event)
 	{
 		parent::OnSave($event);
 
 		if ( $event->status == kEvent::erSUCCESS ) {
 			$this->RunScheduledInventoryActions($event);
 		}
 	}
 
 	/**
 	 * Prepare temp tables for creating new item
 	 * but does not create it. Actual create is
 	 * done in OnPreSaveCreated
 	 *
 	 * @param kEvent $event
 	 * @return void
 	 * @access protected
 	 */
 	protected function OnPreCreate(kEvent $event)
 	{
 		parent::onPreCreate($event);
 
 		$object = $event->getObject();
 		/* @var $object kDBItem */
 
 		$object->SetDBField('Type', $this->Application->GetVar($event->getPrefixSpecial(true) . '_new_type'));
 	}
 
 	/**
 	 * Saves edited item in temp table and loads
 	 * item with passed id in current template
 	 * Used in Prev/Next buttons
 	 *
 	 * @param kEvent $event
 	 * @return void
 	 * @access protected
 	 */
 	protected function OnPreSaveAndGo(kEvent $event)
 	{
 		$event->CallSubEvent('OnPreSave');
 		$this->LoadItem($event);
 
 		$object = $event->getObject();
 		/* @var $object kDBItem */
 
 		$from_type = $object->GetDBField('Type');
 		if ( $event->status == kEvent::erSUCCESS ) {
 			$this->Application->SetVar($event->getPrefixSpecial() . '_id', $this->Application->GetVar($event->getPrefixSpecial(true) . '_GoId'));
 			$this->LoadItem($event);
 			$to_type = $object->GetDBField('Type');
 
 			if ( $from_type != $to_type ) {
 				$from_tabs = $this->GetTabs($from_type);
 				$from_tab_i = array_search($this->Application->GetVar('t'), $from_tabs);
 
 				$to_tabs = $this->GetTabs($to_type);
 				$to_tab = $this->Application->GetVar('t');
 
 				$found = false;
 				while (!isset($to_tabs[$from_tab_i]) && $from_tab_i < count($to_tabs)) {
 					$from_tab_i++;
 				}
 
 				if ( !isset($to_tabs[$from_tab_i]) ) {
 					$from_tab_i = 0;
 				}
 
 				$to_tab = $to_tabs[$from_tab_i];
 
 				$event->redirect = $to_tab;
 			}
 		}
 	}
 
 	function GetTabs($type)
 	{
 		switch($type)
 		{
 			case 1:
 				return Array(
 					0 => 'in-commerce/products/products_edit',
 					1 => 'in-commerce/products/products_inventory',
 					2 => 'in-commerce/products/products_pricing',
 					3 => 'in-commerce/products/products_categories',
 					4 => 'in-commerce/products/products_images',
 					5 => 'in-commerce/products/products_reviews',
 					6 => 'in-commerce/products/products_custom',
 				);
 
 			case 2:
 				return Array(
 					0 => 'in-commerce/products/products_edit',
 					1 => 'in-commerce/products/products_access',
 					/*2 => 'in-commerce/products/products_access_pricing',*/
 					3 => 'in-commerce/products/products_categories',
 					4 => 'in-commerce/products/products_images',
 					5 => 'in-commerce/products/products_reviews',
 					6 => 'in-commerce/products/products_custom',
 				);
 
 			case 3:
 				return Array(
 					0 => 'in-commerce/products/products_edit',
 
 					2 => 'in-commerce/products/products_access_pricing',
 					3 => 'in-commerce/products/products_categories',
 					4 => 'in-commerce/products/products_images',
 					5 => 'in-commerce/products/products_reviews',
 					6 => 'in-commerce/products/products_custom',
 				);
 
 			case 4:
 				return Array(
 					0 => 'in-commerce/products/products_edit',
 
 					2 => 'in-commerce/products/products_files',
 					3 => 'in-commerce/products/products_categories',
 					4 => 'in-commerce/products/products_images',
 					5 => 'in-commerce/products/products_reviews',
 					6 => 'in-commerce/products/products_custom',
 				);
 		}
 	}
 
 	/**
 	 * Return type clauses for list bulding on front
 	 *
 	 * @param kEvent $event
 	 * @return Array
 	 */
 	function getTypeClauses($event)
 	{
 		$types = $event->getEventParam('types');
 		$types = $types ? explode(',', $types) : Array ();
 
 		$except_types = $event->getEventParam('except');
 		$except_types = $except_types ? explode(',', $except_types) : Array ();
 
 		$object = $event->getObject();
 		/* @var $object kDBList */
 
 		$type_clauses = parent::getTypeClauses($event);
 
 		$type_clauses['featured']['include'] = '%1$s.Featured = 1 AND ' . TABLE_PREFIX . 'CategoryItems.PrimaryCat = 1';
 		$type_clauses['featured']['except'] = '%1$s.Featured != 1 AND ' . TABLE_PREFIX . 'CategoryItems.PrimaryCat = 1';
 		$type_clauses['featured']['having_filter'] = false;
 
 		$type_clauses['onsale']['include'] = '%1$s.OnSale = 1 AND ' . TABLE_PREFIX . 'CategoryItems.PrimaryCat = 1';
 		$type_clauses['onsale']['except'] = '%1$s.OnSale != 1 AND ' . TABLE_PREFIX . 'CategoryItems.PrimaryCat = 1';
 		$type_clauses['onsale']['having_filter'] = false;
 
 		// products from selected manufacturer: begin
 		$manufacturer = $event->getEventParam('manufacturer');
 		if ( !$manufacturer ) {
 			$manufacturer = $this->Application->GetVar('manuf_id');
 		}
 
 		if ( $manufacturer ) {
 			$type_clauses['manufacturer']['include'] = '%1$s.ManufacturerId = ' . $manufacturer . ' AND PrimaryCat = 1';
 			$type_clauses['manufacturer']['except'] = '%1$s.ManufacturerId != ' . $manufacturer . ' AND PrimaryCat = 1';
 			$type_clauses['manufacturer']['having_filter'] = false;
 		}
 		// products from selected manufacturer: end
 
 		// recent products: begin
 		$recent = $this->Application->RecallVar('recent_products');
 		if ( $recent ) {
 			$recent = unserialize($recent);
 			$type_clauses['recent']['include'] = '%1$s.ProductId IN (' . implode(',', $recent) . ') AND PrimaryCat = 1';
 			$type_clauses['recent']['except'] = '%1$s.ProductId NOT IN (' . implode(',', $recent) . ') AND PrimaryCat = 1';
 		}
 		else {
 			$type_clauses['recent']['include'] = '0';
 			$type_clauses['recent']['except'] = '1';
 		}
 		$type_clauses['recent']['having_filter'] = false;
 		// recent products: end
 
 		// compare products: begin
 		if ( in_array('compare', $types) || in_array('compare', $except_types) ) {
 			$compare_products = $this->getCompareProducts();
 
 			if ( $compare_products ) {
 				$compare_products = $this->Conn->qstrArray($compare_products);
 				$type_clauses['compare']['include'] = '%1$s.ProductId IN (' . implode(',', $compare_products) . ') AND PrimaryCat = 1';
 				$type_clauses['compare']['except'] = '%1$s.ProductId NOT IN (' . implode(',', $compare_products) . ') AND PrimaryCat = 1';
 			}
 			else {
 				$type_clauses['compare']['include'] = '0';
 				$type_clauses['compare']['except'] = '1';
 			}
 
 			$type_clauses['compare']['having_filter'] = false;
 
 			if ( $event->getEventParam('per_page') === false ) {
 				$event->setEventParam('per_page', $this->Application->ConfigValue('MaxCompareProducts'));
 			}
 		}
 		// compare products: end
 
 		// products already in shopping cart: begin
 		if ( in_array('in_cart', $types) || in_array('in_cart', $except_types) ) {
 			$order_id = $this->Application->RecallVar('ord_id');
 
 			if ( $order_id ) {
 				$sql = 'SELECT ProductId
 						FROM ' . TABLE_PREFIX . 'OrderItems
 						WHERE OrderId = ' . $order_id;
 				$in_cart = $this->Conn->GetCol($sql);
 
 				if ( $in_cart ) {
 					$type_clauses['in_cart']['include'] = '%1$s.ProductId IN (' . implode(',', $in_cart) . ') AND PrimaryCat = 1';
 					$type_clauses['in_cart']['except'] = '%1$s.ProductId NOT IN (' . implode(',', $in_cart) . ') AND PrimaryCat = 1';
 				}
 				else {
 					$type_clauses['in_cart']['include'] = '0';
 					$type_clauses['in_cart']['except'] = '1';
 				}
 			}
 			else {
 				$type_clauses['in_cart']['include'] = '0';
 				$type_clauses['in_cart']['except'] = '1';
 			}
 
 			$type_clauses['in_cart']['having_filter'] = false;
 		}
 		// products already in shopping cart: end
 
 		// my downloadable products: begin
 		if ( in_array('my_downloads', $types) || in_array('my_downloads', $except_types) ) {
 			$user_id = $this->Application->RecallVar('user_id');
 
 			$sql = 'SELECT ProductId
 					FROM ' . TABLE_PREFIX . 'UserFileAccess
 					WHERE PortalUserId = ' . $user_id;
 			$my_downloads = $user_id > 0 ? $this->Conn->GetCol($sql) : false;
 
 			if ( $my_downloads ) {
 				$type_clauses['my_downloads']['include'] = '%1$s.ProductId IN (' . implode(',', $my_downloads) . ') AND PrimaryCat = 1';
 				$type_clauses['my_downloads']['except'] = '%1$s.ProductId NOT IN (' . implode(',', $my_downloads) . ') AND PrimaryCat = 1';
 			}
 			else {
 				$type_clauses['my_downloads']['include'] = '0';
 				$type_clauses['my_downloads']['except'] = '1';
 			}
 
 			$type_clauses['my_downloads']['having_filter'] = false;
 		}
 		// my downloadable products: end
 
 		// my favorite products: begin
 		if ( in_array('wish_list', $types) || in_array('wish_list', $except_types) ) {
 			$sql = 'SELECT ResourceId
 					FROM ' . $this->Application->getUnitOption('fav', 'TableName') . '
 					WHERE PortalUserId = ' . (int)$this->Application->RecallVar('user_id');
 			$wishlist_ids = $this->Conn->GetCol($sql);
 
 			if ( $wishlist_ids ) {
 				$type_clauses['wish_list']['include'] = '%1$s.ResourceId IN (' . implode(',', $wishlist_ids) . ') AND PrimaryCat = 1';
 				$type_clauses['wish_list']['except'] = '%1$s.ResourceId NOT IN (' . implode(',', $wishlist_ids) . ') AND PrimaryCat = 1';
 			}
 			else {
 				$type_clauses['wish_list']['include'] = '0';
 				$type_clauses['wish_list']['except'] = '1';
 			}
 
 			$type_clauses['wish_list']['having_filter'] = false;
 		}
 		// my favorite products: end
 
 		// products from package: begin
 		if ( in_array('content', $types) || in_array('content', $except_types) ) {
 			$object->removeFilter('category_filter');
 			$object->AddGroupByField('%1$s.ProductId');
 
 			$object_product = $this->Application->recallObject($event->Prefix);
 			/* @var $object_product ProductsItem */
 
 			$content_ids_array = $object_product->GetPackageContentIds();
 
 			if ( sizeof($content_ids_array) == 0 ) {
 				$content_ids_array = array ('-1');
 			}
 
 			if ( sizeof($content_ids_array) > 0 ) {
 				$type_clauses['content']['include'] = '%1$s.ProductId IN (' . implode(',', $content_ids_array) . ')';
 			}
 			else {
 				$type_clauses['content']['include'] = '0';
 			}
 
 			$type_clauses['related']['having_filter'] = false;
 		}
 		// products from package: end
 
 		$object->addFilter('not_virtual', '%1$s.Virtual = 0');
 
 		if ( !$this->Application->isAdminUser ) {
 			$object->addFilter('expire_filter', '%1$s.Expire IS NULL OR %1$s.Expire > ' . adodb_mktime());
 		}
 
 		return $type_clauses;
 	}
 
 	function OnClearRecent($event)
 	{
 		$this->Application->RemoveVar('recent_products');
 	}
 
 	/**
 	 * Occurs, when user rates a product
 	 *
 	 * @param kEvent $event
 	 */
 	function OnRateProduct($event)
 	{
 		$event->SetRedirectParam('pass', 'all,p');
 		$event->redirect = $this->Application->GetVar('success_template');
 
 		$object = $event->getObject();
 		/* @var $object kDBItem */
 
 		$user_id = $this->Application->RecallVar('user_id');
 
 		$sql = '	SELECT * FROM ' . TABLE_PREFIX . 'SpamControl
 					WHERE ItemResourceId=' . $object->GetDBField('ResourceId') . '
-					AND IPaddress="' . $_SERVER['REMOTE_ADDR'] . '"
+					AND IPaddress="' . $this->Application->getClientIp() . '"
 					AND PortalUserId=' . $user_id . '
 					AND DataType="Rating"';
 		$res = $this->Conn->GetRow($sql);
 
 		if ( $res && $res['Expire'] < adodb_mktime() ) {
 			$sql = '	DELETE FROM ' . TABLE_PREFIX . 'SpamControl
 						WHERE ItemResourceId=' . $object->GetDBField('ResourceId') . '
-						AND IPaddress="' . $_SERVER['REMOTE_ADDR'] . '"
+						AND IPaddress="' . $this->Application->getClientIp() . '"
 						AND PortalUserId=' . $user_id . '
 						AND DataType="Rating"';
 			$this->Conn->Query($sql);
 			unset($res);
 		}
 
 		$new_rating = $this->Application->GetVar('rating');
 
 		if ( $new_rating !== false && !$res ) {
 			$rating = $object->GetDBField('CachedRating');
 			$votes = $object->GetDBField('CachedVotesQty');
 			$new_votes = $votes + 1;
 
 			$rating = (($rating * $votes) + $new_rating) / $new_votes;
 			$object->SetDBField('CachedRating', $rating);
 			$object->SetDBField('CachedVotesQty', $new_votes);
 			$object->Update();
 
 			$expire = adodb_mktime() + $this->Application->ConfigValue('product_ReviewDelay_Value') * $this->Application->ConfigValue('product_ReviewDelay_Interval');
 			$sql = '	INSERT INTO ' . TABLE_PREFIX . 'SpamControl
 							(ItemResourceId, IPaddress, PortalUserId, DataType, Expire)
 						VALUES (' . $object->GetDBField('ResourceId') . ',
-								"' . $_SERVER['REMOTE_ADDR'] . '",
+								"' . $this->Application->getClientIp() . '",
 								' . $user_id . ',
 								"Rating",
 								' . $expire . ')';
 			$this->Conn->Query($sql);
 		}
 		else {
 			$event->status == kEvent::erFAIL;
 			$event->redirect = false;
 			$object->SetError('CachedRating', 'too_frequent', 'lu_ferror_rate_duplicate');
 		}
 	}
 
 	/**
 	 * Enter description here...
 	 *
 	 * @param kEvent $event
 	 */
 	function OnCancelAction($event)
 	{
 		$event->SetRedirectParam('pass', 'all,p');
 		$event->redirect = $this->Application->GetVar('cancel_template');
 	}
 
 	/**
 	 * Enter description here...
 	 *
 	 * @param kEvent $event
 	 */
 	function OnRecommendProduct($event)
 	{
 		// used for error reporting only -> rewrite code + theme (by Alex)
 		$object = $this->Application->recallObject('u', null, Array('skip_autoload' => true)); // TODO: change theme too
 		/* @var $object kDBItem */
 
 		$friend_email = $this->Application->GetVar('friend_email');
 		$friend_name = $this->Application->GetVar('friend_name');
 		$my_email = $this->Application->GetVar('your_email');
 		$my_name = $this->Application->GetVar('your_name');
 		$my_message = $this->Application->GetVar('your_message');
 
 		$send_params = array();
 		$send_params['to_email']=$friend_email;
 		$send_params['to_name']=$friend_name;
 		$send_params['from_email']=$my_email;
 		$send_params['from_name']=$my_name;
 		$send_params['message']=$my_message;
 
 		if ( preg_match('/' . REGEX_EMAIL_USER . '@' . REGEX_EMAIL_DOMAIN . '/', $friend_email) ) {
 			$user_id = $this->Application->RecallVar('user_id');
-			$email_sent = $this->Application->EmailEventUser('PRODUCT.SUGGEST', $user_id, $send_params);
-			$this->Application->EmailEventAdmin('PRODUCT.SUGGEST');
+			$email_sent = $this->Application->emailUser('PRODUCT.SUGGEST', $user_id, $send_params);
+			$this->Application->emailAdmin('PRODUCT.SUGGEST');
 
 			if ( $email_sent ) {
 				$event->setRedirectParams(Array ('opener' => 's', 'pass' => 'all'));
 				$event->redirect = $this->Application->GetVar('template_success');
 			}
 			else {
 //				$event->setRedirectParams(Array('opener' => 's', 'pass' => 'all'));
 //				$event->redirect = $this->Application->GetVar('template_fail');
 
 				$object->SetError('Email', 'send_error', 'lu_email_send_error');
 				$event->status = kEvent::erFAIL;
 			}
 		}
 		else {
 			$object->SetError('Email', 'invalid_email', 'lu_InvalidEmail');
 			$event->status = kEvent::erFAIL;
 		}
 	}
 
 	/**
 	 * Creates/updates virtual product based on listing type data
 	 *
 	 * @param kEvent $event
 	 */
 	function OnSaveVirtualProduct($event)
 	{
 		$object = $event->getObject( Array('skip_autoload' => true) );
 		$listing_type = $this->Application->recallObject('lst', null, Array('skip_autoload' => true));
 		$listing_type->Load($event->MasterEvent->getEventParam('id'));
 
 		$product_id = $listing_type->GetDBField('VirtualProductId');
 
 		if ($product_id) {
 			$object->Load($product_id);
 		}
 
 		if (!$listing_type->GetDBField('EnableBuying')) {
 			if ($product_id) {
 				// delete virtual product here
 				$temp_handler = $this->Application->recallObject($event->getPrefixSpecial().'_TempHandler', 'kTempTablesHandler');
 				$temp_handler->DeleteItems($event->Prefix, $event->Special, Array($product_id));
 
 				$listing_type->SetDBField('VirtualProductId', 0);
 				$listing_type->Update();
 			}
 			return true;
 		}
 
 		$ml_formatter = $this->Application->recallObject('kMultiLanguage');
 		$object->SetDBField($ml_formatter->LangFieldName('Name'), $listing_type->GetDBField('ShopCartName') );
 		$object->SetDBField($ml_formatter->LangFieldName('Description'), $listing_type->GetDBField('Description'));
 		$object->SetDBField('SKU', 'ENHANCE_LINK_'.abs( crc32( $listing_type->GetDBField('Name') ) ) );
 
 		if ($product_id) {
 			$object->Update();
 		}
 		else {
 			$object->SetDBField('Type', 2);
 			$object->SetDBField('Status', 1);
 			$object->SetDBField('HotItem', 0);
 			$object->SetDBField('PopItem', 0);
 			$object->SetDBField('NewItem', 0);
 			$object->SetDBField('Virtual', 1);
 
 //			$processing_data = Array('ApproveEvent' => 'ls:EnhanceLinkAfterOrderApprove', 'ExpireEvent' => 'ls:ExpireLink');
 			$processing_data = Array(	'ApproveEvent'			=>	'ls:EnhanceLinkAfterOrderApprove',
 										'DenyEvent'				=>	'ls:EnhanceLinkAfterOrderDeny',
 										'CompleteOrderEvent'	=>	'ls:EnhancedLinkOnCompleteOrder',
 										'ExpireEvent'			=>	'ls:ExpireLink',
 										'HasNewProcessing'		=>	1);
 			$object->SetDBField('ProcessingData', serialize($processing_data));
 			$object->Create();
 
 			$listing_type->SetDBField('VirtualProductId', $object->GetID());
 			$listing_type->Update();
 		}
 
 		$additiona_fields = Array(	'AccessDuration'	=>	$listing_type->GetDBField('Duration'),
 									'AccessUnit'		=>	$listing_type->GetDBField('DurationType'),
 							);
 		$this->setPrimaryPrice($object->GetID(), (double)$listing_type->GetDBField('Price'), $additiona_fields);
 	}
 
 	/**
 	 * [HOOK] Deletes virtual product when listing type is deleted
 	 *
 	 * @param kEvent $event
 	 */
 	function OnDeleteListingType($event)
 	{
 		$listing_type = $event->MasterEvent->getObject();
 		/* @var $listing_type kDBItem */
 
 		$product_id = $listing_type->GetDBField('VirtualProductId');
 
 		if ( $product_id ) {
 			$temp_handler = $this->Application->recallObject($event->getPrefixSpecial() . '_TempHandler', 'kTempTablesHandler');
 			$temp_handler->DeleteItems($event->Prefix, $event->Special, Array ($product_id));
 		}
 	}
 
 	/**
 	 * Extends user membership in group when his order is approved
 	 *
 	 * @param kEvent $event
 	 */
 	function OnSubscriptionApprove($event)
 	{
 		$field_values = $event->getEventParam('field_values');
 		$item_data = unserialize($field_values['ItemData']);
 
 		if ( !getArrayValue($item_data,'PortalGroupId') ) {
 			// is subscription product, but no group defined in it's properties
 			trigger_error('Invalid product <b>'.$field_values['ProductName'].'</b> (id: '.$field_values['ProductId'].')', E_USER_WARNING);
 			return false;
 		}
 
 		$sql = 'SELECT PortalUserId
 				FROM ' . $this->Application->getUnitOption('ord', 'TableName') . '
 				WHERE ' . $this->Application->getUnitOption('ord', 'IDField') . ' = ' . $field_values['OrderId'];
 		$user_id = $this->Conn->GetOne($sql);
 
 		$group_id = $item_data['PortalGroupId'];
 		$duration = $item_data['Duration'];
 
 		$sql = 'SELECT *
 				FROM ' . TABLE_PREFIX . 'UserGroupRelations
 				WHERE PortalUserId = ' . $user_id;
 		$user_groups = $this->Conn->Query($sql, 'GroupId');
 
 		if ( !isset($user_groups[$group_id]) ) {
 			$expire = adodb_mktime() + $duration;
 		}
 		else {
 			$expire = $user_groups[$group_id]['MembershipExpires'];
 			$expire = $expire < adodb_mktime() ? adodb_mktime() + $duration : $expire + $duration;
 		}
 
 		/*// Customization healtheconomics.org
 		if ($item_data['DurationType'] == 2) {
 			$expire = $item_data['AccessExpiration'];
 		}
 		// Customization healtheconomics.org --*/
 
 		$fields_hash = Array (
 			'PortalUserId' => $user_id,
 			'GroupId' => $group_id,
 			'MembershipExpires' => $expire,
 		);
 
 		$this->Conn->doInsert($fields_hash, TABLE_PREFIX . 'UserGroupRelations', 'REPLACE');
 
 		$sub_order = $this->Application->recallObject('ord.-sub'.$event->getEventParam('next_sub_number'), 'ord');
 		$sub_order->SetDBField('IsRecurringBilling', getArrayValue($item_data, 'IsRecurringBilling') ? 1 : 0);
 		$sub_order->SetDBField('GroupId', $group_id);
 		$sub_order->SetDBField('NextCharge_date', $expire);
 		$sub_order->SetDBField('NextCharge_time', $expire);
 	}
 
 	function OnDownloadableApprove($event)
 	{
 		$field_values = $event->getEventParam('field_values');
 		$product_id = $field_values['ProductId'];
 		$sql = 'SELECT PortalUserId FROM '.$this->Application->getUnitOption('ord', 'TableName').'
 				WHERE OrderId = '.$field_values['OrderId'];
 		$user_id = $this->Conn->GetOne($sql);
 		$sql = 'INSERT INTO '.TABLE_PREFIX.'UserFileAccess VALUES("", '.$product_id.', '.$user_id.')';
 		$this->Conn->Query($sql);
 	}
 
-	function OnPackageApprove($event){
+	protected function OnPackageApprove(kEvent $event)
+	{
 		$field_values = $event->getEventParam('field_values');
 		$item_data = unserialize($field_values['ItemData']);
 		$package_content_ids = $item_data['PackageContent'];
 
+		$object_item = $this->Application->recallObject('p.packageitem', null, array ('skip_autoload' => true));
+		/* @var $object_item ProductsItem */
 
-
-		$object_item = &$this->Application->recallObject('p.packageitem', null, array('skip_autoload'=>true));
 		foreach ($package_content_ids as $package_item_id) {
-			$object_field_values = array();
-					// query processing data from product and run approve event
-			$sql = 'SELECT ProcessingData FROM '.TABLE_PREFIX.'Products WHERE ProductId = '.$package_item_id;
+			$object_field_values = array ();
+
+			// query processing data from product and run approve event
+			$sql = 'SELECT ProcessingData
+					FROM ' . TABLE_PREFIX . 'Products
+					WHERE ProductId = ' . $package_item_id;
 			$processing_data = $this->Conn->GetOne($sql);
-			if($processing_data)
-			{
+
+			if ( $processing_data ) {
 				$processing_data = unserialize($processing_data);
 				$approve_event = new kEvent($processing_data['ApproveEvent']);
 
 				//$order_item_fields = $this->Conn->GetRow('SELECT * FROM '.TABLE_PREFIX.'OrderItems WHERE OrderItemId = '.$grouping_data[1]);
 				$object_item->Load($package_item_id);
 
 				$object_field_values['OrderId'] = $field_values['OrderId'];
 				$object_field_values['ProductId'] = $package_item_id;
 
 				$object_field_values['ItemData'] = serialize($item_data['PackageItemsItemData'][$package_item_id]);
 
 				$approve_event->setEventParam('field_values', $object_field_values);
 				$this->Application->HandleEvent($approve_event);
 			}
-
-
 		}
-
 	}
 
 	/**
 	 * Saves edited item into temp table
 	 * If there is no id, new item is created in temp table
 	 *
 	 * @param kEvent $event
 	 * @return void
 	 * @access protected
 	 */
 	protected function OnPreSave(kEvent $event)
 	{
 		$this->CheckRequiredOptions($event);
 
 		parent::OnPreSave($event);
 	}
 
 	/**
 	 * Set new price to ProductsPricing
 	 *
 	 * @param kEvent $event
 	 * @return void
 	 * @access protected
 	 */
 	protected function OnAfterItemCreate(kEvent $event)
 	{
 		parent::OnAfterItemCreate($event);
 
 		$this->_updateProductPrice($event);
 	}
 
 	/**
 	 * Set new price to ProductsPricing
 	 *
 	 * @param kEvent $event
 	 * @return void
 	 * @access protected
 	 */
 	protected function OnAfterItemUpdate(kEvent $event)
 	{
 		parent::OnAfterItemUpdate($event);
 
 		$this->_updateProductPrice($event);
 	}
 
 	/**
 	 * Updates product's primary price based on Price virtual field value
 	 *
 	 * @param kEvent $event
 	 */
 	function _updateProductPrice($event)
 	{
 		$object = $event->getObject();
 		/* @var $object kDBItem */
 
 		$price = $object->GetDBField('Price');
 
 		// always create primary pricing, to show on Pricing tab (in admin) for tangible products
 		$force_create = ($object->GetDBField('Type') == PRODUCT_TYPE_TANGIBLE) && is_null($price);
 
 		if ($force_create || ($price != $object->GetOriginalField('Price'))) {
 			// new product OR price was changed in virtual field
 			$this->setPrimaryPrice($object->GetID(), (float)$price);
 		}
 	}
 
 	function CheckRequiredOptions($event)
 	{
 		$object = $event->getObject();
 		if ($object->GetDBField('ProductId') == '') return ; // if product does not have ID - it's not yet created
 		$opt_object = $this->Application->recallObject('po', null, Array('skip_autoload' => true) );
 		$has_required = $this->Conn->GetOne('SELECT COUNT(*) FROM '.$opt_object->TableName.' WHERE Required = 1 AND ProductId = '.$object->GetDBField('ProductId'));
 		//we need to imitate data sumbit, as parent' PreSave sets object values from $items_info
 		$items_info = $this->Application->GetVar( $event->getPrefixSpecial(true) );
 		$items_info[$object->GetDBField('ProductId')]['HasRequiredOptions'] = $has_required ? '1' : '0';
 		$this->Application->SetVar($event->getPrefixSpecial(true), $items_info);
 		$object->SetDBField('HasRequiredOptions', $has_required ? 1 : 0);
 	}
 
 	/**
 	 * Sets required price in primary price backed, if it's missing, then create it
 	 *
 	 * @param int $product_id
 	 * @param double $price
 	 * @param Array $additional_fields
 	 * @return bool
 	 */
 	function setPrimaryPrice($product_id, $price, $additional_fields = Array())
 	{
 		$pr_object = $this->Application->recallObject('pr.-item', null, Array('skip_autoload' => true) );
 		/* @var $pr_object kDBItem */
 
 		$pr_object->Load( Array('ProductId' => $product_id, 'IsPrimary' => 1) );
 
 		$sql = 'SELECT COUNT(*) FROM '.$pr_object->TableName.' WHERE ProductId = '.$product_id;
 		$has_pricings = $this->Conn->GetOne($sql);
 
 		if ($additional_fields) {
 			$pr_object->SetDBFieldsFromHash($additional_fields);
 		}
 
 		if( ($price === false) && $has_pricings ) return false;
 
 		if( $pr_object->isLoaded() )
 		{
 			$pr_object->SetField('Price', $price);
 			return $pr_object->Update();
 		}
 		else
 		{
 			$group_id = $this->Application->ConfigValue('User_LoggedInGroup');
 			$field_values = Array('ProductId' => $product_id, 'IsPrimary' => 1, 'MinQty' => 1, 'MaxQty' => -1, 'GroupId'=>$group_id);
 			$pr_object->SetDBFieldsFromHash($field_values);
 			$pr_object->SetField('Price', $price);
 
 			return $pr_object->Create();
 		}
 	}
 
 	/**
 	 * Occurs after deleting item, id of deleted item
 	 * is stored as 'id' param of event
 	 *
 	 * @param kEvent $event
 	 * @return void
 	 * @access protected
 	 */
 	protected function OnAfterItemDelete(kEvent $event)
 	{
 		parent::OnAfterItemDelete($event);
 
 		$product_id = $event->getEventParam('id');
 		if ( !$product_id ) {
 			return;
 		}
 
 		$sql = 'DELETE FROM ' . TABLE_PREFIX . 'UserFileAccess
 				WHERE ProductId = ' . $product_id;
 		$this->Conn->Query($sql);
 	}
 
 	/**
 	 * Load price from temp table if product mode is temp table
 	 *
 	 * @param kEvent $event
 	 */
 
 	/**
 	 * Load price from temp table if product mode is temp table
 	 *
 	 * @param kEvent $event
 	 * @return void
 	 * @access protected
 	 */
 	protected function OnAfterItemLoad(kEvent $event)
 	{
 		parent::OnAfterItemLoad($event);
 
 		$object = $event->getObject();
 		/* @var $object ProductsItem */
 
 		$a_pricing = $object->getPrimaryPricing();
 		if ( !$a_pricing ) {
 			// pricing doesn't exist for new products
 			$price = $cost = null;
 		}
 		else {
 			$price = (float)$a_pricing['Price'];
 			$cost = (float)$a_pricing['Cost'];
 		}
 
 		// set original fields to use them in OnAfterItemCreate/OnAfterItemUpdate later
 		$object->SetDBField('Price', $price);
 		$object->SetOriginalField('Price', $price);
 
 		$object->SetDBField('Cost', $cost);
 		$object->SetOriginalField('Cost', $cost);
 	}
 
 	/**
 	 * Allows to add products to package besides all that parent method does
 	 *
 	 * @param kEvent $event
 	 */
 	function OnProcessSelected($event)
 	{
 		$dst_field = $this->Application->RecallVar('dst_field');
 
 		if ($dst_field == 'PackageContent') {
 			$this->OnAddToPackage($event);
 		}
 		elseif ($dst_field == 'AssignedCoupon') {
 			$coupon_id = $this->Application->GetVar('selected_ids');
 			$object = $event->getObject();
 			$object->SetDBField('AssignedCoupon', $coupon_id);
 			$this->RemoveRequiredFields($object);
 			$object->Update();
 		}
 		else {
 			parent::OnProcessSelected($event);
 		}
 		$this->finalizePopup($event);
 	}
 
 	/**
 	 * Called when some products are selected in products selector for this prefix
 	 *
 	 * @param kEvent $event
 	 */
 	function OnAddToPackage($event)
 	{
 		$selected_ids = $this->Application->GetVar('selected_ids');
 
 		// update current package content with selected products
 
 		$object = $event->getObject();
 		/* @var $object ProductsItem */
 
 		$product_ids = $selected_ids['p'] ? explode(',', $selected_ids['p']) : Array();
 
 		if ($product_ids) {
 			$current_ids = $object->GetPackageContentIds();
 			$current_ids = array_unique(array_merge($current_ids, $product_ids));
 
 			// remove package product from selected list
 			$this_product = array_search($object->GetID(), $current_ids);
 			if ($this_product !== false) {
 				unset($current_ids[$this_product]);
 			}
 
 			$dst_field = $this->Application->RecallVar('dst_field');
 			$object->SetDBField($dst_field, '|'.implode('|', $current_ids).'|');
 
 			$object->Update();
 			$this->ProcessPackageItems($event);
 		}
 
 		$this->finalizePopup($event);
 	}
 
 
-	function ProcessPackageItems($event)
+	function ProcessPackageItems(kEvent $event)
 	{
 		//$this->Application->SetVar('p_mode', 't');
 
 		$object = $event->getObject();
 		/* @var $object ProductsItem */
 
 		$content_ids = $object->GetPackageContentIds();
 
 		if (sizeof($content_ids) > 0) {
 			$total_weight = $this->Conn->GetOne('SELECT SUM(Weight) FROM '.TABLE_PREFIX.'Products WHERE ProductId IN ('.implode(', ', $content_ids).') AND Type=1');
 
 			if (!$total_weight) $total_weight = 0;
 
 			$this->Conn->Query('UPDATE '.$object->TableName.' SET Weight='.$total_weight.' WHERE ProductId='.$object->GetID());
 		}
 
 		/*
 		$this->Application->SetVar('p_mode', false);
 
-		$list = &$this->Application->recallObject('p.content', 'p_List', array('types'=>'content'));
+		$list = $this->Application->recallObject('p.content', 'p_List', array('types'=>'content'));
 
 		$this->Application->SetVar('p_mode', 't');
 
 		$list->Query();
 
 		$total_weight_a = 0;
 		$total_weight_b = 0;
 
 		$list->GoFirst();
 
 		while (!$list->EOL())
 		{
 			if ($list->GetDBField('Type')==1){
 				$total_weight_a += $list->GetField('Weight_a');
 				$total_weight_b += $list->GetField('Weight_b');
 			}
 			$list->GoNext();
 		}
 
 		$object->SetField('Weight_a', $total_weight_a);
 		$object->SetField('Weight_b', $total_weight_b);
 		*/
 		//$object->Update();
 
 
 	}
 
 	/**
 	 * Enter description here...
 	 *
 	 * @param kEvent $event
 	 */
 
 	function OnSaveItems($event)
 	{
 		//$event->CallSubEvent('OnUpdate');
 		$event->redirect = false;
 		//$event->setRedirectParams(Array ('opener' => 's', 'pass' => 'all,p'));
 	}
 
 	/**
 	 * Removes product from package
 	 *
 	 * @param kEvent $event
 	 */
 	function OnRemovePackageItem($event) {
 
 		$this->Application->SetVar('p_mode', 't');
 
 		$object = $event->getObject();
 
 		$items_info = $this->Application->GetVar('p_content');
 
 		if($items_info)
 		{
 			$product_ids = array_keys($items_info);
 
 			$current_ids = $object->GetPackageContentIds();
 
 			$current_ids_flip = array_flip($current_ids);
 			foreach($product_ids as $key=>$val){
 				unset($current_ids_flip[$val]);
 			}
 			$current_ids = array_keys($current_ids_flip);
 			$current_ids_str = '|'.implode('|', array_unique($current_ids)).'|';
 			$object->SetDBField('PackageContent', $current_ids_str);
 		}
 
 		$object->Update();
 		$this->ProcessPackageItems($event);
 	}
 
 	/**
 	 * Occurs before deleting item, id of item being
 	 * deleted is stored as 'id' event param
 	 *
 	 * @param kEvent $event
 	 * @return void
 	 * @access protected
 	 */
 	protected function OnBeforeItemDelete(kEvent $event)
 	{
 		parent::OnBeforeItemDelete($event);
 
 		$object = $event->getObject();
 		/* @var $object kDBItem */
 
 		$sql = 'SELECT COUNT(*)
 				FROM ' . TABLE_PREFIX . 'Products
 				WHERE PackageContent LIKE "%|' . $object->GetID() . '%"';
 		$product_includes_in = $this->Conn->GetOne($sql);
 
 		if ( $product_includes_in > 0 ) {
 			$event->status = kEvent::erFAIL;
 		}
 	}
 
 	/**
 	 * Returns specific to each item type columns only
 	 *
 	 * @param kEvent $event
 	 * @return Array
 	 * @access protected
 	 */
 	public function getCustomExportColumns(kEvent $event)
 	{
 		$columns = parent::getCustomExportColumns($event);
 
 		$new_columns = Array (
 			'__VIRTUAL__Price' => 'Price',
 			'__VIRTUAL__Cost' => 'Cost',
 		);
 
 		return array_merge($columns, $new_columns);
 	}
 
 /**
 	 * Sets non standart virtual fields (e.g. to other tables)
 	 *
 	 * @param kEvent $event
 	 */
 	function setCustomExportColumns($event)
 	{
 		parent::setCustomExportColumns($event);
 
 		$object = $event->getObject();
 		/* @var $object kDBItem */
 
 		$this->setPrimaryPrice($object->GetID(), (double)$object->GetDBField('Price'), Array ('Cost' => (double)$object->GetDBField('Cost')));
 	}
 
 	function OnPreSaveAndOpenPopup($event)
 	{
 		$object = $event->getObject();
 		/* @var $object kDBItem */
 
 		$this->RemoveRequiredFields($object);
 		$event->CallSubEvent('OnPreSave');
 
 		$event->redirect = $this->Application->GetVar('t');
 		// pass ID too, in case if product is created by OnPreSave call to ensure proper editing
 		$event->SetRedirectParam('pass', 'all');
 		$event->SetRedirectParam($event->getPrefixSpecial(true) . '_id', $object->GetID());
 	}
 
 
 	/**
 	 * Returns ID of current item to be edited
 	 * by checking ID passed in get/post as prefix_id
 	 * or by looking at first from selected ids, stored.
 	 * Returned id is also stored in Session in case
 	 * it was explicitly passed as get/post
 	 *
 	 * @param kEvent $event
 	 * @return int
 	 * @access public
 	 */
 	public function getPassedID(kEvent $event)
 	{
 		if ( $this->Application->isAdminUser ) {
 			$event->setEventParam('raise_warnings', 0);
 		}
 
 		$passed = parent::getPassedID($event);
 
 		if ( $passed ) {
 			return $passed;
 		}
 
 		if ( $this->Application->isAdminUser ) {
 			// we may get product id out of OrderItem, if it exists
 			$ord_item = $this->Application->recallObject('orditems', null, Array ('raise_warnings' => 0));
 			/* @var $ord_item OrdersItem */
 
 			if ( $ord_item->GetDBField('ProductId') ) {
 				$passed = $ord_item->GetDBField('ProductId');
 			}
 		}
 
 		return $passed;
 	}
 
 	/**
 	 * Occurs, when config was parsed, allows to change config data dynamically
 	 *
 	 * @param kEvent $event
 	 * @return void
 	 * @access protected
 	 */
 	protected function OnAfterConfigRead(kEvent $event)
 	{
 		parent::OnAfterConfigRead($event);
 
 		if (!$this->Application->LoggedIn()) {
 			return ;
 		}
 
 		$user_id = $this->Application->RecallVar('user_id');
 
 		$sql = 'SELECT PrimaryGroupId
 				FROM ' . TABLE_PREFIX . 'Users
 				WHERE PortalUserId = ' . $user_id;
 		$primary_group_id = $this->Conn->GetOne($sql);
 
 		if (!$primary_group_id) {
 			return;
 		}
 
 		$sub_select = '	SELECT pp.Price
 						FROM ' . TABLE_PREFIX . 'ProductsPricing AS pp
 			 			WHERE pp.ProductId = %1$s.ProductId AND GroupId = ' . $primary_group_id . '
 			 			ORDER BY MinQty
 			 			LIMIT 0,1';
 
 		$calculated_fields = $this->Application->getUnitOption($event->Prefix, 'CalculatedFields');
 		$calculated_fields['']['Price'] = 'IFNULL((' . $sub_select . '), ' . $calculated_fields['']['Price'] . ')';
 		$this->Application->setUnitOption($event->Prefix, 'CalculatedFields', $calculated_fields);
 	}
 
 	/**
 	 * Starts product editing, remove any pending inventory actions
 	 *
 	 * @param kEvent $event
 	 * @return void
 	 * @access protected
 	 */
 	protected function OnEdit(kEvent $event)
 	{
 		$this->Application->RemoveVar('inventory_actions');
 
 		parent::OnEdit($event);
 	}
 
 	/**
 	 * Adds "Shop Cart" tab on paid listing type editing tab
 	 *
 	 * @param kEvent $event
 	 */
 	function OnModifyPaidListingConfig($event)
 	{
 		$edit_tab_presets = $this->Application->getUnitOption($event->MasterEvent->Prefix, 'EditTabPresets');
 		$edit_tab_presets['Default']['shopping_cart'] = Array ('title' => 'la_tab_ShopCartEntry', 't' => 'in-commerce/paid_listings/paid_listing_type_shopcart', 'priority' => 2);
 		$this->Application->setUnitOption($event->MasterEvent->Prefix, 'EditTabPresets', $edit_tab_presets);
 	}
 
 	/**
 	 * [HOOK] Allows to add cloned subitem to given prefix
 	 *
 	 * @param kEvent $event
 	 * @return void
 	 * @access protected
 	 */
 	protected function OnCloneSubItem(kEvent $event)
 	{
 		parent::OnCloneSubItem($event);
 
 		if ( $event->MasterEvent->Prefix == 'rev' ) {
 			$clones = $this->Application->getUnitOption($event->MasterEvent->Prefix, 'Clones');
 			$subitem_prefix = $event->Prefix . '-' . $event->MasterEvent->Prefix;
 
 			$clones[$subitem_prefix]['ConfigMapping'] = Array (
 				'PerPage'				=>	'Comm_Perpage_Reviews',
 
 				'ReviewDelayInterval'	=>	'product_ReviewDelay_Value',
 				'ReviewDelayValue'		=>	'product_ReviewDelay_Interval',
 			);
 
 			$this->Application->setUnitOption($event->MasterEvent->Prefix, 'Clones', $clones);
 		}
 	}
 
 	/**
 	 * Adds product to comparison list
 	 *
 	 * @param kEvent $event
 	 * @return void
 	 * @access protected
 	 */
 	protected function OnAddToCompare(kEvent $event)
 	{
 		$products = $this->getCompareProducts();
 		$product_id = (int)$this->Application->GetVar($event->Prefix . '_id');
 
 		if ( $product_id ) {
 			$max_products = $this->Application->ConfigValue('MaxCompareProducts');
 
 			if ( count($products) < $max_products ) {
 				$products[] = $product_id;
 				$this->Application->Session->SetCookie('compare_products', implode('|', array_unique($products)));
 
 				$event->SetRedirectParam('result', 'added');
 			}
 			else {
 				$event->SetRedirectParam('result', 'error');
 			}
 		}
 
 		$event->SetRedirectParam('pass', 'm,p');
 	}
 
 	/**
 	 * Adds product to comparison list
 	 *
 	 * @param kEvent $event
 	 * @return void
 	 * @access protected
 	 */
 	protected function OnRemoveFromCompare(kEvent $event)
 	{
 		$products = $this->getCompareProducts();
 
 		$product_id = (int)$this->Application->GetVar($event->Prefix . '_id');
 
 		if ( $product_id && in_array($product_id, $products) ) {
 			$products = array_diff($products, Array ($product_id));
 			$this->Application->Session->SetCookie('compare_products', implode('|', array_unique($products)));
 
 			$event->SetRedirectParam('result', 'removed');
 		}
 
 		$event->SetRedirectParam('pass', 'm,p');
 	}
 
 	/**
 	 * Cancels product compare
 	 *
 	 * @param kEvent $event
 	 * @return void
 	 * @access protected
 	 */
 	protected function OnCancelCompare(kEvent $event)
 	{
 		$this->Application->Session->SetCookie('compare_products', '', -1);
 
 		$event->SetRedirectParam('result', 'all_removed');
 	}
 
 	/**
 	 * Returns products, that needs to be compared with each other
 	 *
 	 * @return Array
 	 * @access protected
 	 */
 	protected function getCompareProducts()
 	{
 		$products = $this->Application->GetVarDirect('compare_products', 'Cookie');
 		$products = $products ? explode('|', $products) : Array ();
 
 		return $products;
 	}
 }
\ No newline at end of file
Index: branches/5.3.x/units/products/products_config.php
===================================================================
--- branches/5.3.x/units/products/products_config.php	(revision 15670)
+++ branches/5.3.x/units/products/products_config.php	(revision 15671)
@@ -1,714 +1,715 @@
 <?php
 /**
 * @version	$Id$
 * @package	In-Commerce
 * @copyright	Copyright (C) 1997 - 2009 Intechnic. All rights reserved.
 * @license	Commercial License
 * This software is protected by copyright law and international treaties.
 * Unauthorized reproduction or unlicensed usage of the code of this program,
 * or any portion of it may result in severe civil and criminal penalties,
 * and will be prosecuted to the maximum extent possible under the law
 * See http://www.in-portal.org/commercial-license for copyright notices and details.
 */
 
 defined('FULL_PATH') or die('restricted access!');
 
 $config = Array (
 	'Prefix' => 'p',
 	'ItemClass' => Array ('class' => 'ProductsItem', 'file' => 'products_item.php', 'build_event' => 'OnItemBuild'),
 	'ListClass' => Array ('class' => 'kCatDBList', 'file' => '', 'build_event' => 'OnListBuild'),
 	'EventHandlerClass' => Array ('class' => 'ProductsEventHandler', 'file' => 'products_event_handler.php', 'build_event' => 'OnBuild'),
 	'TagProcessorClass' => Array ('class' => 'ProductsTagProcessor', 'file' => 'products_tag_processor.php', 'build_event' => 'OnBuild'),
 
 	'AutoLoad' => true,
 
 	'QueryString' => Array (
 		1 => 'id',
 		2 => 'Page',
 		3 => 'PerPage',
 		4 => 'event',
 		5 => 'mode',
 	),
 
 	'CatalogItem' => true,
 	'AdminTemplatePath' => 'products',
 	'AdminTemplatePrefix' => 'products_',
 
 	'SearchConfigPostfix' => 'products',
 
 	'ConfigPriority' => 0,
 
 	'RewritePriority' => 104,
 	'RewriteListener' => 'CategoryItemRewrite:RewriteListener',
 
 	'Hooks' => Array (
 		// for subscription products: access group is saved before changing pricings
 		Array (
 			'Mode' => hAFTER,
 			'Conditional' => true,
 			'HookToPrefix' => 'pr',
 			'HookToSpecial' => '*',
 			'HookToEvent' => Array ('OnNew', 'OnAfterItemLoad'),
 			'DoPrefix' => '',
 			'DoSpecial' => '*',
 			'DoEvent' => 'OnPreSave',
 		),
 
 		Array (
 			'Mode' => hAFTER,
 			'Conditional' => false,
 			'HookToPrefix' => 'lst',
 			'HookToSpecial' => '',
 			'HookToEvent' => Array ( 'OnBeforeCopyToLive' ),
 			'DoPrefix' => '',
 			'DoSpecial' => '',
 			'DoEvent' => 'OnSaveVirtualProduct',
 		),
 
 		Array (
 			'Mode' => hAFTER,
 			'Conditional' => false,
 			'HookToPrefix' => 'lst',
 			'HookToSpecial' => '*',
 			'HookToEvent' => Array ('OnAfterItemDelete'),
 			'DoPrefix' => '',
 			'DoSpecial' => '',
 			'DoEvent' => 'OnDeleteListingType',
 		),
 
 		Array (
 			'Mode' => hAFTER,
 			'Conditional' => false,
 			'HookToPrefix' => 'lst',
 			'HookToSpecial' => '*',
 			'HookToEvent' => Array ('OnAfterConfigRead'),
 			'DoPrefix' => '',
 			'DoSpecial' => '',
 			'DoEvent' => 'OnModifyPaidListingConfig',
 		),
 
 		Array (
 			'Mode' => hBEFORE,
 			'Conditional' => false,
 			'HookToPrefix' => 'file',
 			'HookToSpecial' => '',
 			'HookToEvent' => Array ( 'OnNew', 'OnEdit' ),
 			'DoPrefix' => '',
 			'DoSpecial' => '',
 			'DoEvent' => 'OnPreSave',
 		),
 
 		Array (
 			'Mode' => hBEFORE,
 			'Conditional' => false,
 			'HookToPrefix' => '',
 			'HookToSpecial' => '*',
 			'HookToEvent' => Array ('OnAfterConfigRead'),
 			'DoPrefix' => 'cdata',
 			'DoSpecial' => '*',
 			'DoEvent' => 'OnDefineCustomFields',
 		),
 
 		Array (
 			'Mode' => hBEFORE,
 			'Conditional' => false,
 			'HookToPrefix' => 'rev',
 			'HookToSpecial' => '*',
 			'HookToEvent' => Array ('OnAfterConfigRead'),
 			'DoPrefix' => '',
 			'DoSpecial' => '*',
 			'DoEvent' => 'OnCloneSubItem',
 		),
 
 		Array (
 			'Mode' => hBEFORE,
 			'Conditional' => false,
 			'HookToPrefix' => 'fav',
 			'HookToSpecial' => '*',
 			'HookToEvent' => Array ('OnAfterConfigRead'),
 			'DoPrefix' => '',
 			'DoSpecial' => '*',
 			'DoEvent' => 'OnCloneSubItem',
 		),
 
 		Array (
 			'Mode' => hBEFORE,
 			'Conditional' => false,
 			'HookToPrefix' => 'ci',
 			'HookToSpecial' => '*',
 			'HookToEvent' => Array ('OnAfterConfigRead'),
 			'DoPrefix' => '',
 			'DoSpecial' => '*',
 			'DoEvent' => 'OnCloneSubItem',
 		),
 	),
 
 	'IDField' => 'ProductId',
 	'StatusField' => Array ('Status'),	// field, that is affected by Approve/Decline events
 
 	'TitleField' => 'Name',		// field, used in bluebar when editing existing item
 	'ItemType' => 11,	// this is used when relation to product is added from in-portal and via-versa
 
 	'ViewMenuPhrase' => 'la_text_Products',
 	'CatalogTabIcon' => 'in-commerce:icon16_products.png',
 
 	'ItemPropertyMappings' => Array (
 		'NewDays' => 'Product_NewDays',		// number of days item to be NEW
 		'MinPopVotes' => 'Product_MinPopVotes',	// minimum number of votes for an item to be POP
 		'MinPopRating' => 'Product_MinPopRating',	// minimum rating for an item to be POP
 		'MaxHotNumber' => 'Product_MaxHotNumber',	// maximum number of HOT (top seller) items
 
 		'HotLimit' => 'Product_HotLimit',		// variable name in inp_Cache table
 		'ClickField' => 'Hits',					// item click count is stored here (in item table)
 	),
 
 	'TitlePhrase' => 'la_text_Product',
 
 	'TitlePresets' => Array (
 		'default' => Array (
 			'new_status_labels' => Array ('p' => '!la_title_Adding_Product!'),
 			'edit_status_labels' => Array ('p' => '!la_title_Editing_Product!'),
 			'new_titlefield' => Array ('p' => '!la_title_NewProduct!'),
 		),
 		'product_list' =>Array (
 			'prefixes' => Array ('c_List', 'p_List'),
 			'tag_params' => Array ('c' => Array ('per_page' =>-1)),
 			'format' => "!la_title_Categories! (#c_recordcount#) - !la_title_Products! (#p_recordcount#)",
 		),
 		'products_edit' =>Array (
 			'prefixes' => Array ('p'),
 			'new_titlefield' => Array ('p' => '!la_title_NewProduct!'),
 			'format' => "#p_status# '#p_titlefield#' - !la_title_General!",
 		),
 		'inventory' => Array ('prefixes' => Array ('p'), 'format' => "#p_status# - '#p_titlefield#' - !la_title_Product_Inventory!"),
 		'pricing' => Array ('prefixes' => Array ('p'), 'format' => "#p_status# '#p_titlefield#' - !la_title_Product_Pricing!"),
 		'access_pricing' => Array ('prefixes' => Array ('p'), 'format' => "#p_status# '#p_titlefield#' - !la_title_Product_AccessPricing!"),
 		'access' => Array ('prefixes' => Array ('p'), 'format' => "#p_status# '#p_titlefield#' - !la_title_Product_Access!"),
 		'files' => Array ('prefixes' => Array ('p'), 'format' => "#p_status# '#p_titlefield#' - !la_title_Product_Files!"),
 		'options' => Array ('prefixes' => Array ('p'), 'format' => "#p_status# '#p_titlefield#' - !la_title_Product_Options!"),
 		'categories' => Array ('prefixes' => Array ('p', 'p-ci_List'), 'format' => "#p_status# '#p_titlefield#' - !la_title_Categories!"),
 		'relations' => Array ('prefixes' => Array ('p'), 'format' => "#p_status# '#p_titlefield#' - !la_title_Relations!"),
 		'content' => Array ('prefixes' => Array ('p', 'p.content_List'), 'tag_params' => Array ('p.content' => Array ('types' => 'content', 'live_table' =>true)), 'format' => "#p_status# '#p_titlefield#' - !la_title_Product_PackageContent!"),
 		'images' => Array ('prefixes' => Array ('p'), 'format' => "#p_status# '#p_titlefield#' - !la_title_Images!"),
 		'reviews' => Array ('prefixes' => Array ('p'), 'format' => "#p_status# '#p_titlefield#' - !la_title_Reviews!"),
 		'products_custom' => Array ('prefixes' => Array ('p'), 'format' => "#p_status# '#p_titlefield#' - !la_title_Custom!"),
 		'images_edit' => Array (
 			'prefixes' => Array ('p', 'img'),
 			'new_status_labels' => Array ('img' => '!la_title_Adding_Image!'),
 			'edit_status_labels' => Array ('img' => '!la_title_Editing_Image!'),
 			'new_titlefield' => Array ('img' => '!la_title_New_Image!'),
 			'format' => "#p_status# '#p_titlefield#' - #img_status# '#img_titlefield#'",
 		),
 		'pricing_edit' => Array (
 			'prefixes' => Array ('p', 'pr'),
 			'new_status_labels' => Array ('pr' =>"!la_title_Adding_PriceBracket! '!la_title_New_PriceBracket!'"),
 			'edit_status_labels' => Array ('pr' => '!la_title_Editing_PriceBracket!'),
 			'format' => "#p_status# '#p_titlefield#' - #pr_status#",
 		),
 		'options_edit' => Array (
 			'prefixes' => Array ('p', 'po'),
 			'new_status_labels' => Array ('po' =>"!la_title_Adding_Option!"),
 			'edit_status_labels' => Array ('po' => '!la_title_Editing_Option!'),
 			'new_titlefield' => Array ('po' => '!la_title_New_Option!'),
 			'format' => "#p_status# '#p_titlefield#' - #po_status# '#po_titlefield#'",
 		),
 
 		'options_combinations' => Array ('prefixes' => Array ('p'), 'format' => "#p_status# '#p_titlefield#' - !la_title_ManagingOptionCombinations!"),
 		'shipping_options' => Array ('prefixes' => Array ('p'), 'format' => "#p_status# '#p_titlefield#' - !la_title_ManagingShippingOptions!"),
 
 		'file_edit' => Array (
 			'prefixes' => Array ('p', 'file'),
 			'new_status_labels' => Array ('file' =>"!la_title_Adding_File!"),
 			'edit_status_labels' => Array ('file' => '!la_title_Editing_File!'),
 			'new_titlefield' => Array ('file' => '!la_title_New_File!'),
 			'format' => "#p_status# '#p_titlefield#' - #file_status# '#file_titlefield#'",
 		),
 		'relations_edit' => Array (
 			'prefixes' => Array ('p', 'rel'),
 			'new_status_labels' => Array ('rel' =>"!la_title_Adding_Relationship! '!la_title_New_Relationship!'"),
 			'edit_status_labels' => Array ('rel' => '!la_title_Editing_Relationship!'),
 			'format' => "#p_status# '#p_titlefield#' - #rel_status#",
 		),
 		'reviews_edit' => Array (
 			'prefixes' => Array ('p', 'rev'),
 			'new_status_labels' => Array ('rev' =>"!la_title_Adding_Review! '!la_title_New_Review!'"),
 			'edit_status_labels' => Array ('rev' => '!la_title_Editing_Review!'),
 			'format' => "#p_status# '#p_titlefield#' - #rev_status#",
 		),
 
 		'products_export' => Array ('format' => '!la_title_ProductsExport!'),
 
 		'products_import' => Array ('format' => '!la_title_ImportProducts!'),
 
 		'tree_in-commerce' => Array ('format' => '!la_Text_Version! '.$this->Application->findModule('Name', 'In-Commerce', 'Version')),
 	),
 
 	'EditTabPresets' => Array (
 		'Default' => Array (
 			'general' => Array ('title' => 'la_tab_General', 't' => 'in-commerce/products/products_edit', 'priority' => 1),
 			'inventory' => Array ('title' => 'la_tab_Inventory', 't' => 'in-commerce/products/products_inventory', 'priority' => 2),
 			'access_and_pricing' => Array ('title' => 'la_tab_AccessAndPricing', 't' => 'in-commerce/products/products_access', 'priority' => 3),
 			'pricing' => Array ('title' => 'la_tab_Pricing', 't' => 'in-commerce/products/products_pricing', 'priority' => 4),
 
 //			'pricing2' => Array ('title' => 'la_tab_Pricing', 't' => 'in-commerce/products/products_access_pricing', 'priority' => 5),
 
 			'files_and_pricing' => Array ('title' => 'la_tab_FilesAndPricing', 't' => 'in-commerce/products/products_files', 'priority' => 6),
 			'options' => Array ('title' => 'la_tab_Options', 't' => 'in-commerce/products/products_options', 'priority' => 7),
 			'categories' => Array ('title' => 'la_tab_Categories', 't' => 'in-commerce/products/products_categories', 'priority' => 8),
 			'relations' => Array ('title' => 'la_tab_Relations', 't' => 'in-commerce/products/products_relations', 'priority' => 9),
 			'package_content' => Array ('title' => 'la_tab_PackageContent', 't' => 'in-commerce/products/products_packagecontent', 'priority' => 10),
 			'images' => Array ('title' => 'la_tab_Images', 't' => 'in-commerce/products/products_images', 'priority' => 11),
 			'reviews' => Array ('title' => 'la_tab_Reviews', 't' => 'in-commerce/products/products_reviews', 'priority' => 12),
 			'custom' => Array ('title' => 'la_tab_Custom', 't' => 'in-commerce/products/products_custom', 'priority' => 13),
 		),
 	),
 
 	'PermItemPrefix' => 'PRODUCT',
 
 	'PermTabText' => 'In-Commerce',
 	'PermSection' => Array ('main' => 'CATEGORY:in-commerce:products_list', 'search' => 'in-commerce:search', 'custom' => 'in-commerce:configuration_custom'),
 
 	'Sections' => Array (
 		'in-commerce' => Array (
 			'parent' => 'in-portal:root',
 			'icon' => 'ecommerce',
 			'label' => 'la_title_In-Commerce',
 			'url' => Array ('t' => 'index', 'pass_section' => true, 'pass' => 'm'),
 			'permissions' => Array ('view'),
 			'priority' => 2.1,
 			'container' => true,
 			'type' => stTREE,
 		),
 
 		'in-commerce:products' => Array (
 			'parent' => 'in-portal:site',
 			'icon' => 'products',
 			'label' => 'la_tab_Products',
 			'url' => Array ('t' => 'catalog/advanced_view', 'anchor' => 'tab-p.showall', 'pass' => 'm'),
 			'onclick' => 'setCatalogTab(\'p.showall\')',
 			'permissions' => Array ('view'),
 			'priority' => 3.2,
 			'type' => stTREE,
 		),
 
 		// product settings
 		'in-commerce:setting_folder' => Array (
 			'parent' => 'in-portal:system',
 			'icon' => 'conf_ecommerce',
 			'label' => 'la_title_In-Commerce',
 			'use_parent_header' => 1,
 			'url' => Array ('t' => 'index', 'pass_section' => true, 'pass' => 'm'),
 			'permissions' => Array ('view'),
 			'priority' => 3.1,
 			'container' => true,
 			'type' => stTREE,
 		),
 
 		'in-commerce:general' => Array (
 			'parent' => 'in-commerce:setting_folder',
 			'icon' => 'conf_ecommerce_general',
 			'label' => 'la_tab_GeneralSettings',
 			'url' => Array ('t' => 'config/config_general', 'pass_section' => true, 'pass' => 'm'),
 			'permissions' => Array ('view', 'add', 'edit'),
 			'priority' => 1,
 			'type' => stTREE,
 		),
 
 		'in-commerce:output' => Array (
 			'parent' => 'in-commerce:setting_folder',
 			'icon' => 'core:conf_output',
 			'label' => 'la_tab_ConfigOutput',
 			'url' => Array ('t' => 'config/config_universal', 'pass_section' => true, 'pass' => 'm'),
 			'permissions' => Array ('view', 'add', 'edit'),
 			'priority' => 2,
 			'type' => stTREE,
 		),
 
 		'in-commerce:search' => Array (
 			'parent' => 'in-commerce:setting_folder',
 			'icon' => 'core:conf_search',
 			'label' => 'la_tab_ConfigSearch',
 			'url' => Array ('t' => 'config/config_search', 'module_key' => 'products', 'pass_section' => true, 'pass' => 'm'),
 			'permissions' => Array ('view', 'edit'),
 			'priority' => 7,
 			'type' => stTREE,
 		),
 
 		'in-commerce:configuration_custom' => Array (
 			'parent' => 'in-commerce:setting_folder',
 			'icon' => 'core:conf_customfields',
 			'label' => 'la_tab_ConfigCustom',
 			'url' => Array ('t' => 'custom_fields/custom_fields_list', 'cf_type' => 11, 'pass_section' => true, 'pass' => 'm,cf'),
 			'permissions' => Array ('view', 'add', 'edit', 'delete'),
 			'priority' => 8,
 			'type' => stTREE,
 		),
 
 		'in-commerce:contacts' => Array (
 			'parent' => 'in-commerce:setting_folder',
 			'icon' => 'conf_contact_info',
 			'label' => 'la_tab_ConfigContacts',
 			'url' => Array ('t' => 'config/config_universal', 'pass_section' => true, 'pass' => 'm'),
 			'permissions' => Array ('view', 'add', 'edit'),
 			'priority' => 10,
 			'type' => stTREE,
 		),
 	),
 
 	'FilterMenu' => Array (
 		'Groups' => Array (
 			Array ('mode' => 'AND', 'filters' => Array ('show_new'), 'type' => kDBList::HAVING_FILTER),
 			Array ('mode' => 'AND', 'filters' => Array ('show_hot'), 'type' => kDBList::HAVING_FILTER),
 			Array ('mode' => 'AND', 'filters' => Array ('show_pop'), 'type' => kDBList::HAVING_FILTER),
 			Array ('mode' => 'AND', 'filters' => Array ('show_pick'), 'type' => kDBList::WHERE_FILTER),
 		),
 		'Filters' => Array (
 			'show_new' => Array ('label' => 'la_Text_New', 'on_sql' => '', 'off_sql' => '`IsNew` != 1'  ),
 			'show_hot' => Array ('label' => 'la_Text_TopSellers', 'on_sql' => '', 'off_sql' => '`IsHot` != 1'  ),
 			'show_pop' => Array ('label' => 'la_Text_Pop', 'on_sql' => '', 'off_sql' => '`IsPop` != 1'  ),
 			'show_pick' => Array ('label' => 'la_prompt_EditorsPick', 'on_sql' => '', 'off_sql' => '%1$s.`EditorsPick` != 1'  ),
 		)
 	),
 
 	'TableName' => TABLE_PREFIX . 'Products',
 	'CustomDataTableName' => TABLE_PREFIX . 'ProductsCustomData',
 
 	'CalculatedFields' => Array (
 		'' => Array (
 			'AltName' => 'img.AltName',
 			'SameImages' => 'img.SameImages',
 			'LocalThumb' => 'img.LocalThumb',
 			'ThumbPath' => 'img.ThumbPath',
 			'ThumbUrl' => 'img.ThumbUrl',
 			'LocalImage' => 'img.LocalImage',
 			'LocalPath' => 'img.LocalPath',
 			'FullUrl' => 'img.Url',
 
 			'Price' => 'COALESCE(pricing.Price, 0)',
 			'Cost' => 'COALESCE(pricing.Cost, 0)',
 			'PrimaryCat' => TABLE_PREFIX.'%3$sCategoryItems.PrimaryCat',
 			'CategoryId' => TABLE_PREFIX.'%3$sCategoryItems.CategoryId',
 			'ParentPath' => TABLE_PREFIX.'Categories.ParentPath',
 			'Manufacturer' => TABLE_PREFIX.'Manufacturers.Name',
 			'Filename' => TABLE_PREFIX.'%3$sCategoryItems.Filename',
 			'CategoryFilename' => TABLE_PREFIX.'Categories.NamedParentPath',
 			'FileSize' => 'files.Size',
 			'FilePath' => 'files.FilePath',
 			'FileVersion' => 'files.Version',
 		),
 
 		'showall' => Array (
 			'Price' => 'COALESCE(pricing.Price, 0)',
 			'Manufacturer' => TABLE_PREFIX.'Manufacturers.Name',
 			'PrimaryCat' => TABLE_PREFIX.'%3$sCategoryItems.PrimaryCat',
 			'CategoryId' => TABLE_PREFIX.'%3$sCategoryItems.CategoryId',
 			'FileSize' => 'files.Size',
 			'FilePath' => 'files.FilePath',
 			'FileVersion' => 'files.Version',
 			'Filename' => TABLE_PREFIX.'%3$sCategoryItems.Filename',
 			'CategoryFilename' => TABLE_PREFIX.'Categories.NamedParentPath',
 		),
 	),
 
 	'CacheModRewrite' => true,
 
 	'ListSQLs' => Array (
 		'' => '	SELECT %1$s.* %2$s
 					FROM %1$s
 					LEFT JOIN '.TABLE_PREFIX.'UserGroups ON '.TABLE_PREFIX.'UserGroups.GroupId = %1$s.AccessGroupId
 					LEFT JOIN '.TABLE_PREFIX.'%3$sCategoryItems ON '.TABLE_PREFIX.'%3$sCategoryItems.ItemResourceId = %1$s.ResourceId
 					LEFT JOIN '.TABLE_PREFIX.'Categories ON '.TABLE_PREFIX.'Categories.CategoryId = '.TABLE_PREFIX.'%3$sCategoryItems.CategoryId
 					LEFT JOIN '.TABLE_PREFIX.'%3$sCatalogImages img ON img.ResourceId = %1$s.ResourceId AND img.DefaultImg = 1
 					LEFT JOIN '.TABLE_PREFIX.'%3$sProductFiles files ON files.ProductId = %1$s.ProductId AND files.IsPrimary = 1
 					LEFT JOIN '.TABLE_PREFIX.'%3$sProductsPricing pricing ON pricing.ProductId = %1$s.ProductId AND pricing.IsPrimary = 1
 					LEFT JOIN '.TABLE_PREFIX.'Manufacturers ON '.TABLE_PREFIX.'Manufacturers.ManufacturerId = %1$s.ManufacturerId
 					LEFT JOIN '.TABLE_PREFIX.'CategoryPermissionsCache perm ON perm.CategoryId = '.TABLE_PREFIX.'%3$sCategoryItems.CategoryId
 					LEFT JOIN '.TABLE_PREFIX.'%3$sProductsCustomData cust ON %1$s.ResourceId = cust.ResourceId',
 
 		'showall' => 'SELECT %1$s.* %2$s FROM %1$s
 					LEFT JOIN '.TABLE_PREFIX.'%3$sProductsPricing pricing ON pricing.ProductId = %1$s.ProductId AND pricing.IsPrimary = 1
 					LEFT JOIN '.TABLE_PREFIX.'%3$sProductFiles files ON files.ProductId = %1$s.ProductId AND files.IsPrimary = 1
 					LEFT JOIN '.TABLE_PREFIX.'Manufacturers ON '.TABLE_PREFIX.'Manufacturers.ManufacturerId = %1$s.ManufacturerId
 					LEFT JOIN '.TABLE_PREFIX.'%3$sCategoryItems ON '.TABLE_PREFIX.'%3$sCategoryItems.ItemResourceId = %1$s.ResourceId
 					LEFT JOIN '.TABLE_PREFIX.'Categories ON '.TABLE_PREFIX.'Categories.CategoryId = '.TABLE_PREFIX.'%3$sCategoryItems.CategoryId
 					LEFT JOIN '.TABLE_PREFIX.'CategoryPermissionsCache perm ON perm.CategoryId = '.TABLE_PREFIX.'%3$sCategoryItems.CategoryId
 					LEFT JOIN '.TABLE_PREFIX.'%3$sProductsCustomData cust ON %1$s.ResourceId = cust.ResourceId',
 	),
 
 	'ListSortings' => Array (
 		'' => Array (
 			'ForcedSorting' => Array ('EditorsPick' => 'desc', 'Priority' => 'desc'),
 			'Sorting' => Array ('Name' => 'asc'),
 		)
 	),
 
 	'ItemSQLs' => Array (
 		'' => '	SELECT %1$s.* %2$s
 				FROM %1$s
 				LEFT JOIN '.TABLE_PREFIX.'UserGroups pg ON pg.GroupId = %1$s.AccessGroupId
 				LEFT JOIN '.TABLE_PREFIX.'%3$sCategoryItems ON '.TABLE_PREFIX.'%3$sCategoryItems.ItemResourceId = %1$s.ResourceId
 				LEFT JOIN '.TABLE_PREFIX.'Categories ON '.TABLE_PREFIX.'Categories.CategoryId = '.TABLE_PREFIX.'%3$sCategoryItems.CategoryId
 				LEFT JOIN '.TABLE_PREFIX.'%3$sCatalogImages img ON img.ResourceId = %1$s.ResourceId AND img.DefaultImg = 1
 				LEFT JOIN '.TABLE_PREFIX.'%3$sProductFiles files ON files.ProductId = %1$s.ProductId AND files.IsPrimary = 1
 				LEFT JOIN '.TABLE_PREFIX.'%3$sProductsPricing pricing ON pricing.ProductId = %1$s.ProductId AND pricing.IsPrimary = 1
 				LEFT JOIN '.TABLE_PREFIX.'Manufacturers ON '.TABLE_PREFIX.'Manufacturers.ManufacturerId = %1$s.ManufacturerId
 				LEFT JOIN '.TABLE_PREFIX.'%3$sProductsCustomData cust ON %1$s.ResourceId = cust.ResourceId',
 	),
 
 	'SubItems' => Array ('pr', 'rev', 'img', 'po', 'poc', 'p-ci', 'rel', 'file', 'p-cdata', 'p-fav'),
 
 	'Fields' => Array (
 		'ProductId' => Array ('type' => 'int', 'not_null' => 1, 'default' => 0,),
 		'Name' => Array ('type' => 'string', 'formatter' => 'kMultiLanguage', 'required' => 1, 'max_len' =>255, 'default' => ''),
 		'AutomaticFilename' => Array (
 			'type' => 'int',
 			'formatter' => 'kOptionsFormatter',
 			'options' => Array (0 => 'la_No', 1 => 'la_Yes'),
 			'use_phrases' => 1, 'not_null' => 1, 'default' => 1,
 		),
 		'SKU' => Array ('type' => 'string', 'required' => 1, 'max_len' =>255, 'error_msgs' => Array ('required' => 'Please fill in'), 'default' => NULL),
 		'Description' => Array ('type' => 'string', 'formatter' => 'kMultiLanguage', 'using_fck' => 1, 'default' => NULL),
 		'DescriptionExcerpt' => Array ('type' => 'string', 'formatter' => 'kMultiLanguage', 'using_fck' => 1, 'default' => NULL),
 		'Weight' => Array ('type' => 'float', 'min_value_exc' => 0, 'formatter' => 'kUnitFormatter', 'format' => '%0.2f', 'default' => NULL),
 		'MSRP' => Array ('type' => 'float', 'min_value_inc' => 0, 'formatter' => 'kFormatter', 'format' => '%0.2f', 'default' => NULL),
 		'ManufacturerId' => Array ('type' => 'int', 'formatter' => 'kOptionsFormatter', 'options_sql' => 'SELECT %s FROM '.TABLE_PREFIX.'Manufacturers ORDER BY Name', 'option_key_field' => 'ManufacturerId', 'option_title_field' => 'Name', 'not_null' => 1, 'default' => 0),
 		'Status' => Array (
 			'type' => 'int',
 			'formatter' => 'kOptionsFormatter',
 			'options' => Array (1 => 'la_Active', 2 => 'la_Pending', 0 => 'la_Disabled'), 'use_phrases' => 1,
 			'default' => 2, 'not_null' => 1,
 		),
 		'BackOrder' => Array ('type' => 'int', 'not_null' => 1, 'options' => Array ( 2 => 'la_Auto', 1 => 'la_Always', 0 => 'la_Never' ), 'use_phrases' => 1, 'default' => 2 ),
 		'BackOrderDate' => Array ('type' => 'int', 'formatter' => 'kDateFormatter', 'error_msgs' => Array ('bad_date_format' => 'Please use the following date format: %s'), 'default' => NULL),
 		'NewItem' => Array ('type' => 'int', 'formatter' => 'kOptionsFormatter', 'options' => Array ( 2 => 'la_Auto', 1 => 'la_Always', 0 => 'la_Never' ), 'use_phrases' => 1, 'not_null' => 1, 'default' => 2 ),
 		'HotItem' => Array ('type' => 'int', 'formatter' => 'kOptionsFormatter', 'options' => Array ( 2 => 'la_Auto', 1 => 'la_Always', 0 => 'la_Never' ), 'use_phrases' => 1, 'not_null' => 1, 'default' => 2 ),
 		'PopItem' => Array ('type' => 'int', 'formatter' => 'kOptionsFormatter', 'options' => Array ( 2 => 'la_Auto', 1 => 'la_Always', 0 => 'la_Never' ), 'use_phrases' => 1, 'not_null' => 1, 'default' => 2 ),
 		'EditorsPick' => Array (
 			'type' => 'int',
 			'formatter' => 'kOptionsFormatter',
 			'options' => Array (1 => 'la_Yes', 0 => 'la_No'), 'use_phrases' => 1,
 			'not_null' => 1, 'default' => 0,
 		),
 		'Featured' => Array (
 			'type' => 'int',
 			'formatter' => 'kOptionsFormatter',
 			'options' => Array (1 => 'la_Yes', 0 => 'la_No'), 'use_phrases' => 1,
 			'not_null' => 1, 'default' => 0,
 		),
 		'OnSale' => Array (
 			'type' => 'int',
 			'formatter' => 'kOptionsFormatter',
 			'options' => Array (1 => 'la_Yes', 0 => 'la_No'), 'use_phrases' => 1,
 			'not_null' => 1, 'default' => 0,
 		),
 		'Priority' => Array ('type' => 'int', 'not_null' => 1, 'default' => 0),
 		'CachedRating' => Array ('type' => 'string', 'not_null' => 1, 'formatter' => 'kFormatter', 'default' => 0),
 		'CachedVotesQty' => Array ('type' => 'int', 'not_null' => 1, 'default' => 0),
 		'Hits' => Array ('type' => 'double', 'formatter' => 'kFormatter', 'format' => '%d', 'not_null' => 1, 'default' => 0),
 		'CreatedOn' => Array ('type' => 'int', 'formatter' => 'kDateFormatter', 'default' => '#NOW#'),
 		'Expire' => Array ('type' => 'int', 'formatter' => 'kDateFormatter', 'default' =>null),
 		'Type' => Array (
 			'type' => 'int',
 			'formatter' => 'kOptionsFormatter', 'use_phrases' => 1,
 			'options' => Array (
 				PRODUCT_TYPE_TANGIBLE => 'la_product_tangible',
 				PRODUCT_TYPE_SUBSCRIPTION => 'la_product_subscription',
 				PRODUCT_TYPE_SERVICE => 'la_product_service',
 				PRODUCT_TYPE_DOWNLOADABLE => 'la_product_downloadable',
 				/* PRODUCT_TYPE_PACKAGE => 'la_product_package', */
 			),
 			'not_null' => 1, 'default' => 1,
 		),
 		'Modified' => Array ('type' => 'int', 'formatter' => 'kDateFormatter', 'default' => '#NOW#'),
 		'ModifiedById' => Array ('type' => 'int', 'default' => NULL),
 		'CreatedById' => Array (
 			'type' => 'int',
 			'formatter' => 'kLEFTFormatter',
 			'options' => Array (USER_ROOT => 'root', USER_GUEST => 'Guest'),
 			'left_sql' => 'SELECT %s FROM ' . TABLE_PREFIX . 'Users
 							WHERE `%s` = \'%s\'',
 			'left_key_field' => 'PortalUserId',
 			'left_title_field' => 'Username',
 			'error_msgs' => Array ('invalid_option' => '!la_error_UserNotFound!'),
 			'sample_value' => 'Guest', 'required' => 1, 'default' => NULL,
 		),
 		'ResourceId' => Array ('type' => 'int', 'default' => null),
 		'CachedReviewsQty' => Array ('type' => 'int', 'formatter' => 'kFormatter', 'format' => '%d', 'not_null' => 1, 'default' => 0),
 		'InventoryStatus' => Array ('type' => 'int', 'formatter' => 'kOptionsFormatter', 'options' => Array (0 => 'la_Disabled', 1 => 'la_by_product', 2 => 'la_by_options'), 'use_phrases' => 1, 'not_null' => 1, 'default' => 0),
 		'QtyInStock' => Array ('type' => 'int', 'not_null' => 1, 'default' => 0),
 		'QtyInStockMin' => Array ('type' => 'int', 'not_null' => 1, 'default' => 0),
 		'QtyReserved' => Array ('type' => 'int', 'not_null' => 1, 'default' => 0),
 		'QtyBackOrdered' => Array ('type' => 'int', 'not_null' => 1, 'default' => 0),
 		'QtyOnOrder' => Array ('type' => 'int', 'not_null' => 1, 'default' => 0),
 		'InventoryComment' => Array ('type' => 'string', 'formatter' => 'kFormatter', 'using_fck' => 1, 'default' => null),
 		'Qty' => Array ('type' => 'int', 'formatter' => 'kFormatter', 'regexp' => '/^[\d]+$/', 'error_msgs' => Array ('invalid_format' => '!la_invalid_integer!')),
 		'AccessGroupId' => Array ('type' => 'int', 'formatter' => 'kOptionsFormatter', 'options_sql' => 'SELECT %s FROM '.TABLE_PREFIX.'UserGroups WHERE System!=1 AND Personal !=1 ORDER BY Name', 'option_key_field' => 'GroupId', 'option_title_field' => 'Name', 'default' => NULL),
 		'AccessDuration' => Array ('type' => 'int', 'default' => NULL),
 		'AccessDurationType' => Array ('type' => 'int', 'formatter' => 'kOptionsFormatter', 'use_phrases' => 1, 'options' =>Array (1 => 'la_opt_sec', 2 => 'la_opt_min', 3 => 'la_opt_hour', 4 => 'la_opt_day', 5 => 'la_opt_week', 6 => 'la_opt_month', 7 => 'la_opt_year' ), 'default' => NULL,),
 		'AccessStart' => Array ('type' => 'int', 'formatter' => 'kDateFormatter', 'default' => NULL),
 		'AccessEnd' => Array ('type' => 'int', 'formatter' => 'kDateFormatter', 'default' => NULL,),
 		'OptionsSelectionMode' => Array ('type' => 'int', 'formatter' => 'kOptionsFormatter', 'use_phrases' => 1, 'options' =>Array (0 => 'la_opt_Selection', 1 => 'la_opt_List'), 'default' => 0),
 		'HasRequiredOptions' => Array ('type' => 'int', 'default' => 0, 'not_null' => 1),
 		'Virtual' => Array ('type' => 'int', 'not_null' => 1, 'default' => 0),
 		'ProcessingData' => Array ('type' => 'string', 'default' => ''),
 		'PackageContent' => Array ('type' => 'string', 'default' => NULL),
 		'IsRecurringBilling' => Array (
 			'type' => 'int',
 			'formatter' => 'kOptionsFormatter',
 			'options' => Array (0 => 'la_No', 1 => 'la_Yes'),
 			'use_phrases' => 1, 'not_null' => 1, 'default' => 0,
 		),
 		//'PayPalRecurring' => Array ('type' => 'int', 'formatter' => 'kOptionsFormatter', 'options' => Array (1 => 'la_Yes', 0 => 'la_No'), 'use_phrases' => 1, 'not_null' => '1', 'default' => '0'),
 		'ShippingMode' => Array ('type' => 'int', 'formatter' => 'kOptionsFormatter', 'use_phrases' => 1, 'options' =>Array (0 => 'la_shipping_AnyAndSelected', 1 => 'la_shipping_Limited'), 'not_null' => 1, 'default' =>0),
 
 		'ProcessingData' => Array ('type' => 'string', 'default' => null),
 
 		'ShippingLimitation' => Array ('type' => 'string', 'default' => NULL),
-		'AssignedCoupon' => Array ('type' => 'int', 'not_null' => 1, 'default' => 0,
-							'formatter' => 'kLEFTFormatter',
-							'options' => Array (0 => 'None'),
-							'left_sql' => 'SELECT %s FROM '.TABLE_PREFIX.'ProductsCoupons WHERE `%s` = \'%s\'',
-							'left_key_field' => 'CouponId',
-							'left_title_field' => 'Name'),
+		'AssignedCoupon' => Array (
+			'type' => 'int',
+			'formatter' => 'kLEFTFormatter', 'options' => Array (0 => 'None'),
+			'left_sql' => 'SELECT %s FROM ' . TABLE_PREFIX . 'ProductsCoupons WHERE %s',
+			'left_key_field' => 'CouponId', 'left_title_field' => 'Name',
+			'not_null' => 1, 'default' => 0,
+		),
 		'MinQtyFreePromoShipping' => Array ('type' => 'int', 'not_null' => 1, 'default' => 0),
 		'MetaKeywords' => Array ('type' => 'string', 'default' => null),
 		'MetaDescription' => Array ('type' => 'string', 'formatter' => 'kFormatter', 'using_fck' => 1, 'default' => null),
 	),
 
 	'VirtualFields' => Array (
 		'Relevance' => Array ('type' => 'float', 'default' => 0),
 		'Qty' => Array ('type' => 'int', 'formatter' => 'kFormatter', 'regexp' => '/^[\d]+$/', 'default' => 0),
 		'Price' => Array ('type' => 'float', 'formatter' => 'kFormatter', 'format' => '%.2f', 'default' => NULL),
 		'Cost' => Array ('type' => 'float', 'formatter' => 'kFormatter', 'format' => '%.2f', 'default' => NULL),
 		'CategoryFilename' => Array ('type' => 'string', 'default' => ''),
 		'PrimaryCat' => Array ('type' => 'int', 'default' => 0),
 		'IsHot' => Array ('type' => 'int', 'default' => 0),
 		'IsNew' => Array ('type' => 'int', 'default' => 0),
 		'IsPop' => Array ('type' => 'int', 'default' => 0),
 		'Manufacturer' => Array ('type' => 'string', 'default' => ''),
 
 		// export related fields: begin
 		'CategoryId' => Array ('type' => 'int', 'formatter' => 'kOptionsFormatter', 'options' => Array (), 'default' => 0),
 		'ExportFormat' => Array ('type' => 'int', 'formatter' => 'kOptionsFormatter', 'options' => Array (1 => 'CSV', /*2 => 'XML'*/), 'default' => 1),
 		'ExportFilename' => Array ('type' => 'string', 'default' => ''),
 		'FieldsSeparatedBy' => Array ('type' => 'string', 'default' => ', '),
 		'FieldsEnclosedBy' => Array ('type' => 'string', 'default' => '"'),
 		'LineEndings' => Array ('type' => 'int', 'formatter' => 'kOptionsFormatter', 'options' => Array (1 => 'Windows', 2 => 'UNIX'), 'default' => 1),
 		'LineEndingsInside' => Array ('type' => 'int', 'formatter' => 'kOptionsFormatter', 'options' => Array (1 => 'CRLF', 2 => 'LF'), 'default' => 2),
 		'IncludeFieldTitles' => Array (
 			'type' => 'int',
 			'formatter' => 'kOptionsFormatter',
 			'options' => Array (0 => 'la_No', 1 => 'la_Yes'),
 			'use_phrases' => 1, 'default' => 1,
 		),
 		'ExportColumns' => Array ('type' => 'string', 'formatter' => 'kOptionsFormatter', 'options' => Array (), 'default' => ''),
 		'AvailableColumns' => Array ('type' => 'string', 'formatter' => 'kOptionsFormatter', 'options' => Array (), 'default' => ''),
 		'CategoryFormat' => Array ('type' => 'int', 'formatter' => 'kOptionsFormatter', 'options' => Array (1 => 'la_MixedCategoryPath', 2 => 'la_SeparatedCategoryPath'), 'use_phrases' => 1, 'default' => 1),
 		'CategorySeparator' => Array ('type' => 'string', 'default' => ':'),
 		'IsBaseCategory' => Array (
 			'type' => 'int',
 			'formatter' => 'kOptionsFormatter',
 			'options' => Array (0 => 'la_No', 1 => 'la_Yes'),
 			'use_phrases' => 1, 'default' => 0,
 		),
 		// export related fields: end
 
 		// import related fields: begin
 		'FieldTitles' => Array ('type' => 'int', 'formatter' => 'kOptionsFormatter', 'options' => Array (1 => 'la_Automatic', 2 => 'la_Manual'), 'use_phrases' => 1, 'default' => 1),
 		'ImportSource' => Array ('type' => 'int', 'formatter' => 'kOptionsFormatter', 'options' => Array (1 => 'la_Upload', 2 => 'la_Local'), 'use_phrases' => 1, 'default' => 2),
 		'ImportFilename' => Array ('type' => 'string', 'formatter' => 'kUploadFormatter', 'max_size' => MAX_UPLOAD_SIZE, 'upload_dir' => EXPORT_BASE_PATH . '/', 'default' => ''),
 		'ImportLocalFilename' => Array ('type' => 'string', 'formatter' => 'kOptionsFormatter', 'default' => ''),
 		'CheckDuplicatesMethod' => Array ('type' => 'int', 'formatter' => 'kOptionsFormatter', 'options' => Array (1 => 'la_IDField', 2 => 'la_OtherFields'), 'use_phrases' => 1, 'default' => 1),
 		'ReplaceDuplicates' => Array ('type' => 'int', 'formatter' => 'kOptionsFormatter', 'options' => Array (0 => 'la_No', 1 => 'la_Yes'), 'use_phrases' => 1, 'default' => 0),
 		'DuplicateCheckFields' => Array ('type' => 'string', 'formatter' => 'kOptionsFormatter', 'options' => Array ('Name' => 'NAME'), 'default' => '|Name|'),
 		'SkipFirstRow' => Array ('type' => 'int', 'formatter' => 'kOptionsFormatter', 'options' => Array (1 => 'la_Yes', 0 => 'la_No'), 'use_phrases' => 1, 'default' => 1),
 		// import related fields: end
 
 		'ThumbnailImage' => Array ('type' => 'string', 'default' => ''),
 		'FullImage' => Array ('type' => 'string', 'default' => ''),
 		'ImageAlt' => Array ('type' => 'string', 'default' => ''),
 
 		'Filename' => Array ('type' => 'string', 'default' => ''),
 		'CachedNavbar' => Array ('type' => 'string', 'default' => ''),
 		'ParentPath' => Array ('type' => 'string', 'default' => ''),
 
 		'FileSize' => Array ('type' => 'int', 'formatter' => 'kFilesizeFormatter', 'default' => 0),
 		'FilePath' => Array ('type' => 'string', 'default' => ''),
 		'FileVersion' => Array ('type' => 'string', 'default' => ''),
 
 		// for primary image
 		'AltName' => Array ('type' => 'string', 'default' => ''),
 		'SameImages' => Array ('type' => 'string', 'default' => ''),
 		'LocalThumb' => Array ('type' => 'string', 'default' => ''),
 		'ThumbPath' => Array ('type' => 'string', 'default' => ''),
 		'ThumbUrl' => Array ('type' => 'string', 'default' => ''),
 		'LocalImage' => Array ('type' => 'string', 'default' => ''),
 		'LocalPath' => Array ('type' => 'string', 'default' => ''),
 		'FullUrl' => Array ('type' => 'string', 'default' => ''),
 	),
 
 	'Grids' => Array (
 		'Default' => Array (
 			'Icons' => Array (
 				'default' => 'icon16_product.png',
 				0 => 'icon16_product_disabled.png',
 				1 => 'icon16_product.png',
 				2 => 'icon16_product_pending.png',
 				'NEW' => 'icon16_product_new.png',
 			),
 			'Fields' => Array (
 				'ProductId' => Array ( 'title' => 'column:la_fld_Id', 'data_block' => 'grid_checkbox_td', 'filter_block' => 'grid_range_filter', 'width' => 60, ),
 				'SKU' => Array ( 'title' => 'la_col_ProductSKU', 'filter_block' => 'grid_like_filter', 'width' => 100, ),
 				'Name' => Array ( 'title' => 'la_col_ProductName', 'data_block' => 'grid_catitem_td', 'filter_block' => 'grid_like_filter', 'width' => 150, ),
 				'Priority' => Array ('filter_block' => 'grid_range_filter', 'width' => 65),
 				'Type' => Array ('title' => 'column:la_fld_ProductType', 'filter_block' => 'grid_options_filter', 'width' => 80, ),
 				'Manufacturer' => Array ('filter_block' => 'grid_like_filter', 'width' => 100, ),
 				'Price' => Array ('filter_block' => 'grid_range_filter', 'width' => 70, ),
 				'Status' => Array ('filter_block' => 'grid_options_filter', 'width' => 70, ),
 				'QtyInStock' => Array ('title' => 'column:la_fld_Qty', 'data_block' => 'qty_td', 'filter_block' => 'grid_range_filter', 'width' => 80, ),
 				'QtyBackOrdered' => Array ('title' => 'column:la_fld_QtyBackOrdered', 'filter_block' => 'grid_range_filter', 'width' => 80, ),
 				'OnSale' => Array ('title' => 'column:la_fld_OnSale', 'filter_block' => 'grid_options_filter', 'width' => 70, ),
 				/*'Weight' => Array ( 'title' => 'la_col_ProductWeight', 'filter_block' => 'grid_range_filter', 'width' => 150, ),
 				'CreatedOn' => Array ( 'title' => 'la_col_ProductCreatedOn', 'filter_block' => 'grid_date_range_filter', 'width' => 150, ),
 				'BackOrderDate' => Array ( 'title' => 'la_col_ProductBackOrderDate', 'filter_block' => 'grid_date_range_filter', 'width' => 150, ),*/
 			),
 		),
 
 		'Radio' => Array (
 			'Icons' => Array (
 				'default' => 'icon16_product.png',
 				0 => 'icon16_product_disabled.png',
 				1 => 'icon16_product.png',
 				2 => 'icon16_product_pending.png',
 				'NEW' => 'icon16_product_new.png',
 			),
 			'Selector' => 'radio',
 			'Fields' => Array (
 				'ProductId' => Array ( 'title' => 'column:la_fld_Id', 'data_block' => 'grid_radio_td', 'filter_block' => 'grid_range_filter', 'width' => 60, ),
 				'SKU' => Array ( 'title' => 'la_col_ProductSKU', 'filter_block' => 'grid_like_filter', 'width' => 100, ),
 				'Name' => Array ( 'title' => 'la_col_ProductName', 'data_block' => 'grid_catitem_td', 'filter_block' => 'grid_like_filter', 'width' => 150, ),
 				'Priority' => Array ('filter_block' => 'grid_range_filter', 'width' => 65),
 				'Type' => Array ('title' => 'column:la_fld_ProductType', 'filter_block' => 'grid_options_filter', 'width' => 80, ),
 				'Manufacturer' => Array ('filter_block' => 'grid_like_filter', 'width' => 100, ),
 				'Price' => Array ('filter_block' => 'grid_range_filter', 'width' => 70, ),
 				'Status' => Array ('filter_block' => 'grid_options_filter', 'width' => 70, ),
 				'QtyInStock' => Array ('title' => 'column:la_fld_Qty', 'data_block' => 'qty_td', 'filter_block' => 'grid_range_filter', 'width' => 80, ),
 				'QtyBackOrdered' => Array ('title' => 'column:la_fld_QtyBackOrdered', 'filter_block' => 'grid_range_filter', 'width' => 80, ),
 
 			),
 		),
 	),
 
 	'ConfigMapping' => Array (
 		'PerPage' => 'Comm_Perpage_Products',
 		'ShortListPerPage' => 'Comm_Perpage_Products_Short',
 		'ForceEditorPick' => 'products_EditorPicksAboveRegular',
 		'DefaultSorting1Field' => 'product_OrderProductsBy',
 		'DefaultSorting2Field' => 'product_OrderProductsThenBy',
 		'DefaultSorting1Dir' => 'product_OrderProductsByDir',
 		'DefaultSorting2Dir' => 'product_OrderProductsThenByDir',
 
 		'RatingDelayValue' => 'product_RatingDelay_Value',
 		'RatingDelayInterval' => 'product_RatingDelay_Interval',
 	),
 );
\ No newline at end of file
Index: branches/5.3.x/units/affiliates/affiliates_config.php
===================================================================
--- branches/5.3.x/units/affiliates/affiliates_config.php	(revision 15670)
+++ branches/5.3.x/units/affiliates/affiliates_config.php	(revision 15671)
@@ -1,241 +1,241 @@
 <?php
 /**
 * @version	$Id$
 * @package	In-Commerce
 * @copyright	Copyright (C) 1997 - 2009 Intechnic. All rights reserved.
 * @license	Commercial License
 * This software is protected by copyright law and international treaties.
 * Unauthorized reproduction or unlicensed usage of the code of this program,
 * or any portion of it may result in severe civil and criminal penalties,
 * and will be prosecuted to the maximum extent possible under the law
 * See http://www.in-portal.org/commercial-license for copyright notices and details.
 */
 
 defined('FULL_PATH') or die('restricted access!');
 
 $config = Array (
 	'Prefix' => 'affil',
 	'ItemClass' => Array ('class' => 'kDBItem', 'file' => '', 'build_event' => 'OnItemBuild'),
 	'ListClass' => Array ('class' => 'kDBList', 'file' => '', 'build_event' => 'OnListBuild'),
 	'EventHandlerClass' => Array ('class' => 'AffiliatesEventHandler', 'file' => 'affiliates_event_handler.php', 'build_event' => 'OnBuild'),
 	'TagProcessorClass' => Array ('class' => 'AffiliatesTagProcessor', 'file' => 'affiliates_tag_processor.php', 'build_event' => 'OnBuild'),
 
 	'AutoLoad' => true,
 
 	'Hooks' => Array (
 		Array (
 			'Mode' => hAFTER,
 			'Conditional' => false,
 			'HookToPrefix' => 'u',
 			'HookToSpecial' => 'register',
 			'HookToEvent' => Array ('OnBeforeItemCreate', 'OnBeforeItemUpdate'),
 			'DoPrefix' => '',
 			'DoSpecial' => 'register',
 			'DoEvent' => 'OnValidateAffiliate',
 		),
 
 		Array (
 			'Mode' => hAFTER,
 			'Conditional' => false,
 			'HookToPrefix' => 'u',
 			'HookToSpecial' => 'register',
 			'HookToEvent' => Array ('OnCreate'),
 			'DoPrefix' => '',
 			'DoSpecial' => 'register',
 			'DoEvent' => 'OnRegisterAffiliate',
 		),
 
 		Array (
 			'Mode' => hAFTER,
 			'Conditional' => false,
 			'HookToPrefix' => 'adm',
 			'HookToSpecial' => '',
 			'HookToEvent' => Array ('OnStartup'),
 			'DoPrefix' => '',
 			'DoSpecial' => '',
 			'DoEvent' => 'OnResetStatistics',
 		),
 
 		Array (
 			'Mode' => hAFTER,
 			'Conditional' => false,
 			'HookToPrefix' => 'adm',
 			'HookToSpecial' => '',
 			'HookToEvent' => Array ('OnStartup'),
 			'DoPrefix' => '',
 			'DoSpecial' => '',
 			'DoEvent' => 'OnStoreAffiliate',
 		),
 	),
 
 	'AggregateTags' => Array (
 		Array (
 			'AggregateTo' => 'u',
 			'AggregatedTagName' => 'IsAffiliate',
 			'LocalTagName' => 'User_IsAffiliate',
 		),
 		Array (
 			'AggregateTo' => 'u',
 			'AggregatedTagName' => 'AffiliateIsActive',
 			'LocalTagName' => 'User_AffiliateIsActive',
 		),
 		Array (
 			'AggregateTo' => 'u',
 			'AggregatedTagName' => 'AffiliateField',
 			'LocalTagName' => 'CurrentUserAffiliateField',
 		),
 		Array (
 			'AggregateTo' => 'u',
 			'AggregatedTagName' => 'IsAffiliateOrRegisterAsAffiliateAllowed',
 			'LocalTagName' => 'IsAffiliateOrRegisterAsAffiliateAllowed',
 		),
 		Array (
 			'AggregateTo' => 'm',
 			'AggregatedTagName' => 'RequireAffiliate',
 			'LocalTagName' => 'Main_RequireAffiliate',
 		),
 		Array (
 			'AggregateTo' => 'm',
 			'AggregatedTagName' => 'AllowAffiliateRegistration',
 			'LocalTagName' => 'AllowAffiliateRegistration',
 		),
 	),
 
 	'QueryString' => Array (
 		1 => 'id',
 		2 => 'Page',
 		3 => 'PerPage',
 		4 => 'event',
 		5 => 'mode',
 	),
 
 	'IDField' => 'AffiliateId',
 	'StatusField' => Array ('Status'),	// field, that is affected by Approve/Decline events
 
 	'TitleField' => 'UserName',
 	'TitlePresets' => Array (
 		'default' => Array (
 			'new_status_labels' => Array ('affil' => '!la_title_Adding_Affiliate!'),
 			'edit_status_labels' => Array ('affil' => '!la_title_Editing_Affiliate!'),
 			'new_titlefield' => Array ('affil' => '!la_title_New_Affiliate!'),
 		),
 
 		'affiliates_list' => Array ('prefixes' => Array ('affil_List'), 'format' => "!la_title_Affiliates!"),
 		'affiliates_edit' => Array ('prefixes' => Array ('affil'), 'format' => "#affil_status# '#affil_titlefield#' - !la_title_General!"),
 		'affiliate_payments' => Array ('prefixes' => Array ('affil', 'apayments_List'), 'format' => "#affil_status# '#affil_titlefield#' - !la_title_Payments!"),
 		'affiliates_payout' => Array ('prefixes' => Array ('affil', 'apayments'), 'format' => "!la_title_PayOut_To! '#affil_titlefield#'"),
 	),
 
 	'Forms' => Array (
 		'registration' => Array (
 			'VirtualFields' => Array (
 				'TermsAccepted' => Array (
 					'type' => 'int',
 					'formatter' => 'kOptionsFormatter', 'options' => Array (1 => 'la_Yes', 0 => 'la_No'), 'use_phrases' => 1,
 					'error_msgs' => Array ('required' => '!lu_comm_MustAgreeAffiliateTermsError!'),
 					'required' => 1, 'default' => NULL,
 				),
 			)
 		),
 	),
 
 	'EditTabPresets' => Array (
 		'Default' => Array (
 			'general' => Array ('title' => 'la_tab_General', 't' => 'in-commerce/affiliate_plans/affiliates_edit', 'priority' => 1),
 			'payments' => Array ('title' => 'la_tab_Payments', 't' => 'in-commerce/affiliate_plans/affiliate_edit_payments', 'priority' => 2),
 		),
 	),
 
 	'PermSection' => Array ('main' => 'in-commerce:affiliates'),
 
 	'Sections' => Array (
 		'in-commerce:affiliates_folder' => Array (
 			'parent' => 'in-commerce',
 			'icon' => 'affiliates',
 			'label' => 'la_tab_Affiliates',
 			'use_parent_header' => 1,
 			'permissions' => Array (),
 			'priority' => 5,
 			'type' => stTREE,
 		),
 
 		'in-commerce:affiliates' => Array (
 			'parent' => 'in-commerce:affiliates_folder',
 			'icon' => 'affiliates',
 			'label' => 'la_tab_Affiliates',
 			'url' => Array ('t' => 'in-commerce/affiliate_plans/affiliates_list', 'pass' => 'm'),
 			'permissions' => Array ('view', 'add', 'edit', 'delete', 'advanced:approve', 'advanced:decline'),
 			'priority' => 5.1, // <parent_priority>.<own_priority>, because this section replaces parent in tree
 			'type' => stTAB,
 		),
 	),
 
 	'TableName' => TABLE_PREFIX.'Affiliates',
 
 	'CalculatedFields' => Array (
 		'' => Array (
 			'UserId' => 'u.PortalUserId',
-			'UserName' => 'IF( LENGTH(u.Username), u.Username, \'\')',
+			'UserName' => 'IF(u.Username = "", u.Email, u.Username)',
 			'PlanName' => 'ap.Name',
 		),
 	),
 
 	'ListSQLs' => Array (
 		'' => '	SELECT %1$s.* %2$s
 				FROM %1$s
 				LEFT JOIN '.TABLE_PREFIX.'Users u ON %1$s.PortalUserId = u.PortalUserId
 				LEFT JOIN '.TABLE_PREFIX.'AffiliatePlans ap ON %1$s.AffiliatePlanId = ap.AffiliatePlanId'
 	),
 
 	'SubItems' => Array ('apayments'),
 
 	'ListSortings' => Array (
 		'' => Array (
 			'Sorting' => Array ('CreatedOn' => 'desc', 'UserName' => 'asc'),
 		)
 	),
 
 	'Fields' => Array (
 		'AffiliateId' => Array ('type' => 'int', 'not_null' => 1, 'default' => 0),
-		'PortalUserId' => Array ('type' => 'int',  'unique'=>Array ('PortalUserId'), 'formatter' => 'kLEFTFormatter', 'error_msgs' => Array ('invalid_option' => '!la_error_UserNotFound!', 'unique' => '!la_affiliate_already_exists!'), 'options' => Array (USER_ROOT => 'root', USER_GUEST => 'Guest'),'left_sql' => 'SELECT %s FROM '.TABLE_PREFIX.'Users WHERE `%s` = \'%s\'', 'left_key_field' => 'PortalUserId', 'left_title_field' => 'Username', 'required' => 1, 'not_null' => 1, 'default' => 0, ),
+		'PortalUserId' => Array ('type' => 'int', 'unique' => Array (), 'formatter' => 'kLEFTFormatter', 'error_msgs' => Array ('invalid_option' => '!la_error_UserNotFound!', 'unique' => '!la_affiliate_already_exists!'), 'options' => Array (USER_ROOT => 'root', USER_GUEST => 'Guest'), 'left_sql' => 'SELECT %s FROM ' . TABLE_PREFIX . 'Users WHERE %s', 'left_key_field' => 'PortalUserId', 'left_title_field' => USER_TITLE_FIELD, 'required' => 1, 'default' => null),
 		'AffiliatePlanId' => Array ('type' => 'int', 'formatter' => 'kOptionsFormatter', 'options_sql' => 'SELECT Name, AffiliatePlanId FROM '.TABLE_PREFIX.'AffiliatePlans WHERE Enabled = 1 ORDER BY Name', 'option_key_field' => 'AffiliatePlanId', 'option_title_field' => 'Name', 'not_null' => 1, 'default' => 0),
 		'AccumulatedAmount' => Array ('type' => 'double', 'formatter' => 'kFormatter', 'format' => '%.02f', 'not_null' => '1', 'default' => '0.00'),
 		'AmountToPay' => Array ('type' => 'double', 'formatter' => 'kFormatter', 'format' => '%.02f', 'not_null' => '1', 'default' => '0.00'),
 		'LastPaymentDate' => Array ('type' => 'int', 'formatter' => 'kDateFormatter', 'default' => NULL),
 		'LastOrderDate' => Array ('type' => 'int', 'formatter' => 'kDateFormatter', 'default' => NULL),
 		'Status' => Array ('type' => 'int', 'formatter' => 'kOptionsFormatter', 'options'=>Array (1=>'la_Active', 2=>'la_Pending', 0=>'la_Disabled'), 'use_phrases'=>1, 'not_null' => '1', 'default' => STATUS_PENDING),
 		'AffiliateCode' => Array ('type' => 'string', 'not_null' => '1', 'default' => ''),
 		'ItemsSold' => Array ('type' => 'int', 'not_null' => 1, 'default' => 0),
 		'PaymentTypeId' => Array ('type' => 'int', 'formatter' => 'kOptionsFormatter', 'options' => Array (0 => ''), 'options_sql' => 'SELECT Name, PaymentTypeId FROM '.TABLE_PREFIX.'AffiliatePaymentTypes WHERE Status = 1 ORDER BY IsPrimary DESC, Priority DESC, Name ASC', 'option_key_field' => 'PaymentTypeId', 'option_title_field' => 'Name', 'not_null' => 1, 'default' => 0),
 		'SSN' => Array ('type' => 'string', 'not_null' => '1', 'default' => '', 'required' => 1),
 		'Comments' => Array ('type' => 'string', 'formatter' => 'kFormatter', 'using_fck' => 1, 'default' => NULL),
 		'CreatedOn' => Array ('type' => 'int', 'formatter' => 'kDateFormatter', 'default' => '#NOW#'),
 	),
 
 	'VirtualFields' => Array (
 		'UserName' => Array ('type' => 'string', 'default' => ''),
 		'PlanName' => Array ('type' => 'string', 'default' => ''),
 		'UserId' => Array ('type' => 'int', 'default' => 0),
 	),
 
 	'Grids' => Array (
 		'Default' => Array (
 			'Icons' => Array (
 				'default' => 'icon16_item.png',
 				0 => 'icon16_disabled.png',
 				1 => 'icon16_item.png',
 				2 => 'icon16_pending.png',
 				'module' => 'core',
 			),
 			'Fields' => Array (
 				'AffiliateId' => Array ( 'title' => 'column:la_fld_Id', 'data_block' => 'grid_checkbox_td', 'filter_block' => 'grid_range_filter', 'width' => 60, ),
 				'UserName' => Array ( 'data_block' => 'grid_userlink_td', 'filter_block' => 'grid_like_filter'),
 				'PlanName' => Array ( 'title' => 'la_col_PlanName', 'filter_block' => 'grid_like_filter'),
 
 				'PaymentTypeId' => Array ( 'title' => 'column:la_fld_PaymentType', 'filter_block' => 'grid_options_filter', 'width' => 120, ),
 				'CreatedOn' => Array ( 'title' => 'column:la_fld_RegisteredOn', 'format' => '_regional_DateFormat', 'filter_block' => 'grid_date_range_filter', 'width' => 140, ),
 				'Status' => Array ( 'filter_block' => 'grid_options_filter', 'width' => 100, ),
 			),
 		),
 	),
 );
\ No newline at end of file
Index: branches/5.3.x/units/affiliates/affiliates_event_handler.php
===================================================================
--- branches/5.3.x/units/affiliates/affiliates_event_handler.php	(revision 15670)
+++ branches/5.3.x/units/affiliates/affiliates_event_handler.php	(revision 15671)
@@ -1,663 +1,663 @@
 <?php
 /**
 * @version	$Id$
 * @package	In-Commerce
 * @copyright	Copyright (C) 1997 - 2009 Intechnic. All rights reserved.
 * @license	Commercial License
 * This software is protected by copyright law and international treaties.
 * Unauthorized reproduction or unlicensed usage of the code of this program,
 * or any portion of it may result in severe civil and criminal penalties,
 * and will be prosecuted to the maximum extent possible under the law
 * See http://www.in-portal.org/commercial-license for copyright notices and details.
 */
 
 	defined('FULL_PATH') or die('restricted access!');
 
 	class AffiliatesEventHandler extends kDBEventHandler {
 
 		/**
 		 * Allows to override standard permission mapping
 		 *
 		 * @return void
 		 * @access protected
 		 * @see kEventHandler::$permMapping
 		 */
 		protected function mapPermissions()
 		{
 			parent::mapPermissions();
 
 			$permissions = Array (
 				'OnItemBuild' => Array ('self' => true),
 			);
 
 			$this->permMapping = array_merge($this->permMapping, $permissions);
 		}
 
 		/**
 		 * Checks user permission to execute given $event
 		 *
 		 * @param kEvent $event
 		 * @return bool
 		 * @access public
 		 */
 		public function CheckPermission(kEvent $event)
 		{
 			if ( $event->Name == 'OnBecomeAffiliate' || $event->Name == 'OnChangePaymentType' ) {
 				return $this->Application->LoggedIn() && $this->Application->ConfigValue('Comm_RegisterAsAffiliate');
 			}
 
 			return parent::CheckPermission($event);
 		}
 
 		/**
 		 * Allows to get ID of affiliate record, associated with currently logged-in user
 		 *
 		 * @param kEvent $event
 		 * @return int
 		 * @access public
 		 */
 		public function getPassedID(kEvent $event)
 		{
 			if ( $event->Special == 'user' ) {
 				$event->setEventParam('raise_warnings', 0);
 
 				$sql = 'SELECT ' . $this->Application->getUnitOption($event->Prefix, 'IDField') . '
 						FROM ' . $this->Application->getUnitOption($event->Prefix, 'TableName') . '
 						WHERE PortalUserId = ' . (int)$this->Application->RecallVar('user_id');
 				$id = $this->Conn->GetOne($sql);
 
 				if ( $id ) {
 					return $id;
 				}
 			}
 
 			return parent::getPassedID($event);
 		}
 
 		/**
 		 * Generate new affiliate code
 		 *
 		 * @param kEvent $event
 		 * @return string
 		 */
 		function generateAffiliateCode($event)
 		{
 			// accepts 1 - 36
 			$number_length = 11;
 			$num_chars = Array(	'1'=>'a','2'=>'b','3'=>'c','4'=>'d','5'=>'e','6'=>'f',
 								'7'=>'g','8'=>'h','9'=>'i','10'=>'j','11'=>'k','12'=>'l',
 								'13'=>'m','14'=>'n','15'=>'o','16'=>'p','17'=>'q','18'=>'r',
 								'19'=>'s','20'=>'t','21'=>'u','22'=>'v','23'=>'w','24'=>'x',
 								'25'=>'y','26'=>'z','27'=>'0','28'=>'1','29'=>'2','30'=>'3',
 								'31'=>'4','32'=>'5','33'=>'6','34'=>'7','35'=>'8','36'=>'9');
 
 			$ret = '';
 			for($i=1; $i<=$number_length; $i++)
 			{
 				mt_srand((double)microtime() * 1000000);
 				$num = mt_rand(1,36);
 				$ret .= $num_chars[$num];
 			}
 			$ret = strtoupper($ret);
 
 			$id_field = $this->Application->getUnitOption($event->Prefix, 'IDField');
 			$table = $this->Application->getUnitOption($event->Prefix, 'TableName');
 
 			$sql = 'SELECT %s FROM %s WHERE AffiliateCode = %s';
 			$code_found = $this->Conn->GetOne( sprintf($sql, $id_field, $table, $this->Conn->qstr($ret) ) );
 			if($code_found) return $this->generateAffiliateCode($event);
 
 			return $ret;
 		}
 
 		/**
 		 * Creates new affiliate code when new affiliate is created
 		 *
 		 * @param kEvent $event
 		 * @return void
 		 * @access protected
 		 */
 		protected function OnBeforeItemCreate(kEvent $event)
 		{
 			parent::OnBeforeItemCreate($event);
 
 			$object = $event->getObject();
 			/* @var $object kDBItem */
 
 			$object->SetDBField('AffiliateCode', $this->generateAffiliateCode($event));
 
 			if ( $object->getFormName() == 'registration' ) {
 				if ( $this->Application->LoggedIn() ) {
 					$object->SetDBField('PortalUserId', $this->Application->RecallVar('user_id'));
 				}
 
 				$object->SetDBField('AffiliatePlanId', $this->_getPrimaryAffiliatePlan());
 			}
 		}
 
 		/**
 		 * Ensures, that user can only update his affiliate record
 		 *
 		 * @param kEvent $event
 		 * @return void
 		 * @access protected
 		 */
 		protected function OnBeforeItemUpdate(kEvent $event)
 		{
 			parent::OnBeforeItemUpdate($event);
 
 			if ( !$this->Application->isAdmin ) {
 				$object = $event->getObject();
 				/* @var $object kDBItem */
 
 				$object->SetDBField('PortalUserId', $object->GetOriginalField('PortalUserId'));
 
 				if ( $object->GetDBField('PortalUserId') != $this->Application->RecallVar('user_id') ) {
 					$object->SetError('PortalUserId', 'not_owner');
 				}
 			}
 		}
 
 		/**
 		 * [HOOK] Stores affiliate id using method from Config (session or cookie) if correct code is present in url
 		 *
 		 * @param kEvent $event
 		 * @return bool
 		 */
 		function OnStoreAffiliate($event)
 		{
 			if ( defined('IS_INSTALL') && IS_INSTALL ) {
 				return;
 			}
 
 			$object = $this->Application->recallObject($event->Prefix . '.-item', null, Array ('skip_autoload' => true));
 			/* @var $object kDBItem */
 
 			$affiliate_storage_method = $this->Application->ConfigValue('Comm_AffiliateStorageMethod');
 
 			$affiliate = $this->Application->GetVar('affiliate');
 			if ( $affiliate ) {
 				$object->Load($affiliate, 'AffiliateCode');
 			}
 			elseif ( $affiliate_storage_method == 2 ) {
 				$affiliate_id = $this->Application->GetVar('affiliate_id');
 				$object->Load($affiliate_id);
 			}
 
 			if ( $object->isLoaded() && ($object->GetDBField('Status') == 1) ) {
 				// user is found with such email
 				$affiliate_user = $this->Application->recallObject('u.affiliate', null, Array ('skip_autoload' => true));
 				/* @var $affiliate_user UsersItem */
 
 				$affiliate_user->Load($object->GetDBField('PortalUserId'));
 
 				if ( $affiliate_user->GetDBField('Status') == 1 ) {
 					$affiliate_id = $object->GetDBField('AffiliateId');
 					$this->Application->setVisitField('AffiliateId', $affiliate_id);
 
 					if ( $affiliate_storage_method == 1 ) {
 						$this->Application->StoreVar('affiliate_id', $affiliate_id); // per session
 					}
 					else {
 						// in cookie
 						$this->Application->Session->SetCookie('affiliate_id', $affiliate_id, $this->getCookieExpiration());
 					}
 				}
 			}
 		}
 
 		/**
 		 * Returns affiliate cookie expiration date
 		 *
 		 * @return int
 		 */
 		function getCookieExpiration()
 		{
 			$expire = $this->Application->ConfigValue('Comm_AffiliateCookieDuration'); // days
 			return adodb_mktime() + $expire * 24 * 60 * 60;
 		}
 
 		/**
 		 * Calculate what amount is earned by affiliate based on it's affiliate plan & store it
 		 *
 		 * @param kEvent $event
 		 * @author Alex
 		 */
 		function OnOrderApprove($event)
 		{
 			$order = $this->Application->recallObject($event->getEventParam('Order_PrefixSpecial'));
 			/* @var $order OrdersItem */
 
 			$affiliate_id = $order->GetDBField('AffiliateId');
 			if ( !$affiliate_id ) {
 				return false;
 			}
 
 			$object = $event->getObject(Array ('ship_autoload' => true));
 			/* @var $object kDBItem */
 
 			if ( $object->Load($affiliate_id) ) {
 				$affiliate_plan = $this->Application->recallObject('ap', null, Array ('skip_autoload' => true));
 				/* @var $affiliate_plan kDBItem */
 
 				$affiliate_plan->Load($object->GetDBField('AffiliatePlanId'));
 
 				if ( $affiliate_plan->isLoaded() ) {
 					$sql = 'SELECT SUM(Quantity) FROM %s WHERE OrderId = %s';
 					$orderitems_table = $this->Application->getUnitOption('orditems', 'TableName');
 					$items_sold = $this->Conn->GetOne(sprintf($sql, $orderitems_table, $order->GetID()));
 
 					$object->SetDBField('AccumulatedAmount', $object->GetDBField('AccumulatedAmount') + $order->GetDBField('TotalAmount'));
 					$object->SetDBField('ItemsSold', $object->GetDBField('ItemsSold') + $items_sold);
 
 					switch ($affiliate_plan->GetDBField('PlanType')) {
 						case 1: // by amount
 							$value = $object->GetDBField('AccumulatedAmount');
 							break;
 
 						case 2: // by items sold (count)
 							$value = $object->GetDBField('ItemsSold');
 							break;
 					}
 
 					$apb_table = $this->Application->getUnitOption('apbrackets', 'TableName');
 					$sql = 'SELECT Percent FROM %1$s WHERE (%2$s >= FromAmount) AND ( (%2$s <= ToAmount) OR (ToAmount = -1) ) AND (AffiliatePlanId = %3$s)';
 					$commission_percent = $this->Conn->GetOne(sprintf($sql, $apb_table, $this->Conn->qstr($value), $affiliate_plan->GetID()));
 
 					// process only orders of current affiliate from period start to this order date
 					$period_ends = $order->GetDBField('OrderDate');
 					$period_starts = $this->getPeriodStartTS($period_ends, $affiliate_plan->GetDBField('ResetInterval'));
 
 					$sql = 'SELECT AffiliateCommission, (SubTotal+ShippingCost+VAT) AS TotalAmount, OrderId
 							FROM ' . $order->TableName . '
 							WHERE OrderDate >= %s AND OrderDate <= %s AND AffiliateId = ' . $affiliate_id;
 
 					$amount_to_pay_before = 0;
 					$amount_to_pay_after = 0;
 					$order_update_sql = 'UPDATE ' . $order->TableName . ' SET AffiliateCommission = %s WHERE ' . $order->IDField . ' = %s';
 					$orders = $this->Conn->Query(sprintf($sql, $period_starts, $period_ends), 'OrderId');
 					if ( $orders ) {
 						foreach ($orders as $order_id => $order_data) {
 							$amount_to_pay_before += $order_data['AffiliateCommission'];
 							$commission = $order_data['TotalAmount'] * ($commission_percent / 100);
 							$this->Conn->Query(sprintf($order_update_sql, $this->Conn->qstr($commission), $order_id));
 							$amount_to_pay_after += $commission;
 						}
 
 
 					}
 					$object->SetDBField('AmountToPay', $object->GetDBField('AmountToPay') - $amount_to_pay_before + $amount_to_pay_after);
 					$object->SetDBField('LastOrderDate_date', $order->GetDBField('OrderDate_date'));
 					$object->SetDBField('LastOrderDate_time', $order->GetDBField('OrderDate_time'));
 					$object->Update();
 
 					$order->SetDBField('AffiliateCommission', $commission); // set last commission to this order, because ApproveEvent was called for him
 				}
 			}
 		}
 
 		/**
 		 * [HOOK] Validates affiliate fields on user registration form
 		 *
 		 * @param kEvent $event
 		 * @return void
 		 * @access protected
 		 */
 		protected function OnValidateAffiliate($event)
 		{
 			if ( $this->Application->GetVar('RegisterAsAffiliate') != 'on' || $event->MasterEvent->status != kEvent::erSUCCESS ) {
 				return;
 			}
 
 			$object = $event->getObject( Array('form_name' => 'registration', 'skip_autoload' => true) );
 			/* @var $object kDBItem */
 
 			$field_values = $this->getSubmittedFields($event);
 			$object->SetFieldsFromHash($field_values, $this->getRequestProtectedFields($field_values));
 			$object->setID(0);
 
 			if ( !$object->Validate() ) {
 				$user = $event->MasterEvent->getObject();
 				/* @var $user kDBItem */
 
 				$user->Validate();
 
 				$event->MasterEvent->status = kEvent::erFAIL;
 			}
 		}
 
 		/**
 		 * [AFTER HOOK] to u:OnCreate
 		 *
 		 * @param kEvent $event
 		 */
 		function OnRegisterAffiliate($event)
 		{
 			if ( $this->Application->GetVar('RegisterAsAffiliate') != 'on' || $event->MasterEvent->status != kEvent::erSUCCESS ) {
 				return;
 			}
 
 			$object = $event->getObject();
 			/* @var $object kDBItem */
 
 			$user = $event->MasterEvent->getObject();
 			/* @var $user UsersItem */
 
 			$object->SetDBField('PortalUserId', $user->GetID());
 
 			if ( $object->Create() ) {
-				$this->Application->EmailEventUser('AFFILIATE.REGISTER', $user->GetID());
-				$this->Application->EmailEventAdmin('AFFILIATE.REGISTER');
+				$this->Application->emailUser('AFFILIATE.REGISTER', $user->GetID());
+				$this->Application->emailAdmin('AFFILIATE.REGISTER');
 			}
 		}
 
 		/**
 		 * Returns primary affiliate plan
 		 *
 		 * @return int
 		 * @access protected
 		 */
 		protected function _getPrimaryAffiliatePlan()
 		{
 			$sql = 'SELECT AffiliatePlanId
 					FROM ' . $this->Application->getUnitOption('ap', 'TableName') . '
 					WHERE IsPrimary = 1';
 
 			return (int)$this->Conn->GetOne($sql);
 		}
 
 		/**
 		 * Creates affiliate record for logged-in user
 		 *
 		 * @param kEvent $event
 		 */
 		function OnBecomeAffiliate($event)
 		{
 			$object = $event->getObject( Array('form_name' => 'registration', 'skip_autoload' => true) );
 			/* @var $object UsersItem */
 
 			$event->CallSubEvent('OnCreate');
 
 			if ( $event->status == kEvent::erSUCCESS ) {
 				$event->SetRedirectParam('opener', 's');
 
 				$next_template = $this->Application->GetVar('next_template');
 
 				if ( $next_template ) {
 					$event->redirect = $next_template;
 				}
 			}
 		}
 
 		/**
 		 * Change affiliate payment type of affiliate record associated with logged-in user
 		 *
 		 * @param kEvent $event
 		 * @return void
 		 * @access protected
 		 */
 		protected function OnChangePaymentType($event)
 		{
 			$event->CallSubEvent('OnUpdate');
 
 			if ( $event->status == kEvent::erSUCCESS ) {
 				$object = $event->getObject();
 				/* @var $object kDBItem */
 
-				$this->Application->EmailEventUser('AFFILIATE.PAYMENT.TYPE.CHANGED', $object->GetDBField('PortalUserId'));
-				$this->Application->EmailEventAdmin('AFFILIATE.PAYMENT.TYPE.CHANGED');
+				$this->Application->emailUser('AFFILIATE.PAYMENT.TYPE.CHANGED', $object->GetDBField('PortalUserId'));
+				$this->Application->emailAdmin('AFFILIATE.PAYMENT.TYPE.CHANGED');
 
 				$next_template = $this->Application->GetVar('next_template');
 
 				if ( $next_template ) {
 					$event->redirect = $this->Application->GetVar('next_template');
 				}
 
 				$event->SetRedirectParam('opener', 's');
 			}
 		}
 
 		/**
 		 * If new payments made, then send email about that
 		 *
 		 * @param kEvent $event
 		 * @return void
 		 * @access protected
 		 */
 		protected function OnBeforeDeleteFromLive(kEvent $event)
 		{
 			parent::OnBeforeDeleteFromLive($event);
 
 			$payment_object = $this->Application->recallObject('apayments', 'apayments', Array ('skip_autoload' => true));
 			/* @var $payment_object kDBItem */
 
 			$id = $event->getEventParam('id');
 			$ap_table = $this->Application->getUnitOption('apayments', 'TableName');
 
 			$sql = 'SELECT AffiliatePaymentId
 					FROM ' . $ap_table . '
 					WHERE AffiliateId = ' . $id;
 			$live_ids = $this->Conn->GetCol($sql);
 
 			$sql = 'SELECT AffiliatePaymentId
 					FROM ' . $payment_object->TableName . '
 					WHERE AffiliateId = ' . $id;
 			$temp_ids = $this->Conn->GetCol($sql);
 
 			$new_ids = array_diff($temp_ids, $live_ids);
 
 			foreach ($new_ids as $payment_id) {
 				$payment_object->Load($payment_id);
-				$this->Application->EmailEventUser('AFFILIATE.PAYMENT', $payment_object->GetDBField('PortalUserId'));
-				$this->Application->EmailEventAdmin('AFFILIATE.PAYMENT');
+				$this->Application->emailUser('AFFILIATE.PAYMENT', $payment_object->GetDBField('PortalUserId'));
+				$this->Application->emailAdmin('AFFILIATE.PAYMENT');
 			}
 
 			$object = $event->getObject();
 			/* @var $object kDBItem */
 
 			$passed_id = $event->getEventParam('id');
 
 			if ( $object->GetID() != $passed_id ) {
 				$object->Load($passed_id);
 			}
 
 			$sql = 'SELECT Status
 					FROM ' . $this->Application->getUnitOption($event->Prefix, 'TableName') . '
 					WHERE ' . $object->IDField . ' = ' . $object->GetID();
 			$old_status = $this->Conn->GetOne($sql);
 
 			if ( $old_status == 2 && $object->GetDBField('Status') == 1 ) {
-				$this->Application->EmailEventUser('AFFILIATE.REGISTRATION.APPROVED', $object->GetDBField('PortalUserId'));
-				$this->Application->EmailEventAdmin('AFFILIATE.REGISTRATION.APPROVED');
+				$this->Application->emailUser('AFFILIATE.REGISTRATION.APPROVED', $object->GetDBField('PortalUserId'));
+				$this->Application->emailAdmin('AFFILIATE.REGISTRATION.APPROVED');
 			}
 		}
 
 		/**
 		 * [HOOK] Resets statistics (accumulated amount & items sold) for affiliates based on ResetInterval in their plan
 		 *
 		 * @param kEvent $event
 		 * @author Alex
 		 */
 		function OnResetStatistics($event)
 		{
 			if ( defined('IS_INSTALL') && IS_INSTALL ) {
 				return;
 			}
 
 			$intervals = Array (86400 => 'la_day', 604800 => 'la_week', 2628000 => 'la_month', 7884000 => 'la_quartely', 31536000 => 'la_year');
 
 			$affiliates_table = $this->Application->getUnitOption($event->Prefix, 'TableName');
 			$affiliate_plan_table = $this->Application->getUnitOption('ap', 'TableName');
 
 			$base_time = adodb_mktime();
 			$where_clause = Array ();
 
 			foreach ($intervals as $interval_length => $interval_description) {
 				$start_timestamp = $this->getPeriodStartTS($base_time, $interval_length);
 				$where_clause[] = 'ap.ResetInterval = ' . $interval_length . ' AND LastOrderDate < ' . $start_timestamp;
 			}
 
 			$sql = 'SELECT AffiliateId
 					FROM ' . $affiliates_table . ' a
 					LEFT JOIN ' . $affiliate_plan_table . ' ap ON a.AffiliatePlanId = ap.AffiliatePlanId
 					WHERE (' . implode(') OR (', $where_clause) . ')';
 			$affiliate_ids = $this->Conn->GetCol($sql);
 
 			if ( !$affiliate_ids ) {
 				return;
 			}
 
 			if ( defined('DEBUG_MODE') && DEBUG_MODE && $this->Application->isDebugMode() ) {
 				$this->Application->Debugger->appendHTML('Affiliates Pending Totals Reset: ');
 				$this->Application->Debugger->dumpVars($affiliate_ids);
 			}
 
 			$fields_hash = Array (
 				'AccumulatedAmount' => 0,
 				'ItemsSold' => 0,
 				'LastOrderDate' => $base_time,
 			);
 
 			$this->Conn->doUpdate($fields_hash, $affiliates_table, 'AffiliateId IN (' . implode(',', $affiliate_ids) . ')');
 		}
 
 		/**
 		 * Returns calendar period start timestamp based on current timestamp ($base_time) and $period_length
 		 *
 		 * @param int $base_time
 		 * @param int $period_length
 		 * @return int
 		 * @author Alex
 		 */
 		function getPeriodStartTS($base_time, $period_length)
 		{
 			$start_timestamp = 0;
 
 			switch ($period_length) {
 				case 86400: // day
 					$start_timestamp = adodb_mktime(0, 0, 0, adodb_date('m', $base_time), adodb_date('d', $base_time), adodb_date('Y', $base_time));
 					break;
 
 				case 604800: // week
 					$day_seconds = 86400;
 					$first_week_day = $this->Application->ConfigValue('FirstDayOfWeek');
 					$morning = adodb_mktime(0, 0, 0, adodb_date('m', $base_time), adodb_date('d', $base_time), adodb_date('Y', $base_time));
 					$week_day = adodb_date('w', $morning);
 					if ( $week_day == $first_week_day ) {
 						// if it is already first week day, then don't search for previous week day
 						$day_diff = 0;
 					}
 					else {
 						// this way, because sunday is 0, but not 7 as it should be
 						$day_diff = $week_day != 0 ? $week_day - $first_week_day : 7 - $first_week_day;
 					}
 					$start_timestamp = $morning - $day_diff * $day_seconds;
 					break;
 
 				case 2628000: // month
 					$start_timestamp = adodb_mktime(0, 0, 0, adodb_date('m', $base_time), 1, adodb_date('Y', $base_time));
 					break;
 
 				case 7884000: // quartal
 					$first_quartal_month = (ceil(adodb_date('m', $base_time) / 3) - 1) * 3 + 1;
 					$start_timestamp = adodb_mktime(0, 0, 0, $first_quartal_month, 1, adodb_date('Y', $base_time));
 					break;
 
 				case 31536000:
 					$start_timestamp = adodb_mktime(0, 0, 0, 1, 1, adodb_date('Y', $base_time));
 					break;
 			}
 
 			return $start_timestamp;
 		}
 
 		/**
 		 * Apply same processing to each item being selected in grid
 		 *
 		 * @param kEvent $event
 		 * @return void
 		 * @access protected
 		 */
 		protected function iterateItems(kEvent $event)
 		{
 			if ( $this->Application->CheckPermission('SYSTEM_ACCESS.READONLY', 1) ) {
 				$event->status = kEvent::erFAIL;
 				return;
 			}
 
 			$object = $event->getObject(Array ('skip_autoload' => true));
 			/* @var $object kDBItem */
 
 			$ids = $this->StoreSelectedIDs($event);
 
 			if ( $ids ) {
-				$status_field = array_shift($this->Application->getUnitOption($event->Prefix, 'StatusField'));
+				$status_field = $object->getStatusField();
 
 				foreach ($ids as $id) {
 					$object->Load($id);
 
 					switch ($event->Name) {
 						case 'OnMassApprove':
 							$object->SetDBField($status_field, 1);
 							break;
 
 						case 'OnMassDecline':
 							$object->SetDBField($status_field, 0);
 							break;
 
 						case 'OnMassMoveUp':
 							$object->SetDBField('Priority', $object->GetDBField('Priority') + 1);
 							break;
 
 						case 'OnMassMoveDown':
 							$object->SetDBField('Priority', $object->GetDBField('Priority') - 1);
 							break;
 					}
 
 					if ( $object->Update() ) {
 						switch ($event->Name) {
 							case 'OnMassApprove':
-								$this->Application->EmailEventUser('AFFILIATE.REGISTRATION.APPROVED', $object->GetDBField('PortalUserId'));
-								$this->Application->EmailEventAdmin('AFFILIATE.REGISTRATION.APPROVED');
+								$this->Application->emailUser('AFFILIATE.REGISTRATION.APPROVED', $object->GetDBField('PortalUserId'));
+								$this->Application->emailAdmin('AFFILIATE.REGISTRATION.APPROVED');
 								break;
 							case 'OnMassDecline':
-								$this->Application->EmailEventUser('AFFILIATE.REGISTRATION.DENIED', $object->GetDBField('PortalUserId'));
-								$this->Application->EmailEventAdmin('AFFILIATE.REGISTRATION.DENIED');
+								$this->Application->emailUser('AFFILIATE.REGISTRATION.DENIED', $object->GetDBField('PortalUserId'));
+								$this->Application->emailAdmin('AFFILIATE.REGISTRATION.DENIED');
 								break;
 						}
 						$event->status = kEvent::erSUCCESS;
 						$event->SetRedirectParam('opener', 's'); //stay!
 					}
 					else {
 						$event->status = kEvent::erFAIL;
 						$event->redirect = false;
 						break;
 					}
 				}
 			}
 		}
 
 		/**
 		 * Checks that user in affiliate record matches current user
 		 * (non permission-based)
 		 *
 		 * @param kEvent $event
 		 * @return bool
 		 * @access protected
 		 */
 		protected function checkItemStatus(kEvent $event)
 		{
 			if ( $this->Application->isAdminUser ) {
 				return true;
 			}
 
 			$object = $event->getObject();
 			/* @var $object kDBItem */
 
 			if ( !$object->isLoaded() ) {
 				return true;
 			}
 
 			return $object->GetDBField('PortalUserId') == $this->Application->RecallVar('user_id');
 		}
 	}
\ No newline at end of file
Index: branches/5.3.x/units/taxesdestinations/taxes_dst_event_handler.php
===================================================================
--- branches/5.3.x/units/taxesdestinations/taxes_dst_event_handler.php	(revision 15670)
+++ branches/5.3.x/units/taxesdestinations/taxes_dst_event_handler.php	(revision 15671)
@@ -1,174 +1,176 @@
 <?php
 /**
 * @version	$Id$
 * @package	In-Commerce
 * @copyright	Copyright (C) 1997 - 2009 Intechnic. All rights reserved.
 * @license	Commercial License
 * This software is protected by copyright law and international treaties.
 * Unauthorized reproduction or unlicensed usage of the code of this program,
 * or any portion of it may result in severe civil and criminal penalties,
 * and will be prosecuted to the maximum extent possible under the law
 * See http://www.in-portal.org/commercial-license for copyright notices and details.
 */
 
 defined('FULL_PATH') or die('restricted access!');
 
 class TaxDstEventHandler extends kDBEventHandler {
 
 	/**
 	 * Saves items
 	 *
 	 * @param kEvent $event
 	 */
 	function OnSaveDestinations($event)
 	{
 		$object = $event->getObject(Array ('skip_autoload' => true));
 		/* @var $object kDBItem */
 
 		$items_info = $this->Application->GetVar($event->getPrefixSpecial(true));
 
 		$tax_object = $this->Application->recallObject('tax');
 		/* @var $tax_object kDBItem */
 
 		$std_dest_id = $this->Application->GetVar('StatesCountry');
 
 		if ( $items_info ) {
 			$taxdest = $this->Application->recallObject($event->getPrefixSpecial(true), null);
 			/* @var $taxdest kDBItem */
 
 			$parent_info =& $object->GetLinkedInfo();
 
 			$queryDel = "DELETE FROM " . $object->TableName . " WHERE TaxZoneId=" . $parent_info['ParentId'];
 			$this->Conn->Query($queryDel);
 
 			foreach ($items_info as $field_values) {
 				if ( $tax_object->GetDBField('Type') == 3 && (!$field_values['DestValue'] || $field_values['DestValue'] == '') ) {
 					continue;
 				}
 
 				if ( !$field_values['StdDestId'] ) {
 					$field_values['StdDestId'] = $std_dest_id;
 				}
 
 				$field_values['TaxZoneId'] = $parent_info['ParentId'];
 
 				if ( $taxdest->Load($field_values['TaxZoneDestId'], "TaxZoneDestId") ) {
 					$taxdest->SetFieldsFromHash($field_values);
 					$taxdest->Update($field_values['TaxZoneDestId']);
 				}
 				else {
 					$taxdest->SetFieldsFromHash($field_values);
 					$taxdest->Create($field_values['TaxZoneDestId']);
 				}
 			}
 		}
 	}
 
 	/**
 	 * Creates new kDBItem
 	 *
 	 * @param kEvent $event
 	 * @return void
 	 * @access protected
 	 */
 	protected function OnCreate(kEvent $event)
 	{
 		$object = $event->getObject(Array ('skip_autoload' => true));
 		/* @var $object kDBItem */
 
 		$items_info = $this->Application->GetVar($event->getPrefixSpecial(true));
 		if ( !$items_info ) {
 			return;
 		}
 
 		foreach ($items_info as $field_values) {
 			$object->SetFieldsFromHash($field_values);
 			$this->customProcessing($event, 'before');
 
 			if ( $object->Create() ) {
 				$this->customProcessing($event, 'after');
 			}
 			else {
 				$event->status = kEvent::erFAIL;
 				$event->redirect = false;
 				$this->Application->SetVar($event->getPrefixSpecial() . '_SaveEvent', 'OnCreate');
 				$object->setID(0);
 			}
 		}
 	}
 
 	/**
 	 * Apply custom processing to item
 	 *
 	 * @param kEvent $event
 	 * @param string $type
 	 * @return void
 	 * @access protected
 	 */
 	protected function customProcessing(kEvent $event, $type)
 	{
 		switch ($type) {
 			case 'before':
 				$object = $event->getObject();
 				/* @var $object kDBItem */
 
 				$events = $this->Application->GetVar('events');
 
 				if ( $events['tax'] == 'OnUpdate' ) {
 					$object->SetDBField('TaxZoneId', $this->Application->GetVar('tax_id'));
 				}
 
 				$tax_object = $this->Application->recallObject('tax');
 				/* @var $tax_object kDBItem */
 
 				if ( $tax_object->GetDBField('Type') == 3 ) {
 					$tax_object->SetDBField('StdDestId', $this->Application->GetVar('StatesCountry'));
 				}
 				break;
 		}
 	}
 
 	 /**
 	 *
 	 *
 	 * @param kEvent $event
 	 */
 	function OnZoneUpdate($event) {
 
 		$object = $event->getObject();
 		/* @var $object kDBItem */
 
-		$zone_object = &$this->Application->recallObject('tax');
+		$zone_object = $this->Application->recallObject('tax');
+		/* @var $zone_object kDBItem */
+
 		$zone_id = (int)$this->Application->GetVar('tax_id');
 		$zone_type = $zone_object->GetDBField('Type');
 
 		$delete_zones_sql = 'DELETE FROM '.$object->TableName.' WHERE TaxZoneId = '.$zone_id;
 		$this->Conn->Query($delete_zones_sql);
 
 		$selected_destinations = $this->Application->GetVar('selected_destinations');
 		$selected_destinations_array = explode(',', $selected_destinations);
 		$selected_destinations_array = array_unique($selected_destinations_array);
 
 		foreach ($selected_destinations_array as $key => $dest_id) {
 
 					if ($zone_object->GetDBField('Type') == 3){
 						list ($tax_dest_id, $dest_value) = explode('|', $dest_id);
 						$dest_id = $this->Application->GetVar('CountrySelector');
 					}
 					else {
 						$dest_value = '';
 					}
 
 					if ($dest_id > 0){
 						$object->SetDBField('TaxZoneId', $zone_id);
 						$object->SetDBField('StdDestId', $dest_id);
 						$object->SetDBField('DestValue', $dest_value);
 						$object->Create();
 					}
 
 		}
 
 
 	}
 
 }
\ No newline at end of file
Index: branches/5.3.x/units/order_items/order_items_tag_processor.php
===================================================================
--- branches/5.3.x/units/order_items/order_items_tag_processor.php	(revision 15670)
+++ branches/5.3.x/units/order_items/order_items_tag_processor.php	(revision 15671)
@@ -1,300 +1,300 @@
 <?php
 /**
 * @version	$Id$
 * @package	In-Commerce
 * @copyright	Copyright (C) 1997 - 2009 Intechnic. All rights reserved.
 * @license	Commercial License
 * This software is protected by copyright law and international treaties.
 * Unauthorized reproduction or unlicensed usage of the code of this program,
 * or any portion of it may result in severe civil and criminal penalties,
 * and will be prosecuted to the maximum extent possible under the law
 * See http://www.in-portal.org/commercial-license for copyright notices and details.
 */
 
 defined('FULL_PATH') or die('restricted access!');
 
 class OrderItemsTagProcessor extends kDBTagProcessor
 {
 	function PrintGrid($params)
 	{
 		$order = $this->Application->recallObject('ord');
 		/* @var $order kDBList */
 
 		if ( $order->GetDBField('Status') != ORDER_STATUS_INCOMPLETE ) {
 			$params['grid'] = $params['NotEditable'];
 		}
 		else {
 			$params['grid'] = $params['Editable'];
 		}
 
 		return $this->Application->ProcessParsedTag('m', 'ParseBlock', $params);
 	}
 
 	function IsTangible($params)
 	{
 		$object = $this->getObject($params);
 		/* @var $object kDBItem */
 
 		return $object->GetDBField('Type') == PRODUCT_TYPE_TANGIBLE;
 	}
 
 	function HasQty($params)
 	{
 		$object = $this->getObject($params);
 		/* @var $object kDBItem */
 
 		return in_array($object->GetDBField('Type'), Array (PRODUCT_TYPE_TANGIBLE, 6));
 	}
 
 	function HasDiscount($params)
 	{
 		$object = $this->getObject($params);
 		/* @var $object kDBItem */
 
 		return (float)$object->GetDBField('ItemDiscount') ? 1 : 0;
 	}
 
 	function HasOptions($params)
 	{
 		$object = $this->getObject($params);
 		$item_data = @unserialize($object->GetDBField('ItemData'));
 		return isset($item_data['Options']);
 	}
 
 	function PrintOptions($params)
 	{
 		$object = $this->getObject($params);
 		/* @var $object kDBItem */
 
 		$item_data = @unserialize($object->GetDBField('ItemData'));
 
 		$render_as = $this->SelectParam($params, 'render_as');
 		$block_params['name'] = $render_as;
 
 		$opt_helper = $this->Application->recallObject('kProductOptionsHelper');
 		/* @var $opt_helper kProductOptionsHelper */
 
 		$o = '';
 		$options = $item_data['Options'];
 		foreach ($options as $opt => $val) {
 			if ( !is_array($val) ) {
 				$val = htmlspecialchars_decode($val);
 			}
 			$key_data = $opt_helper->ConvertKey($opt, $object->GetDBField('ProductId'));
 
 			$parsed = $opt_helper->ExplodeOptionValues($key_data);
 			if ( $parsed ) {
 				$values = $parsed['Values'];
 				$prices = $parsed['Prices'];
 				$price_types = $parsed['PriceTypes'];
 			}
 			else {
 				$values = array ();
 				$prices = array ();
 				$price_types = array ();
 			}
 
 			$key = $key_data['Name'];
 			/*if (is_array($val)) {
 				$val = join(',', $val);
 			}*/
 
 			$lang = $this->Application->recallObject('lang.current');
 			/* @var $lang LanguagesItem */
 
 			if ( $render_as ) {
 				$block_params['option'] = $key;
 				if ( is_array($val) ) {
 					$block_params['value'] = $val;
 					$block_params['type'] = $key_data['OptionType'];
 					$block_params['price'] = $prices;
 					$block_params['price_type'] = $price_types;
 				}
 				else {
 					$price_type = array_key_exists($val, $price_types) ? $price_types[$val] : '';
 					$price = array_key_exists($val, $prices) ? $prices[$val] : '';
 
 					if ( $price_type == '$' ) {
 						$iso = $this->GetISO($params['currency']);
 						$value = $this->AddCurrencySymbol($lang->formatNumber($this->ConvertCurrency($price, $iso), 2), $iso, true); // true to force sign
 						$block_params['price'] = $value;
 						$block_params['price_type'] = '';
 						$block_params['sign'] = ''; // sign is included in the formatted value
 					}
 					else {
 						$block_params['price'] = $price;
 						$block_params['price_type'] = $price_type;
 						$block_params['sign'] = $price >= 0 ? '+' : '-';
 					}
-					$block_params['value'] = htmlspecialchars($val);
+					$block_params['value'] = htmlspecialchars($val, null, CHARSET);
 					$block_params['type'] = $key_data['OptionType'];
 				}
 				$o .= $this->Application->ParseBlock($block_params, 1);
 			}
 			else {
 				$o .= $key . ': ' . $val . '<br>';
 			}
 		}
 		return $o;
 	}
 
 	function ProductsInStock($params)
 	{
 		$object = $this->getObject($params);
 
 		if (!$object->GetDBField('InventoryStatus')) {
 			// unlimited count available
 			return false;
 		}
 
 		if ($object->GetDBField('InventoryStatus') == 2) {
 			$poc_table = $this->Application->getUnitOption('poc', 'TableName');
 			$sql = 'SELECT QtyInStock
 					FROM '.$poc_table.'
 					WHERE (ProductId = '.$object->GetDBField('ProductId').') AND (Availability = 1) AND (CombinationCRC = '.$object->GetDBField('OptionsSalt').')';
 			$ret = $this->Conn->GetOne($sql);
 		}
 		else {
 			$ret = $object->GetDBField('QtyInStock');
 		}
 
 		return $ret;
 	}
 
 	function PrintOptionValues($params)
 	{
 		$block_params['name'] = $params['render_as'];
 
 		$values = $this->Application->Parser->GetParam('value');
 		/* @var $values Array */
 
 		$prices = $this->Application->Parser->GetParam('price');
 		$price_types = $this->Application->Parser->GetParam('price_type');
 
 		$o = '';
 		$i = 0;
 		foreach ($values as $val) {
 			$i++;
 			$val = htmlspecialchars_decode($val);
-			$block_params['value'] = htmlspecialchars($val);
+			$block_params['value'] = htmlspecialchars($val, null, CHARSET);
 			if ($price_types[$val] == '$') {
 				$iso = $this->GetISO($params['currency']);
 				$value = $this->AddCurrencySymbol(sprintf("%.2f", $this->ConvertCurrency($prices[$val], $iso)), $iso, true); // true to force sign
 				$block_params['price'] = $value;
 				$block_params['price_type'] = '';
 				$block_params['sign'] = ''; // sign is included in the formatted value
 			}
 			else {
 				$block_params['price'] = $prices[$val];
 				$block_params['price_type'] = $price_types[$val];
 				$block_params['sign'] = $prices[$val] >= 0 ? '+' : '-';
 			}
 			$block_params['is_last'] = $i == count($values);
 			$o.= $this->Application->ParseBlock($block_params, 1);
 		}
 		return $o;
 	}
 
 	/*function ConvertKey($key, &$object)
 	{
 		static $mapping = null;
 		if (is_null($mapping) || !isset($mapping[$object->GetDBField('ProductId')])) {
 			$table = TABLE_PREFIX.'ProductOptions';
 			$sql = 'SELECT * FROM '.$table.' WHERE ProductId = '.$object->GetDBField('ProductId');
 			$mapping[$object->GetDBField('ProductId')] = $this->Conn->Query($sql, 'ProductOptionId');
 		}
 		return $mapping[$object->GetDBField('ProductId')][$key];
 	}*/
 
 	function PrintList($params)
 	{
 		$list =& $this->GetList($params);
 		$id_field = $this->Application->getUnitOption($this->Prefix, 'IDField');
 
 		$list->Query();
 		$o = '';
 		$list->GoFirst();
 
 		$block_params = $this->prepareTagParams($params);
 		$block_params['name'] = $this->SelectParam($params, 'render_as,block');
 		$block_params['pass_params'] = 'true';
 
 		$product_object = $this->Application->recallObject('p', 'p', Array ('skip_autoload' => true));
 		/* @var $product_object kCatDBItem */
 
 		$i = 0;
 		$product_id = $product_object->GetID();
 		$product_id_get = $this->Application->GetVar('p_id');
 
 		while (!$list->EOL()) {
 			// load product used in orderitem
 			$this->Application->SetVar($this->getPrefixSpecial() . '_id', $list->GetDBField($id_field)); // for edit/delete links using GET
 			$this->Application->SetVar('p_id', $list->GetDBField('ProductId'));
 			$product_object->Load($list->GetDBField('ProductId')); // correct product load
 
 			$this->Application->SetVar('m_cat_id', $product_object->GetDBField('CategoryId'));
 
 			$block_params['is_last'] = ($i == $list->GetSelectedCount() - 1);
 
 			$o .= $this->Application->ParseBlock($block_params, 1);
 			$list->GoNext();
 			$i++;
 		}
 
 		// restore IDs used in cycle
 		$this->Application->SetVar('p_id', $product_id_get);
 		$this->Application->DeleteVar($this->getPrefixSpecial() . '_id');
 
 		if ( $product_id ) {
 			$product_object->Load($product_id);
 		}
 
 		return $o;
 	}
 
 	function DisplayOptionsPricing($params)
 	{
 		$object = $this->getObject($params);
 		/* @var $object kDBItem */
 
 		if ( $object->GetDBField('OptionsSelectionMode') == 1 ) {
 			return false;
 		}
 
 		$item_data = unserialize($object->GetDBField('ItemData'));
 		if ( !is_array($item_data) ) {
 			return false;
 		}
 
 		$options = getArrayValue($item_data, 'Options');
 		$helper = $this->Application->recallObject('kProductOptionsHelper');
 		/* @var $helper kProductOptionsHelper */
 
 		$crc = $helper->OptionsSalt($options, true);
 
 		$sql = 'SELECT COUNT(*)
 				FROM ' . TABLE_PREFIX . 'ProductOptionCombinations
 				WHERE CombinationCRC = ' . $crc . ' AND ProductId = ' . $object->GetDBField('ProductId') . ' AND (Price != 0 OR (PriceType = 1 AND Price = 0))';
 
 		return $this->Conn->GetOne($sql) == 0; // no overriding combinations found
 	}
 
 	function RowIndex($params)
 	{
 		$object = $this->getObject($params);
 		/* @var $object kDBItem */
 
 		return $object->GetDBField('ProductId') . ':' . $object->GetDBField('OptionsSalt') . ':' . $object->GetDBField('BackOrderFlag');
 	}
 
 	function FreePromoShippingAvailable($params)
 	{
 		$object = $this->getObject($params);
 		/* @var $object kDBItem */
 
 		$order_helper = $this->Application->recallObject('OrderHelper');
 		/* @var $order_helper OrderHelper */
 
 		return $order_helper->eligibleForFreePromoShipping($object);
 	}
 }
\ No newline at end of file
Index: branches/5.3.x/units/gift_certificates/gift_certificates_eh.php
===================================================================
--- branches/5.3.x/units/gift_certificates/gift_certificates_eh.php	(revision 15670)
+++ branches/5.3.x/units/gift_certificates/gift_certificates_eh.php	(revision 15671)
@@ -1,202 +1,202 @@
 <?php
 /**
 * @version	$Id$
 * @package	In-Commerce
 * @copyright	Copyright (C) 1997 - 2009 Intechnic. All rights reserved.
 * @license	Commercial License
 * This software is protected by copyright law and international treaties.
 * Unauthorized reproduction or unlicensed usage of the code of this program,
 * or any portion of it may result in severe civil and criminal penalties,
 * and will be prosecuted to the maximum extent possible under the law
 * See http://www.in-portal.org/commercial-license for copyright notices and details.
 */
 
 defined('FULL_PATH') or die('restricted access!');
 
 class GiftCertificateEventHandler extends kDBEventHandler {
 
 	/**
 	 * Allows to override standard permission mapping
 	 *
 	 * @return void
 	 * @access protected
 	 * @see kEventHandler::$permMapping
 	 */
 	protected function mapPermissions()
 	{
 		parent::mapPermissions();
 
 		$permissions = Array (
 			'OnItemBuild' => Array ('self' => true),
 		);
 
 		$this->permMapping = array_merge($this->permMapping, $permissions);
 	}
 
 	/**
 	 * Prepare temp tables for creating new item
 	 * but does not create it. Actual create is
 	 * done in OnPreSaveCreated
 	 *
 	 * @param kEvent $event
 	 * @return void
 	 * @access protected
 	 */
 	protected function OnPreCreate(kEvent $event)
 	{
 		parent::OnPreCreate($event);
 
 		$object = $event->getObject();
 		/* @var $object kDBItem */
 
 		$exp_date = adodb_mktime();
 		$default_duration = $this->Application->ConfigValue('Comm_DefaultCouponDuration');
 
 		if ( $default_duration ) {
 			$exp_date += (int)$default_duration * 86400;
 		}
 		$object->SetDBField('Expiration_date', $exp_date);
 	}
 
 	/**
 	 * Occurs before updating item
 	 *
 	 * @param kEvent $event
 	 * @return void
 	 * @access protected
 	 */
 	protected function OnBeforeItemUpdate(kEvent $event)
 	{
 		parent::OnBeforeItemUpdate($event);
 
 		$this->itemChanged($event);
 	}
 
 	/**
 	 * Occurs before creating item
 	 *
 	 * @param kEvent $event
 	 * @return void
 	 * @access protected
 	 */
 	protected function OnBeforeItemCreate(kEvent $event)
 	{
 		parent::OnBeforeItemCreate($event);
 
 		$this->itemChanged($event);
 
 		$object = $event->getObject();
 		/* @var $object kDBItem */
 
 		$object->SetDBField('Debit', $object->GetDBField('Amount'));
 	}
 
 	/**
 	 * Occurs before item is changed
 	 *
 	 * @param kEvent $event
 	 */
 	function itemChanged($event)
 	{
 		$object = $event->getObject();
 		/* @var $object kDBItem */
 
 		$amount = abs($object->GetDBField('Amount'));
 		$debit = abs($object->GetDBField('Debit'));
 
 		if ( $debit > $amount ) {
 			$debit = $amount;
 		}
 
 		$object->SetDBField('Amount', $amount);
 		$object->SetDBField('Debit', $debit);
 
 		if ( $object->GetDBField('SendVia') == 1 ) {
 			// by postal mail
 			if ( $this->Application->GetVar('email_certificate') == 0 ) {
 				$object->setRequired('RecipientEmail', false);
 			}
 
 			$cs_helper = $this->Application->recallObject('CountryStatesHelper');
 			/* @var $cs_helper kCountryStatesHelper */
 
 			if ( !$cs_helper->CountryHasStates($object->GetDBField('RecipientCountry')) ) {
 				$object->setRequired('RecipientState', false);
 			}
 
 			$cs_helper->CheckStateField($event, 'RecipientState', 'RecipientCountry');
 		}
 		else {
 			$non_required_fields = Array (
 				'RecipientState', 'RecipientCity', 'RecipientCountry', 'RecipientZipcode',
 				'RecipientAddress1', 'RecipientFirstname', 'RecipientLastname'
 			);
 
 			$object->setRequired($non_required_fields, false);
 		}
 	}
 
 	/**
 	 * Print current gift certificate
 	 *
 	 * @param kEvent $event
 	 * @return void
 	 * @access protected
 	 */
 	protected function OnSave(kEvent $event)
 	{
 		parent::OnSave($event);
 
 		if ( $event->status != kEvent::erSUCCESS || !$this->Application->GetVar('print_certificate') ) {
 			return ;
 		}
 
 		$object = $event->getObject();
 		/* @var $object kDBItem */
 
 		// get object id by unique field Code
 		$sql = 'SELECT ' . $object->IDField . '
 				FROM ' . $this->Application->GetLiveName($object->TableName) . '
 				WHERE Code = ' . $this->Conn->qstr( $object->GetDBField('Code') );
 		$id = $this->Conn->GetOne($sql);
 
 		$this->Application->StoreVar('print_certificate_id', $id);
 	}
 
 	/**
 	 * Email selected gift certificate
 	 *
 	 * @param kEvent $event
 	 */
 	function OnEmailGiftCertificate($event)
 	{
 		$ids = $this->StoreSelectedIDs($event);
 		if (!$ids) {
 			return ;
 		}
 
 		$object = $event->getObject( Array ('skip_autoload' => true) );
 		/* @var $object kDBItem */
 
 		foreach ($ids as $id) {
 			$object->Load($id);
 
 			$send_params = Array (
 				'from_email' => $this->Application->ConfigValue('DefaultEmailSender'),
 				'from_name' => $object->GetDBField('Purchaser'),
 				'message' => $object->GetDBField('Message'),
 				'amount' => $object->GetField('Amount'),
 				'gifcert_id' => $object->GetDBField('Code'),
 			);
 
-			$this->Application->EmailEventAdmin('USER.GIFTCERTIFICATE', null, $send_params);
+			$this->Application->emailAdmin('USER.GIFTCERTIFICATE', null, $send_params);
 
 			$send_params['to_email'] = $object->GetDBField('RecipientEmail');
 			$send_params['to_name'] = $object->GetDBField('Recipient');
-			$this->Application->EmailEventUser('USER.GIFTCERTIFICATE', null, $send_params);
+			$this->Application->emailUser('USER.GIFTCERTIFICATE', null, $send_params);
 		}
 
 		$this->clearSelectedIDs($event);
 	}
 
 }
\ No newline at end of file
Index: branches/5.3.x/admin_templates/manufacturers/manufacturers_edit.tpl
===================================================================
--- branches/5.3.x/admin_templates/manufacturers/manufacturers_edit.tpl	(revision 15670)
+++ branches/5.3.x/admin_templates/manufacturers/manufacturers_edit.tpl	(revision 15671)
@@ -1,83 +1,83 @@
 <inp2:adm_SetPopupSize width="780" height="580"/>
 
 <inp2:m_include t="incs/header"/>
 <inp2:m_RenderElement name="combined_header" section="in-commerce:manufacturers" prefix="manuf" title_preset="manuf_edit"/>
 
 <!-- ToolBar -->
 <table class="toolbar" height="30" cellspacing="0" cellpadding="0" width="100%" border="0">
 <tbody>
 	<tr>
   	<td>
   		<script type="text/javascript">
 				a_toolbar = new ToolBar();
 				a_toolbar.AddButton( new ToolBarButton('select', '<inp2:m_phrase label="la_ToolTip_Save" escape="1"/>', function() {
 							submit_event('manuf','<inp2:manuf_SaveEvent/>');
 						}
 					) );
 				a_toolbar.AddButton( new ToolBarButton('cancel', '<inp2:m_phrase label="la_ToolTip_Cancel" escape="1"/>', function() {
 							submit_event('manuf','OnCancelEdit');
 						}
 				 ) );
 
 				a_toolbar.AddButton( new ToolBarSeparator('sep1') );
 
 				a_toolbar.AddButton( new ToolBarButton('prev', '<inp2:m_phrase label="la_ToolTip_Prev" escape="1"/>', function() {
 							go_to_id('manuf', '<inp2:manuf_PrevId/>');
 						}
 				 ) );
 				a_toolbar.AddButton( new ToolBarButton('next', '<inp2:m_phrase label="la_ToolTip_Next" escape="1"/>', function() {
 							go_to_id('manuf', '<inp2:manuf_NextId/>');
 						}
 				 ) );
 
 				a_toolbar.Render();
 
 				<inp2:m_if check="manuf_IsSingle" >
 					a_toolbar.HideButton('prev');
 					a_toolbar.HideButton('next');
 					a_toolbar.HideButton('sep1');
 				<inp2:m_else/>
 					<inp2:m_if check="manuf_IsLast" >
 						a_toolbar.DisableButton('next');
 					</inp2:m_if>
 					<inp2:m_if check="manuf_IsFirst" >
 						a_toolbar.DisableButton('prev');
 					</inp2:m_if>
 				</inp2:m_if>
 			</script>
 
 			<script src="js/swfobject.js" type="text/javascript"></script>
 			<script type="text/javascript" src="<inp2:m_Compress files='js/uploader/upload_manager.js|js/uploader/uploader.js'/>"></script>
 		</td>
 	</tr>
 </tbody>
 </table>
 
 <inp2:manuf_SaveWarning name="grid_save_warning"/>
 <inp2:manuf_ErrorWarning name="form_error_warning"/>
 
 <div id="scroll_container">
 	<table class="edit-form">
 			<inp2:m_RenderElement name="subsection" title="la_title_General"/>
 				<inp2:m_RenderElement name="inp_id_label" prefix="manuf" field="ManufacturerId" title="la_fld_Id"/>
 				<inp2:m_RenderElement name="inp_edit_box" prefix="manuf" field="Name" title="la_fld_Name" size="40"/>
-				<inp2:m_RenderElement name="inp_edit_textarea" prefix="manuf" field="Description" title="la_fld_Description" control_options="{min_height: 100}" cols="40" rows="5"/>
+				<inp2:m_RenderElement name="inp_edit_textarea" prefix="manuf" field="Description" title="la_fld_Description" control_options="{min_height: 100}" allow_html="1" cols="40" rows="5"/>
 				<inp2:m_RenderElement name="inp_edit_box" prefix="manuf" field="URL" title="la_fld_URL" size="40"/>
 				<inp2:m_RenderElement name="inp_edit_swf_upload" prefix="manuf" field="Logo" thumbnail="120x120" title="la_fld_Logo"/>
 				<inp2:m_RenderElement name="inp_edit_checkbox" prefix="manuf" field="IsPopular" title="la_fld_Popular"/>
 
 			<inp2:m_RenderElement name="subsection" title="la_title_ContactInformation"/>
 				<inp2:m_RenderElement name="inp_edit_box" prefix="manuf" field="Address1" title="la_fld_Address1" size="40"/>
 				<inp2:m_RenderElement name="inp_edit_box" prefix="manuf" field="Address2" title="la_fld_Address2" size="40"/>
 				<inp2:m_RenderElement name="inp_edit_box" prefix="manuf" field="City" title="la_fld_City" size="40"/>
 				<inp2:m_RenderElement name="inp_edit_box" prefix="manuf" field="State" title="la_fld_State" size="40"/>
 				<inp2:m_RenderElement name="inp_edit_options" has_empty="1" prefix="manuf" field="Country" title="la_fld_Country" size="40"/>
 				<inp2:m_RenderElement name="inp_edit_box" prefix="manuf" field="Zip" title="la_fld_Zip" size="40"/>
 				<inp2:m_RenderElement name="inp_edit_box" prefix="manuf" field="Phone" title="la_fld_Phone" size="40"/>
 				<inp2:m_RenderElement name="inp_edit_box" prefix="manuf" field="Fax" title="la_fld_Fax" size="40"/>
 				<inp2:m_RenderElement name="inp_edit_box" prefix="manuf" field="Email" title="la_fld_Email" size="40"/>
 			<inp2:m_RenderElement name="inp_edit_filler"/>
 	</table>
 </div>
 
 <inp2:m_include t="incs/footer"/>
\ No newline at end of file
Index: branches/5.3.x/admin_templates/affiliate_plans/affiliate_plans_items.tpl
===================================================================
--- branches/5.3.x/admin_templates/affiliate_plans/affiliate_plans_items.tpl	(revision 15670)
+++ branches/5.3.x/admin_templates/affiliate_plans/affiliate_plans_items.tpl	(revision 15671)
@@ -1,114 +1,116 @@
+<inp2:adm_SetPopupSize width="750" height="400"/>
+
 <inp2:m_include t="incs/header"/>
 
 <inp2:m_if check="api_IsEntireOrder">
 	<inp2:m_SetParam grid="Default"/>
 <inp2:m_else/>
 	<inp2:m_SetParam grid="AffiliatePlansItems"/>
 </inp2:m_if>
 
 <inp2:m_RenderElement name="combined_header" prefix="ap" section="in-commerce:affiliate_plans" grid="$grid" title_preset="affiliate_plans_items" pagination="1" tab_preset="Default"/>
 
 <!-- ToolBar -->
 <table class="toolbar" height="30" cellspacing="0" cellpadding="0" width="100%" border="0">
 <tbody>
 	<tr>
   	<td>
   		<script type="text/javascript">
 				a_toolbar = new ToolBar();
 				a_toolbar.AddButton( new ToolBarButton('select', '<inp2:m_phrase label="la_ToolTip_Save" escape="1"/>', function() {
 							submit_event('ap','<inp2:ap_SaveEvent/>');
 						}
 					) );
 				a_toolbar.AddButton( new ToolBarButton('cancel', '<inp2:m_phrase label="la_ToolTip_Cancel" escape="1"/>', function() {
 							submit_event('ap','OnCancelEdit');
 						}
 				 ) );
 
 				a_toolbar.AddButton( new ToolBarSeparator('sep1') );
 
 				a_toolbar.AddButton( new ToolBarButton('prev', '<inp2:m_phrase label="la_ToolTip_Prev" escape="1"/>', function() {
 							go_to_id('ap', '<inp2:ap_PrevId/>');
 						}
 				 ) );
 				a_toolbar.AddButton( new ToolBarButton('next', '<inp2:m_phrase label="la_ToolTip_Next" escape="1"/>', function() {
 							go_to_id('ap', '<inp2:ap_NextId/>');
 						}
 				 ) );
 
 				a_toolbar.AddButton( new ToolBarSeparator('sep2') );
 
 				a_toolbar.AddButton( new ToolBarButton('new_item', '<inp2:m_phrase label="la_ToolTip_New_Products" escape="1"/>',
 						function() {
 							openSelector('api', '<inp2:adm_SelectorLink prefix="api" selection_mode="multi" tabs_dependant="no" tab_prefixes="p"/>', '');
 						} ) );
 
 
 				a_toolbar.AddButton( new ToolBarButton('delete', '<inp2:m_phrase label="la_ToolTip_Delete" escape="1"/>',
 						function() {
 							std_delete_items('api')
 						} ) );
 
 				a_toolbar.AddButton( new ToolBarButton('entire_order', '<inp2:m_phrase label="la_ToolTip_EntireOrder" escape="1"/>',
 						function() {
 							if (inpConfirm('<inp2:m_phrase label="la_EntireOrderConfirmation"/>'))
 							{
 								submit_event('api', 'OnEntireOrder');
 							}
 						} ) );
 				a_toolbar.AddButton( new ToolBarSeparator('sep3') );
 
 				a_toolbar.AddButton( new ToolBarButton('view', '<inp2:m_phrase label="la_ToolTip_View" escape="1"/>', function() {
 							show_viewmenu(a_toolbar,'view');
 						}
 				) );
 
 				a_toolbar.Render();
 
 				<inp2:m_if check="ap_IsSingle" >
 					a_toolbar.HideButton('prev');
 					a_toolbar.HideButton('next');
 					a_toolbar.HideButton('sep1');
 					//a_toolbar.HideButton('sep2');
 				<inp2:m_else/>
 					<inp2:m_if check="ap_IsLast" >
 						a_toolbar.DisableButton('next');
 					</inp2:m_if>
 					<inp2:m_if check="ap_IsFirst" >
 						a_toolbar.DisableButton('prev');
 					</inp2:m_if>
 				</inp2:m_if>
 
 				function edit()
 				{
 					// required for correct row selection
 				}
 
 			</script>
 		</td>
 
 		<inp2:m_RenderElement name="search_main_toolbar" prefix="api" grid="$grid"/>
 	</tr>
 </tbody>
 </table>
 
 <inp2:m_DefineElement name="grid_item_checkbox_td">
 	<inp2:m_if check="FieldEquals" field="ItemType" value="1">
 		<inp2:Field field="ProductId" no_special="no_special"/>
 	<inp2:m_else/>
 		<inp2:Field field="CategoryId" no_special="no_special"/>
 	</inp2:m_if>
 </inp2:m_DefineElement>
 
 <inp2:m_RenderElement name="grid" PrefixSpecial="api" IdField="AffiliateItemId" grid="$grid"/>
 
 <script type="text/javascript">
 	<inp2:m_if check="api_IsEntireOrder" >
 			a_toolbar.DisableButton('new_item');
 	</inp2:m_if>
 
 	Grids['api'].SetDependantToolbarButtons( new Array('delete') );
 </script>
 
 <input type="hidden" name="main_prefix" id="main_prefix" value="api">
 
 <inp2:m_include t="incs/footer"/>
\ No newline at end of file
Index: branches/5.3.x/admin_templates/affiliate_plans/affiliate_plans_edit.tpl
===================================================================
--- branches/5.3.x/admin_templates/affiliate_plans/affiliate_plans_edit.tpl	(revision 15670)
+++ branches/5.3.x/admin_templates/affiliate_plans/affiliate_plans_edit.tpl	(revision 15671)
@@ -1,103 +1,105 @@
+<inp2:adm_SetPopupSize width="750" height="400"/>
+
 <inp2:m_include t="incs/header"/>
 <inp2:m_RenderElement name="combined_header" prefix="ap" section="in-commerce:affiliate_plans" title_preset="affiliate_plans_edit" tab_preset="Default"/>
 
 <!-- ToolBar -->
 <table class="toolbar" height="30" cellspacing="0" cellpadding="0" width="100%" border="0">
 <tbody>
 	<tr>
   	<td>
   		<script type="text/javascript">
 				a_toolbar = new ToolBar();
 				a_toolbar.AddButton( new ToolBarButton('select', '<inp2:m_phrase label="la_ToolTip_Save" escape="1"/>', function() {
 						submit_event('ap','<inp2:ap_SaveEvent/>');
 						}
 					) );
 				a_toolbar.AddButton( new ToolBarButton('cancel', '<inp2:m_phrase label="la_ToolTip_Cancel" escape="1"/>', function() {
 						submit_event('ap','OnCancelEdit');
 						}
 				 ) );
 
 				a_toolbar.AddButton( new ToolBarSeparator('sep1') );
 
 				a_toolbar.AddButton( new ToolBarButton('prev', '<inp2:m_phrase label="la_ToolTip_Prev" escape="1"/>', function() {
 							go_to_id('ap', '<inp2:ap_PrevId/>');
 						}
 				 ) );
 				a_toolbar.AddButton( new ToolBarButton('next', '<inp2:m_phrase label="la_ToolTip_Next" escape="1"/>', function() {
 							go_to_id('ap', '<inp2:ap_NextId/>');
 						}
 				 ) );
 
 				a_toolbar.AddButton( new ToolBarSeparator('sep2') );
 
 				a_toolbar.Render();
 
 				<inp2:m_if check="ap_IsSingle" >
 					a_toolbar.HideButton('prev');
 					a_toolbar.HideButton('next');
 					a_toolbar.HideButton('sep1');
 					a_toolbar.HideButton('sep2');
 				<inp2:m_else/>
 					<inp2:m_if check="ap_IsLast" >
 						a_toolbar.DisableButton('next');
 					</inp2:m_if>
 					<inp2:m_if check="ap_IsFirst" >
 						a_toolbar.DisableButton('prev');
 					</inp2:m_if>
 				</inp2:m_if>
 			</script>
 		</td>
 	</tr>
 </tbody>
 </table>
 
 <inp2:ap_SaveWarning name="grid_save_warning"/>
 <inp2:ap_ErrorWarning name="form_error_warning"/>
 
 <div id="scroll_container">
 	<table class="edit-form">
 		<inp2:m_RenderElement name="subsection" title="la_section_General"/>
 			<inp2:m_RenderElement name="inp_label" prefix="ap" field="AffiliatePlanId" title="la_fld_Id"/>
 			<inp2:m_RenderElement name="inp_edit_box" prefix="ap" field="Name" title="la_fld_Name" size="40"/>
 			<inp2:m_RenderElement name="inp_edit_radio" prefix="ap" field="PlanType" title="la_fld_PlanType"/>
 			<inp2:m_RenderElement name="inp_edit_options" prefix="ap" field="ResetInterval" title="la_fld_Period"/>
 			<inp2:m_RenderElement name="inp_edit_checkbox" prefix="ap" field="IsPrimary" title="la_fld_Primary" onchange="check_status()" />
 			<inp2:m_RenderElement name="inp_edit_checkbox" prefix="ap" field="Enabled" title="la_fld_Enabled" onchange="check_primary()"/>
 
 			<inp2:m_RenderElement design="form_row" prefix="ap" field="MinPaymentAmount" title="la_fld_MinimumPaymentAmount">
 				<td class="control-cell">
 					<input type="text" name="<inp2:ap_InputName field='MinPaymentAmount' />" id="<inp2:ap_InputName field='MinPaymentAmount' />" value="<inp2:ap_Field name='MinPaymentAmount' />" tabindex="<inp2:m_get param='tab_index'/>" size="8">
 					<span class="small">(<inp2:curr_PrimaryCurrencyISO />)</span>
 				</td>
 			</inp2:m_RenderElement>
 		<inp2:m_RenderElement name="inp_edit_filler"/>
 	</table>
 </div>
 
 <script type="text/javascript">
 	if(document.getElementById('_cb_<inp2:ap_InputName field="IsPrimary"/>').checked)
 	{
 		document.getElementById('_cb_<inp2:ap_InputName field="IsPrimary"/>').disabled = true;
 		document.getElementById('_cb_<inp2:ap_InputName field="Enabled"/>').disabled = true;
 	}
 
 	function check_status()
 	{
 		if(document.getElementById('_cb_<inp2:ap_InputName field="IsPrimary"/>').checked)
 		{
 			document.getElementById('_cb_<inp2:ap_InputName field="Enabled"/>').checked = true;
 			document.getElementById('<inp2:ap_InputName field="Enabled"/>').value = 1;
 		}
 	}
 
 	function check_primary()
 	{
 		if(!document.getElementById('_cb_<inp2:ap_InputName field="Enabled"/>').checked)
 		{
 			document.getElementById('_cb_<inp2:ap_InputName field="IsPrimary"/>').checked = false;
 			document.getElementById('<inp2:ap_InputName field="IsPrimary"/>').value = 0;
 		}
 	}
 </script>
 
 <inp2:m_include t="incs/footer"/>
\ No newline at end of file
Index: branches/5.3.x/admin_templates/affiliate_plans/affiliate_edit_payments.tpl
===================================================================
--- branches/5.3.x/admin_templates/affiliate_plans/affiliate_edit_payments.tpl	(revision 15670)
+++ branches/5.3.x/admin_templates/affiliate_plans/affiliate_edit_payments.tpl	(revision 15671)
@@ -1,69 +1,71 @@
+<inp2:adm_SetPopupSize width="750" height="400"/>
+
 <inp2:m_include t="incs/header"/>
 <inp2:m_RenderElement name="combined_header" prefix="affil" section="in-commerce:affiliates" title_preset="affiliate_payments" pagination="1" pagination_prefix="apayments" tab_preset="Default"/>
 
 <!-- ToolBar -->
 <table class="toolbar" height="30" cellspacing="0" cellpadding="0" width="100%" border="0">
 <tbody>
 	<tr>
   	<td>
   		<script type="text/javascript">
 				a_toolbar = new ToolBar();
 				a_toolbar.AddButton( new ToolBarButton('select', '<inp2:m_phrase label="la_ToolTip_Save" escape="1"/>', function() {
 							submit_event('affil','<inp2:affil_SaveEvent/>');
 						}
 					) );
 				a_toolbar.AddButton( new ToolBarButton('cancel', '<inp2:m_phrase label="la_ToolTip_Cancel" escape="1"/>', function() {
 							submit_event('affil','OnCancelEdit');
 						}
 				 ) );
 
 				a_toolbar.AddButton( new ToolBarSeparator('sep1') );
 
 				a_toolbar.AddButton( new ToolBarButton('prev', '<inp2:m_phrase label="la_ToolTip_Prev" escape="1"/>', function() {
 							go_to_id('affil', '<inp2:affil_PrevId/>');
 						}
 				 ) );
 				a_toolbar.AddButton( new ToolBarButton('next', '<inp2:m_phrase label="la_ToolTip_Next" escape="1"/>', function() {
 							go_to_id('affil', '<inp2:affil_NextId/>');
 						}
 				 ) );
 
 				a_toolbar.AddButton( new ToolBarSeparator('sep2') );
 
 				a_toolbar.AddButton( new ToolBarButton('view', '<inp2:m_phrase label="la_ToolTip_View" escape="1"/>', function() {
 							show_viewmenu(a_toolbar,'view');
 						}
 				) );
 
 				a_toolbar.Render();
 
 				<inp2:m_if check="affil_IsSingle" >
 					a_toolbar.HideButton('prev');
 					a_toolbar.HideButton('next');
 					a_toolbar.HideButton('sep1');
 					//a_toolbar.HideButton('sep2');
 				<inp2:m_else/>
 					<inp2:m_if check="affil_IsLast" >
 						a_toolbar.DisableButton('next');
 					</inp2:m_if>
 					<inp2:m_if check="affil_IsFirst" >
 						a_toolbar.DisableButton('prev');
 					</inp2:m_if>
 				</inp2:m_if>
 
 				function edit()
 				{
 					// required for correct row selection
 				}
 
 			</script>
 		</td>
 
 		<inp2:m_RenderElement name="search_main_toolbar" prefix="apayments" grid="Default"/>
 	</tr>
 </tbody>
 </table>
 
 <inp2:m_RenderElement name="grid" PrefixSpecial="apayments" IdField="AffiliatePaymentId" grid="Default"/>
 
 <inp2:m_include t="incs/footer"/>
\ No newline at end of file
Index: branches/5.3.x/admin_templates/affiliate_plans/affiliate_payment_types_edit.tpl
===================================================================
--- branches/5.3.x/admin_templates/affiliate_plans/affiliate_payment_types_edit.tpl	(revision 15670)
+++ branches/5.3.x/admin_templates/affiliate_plans/affiliate_payment_types_edit.tpl	(revision 15671)
@@ -1,95 +1,97 @@
+<inp2:adm_SetPopupSize width="750" height="400"/>
+
 <inp2:m_include t="incs/header"/>
 <inp2:m_RenderElement name="combined_header" prefix="apt" section="in-commerce:affiliate_payment_types" title_preset="affiliate_payment_types_edit"/>
 
 <!-- ToolBar -->
 <table class="toolbar" height="30" cellspacing="0" cellpadding="0" width="100%" border="0">
 <tbody>
 	<tr>
   	<td>
   		<script type="text/javascript">
 				a_toolbar = new ToolBar();
 				a_toolbar.AddButton( new ToolBarButton('select', '<inp2:m_phrase label="la_ToolTip_Save" escape="1"/>', function() {
 							submit_event('apt','<inp2:apt_SaveEvent/>');
 						}
 					) );
 				a_toolbar.AddButton( new ToolBarButton('cancel', '<inp2:m_phrase label="la_ToolTip_Cancel" escape="1"/>', function() {
 							submit_event('apt','OnCancelEdit');
 						}
 				 ) );
 
 				a_toolbar.AddButton( new ToolBarSeparator('sep1') );
 
 				a_toolbar.AddButton( new ToolBarButton('prev', '<inp2:m_phrase label="la_ToolTip_Prev" escape="1"/>', function() {
 							go_to_id('apt', '<inp2:apt_PrevId/>');
 						}
 				 ) );
 				a_toolbar.AddButton( new ToolBarButton('next', '<inp2:m_phrase label="la_ToolTip_Next" escape="1"/>', function() {
 							go_to_id('apt', '<inp2:apt_NextId/>');
 						}
 				 ) );
 
 				a_toolbar.AddButton( new ToolBarSeparator('sep2') );
 
 				a_toolbar.Render();
 
 				<inp2:m_if check="apt_IsSingle" >
 					a_toolbar.HideButton('prev');
 					a_toolbar.HideButton('next');
 					a_toolbar.HideButton('sep1');
 					a_toolbar.HideButton('sep2');
 				<inp2:m_else/>
 					<inp2:m_if check="apt_IsLast" >
 						a_toolbar.DisableButton('next');
 					</inp2:m_if>
 					<inp2:m_if check="apt_IsFirst" >
 						a_toolbar.DisableButton('prev');
 					</inp2:m_if>
 				</inp2:m_if>
 			</script>
 		</td>
 	</tr>
 </tbody>
 </table>
 
 <inp2:apt_SaveWarning name="grid_save_warning"/>
 <inp2:apt_ErrorWarning name="form_error_warning"/>
 
 <div id="scroll_container">
 	<table class="edit-form">
 		<inp2:m_RenderElement name="inp_id_label" prefix="apt" field="PaymentTypeId" title="la_fld_Id"/>
 		<inp2:m_RenderElement name="inp_edit_box" prefix="apt" field="Name" title="la_fld_Name" size="40"/>
 		<inp2:m_RenderElement name="inp_edit_checkbox" prefix="apt" field="IsPrimary" title="la_fld_IsPrimary" onchange="check_status()"/>
 		<inp2:m_RenderElement name="inp_edit_checkbox" prefix="apt" field="Status" title="la_fld_Enabled"  onchange="check_primary()"/>
 		<inp2:m_RenderElement name="inp_edit_box" prefix="apt" field="Priority" title="la_fld_Priority" size="5"/>
 		<inp2:m_RenderElement name="inp_edit_textarea" prefix="apt" field="Description" title="la_fld_Description" cols="40" rows="5"/>
 		<inp2:m_RenderElement name="inp_edit_filler"/>
 	</table>
 </div>
 
 <script type="text/javascript">
 	if(document.getElementById('_cb_<inp2:apt_InputName field="IsPrimary"/>').checked)
 	{
 		document.getElementById('_cb_<inp2:apt_InputName field="IsPrimary"/>').disabled = true;
 		document.getElementById('_cb_<inp2:apt_InputName field="Status"/>').disabled = true;
 	}
 
 	function check_status()
 	{
 		if(document.getElementById('_cb_<inp2:apt_InputName field="IsPrimary"/>').checked)
 		{
 			document.getElementById('_cb_<inp2:apt_InputName field="Status"/>').checked = true;
 			document.getElementById('<inp2:apt_InputName field="Status"/>').value = 1;
 		}
 	}
 
 	function check_primary()
 	{
 		if(!document.getElementById('_cb_<inp2:apt_InputName field="Status"/>').checked)
 		{
 			document.getElementById('_cb_<inp2:apt_InputName field="IsPrimary"/>').checked = false;
 			document.getElementById('<inp2:apt_InputName field="IsPrimary"/>').value = 0;
 		}
 	}
 </script>
 
 <inp2:m_include t="incs/footer"/>
\ No newline at end of file
Index: branches/5.3.x/admin_templates/affiliate_plans/affiliates_edit.tpl
===================================================================
--- branches/5.3.x/admin_templates/affiliate_plans/affiliates_edit.tpl	(revision 15670)
+++ branches/5.3.x/admin_templates/affiliate_plans/affiliates_edit.tpl	(revision 15671)
@@ -1,100 +1,102 @@
+<inp2:adm_SetPopupSize width="750" height="400"/>
+
 <inp2:m_include t="incs/header"/>
 <inp2:m_RenderElement name="combined_header" prefix="affil" section="in-commerce:affiliates" title_preset="affiliates_edit" tab_preset="Default"/>
 
 <!-- ToolBar -->
 <table class="toolbar" height="30" cellspacing="0" cellpadding="0" width="100%" border="0">
 <tbody>
 	<tr>
   	<td>
   		<script type="text/javascript">
 				a_toolbar = new ToolBar();
 				a_toolbar.AddButton( new ToolBarButton('select', '<inp2:m_phrase label="la_ToolTip_Save" escape="1"/>', function() {
 						submit_event('affil','<inp2:affil_SaveEvent/>');
 						}
 					) );
 				a_toolbar.AddButton( new ToolBarButton('cancel', '<inp2:m_phrase label="la_ToolTip_Cancel" escape="1"/>', function() {
 						submit_event('affil','OnCancelEdit');
 						}
 				 ) );
 
 				a_toolbar.AddButton( new ToolBarSeparator('sep1') );
 
 				a_toolbar.AddButton( new ToolBarButton('prev', '<inp2:m_phrase label="la_ToolTip_Prev" escape="1"/>', function() {
 							go_to_id('affil', '<inp2:affil_PrevId/>');
 						}
 				 ) );
 				a_toolbar.AddButton( new ToolBarButton('next', '<inp2:m_phrase label="la_ToolTip_Next" escape="1"/>', function() {
 							go_to_id('affil', '<inp2:affil_NextId/>');
 						}
 				 ) );
 
 				<inp2:m_if check="affil_IsNewMode" inverse="inverse">
 					a_toolbar.AddButton( new ToolBarSeparator('sep2') );
 
 					a_toolbar.AddButton( new ToolBarButton('in-commerce:pay_out', '<inp2:m_phrase label="la_ToolTip_PayOut" escape="1"/>', function() {
 						direct_edit('affil', '<inp2:m_t t="in-commerce/affiliate_plans/affiliates_payout" m_opener="d" apayments_event="OnNew" pass="all,apayments"/>');
 						}
 					) );
 				</inp2:m_if>
 
 				a_toolbar.Render();
 
 				<inp2:m_if check="affil_IsSingle" >
 					a_toolbar.HideButton('prev');
 					a_toolbar.HideButton('next');
 					a_toolbar.HideButton('sep1');
 					//a_toolbar.HideButton('sep2');
 				<inp2:m_else/>
 					<inp2:m_if check="affil_IsLast" >
 						a_toolbar.DisableButton('next');
 					</inp2:m_if>
 					<inp2:m_if check="affil_IsFirst" >
 						a_toolbar.DisableButton('prev');
 					</inp2:m_if>
 				</inp2:m_if>
 			</script>
 		</td>
 	</tr>
 </tbody>
 </table>
 
 <inp2:affil_SaveWarning name="grid_save_warning"/>
 <inp2:affil_ErrorWarning name="form_error_warning"/>
 
 <div id="scroll_container">
 	<table class="edit-form">
 		<inp2:m_RenderElement name="subsection" title="la_section_General"/>
 			<inp2:m_RenderElement name="inp_id_label" prefix="affil" field="AffiliateId" title="la_fld_Id"/>
 			<inp2:m_RenderElement name="inp_edit_user" prefix="affil" field="PortalUserId" title="la_fld_Username"/>
 			<inp2:m_RenderElement name="inp_edit_options" prefix="affil" field="AffiliatePlanId" title="la_fld_AffiliatePlan"/>
 			<inp2:m_RenderElement name="inp_edit_options" prefix="affil" field="PaymentTypeId" title="la_fld_PaymentType"/>
 			<inp2:m_RenderElement name="inp_edit_box" prefix="affil" field="SSN" title="la_fld_SSN" />
 			<inp2:m_RenderElement name="inp_edit_radio" prefix="affil" field="Status" title="la_fld_Status"/>
 			<inp2:m_RenderElement name="inp_edit_date" prefix="affil" field="CreatedOn" title="la_fld_RegisteredOn" />
 			<inp2:m_RenderElement name="inp_edit_textarea" prefix="affil" field="Comments" title="la_fld_Comments" cols="40" rows="5"/>
 
 			<inp2:m_if check="affil_IsNewMode" inverse="inverse">
 				<inp2:m_RenderElement name="subsection" title="la_section_AdvertisingMaterials"/>
 					<tr class="<inp2:m_odd_even odd='edit-form-odd' even='edit-form-even'/>">
 						<inp2:m_inc param="tab_index" by="1"/>
 						<td class="label-cell">
 							<inp2:m_phrase label="la_fld_AffiliateLink"/>:
 						</td>
 						<td class="control-mid">&nbsp;</td>
 						<td class="control-cell">
 							<a href="<inp2:affil_GetAffiliateLink template='index'/>" target="_blank"><inp2:affil_GetAffiliateLink template="index" prefix="_FRONT_"/></a>
 						</td>
 					</tr>
 					<inp2:m_RenderElement name="inp_label" prefix="affil" field="AffiliateCode" title="la_fld_AffiliateCode"/>
 
 				<inp2:m_RenderElement name="subsection" title="la_section_Statistics"/>
 					<inp2:m_RenderElement name="inp_label" prefix="affil" field="AccumulatedAmount" title="la_fld_AccumulatedAmount" currency="selected"/>
 					<inp2:m_RenderElement name="inp_label" prefix="affil" field="ItemsSold" title="la_fld_ItemsSold"/>
 					<inp2:m_RenderElement name="inp_label" prefix="affil" field="AmountToPay" title="la_fld_AmountToPay" currency="selected"/>
 					<inp2:m_RenderElement name="inp_label" prefix="affil" field="LastPaymentDate_date" title="la_fld_LastPaymentDate"/>
 			</inp2:m_if>
 		<inp2:m_RenderElement name="inp_edit_filler"/>
 	</table>
 </div>
 
 <inp2:m_include t="incs/footer"/>
\ No newline at end of file
Index: branches/5.3.x/admin_templates/affiliate_plans/affiliate_plans_brackets.tpl
===================================================================
--- branches/5.3.x/admin_templates/affiliate_plans/affiliate_plans_brackets.tpl	(revision 15670)
+++ branches/5.3.x/admin_templates/affiliate_plans/affiliate_plans_brackets.tpl	(revision 15671)
@@ -1,176 +1,178 @@
+<inp2:adm_SetPopupSize width="750" height="400"/>
+
 <inp2:m_include t="incs/header"/>
 <inp2:m_RenderElement name="combined_header" prefix="ap" section="in-commerce:affiliate_plans" title_preset="affiliate_plans_brackets" tab_preset="Default"/>
 
 <!-- ToolBar -->
 <table class="toolbar" height="30" cellspacing="0" cellpadding="0" width="100%" border="0">
 <tbody>
 	<tr>
   	<td>
   		<script type="text/javascript">
 				a_toolbar = new ToolBar();
 
 				a_toolbar.AddButton( new ToolBarButton('select', '<inp2:m_phrase label="la_ToolTip_Save" escape="1"/>', function() {
 							submit_event('ap','<inp2:ap_SaveEvent/>');
 						}
 					) );
 				a_toolbar.AddButton( new ToolBarButton('cancel', '<inp2:m_phrase label="la_ToolTip_Cancel" escape="1"/>', function() {
 							submit_event('ap','OnCancelEdit');
 						}
 				 ) );
 
 				a_toolbar.AddButton( new ToolBarSeparator('sep1') );
 
 				a_toolbar.AddButton( new ToolBarButton('prev', '<inp2:m_phrase label="la_ToolTip_Prev" escape="1"/>', function() {
 							go_to_id('ap', '<inp2:ap_PrevId/>');
 						}
 				 ) );
 				a_toolbar.AddButton( new ToolBarButton('next', '<inp2:m_phrase label="la_ToolTip_Next" escape="1"/>', function() {
 							go_to_id('ap', '<inp2:ap_NextId/>');
 						}
 				 ) );
 
 				a_toolbar.AddButton( new ToolBarSeparator('sep2') );
 
 				function add_brackets()
 	  			{
 	  				submit_event('apbrackets', 'OnMoreBrackets')
 	  			}
 				a_toolbar.AddButton( new ToolBarButton('in-commerce:more_brackets', '<inp2:m_phrase label="la_ToolTip_MoreBrackets" escape="1"/>', add_brackets) );
 
 				function infinity()
 	  			{
 					submit_event('apbrackets', 'OnInfinity');
 	  			}
 				a_toolbar.AddButton( new ToolBarButton('in-commerce:infinity', '<inp2:m_phrase label="la_ToolTip_Infinity" escape="1"/>', infinity) );
 
 				function arrange_brackets()
 	  			{
 					submit_event('apbrackets', 'OnArrange')
 	  			}
 				a_toolbar.AddButton( new ToolBarButton('in-commerce:arrange', '<inp2:m_phrase label="la_ToolTip_Arrange" escape="1"/>', arrange_brackets) );
 
 				a_toolbar.Render();
 
 				<inp2:m_if check="ap_IsSingle" >
 					a_toolbar.HideButton('prev');
 					a_toolbar.HideButton('next');
 					a_toolbar.HideButton('sep1');
 					//a_toolbar.HideButton('sep2');
 				<inp2:m_else/>
 					<inp2:m_if check="ap_IsLast" >
 						a_toolbar.DisableButton('next');
 					</inp2:m_if>
 					<inp2:m_if check="ap_IsFirst" >
 						a_toolbar.DisableButton('prev');
 					</inp2:m_if>
 				</inp2:m_if>
 			</script>
 		</td>
 	</tr>
 </tbody>
 </table>
 
 <inp2:m_DefineElement name="pr_edit_box" >
 <td>
 	<input type="text" size="<inp2:m_param name="size"/>" name="<inp2:m_param name="PrefixSpecial"/>[<inp2:m_param name="id"/>][<inp2:m_param name="field"/>]"
 				id="<inp2:m_param name="PrefixSpecial"/>[<inp2:m_param name="id"/>][<inp2:m_param name="field"/>]"
 				tabindex="<inp2:m_get param="tab_index"/>"
 				value="<inp2:m_param name="$field"/>"
 			>
 </inp2:m_DefineElement>
 
 <inp2:m_DefineElement name="pr_edit_max" >
 <td>
 			<input type="text" size="10" name="<inp2:m_param name="PrefixSpecial"/>[<inp2:m_param name="id"/>][<inp2:m_param name="field"/>]"
 				id="<inp2:m_param name="PrefixSpecial"/>[<inp2:m_param name="id"/>][<inp2:m_param name="field"/>]"
 				tabindex="<inp2:m_get param="tab_index"/>"
 				value="<inp2:m_param name="max"/>"
 				<inp2:m_if check="m_ParamEquals" param="next_min_id" value="">
 				<inp2:m_else />
 				onchange="set_start(<inp2:m_param name="id"/>, <inp2:m_param name="next_min_id"/>,'<inp2:m_param name="PrefixSpecial"/>')"
 				</inp2:m_if>
 
 			>
 </td>
 </inp2:m_DefineElement>
 
 <inp2:m_DefineElement name="pr_edit_min" >
 <td>
 			<input type="hidden" name="<inp2:m_param name="PrefixSpecial"/>[<inp2:m_param name="id"/>][<inp2:m_param name="IdField"/>]" id="<inp2:m_param name="PrefixSpecial"/>[<inp2:m_param name="id"/>][<inp2:m_param name="IdField"/>]" value="<inp2:m_param name="id"/>">
 			<input type="text" size="10"
 				<inp2:m_if check="m_ParamEquals" param="first" value="1">
 					<inp2:m_inc param="tab_index" by="1"/>
 					tabindex="<inp2:m_get param="tab_index"/>"
 				<inp2:m_else/>
 					readonly
 				</inp2:m_if>
 				name="<inp2:m_param name="PrefixSpecial"/>[<inp2:m_param name="id"/>][<inp2:m_param name="field"/>]"
 				id="<inp2:m_param name="PrefixSpecial"/>[<inp2:m_param name="id"/>][<inp2:m_param name="field"/>]"
 				value="<inp2:m_param name="min"/>"
 				<inp2:m_if check="m_ParamEquals" param="first" value="1"><inp2:m_else/>disabled</inp2:m_if>
 			>
 </td>
 </inp2:m_DefineElement>
 
 <inp2:m_DefineElement name="prbracket">
 	<tr class="<inp2:m_odd_even odd="table-color1" even="table-color2"/>">
 
 		<inp2:m_RenderElement name="pr_edit_min" IdField="$IdField" PrefixSpecial="$PrefixSpecial" field="FromAmount" size="40" pass_params="true"/>
 
 		<inp2:m_RenderElement name="pr_edit_max" IdField="$IdField" PrefixSpecial="$PrefixSpecial" field="ToAmount" size="40" pass_params="true"/>
 
 		<inp2:m_RenderElement name="pr_edit_box" IdField="$IdField" PrefixSpecial="$PrefixSpecial" field="Percent" size="4" pass_params="true"/>
 
 	</tr>
 </inp2:m_DefineElement>
 
 
 <script>
 
 	function set_start(id, next_id, prefix_special)
 	{
 		//var next_id = id - 1;
 		var input_id = prefix_special + '[' + next_id + '][FromAmount]';
 		//var orig_id = prefix_special + '[' + id + '][FromAmount]';
 		if(document.getElementById(input_id) != null)
 		{
 			var new_value = parseInt(document.getElementById(prefix_special + '[' + id + '][ToAmount]').value);
 			if( isNaN(new_value) ) new_value = 0;
 			document.getElementById(prefix_special + '[' + id + '][ToAmount]').value = new_value;
 			document.getElementById(input_id).value = new_value;
 		}
 	}
 
 	function enableKernelFormFields()
 	{
 		var kForm = document.forms.kernel_form;
 		var elem = false;
 		for (var i=0; i<kForm.elements.length; i++){
 			elem = kForm.elements[i];
 			if (elem.type == "text" && elem.disabled == true){
 				elem.disabled = false;
 			}
 		}
 	}
 
 </script>
 
 <inp2:m_DefineElement name="pr_grid_th" >
 	<td class="columntitle_small"><inp2:m_phrase label="$phrase" /></td>
 </inp2:m_DefineElement>
 
 <inp2:apbrackets_SaveWarning name="grid_save_warning"/>
 <table width="100%" border="0" cellspacing="0" cellpadding="4" class="tableborder">
 	<tr nowrap="nowrap" class="grid-header-row-0">
 		<inp2:m_RenderElement name="pr_grid_th" phrase="column:la_fld_FromAmount"/>
 		<inp2:m_RenderElement name="pr_grid_th" phrase="column:la_fld_ToAmount"/>
 		<inp2:m_RenderElement name="pr_grid_th" phrase="la_col_Percent"/>
 	</tr>
 	<inp2:apbrackets_ShowPricingForm block="prbracket" IdField="AffiliateBracketId"/>
 </table>
 
 <inp2:m_include t="incs/footer"/>
 
 <script>
 	document.forms.kernel_form.onsubmit =  enableKernelFormFields;
 </script>
\ No newline at end of file
Index: branches/5.3.x/admin_templates/paid_listings/paid_listing_type_shopcart.tpl
===================================================================
--- branches/5.3.x/admin_templates/paid_listings/paid_listing_type_shopcart.tpl	(revision 15670)
+++ branches/5.3.x/admin_templates/paid_listings/paid_listing_type_shopcart.tpl	(revision 15671)
@@ -1,66 +1,68 @@
+<inp2:adm_SetPopupSize width="790" height="440"/>
+
 <inp2:m_include t="incs/header"/>
 <inp2:m_RenderElement name="combined_header" prefix="lst" section="in-link:listing_types" title_preset="listing_type_shop_cart" tab_preset="Default"/>
 
 <!-- ToolBar -->
 <table class="toolbar" height="30" cellspacing="0" cellpadding="0" width="100%" border="0">
 <tbody>
 	<tr>
   	<td>
   		<script type="text/javascript">
 				a_toolbar = new ToolBar();
 				a_toolbar.AddButton( new ToolBarButton('select', '<inp2:m_phrase label="la_ToolTip_Save" escape="1"/>', function() {
 						submit_event('lst','<inp2:lst_SaveEvent/>');
 						}
 					) );
 				a_toolbar.AddButton( new ToolBarButton('cancel', '<inp2:m_phrase label="la_ToolTip_Cancel" escape="1"/>', function() {
 						submit_event('lst','OnCancelEdit');
 						}
 				 ) );
 
 				a_toolbar.AddButton( new ToolBarSeparator('sep1') );
 
 				a_toolbar.AddButton( new ToolBarButton('prev', '<inp2:m_phrase label="la_ToolTip_Prev" escape="1"/>', function() {
 							go_to_id('lst', '<inp2:lst_PrevId/>');
 						}
 				 ) );
 				a_toolbar.AddButton( new ToolBarButton('next', '<inp2:m_phrase label="la_ToolTip_Next" escape="1"/>', function() {
 							go_to_id('lst', '<inp2:lst_NextId/>');
 						}
 				 ) );
 
 				a_toolbar.Render();
 
 				<inp2:m_if check="lst_IsSingle" >
 					a_toolbar.HideButton('prev');
 					a_toolbar.HideButton('next');
 					a_toolbar.HideButton('sep1');
 				<inp2:m_else/>
 					<inp2:m_if check="lst_IsLast" >
 						a_toolbar.DisableButton('next');
 					</inp2:m_if>
 					<inp2:m_if check="lst_IsFirst" >
 						a_toolbar.DisableButton('prev');
 					</inp2:m_if>
 				</inp2:m_if>
 			</script>
 		</td>
 	</tr>
 </tbody>
 </table>
 
 <inp2:lst_SaveWarning name="grid_save_warning"/>
 <inp2:lst_ErrorWarning name="form_error_warning"/>
 
 <div id="scroll_container">
 	<table class="edit-form">
 		<inp2:m_RenderElement name="subsection" title="la_Text_ShopCartItem"/>
 			<inp2:m_RenderElement name="inp_edit_checkbox" prefix="lst" field="EnableBuying" title="la_fld_EnableBuying" />
 			<inp2:m_RenderElement name="inp_edit_box" prefix="lst" field="ShopCartName" title="la_fld_ShopCartName" size="20" />
 			<inp2:m_RenderElement name="inp_edit_box" prefix="lst" field="Price" title="la_fld_Price" size="8" />
 			<!-- <inp2:m_RenderElement name="inp_edit_checkbox" prefix="lst" field="Recurring" title="la_fld_Recurring" /> -->
 
 	<inp2:m_RenderElement name="inp_edit_filler"/>
 	</table>
 </div>
 
 <inp2:m_include t="incs/footer"/>
\ No newline at end of file
Index: branches/5.3.x/admin_templates/currencies/currencies_edit.tpl
===================================================================
--- branches/5.3.x/admin_templates/currencies/currencies_edit.tpl	(revision 15670)
+++ branches/5.3.x/admin_templates/currencies/currencies_edit.tpl	(revision 15671)
@@ -1,114 +1,116 @@
+<inp2:adm_SetPopupSize width="750" height="400"/>
+
 <inp2:m_include t="incs/header"/>
 <inp2:m_RenderElement name="combined_header" prefix="curr" section="in-commerce:currencies" title_preset="currencies_edit"/>
 
 <!-- ToolBar -->
 <table class="toolbar" height="30" cellspacing="0" cellpadding="0" width="100%" border="0">
 <tbody>
 	<tr>
   	<td>
   		<script type="text/javascript">
 				a_toolbar = new ToolBar();
 				a_toolbar.AddButton( new ToolBarButton('select', '<inp2:m_phrase label="la_ToolTip_Save" escape="1"/>', function() {
 							submit_event('curr','<inp2:curr_SaveEvent/>');
 						}
 					) );
 				a_toolbar.AddButton( new ToolBarButton('cancel', '<inp2:m_phrase label="la_ToolTip_Cancel" escape="1"/>', function() {
 							submit_event('curr','OnCancelEdit');
 						}
 				 ) );
 
 				a_toolbar.AddButton( new ToolBarSeparator('sep1') );
 
 				a_toolbar.AddButton( new ToolBarButton('prev', '<inp2:m_phrase label="la_ToolTip_Prev" escape="1"/>', function() {
 							go_to_id('curr', '<inp2:curr_PrevId/>');
 						}
 				 ) );
 				a_toolbar.AddButton( new ToolBarButton('next', '<inp2:m_phrase label="la_ToolTip_Next" escape="1"/>', function() {
 							go_to_id('curr', '<inp2:curr_NextId/>');
 						}
 				 ) );
 
 				a_toolbar.Render();
 
 				<inp2:m_if check="curr_IsSingle" >
 					a_toolbar.HideButton('prev');
 					a_toolbar.HideButton('next');
 					a_toolbar.HideButton('sep1');
 					a_toolbar.HideButton('sep2');
 				<inp2:m_else/>
 					<inp2:m_if check="curr_IsLast" >
 						a_toolbar.DisableButton('next');
 					</inp2:m_if>
 					<inp2:m_if check="curr_IsFirst" >
 						a_toolbar.DisableButton('prev');
 					</inp2:m_if>
 				</inp2:m_if>
 
 			</script>
 		</td>
 	</tr>
 </tbody>
 </table>
 
 <inp2:curr_SaveWarning name="grid_save_warning"/>
 <inp2:curr_ErrorWarning name="form_error_warning"/>
 
 <div id="scroll_container">
 	<table class="edit-form">
 		<inp2:m_RenderElement name="subsection" title="la_section_Currency"/>
 			<inp2:m_RenderElement name="inp_label" prefix="curr" field="CurrencyId" title="la_fld_Id"/>
 			<inp2:m_RenderElement name="inp_label" prefix="curr" field="ISO" title="la_fld_ISOCode"/>
 
 			<inp2:m_RenderElement design="form_row" prefix="curr" field="RateToPrimary" title="la_fld_RateToPrimary">
 				<td class="control-cell">
 					<input type="text" name="<inp2:curr_InputName field='RateToPrimary'/>" id="<inp2:curr_InputName field='RateToPrimary'/>" value="<inp2:curr_Field field='RateToPrimary'/>" size="10">
 					<input type="button" class="button" onclick="submit_event('curr', 'OnUpdateRate')" value="<inp2:m_phrase label='la_UpdateRate'/>">
 					<span class="small">1 <inp2:curr_Field field="ISO"/> = ? <inp2:curr_PrimaryCurrencyISO /></span>
 				</td>
 			</inp2:m_RenderElement>
 
 			<inp2:m_RenderElement design="form_row" prefix="curr" field="Symbol" title="la_fld_CurrencySymbol">
 				<td class="control-cell">
 					<input type="text" name="<inp2:curr_InputName field='Symbol'/>" id="<inp2:curr_InputName field='Symbol'/>" value="<inp2:curr_Field field='Symbol'/>" tabindex="<inp2:m_get param='tab_index'/>" size="10">
 					<span class="small"><inp2:m_phrase label="la_ISOUsedIfBlank" /></span>
 					<inp2:curr_Error field="Symbol"/>
 				</td>
 			</inp2:m_RenderElement>
 
 			<inp2:m_RenderElement name="inp_edit_radio" prefix="curr" field="SymbolPosition" title="la_fld_CurrencySymbolPosition"/>
 
 			<inp2:m_RenderElement name="inp_edit_box" prefix="curr" field="Name" title="la_fld_CurrencyName" size="40"/>
 			<inp2:m_RenderElement name="inp_edit_checkbox" prefix="curr" field="IsPrimary" title="la_fld_Primary" onchange="check_status()"/>
 			<inp2:m_RenderElement name="inp_edit_checkbox" prefix="curr" field="Status" title="la_fld_Enabled" onchange="check_primary()"/>
 			<inp2:m_RenderElement name="inp_edit_box" prefix="curr" field="Priority" title="la_fld_Priority" size="5"/>
 		<inp2:m_RenderElement name="inp_edit_filler"/>
 	</table>
 </div>
 
 <script type="text/javascript">
 	if(document.getElementById('_cb_curr[<inp2:curr_field field="CurrencyId" />][IsPrimary]').checked)
 	{
 		document.getElementById('_cb_curr[<inp2:curr_field field="CurrencyId" />][IsPrimary]').disabled = true;
 		document.getElementById('_cb_curr[<inp2:curr_field field="CurrencyId" />][Status]').disabled = true;
 	}
 
 	function check_status()
 	{
 		if(document.getElementById('_cb_curr[<inp2:curr_field field="CurrencyId" />][IsPrimary]').checked)
 		{
 			document.getElementById('_cb_curr[<inp2:curr_field field="CurrencyId" />][Status]').checked = true;
 			document.getElementById('<inp2:curr_InputName field="Status"/>').value = 1;
 		}
 	}
 
 	function check_primary()
 	{
 		if(!document.getElementById('_cb_curr[<inp2:curr_field field="CurrencyId" />][Status]').checked)
 		{
 			document.getElementById('_cb_curr[<inp2:curr_field field="CurrencyId" />][IsPrimary]').checked = false;
 			document.getElementById('<inp2:curr_InputName field="IsPrimary"/>').value = 0;
 		}
 	}
 </script>
 
 <inp2:m_include t="incs/footer"/>
\ No newline at end of file
Index: branches/5.3.x/admin_templates/products/access_pricing_edit.tpl
===================================================================
--- branches/5.3.x/admin_templates/products/access_pricing_edit.tpl	(revision 15670)
+++ branches/5.3.x/admin_templates/products/access_pricing_edit.tpl	(revision 15671)
@@ -1,82 +1,84 @@
+<inp2:adm_SetPopupSize width="750" height="400"/>
+
 <inp2:m_include t="incs/header"/>
 <inp2:m_RenderElement name="combined_header" prefix="p" section="in-portal:browse" title_preset="pricing_edit"/>
 
 <!-- ToolBar -->
 <table class="toolbar" height="30" cellspacing="0" cellpadding="0" width="100%" border="0">
 <tbody>
 	<tr>
   	<td>
   		<script type="text/javascript">
 				a_toolbar = new ToolBar();
 				a_toolbar.AddButton( new ToolBarButton('select', '<inp2:m_phrase label="la_ToolTip_Save" escape="1"/>', function() {
 							submit_event('pr','<inp2:pr_SaveEvent/>');
 						}
 					) );
 				a_toolbar.AddButton( new ToolBarButton('cancel', '<inp2:m_phrase label="la_ToolTip_Cancel" escape="1"/>', function() {
 							submit_event('pr','OnCancel');
 						}
 				 ) );
 
 				a_toolbar.AddButton( new ToolBarSeparator('sep1') );
 
 				a_toolbar.AddButton( new ToolBarButton('prev', '<inp2:m_phrase label="la_ToolTip_Prev" escape="1"/>', function() {
 						go_to_id('pr', '<inp2:pr_PrevId/>');
 					}
 				));
 
 				a_toolbar.AddButton( new ToolBarButton('next', '<inp2:m_phrase label="la_ToolTip_Next" escape="1"/>', function() {
 						go_to_id('pr', '<inp2:pr_NextId/>');
 					}
 				));
 
 				a_toolbar.Render();
-				
+
 				<inp2:m_if check="pr_IsSingle">
 					a_toolbar.HideButton('prev');
 					a_toolbar.HideButton('next');
 					a_toolbar.HideButton('sep1');
 				<inp2:m_else/>
 					<inp2:m_if check="pr_IsLast">
 						a_toolbar.DisableButton('next');
 					</inp2:m_if>
 					<inp2:m_if check="pr_IsFirst">
 						a_toolbar.DisableButton('prev');
 					</inp2:m_if>
 				</inp2:m_if>
 			</script>
 		</td>
 	</tr>
 </tbody>
 </table>
 
 <inp2:pr_SaveWarning name="grid_save_warning"/>
 <inp2:pr_ErrorWarning name="form_error_warning"/>
 
 <div id="scroll_container">
 	<table class="edit-form">
 		<inp2:m_RenderElement name="subsection" title="la_section_PriceBracket"/>
 			<inp2:m_RenderElement name="inp_edit_hidden" prefix="pr" field="ProductId"/>
 			<inp2:m_RenderElement name="inp_edit_box" prefix="pr" field="AccessDuration" title="la_fld_AccessDuration" size="4"/>
 			<inp2:m_RenderElement name="inp_edit_options" prefix="pr" field="AccessUnit" title="la_fld_AccessDurationUnit" size="20"/>
 
-			<!--## TODO check on implementation (came from customization healtheconomics.org) 
+			<!--## TODO check on implementation (came from customization healtheconomics.org)
 			<inp2:m_RenderElement name="inp_edit_box" prefix="pr" field="AccessRebillDate" title="la_fld_AccessRebillDate" size="5"/>
 			<inp2:m_RenderElement name="inp_edit_radio" prefix="pr" field="DurationType" title="la_fld_DurationType"/>
 			<inp2:m_RenderElement name="inp_edit_date" prefix="pr" field="AccessExpiration" title="la_fld_AccessExpiration"/>
 			## -->
-			
+
 			<inp2:m_RenderElement name="inp_edit_box" prefix="pr" field="Description" title="la_fld_Description" size="30"/>
 			<inp2:m_RenderElement name="inp_edit_box" prefix="pr" field="Price" title="la_fld_Price" size="4"/>
 			<inp2:m_RenderElement name="inp_edit_checkbox" prefix="pr" field="IsPrimary" title="la_fld_Primary"/>
 
 		<inp2:m_RenderElement name="inp_edit_filler"/>
 	</table>
 </div>
 
 <inp2:m_if check="pr_Field" name="IsPrimary">
 	<script type="text/javascript">
 		document.getElementById('_cb_<inp2:pr_InputName field="IsPrimary"/>').disabled = true;
 	</script>
 </inp2:m_if>
 
 <inp2:m_include t="incs/footer"/>
\ No newline at end of file
Index: branches/5.3.x/admin_templates/products/file_edit.tpl
===================================================================
--- branches/5.3.x/admin_templates/products/file_edit.tpl	(revision 15670)
+++ branches/5.3.x/admin_templates/products/file_edit.tpl	(revision 15671)
@@ -1,95 +1,97 @@
+<inp2:adm_SetPopupSize width="750" height="400"/>
+
 <inp2:m_include t="incs/header"/>
 <inp2:m_RenderElement name="combined_header" prefix="p" section="in-portal:browse" title_preset="file_edit"/>
 
 <!-- ToolBar -->
 <table class="toolbar" height="30" cellspacing="0" cellpadding="0" width="100%" border="0">
 <tbody>
 	<tr>
   	<td>
   		<script type="text/javascript">
 				a_toolbar = new ToolBar();
 				a_toolbar.AddButton( new ToolBarButton('select', '<inp2:m_phrase label="la_ToolTip_Save" escape="1"/>', function() {
 							submit_event('file','<inp2:file_SaveEvent/>');
 						}
 					) );
 				a_toolbar.AddButton( new ToolBarButton('cancel', '<inp2:m_phrase label="la_ToolTip_Cancel" escape="1"/>', function() {
 							submit_event('file','OnCancel');
 						}
 				 ) );
 
 				a_toolbar.AddButton( new ToolBarSeparator('sep1') );
 
 				a_toolbar.AddButton( new ToolBarButton('prev', '<inp2:m_phrase label="la_ToolTip_Prev" escape="1"/>', function() {
 						go_to_id('file', '<inp2:file_PrevId/>');
 					}
 				));
 
 				a_toolbar.AddButton( new ToolBarButton('next', '<inp2:m_phrase label="la_ToolTip_Next" escape="1"/>', function() {
 						go_to_id('file', '<inp2:file_NextId/>');
 					}
 				));
 
 				a_toolbar.Render();
 
 				<inp2:m_if check="file_IsSingle">
 					a_toolbar.HideButton('prev');
 					a_toolbar.HideButton('next');
 					a_toolbar.HideButton('sep1');
 				<inp2:m_else/>
 					<inp2:m_if check="file_IsLast">
 						a_toolbar.DisableButton('next');
 					</inp2:m_if>
 					<inp2:m_if check="file_IsFirst">
 						a_toolbar.DisableButton('prev');
 					</inp2:m_if>
-				</inp2:m_if>				
+				</inp2:m_if>
 			</script>
 		</td>
 	</tr>
 </tbody>
 </table>
 
 <inp2:file_SaveWarning name="grid_save_warning"/>
 <inp2:file_ErrorWarning name="form_error_warning"/>
 
 <div id="scroll_container">
 	<table class="edit-form">
 		<inp2:m_RenderElement name="subsection" title="la_section_File"/>
 			<inp2:m_RenderElement name="inp_edit_hidden" prefix="file" field="ProductId"/>
 			<inp2:m_RenderElement name="inp_edit_box" prefix="file" field="Name" title="la_fld_Name" size="50" />
 			<inp2:m_RenderElement name="inp_edit_box" prefix="file" field="Version" title="la_fld_Version" size="10" />
 			<inp2:m_RenderElement name="inp_edit_upload" prefix="file" field="RealPath" title="la_fld_FilePath" />
 			<inp2:m_RenderElement name="inp_edit_checkbox" prefix="file" field="Status" title="la_fld_Enabled" onchange="check_primary()" />
 			<inp2:m_RenderElement name="inp_edit_checkbox" prefix="file" field="IsPrimary" title="la_fld_Primary" onchange="check_status()" />
 			<inp2:m_RenderElement name="inp_edit_box" prefix="file" field="Priority" title="la_fld_Priority" size="4"/>
 			<inp2:m_RenderElement name="inp_edit_date" prefix="file" field="AddedOn" title="la_fld_AddedOn" />
 		<inp2:m_RenderElement name="inp_edit_filler"/>
 	</table>
 </div>
 
 <script type="text/javascript">
 	<inp2:m_if check="file_Field" name="IsPrimary">
 		document.getElementById('_cb_<inp2:file_InputName field="IsPrimary" />').disabled = true;
 		document.getElementById('_cb_<inp2:file_InputName field="Status" />').disabled = true;
 	</inp2:m_if>
 
 	function check_status()
 	{
 		if(document.getElementById('_cb_<inp2:file_InputName field="IsPrimary" />').checked)
 		{
 			document.getElementById('_cb_<inp2:file_InputName field="Status" />').checked = true;
 			document.getElementById('<inp2:file_InputName field="Status"/>').value = 1;
 		}
 	}
 
 	function check_primary()
 	{
 		if(!document.getElementById('_cb_<inp2:file_InputName field="Status" />').checked)
 		{
 			document.getElementById('_cb_<inp2:file_InputName field="IsPrimary" />').checked = false;
 			document.getElementById('<inp2:file_InputName field="IsPrimary"/>').value = 0;
 		}
 	}
 </script>
 
 <inp2:m_include t="incs/footer"/>
\ No newline at end of file
Index: branches/5.3.x/admin_templates/products/pricing_edit.tpl
===================================================================
--- branches/5.3.x/admin_templates/products/pricing_edit.tpl	(revision 15670)
+++ branches/5.3.x/admin_templates/products/pricing_edit.tpl	(revision 15671)
@@ -1,46 +1,48 @@
+<inp2:adm_SetPopupSize width="750" height="400"/>
+
 <inp2:m_include t="incs/header"/>
 <inp2:m_RenderElement name="combined_header" prefix="p" section="in-portal:browse" title_preset="pricing_edit"/>
 
 <!-- ToolBar -->
 <table class="toolbar" height="30" cellspacing="0" cellpadding="0" width="100%" border="0">
 <tbody>
 	<tr>
   	<td>
   		<script type="text/javascript">
 				a_toolbar = new ToolBar();
 				a_toolbar.AddButton( new ToolBarButton('select', '<inp2:m_phrase label="la_ToolTip_Save" escape="1"/>', function() {
 							submit_event('pr','<inp2:pr_SaveEvent/>');
 						}
 					) );
 				a_toolbar.AddButton( new ToolBarButton('cancel', '<inp2:m_phrase label="la_ToolTip_Cancel" escape="1"/>', function() {
 							submit_event('pr','OnCancel');
 						}
 				 ) );
 
 				a_toolbar.Render();
 			</script>
 		</td>
 	</tr>
 </tbody>
 </table>
 
 <inp2:pr_SaveWarning name="grid_save_warning"/>
 <inp2:pr_ErrorWarning name="form_error_warning"/>
 
 <div id="scroll_container">
 	<table class="edit-form">
 		<inp2:m_RenderElement name="subsection" title="la_section_PriceBracket"/>
 			<inp2:m_RenderElement name="inp_edit_hidden" prefix="pr" field="ProductId"/>
 			<inp2:m_RenderElement name="inp_edit_box" prefix="pr" field="MinQty" title="la_fld_MinQty" size="4"/>
 			<inp2:m_RenderElement name="inp_edit_box" prefix="pr" field="MaxQty" title="la_fld_MaxQty" size="4"/>
 			<inp2:m_RenderElement name="inp_edit_box" prefix="pr" field="Price" title="la_fld_Price" size="4"/>
 		<!--## temporarily commented out
 			<inp2:m_RenderElement name="inp_edit_box" prefix="pr" field="Points" title="la_fld_Points" size="4"/>
 		##-->
 			<inp2:m_RenderElement name="inp_edit_box" prefix="pr" field="Cost" title="la_fld_Cost" size="4"/>
 			<inp2:m_RenderElement name="inp_edit_checkbox" prefix="pr" field="Negotiated" title="la_fld_Negotiated" size="4"/>
 		<inp2:m_RenderElement name="inp_edit_filler"/>
 	</table>
 </div>
 
 <inp2:m_include t="incs/footer"/>
\ No newline at end of file
Index: branches/5.3.x/admin_templates/products/relations_edit.tpl
===================================================================
--- branches/5.3.x/admin_templates/products/relations_edit.tpl	(revision 15670)
+++ branches/5.3.x/admin_templates/products/relations_edit.tpl	(revision 15671)
@@ -1,74 +1,76 @@
+<inp2:adm_SetPopupSize width="750" height="400"/>
+
 <inp2:m_include t="incs/header"/>
 <inp2:m_RenderElement name="combined_header" prefix="p" section="in-portal:browse" title_preset="relations_edit"/>
 
 <!-- ToolBar -->
 <table class="toolbar" height="30" cellspacing="0" cellpadding="0" width="100%" border="0">
 <tbody>
 	<tr>
   	<td>
   		<script type="text/javascript">
 				a_toolbar = new ToolBar();
 				a_toolbar.AddButton( new ToolBarButton('select', '<inp2:m_phrase label="la_ToolTip_Save" escape="1"/>', function() {
 							submit_event('rel','<inp2:rel_SaveEvent/>');
 						}
 					) );
 				a_toolbar.AddButton( new ToolBarButton('cancel', '<inp2:m_phrase label="la_ToolTip_Cancel" escape="1"/>', function() {
 							submit_event('rel','OnCancel');
 						}
 				 ) );
 
 				a_toolbar.AddButton( new ToolBarSeparator('sep1') );
 
 				a_toolbar.AddButton( new ToolBarButton('prev', '<inp2:m_phrase label="la_ToolTip_Prev" escape="1"/>', function() {
 					go_to_id('rel', '<inp2:rel_PrevId/>');
 				}
 				));
 
 				a_toolbar.AddButton( new ToolBarButton('next', '<inp2:m_phrase label="la_ToolTip_Next" escape="1"/>', function() {
 						go_to_id('rel', '<inp2:rel_NextId/>');
 					}
 				));
 
 				a_toolbar.Render();
 
 				<inp2:m_if check="rel_IsSingle" >
 					a_toolbar.HideButton('prev');
 					a_toolbar.HideButton('next');
 					a_toolbar.HideButton('sep1');
 				<inp2:m_else/>
 					<inp2:m_if check="rel_IsLast" >
 						a_toolbar.DisableButton('next');
 					</inp2:m_if>
 					<inp2:m_if check="rel_IsFirst" >
 						a_toolbar.DisableButton('prev');
 					</inp2:m_if>
 				</inp2:m_if>
 			</script>
 		</td>
 	</tr>
 </tbody>
 </table>
 
 <inp2:m_include t="categories/ci_blocks"/>
 
 <inp2:rel_SaveWarning name="grid_save_warning"/>
 <inp2:rel_ErrorWarning name="form_error_warning"/>
 
 <div id="scroll_container">
 	<table class="edit-form">
 		<inp2:m_RenderElement name="subsection" title="la_section_Relation"/>
 			<inp2:m_RenderElement name="inp_edit_hidden" prefix="rel" field="SourceId"/>
 			<inp2:m_RenderElement name="inp_edit_hidden" prefix="rel" field="SourceType"/>
 			<inp2:m_RenderElement name="inp_edit_hidden" prefix="rel" field="TargetId"/>
 			<inp2:m_RenderElement name="inp_edit_hidden" prefix="rel" field="TargetType"/>
 
 			<inp2:m_RenderElement name="inp_id_label" prefix="rel" field="RelationshipId" title="la_fld_Id"/>
 			<inp2:m_RenderElement name="inp_edit_relation" prefix="rel" field="TargetId" title="la_fld_TargetId"/>
 			<inp2:m_RenderElement name="inp_edit_radio" prefix="rel" field="Type" title="la_fld_RelationshipType"/>
 			<inp2:m_RenderElement name="inp_edit_checkbox" prefix="rel" field="Enabled" title="la_fld_Enabled"/>
 			<inp2:m_RenderElement name="inp_edit_box" prefix="rel" field="Priority" title="la_fld_Priority" size="4"/>
 		<inp2:m_RenderElement name="inp_edit_filler"/>
 	</table>
 </div>
 
 <inp2:m_include t="incs/footer"/>
\ No newline at end of file
Index: branches/5.3.x/admin_templates/products/review_edit.tpl
===================================================================
--- branches/5.3.x/admin_templates/products/review_edit.tpl	(revision 15670)
+++ branches/5.3.x/admin_templates/products/review_edit.tpl	(revision 15671)
@@ -1,75 +1,77 @@
+<inp2:adm_SetPopupSize width="750" height="400"/>
+
 <inp2:m_include t="incs/header"/>
 <inp2:m_RenderElement name="combined_header" prefix="p" section="in-portal:browse" title_preset="reviews_edit"/>
 
 <!-- ToolBar -->
 <table class="toolbar" height="30" cellspacing="0" cellpadding="0" width="100%" border="0">
 <tbody>
 	<tr>
   	<td>
   		<script type="text/javascript">
 				a_toolbar = new ToolBar();
 				a_toolbar.AddButton( new ToolBarButton('select', '<inp2:m_phrase label="la_ToolTip_Save" escape="1"/>', function() {
 							submit_event('rev','<inp2:rev_SaveEvent/>');
 						}
 					) );
 				a_toolbar.AddButton( new ToolBarButton('cancel', '<inp2:m_phrase label="la_ToolTip_Cancel" escape="1"/>', function() {
 							submit_event('rev','OnCancel');
 						}
 				 ) );
 
 				a_toolbar.AddButton( new ToolBarSeparator('sep1') );
 
 				a_toolbar.AddButton( new ToolBarButton('prev', '<inp2:m_phrase label="la_ToolTip_Prev" escape="1"/>', function() {
 						go_to_id('rev', '<inp2:rev_PrevId/>');
 					}
 				));
 
 				a_toolbar.AddButton( new ToolBarButton('next', '<inp2:m_phrase label="la_ToolTip_Next" escape="1"/>', function() {
 						go_to_id('rev', '<inp2:rev_NextId/>');
 					}
 				));
 
 				a_toolbar.Render();
 
 				<inp2:m_if check="rev_IsSingle" >
 					a_toolbar.HideButton('prev');
 					a_toolbar.HideButton('next');
 					a_toolbar.HideButton('sep1');
 				<inp2:m_else/>
 					<inp2:m_if check="rev_IsLast" >
 						a_toolbar.DisableButton('next');
 					</inp2:m_if>
 					<inp2:m_if check="rev_IsFirst" >
 						a_toolbar.DisableButton('prev');
 					</inp2:m_if>
 				</inp2:m_if>
 			</script>
 		</td>
 	</tr>
 </tbody>
 </table>
 
 <inp2:rev_SaveWarning name="grid_save_warning"/>
 <inp2:rev_ErrorWarning name="form_error_warning"/>
 
 <inp2:m_RenderElement name="inp_edit_hidden" prefix="rev" field="ItemId"/>
 
 <div id="scroll_container">
 	<table class="edit-form">
 		<inp2:m_RenderElement name="subsection" title="la_Text_Review"/>
 			<inp2:m_RenderElement name="inp_edit_checkbox_allow_html" prefix="rev" field="TextFormat"/>
 			<inp2:m_RenderElement name="inp_id_label" prefix="rev" field="ReviewId" title="la_fld_Id"/>
 			<inp2:m_RenderElement name="inp_edit_user" prefix="rev" field="CreatedById" title="la_fld_CreatedById" class="text"/>
 			<inp2:m_RenderElement name="inp_edit_textarea" prefix="rev" field="ReviewText" title="la_fld_ReviewText" cols="70" rows="8"/>
 			<inp2:m_RenderElement name="inp_edit_box" prefix="rev" field="HelpfulCount" title="la_fld_HelpfulCount" style="width: 50px;"/>
 			<inp2:m_RenderElement name="inp_edit_box" prefix="rev" field="NotHelpfulCount" title="la_fld_NotHelpfulCount" style="width: 50px;"/>
 
 		<inp2:m_RenderElement name="subsection" title="la_Text_General"/>
 			<inp2:m_RenderElement name="inp_edit_radio" prefix="rev" field="Status" title="la_fld_Status"/>
 			<inp2:m_RenderElement name="inp_edit_box" prefix="rev" field="Priority" title="la_fld_Priority" size="3" class="text"/>
 			<inp2:m_RenderElement name="inp_edit_date_time" prefix="rev" field="CreatedOn" title="la_fld_CreatedOn" size="20" class="text"/>
 		<inp2:m_RenderElement name="inp_edit_filler"/>
 	</table>
 </div>
 
 <inp2:m_include t="incs/footer"/>
\ No newline at end of file
Index: branches/5.3.x/admin_templates/products/products_edit.tpl
===================================================================
--- branches/5.3.x/admin_templates/products/products_edit.tpl	(revision 15670)
+++ branches/5.3.x/admin_templates/products/products_edit.tpl	(revision 15671)
@@ -1,181 +1,181 @@
 <inp2:adm_SetPopupSize width="1000" height="680"/>
 
 <inp2:m_include t="incs/header"/>
 <inp2:m_RenderElement name="combined_header" prefix="p" section="in-portal:browse" title_preset="products_edit" tab_preset="Default"/>
 
 <!-- ToolBar -->
 <table class="toolbar" height="30" cellspacing="0" cellpadding="0" width="100%" border="0">
 <tbody>
 	<tr>
   	<td>
   		<script type="text/javascript">
 				a_toolbar = new ToolBar();
 				a_toolbar.AddButton( new ToolBarButton('select', '<inp2:m_phrase label="la_ToolTip_Save" escape="1"/>', function() {
 							submit_event('p','<inp2:p_SaveEvent/>');
 						}
 					) );
 				a_toolbar.AddButton( new ToolBarButton('cancel', '<inp2:m_phrase label="la_ToolTip_Cancel" escape="1"/>', function() {
 							submit_event('p','OnCancelEdit');
 						}
 				 ) );
 
 				a_toolbar.AddButton( new ToolBarSeparator('sep1') );
 
 				a_toolbar.AddButton( new ToolBarButton('prev', '<inp2:m_phrase label="la_ToolTip_Prev" escape="1"/>', function() {
 							go_to_id('p', '<inp2:p_PrevId/>');
 						}
 				 ) );
 				a_toolbar.AddButton( new ToolBarButton('next', '<inp2:m_phrase label="la_ToolTip_Next" escape="1"/>', function() {
 							go_to_id('p', '<inp2:p_NextId/>');
 						}
 				 ) );
 
 				//a_toolbar.AddButton( new ToolBarSeparator('sep2') );
 
 				a_toolbar.Render();
 
 				<inp2:m_if check="p_IsSingle" >
 					a_toolbar.HideButton('prev');
 					a_toolbar.HideButton('next');
 					a_toolbar.HideButton('sep1');
 					//a_toolbar.HideButton('sep2');
 				<inp2:m_else/>
 					<inp2:m_if check="p_IsLast" >
 						a_toolbar.DisableButton('next');
 					</inp2:m_if>
 					<inp2:m_if check="p_IsFirst" >
 						a_toolbar.DisableButton('prev');
 					</inp2:m_if>
 				</inp2:m_if>
 			</script>
 		</td>
 
 		<inp2:m_RenderElement name="ml_selector" prefix="p"/>
 	</tr>
 </tbody>
 </table>
 
 <inp2:m_RenderElement name="inp_edit_hidden" prefix="p" field="Type" db="db"/>
 
 <inp2:p_SaveWarning name="grid_save_warning"/>
 <inp2:p_ErrorWarning name="form_error_warning"/>
 
 <div id="scroll_container">
 	<table class="edit-form">
 		<inp2:m_RenderElement name="subsection" title="la_section_Product"/>
 			<inp2:m_RenderElement name="inp_label" prefix="p" field="ProductId" title="la_fld_Id"/>
 
 			<inp2:m_if check="m_IsDebugMode" >
 				<inp2:m_RenderElement name="inp_label" prefix="p" field="Type" title="la_fld_ProductType"/>
 			</inp2:m_if>
 
 			<inp2:m_RenderElement name="inp_edit_box_ml" prefix="p" field="Name" title="la_fld_Title" size="70"/>
 			<inp2:m_RenderElement name="inp_edit_box" prefix="p" field="SKU" title="la_fld_SKU" size="70"/>
 
-			<inp2:m_RenderElement name="inp_edit_textarea_ml" prefix="p" field="Description" title="la_fld_Description" cols="70" rows="5"/>
+			<inp2:m_RenderElement name="inp_edit_textarea_ml" prefix="p" field="Description" title="la_fld_Description" allow_html="1" cols="70" rows="5"/>
 			<inp2:m_RenderElement name="inp_edit_textarea_ml" prefix="p" field="DescriptionExcerpt" title="la_fld_DescriptionExcerpt" cols="70" rows="3"/>
 
 			<inp2:m_RenderElement name="inp_edit_checkbox" prefix="p" field="AutomaticFilename" title="la_fld_AutomaticFilename" onchange="reflect_filename()"/>
 			<inp2:m_RenderElement name="inp_edit_box" prefix="p" field="Filename" title="la_fld_Filename" size="70"/>
 			<inp2:m_RenderElement name="inp_edit_options" prefix="p" field="CategoryId" title="la_fld_ParentSection" display_original="1"/>
 
 		<inp2:m_RenderElement name="subsection" title="la_section_Properties"/>
 
 			<inp2:m_if check="p_FieldEquals" field="Type" value="1" >
 				<inp2:m_RenderElement name="inp_edit_box" prefix="p" field="MinQtyFreePromoShipping" title="la_fld_ProductFreeShipping" size="5"/>
 			</inp2:m_if>
 
 			<inp2:m_if check="p_FieldEquals" field="Type" value="1">
 				<tr class="<inp2:m_odd_even odd='edit-form-odd' even='edit-form-even'/>">
 					<td class="label-cell">
 						<inp2:m_phrase label="la_fld_ManageShipping"/>:
 					</td>
 					<td class="control-mid">&nbsp;</td>
 					<td class="control-cell">
 						<a href="javascript:openShipping()">Open</a>
 					</td>
 				</tr>
 			</inp2:m_if>
 
 			<tr class="<inp2:m_odd_even odd='edit-form-odd' even='edit-form-even'/>">
 				<td class="label-cell">
 					<inp2:m_phrase label="la_fld_AssignedCoupon"/>:
 				</td>
 				<td class="control-mid">&nbsp;</td>
 				<td class="control-cell">
 					<inp2:p_Field name="AssignedCoupon" />&nbsp;<a href="javascript:openCouponSelector()">Open</a>
 				</td>
 			</tr>
 
 			<inp2:m_RenderElement name="inp_edit_options" prefix="p" field="ManufacturerId" title="la_fld_Manufacturer" size="4" has_empty="1"/>
 
 			<inp2:m_if check="p_FieldEquals" field="Type" value="3">
 				<inp2:m_RenderElement name="inp_edit_box" prefix="p" field="Price" title="la_fld_Price" size="5"/>
 			</inp2:m_if>
 
 			<inp2:m_if check="p_FieldEquals" field="Type" value="6">
 				<inp2:m_RenderElement name="inp_edit_box" prefix="p" field="Price" title="la_fld_Price" size="5"/>
 			</inp2:m_if>
 
 			<inp2:m_if check="p_FieldEquals" field="Type" value="1" >
 				<inp2:m_RenderElement name="inp_edit_weight" prefix="p" field="Weight" title="la_fld_Weight" size="5"/>
 			</inp2:m_if>
 
 			<inp2:m_RenderElement name="inp_edit_box" prefix="p" field="MSRP" title="la_fld_MSRP" size="5"/>
 			<inp2:m_RenderElement name="inp_edit_radio" prefix="p" field="Status" title="la_fld_Status"/>
 
 			<inp2:m_RenderElement name="inp_edit_radio" prefix="p" field="NewItem" title="la_fld_New"/>
 			<inp2:m_RenderElement name="inp_edit_radio" prefix="p" field="HotItem" title="la_fld_TopSeller"/>
 			<inp2:m_RenderElement name="inp_edit_radio" prefix="p" field="PopItem" title="la_fld_Pop"/>
 			<inp2:m_RenderElement name="inp_edit_checkbox" prefix="p" field="EditorsPick" title="la_fld_EditorsPick"/>
 			<inp2:m_RenderElement name="inp_edit_checkbox" prefix="p" field="Featured" title="la_fld_Featured"/>
 			<inp2:m_RenderElement name="inp_edit_checkbox" prefix="p" field="OnSale" title="la_fld_OnSale"/>
 			<inp2:m_RenderElement name="inp_edit_box" prefix="p" field="Priority" title="la_fld_Priority" size="4"/>
 
 			<inp2:m_RenderElement name="inp_edit_date_time" prefix="p" field="CreatedOn" title="la_fld_CreatedOn" size="12"/>
 			<inp2:m_RenderElement name="inp_edit_date_time" prefix="p" field="Expire" title="la_fld_Expire" size="12"/>
 
 			<inp2:m_RenderElement name="inp_edit_box" prefix="p" field="MetaKeywords" title="la_fld_MetaKeywords" size="70"/>
 			<inp2:m_RenderElement name="inp_edit_textarea" prefix="p" field="MetaDescription" title="la_fld_MetaDescription" cols="70" rows="5"/>
 
 			<inp2:m_if check="p_FieldEquals" field="Type" value="1" >
 				<inp2:m_RenderElement name="subsection" title="la_section_Backordering"/>
 					<inp2:m_RenderElement name="inp_edit_radio" prefix="p" field="BackOrder" title="la_fld_BackOrder"/>
 					<inp2:m_RenderElement name="inp_edit_date_time" format="mm/dd/y" prefix="p" field="BackOrderDate" title="la_fld_BackOrderDate" size="12"/>
 					<inp2:m_RenderElement name="inp_edit_box" prefix="p" field="QtyInStockMin" title="la_fld_QtyInStockMin" size="4"/>
 			</inp2:m_if>
 
 		<inp2:m_RenderElement name="subsection" title="la_section_Counters"/>
 			<inp2:m_RenderElement name="inp_edit_box" prefix="p" field="CachedRating" title="la_fld_Rating" size="4"/>
 			<inp2:m_RenderElement name="inp_edit_box" prefix="p" field="CachedVotesQty" title="la_fld_Votes" size="4"/>
 			<inp2:m_RenderElement name="inp_edit_box" prefix="p" field="Hits" title="la_fld_QtySold" size="4"/>
 			<input type="hidden" name="Hits_original" id="Hits_original" value="<inp2:p_Field name="Hits" db="db" />" />
 
 	<!-- custom fields: begin -->
 		<inp2:m_include t="incs/custom_blocks"/>
 		<inp2:cf.general_PrintList render_as="cv_row_block" SourcePrefix="p" value_field="Value" per_page="-1" grid="Default" />
 	<!-- custom fields: end -->
 
 		<inp2:m_RenderElement name="inp_edit_filler"/>
 	</table>
 </div>
 
 <script language="javascript" type="text/javascript">
 	$(document).ready(reflect_filename);
 	disable_categories('<inp2:p_InputName name="CategoryId"/>', <inp2:p_AllowedCategoriesJSON/>);
 
 	function reflect_filename() {
     	var $checked = document.getElementById('_cb_<inp2:p_InputName field="AutomaticFilename"/>').checked;
     	document.getElementById('<inp2:p_InputName field="Filename"/>').readOnly = $checked;
     }
 
 	function openShipping() {
 		openSelector('p','<inp2:m_link t="in-commerce/products/shipping_options" pass="all"/>', 'ShippingOption', '800x600', 'OnPreSaveAndOpenPopup');
 	}
 
 	function openCouponSelector() {
 		openSelector('p','<inp2:m_link t="in-commerce/discounts/coupon_selector" pass="all"/>', 'AssignedCoupon', '800x400', 'OnPreSaveAndOpenPopup');
 	}
 </script>
 
 <inp2:m_include t="incs/footer"/>
\ No newline at end of file
Index: branches/5.3.x/admin_templates/products/images_edit.tpl
===================================================================
--- branches/5.3.x/admin_templates/products/images_edit.tpl	(revision 15670)
+++ branches/5.3.x/admin_templates/products/images_edit.tpl	(revision 15671)
@@ -1,86 +1,88 @@
+<inp2:adm_SetPopupSize width="750" height="670"/>
+
 <inp2:m_include t="incs/header"/>
 <inp2:m_RenderElement name="combined_header" prefix="p" section="in-portal:browse" title_preset="images_edit"/>
 
 <inp2:m_include t="incs/image_blocks"/>
 
 <!-- ToolBar -->
 <table class="toolbar" height="30" cellspacing="0" cellpadding="0" width="100%" border="0">
 <tbody>
 	<tr>
   	<td>
   		<script type="text/javascript">
 				a_toolbar = new ToolBar();
 				a_toolbar.AddButton( new ToolBarButton('select', '<inp2:m_phrase label="la_ToolTip_Save" escape="1"/>', function() {
 							submit_event('img','<inp2:img_SaveEvent/>');
 						}
 					) );
 				a_toolbar.AddButton( new ToolBarButton('cancel', '<inp2:m_phrase label="la_ToolTip_Cancel" escape="1"/>', function() {
 							submit_event('img','OnCancel');
 						}
 				 ) );
 
 				a_toolbar.AddButton( new ToolBarSeparator('sep1') );
 
 				a_toolbar.AddButton( new ToolBarButton('prev', '<inp2:m_phrase label="la_ToolTip_Prev" escape="1"/>', function() {
 						go_to_id('img', '<inp2:img_PrevId/>');
 					}
 				));
 
 				a_toolbar.AddButton( new ToolBarButton('next', '<inp2:m_phrase label="la_ToolTip_Next" escape="1"/>', function() {
 						go_to_id('img', '<inp2:img_NextId/>');
 					}
 				));
 
 				a_toolbar.Render();
 
 				<inp2:m_if check="img_IsSingle" >
 					a_toolbar.HideButton('prev');
 					a_toolbar.HideButton('next');
-					a_toolbar.HideButton('sep1');					
+					a_toolbar.HideButton('sep1');
 				<inp2:m_else/>
 					<inp2:m_if check="img_IsLast" >
 						a_toolbar.DisableButton('next');
 					</inp2:m_if>
 					<inp2:m_if check="img_IsFirst" >
 						a_toolbar.DisableButton('prev');
 					</inp2:m_if>
 				</inp2:m_if>
 			</script>
 		</td>
 	</tr>
 </tbody>
 </table>
 
 <inp2:img_SaveWarning name="grid_save_warning"/>
 <inp2:img_ErrorWarning name="form_error_warning"/>
 
 <div id="scroll_container">
 	<table class="edit-form">
 		<inp2:m_RenderElement name="subsection" title="la_section_Image"/>
 			<inp2:m_RenderElement name="inp_edit_hidden" prefix="img" field="ResourceId"/>
 			<inp2:m_RenderElement name="inp_id_label" prefix="img" field="ImageId" title="la_fld_Id"/>
 
 			<inp2:m_RenderElement name="inp_edit_box" prefix="img" field="Name" title="la_fld_Name" size="40"/>
 			<inp2:m_RenderElement name="inp_edit_box" prefix="img" field="AltName" title="la_fld_AltValue" size="40"/>
 
 			<inp2:m_RenderElement name="inp_edit_checkbox" prefix="img" field="Enabled" title="la_fld_Enabled" onchange="check_primary()" />
 			<inp2:m_RenderElement name="inp_edit_checkbox" prefix="img" field="DefaultImg" title="la_fld_Primary" onchange="check_status()" />
 			<inp2:m_RenderElement name="inp_edit_box" prefix="img" field="Priority" title="la_fld_Priority" size="5"/>
 
 		<inp2:m_RenderElement name="subsection" title="la_section_ThumbnailImage"/>
 			<inp2:m_RenderElement name="thumbnail_section" prefix="img"/>
 
 		<inp2:m_RenderElement name="subsection" title="la_section_FullSizeImage"/>
 			<inp2:m_RenderElement name="inp_edit_checkbox" prefix="img" field="SameImages" title="la_fld_SameAsThumb" onchange="toggle_fullsize()"/>
 			<inp2:m_RenderElement name="fullsize_section" prefix="img"/>
 
 		<inp2:m_RenderElement name="inp_edit_filler"/>
 	</table>
 </div>
 
 <script type="text/javascript">
 	<inp2:m_RenderElement name="images_edit_js" prefix="img"/>
 	toggle_fullsize();
 </script>
 
 <inp2:m_include t="incs/footer"/>
\ No newline at end of file
Index: branches/5.3.x/admin_templates/img/toolbar/toolbar-sprite.png
===================================================================
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Index: branches/5.3.x/install/upgrades.php
===================================================================
--- branches/5.3.x/install/upgrades.php	(revision 15670)
+++ branches/5.3.x/install/upgrades.php	(revision 15671)
@@ -1,188 +1,189 @@
 <?php
 /**
 * @version	$Id$
 * @package	In-Commerce
 * @copyright	Copyright (C) 1997 - 2009 Intechnic. All rights reserved.
 * @license	Commercial License
 * This software is protected by copyright law and international treaties.
 * Unauthorized reproduction or unlicensed usage of the code of this program,
 * or any portion of it may result in severe civil and criminal penalties,
 * and will be prosecuted to the maximum extent possible under the law
 * See http://www.in-portal.org/commercial-license for copyright notices and details.
 */
 	defined('FULL_PATH') or die('restricted access!');
 
 	$upgrade_class = 'InCommerceUpgrades';
 
 	/**
 	 * Class, that holds all upgrade scripts for "In-Commerce" module
 	 *
 	 */
 	class InCommerceUpgrades extends kUpgradeHelper {
 
 		public function __construct()
 		{
 			parent::__construct();
 
 			$this->dependencies = Array (
 				'4.3.9' => Array ('Core' => '4.3.9'),
 				'5.0.0' => Array ('Core' => '5.0.0'),
 				'5.0.1' => Array ('Core' => '5.0.1'),
 				'5.0.2-B1' => Array ('Core' => '5.0.2-B1'),
 				'5.0.2-B2' => Array ('Core' => '5.0.2-B2'),
 				'5.0.2-RC1' => Array ('Core' => '5.0.2-RC1'),
 				'5.0.2' => Array ('Core' => '5.0.2'),
 				'5.0.3-B1' => Array ('Core' => '5.0.3-B1'),
 				'5.0.3-B2' => Array ('Core' => '5.0.3-B2'),
 				'5.0.3-RC1' => Array ('Core' => '5.0.3-RC1'),
 				'5.0.3' => Array ('Core' => '5.0.3'),
 				'5.0.4-B1' => Array ('Core' => '5.0.4-B1'),
 				'5.0.4-B2' => Array ('Core' => '5.0.4-B2'),
 				'5.0.4' => Array ('Core' => '5.0.4'),
 				'5.1.0-B1' => Array ('Core' => '5.1.0-B1'),
 				'5.1.0-B2' => Array ('Core' => '5.1.0-B2'),
 				'5.1.0-RC1' => Array ('Core' => '5.1.0-RC1'),
 				'5.1.0' => Array ('Core' => '5.1.0'),
 				'5.1.1-B1' => Array ('Core' => '5.1.1-B1'),
 				'5.1.1-B2' => Array ('Core' => '5.1.1-B2'),
 				'5.1.1-RC1' => Array ('Core' => '5.1.1-RC1'),
 				'5.1.1' => Array ('Core' => '5.1.1'),
 				'5.1.2-B1' => Array ('Core' => '5.1.2-B1'),
 				'5.1.2-B2' => Array ('Core' => '5.1.2-B2'),
 				'5.1.2-RC1' => Array ('Core' => '5.1.2-RC1'),
 				'5.1.2' => Array ('Core' => '5.1.2'),
 				'5.1.3-B1' => Array ('Core' => '5.1.3-B1'),
 				'5.1.3-B2' => Array ('Core' => '5.1.3-B2'),
 				'5.1.3-RC1' => Array ('Core' => '5.1.3-RC1'),
 				'5.1.3-RC2' => Array ('Core' => '5.1.3-RC2'),
 				'5.1.3' => Array ('Core' => '5.1.3'),
 				'5.2.0-B1' => Array ('Core' => '5.2.0-B1'),
 				'5.2.0-B2' => Array ('Core' => '5.2.0-B2'),
 				'5.2.0-B3' => Array ('Core' => '5.2.0-B3'),
 				'5.2.0-RC1' => Array ('Core' => '5.2.0-RC1'),
 				'5.2.0' => Array ('Core' => '5.2.0'),
+				'5.2.1-B1' => Array ('Core' => '5.2.1-B1'),
 			);
 		}
 
 		/**
 		 * Changes table structure, where multilingual fields of TEXT type are present
 		 *
 		 * @param string $mode when called mode {before, after)
 		 */
 		function Upgrade_5_0_0($mode)
 		{
 			if ($mode == 'after') {
 				// update icon
 				$root_category = $this->Application->findModule('Name', 'In-Commerce', 'RootCat');
 
 				$sql = 'UPDATE ' . $this->Application->getUnitOption('c', 'TableName') . '
 						SET UseMenuIconUrl = 1, MenuIconUrl = "in-commerce/img/menu_products.gif"
 						WHERE ' . $this->Application->getUnitOption('c', 'IDField') . ' = ' . $root_category;
 				$this->Conn->Query($sql);
 
 				$this->_updateDetailTemplate('p', 'in-commerce/product/details', 'in-commerce/designs/detail');
 
 				// copy store name to company name
 				$store_name = $this->Application->ConfigValue('Comm_StoreName');
 
 				$sql = 'UPDATE ' . TABLE_PREFIX . 'ConfigurationValues
 						SET VariableValue = ' . $this->Conn->qstr($store_name) . '
 						WHERE VariableName = "Comm_CompanyName"';
 				$this->Conn->Query($sql);
 			}
 		}
 
 		/**
 		 * Update to 5.0.1, update details template
 		 *
 		 * @param string $mode when called mode {before, after)
 		 */
 		function Upgrade_5_0_1($mode)
 		{
 			if ($mode == 'after') {
 				$this->_updateDetailTemplate('p', 'in-commerce/designs/detail', 'in-commerce/products/product_detail');
 
 				// clean incomplete orders 5+ hours old
 				// don't use ORDER_STATUS_INCOMPLETE constant, since it's not available upgrade
-				$delete_timestamp = mktime() - (3600 * 5);
+				$delete_timestamp = time() - (3600 * 5);
 				$sql = 'SELECT OrderId FROM ' . TABLE_PREFIX . 'Orders
 							WHERE Status = ' . 0 . '
 							AND OrderDate < ' . $delete_timestamp;
 
 				$orders_to_delete = $this->Conn->GetCol($sql);
 
 				if ( $orders_to_delete && is_array($orders_to_delete) ) {
 
 					$this->Conn->Query( 'DELETE FROM ' . TABLE_PREFIX . 'OrderItems
 											WHERE OrderId IN ( ' . implode(',', $orders_to_delete) . ' )' );
 
 					$this->Conn->Query( 'DELETE FROM ' . TABLE_PREFIX . 'Orders
 											WHERE Status = ' . 0 . '
 											AND OrderDate < ' . $delete_timestamp );
 				}
 
 				// delete old events
 				$events_to_delete = Array ( 'SITE.SUGGEST' );
 
 				$sql = 'SELECT EventId FROM ' . TABLE_PREFIX . 'Events
 							WHERE Event IN ("' . implode('","', $events_to_delete) . '")';
 				$event_ids = $this->Conn->GetCol($sql);
 
 				if ($event_ids) {
 					$sql = 'DELETE FROM ' . TABLE_PREFIX . 'EmailMessage
 								WHERE EventId IN (' . implode(',', $event_ids) . ')';
 					$this->Conn->Query($sql);
 
 					$sql = 'DELETE FROM ' . TABLE_PREFIX . 'Events
 								WHERE EventId IN (' . implode(',', $event_ids) . ')';
 					$this->Conn->Query($sql);
 
 					$sql = 'DELETE FROM ' . TABLE_PREFIX . 'Phrase
 								WHERE Phrase IN ("la_event_user.suggest_site")';
 					$this->Conn->Query($sql);
 				}
 			}
 		}
 
 		/**
 		 * Update to 5.2.0-RC1
 		 *
 		 * @param string $mode when called mode {before, after)
 		 */
 		public function Upgrade_5_2_0_RC1($mode)
 		{
 			if ( $mode != 'before' ) {
 				return;
 			}
 
 			$table_name = $this->Application->getUnitOption('pt', 'TableName');
 			$table_structure = $this->Conn->Query('DESCRIBE ' . $table_name, 'Field');
 
 			if ( isset($table_structure['Description']) ) {
 				$sql = 'UPDATE ' . $table_name . '
 						SET Description = ""
 						WHERE Description IS NULL';
 				$this->Conn->Query($sql);
 
 				$sql = 'ALTER TABLE ' . $table_name . '
 						CHANGE `Description` `Description` VARCHAR(255) NOT NULL DEFAULT ""';
 				$this->Conn->Query($sql);
 			}
 
 			$ml_helper = $this->Application->recallObject('kMultiLanguageHelper');
 			/* @var $ml_helper kMultiLanguageHelper */
 
 			$ml_helper->createFields('pt');
 
 			if ( isset($table_structure['Description']) ) {
 				$sql = 'UPDATE ' . $table_name . '
 						SET
 							l' . $this->Application->GetDefaultLanguageId() . '_Description = Description,
 							l' . $this->Application->GetDefaultLanguageId() . '_Instructions = Instructions';
 				$this->Conn->Query($sql);
 
 				$sql = 'ALTER TABLE ' . $table_name . ' DROP Description, DROP Instructions';
 				$this->Conn->Query($sql);
 			}
 		}
 	}
\ No newline at end of file
Index: branches/5.3.x/install/install_schema.sql
===================================================================
--- branches/5.3.x/install/install_schema.sql	(revision 15670)
+++ branches/5.3.x/install/install_schema.sql	(revision 15671)
@@ -1,747 +1,747 @@
 CREATE TABLE Addresses (
   AddressId int(11) NOT NULL auto_increment,
   PortalUserId int(11) NOT NULL default '0',
   `To` varchar(255) NOT NULL default '',
   Company varchar(255) NOT NULL default '',
   Phone varchar(255) NOT NULL default '',
   Fax varchar(255) NOT NULL default '',
   Email varchar(255) NOT NULL default '',
   Address1 varchar(255) NOT NULL default '',
   Address2 varchar(255) NOT NULL default '',
   City varchar(255) NOT NULL default '',
   State char(2) NOT NULL default '',
   Zip varchar(20) NOT NULL default '',
   Country char(3) NOT NULL default '',
   LastUsedAsBilling tinyint(4) unsigned NOT NULL default '0',
   LastUsedAsShipping tinyint(4) unsigned NOT NULL default '0',
   IsProfileAddress tinyint(4) NOT NULL default '0',
   PRIMARY KEY  (AddressId),
   KEY PortalUserId (PortalUserId),
   KEY LastUsedAsBilling (LastUsedAsBilling),
   KEY LastUsedAsShipping (LastUsedAsShipping),
   KEY IsProfileAddress (IsProfileAddress)
 );
 
 CREATE TABLE Currencies (
   CurrencyId int(11) NOT NULL AUTO_INCREMENT,
   ISO char(3) NOT NULL DEFAULT '',
   Symbol varchar(255) DEFAULT NULL,
   SymbolPosition tinyint(4) DEFAULT NULL,
   `Name` varchar(255) NOT NULL DEFAULT '',
   RateToPrimary double NOT NULL DEFAULT '1',
   Modified int(11) DEFAULT NULL,
   `Status` smallint(6) NOT NULL DEFAULT '1',
   IsPrimary smallint(6) NOT NULL DEFAULT '0',
   Priority int(11) NOT NULL DEFAULT '0',
   PRIMARY KEY (CurrencyId),
   KEY Priority (Priority),
   KEY IsPrimary (IsPrimary),
   KEY Modified (Modified)
 );
 
 CREATE TABLE GatewayConfigFields (
   GWConfigFieldId int(11) NOT NULL AUTO_INCREMENT,
   SystemFieldName varchar(50) NOT NULL DEFAULT '',
   FieldName varchar(100) NOT NULL DEFAULT '',
   ElementType varchar(30) NOT NULL DEFAULT 'text',
   ValueList mediumtext,
   GatewayId int(11) NOT NULL DEFAULT '0',
   PRIMARY KEY (GWConfigFieldId),
   KEY GatewayId (GatewayId)
 );
 
 CREATE TABLE GatewayConfigValues (
   GWConfigValueId int(11) NOT NULL auto_increment,
   GWConfigFieldId int(11) NOT NULL default '0',
   PaymentTypeId int(11) NOT NULL default '0',
   Value varchar(255) default NULL,
   PRIMARY KEY  (GWConfigValueId),
   KEY GWConfigFieldId (GWConfigFieldId),
   KEY PaymentTypeId (PaymentTypeId)
 );
 
 CREATE TABLE Gateways (
   GatewayId int(11) NOT NULL auto_increment,
   Name varchar(100) NOT NULL default '',
   ClassName varchar(150) NOT NULL default '',
   ClassFile varchar(255) NOT NULL default '',
   RequireCCFields tinyint(4) NOT NULL default '0',
   PRIMARY KEY  (GatewayId)
 );
 
 CREATE TABLE Manufacturers (
   ManufacturerId int(11) NOT NULL AUTO_INCREMENT,
   `Name` varchar(255) NOT NULL DEFAULT '',
   Description text,
   URL varchar(255) NOT NULL DEFAULT '',
   Logo varchar(255) NOT NULL DEFAULT '',
   IsPopular int(10) unsigned NOT NULL DEFAULT '0',
   Address1 varchar(255) DEFAULT NULL,
   Address2 varchar(255) DEFAULT NULL,
   City varchar(255) DEFAULT NULL,
   State varchar(50) DEFAULT NULL,
   Zip varchar(50) DEFAULT NULL,
   Country varchar(255) DEFAULT NULL,
   Phone varchar(50) DEFAULT NULL,
   Fax varchar(50) DEFAULT NULL,
   Email varchar(255) DEFAULT NULL,
   PRIMARY KEY (ManufacturerId)
 );
 
 CREATE TABLE OrderItems (
   OrderItemId int(11) NOT NULL AUTO_INCREMENT,
   OrderId int(11) NOT NULL DEFAULT '0',
   ProductId int(11) NOT NULL DEFAULT '0',
   ProductName varchar(255) NOT NULL DEFAULT '',
   Quantity int(11) NOT NULL DEFAULT '0',
   QuantityReserved int(11) DEFAULT NULL,
   FlatPrice decimal(10,4) NOT NULL DEFAULT '0.0000',
   Price decimal(10,4) NOT NULL DEFAULT '0.0000',
   Cost double(10,4) NOT NULL DEFAULT '0.0000',
   BackOrderFlag tinyint(4) DEFAULT '0',
   Weight double DEFAULT NULL,
   ShippingTypeId varchar(255) DEFAULT NULL,
   ItemData text,
   OptionsSalt bigint(11) DEFAULT '0',
   SplitShippingGroup int(11) NOT NULL DEFAULT '0',
   PackageNum int(11) NOT NULL DEFAULT '0',
   ReturnType tinyint(3) unsigned NOT NULL DEFAULT '0',
   ReturnAmount decimal(10,2) NOT NULL DEFAULT '0.00',
   ReturnedOn int(10) unsigned DEFAULT NULL,
   PRIMARY KEY (OrderItemId),
   KEY OrderId (OrderId),
   KEY ProductId (ProductId),
   KEY BackOrderFlag (BackOrderFlag),
   KEY PackageNum (PackageNum),
   KEY ReturnType (ReturnType),
   KEY ReturnedOn (ReturnedOn),
   KEY Quantity (Quantity),
   KEY QuantityReserved (QuantityReserved),
   KEY OptionsSalt (OptionsSalt),
   KEY SplitShippingGroup (SplitShippingGroup)
 );
 
 CREATE TABLE Orders (
   OrderId int(11) NOT NULL AUTO_INCREMENT,
   Number mediumint(9) NOT NULL DEFAULT '0',
   SubNumber smallint(6) NOT NULL DEFAULT '0',
   `Status` tinyint(3) unsigned NOT NULL DEFAULT '0',
   OnHold tinyint(3) unsigned NOT NULL DEFAULT '0',
   OrderDate int(10) unsigned DEFAULT NULL,
   PortalUserId int(11) NOT NULL DEFAULT '-1',
   OrderIP varchar(30) NOT NULL DEFAULT '',
   UserComment text,
   AdminComment text,
   BillingTo varchar(255) NOT NULL DEFAULT '',
   BillingCompany varchar(255) NOT NULL DEFAULT '',
   BillingPhone varchar(255) NOT NULL DEFAULT '',
   BillingFax varchar(255) NOT NULL DEFAULT '',
   BillingEmail varchar(255) NOT NULL DEFAULT '',
   BillingAddress1 varchar(255) NOT NULL DEFAULT '',
   BillingAddress2 varchar(255) NOT NULL DEFAULT '',
   BillingCity varchar(255) NOT NULL DEFAULT '',
   BillingState varchar(255) NOT NULL DEFAULT '',
   BillingZip varchar(255) NOT NULL DEFAULT '',
   BillingCountry varchar(255) NOT NULL DEFAULT 'USA',
   VAT decimal(20,4) NOT NULL DEFAULT '0.0000',
   VATPercent decimal(20,4) NOT NULL DEFAULT '0.0000',
   PaymentType tinyint(3) unsigned NOT NULL DEFAULT '0',
   PaymentAccount varchar(255) NOT NULL DEFAULT '',
   PaymentExpires int(10) unsigned DEFAULT NULL,
   PaymentNameOnCard varchar(255) NOT NULL DEFAULT '',
   PaymentCCExpDate varchar(5) NOT NULL DEFAULT '',
   PaymentCardType varchar(255) NOT NULL DEFAULT '',
   ShippingTo varchar(255) NOT NULL DEFAULT '',
   ShippingCompany varchar(255) NOT NULL DEFAULT '',
   ShippingPhone varchar(255) NOT NULL DEFAULT '',
   ShippingFax varchar(255) NOT NULL DEFAULT '',
   ShippingEmail varchar(255) NOT NULL DEFAULT '',
   ShippingAddress1 varchar(255) NOT NULL DEFAULT '',
   ShippingAddress2 varchar(255) NOT NULL DEFAULT '',
   ShippingCity varchar(255) NOT NULL DEFAULT '',
   ShippingState varchar(255) NOT NULL DEFAULT '',
   ShippingZip varchar(255) NOT NULL DEFAULT '',
   ShippingCountry varchar(255) NOT NULL DEFAULT 'USA',
   ShippingType int(11) NOT NULL DEFAULT '0',
   ShippingCost decimal(20,4) NOT NULL DEFAULT '0.0000',
   ShippingCustomerAccount varchar(255) NOT NULL DEFAULT '',
   ShippingTracking varchar(255) NOT NULL DEFAULT '',
   ShippingDate int(11) DEFAULT NULL,
   SubTotal decimal(20,4) unsigned NOT NULL DEFAULT '0.0000',
   ReturnTotal decimal(20,4) NOT NULL DEFAULT '0.0000',
   CostTotal decimal(20,4) NOT NULL DEFAULT '0.0000',
   OriginalAmount decimal(20,4) NOT NULL DEFAULT '0.0000',
   ShippingOption tinyint(4) NOT NULL DEFAULT '0',
   ShippingInfo text,
   CouponId int(11) DEFAULT NULL,
   CouponDiscount decimal(20,4) NOT NULL DEFAULT '0.0000',
   DiscountTotal decimal(10,4) NOT NULL DEFAULT '0.0000',
   TransactionStatus tinyint(3) unsigned NOT NULL DEFAULT '2',
   GWResult1 mediumtext,
   GWResult2 mediumtext,
   AffiliateId int(10) unsigned NOT NULL DEFAULT '0',
   VisitId int(10) unsigned NOT NULL DEFAULT '0',
   AffiliateCommission decimal(10,4) NOT NULL DEFAULT '0.0000',
   ProcessingFee decimal(20,4) DEFAULT '0.0000',
   InsuranceFee decimal(20,4) NOT NULL DEFAULT '0.0000',
   ShippingTaxable tinyint(1) NOT NULL DEFAULT '0',
   ProcessingTaxable tinyint(1) NOT NULL DEFAULT '0',
   IsRecurringBilling tinyint(4) NOT NULL DEFAULT '0',
   NextCharge int(10) unsigned DEFAULT NULL,
   GroupId int(10) unsigned NOT NULL DEFAULT '0',
   ChargeOnNextApprove tinyint(4) NOT NULL DEFAULT '0',
   ShippingGroupOption tinyint(4) NOT NULL DEFAULT '0',
   GiftCertificateId int(11) DEFAULT NULL,
   GiftCertificateDiscount decimal(20,4) NOT NULL DEFAULT '0.0000',
   GoogleOrderNumber bigint(20) unsigned DEFAULT NULL,
   VATIncluded tinyint(1) unsigned NOT NULL DEFAULT 0,
   PRIMARY KEY (OrderId),
   KEY AffiliateId (AffiliateId),
   KEY VisitId (VisitId),
   KEY GoogleOrderNumber (GoogleOrderNumber),
   KEY Number (Number),
   KEY SubNumber (SubNumber),
   KEY `Status` (`Status`),
   KEY OrderDate (OrderDate),
   KEY PaymentType (PaymentType),
   KEY CouponId (CouponId),
   KEY GroupId (GroupId),
   KEY GiftCertificateId (GiftCertificateId)
 );
 
 CREATE TABLE GiftCertificates (
   GiftCertificateId int(11) NOT NULL AUTO_INCREMENT,
   OrderId int(11) DEFAULT '0',
   Purchaser varchar(64) DEFAULT NULL,
   Recipient varchar(64) DEFAULT NULL,
   SendVia tinyint(1) NOT NULL DEFAULT '0',
   RecipientEmail varchar(64) NOT NULL DEFAULT '',
   RecipientFirstname varchar(128) DEFAULT NULL,
   RecipientLastname varchar(128) DEFAULT NULL,
   RecipientAddress1 varchar(255) DEFAULT NULL,
   RecipientAddress2 varchar(255) DEFAULT NULL,
   RecipientCity varchar(64) DEFAULT NULL,
   RecipientState varchar(32) DEFAULT NULL,
   RecipientZipcode varchar(32) DEFAULT NULL,
   RecipientCountry char(3) NOT NULL DEFAULT 'USA',
   RecipientPhone varchar(32) DEFAULT NULL,
   Message text,
   Amount decimal(12,2) DEFAULT '0.00',
   Debit decimal(12,2) DEFAULT '0.00',
   `Status` tinyint(1) NOT NULL DEFAULT '2',
   AddDate int(11) DEFAULT '0',
   Expiration int(11) DEFAULT NULL,
   `Code` varchar(255) DEFAULT NULL,
   PRIMARY KEY (GiftCertificateId),
   UNIQUE KEY `Code` (`Code`),
   KEY OrderId (OrderId),
   KEY `Status` (`Status`),
   KEY AddDate (AddDate)
 );
 
 CREATE TABLE PaymentTypeCurrencies (
   PaymentTypeCurrencyId int(11) NOT NULL auto_increment,
   PaymentTypeId int(11) NOT NULL default '0',
   CurrencyId int(11) NOT NULL default '0',
   PRIMARY KEY  (PaymentTypeCurrencyId),
   KEY PaymentTypeId (PaymentTypeId),
   KEY CurrencyId (CurrencyId)
 );
 
 CREATE TABLE PaymentTypes (
   PaymentTypeId int(11) NOT NULL AUTO_INCREMENT,
   `Name` varchar(100) NOT NULL DEFAULT '',
   l1_Description varchar(255) DEFAULT '',
   l2_Description varchar(255) DEFAULT '',
   l3_Description varchar(255) DEFAULT '',
   l4_Description varchar(255) DEFAULT '',
   l5_Description varchar(255) DEFAULT '',
   l1_Instructions text,
   l2_Instructions text,
   l3_Instructions text,
   l4_Instructions text,
   l5_Instructions text,
   AdminComments text,
   `Status` int(11) NOT NULL DEFAULT '0',
   Priority int(11) NOT NULL DEFAULT '0',
   IsPrimary tinyint(4) NOT NULL DEFAULT '0',
   BuiltIn smallint(6) NOT NULL DEFAULT '0',
   GatewayId int(11) NOT NULL DEFAULT '1',
   PlacedOrdersEdit tinyint(4) NOT NULL DEFAULT '0',
   ProcessingFee double NOT NULL DEFAULT '0',
   PortalGroups text,
   PRIMARY KEY (PaymentTypeId),
   KEY `Status` (`Status`),
   KEY Priority (Priority),
   KEY GatewayId (GatewayId),
   KEY BuiltIn (BuiltIn),
   KEY IsPrimary (IsPrimary),
   KEY l1_Description (l1_Description(5)),
   KEY l2_Description (l2_Description(5)),
   KEY l3_Description (l3_Description(5)),
   KEY l4_Description (l4_Description(5)),
   KEY l5_Description (l5_Description(5)),
   KEY l1_Instructions (l1_Instructions(5)),
   KEY l2_Instructions (l2_Instructions(5)),
   KEY l3_Instructions (l3_Instructions(5)),
   KEY l4_Instructions (l4_Instructions(5)),
   KEY l5_Instructions (l5_Instructions(5))
 );
 
 CREATE TABLE Products (
   ProductId int(11) NOT NULL AUTO_INCREMENT,
   `Name` varchar(255) DEFAULT '',
   l1_Name varchar(255) DEFAULT NULL,
   l2_Name varchar(255) DEFAULT NULL,
   l3_Name varchar(255) DEFAULT NULL,
   l4_Name varchar(255) DEFAULT NULL,
   l5_Name varchar(255) DEFAULT NULL,
   AutomaticFilename tinyint(3) unsigned NOT NULL DEFAULT '1',
   SKU varchar(255) DEFAULT NULL,
   `Type` tinyint(2) unsigned NOT NULL DEFAULT '1',
   Description text,
   l1_Description text,
   l2_Description text,
   l3_Description text,
   l4_Description text,
   l5_Description text,
   DescriptionExcerpt text,
   l1_DescriptionExcerpt text,
   l2_DescriptionExcerpt text,
   l3_DescriptionExcerpt text,
   l4_DescriptionExcerpt text,
   l5_DescriptionExcerpt text,
   Weight double(10,4) DEFAULT NULL,
   ManufacturerId int(11) NOT NULL DEFAULT '0',
   MSRP double DEFAULT NULL,
   BackOrder tinyint(3) unsigned NOT NULL DEFAULT '2',
   BackOrderDate int(11) DEFAULT NULL,
   CreatedOn int(10) unsigned DEFAULT NULL,
   Modified int(10) unsigned DEFAULT NULL,
   Expire int(10) unsigned DEFAULT NULL,
   Hits double NOT NULL DEFAULT '0',
   CachedRating varchar(10) NOT NULL DEFAULT '0',
   CachedVotesQty int(11) NOT NULL DEFAULT '0',
   CachedReviewsQty int(11) NOT NULL DEFAULT '0',
   CreatedById int(11) DEFAULT NULL,
   ModifiedById int(11) DEFAULT NULL,
   Priority int(11) NOT NULL DEFAULT '0',
   `Status` tinyint(4) NOT NULL DEFAULT '2',
   EditorsPick tinyint(4) NOT NULL DEFAULT '0',
   Featured tinyint(4) NOT NULL DEFAULT '0',
   OnSale tinyint(1) NOT NULL DEFAULT '0',
   ResourceId int(11) DEFAULT NULL,
   HotItem tinyint(4) NOT NULL DEFAULT '2',
   PopItem tinyint(4) NOT NULL DEFAULT '2',
   NewItem tinyint(4) NOT NULL DEFAULT '2',
   InventoryStatus tinyint(4) NOT NULL DEFAULT '0',
   QtyInStock int(11) NOT NULL DEFAULT '0',
   QtyInStockMin int(11) NOT NULL DEFAULT '0',
   QtyReserved int(11) NOT NULL DEFAULT '0',
   QtyBackOrdered int(11) NOT NULL DEFAULT '0',
   QtyOnOrder int(11) NOT NULL DEFAULT '0',
   InventoryComment text,
   AccessGroupId int(11) DEFAULT NULL,
   AccessDuration int(11) DEFAULT NULL,
   AccessDurationType tinyint(4) DEFAULT NULL,
   AccessStart int(11) DEFAULT NULL,
   AccessEnd int(11) DEFAULT NULL,
   Virtual tinyint(4) NOT NULL DEFAULT '0',
   ProcessingData text,
   PackageContent mediumtext,
   OptionsSelectionMode tinyint(4) DEFAULT '0',
   HasRequiredOptions tinyint(1) NOT NULL DEFAULT '0',
   IsRecurringBilling tinyint(3) unsigned NOT NULL DEFAULT '0',
   ShippingMode tinyint(1) NOT NULL DEFAULT '0',
   ShippingLimitation text,
   AssignedCoupon int(11) NOT NULL DEFAULT '0',
   MinQtyFreePromoShipping int(11) NOT NULL DEFAULT '0',
   MetaKeywords varchar(255) DEFAULT NULL,
   MetaDescription text,
   PRIMARY KEY (ProductId),
   KEY ResourceId (ResourceId),
   KEY Hits (Hits),
   KEY `Name` (`Name`),
   KEY EditorsPick (EditorsPick),
   KEY CreatedOn (CreatedOn),
   KEY Modified (Modified,CreatedOn),
   KEY `Status` (`Status`),
   KEY l1_Name (l1_Name),
   KEY Priority (Priority),
   KEY ManufacturerId (ManufacturerId),
   KEY NewItem (NewItem),
   KEY PopItem (PopItem),
   KEY HotItem (HotItem),
   KEY Featured (Featured),
   KEY OnSale (OnSale),
   KEY Expire (Expire),
   KEY Virtual (Virtual),
   KEY AccessGroupId (AccessGroupId)
 );
 
 CREATE TABLE ProductsCouponItems (
   CouponItemId int(11) NOT NULL auto_increment,
   CouponId int(11) default NULL,
   ItemResourceId int(11) default NULL,
   ItemType TINYINT(4) NOT NULL DEFAULT '1',
   PRIMARY KEY  (CouponItemId),
   KEY DiscountId (CouponId),
   KEY ItemResourceId (ItemResourceId),
   KEY ItemType (ItemType)
 );
 
 CREATE TABLE ProductsCoupons (
   CouponId int(11) NOT NULL auto_increment,
   `Status` tinyint(4) NOT NULL default '1',
   Name varchar(255) default NULL,
   Code varchar(255) default NULL,
   Expiration int(11) default NULL,
   GroupId int(11) default NULL,
   `Type` tinyint(1) NOT NULL default '1',
   Amount double default NULL,
   LastUsedBy int(11) default NULL,
   LastUsedOn int(11) default NULL,
   NumberOfUses int(11) default '1',
   PRIMARY KEY  (CouponId),
   KEY `Status` (`Status`),
   KEY Code (Code)
 );
 
 CREATE TABLE ProductsDiscountItems (
   DiscountItemId int(11) NOT NULL auto_increment,
   DiscountId int(11) default NULL,
   ItemResourceId int(11) default NULL,
   ItemType TINYINT(4) NOT NULL DEFAULT '1',
   PRIMARY KEY  (DiscountItemId),
   KEY DiscountId (DiscountId),
   KEY ItemResourceId (ItemResourceId),
   KEY ItemType (ItemType)
 );
 
 CREATE TABLE ProductsDiscounts (
   DiscountId int(11) NOT NULL auto_increment,
   `Status` tinyint(4) default '2',
   `Name` varchar(255) default NULL,
   `Start` int(11) default NULL,
   `End` int(11) default NULL,
   GroupId int(11) default NULL,
   `Type` tinyint(1) default '1',
   Amount double default NULL,
   PRIMARY KEY  (DiscountId),
   KEY `Status` (`Status`)
 );
 
 CREATE TABLE ProductsPricing (
   PriceId int(11) NOT NULL auto_increment,
   ProductId int(11) NOT NULL default '0',
   MinQty int(11) default NULL,
   MaxQty int(11) default NULL,
   Cost decimal(10,4) default NULL,
   Price decimal(10,4) NOT NULL default '0.0000',
   Negotiated tinyint(1) default NULL,
   Points int(11) default NULL,
   AccessDuration int(11) NOT NULL default '0',
   AccessUnit int(11) NOT NULL default '0',
   Description varchar(255) default NULL,
   IsPrimary tinyint(4) NOT NULL default '0',
   GroupId int(11) NOT NULL default '0',
   PRIMARY KEY  (PriceId),
   KEY ProductId (ProductId),
   KEY GroupId (GroupId),
   KEY IsPrimary (IsPrimary)
 );
 
 CREATE TABLE ProductFiles (
   FileId int(11) NOT NULL AUTO_INCREMENT,
   ProductId int(11) NOT NULL DEFAULT '0',
   `Name` varchar(255) NOT NULL DEFAULT '',
   Version varchar(100) NOT NULL DEFAULT '',
   FilePath varchar(255) NOT NULL DEFAULT '',
   RealPath varchar(255) NOT NULL DEFAULT '',
   Size int(11) NOT NULL DEFAULT '0',
   `Status` tinyint(4) NOT NULL DEFAULT '0',
   IsPrimary tinyint(4) NOT NULL DEFAULT '0',
   Priority smallint(6) NOT NULL DEFAULT '0',
   AddedOn int(11) DEFAULT NULL,
   AddedById int(11) DEFAULT NULL,
   MIMEType varchar(255) NOT NULL DEFAULT '',
   PRIMARY KEY (FileId),
   KEY ProductId (ProductId),
   KEY `Status` (`Status`),
   KEY IsPrimary (IsPrimary),
   KEY Priority (Priority),
   KEY AddedOn (AddedOn)
 );
 
 CREATE TABLE UserFileAccess (
   FileAccessId int(11) NOT NULL AUTO_INCREMENT,
   ProductId int(11) NOT NULL DEFAULT '0',
   PortalUserId int(11) NOT NULL DEFAULT '0',
   PRIMARY KEY (FileAccessId),
   KEY ProductId (ProductId),
   KEY PortalUserId (PortalUserId)
 );
 
 CREATE TABLE UserDownloads (
   DownloadId int(11) NOT NULL AUTO_INCREMENT,
   PortalUserId int(11) NOT NULL DEFAULT '0',
   Username varchar(255) NOT NULL DEFAULT '',
   ProductId int(11) NOT NULL DEFAULT '0',
   ProductName varchar(255) NOT NULL DEFAULT '',
   FileId int(11) NOT NULL DEFAULT '0',
   Filename varchar(255) NOT NULL DEFAULT '',
   IPAddress varchar(100) NOT NULL DEFAULT '',
   StartedOn int(11) DEFAULT NULL,
   EndedOn int(11) DEFAULT NULL,
   PRIMARY KEY (DownloadId),
   KEY PortalUserId (PortalUserId),
   KEY ProductId (ProductId)
 );
 
 CREATE TABLE ShippingBrackets (
   BracketId int(11) NOT NULL auto_increment,
   ShippingTypeID int(11) NOT NULL default '0',
   Start double NOT NULL default '0',
   End double NOT NULL default '0',
   PRIMARY KEY  (BracketId),
   KEY ShippingTypeID (ShippingTypeID),
   KEY Start (Start),
   KEY End (End)
 );
 
 CREATE TABLE ShippingCosts (
   ShippingCostId int(11) NOT NULL auto_increment,
   ZoneID int(11) NOT NULL default '0',
   BracketId int(11) NOT NULL default '0',
   Flat decimal(10,4) default NULL,
   PerUnit decimal(10,4) default NULL,
   PRIMARY KEY  (ShippingCostId),
   KEY ZoneID (ZoneID),
   KEY BracketId (BracketId)
 );
 
 CREATE TABLE ShippingQuoteEngines (
   EngineId int(11) NOT NULL AUTO_INCREMENT,
   `Name` varchar(255) NOT NULL DEFAULT '',
   FlatSurcharge double NOT NULL DEFAULT '0',
   PercentSurcharge double NOT NULL DEFAULT '0',
   `Status` smallint(6) NOT NULL DEFAULT '0',
   Properties text,
   ClassName varchar(255) NOT NULL DEFAULT '',
   PRIMARY KEY (EngineId),
   KEY `Status` (`Status`)
 );
 
 CREATE TABLE ShippingType (
   ShippingID int(11) NOT NULL AUTO_INCREMENT,
   `Code` varchar(25) NOT NULL DEFAULT '',
   `Name` varchar(100) NOT NULL DEFAULT '',
   SpeedCode varchar(25) NOT NULL DEFAULT '',
   LocationFrom int(11) NOT NULL DEFAULT '1',
   `Type` int(11) NOT NULL DEFAULT '1',
   BaseFee double NOT NULL DEFAULT '0',
   CODFlatSurcharge double NOT NULL DEFAULT '0',
   CODPercentSurcharge double NOT NULL DEFAULT '0',
   `Status` tinyint(4) NOT NULL DEFAULT '1',
   CostType tinyint(4) NOT NULL DEFAULT '1',
   ZeroIfEmpty tinyint(4) NOT NULL DEFAULT '1',
   PrecisionBeforeSep tinyint(4) NOT NULL DEFAULT '2',
   PrecisionAfterSep tinyint(4) NOT NULL DEFAULT '2',
   PortalGroups text,
   FreeShippingMinAmount double(10,4) NOT NULL DEFAULT '0.0000',
   IsFreePromoShipping tinyint(1) NOT NULL DEFAULT '0',
   InsuranceFee decimal(10,2) DEFAULT NULL,
   InsuranceType tinyint(1) NOT NULL DEFAULT '2',
   PRIMARY KEY (ShippingID),
   KEY `Type` (`Type`),
   KEY `Status` (`Status`)
 );
 
 CREATE TABLE ShippingZones (
   ZoneID int(11) NOT NULL auto_increment,
   ShippingTypeID int(11) NOT NULL default '0',
   Name varchar(100) NOT NULL default '',
   Type int(11) NOT NULL default '1',
   CODallowed smallint(6) NOT NULL default '1',
   PRIMARY KEY  (ZoneID),
   KEY ShippingTypeID (ShippingTypeID),
   KEY `Type` (`Type`)
 );
 
 CREATE TABLE ShippingZonesDestinations (
   ZoneDestId int(11) NOT NULL auto_increment,
   ShippingZoneId int(11) NOT NULL default '0',
   StdDestId int(11) default '0',
   DestValue varchar(255) default NULL,
   PRIMARY KEY  (ZoneDestId),
   KEY ShippingZoneId (ShippingZoneId),
   KEY StdDestId (StdDestId)
 );
 
 CREATE TABLE TaxZones (
   TaxZoneId int(11) NOT NULL auto_increment,
   Name varchar(100) NOT NULL default '',
   Type int(11) NOT NULL default '1',
   TaxValue double NOT NULL default '0',
   ApplyToShipping TINYINT( 1 ) NOT NULL DEFAULT '0',
   ApplyToProcessing TINYINT( 1 ) NOT NULL DEFAULT '0',
   PRIMARY KEY  (TaxZoneId)
 );
 
 CREATE TABLE TaxZonesDestinations (
   TaxZoneDestId int(11) NOT NULL auto_increment,
   TaxZoneId int(11) NOT NULL default '0',
   StdDestId int(11) default '0',
   DestValue varchar(255) default NULL,
   PRIMARY KEY  (TaxZoneDestId),
   KEY TaxZoneId (TaxZoneId),
   KEY StdDestId (StdDestId)
 );
 
 CREATE TABLE AffiliatePayments (
   AffiliatePaymentId int(11) NOT NULL AUTO_INCREMENT,
   AffiliateId int(10) unsigned NOT NULL DEFAULT '0',
   PaymentDate int(10) unsigned DEFAULT NULL,
   Amount decimal(10,2) NOT NULL DEFAULT '0.00',
   `Comment` text,
   PaymentReference varchar(255) NOT NULL DEFAULT '',
   PaymentTypeId int(11) NOT NULL DEFAULT '0',
   PRIMARY KEY (AffiliatePaymentId),
   KEY AffiliateId (AffiliateId),
   KEY PaymentDate (PaymentDate),
   KEY PaymentTypeId (PaymentTypeId)
 );
 
 CREATE TABLE AffiliatePaymentTypes (
   PaymentTypeId int(11) NOT NULL AUTO_INCREMENT,
   `Name` varchar(255) NOT NULL DEFAULT '',
   Description text,
   IsPrimary tinyint(4) NOT NULL DEFAULT '0',
   `Status` tinyint(4) NOT NULL DEFAULT '0',
   Priority tinyint(4) NOT NULL DEFAULT '0',
   PRIMARY KEY (PaymentTypeId),
   KEY IsPrimary (IsPrimary),
   KEY `Status` (`Status`),
   KEY Priority (Priority)
 );
 
 CREATE TABLE AffiliatePlans (
   AffiliatePlanId int(11) NOT NULL auto_increment,
   Name varchar(255) NOT NULL default '',
   PlanType tinyint(3) unsigned NOT NULL default '1',
   ResetInterval int(10) unsigned NOT NULL default '0',
   PaymentType tinyint(4) NOT NULL default '0',
   MinPaymentAmount varchar(255) NOT NULL default '',
   Enabled tinyint(4) unsigned NOT NULL default '0',
   IsPrimary tinyint(4) NOT NULL default '0',
   PRIMARY KEY  (AffiliatePlanId),
   KEY PaymentType (PaymentType),
   KEY Enabled (Enabled),
   KEY IsPrimary (IsPrimary)
 );
 
 CREATE TABLE AffiliatePlansBrackets (
   AffiliateBracketId int(11) NOT NULL auto_increment,
   AffiliatePlanId int(11) NOT NULL default '0',
   FromAmount decimal(10,4) NOT NULL default '0.0000',
   ToAmount decimal(10,4) NOT NULL default '0.0000',
   Percent decimal(10,2) NOT NULL default '0.00',
   PRIMARY KEY  (AffiliateBracketId),
   KEY AffiliatePlanId (AffiliatePlanId)
 );
 
 CREATE TABLE AffiliatePlansItems (
   AffiliateItemId int(11) NOT NULL auto_increment,
   AffiliatePlanId int(11) NOT NULL default '0',
   ItemResourceId int(10) unsigned NOT NULL default '0',
   ItemType tinyint(4) NOT NULL default '1',
   PRIMARY KEY  (AffiliateItemId),
   KEY AffiliatePlanId (AffiliatePlanId),
   KEY ItemResourceId (ItemResourceId),
   KEY ItemType (ItemType)
 );
 
 CREATE TABLE Affiliates (
   AffiliateId int(11) NOT NULL AUTO_INCREMENT,
-  PortalUserId int(10) unsigned NOT NULL DEFAULT '0',
+  PortalUserId int(10) DEFAULT NULL,
   AffiliatePlanId int(10) unsigned NOT NULL DEFAULT '0',
   AccumulatedAmount decimal(10,2) NOT NULL DEFAULT '0.00',
   AmountToPay decimal(10,2) NOT NULL DEFAULT '0.00',
   LastPaymentDate int(11) unsigned DEFAULT NULL,
   LastOrderDate int(11) unsigned DEFAULT NULL,
   `Status` tinyint(4) NOT NULL DEFAULT '2',
   AffiliateCode varchar(30) NOT NULL DEFAULT '',
   ItemsSold int(10) unsigned NOT NULL DEFAULT '0',
   PaymentTypeId int(11) NOT NULL DEFAULT '0',
   SSN varchar(100) NOT NULL DEFAULT '',
   Comments text,
   CreatedOn int(11) DEFAULT NULL,
   PRIMARY KEY (AffiliateId),
-  UNIQUE KEY PortalUserId (PortalUserId),
   UNIQUE KEY AffiliateCode (AffiliateCode),
+  UNIQUE KEY PortalUserId (PortalUserId),
   KEY LastOrderDate (LastOrderDate),
   KEY AffiliatePlanId (AffiliatePlanId),
   KEY `Status` (`Status`),
   KEY PaymentTypeId (PaymentTypeId),
   KEY CreatedOn (CreatedOn)
 );
 
 CREATE TABLE ProductOptionCombinations (
   CombinationId int(11) NOT NULL AUTO_INCREMENT,
   ProductId int(11) NOT NULL DEFAULT '0',
   Combination text,
   CombinationCRC bigint(11) NOT NULL DEFAULT '0',
   PriceType tinyint(1) DEFAULT '3',
   Price float DEFAULT NULL,
   WeightType tinyint(1) DEFAULT '3',
   Weight float DEFAULT NULL,
   Availability tinyint(1) NOT NULL DEFAULT '1',
   Priority int(11) NOT NULL DEFAULT '0',
   QtyInStock int(11) NOT NULL DEFAULT '0',
   QtyReserved int(11) NOT NULL DEFAULT '0',
   QtyBackOrdered int(11) NOT NULL DEFAULT '0',
   QtyOnOrder int(11) NOT NULL DEFAULT '0',
   SKU varchar(255) NOT NULL DEFAULT '',
   PRIMARY KEY (CombinationId),
   KEY CombinationCRC (CombinationCRC),
   KEY ProductId (ProductId),
   KEY Availability (Availability)
 );
 
 CREATE TABLE ProductOptions (
   ProductOptionId int(11) NOT NULL auto_increment,
   ProductId int(11) NOT NULL default '0',
   Name varchar(255) NOT NULL default '',
   OptionType TINYINT(4) NOT NULL DEFAULT '0',
   Required tinyint(4) NOT NULL default '0',
   Listable tinyint(4) NOT NULL default '0',
   Priority int(11) NOT NULL default '0',
   `Values` text,
   Prices text,
   PriceTypes text,
   PRIMARY KEY  (ProductOptionId),
   KEY ProductId (ProductId,Priority),
   KEY OptionType (OptionType),
   KEY Listable (Listable)
 );
 
 CREATE TABLE ProductsCustomData (
   CustomDataId int(11) NOT NULL auto_increment,
   ResourceId int(10) unsigned NOT NULL default '0',
   KEY ResourceId (ResourceId),
   PRIMARY KEY  (CustomDataId)
 );
 
 ALTER TABLE SiteDomains
 	ADD COLUMN BillingCountry varchar(3) NOT NULL DEFAULT '',
 	ADD COLUMN ShippingCountry varchar(3) NOT NULL DEFAULT '',
 	ADD COLUMN PrimaryCurrencyId int(11) NOT NULL DEFAULT '0',
 	ADD COLUMN Currencies varchar(255) NOT NULL DEFAULT '',
 	ADD COLUMN PrimaryPaymentTypeId int(11) NOT NULL DEFAULT '0',
 	ADD COLUMN PaymentTypes varchar(255) NOT NULL DEFAULT '',
 	ADD INDEX (BillingCountry),
 	ADD INDEX (ShippingCountry),
 	ADD INDEX (PrimaryCurrencyId),
 	ADD INDEX (Currencies),
 	ADD INDEX (PrimaryPaymentTypeId),
 	ADD INDEX (PaymentTypes);
\ No newline at end of file
Index: branches/5.3.x/install/upgrades.sql
===================================================================
--- branches/5.3.x/install/upgrades.sql	(revision 15670)
+++ branches/5.3.x/install/upgrades.sql	(revision 15671)
@@ -1,284 +1,288 @@
 # ===== v 4.3.9 =====
 
 INSERT INTO ImportScripts VALUES (DEFAULT, 'Products from CSV file [In-Commerce]', '', 'p', 'In-Commerce', '', 'CSV', '1');
 
 ALTER TABLE Products ADD OnSale TINYINT(1) NOT NULL default '0' AFTER Featured, ADD INDEX (OnSale);
 
 UPDATE Phrase SET Module = 'In-Commerce' WHERE Phrase IN ('lu_comm_Images', 'lu_comm_ImagesHeader');
 
 # ===== v 5.0.0 =====
 UPDATE Category SET Template = '/in-commerce/designs/section' WHERE Template = 'in-commerce/store/category';
 UPDATE Category SET CachedTemplate = '/in-commerce/designs/section' WHERE CachedTemplate = 'in-commerce/store/category';
 
 UPDATE ConfigurationValues SET VariableValue = '/in-commerce/designs/section' WHERE VariableName = 'p_CategoryTemplate';
 UPDATE ConfigurationValues SET VariableValue = 'in-commerce/designs/detail' WHERE VariableName = 'p_ItemTemplate';
 
 DELETE FROM PersistantSessionData WHERE VariableName IN ('affil_columns_.', 'ap_columns_.', 'apayments_columns_.', 'apayments.log_columns_.', 'd_columns_.', 'coup_columns_.', 'file_columns_.', 'po_columns_.', 'z_columns_.', 'tax_columns_.');
 DELETE FROM PersistantSessionData WHERE VariableName LIKE '%ord.%';
 
 INSERT INTO Permissions VALUES (DEFAULT, 'in-commerce:products.view', 11, 1, 1, 0);
 INSERT INTO Permissions VALUES (DEFAULT, 'in-commerce:setting_folder.view', 11, 1, 1, 0);
 
 INSERT INTO ShippingQuoteEngines VALUES (DEFAULT, 'USPS.com', 0, 0, 0, 'a:21:{s:12:"AccountLogin";s:0:"";s:15:"AccountPassword";N;s:10:"UPSEnabled";N;s:10:"UPSAccount";s:0:"";s:11:"UPSInvoiced";N;s:10:"FDXEnabled";N;s:10:"FDXAccount";s:0:"";s:10:"DHLEnabled";N;s:10:"DHLAccount";s:0:"";s:11:"DHLInvoiced";N;s:10:"USPEnabled";N;s:10:"USPAccount";s:0:"";s:11:"USPInvoiced";N;s:10:"ARBEnabled";N;s:10:"ARBAccount";s:0:"";s:11:"ARBInvoiced";N;s:10:"1DYEnabled";N;s:10:"2DYEnabled";N;s:10:"3DYEnabled";N;s:10:"GNDEnabled";N;s:10:"ShipMethod";N;}', 'USPS');
 
 INSERT INTO ConfigurationAdmin VALUES ('Comm_CompanyName', 'la_Text_ContactsGeneral', 'la_text_CompanyName', 'text', NULL, NULL, 10.01, 0, 0);
 INSERT INTO ConfigurationValues VALUES (DEFAULT, 'Comm_CompanyName', '', 'In-Commerce', 'in-commerce:contacts');
 
 UPDATE ConfigurationAdmin SET prompt = 'la_text_StoreName', DisplayOrder = 10.02 WHERE VariableName = 'Comm_StoreName';
 
 INSERT INTO ConfigurationAdmin VALUES ('Comm_Contacts_Name', 'la_Text_ContactsGeneral', 'la_text_ContactName', 'text', NULL, NULL, 10.03, 0, 0);
 INSERT INTO ConfigurationValues VALUES (DEFAULT, 'Comm_Contacts_Name', '', 'In-Commerce', 'in-commerce:contacts');
 
 UPDATE ConfigurationAdmin SET DisplayOrder = 10.04 WHERE VariableName = 'Comm_Contacts_Phone';
 UPDATE ConfigurationAdmin SET DisplayOrder = 10.05 WHERE VariableName = 'Comm_Contacts_Fax';
 UPDATE ConfigurationAdmin SET DisplayOrder = 10.06 WHERE VariableName = 'Comm_Contacts_Email';
 UPDATE ConfigurationAdmin SET DisplayOrder = 10.07 WHERE VariableName = 'Comm_Contacts_Additional';
 
 DELETE FROM Phrase WHERE Phrase IN ('la_fld_ManufacturerId', 'la_fld_DiscountId', 'la_fld_CouponId', 'la_fld_AffiliatePlanId', 'la_fld_AffiliateId', 'la_fld_ZoneId', 'la_fld_EngineId', 'la_fld_ShippingId', 'la_fld_ProductId', 'la_fld_OptionId', 'la_fld_CurrencyId', 'la_fld_Zone_Name');
 
 UPDATE Phrase SET Module = 'In-Commerce' WHERE ((Phrase LIKE '%Product%' OR Phrase LIKE '%Shipping%' OR Phrase LIKE '%Coupon%' OR Phrase LIKE '%Discount%' OR Phrase LIKE '%Report%' OR Phrase LIKE '%Currency%' OR Phrase LIKE '%Cart%') AND (Module = 'Core'));
 
 # ===== v 5.0.1 =====
 UPDATE ConfigurationValues SET VariableValue = 'in-commerce/products/product_detail' WHERE VariableName = 'p_ItemTemplate';
 
 UPDATE ConfigurationAdmin SET ValueList = '1=la_opt_Session,2=la_opt_PermanentCookie' WHERE VariableName = 'Comm_AffiliateStorageMethod';
 
 UPDATE ConfigurationAdmin SET ValueList = 'ASC=la_common_Ascending,DESC=la_common_Descending'
 WHERE VariableName IN ('product_OrderProductsByDir', 'product_OrderProductsThenByDir');
 
 UPDATE ConfigurationAdmin SET ValueList = '1=la_opt_PriceCalculationByPrimary,2=la_opt_PriceCalculationByOptimal'
 WHERE VariableName = 'Comm_PriceBracketCalculation';
 
 UPDATE ConfigurationAdmin
 SET ValueList = '1=la_opt_Sec,60=la_opt_Min,3600=la_opt_Hour,86400=la_opt_Day,604800=la_opt_Week,2419200=la_opt_Month,29030400=la_opt_Year'
 WHERE VariableName IN ('product_ReviewDelay_Interval', 'product_RatingDelay_Interval');
 
 UPDATE CustomField SET FieldLabel = 'la_fld_cust_p_ItemTemplate', Prompt = 'la_fld_cust_p_ItemTemplate' WHERE FieldName = 'p_ItemTemplate';
 
 UPDATE Events SET Type = 1 WHERE Event = 'BACKORDER.FULLFILL';
 
 UPDATE ConfigurationAdmin SET ValueList = 'style="width: 50px;"' WHERE VariableName IN ('product_RatingDelay_Value', 'product_ReviewDelay_Value');
 
 # ===== v 5.0.2-B1 =====
 ALTER TABLE AffiliatePayments
 	CHANGE Comment Comment text NULL,
 	CHANGE PaymentDate PaymentDate INT(10) UNSIGNED NULL DEFAULT NULL;
 
 ALTER TABLE AffiliatePaymentTypes CHANGE Description Description text NULL;
 
 ALTER TABLE Affiliates
 	CHANGE Comments Comments text NULL,
 	CHANGE CreatedOn CreatedOn INT(11) NULL DEFAULT NULL;
 
 ALTER TABLE Manufacturers CHANGE Description Description text NULL;
 
 ALTER TABLE Orders
 	CHANGE UserComment UserComment text NULL,
 	CHANGE AdminComment AdminComment text NULL,
 	CHANGE GWResult1 GWResult1 MEDIUMTEXT NULL,
 	CHANGE GWResult2 GWResult2 MEDIUMTEXT NULL,
 	CHANGE OrderDate OrderDate INT(10) UNSIGNED NULL DEFAULT NULL,
 	CHANGE PaymentExpires PaymentExpires INT(10) UNSIGNED NULL DEFAULT NULL;
 
 ALTER TABLE PaymentTypes CHANGE PortalGroups PortalGroups text NULL;
 ALTER TABLE ProductOptionCombinations CHANGE Combination Combination text NULL;
 
 ALTER TABLE Products
 	CHANGE ShippingLimitation ShippingLimitation text NULL,
 	CHANGE PackageContent PackageContent MEDIUMTEXT NULL;
 
 ALTER TABLE ShippingQuoteEngines CHANGE Properties Properties text NULL;
 ALTER TABLE ShippingType CHANGE PortalGroups PortalGroups text NULL;
 
 ALTER TABLE ProductFiles
 	CHANGE ProductId ProductId INT(11) NOT NULL DEFAULT '0',
 	CHANGE `Name` `Name` VARCHAR(255) NOT NULL DEFAULT '',
 	CHANGE Version Version VARCHAR(100) NOT NULL DEFAULT '',
 	CHANGE FilePath FilePath VARCHAR(255) NOT NULL DEFAULT '',
 	CHANGE RealPath RealPath VARCHAR(255) NOT NULL DEFAULT '',
 	CHANGE Size Size INT(11) NOT NULL DEFAULT '0',
 	CHANGE AddedOn AddedOn INT(11) NULL DEFAULT NULL;
 
 ALTER TABLE UserFileAccess
 	CHANGE ProductId ProductId INT( 11 ) NOT NULL DEFAULT '0',
 	CHANGE PortalUserId PortalUserId INT( 11 ) NOT NULL DEFAULT '0';
 
 ALTER TABLE GatewayConfigFields CHANGE ValueList ValueList MEDIUMTEXT NULL;
 
 ALTER TABLE Currencies
 	CHANGE `Status` `Status` SMALLINT(6) NOT NULL DEFAULT '1',
 	CHANGE Modified Modified INT(11) NULL DEFAULT NULL;
 
 ALTER TABLE GiftCertificates CHANGE `Status` `Status` TINYINT(1) NOT NULL DEFAULT '2';
 
 ALTER TABLE UserDownloads
 	CHANGE StartedOn StartedOn INT(11) NULL DEFAULT NULL,
 	CHANGE EndedOn EndedOn INT(11) NULL DEFAULT NULL;
 
 # ===== v 5.0.2-B2 =====
 
 # ===== v 5.0.2-RC1 =====
 
 # ===== v 5.0.2 =====
 
 # ===== v 5.0.3-B1 =====
 UPDATE Phrase
 SET PhraseType = 1
 WHERE Phrase IN (
 	'la_ship_All_Together', 'la_ship_Backorders_Upon_Avail', 'la_ship_Backorder_Separately',
 	'lu_ship_Shipment', 'lu_ship_ShippingType'
 );
 
 # ===== v 5.0.3-B2 =====
 
 # ===== v 5.0.3-RC1 =====
 
 # ===== v 5.0.3 =====
 
 # ===== v 5.0.4-B1 =====
 
 # ===== v 5.0.4-B2 =====
 
 # ===== v 5.0.4 =====
 
 # ===== v 5.1.0-B1 =====
 UPDATE Modules SET Path = 'modules/in-commerce/' WHERE `Name` = 'In-Commerce';
 
 UPDATE ConfigurationValues
 SET ValueList = '0=lu_none||<SQL+>SELECT l%3$s_Name AS OptionName, IsoCode AS OptionValue FROM <PREFIX>CountryStates WHERE Type = 1 ORDER BY OptionName</SQL>'
 WHERE ValueList = '0=lu_none||<SQL>SELECT DestName AS OptionName, DestAbbr AS OptionValue FROM <PREFIX>StdDestinations WHERE DestParentId IS NULL Order BY OptionName</SQL>';
 
 ALTER TABLE SiteDomains
 	ADD COLUMN BillingCountry varchar(3) NOT NULL DEFAULT '',
 	ADD COLUMN ShippingCountry varchar(3) NOT NULL DEFAULT '',
 	ADD COLUMN PrimaryCurrencyId int(11) NOT NULL DEFAULT '0',
 	ADD COLUMN Currencies varchar(255) NOT NULL DEFAULT '',
 	ADD COLUMN PrimaryPaymentTypeId int(11) NOT NULL DEFAULT '0',
 	ADD COLUMN PaymentTypes varchar(255) NOT NULL DEFAULT '',
 	ADD INDEX (BillingCountry),
 	ADD INDEX (ShippingCountry),
 	ADD INDEX (PrimaryCurrencyId),
 	ADD INDEX (Currencies),
 	ADD INDEX (PrimaryPaymentTypeId),
 	ADD INDEX (PaymentTypes);
 
 UPDATE Phrase SET Module = 'Core' WHERE Phrase IN ('la_btn_Add', 'la_fld_RecipientName', 'la_fld_SenderName');
 DELETE FROM Permissions WHERE Permission LIKE 'in-commerce:incommerce_configemail%';
 
 # ===== v 5.1.0-B2 =====
 
 # ===== v 5.1.0-RC1 =====
 UPDATE Phrase
 SET PhraseType = 1
 WHERE Phrase IN (
 	'la_col_Qty', 'la_col_QtyBackordered', 'la_ItemBackordered', 'la_ship_all_together',
 	'la_ship_backorders_upon_avail', 'la_ship_backorder_separately', 'la_tooltip_New_Coupon',
 	'la_tooltip_New_Discount'
 );
 
 DELETE FROM Phrase WHERE Phrase = 'la_comm_ProductsByManuf';
 
 # ===== v 5.1.0 =====
 ALTER TABLE Products CHANGE CachedRating CachedRating varchar(10) NOT NULL default '0';
 
 # ===== v 5.1.1-B1 =====
 ALTER TABLE Orders CHANGE ShippingOption ShippingOption TINYINT(4) NOT NULL DEFAULT '0';
 
 ALTER TABLE ProductFiles CHANGE AddedById AddedById INT(11) NULL DEFAULT NULL;
 UPDATE ProductFiles SET AddedById = NULL WHERE AddedById = 0;
 
 ALTER TABLE Products
 	CHANGE CreatedById CreatedById INT(11) NULL DEFAULT NULL ,
 	CHANGE ModifiedById ModifiedById INT(11) NULL DEFAULT NULL;
 UPDATE Products SET CreatedById = NULL WHERE CreatedById = 0;
 UPDATE Products SET ModifiedById = NULL WHERE ModifiedById = 0;
 
 # ===== v 5.1.1-B2 =====
 
 # ===== v 5.1.1-RC1 =====
 
 # ===== v 5.1.1 =====
 
 # ===== v 5.1.2-B1 =====
 DELETE FROM Phrase WHERE PhraseKey = 'LA_TITLE_ADDING_ORDER_ITEM';
 
 # ===== v 5.1.2-B2 =====
 UPDATE Phrase SET l<%PRIMARY_LANGUAGE%>_Translation = REPLACE(l<%PRIMARY_LANGUAGE%>_Translation, 'Discounts & Coupons', 'Discounts & Certificates') WHERE PhraseKey = 'LA_TAB_DISCOUNTSANDCOUPONS';
 
 # ===== v 5.1.2-RC1 =====
 UPDATE Phrase SET Module = 'Core' WHERE PhraseKey = 'LA_FLD_ISOCODE' OR PhraseKey = 'LA_COL_ISOCODE';
 
 # ===== v 5.1.2 =====
 
 # ===== v 5.1.3-B1 =====
 ALTER TABLE AffiliatePlansBrackets CHANGE Percent Percent DECIMAL (10,2) NOT NULL DEFAULT '0.00';
 
 # ===== v 5.1.3-B2 =====
 
 # ===== v 5.1.3-RC1 =====
 UPDATE ConfigurationValues
 SET VariableValue = 'in-commerce/products/product_detail'
 WHERE VariableName = 'p_ItemTemplate' AND VariableValue = 'in-commerce/designs/detail';
 
 # ===== v 5.1.3-RC2 =====
 
 # ===== v 5.1.3 =====
 
 # ===== v 5.2.0-B1 =====
 UPDATE SearchConfig
 SET DisplayName = REPLACE(DisplayName, 'lu_', 'lc_')
 WHERE DisplayName IN ('lu_field_descriptionex', 'lu_field_manufacturer', 'lu_field_qtysold', 'lu_field_topseller');
 
 INSERT INTO SystemSettings VALUES(DEFAULT, 'OrderVATIncluded', '0', 'In-Commerce', 'in-commerce:general', 'la_Text_Orders', 'la_config_OrderVATIncluded', 'checkbox', NULL, NULL, 10.12, '0', '0', NULL);
 
 ALTER TABLE Orders ADD VATIncluded TINYINT(1) UNSIGNED NOT NULL DEFAULT '0';
 
 INSERT INTO ItemFilters VALUES
 	(DEFAULT, 'p', 'ManufacturerId', 'checkbox', 1, NULL),
 	(DEFAULT, 'p', 'Price', 'range', 1, 11),
 	(DEFAULT, 'p', 'EditorsPick', 'radio', 1, NULL);
 
 DELETE FROM LanguageLabels WHERE PhraseKey = 'LA_COL_ITEMNAME';
 
 DELETE FROM LanguageLabels
 WHERE PhraseKey IN ('LA_ALLOWORDERINGINNONPRIMARYCURRENCY', 'LA_ALLOWORDERDIFFERENTTYPES');
 
 DELETE FROM SystemSettings
 WHERE VariableName IN ('Comm_AllowOrderingInNonPrimaryCurrency', 'Comm_Allow_Order_Different_Types');
 
 UPDATE SystemSettings
 SET DisplayOrder = 20.01
 WHERE VariableName = 'Comm_ExchangeRateSource';
 
 UPDATE SystemSettings
 SET DisplayOrder = DisplayOrder - 0.01
 WHERE VariableName IN (
 	'Comm_Enable_Backordering', 'Comm_Process_Backorders_Auto', 'Comm_Next_Order_Number', 'Comm_Order_Number_Format_P',
 	'Comm_Order_Number_Format_S', 'Comm_RecurringChargeInverval', 'Comm_AutoProcessRecurringOrders', 'MaxAddresses',
 	'Comm_MaskProcessedCreditCards', 'OrderVATIncluded'
 );
 
 INSERT INTO SystemSettings VALUES(DEFAULT, 'MaxCompareProducts', '3', 'In-Commerce', 'in-commerce:output', 'la_Text_Products', 'la_config_MaxCompareProducts', 'text', NULL, NULL, 10.12, 0, 1, NULL);
 
 # ===== v 5.2.0-B2 =====
 UPDATE Products main_table
 SET main_table.CachedReviewsQty = (SELECT COUNT(*) FROM <%TABLE_PREFIX%>CatalogReviews review_table WHERE review_table.ItemId = main_table.ResourceId);
 
 # ===== v 5.2.0-B3 =====
 ALTER TABLE OrderItems CHANGE OptionsSalt OptionsSalt BIGINT(11) NULL DEFAULT '0';
 UPDATE OrderItems
 SET OptionsSalt = CAST((OptionsSalt & 0xFFFFFFFF) AS UNSIGNED INTEGER)
 WHERE OptionsSalt < 0;
 
 ALTER TABLE ProductOptionCombinations CHANGE CombinationCRC CombinationCRC BIGINT(11) NOT NULL DEFAULT '0';
 UPDATE ProductOptionCombinations
 SET CombinationCRC = CAST((CombinationCRC & 0xFFFFFFFF) AS UNSIGNED INTEGER)
 WHERE CombinationCRC < 0;
 
 # ===== v 5.2.0-RC1 =====
 DELETE FROM Currencies WHERE ISO = 'NZD' LIMIT 1;
 
 # ===== v 5.2.0 =====
 INSERT INTO Permissions VALUES(DEFAULT, 'in-commerce:general.add', 11, 1, 1, 0);
 INSERT INTO Permissions VALUES(DEFAULT, 'in-commerce:output.add', 11, 1, 1, 0);
 INSERT INTO Permissions VALUES(DEFAULT, 'in-commerce:contacts.add', 11, 1, 1, 0);
+
+# ===== v 5.2.1-B1 =====
+ALTER TABLE Affiliates CHANGE PortalUserId PortalUserId INT(10) NULL DEFAULT NULL;
+UPDATE Affiliates SET PortalUserId = NULL WHERE PortalUserId = 0;
Index: branches/5.3.x/install/install_data.sql
===================================================================
--- branches/5.3.x/install/install_data.sql	(revision 15670)
+++ branches/5.3.x/install/install_data.sql	(revision 15671)
@@ -1,480 +1,480 @@
 # Section "in-commerce:contacts":
 INSERT INTO SystemSettings VALUES(DEFAULT, 'Comm_CompanyName', '', 'In-Commerce', 'in-commerce:contacts', 'la_Text_ContactsGeneral', 'la_text_CompanyName', 'text', NULL, NULL, 10.01, 0, 0, NULL);
 INSERT INTO SystemSettings VALUES(DEFAULT, 'Comm_StoreName', '', 'In-Commerce', 'in-commerce:contacts', 'la_Text_ContactsGeneral', 'la_text_StoreName', 'text', NULL, NULL, 10.02, 0, 0, NULL);
 INSERT INTO SystemSettings VALUES(DEFAULT, 'Comm_Contacts_Name', '', 'In-Commerce', 'in-commerce:contacts', 'la_Text_ContactsGeneral', 'la_text_ContactName', 'text', NULL, NULL, 10.03, 0, 0, NULL);
 INSERT INTO SystemSettings VALUES(DEFAULT, 'Comm_Contacts_Phone', '', 'In-Commerce', 'in-commerce:contacts', 'la_Text_ContactsGeneral', 'la_text_Phone', 'text', NULL, NULL, 10.04, 0, 1, NULL);
 INSERT INTO SystemSettings VALUES(DEFAULT, 'Comm_Contacts_Fax', '', 'In-Commerce', 'in-commerce:contacts', 'la_Text_ContactsGeneral', 'la_text_Fax', 'text', NULL, NULL, 10.05, 0, 1, NULL);
 INSERT INTO SystemSettings VALUES(DEFAULT, 'Comm_Contacts_Email', '', 'In-Commerce', 'in-commerce:contacts', 'la_Text_ContactsGeneral', 'la_text_Email', 'text', NULL, NULL, 10.06, 0, 1, NULL);
 INSERT INTO SystemSettings VALUES(DEFAULT, 'Comm_Contacts_Additional', '', 'In-Commerce', 'in-commerce:contacts', 'la_Text_ContactsGeneral', 'la_text_Additional', 'textarea', NULL, NULL, 10.07, 0, 1, NULL);
 INSERT INTO SystemSettings VALUES(DEFAULT, 'Comm_AddressLine1', '', 'In-Commerce', 'in-commerce:contacts', 'la_Text_StoreAddress', 'la_AddressLine1', 'text', NULL, NULL, 20.01, 0, 1, NULL);
 INSERT INTO SystemSettings VALUES(DEFAULT, 'Comm_AddressLine2', '', 'In-Commerce', 'in-commerce:contacts', 'la_Text_StoreAddress', 'la_AddressLine2', 'text', NULL, NULL, 20.02, 0, 1, NULL);
 INSERT INTO SystemSettings VALUES(DEFAULT, 'Comm_City', '', 'In-Commerce', 'in-commerce:contacts', 'la_Text_StoreAddress', 'la_City', 'text', NULL, NULL, 20.03, 0, 1, NULL);
 INSERT INTO SystemSettings VALUES(DEFAULT, 'Comm_ZIP', '', 'In-Commerce', 'in-commerce:contacts', 'la_Text_StoreAddress', 'la_ZIP', 'text', NULL, NULL, 20.04, 0, 1, NULL);
 INSERT INTO SystemSettings VALUES(DEFAULT, 'Comm_Country', '', 'In-Commerce', 'in-commerce:contacts', 'la_Text_StoreAddress', 'la_Country', 'select', NULL, '0=lu_none||<SQL+>SELECT l%3$s_Name AS OptionName, IsoCode AS OptionValue FROM <PREFIX>CountryStates WHERE Type = 1 ORDER BY OptionName</SQL>', 20.05, 0, 1, NULL);
 INSERT INTO SystemSettings VALUES(DEFAULT, 'Comm_State', '', 'In-Commerce', 'in-commerce:contacts', 'la_Text_StoreAddress', 'la_State', 'text', NULL, '', 20.06, 0, 1, NULL);
 INSERT INTO SystemSettings VALUES(DEFAULT, 'Comm_Shipping_AddressLine1', '', 'In-Commerce', 'in-commerce:contacts', 'la_Text_ShippingAddress', 'la_AddressLine1', 'text', NULL, NULL, 30.01, 0, 1, NULL);
 INSERT INTO SystemSettings VALUES(DEFAULT, 'Comm_Shipping_AddressLine2', '', 'In-Commerce', 'in-commerce:contacts', 'la_Text_ShippingAddress', 'la_AddressLine2', 'text', NULL, NULL, 30.02, 0, 1, NULL);
 INSERT INTO SystemSettings VALUES(DEFAULT, 'Comm_Shipping_City', '', 'In-Commerce', 'in-commerce:contacts', 'la_Text_ShippingAddress', 'la_City', 'text', NULL, NULL, 30.03, 0, 1, NULL);
 INSERT INTO SystemSettings VALUES(DEFAULT, 'Comm_Shipping_ZIP', '', 'In-Commerce', 'in-commerce:contacts', 'la_Text_ShippingAddress', 'la_ZIP', 'text', NULL, NULL, 30.04, 0, 1, NULL);
 INSERT INTO SystemSettings VALUES(DEFAULT, 'Comm_Shipping_Country', '', 'In-Commerce', 'in-commerce:contacts', 'la_Text_ShippingAddress', 'la_Country', 'select', NULL, '0=lu_none||<SQL+>SELECT l%3$s_Name AS OptionName, IsoCode AS OptionValue FROM <PREFIX>CountryStates WHERE Type = 1 ORDER BY OptionName</SQL>', 30.05, 0, 1, NULL);
 INSERT INTO SystemSettings VALUES(DEFAULT, 'Comm_Shipping_State', '', 'In-Commerce', 'in-commerce:contacts', 'la_Text_ShippingAddress', 'la_State', 'text', NULL, NULL, 30.06, 0, 1, NULL);
 
 # Section "in-commerce:general":
 INSERT INTO SystemSettings VALUES(DEFAULT, 'Comm_RequireLoginBeforeCheckout', '0', 'In-Commerce', 'in-commerce:general', 'la_Text_Orders', 'la_orders_RequireLogin', 'checkbox', NULL, NULL, 10.01, 0, 1, NULL);
 INSERT INTO SystemSettings VALUES(DEFAULT, 'Comm_Enable_Backordering', '1', 'In-Commerce', 'in-commerce:general', 'la_Text_Orders', 'la_EnableBackordering', 'checkbox', NULL, NULL, 10.02, 0, 1, NULL);
 INSERT INTO SystemSettings VALUES(DEFAULT, 'Comm_Process_Backorders_Auto', '1', 'In-Commerce', 'in-commerce:general', 'la_Text_Orders', 'la_ProcessBackorderingAuto', 'checkbox', NULL, NULL, 10.03, 0, 1, NULL);
 INSERT INTO SystemSettings VALUES(DEFAULT, 'Comm_Next_Order_Number', '1', 'In-Commerce', 'in-commerce:general', 'la_Text_Orders', 'la_orders_NextOrderNumber', 'text', NULL, NULL, 10.04, 0, 1, NULL);
 INSERT INTO SystemSettings VALUES(DEFAULT, 'Comm_Order_Number_Format_P', '6', 'In-Commerce', 'in-commerce:general', 'la_Text_Orders', 'la_OrderMainNumberDigits', 'text', NULL, NULL, 10.05, 0, 1, NULL);
 INSERT INTO SystemSettings VALUES(DEFAULT, 'Comm_Order_Number_Format_S', '3', 'In-Commerce', 'in-commerce:general', 'la_Text_Orders', 'la_OrderSecNumberDigits', 'text', NULL, NULL, 10.06, 0, 1, NULL);
 INSERT INTO SystemSettings VALUES(DEFAULT, 'Comm_RecurringChargeInverval', '1', 'In-Commerce', 'in-commerce:general', 'la_Text_Orders', 'la_RecurringChargeInverval', 'text', NULL, NULL, 10.07, 0, 0, NULL);
 INSERT INTO SystemSettings VALUES(DEFAULT, 'Comm_AutoProcessRecurringOrders', '1', 'In-Commerce', 'in-commerce:general', 'la_Text_Orders', 'la_AutoProcessRecurringOrders', 'checkbox', NULL, NULL, 10.08, 0, 0, NULL);
 INSERT INTO SystemSettings VALUES(DEFAULT, 'MaxAddresses', '0', 'In-Commerce', 'in-commerce:general', 'la_Text_Orders', 'la_MaxAddresses', 'text', NULL, NULL, 10.09, 0, 0, NULL);
 INSERT INTO SystemSettings VALUES(DEFAULT, 'Comm_MaskProcessedCreditCards', '0', 'In-Commerce', 'in-commerce:general', 'la_Text_Orders', 'la_MaskProcessedCreditCards', 'checkbox', NULL, NULL, 10.1, 0, 0, NULL);
 INSERT INTO SystemSettings VALUES(DEFAULT, 'OrderVATIncluded', '0', 'In-Commerce', 'in-commerce:general', 'la_Text_Orders', 'la_config_OrderVATIncluded', 'checkbox', NULL, NULL, 10.11, '0', '0', NULL);
 INSERT INTO SystemSettings VALUES(DEFAULT, 'Comm_ExchangeRateSource', '3', 'In-Commerce', 'in-commerce:general', 'la_Text_Currencies', 'la_ExchangeRateSource', 'select', NULL, '2=la_FederalReserveBank||3=la_EuropeanCentralBank||1=la_BankOfLatvia', 20.01, 0, 1, NULL);
 INSERT INTO SystemSettings VALUES(DEFAULT, 'Comm_DefaultCouponDuration', '14', 'In-Commerce', 'in-commerce:general', 'la_Text_Coupons', 'la_conf_DefaultCouponDuration', 'text', NULL, NULL, 30.01, 0, 1, NULL);
 INSERT INTO SystemSettings VALUES(DEFAULT, 'Comm_RegisterAsAffiliate', '0', 'In-Commerce', 'in-commerce:general', 'la_Text_Affiliates', 'la_prompt_register_as_affiliate', 'checkbox', NULL, '', 40.01, 0, 1, NULL);
 INSERT INTO SystemSettings VALUES(DEFAULT, 'Comm_AffiliateStorageMethod', '1', 'In-Commerce', 'in-commerce:general', 'la_Text_Affiliates', 'la_prompt_affiliate_storage_method', 'radio', NULL, '1=la_opt_Session||2=la_opt_PermanentCookie', 40.02, 0, 1, NULL);
 INSERT INTO SystemSettings VALUES(DEFAULT, 'Comm_AffiliateCookieDuration', '30', 'In-Commerce', 'in-commerce:general', 'la_Text_Affiliates', 'la_prompt_affiliate_cookie_duration', 'text', NULL, '', 40.03, 0, 1, NULL);
 INSERT INTO SystemSettings VALUES(DEFAULT, 'Comm_PriceBracketCalculation', '1', 'In-Commerce', 'in-commerce:general', 'la_Text_PricingCalculation', 'la_prompt_PriceBracketCalculation', 'radio', NULL, '1=la_opt_PriceCalculationByPrimary||2=la_opt_PriceCalculationByOptimal', 50, 0, 1, NULL);
 
 # Section "in-commerce:output":
 INSERT INTO SystemSettings VALUES(DEFAULT, 'product_OrderProductsBy', 'Name', 'In-Commerce', 'in-commerce:output', 'la_Text_Products', 'la_conf_OrderProductsBy', 'select', NULL, '=la_none||Name=la_fld_Title||SKU=la_fld_SKU||Manufacturer=la_fld_Manufacturer||Price=la_fld_Price||CreatedOn=la_fld_CreatedOn||Modified=la_fld_Modified||Qty=la_fld_Qty||<SQL>SELECT Prompt AS OptionName, CONCAT("cust_", FieldName) AS OptionValue FROM <PREFIX>CustomFields WHERE (Type = 11) AND (IsSystem = 0)</SQL>', 10.01, 1, 1, NULL);
 INSERT INTO SystemSettings VALUES(DEFAULT, 'product_OrderProductsByDir', 'ASC', 'In-Commerce', 'in-commerce:output', 'la_Text_Products', 'la_conf_OrderProductsBy', 'select', NULL, 'ASC=la_common_Ascending||DESC=la_common_Descending', 10.01, 2, 1, NULL);
 INSERT INTO SystemSettings VALUES(DEFAULT, 'product_OrderProductsThenBy', 'Price', 'In-Commerce', 'in-commerce:output', 'la_Text_Products', 'la_conf_ThenBy', 'select', NULL, '=la_none||Name=la_fld_Title||SKU=la_fld_SKU||Manufacturer=la_fld_Manufacturer||Price=la_fld_Price||CreatedOn=la_fld_CreatedOn||Modified=la_fld_Modified||Qty=la_fld_Qty||<SQL>SELECT Prompt AS OptionName, CONCAT("cust_", FieldName) AS OptionValue FROM <PREFIX>CustomFields WHERE (Type = 11) AND (IsSystem = 0)</SQL>', 10.02, 1, 1, NULL);
 INSERT INTO SystemSettings VALUES(DEFAULT, 'product_OrderProductsThenByDir', 'ASC', 'In-Commerce', 'in-commerce:output', 'la_Text_Products', 'la_conf_ThenBy', 'select', NULL, 'ASC=la_common_Ascending||DESC=la_common_Descending', 10.02, 2, 1, NULL);
 INSERT INTO SystemSettings VALUES(DEFAULT, 'Comm_Perpage_Products', '10', 'In-Commerce', 'in-commerce:output', 'la_Text_Products', 'la_Perpage_Products', 'text', NULL, NULL, 10.03, 0, 1, NULL);
 INSERT INTO SystemSettings VALUES(DEFAULT, 'Comm_Perpage_Products_Short', '3', 'In-Commerce', 'in-commerce:output', 'la_Text_Products', 'la_Perpage_Products_Shortlist', 'text', NULL, NULL, 10.04, 0, 1, NULL);
 INSERT INTO SystemSettings VALUES(DEFAULT, 'Product_NewDays', '7', 'In-Commerce', 'in-commerce:output', 'la_Text_Products', 'la_conf_DaysToBeNew', 'text', NULL, NULL, 10.05, 0, 1, NULL);
 INSERT INTO SystemSettings VALUES(DEFAULT, 'Product_MinPopRating', '4', 'In-Commerce', 'in-commerce:output', 'la_Text_Products', 'la_fld_Product_MinPopRating', 'text', NULL, NULL, 10.06, 0, 1, NULL);
 INSERT INTO SystemSettings VALUES(DEFAULT, 'Product_MinPopVotes', '1', 'In-Commerce', 'in-commerce:output', 'la_Text_Products', 'la_fld_Product_MinPopVotes', 'text', NULL, NULL, 10.07, 0, 1, NULL);
 INSERT INTO SystemSettings VALUES(DEFAULT, 'Product_MaxHotNumber', '5', 'In-Commerce', 'in-commerce:output', 'la_Text_Products', 'la_fld_Product_MaxHotNumber', 'text', NULL, NULL, 10.08, 0, 1, NULL);
 INSERT INTO SystemSettings VALUES(DEFAULT, 'products_EditorPicksAboveRegular', '1', 'In-Commerce', 'in-commerce:output', 'la_Text_Products', 'la_conf_EditorPicksAboveRegular', 'checkbox', NULL, NULL, 10.09, 0, 1, NULL);
 INSERT INTO SystemSettings VALUES(DEFAULT, 'product_RatingDelay_Value', '30', 'In-Commerce', 'in-commerce:output', 'la_Text_Products', 'la_prompt_DupRating', 'text', '', 'style="width: 50px;"', 10.1, 1, 1, NULL);
 INSERT INTO SystemSettings VALUES(DEFAULT, 'product_RatingDelay_Interval', '86400', 'In-Commerce', 'in-commerce:output', 'la_Text_Products', 'la_prompt_DupRating', 'select', '', '1=la_opt_Sec||60=la_opt_Min||3600=la_opt_Hour||86400=la_opt_Day||604800=la_opt_Week||2419200=la_opt_Month||29030400=la_opt_Year', 10.1, 2, 1, NULL);
 INSERT INTO SystemSettings VALUES(DEFAULT, 'ShowProductImagesInOrders', '0', 'In-Commerce', 'in-commerce:output', 'la_Text_Products', 'la_config_ShowProductImagesInOrders', 'checkbox', NULL, NULL, 10.11, 0, 1, NULL);
 INSERT INTO SystemSettings VALUES(DEFAULT, 'MaxCompareProducts', '3', 'In-Commerce', 'in-commerce:output', 'la_Text_Products', 'la_config_MaxCompareProducts', 'text', NULL, NULL, 10.12, 0, 1, NULL);
 INSERT INTO SystemSettings VALUES(DEFAULT, 'Comm_Perpage_Reviews', '10', 'In-Commerce', 'in-commerce:output', 'la_Text_Reviews', 'la_config_PerpageReviews', 'text', NULL, NULL, 20.01, 0, 1, NULL);
 INSERT INTO SystemSettings VALUES(DEFAULT, 'product_ReviewDelay_Value', '30', 'In-Commerce', 'in-commerce:output', 'la_Text_Reviews', 'la_prompt_DupReviews', 'text', '', 'style="width: 50px;"', 20.02, 1, 1, NULL);
 INSERT INTO SystemSettings VALUES(DEFAULT, 'product_ReviewDelay_Interval', '86400', 'In-Commerce', 'in-commerce:output', 'la_Text_Reviews', 'la_prompt_DupReviews', 'select', '', '1=la_opt_Sec||60=la_opt_Min||3600=la_opt_Hour||86400=la_opt_Day||604800=la_opt_Week||2419200=la_opt_Month||29030400=la_opt_Year', 20.02, 2, 1, NULL);
 INSERT INTO SystemSettings VALUES(DEFAULT, 'Comm_Perpage_Manufacturers', '10', 'In-Commerce', 'in-commerce:output', 'la_Text_Manufacturers', 'la_Perpage_Manufacturers', 'text', NULL, NULL, 30.01, 0, 1, NULL);
 INSERT INTO SystemSettings VALUES(DEFAULT, 'Comm_Perpage_Manufacturers_Short', '3', 'In-Commerce', 'in-commerce:output', 'la_Text_Manufacturers', 'la_Perpage_Manufacturers_Short', 'text', NULL, NULL, 30.02, 0, 1, NULL);
 INSERT INTO SystemSettings VALUES(DEFAULT, 'p_CategoryTemplate', '/in-commerce/designs/section', 'In-Commerce', 'in-commerce:output', 'la_section_Templates', 'la_fld_CategoryTemplate', 'text', '', '', 40.01, 0, 0, NULL);
 INSERT INTO SystemSettings VALUES(DEFAULT, 'p_ItemTemplate', 'in-commerce/products/product_detail', 'In-Commerce', 'in-commerce:output', 'la_section_Templates', 'la_fld_ItemTemplate', 'text', '', '', 40.02, 0, 0, NULL);
 INSERT INTO SystemSettings VALUES(DEFAULT, 'p_MaxImageCount', '5', 'In-Commerce', 'in-commerce:output', 'la_section_ImageSettings', 'la_config_MaxImageCount', 'text', '', '', 50.01, 0, 0, NULL);
 INSERT INTO SystemSettings VALUES(DEFAULT, 'p_ThumbnailImageWidth', '120', 'In-Commerce', 'in-commerce:output', 'la_section_ImageSettings', 'la_config_ThumbnailImageWidth', 'text', '', '', 50.02, 0, 0, NULL);
 INSERT INTO SystemSettings VALUES(DEFAULT, 'p_ThumbnailImageHeight', '120', 'In-Commerce', 'in-commerce:output', 'la_section_ImageSettings', 'la_config_ThumbnailImageHeight', 'text', '', '', 50.03, 0, 0, NULL);
 INSERT INTO SystemSettings VALUES(DEFAULT, 'p_FullImageWidth', '450', 'In-Commerce', 'in-commerce:output', 'la_section_ImageSettings', 'la_config_FullImageWidth', 'text', '', '', 50.04, 0, 0, NULL);
 INSERT INTO SystemSettings VALUES(DEFAULT, 'p_FullImageHeight', '450', 'In-Commerce', 'in-commerce:output', 'la_section_ImageSettings', 'la_config_FullImageHeight', 'text', '', '', 50.05, 0, 0, NULL);
 
 # Section "in-commerce:search":
 INSERT INTO SystemSettings VALUES(DEFAULT, 'Search_ShowMultiple_products', '1', 'In-Commerce', 'in-commerce:search', 'la_config_ShowMultiple', 'la_Text_MultipleShow', 'text', NULL, NULL, 0, 0, 1, NULL);
 INSERT INTO SystemSettings VALUES(DEFAULT, 'SearchRel_Keyword_products', '70', 'In-Commerce', 'in-commerce:search', 'la_config_SearchRel_DefaultKeyword', 'la_text_keyword', 'text', NULL, NULL, 0, 0, 1, NULL);
 INSERT INTO SystemSettings VALUES(DEFAULT, 'SearchRel_Pop_products', '10', 'In-Commerce', 'in-commerce:search', 'la_config_DefaultPop', 'la_text_popularity', 'text', NULL, NULL, 0, 0, 1, NULL);
 INSERT INTO SystemSettings VALUES(DEFAULT, 'SearchRel_Rating_products', '10', 'In-Commerce', 'in-commerce:search', 'la_config_DefaultRating', 'la_prompt_Rating', 'text', NULL, NULL, 0, 0, 1, NULL);
 INSERT INTO SystemSettings VALUES(DEFAULT, 'SearchRel_Increase_products', '30', 'In-Commerce', 'in-commerce:search', 'la_config_DefaultIncreaseImportance', 'la_text_increase_importance', 'text', NULL, NULL, 0, 0, 1, NULL);
 
 INSERT INTO Currencies VALUES (6, 'AFA', '', 0, 'la_AFA', 1, 1120641028, 0, 0, 0);
 INSERT INTO Currencies VALUES (7, 'ALL', '', 0, 'la_ALL', 1, 1120641028, 0, 0, 0);
 INSERT INTO Currencies VALUES (8, 'DZD', '', 0, 'la_DZD', 1, 1120641028, 0, 0, 0);
 INSERT INTO Currencies VALUES (9, 'ADP', '', 0, 'la_ADP', 1, 1124019233, 0, 0, 0);
 INSERT INTO Currencies VALUES (10, 'AOA', '', 0, 'la_AOA', 1, 1120641028, 0, 0, 0);
 INSERT INTO Currencies VALUES (11, 'ARS', '', 0, 'la_ARS', 1, 1120641028, 0, 0, 0);
 INSERT INTO Currencies VALUES (12, 'AMD', '', 0, 'la_AMD', 1, 1120641028, 0, 0, 0);
 INSERT INTO Currencies VALUES (13, 'AWG', '', 0, 'la_AWG', 1, 1120641028, 0, 0, 0);
 INSERT INTO Currencies VALUES (14, 'AZM', '', 0, 'la_AZM', 1, 1120641028, 0, 0, 0);
 INSERT INTO Currencies VALUES (15, 'BSD', '', 0, 'la_BSD', 1, 1120641028, 0, 0, 0);
 INSERT INTO Currencies VALUES (16, 'BHD', '', 0, 'la_BHD', 1, 1120641028, 0, 0, 0);
 INSERT INTO Currencies VALUES (17, 'BDT', '', 0, 'la_BDT', 1, 1120641028, 0, 0, 0);
 INSERT INTO Currencies VALUES (18, 'BBD', '', 0, 'la_BBD', 1, 1120641028, 0, 0, 0);
 INSERT INTO Currencies VALUES (19, 'BYR', '', 0, 'la_BYR', 0.46440677966102, 1120641028, 0, 0, 0);
 INSERT INTO Currencies VALUES (20, 'BZD', '', 0, 'la_BZD', 1, 1120641028, 0, 0, 0);
 INSERT INTO Currencies VALUES (21, 'BMD', '', 0, 'la_BMD', 1, 1120641028, 0, 0, 0);
 INSERT INTO Currencies VALUES (22, 'BTN', '', 0, 'la_BTN', 1, 1120641028, 0, 0, 0);
 INSERT INTO Currencies VALUES (23, 'INR', '', 0, 'la_INR', 0.022962112514351, 1120641028, 0, 0, 0);
 INSERT INTO Currencies VALUES (24, 'BOV', '', 0, 'la_BOV', 1, 1120641028, 0, 0, 0);
 INSERT INTO Currencies VALUES (25, 'BOB', '', 0, 'la_BOB', 1, 1120641028, 0, 0, 0);
 INSERT INTO Currencies VALUES (26, 'BAM', '', 0, 'la_BAM', 1, 1120641028, 0, 0, 0);
 INSERT INTO Currencies VALUES (27, 'BWP', '', 0, 'la_BWP', 1, 1120641028, 0, 0, 0);
 INSERT INTO Currencies VALUES (28, 'BRL', '', 0, 'la_BRL', 0.42331625957753, 1120641028, 0, 0, 0);
 INSERT INTO Currencies VALUES (29, 'BND', '', 0, 'la_BND', 1, 1120641028, 0, 0, 0);
 INSERT INTO Currencies VALUES (30, 'BGL', '', 0, 'la_BGL', 1, 1120641028, 0, 0, 0);
 INSERT INTO Currencies VALUES (31, 'BGN', '', 0, 'la_BGN', 0.60754639807761, 1120650640, 0, 0, 0);
 INSERT INTO Currencies VALUES (32, 'BIF', '', 0, 'la_BIF', 1, 1120641028, 0, 0, 0);
 INSERT INTO Currencies VALUES (33, 'KHR', '', 0, 'la_KHR', 1, 1120641028, 0, 0, 0);
 INSERT INTO Currencies VALUES (34, 'CAD', '', 0, 'la_CAD', 0.80579100834068, 1120657409, 0, 0, 0);
 INSERT INTO Currencies VALUES (35, 'CVE', '', 0, 'la_CVE', 1, 1120641028, 0, 0, 0);
 INSERT INTO Currencies VALUES (36, 'KYD', '', 0, 'la_KYD', 1, 1120641028, 0, 0, 0);
 INSERT INTO Currencies VALUES (37, 'XAF', '', 0, 'la_XAF', 1, 1120641028, 0, 0, 0);
 INSERT INTO Currencies VALUES (38, 'CLF', '', 0, 'la_CLF', 1, 1120641028, 0, 0, 0);
 INSERT INTO Currencies VALUES (39, 'CLP', '', 0, 'la_CLP', 1, 1120641028, 0, 0, 0);
 INSERT INTO Currencies VALUES (40, 'CNY', '', 0, 'la_CNY', 0.12082358922217, 1120650640, 0, 0, 0);
 INSERT INTO Currencies VALUES (41, 'COP', '', 0, 'la_COP', 1, 1120641028, 0, 0, 0);
 INSERT INTO Currencies VALUES (42, 'KMF', '', 0, 'la_KMF', 1, 1120641028, 0, 0, 0);
 INSERT INTO Currencies VALUES (43, 'CDF', '', 0, 'la_CDF', 1, 1120641028, 0, 0, 0);
 INSERT INTO Currencies VALUES (44, 'CRC', '', 0, 'la_CRC', 1, 1120641028, 0, 0, 0);
 INSERT INTO Currencies VALUES (45, 'HRK', '', 0, 'la_HRK', 0.16222968545216, 1120650640, 0, 0, 0);
 INSERT INTO Currencies VALUES (46, 'CUP', '', 0, 'la_CUP', 1, 1120641028, 0, 0, 0);
 INSERT INTO Currencies VALUES (47, 'CYP', '', 0, 'la_CYP', 2.0723753051971, 1120650640, 0, 0, 0);
 INSERT INTO Currencies VALUES (48, 'CZK', '', 0, 'la_CZK', 0.039512535745162, 1120650640, 0, 0, 0);
 INSERT INTO Currencies VALUES (49, 'DKK', '', 0, 'la_DKK', 0.15944343065693, 1120650640, 0, 0, 0);
 INSERT INTO Currencies VALUES (50, 'DJF', '', 0, 'la_DJF', 1, 1120641028, 0, 0, 0);
 INSERT INTO Currencies VALUES (51, 'DOP', '', 0, 'la_DOP', 1, 1120641028, 0, 0, 0);
 INSERT INTO Currencies VALUES (52, 'TPE', '', 0, 'la_TPE', 1, 1120641028, 0, 0, 0);
 INSERT INTO Currencies VALUES (53, 'ECV', '', 0, 'la_ECV', 1, 1120641028, 0, 0, 0);
 INSERT INTO Currencies VALUES (54, 'ECS', '', 0, 'la_ECS', 1, 1120641028, 0, 0, 0);
 INSERT INTO Currencies VALUES (55, 'EGP', '', 0, 'la_EGP', 1, 1120641028, 0, 0, 0);
 INSERT INTO Currencies VALUES (56, 'SVC', '', 0, 'la_SVC', 1, 1120641028, 0, 0, 0);
 INSERT INTO Currencies VALUES (57, 'ERN', '', 0, 'la_ERN', 1, 1120641028, 0, 0, 0);
 INSERT INTO Currencies VALUES (58, 'EEK', '', 0, 'la_EEK', 0.075946211956591, 1120650640, 0, 0, 0);
 INSERT INTO Currencies VALUES (59, 'ETB', '', 0, 'la_ETB', 1, 1120641028, 0, 0, 0);
 INSERT INTO Currencies VALUES (60, 'FKP', '', 0, 'la_FKP', 1, 1120641028, 0, 0, 0);
 INSERT INTO Currencies VALUES (61, 'FJD', '', 0, 'la_FJD', 1, 1120641028, 0, 0, 0);
 INSERT INTO Currencies VALUES (62, 'GMD', '', 0, 'la_GMD', 1, 1120641028, 0, 0, 0);
 INSERT INTO Currencies VALUES (63, 'GEL', '', 0, 'la_GEL', 1, 1124019233, 0, 0, 0);
 INSERT INTO Currencies VALUES (64, 'GHC', '', 0, 'la_GHC', 1, 1120641028, 0, 0, 0);
 INSERT INTO Currencies VALUES (65, 'GIP', '', 0, 'la_GIP', 1, 1120641028, 0, 0, 0);
 INSERT INTO Currencies VALUES (66, 'GTQ', '', 0, 'la_GTQ', 1, 1120641028, 0, 0, 0);
 INSERT INTO Currencies VALUES (67, 'GNF', '', 0, 'la_GNF', 1, 1120641028, 0, 0, 0);
 INSERT INTO Currencies VALUES (68, 'GWP', '', 0, 'la_GWP', 1, 1120641028, 0, 0, 0);
 INSERT INTO Currencies VALUES (69, 'GYD', '', 0, 'la_GYD', 1, 1120641028, 0, 0, 0);
 INSERT INTO Currencies VALUES (70, 'HTG', '', 0, 'la_HTG', 1, 1120641028, 0, 0, 0);
 INSERT INTO Currencies VALUES (71, 'HNL', '', 0, 'la_HNL', 1, 1120641028, 0, 0, 0);
 INSERT INTO Currencies VALUES (72, 'HKD', '', 0, 'la_HKD', 0.1286359158665, 1120650640, 0, 0, 0);
 INSERT INTO Currencies VALUES (73, 'HUF', '', 0, 'la_HUF', 0.0048070388349515, 1120650640, 0, 0, 0);
 INSERT INTO Currencies VALUES (74, 'ISK', '', 0, 'la_ISK', 0.015143366891806, 1120650640, 0, 0, 0);
 INSERT INTO Currencies VALUES (75, 'IDR', '', 0, 'la_IDR', 0.00010126584435926, 1120650640, 0, 0, 0);
 INSERT INTO Currencies VALUES (76, 'IRR', '', 0, 'la_IRR', 1, 1120641028, 0, 0, 0);
 INSERT INTO Currencies VALUES (77, 'IQD', '', 0, 'la_IQD', 1, 1120641028, 0, 0, 0);
 INSERT INTO Currencies VALUES (78, 'ILS', '', 0, 'la_ILS', 0.21864406779661, 1120641028, 0, 0, 0);
 INSERT INTO Currencies VALUES (79, 'JMD', '', 0, 'la_JMD', 1, 1120641028, 0, 0, 0);
 INSERT INTO Currencies VALUES (80, 'JPY', '', 0, 'la_JPY', 0.0089325716003909, 1120650640, 0, 0, 0);
 INSERT INTO Currencies VALUES (81, 'JOD', '', 0, 'la_JOD', 1, 1120641028, 0, 0, 0);
 INSERT INTO Currencies VALUES (82, 'KZT', '', 0, 'la_KZT', 7.3559322033898, 1120641028, 0, 0, 0);
 INSERT INTO Currencies VALUES (83, 'KES', '', 0, 'la_KES', 1, 1120641028, 0, 0, 0);
 INSERT INTO Currencies VALUES (84, 'AUD', '', 0, 'la_AUD', 0.74088160109733, 1120650640, 1, 0, 0);
 INSERT INTO Currencies VALUES (85, 'KPW', '', 0, 'la_KPW', 1, 1120641028, 0, 0, 0);
 INSERT INTO Currencies VALUES (86, 'KRW', '', 0, 'la_KRW', 0.00095066281590758, 1120650640, 0, 0, 0);
 INSERT INTO Currencies VALUES (87, 'KWD', '', 0, 'la_KWD', 1, 1120641028, 0, 0, 0);
 INSERT INTO Currencies VALUES (88, 'KGS', '', 0, 'la_KGS', 1, 1120641028, 0, 0, 0);
 INSERT INTO Currencies VALUES (89, 'LAK', '', 0, 'la_LAK', 1, 1120641028, 0, 0, 0);
 INSERT INTO Currencies VALUES (90, 'LVL', '', 0, 'la_LVL', 1.7697169946847, 1124019016, 0, 0, 0);
 INSERT INTO Currencies VALUES (91, 'LBP', '', 0, 'la_LBP', 1, 1120641028, 0, 0, 0);
 INSERT INTO Currencies VALUES (92, 'LSL', '', 0, 'la_LSL', 1, 1120641028, 0, 0, 0);
 INSERT INTO Currencies VALUES (93, 'LRD', '', 0, 'la_LRD', 1, 1120641028, 0, 0, 0);
 INSERT INTO Currencies VALUES (94, 'LYD', '', 0, 'la_LYD', 1, 1120641028, 0, 0, 0);
 INSERT INTO Currencies VALUES (95, 'CHF', '', 0, 'la_CHF', 0.76560788608981, 1120650640, 0, 0, 0);
 INSERT INTO Currencies VALUES (96, 'LTL', '', 0, 'la_LTL', 0.34415546802595, 1120650640, 0, 0, 0);
 INSERT INTO Currencies VALUES (97, 'MOP', '', 0, 'la_MOP', 1, 1120641028, 0, 0, 0);
 INSERT INTO Currencies VALUES (98, 'MKD', '', 0, 'la_MKD', 1, 1120641028, 0, 0, 0);
 INSERT INTO Currencies VALUES (99, 'MGF', '', 0, 'la_MGF', 1, 1120641028, 0, 0, 0);
 INSERT INTO Currencies VALUES (100, 'MWK', '', 0, 'la_MWK', 1, 1120641028, 0, 0, 0);
 INSERT INTO Currencies VALUES (101, 'MYR', '', 0, 'la_MYR', 0.2631019594819, 1120650640, 0, 0, 0);
 INSERT INTO Currencies VALUES (102, 'MVR', '', 0, 'la_MVR', 1, 1120641028, 0, 0, 0);
 INSERT INTO Currencies VALUES (103, 'MTL', '', 0, 'la_MTL', 2.7679944095038, 1120650640, 0, 0, 0);
 INSERT INTO Currencies VALUES (104, 'EUR', '&euro;&nbsp;', 0, 'la_EUR', 1.2319, 1124019016, 1, 0, 0);
 INSERT INTO Currencies VALUES (105, 'MRO', '', 0, 'la_MRO', 1, 1120641028, 0, 0, 0);
 INSERT INTO Currencies VALUES (106, 'MUR', '', 0, 'la_MUR', 1, 1120641028, 0, 0, 0);
 INSERT INTO Currencies VALUES (107, 'MXN', '', 0, 'la_MXN', 0.092980009298001, 1120641028, 0, 0, 0);
 INSERT INTO Currencies VALUES (108, 'MXV', '', 0, 'la_MXV', 1, 1120641028, 0, 0, 0);
 INSERT INTO Currencies VALUES (109, 'MDL', '', 0, 'la_MDL', 0.079830508474576, 1120641028, 0, 0, 0);
 INSERT INTO Currencies VALUES (110, 'MNT', '', 0, 'la_MNT', 1, 1120641028, 0, 0, 0);
 INSERT INTO Currencies VALUES (111, 'XCD', '', 0, 'la_XCD', 1, 1120641028, 0, 0, 0);
 INSERT INTO Currencies VALUES (112, 'MZM', '', 0, 'la_MZM', 1, 1120641028, 0, 0, 0);
 INSERT INTO Currencies VALUES (113, 'MMK', '', 0, 'la_MMK', 1, 1120641028, 0, 0, 0);
 INSERT INTO Currencies VALUES (114, 'ZAR', '', 0, 'la_ZAR', 0.14487399875645, 1120650640, 0, 0, 0);
 INSERT INTO Currencies VALUES (115, 'NAD', '', 0, 'la_NAD', 1, 1120641028, 0, 0, 0);
 INSERT INTO Currencies VALUES (116, 'NPR', '', 0, 'la_NPR', 1, 1120641028, 0, 0, 0);
 INSERT INTO Currencies VALUES (117, 'ANG', '', 0, 'la_ANG', 1, 1120641028, 0, 0, 0);
 INSERT INTO Currencies VALUES (118, 'XPF', '', 0, 'la_XPF', 1, 1120641028, 0, 0, 0);
 INSERT INTO Currencies VALUES (120, 'NIO', '', 0, 'la_NIO', 1, 1120641028, 0, 0, 0);
 INSERT INTO Currencies VALUES (121, 'NGN', '', 0, 'la_NGN', 1, 1120641028, 0, 0, 0);
 INSERT INTO Currencies VALUES (122, 'NOK', '', 0, 'la_NOK', 0.15015163002274, 1120650640, 0, 0, 0);
 INSERT INTO Currencies VALUES (123, 'OMR', '', 0, 'la_OMR', 1, 1120641028, 0, 0, 0);
 INSERT INTO Currencies VALUES (124, 'PKR', '', 0, 'la_PKR', 1, 1120641028, 0, 0, 0);
 INSERT INTO Currencies VALUES (125, 'PAB', '', 0, 'la_PAB', 1, 1120641028, 0, 0, 0);
 INSERT INTO Currencies VALUES (126, 'PGK', '', 0, 'la_PGK', 1, 1120641028, 0, 0, 0);
 INSERT INTO Currencies VALUES (127, 'PYG', '', 0, 'la_PYG', 1, 1120641028, 0, 0, 0);
 INSERT INTO Currencies VALUES (128, 'PEN', '', 0, 'la_PEN', 1, 1120641028, 0, 0, 0);
 INSERT INTO Currencies VALUES (129, 'PHP', '', 0, 'la_PHP', 0.017769769111138, 1120650640, 0, 0, 0);
 INSERT INTO Currencies VALUES (130, 'PLN', '', 0, 'la_PLN', 0.29408270844161, 1120650640, 0, 0, 0);
 INSERT INTO Currencies VALUES (131, 'USD', '$&nbsp;', 0, 'la_USD', 1, 1124019100, 1, 1, 0);
 INSERT INTO Currencies VALUES (132, 'QAR', '', 0, 'la_QAR', 1, 1120641028, 0, 0, 0);
 INSERT INTO Currencies VALUES (133, 'ROL', '', 0, 'la_ROL', 1, 1120641028, 0, 0, 0);
 INSERT INTO Currencies VALUES (134, 'RUB', NULL, 0, 'la_RUB', 0.0347, 1123850285, 0, 0, 0);
 INSERT INTO Currencies VALUES (136, 'RWF', '', 0, 'la_RWF', 1, 1120641028, 0, 0, 0);
 INSERT INTO Currencies VALUES (137, 'SHP', '', 0, 'la_SHP', 1, 1120641028, 0, 0, 0);
 INSERT INTO Currencies VALUES (138, 'WST', '', 0, 'la_WST', 1, 1120641028, 0, 0, 0);
 INSERT INTO Currencies VALUES (139, 'STD', '', 0, 'la_STD', 1, 1120641028, 0, 0, 0);
 INSERT INTO Currencies VALUES (140, 'SAR', '', 0, 'la_SAR', 1, 1120641028, 0, 0, 0);
 INSERT INTO Currencies VALUES (141, 'SCR', '', 0, 'la_SCR', 1, 1120641028, 0, 0, 0);
 INSERT INTO Currencies VALUES (142, 'SLL', '', 0, 'la_SLL', 1, 1120641028, 0, 0, 0);
 INSERT INTO Currencies VALUES (143, 'SGD', '', 0, 'la_SGD', 0.58838383838384, 1120650640, 0, 0, 0);
 INSERT INTO Currencies VALUES (144, 'SKK', '', 0, 'la_SKK', 0.031050431147113, 1120650640, 0, 0, 0);
 INSERT INTO Currencies VALUES (145, 'SIT', '', 0, 'la_SIT', 0.0049628299365185, 1120650640, 0, 0, 0);
 INSERT INTO Currencies VALUES (146, 'SBD', '', 0, 'la_SBD', 1, 1120641028, 0, 0, 0);
 INSERT INTO Currencies VALUES (147, 'SOS', '', 0, 'la_SOS', 1, 1120641028, 0, 0, 0);
 INSERT INTO Currencies VALUES (148, 'LKR', '', 0, 'la_LKR', 0.0099920063948841, 1120641028, 0, 0, 0);
 INSERT INTO Currencies VALUES (149, 'SDD', '', 0, 'la_SDD', 1, 1120641028, 0, 0, 0);
 INSERT INTO Currencies VALUES (150, 'SRG', '', 0, 'la_SRG', 1, 1120641028, 0, 0, 0);
 INSERT INTO Currencies VALUES (151, 'SZL', '', 0, 'la_SZL', 1, 1120641028, 0, 0, 0);
 INSERT INTO Currencies VALUES (152, 'SEK', '', 0, 'la_SEK', 0.12594327624216, 1120650640, 0, 0, 0);
 INSERT INTO Currencies VALUES (153, 'SYP', '', 0, 'la_SYP', 1, 1120641028, 0, 0, 0);
 INSERT INTO Currencies VALUES (154, 'TWD', '', 0, 'la_TWD', 0.031298904538341, 1120641028, 0, 0, 0);
 INSERT INTO Currencies VALUES (155, 'TJS', '', 0, 'la_TJS', 1, 1120641028, 0, 0, 0);
 INSERT INTO Currencies VALUES (156, 'TZS', '', 0, 'la_TZS', 1, 1120641028, 0, 0, 0);
 INSERT INTO Currencies VALUES (157, 'THB', '', 0, 'la_THB', 0.024061474911918, 1120650640, 0, 0, 0);
 INSERT INTO Currencies VALUES (158, 'XOF', '', 0, 'la_XOF', 1, 1120641028, 0, 0, 0);
 INSERT INTO Currencies VALUES (159, 'NZD', '', 0, 'la_NZD', 0.67409802586794, 1120650640, 0, 0, 0);
 INSERT INTO Currencies VALUES (160, 'TOP', '', 0, 'la_TOP', 1, 1120641028, 0, 0, 0);
 INSERT INTO Currencies VALUES (161, 'TTD', '', 0, 'la_TTD', 1, 1120641028, 0, 0, 0);
 INSERT INTO Currencies VALUES (162, 'TND', '', 0, 'la_TND', 1, 1120641028, 0, 0, 0);
 INSERT INTO Currencies VALUES (163, 'TRL', '', 0, 'la_TRL', 1, 1120641028, 0, 0, 0);
 INSERT INTO Currencies VALUES (164, 'TMM', '', 0, 'la_TMM', 1, 1120641028, 0, 0, 0);
 INSERT INTO Currencies VALUES (165, 'UGX', '', 0, 'la_UGX', 1, 1120641028, 0, 0, 0);
 INSERT INTO Currencies VALUES (166, 'UAH', '', 0, 'la_UAH', 0.19830508474576, 1120641028, 0, 0, 0);
 INSERT INTO Currencies VALUES (167, 'AED', '', 0, 'la_AED', 0.2728813559322, 1120641028, 0, 0, 0);
 INSERT INTO Currencies VALUES (168, 'GBP', NULL, 0, 'la_GBP', 1.7543367535248, 1120657409, 1, 0, 0);
 INSERT INTO Currencies VALUES (169, 'USS', '', 0, 'la_USS', 1, 1120641028, 0, 0, 0);
 INSERT INTO Currencies VALUES (170, 'USN', '', 0, 'la_USN', 1, 1120641028, 0, 0, 0);
 INSERT INTO Currencies VALUES (171, 'UYU', '', 0, 'la_UYU', 1, 1120641028, 0, 0, 0);
 INSERT INTO Currencies VALUES (172, 'UZS', '', 0, 'la_UZS', 1, 1120641028, 0, 0, 0);
 INSERT INTO Currencies VALUES (173, 'VUV', '', 0, 'la_VUV', 1, 1120641028, 0, 0, 0);
 INSERT INTO Currencies VALUES (174, 'VEB', '', 0, 'la_VEB', 0.00046628741956542, 1120641028, 0, 0, 0);
 INSERT INTO Currencies VALUES (175, 'VND', '', 0, 'la_VND', 1, 1120641028, 0, 0, 0);
 INSERT INTO Currencies VALUES (176, 'MAD', '', 0, 'la_MAD', 1, 1120641028, 0, 0, 0);
 INSERT INTO Currencies VALUES (177, 'YER', '', 0, 'la_YER', 1, 1120641028, 0, 0, 0);
 INSERT INTO Currencies VALUES (178, 'YUM', '', 0, 'la_YUM', 1, 1120641028, 0, 0, 0);
 INSERT INTO Currencies VALUES (179, 'ZMK', '', 0, 'la_ZMK', 1, 1120641028, 0, 0, 0);
 INSERT INTO Currencies VALUES (180, 'ZWD', '', 0, 'la_ZWD', 1, 1120641028, 0, 0, 0);
 INSERT INTO Currencies VALUES (181, 'AFN', '', 0, 'la_AFN', 0.02, 1120641028, 0, 0, 0);
 
 INSERT INTO CustomFields VALUES (DEFAULT, 11, 'Features', 'la_Features', 1, 'la_Text_CustomFields', 'la_Features', 'textarea', 'rows="5" cols="70"', '', 0, 1, 0, 0);
 INSERT INTO CustomFields VALUES (DEFAULT, 11, 'Availability', 'la_Availability', 1, 'la_Text_CustomFields', 'la_Availability', 'text', 'size="70"', '', 0, 1, 0, 0);
 INSERT INTO CustomFields VALUES (DEFAULT, 1, 'p_ItemTemplate', 'la_fld_cust_p_ItemTemplate', 0, 'la_title_SystemCF', 'la_fld_cust_p_ItemTemplate', 'text', NULL, '', 0, 0, 1, 0);
 INSERT INTO CustomFields VALUES (DEFAULT, 6, 'shipping_addr_block', 'la_fld_BlockShippingAddress', 0, 'la_section_StoreSettings', 'la_fld_BlockShippingAddress', 'checkbox', '1=+Block', '', 0, 1, 1, 0);
 
-INSERT INTO EmailEvents (EventId, Event, ReplacementTags, Enabled, FrontEndOnly, Module, Description, Type, AllowChangingSender, AllowChangingRecipient) VALUES(DEFAULT, 'ORDER.SUBMIT', NULL, 1, 1, 'In-Commerce', 'Order Submitted', 1, 1, 1);
-INSERT INTO EmailEvents (EventId, Event, ReplacementTags, Enabled, FrontEndOnly, Module, Description, Type, AllowChangingSender, AllowChangingRecipient) VALUES(DEFAULT, 'ORDER.SUBMIT', NULL, 1, 1, 'In-Commerce', 'Order Submitted', 0, 1, 1);
-INSERT INTO EmailEvents (EventId, Event, ReplacementTags, Enabled, FrontEndOnly, Module, Description, Type, AllowChangingSender, AllowChangingRecipient) VALUES(DEFAULT, 'ORDER.APPROVE', NULL, 1, 0, 'In-Commerce', 'Order Approved', 0, 1, 1);
-INSERT INTO EmailEvents (EventId, Event, ReplacementTags, Enabled, FrontEndOnly, Module, Description, Type, AllowChangingSender, AllowChangingRecipient) VALUES(DEFAULT, 'ORDER.DENY', NULL, 1, 0, 'In-Commerce', 'Order Denied', 0, 1, 1);
-INSERT INTO EmailEvents (EventId, Event, ReplacementTags, Enabled, FrontEndOnly, Module, Description, Type, AllowChangingSender, AllowChangingRecipient) VALUES(DEFAULT, 'ORDER.SHIP', NULL, 1, 0, 'In-Commerce', 'Order Shipped', 0, 1, 1);
-INSERT INTO EmailEvents (EventId, Event, ReplacementTags, Enabled, FrontEndOnly, Module, Description, Type, AllowChangingSender, AllowChangingRecipient) VALUES(DEFAULT, 'BACKORDER.ADD', NULL, 1, 1, 'In-Commerce', 'Backorder Added', 1, 1, 1);
-INSERT INTO EmailEvents (EventId, Event, ReplacementTags, Enabled, FrontEndOnly, Module, Description, Type, AllowChangingSender, AllowChangingRecipient) VALUES(DEFAULT, 'BACKORDER.ADD', NULL, 1, 1, 'In-Commerce', 'Backorder Added', 0, 1, 1);
-INSERT INTO EmailEvents (EventId, Event, ReplacementTags, Enabled, FrontEndOnly, Module, Description, Type, AllowChangingSender, AllowChangingRecipient) VALUES(DEFAULT, 'BACKORDER.FULLFILL', NULL, 1, 0, 'In-Commerce', 'Back-order is Fulfilled', 1, 1, 1);
-INSERT INTO EmailEvents (EventId, Event, ReplacementTags, Enabled, FrontEndOnly, Module, Description, Type, AllowChangingSender, AllowChangingRecipient) VALUES(DEFAULT, 'BACKORDER.PROCESS', NULL, 1, 0, 'In-Commerce', 'Backorder Processed', 0, 1, 1);
-INSERT INTO EmailEvents (EventId, Event, ReplacementTags, Enabled, FrontEndOnly, Module, Description, Type, AllowChangingSender, AllowChangingRecipient) VALUES(DEFAULT, 'PRODUCT.SUGGEST', NULL, 1, 0, 'In-Commerce', 'Suggest product to a friend', 0, 1, 1);
-INSERT INTO EmailEvents (EventId, Event, ReplacementTags, Enabled, FrontEndOnly, Module, Description, Type, AllowChangingSender, AllowChangingRecipient) VALUES(DEFAULT, 'PRODUCT.SUGGEST', NULL, 1, 1, 'In-Commerce', 'Suggest product to a friend', 1, 1, 1);
-INSERT INTO EmailEvents (EventId, Event, ReplacementTags, Enabled, FrontEndOnly, Module, Description, Type, AllowChangingSender, AllowChangingRecipient) VALUES(DEFAULT, 'AFFILIATE.REGISTER', NULL, 1, 1, 'In-Commerce', 'Affiliate registered', 0, 1, 1);
-INSERT INTO EmailEvents (EventId, Event, ReplacementTags, Enabled, FrontEndOnly, Module, Description, Type, AllowChangingSender, AllowChangingRecipient) VALUES(DEFAULT, 'AFFILIATE.REGISTER', NULL, 1, 1, 'In-Commerce', 'Affiliate registered', 1, 1, 1);
-INSERT INTO EmailEvents (EventId, Event, ReplacementTags, Enabled, FrontEndOnly, Module, Description, Type, AllowChangingSender, AllowChangingRecipient) VALUES(DEFAULT, 'AFFILIATE.PAYMENT', NULL, 1, 0, 'In-Commerce', 'Affiliate payment issued', 0, 1, 1);
-INSERT INTO EmailEvents (EventId, Event, ReplacementTags, Enabled, FrontEndOnly, Module, Description, Type, AllowChangingSender, AllowChangingRecipient) VALUES(DEFAULT, 'AFFILIATE.PAYMENT', NULL, 1, 0, 'In-Commerce', 'Affiliate payment issued', 1, 1, 1);
-INSERT INTO EmailEvents (EventId, Event, ReplacementTags, Enabled, FrontEndOnly, Module, Description, Type, AllowChangingSender, AllowChangingRecipient) VALUES(DEFAULT, 'AFFILIATE.REGISTRATION.APPROVED', NULL, 1, 0, 'In-Commerce', 'Affiliate registration approved', 0, 1, 1);
-INSERT INTO EmailEvents (EventId, Event, ReplacementTags, Enabled, FrontEndOnly, Module, Description, Type, AllowChangingSender, AllowChangingRecipient) VALUES(DEFAULT, 'AFFILIATE.REGISTRATION.APPROVED', NULL, 0, 0, 'In-Commerce', 'Affiliate registration approved', 1, 1, 1);
-INSERT INTO EmailEvents (EventId, Event, ReplacementTags, Enabled, FrontEndOnly, Module, Description, Type, AllowChangingSender, AllowChangingRecipient) VALUES(DEFAULT, 'AFFILIATE.REGISTRATION.DENIED', NULL, 1, 0, 'In-Commerce', 'Affiliate registration denied', 0, 1, 1);
-INSERT INTO EmailEvents (EventId, Event, ReplacementTags, Enabled, FrontEndOnly, Module, Description, Type, AllowChangingSender, AllowChangingRecipient) VALUES(DEFAULT, 'AFFILIATE.REGISTRATION.DENIED', NULL, 0, 0, 'In-Commerce', 'Affiliate registration denied', 1, 1, 1);
-INSERT INTO EmailEvents (EventId, Event, ReplacementTags, Enabled, FrontEndOnly, Module, Description, Type, AllowChangingSender, AllowChangingRecipient) VALUES(DEFAULT, 'AFFILIATE.PAYMENT.TYPE.CHANGED', NULL, 1, 0, 'In-Commerce', 'Affiliate payment type changed', 0, 1, 1);
-INSERT INTO EmailEvents (EventId, Event, ReplacementTags, Enabled, FrontEndOnly, Module, Description, Type, AllowChangingSender, AllowChangingRecipient) VALUES(DEFAULT, 'AFFILIATE.PAYMENT.TYPE.CHANGED', NULL, 1, 0, 'In-Commerce', 'Affiliate payment type changed', 1, 1, 1);
-INSERT INTO EmailEvents (EventId, Event, ReplacementTags, Enabled, FrontEndOnly, Module, Description, Type, AllowChangingSender, AllowChangingRecipient) VALUES(DEFAULT, 'ORDER.RECURRING.PROCESSED', NULL, 1, 0, 'In-Commerce', 'Recurring Order Processed', 0, 1, 1);
-INSERT INTO EmailEvents (EventId, Event, ReplacementTags, Enabled, FrontEndOnly, Module, Description, Type, AllowChangingSender, AllowChangingRecipient) VALUES(DEFAULT, 'ORDER.RECURRING.PROCESSED', NULL, 1, 0, 'In-Commerce', 'Recurring Order Processed', 1, 1, 1);
-INSERT INTO EmailEvents (EventId, Event, ReplacementTags, Enabled, FrontEndOnly, Module, Description, Type, AllowChangingSender, AllowChangingRecipient) VALUES(DEFAULT, 'ORDER.RECURRING.DENIED', NULL, 1, 0, 'In-Commerce', 'Recurring Order Denied', 0, 1, 1);
-INSERT INTO EmailEvents (EventId, Event, ReplacementTags, Enabled, FrontEndOnly, Module, Description, Type, AllowChangingSender, AllowChangingRecipient) VALUES(DEFAULT, 'ORDER.RECURRING.DENIED', NULL, 1, 0, 'In-Commerce', 'Recurring Order Denied', 1, 1, 1);
-INSERT INTO EmailEvents (EventId, Event, ReplacementTags, Enabled, FrontEndOnly, Module, Description, Type, AllowChangingSender, AllowChangingRecipient) VALUES(DEFAULT, 'USER.GIFTCERTIFICATE', NULL, 1, 0, 'In-Commerce', 'Gift Certificate', 0, 1, 1);
-INSERT INTO EmailEvents (EventId, Event, ReplacementTags, Enabled, FrontEndOnly, Module, Description, Type, AllowChangingSender, AllowChangingRecipient) VALUES(DEFAULT, 'USER.GIFTCERTIFICATE', NULL, 1, 0, 'In-Commerce', 'Gift Certificate', 1, 1, 1);
+INSERT INTO EmailTemplates (TemplateId, TemplateName, ReplacementTags, Enabled, FrontEndOnly, Module, Description, Type, AllowChangingSender, AllowChangingRecipient) VALUES(DEFAULT, 'ORDER.SUBMIT', NULL, 1, 1, 'In-Commerce', 'Order Submitted', 1, 1, 1);
+INSERT INTO EmailTemplates (TemplateId, TemplateName, ReplacementTags, Enabled, FrontEndOnly, Module, Description, Type, AllowChangingSender, AllowChangingRecipient) VALUES(DEFAULT, 'ORDER.SUBMIT', NULL, 1, 1, 'In-Commerce', 'Order Submitted', 0, 1, 1);
+INSERT INTO EmailTemplates (TemplateId, TemplateName, ReplacementTags, Enabled, FrontEndOnly, Module, Description, Type, AllowChangingSender, AllowChangingRecipient) VALUES(DEFAULT, 'ORDER.APPROVE', NULL, 1, 0, 'In-Commerce', 'Order Approved', 0, 1, 1);
+INSERT INTO EmailTemplates (TemplateId, TemplateName, ReplacementTags, Enabled, FrontEndOnly, Module, Description, Type, AllowChangingSender, AllowChangingRecipient) VALUES(DEFAULT, 'ORDER.DENY', NULL, 1, 0, 'In-Commerce', 'Order Denied', 0, 1, 1);
+INSERT INTO EmailTemplates (TemplateId, TemplateName, ReplacementTags, Enabled, FrontEndOnly, Module, Description, Type, AllowChangingSender, AllowChangingRecipient) VALUES(DEFAULT, 'ORDER.SHIP', NULL, 1, 0, 'In-Commerce', 'Order Shipped', 0, 1, 1);
+INSERT INTO EmailTemplates (TemplateId, TemplateName, ReplacementTags, Enabled, FrontEndOnly, Module, Description, Type, AllowChangingSender, AllowChangingRecipient) VALUES(DEFAULT, 'BACKORDER.ADD', NULL, 1, 1, 'In-Commerce', 'Backorder Added', 1, 1, 1);
+INSERT INTO EmailTemplates (TemplateId, TemplateName, ReplacementTags, Enabled, FrontEndOnly, Module, Description, Type, AllowChangingSender, AllowChangingRecipient) VALUES(DEFAULT, 'BACKORDER.ADD', NULL, 1, 1, 'In-Commerce', 'Backorder Added', 0, 1, 1);
+INSERT INTO EmailTemplates (TemplateId, TemplateName, ReplacementTags, Enabled, FrontEndOnly, Module, Description, Type, AllowChangingSender, AllowChangingRecipient) VALUES(DEFAULT, 'BACKORDER.FULLFILL', NULL, 1, 0, 'In-Commerce', 'Back-order is Fulfilled', 1, 1, 1);
+INSERT INTO EmailTemplates (TemplateId, TemplateName, ReplacementTags, Enabled, FrontEndOnly, Module, Description, Type, AllowChangingSender, AllowChangingRecipient) VALUES(DEFAULT, 'BACKORDER.PROCESS', NULL, 1, 0, 'In-Commerce', 'Backorder Processed', 0, 1, 1);
+INSERT INTO EmailTemplates (TemplateId, TemplateName, ReplacementTags, Enabled, FrontEndOnly, Module, Description, Type, AllowChangingSender, AllowChangingRecipient) VALUES(DEFAULT, 'PRODUCT.SUGGEST', NULL, 1, 0, 'In-Commerce', 'Suggest product to a friend', 0, 1, 1);
+INSERT INTO EmailTemplates (TemplateId, TemplateName, ReplacementTags, Enabled, FrontEndOnly, Module, Description, Type, AllowChangingSender, AllowChangingRecipient) VALUES(DEFAULT, 'PRODUCT.SUGGEST', NULL, 1, 1, 'In-Commerce', 'Suggest product to a friend', 1, 1, 1);
+INSERT INTO EmailTemplates (TemplateId, TemplateName, ReplacementTags, Enabled, FrontEndOnly, Module, Description, Type, AllowChangingSender, AllowChangingRecipient) VALUES(DEFAULT, 'AFFILIATE.REGISTER', NULL, 1, 1, 'In-Commerce', 'Affiliate registered', 0, 1, 1);
+INSERT INTO EmailTemplates (TemplateId, TemplateName, ReplacementTags, Enabled, FrontEndOnly, Module, Description, Type, AllowChangingSender, AllowChangingRecipient) VALUES(DEFAULT, 'AFFILIATE.REGISTER', NULL, 1, 1, 'In-Commerce', 'Affiliate registered', 1, 1, 1);
+INSERT INTO EmailTemplates (TemplateId, TemplateName, ReplacementTags, Enabled, FrontEndOnly, Module, Description, Type, AllowChangingSender, AllowChangingRecipient) VALUES(DEFAULT, 'AFFILIATE.PAYMENT', NULL, 1, 0, 'In-Commerce', 'Affiliate payment issued', 0, 1, 1);
+INSERT INTO EmailTemplates (TemplateId, TemplateName, ReplacementTags, Enabled, FrontEndOnly, Module, Description, Type, AllowChangingSender, AllowChangingRecipient) VALUES(DEFAULT, 'AFFILIATE.PAYMENT', NULL, 1, 0, 'In-Commerce', 'Affiliate payment issued', 1, 1, 1);
+INSERT INTO EmailTemplates (TemplateId, TemplateName, ReplacementTags, Enabled, FrontEndOnly, Module, Description, Type, AllowChangingSender, AllowChangingRecipient) VALUES(DEFAULT, 'AFFILIATE.REGISTRATION.APPROVED', NULL, 1, 0, 'In-Commerce', 'Affiliate registration approved', 0, 1, 1);
+INSERT INTO EmailTemplates (TemplateId, TemplateName, ReplacementTags, Enabled, FrontEndOnly, Module, Description, Type, AllowChangingSender, AllowChangingRecipient) VALUES(DEFAULT, 'AFFILIATE.REGISTRATION.APPROVED', NULL, 0, 0, 'In-Commerce', 'Affiliate registration approved', 1, 1, 1);
+INSERT INTO EmailTemplates (TemplateId, TemplateName, ReplacementTags, Enabled, FrontEndOnly, Module, Description, Type, AllowChangingSender, AllowChangingRecipient) VALUES(DEFAULT, 'AFFILIATE.REGISTRATION.DENIED', NULL, 1, 0, 'In-Commerce', 'Affiliate registration denied', 0, 1, 1);
+INSERT INTO EmailTemplates (TemplateId, TemplateName, ReplacementTags, Enabled, FrontEndOnly, Module, Description, Type, AllowChangingSender, AllowChangingRecipient) VALUES(DEFAULT, 'AFFILIATE.REGISTRATION.DENIED', NULL, 0, 0, 'In-Commerce', 'Affiliate registration denied', 1, 1, 1);
+INSERT INTO EmailTemplates (TemplateId, TemplateName, ReplacementTags, Enabled, FrontEndOnly, Module, Description, Type, AllowChangingSender, AllowChangingRecipient) VALUES(DEFAULT, 'AFFILIATE.PAYMENT.TYPE.CHANGED', NULL, 1, 0, 'In-Commerce', 'Affiliate payment type changed', 0, 1, 1);
+INSERT INTO EmailTemplates (TemplateId, TemplateName, ReplacementTags, Enabled, FrontEndOnly, Module, Description, Type, AllowChangingSender, AllowChangingRecipient) VALUES(DEFAULT, 'AFFILIATE.PAYMENT.TYPE.CHANGED', NULL, 1, 0, 'In-Commerce', 'Affiliate payment type changed', 1, 1, 1);
+INSERT INTO EmailTemplates (TemplateId, TemplateName, ReplacementTags, Enabled, FrontEndOnly, Module, Description, Type, AllowChangingSender, AllowChangingRecipient) VALUES(DEFAULT, 'ORDER.RECURRING.PROCESSED', NULL, 1, 0, 'In-Commerce', 'Recurring Order Processed', 0, 1, 1);
+INSERT INTO EmailTemplates (TemplateId, TemplateName, ReplacementTags, Enabled, FrontEndOnly, Module, Description, Type, AllowChangingSender, AllowChangingRecipient) VALUES(DEFAULT, 'ORDER.RECURRING.PROCESSED', NULL, 1, 0, 'In-Commerce', 'Recurring Order Processed', 1, 1, 1);
+INSERT INTO EmailTemplates (TemplateId, TemplateName, ReplacementTags, Enabled, FrontEndOnly, Module, Description, Type, AllowChangingSender, AllowChangingRecipient) VALUES(DEFAULT, 'ORDER.RECURRING.DENIED', NULL, 1, 0, 'In-Commerce', 'Recurring Order Denied', 0, 1, 1);
+INSERT INTO EmailTemplates (TemplateId, TemplateName, ReplacementTags, Enabled, FrontEndOnly, Module, Description, Type, AllowChangingSender, AllowChangingRecipient) VALUES(DEFAULT, 'ORDER.RECURRING.DENIED', NULL, 1, 0, 'In-Commerce', 'Recurring Order Denied', 1, 1, 1);
+INSERT INTO EmailTemplates (TemplateId, TemplateName, ReplacementTags, Enabled, FrontEndOnly, Module, Description, Type, AllowChangingSender, AllowChangingRecipient) VALUES(DEFAULT, 'USER.GIFTCERTIFICATE', NULL, 1, 0, 'In-Commerce', 'Gift Certificate', 0, 1, 1);
+INSERT INTO EmailTemplates (TemplateId, TemplateName, ReplacementTags, Enabled, FrontEndOnly, Module, Description, Type, AllowChangingSender, AllowChangingRecipient) VALUES(DEFAULT, 'USER.GIFTCERTIFICATE', NULL, 1, 0, 'In-Commerce', 'Gift Certificate', 1, 1, 1);
 
 INSERT INTO GatewayConfigFields VALUES (1, 'submit_url', 'Gateway URL', 'text', '', 2);
 INSERT INTO GatewayConfigFields VALUES (2, 'user_account', 'Authorize.net User Name', 'text', '', 2);
 INSERT INTO GatewayConfigFields VALUES (4, 'transaction_key', 'Authorize.net Transaction Key', 'text', '', 2);
 INSERT INTO GatewayConfigFields VALUES (9, 'business_account', 'Username', 'text', '', 4);
 INSERT INTO GatewayConfigFields VALUES (10, 'submit_url', 'Gateway URL', 'text', '', 4);
 INSERT INTO GatewayConfigFields VALUES (11, 'currency_code', 'Payment Currency Code', 'text', '', 4);
 INSERT INTO GatewayConfigFields VALUES (12, 'shipping_control', 'Shipping Control', 'select', '3=la_CreditDirect,4=la_CreditPreAuthorize', 2);
 INSERT INTO GatewayConfigFields VALUES (13, 'encapsulate_char', 'Encapsulate Char', 'text', '', 2);
 INSERT INTO GatewayConfigFields VALUES (14, 'shipping_control', 'Shipping Control', 'select', '3=la_CreditDirect,4=la_CreditPreAuthorize', 4);
 
 INSERT INTO GatewayConfigValues VALUES (36, 12, 3, '4');
 INSERT INTO GatewayConfigValues VALUES (35, 1, 3, 'https://secure.authorize.net/gateway/transact.dll');
 INSERT INTO GatewayConfigValues VALUES (34, 2, 3, '');
 INSERT INTO GatewayConfigValues VALUES (33, 4, 3, '');
 INSERT INTO GatewayConfigValues VALUES (32, 9, 4, '');
 INSERT INTO GatewayConfigValues VALUES (31, 10, 4, 'https://www.paypal.com/cgi-bin/webscr');
 INSERT INTO GatewayConfigValues VALUES (37, 11, 4, 'USD');
 INSERT INTO GatewayConfigValues VALUES (38, 13, 3, '|');
 INSERT INTO GatewayConfigValues VALUES (39, 14, 4, '4');
 
 INSERT INTO Gateways VALUES (1, 'None', 'kGWBase', 'gw_base.php', 0);
 INSERT INTO Gateways VALUES (2, 'Credit Card (Authorize.Net)', 'kGWAuthorizeNet', 'authorizenet.php', 1);
 INSERT INTO Gateways VALUES (3, 'Credit Card (Manual Processing)', 'kGWBase', 'gw_base.php', 1);
 INSERT INTO Gateways VALUES (4, 'PayPal', 'kGWPayPal', 'paypal.php', 0);
 
 INSERT INTO ItemTypes VALUES (11, 'In-Commerce', 'p', 'Products', 'Name', 'CreatedById', NULL, NULL, '', 0, '', 'ProductsItem', 'Product');
 INSERT INTO ItemTypes VALUES (13, 'In-Commerce', 'ord', 'Orders', 'OrderNumber', '', NULL, NULL, '', 0, '', 'OrdersItem', 'Order');
 
 INSERT INTO PaymentTypes (PaymentTypeId, `Name`, l1_Description, l1_Instructions, AdminComments, `Status`, Priority, IsPrimary, BuiltIn, GatewayId, PlacedOrdersEdit, ProcessingFee, PortalGroups) VALUES (1, 'Credit Card (manual)', 'Credit Card', 'Please enter your credit card details.', NULL, 1, 0, 1, 1, 3, DEFAULT, DEFAULT, ',15,');
 INSERT INTO PaymentTypes (PaymentTypeId, `Name`, l1_Description, l1_Instructions, AdminComments, `Status`, Priority, IsPrimary, BuiltIn, GatewayId, PlacedOrdersEdit, ProcessingFee, PortalGroups) VALUES (4, 'PayPal', 'PayPal', 'You will be redirected to PayPal site to make the payment after confirming your order on the next checkout step.', NULL, 0, 0, 0, 1, 4, DEFAULT, DEFAULT, ',15,');
 INSERT INTO PaymentTypes (PaymentTypeId, `Name`, l1_Description, l1_Instructions, AdminComments, `Status`, Priority, IsPrimary, BuiltIn, GatewayId, PlacedOrdersEdit, ProcessingFee, PortalGroups) VALUES (2, 'Check/MO', 'Check or Money Order', NULL, NULL, 0, 0, 0, 1, 1, 1, DEFAULT, ',15,');
 INSERT INTO PaymentTypes (PaymentTypeId, `Name`, l1_Description, l1_Instructions, AdminComments, `Status`, Priority, IsPrimary, BuiltIn, GatewayId, PlacedOrdersEdit, ProcessingFee, PortalGroups) VALUES (3, 'Authorize.Net', 'Credit Card', 'Please enter your Credit Card details below. Your credit card will not be charged until you confirm your purchase on the next(last) step of checkout process.', NULL, 0, 0, 0, 1, 2, DEFAULT, DEFAULT, ',15,');
 
 INSERT INTO PaymentTypeCurrencies VALUES (DEFAULT, 4, 131);
 INSERT INTO PaymentTypeCurrencies VALUES (DEFAULT, 2, 131);
 INSERT INTO PaymentTypeCurrencies VALUES (DEFAULT, 3, 131);
 INSERT INTO PaymentTypeCurrencies VALUES (DEFAULT, 1, 131);
 
 INSERT INTO CategoryPermissionsConfig VALUES (DEFAULT, 'PRODUCT.RATE', 'la_PermName_Product.Rate_desc', 'In-Commerce', 1);
 INSERT INTO CategoryPermissionsConfig VALUES (DEFAULT, 'PRODUCT.REVIEW', 'la_PermName_Product.Review_desc', 'In-Commerce', 1);
 INSERT INTO CategoryPermissionsConfig VALUES (DEFAULT, 'PRODUCT.REVIEW.PENDING', 'la_PermName_Product.Review_Pending_desc', 'In-Commerce', 1);
 INSERT INTO CategoryPermissionsConfig VALUES (DEFAULT, 'PRODUCT.ADD', 'la_PermName_Product.Add_desc', 'In-Commerce', 1);
 INSERT INTO CategoryPermissionsConfig VALUES (DEFAULT, 'PRODUCT.DELETE', 'la_PermName_Product.Delete_desc', 'In-Commerce', 1);
 INSERT INTO CategoryPermissionsConfig VALUES (DEFAULT, 'PRODUCT.MODIFY', 'la_PermName_Product.Modify_desc', 'In-Commerce', 1);
 INSERT INTO CategoryPermissionsConfig VALUES (DEFAULT, 'PRODUCT.VIEW', 'la_PermName_Product.View_desc', 'In-Commerce', 1);
 
 INSERT INTO Permissions VALUES (DEFAULT, 'PRODUCT.VIEW', 14, 1, 0, {ProductCatId});
 INSERT INTO Permissions VALUES (DEFAULT, 'PRODUCT.RATE', 13, 1, 0, {ProductCatId});
 INSERT INTO Permissions VALUES (DEFAULT, 'PRODUCT.REVIEW', 13, 1, 0, {ProductCatId});
 INSERT INTO Permissions VALUES (DEFAULT, 'PRODUCT.REVIEW.PENDING', 13, 1, 0, {ProductCatId});
 INSERT INTO Permissions VALUES (DEFAULT, 'FAVORITES', 13, 1, 0, {ProductCatId});
 INSERT INTO Permissions VALUES (DEFAULT, 'PRODUCT.VIEW', 13, 1, 0, {ProductCatId});
 INSERT INTO Permissions VALUES (DEFAULT, 'PRODUCT.VIEW', 12, 1, 0, {ProductCatId});
 INSERT INTO Permissions VALUES (DEFAULT, 'PRODUCT.ADD', 11, 1, 0, {ProductCatId});
 INSERT INTO Permissions VALUES (DEFAULT, 'PRODUCT.DELETE', 11, 1, 0, {ProductCatId});
 INSERT INTO Permissions VALUES (DEFAULT, 'PRODUCT.MODIFY', 11, 1, 0, {ProductCatId});
 INSERT INTO Permissions VALUES (DEFAULT, 'PRODUCT.VIEW', 11, 1, 0, {ProductCatId});
 INSERT INTO Permissions VALUES (DEFAULT, 'in-commerce.view', 11, 1, 1, 0);
 INSERT INTO Permissions VALUES (DEFAULT, 'in-commerce:products.view', 11, 1, 1, 0);
 INSERT INTO Permissions VALUES (DEFAULT, 'in-commerce:setting_folder.view', 11, 1, 1, 0);
 INSERT INTO Permissions VALUES (DEFAULT, 'in-commerce:orders.view', 11, 1, 1, 0);
 INSERT INTO Permissions VALUES (DEFAULT, 'in-commerce:orders.add', 11, 1, 1, 0);
 INSERT INTO Permissions VALUES (DEFAULT, 'in-commerce:orders.edit', 11, 1, 1, 0);
 INSERT INTO Permissions VALUES (DEFAULT, 'in-commerce:orders.delete', 11, 1, 1, 0);
 INSERT INTO Permissions VALUES (DEFAULT, 'in-commerce:orders.advanced:approve', 11, 1, 1, 0);
 INSERT INTO Permissions VALUES (DEFAULT, 'in-commerce:orders.advanced:deny', 11, 1, 1, 0);
 INSERT INTO Permissions VALUES (DEFAULT, 'in-commerce:orders.advanced:archive', 11, 1, 1, 0);
 INSERT INTO Permissions VALUES (DEFAULT, 'in-commerce:orders.advanced:place', 11, 1, 1, 0);
 INSERT INTO Permissions VALUES (DEFAULT, 'in-commerce:orders.advanced:process', 11, 1, 1, 0);
 INSERT INTO Permissions VALUES (DEFAULT, 'in-commerce:orders.advanced:ship', 11, 1, 1, 0);
 INSERT INTO Permissions VALUES (DEFAULT, 'in-commerce:orders.advanced:reset_to_pending', 11, 1, 1, 0);
 INSERT INTO Permissions VALUES (DEFAULT, 'in-commerce:discounts.view', 11, 1, 1, 0);
 INSERT INTO Permissions VALUES (DEFAULT, 'in-commerce:discounts.add', 11, 1, 1, 0);
 INSERT INTO Permissions VALUES (DEFAULT, 'in-commerce:discounts.edit', 11, 1, 1, 0);
 INSERT INTO Permissions VALUES (DEFAULT, 'in-commerce:discounts.delete', 11, 1, 1, 0);
 INSERT INTO Permissions VALUES (DEFAULT, 'in-commerce:discounts.advanced:approve', 11, 1, 1, 0);
 INSERT INTO Permissions VALUES (DEFAULT, 'in-commerce:discounts.advanced:decline', 11, 1, 1, 0);
 INSERT INTO Permissions VALUES (DEFAULT, 'in-commerce:coupons.view', 11, 1, 1, 0);
 INSERT INTO Permissions VALUES (DEFAULT, 'in-commerce:coupons.add', 11, 1, 1, 0);
 INSERT INTO Permissions VALUES (DEFAULT, 'in-commerce:coupons.edit', 11, 1, 1, 0);
 INSERT INTO Permissions VALUES (DEFAULT, 'in-commerce:coupons.delete', 11, 1, 1, 0);
 INSERT INTO Permissions VALUES (DEFAULT, 'in-commerce:coupons.advanced:approve', 11, 1, 1, 0);
 INSERT INTO Permissions VALUES (DEFAULT, 'in-commerce:coupons.advanced:decline', 11, 1, 1, 0);
 INSERT INTO Permissions VALUES (DEFAULT, 'in-commerce:manufacturers.view', 11, 1, 1, 0);
 INSERT INTO Permissions VALUES (DEFAULT, 'in-commerce:manufacturers.add', 11, 1, 1, 0);
 INSERT INTO Permissions VALUES (DEFAULT, 'in-commerce:manufacturers.edit', 11, 1, 1, 0);
 INSERT INTO Permissions VALUES (DEFAULT, 'in-commerce:manufacturers.delete', 11, 1, 1, 0);
 INSERT INTO Permissions VALUES (DEFAULT, 'in-commerce:currencies.view', 11, 1, 1, 0);
 INSERT INTO Permissions VALUES (DEFAULT, 'in-commerce:currencies.add', 11, 1, 1, 0);
 INSERT INTO Permissions VALUES (DEFAULT, 'in-commerce:currencies.edit', 11, 1, 1, 0);
 INSERT INTO Permissions VALUES (DEFAULT, 'in-commerce:currencies.delete', 11, 1, 1, 0);
 INSERT INTO Permissions VALUES (DEFAULT, 'in-commerce:currencies.advanced:move_up', 11, 1, 1, 0);
 INSERT INTO Permissions VALUES (DEFAULT, 'in-commerce:currencies.advanced:move_down', 11, 1, 1, 0);
 INSERT INTO Permissions VALUES (DEFAULT, 'in-commerce:currencies.advanced:update_rate', 11, 1, 1, 0);
 INSERT INTO Permissions VALUES (DEFAULT, 'in-commerce:currencies.advanced:set_primary', 11, 1, 1, 0);
 INSERT INTO Permissions VALUES (DEFAULT, 'in-commerce:shipping.view', 11, 1, 1, 0);
 INSERT INTO Permissions VALUES (DEFAULT, 'in-commerce:shipping.add', 11, 1, 1, 0);
 INSERT INTO Permissions VALUES (DEFAULT, 'in-commerce:shipping.edit', 11, 1, 1, 0);
 INSERT INTO Permissions VALUES (DEFAULT, 'in-commerce:shipping.delete', 11, 1, 1, 0);
 INSERT INTO Permissions VALUES (DEFAULT, 'in-commerce:shipping.advanced:approve', 11, 1, 1, 0);
 INSERT INTO Permissions VALUES (DEFAULT, 'in-commerce:shipping.advanced:decline', 11, 1, 1, 0);
 INSERT INTO Permissions VALUES (DEFAULT, 'in-commerce:shipping_quote_engines.view', 11, 1, 1, 0);
 INSERT INTO Permissions VALUES (DEFAULT, 'in-commerce:shipping_quote_engines.edit', 11, 1, 1, 0);
 INSERT INTO Permissions VALUES (DEFAULT, 'in-commerce:shipping_quote_engines.advanced:approve', 11, 1, 1, 0);
 INSERT INTO Permissions VALUES (DEFAULT, 'in-commerce:shipping_quote_engines.advanced:decline', 11, 1, 1, 0);
 INSERT INTO Permissions VALUES (DEFAULT, 'in-commerce:payment_types.view', 11, 1, 1, 0);
 INSERT INTO Permissions VALUES (DEFAULT, 'in-commerce:payment_types.add', 11, 1, 1, 0);
 INSERT INTO Permissions VALUES (DEFAULT, 'in-commerce:payment_types.edit', 11, 1, 1, 0);
 INSERT INTO Permissions VALUES (DEFAULT, 'in-commerce:payment_types.delete', 11, 1, 1, 0);
 INSERT INTO Permissions VALUES (DEFAULT, 'in-commerce:taxes.view', 11, 1, 1, 0);
 INSERT INTO Permissions VALUES (DEFAULT, 'in-commerce:taxes.add', 11, 1, 1, 0);
 INSERT INTO Permissions VALUES (DEFAULT, 'in-commerce:taxes.edit', 11, 1, 1, 0);
 INSERT INTO Permissions VALUES (DEFAULT, 'in-commerce:taxes.delete', 11, 1, 1, 0);
 INSERT INTO Permissions VALUES (DEFAULT, 'in-commerce:affiliates.view', 11, 1, 1, 0);
 INSERT INTO Permissions VALUES (DEFAULT, 'in-commerce:affiliates.add', 11, 1, 1, 0);
 INSERT INTO Permissions VALUES (DEFAULT, 'in-commerce:affiliates.edit', 11, 1, 1, 0);
 INSERT INTO Permissions VALUES (DEFAULT, 'in-commerce:affiliates.delete', 11, 1, 1, 0);
 INSERT INTO Permissions VALUES (DEFAULT, 'in-commerce:affiliates.advanced:approve', 11, 1, 1, 0);
 INSERT INTO Permissions VALUES (DEFAULT, 'in-commerce:affiliates.advanced:decline', 11, 1, 1, 0);
 INSERT INTO Permissions VALUES (DEFAULT, 'in-commerce:affiliate_plans.view', 11, 1, 1, 0);
 INSERT INTO Permissions VALUES (DEFAULT, 'in-commerce:affiliate_plans.add', 11, 1, 1, 0);
 INSERT INTO Permissions VALUES (DEFAULT, 'in-commerce:affiliate_plans.edit', 11, 1, 1, 0);
 INSERT INTO Permissions VALUES (DEFAULT, 'in-commerce:affiliate_plans.delete', 11, 1, 1, 0);
 INSERT INTO Permissions VALUES (DEFAULT, 'in-commerce:affiliate_plans.advanced:approve', 11, 1, 1, 0);
 INSERT INTO Permissions VALUES (DEFAULT, 'in-commerce:affiliate_plans.advanced:decline', 11, 1, 1, 0);
 INSERT INTO Permissions VALUES (DEFAULT, 'in-commerce:affiliate_plans.advanced:set_primary', 11, 1, 1, 0);
 INSERT INTO Permissions VALUES (DEFAULT, 'in-commerce:affiliate_payment_types.view', 11, 1, 1, 0);
 INSERT INTO Permissions VALUES (DEFAULT, 'in-commerce:affiliate_payment_types.add', 11, 1, 1, 0);
 INSERT INTO Permissions VALUES (DEFAULT, 'in-commerce:affiliate_payment_types.edit', 11, 1, 1, 0);
 INSERT INTO Permissions VALUES (DEFAULT, 'in-commerce:affiliate_payment_types.delete', 11, 1, 1, 0);
 INSERT INTO Permissions VALUES (DEFAULT, 'in-commerce:affiliate_payment_types.advanced:approve', 11, 1, 1, 0);
 INSERT INTO Permissions VALUES (DEFAULT, 'in-commerce:affiliate_payment_types.advanced:decline', 11, 1, 1, 0);
 INSERT INTO Permissions VALUES (DEFAULT, 'in-commerce:affiliate_payment_types.advanced:set_primary', 11, 1, 1, 0);
 INSERT INTO Permissions VALUES (DEFAULT, 'in-commerce:affiliate_payment_types.advanced:move_up', 11, 1, 1, 0);
 INSERT INTO Permissions VALUES (DEFAULT, 'in-commerce:affiliate_payment_types.advanced:move_down', 11, 1, 1, 0);
 INSERT INTO Permissions VALUES (DEFAULT, 'in-commerce:general.view', 11, 1, 1, 0);
 INSERT INTO Permissions VALUES (DEFAULT, 'in-commerce:general.add', 11, 1, 1, 0);
 INSERT INTO Permissions VALUES (DEFAULT, 'in-commerce:general.edit', 11, 1, 1, 0);
 INSERT INTO Permissions VALUES (DEFAULT, 'in-commerce:output.view', 11, 1, 1, 0);
 INSERT INTO Permissions VALUES (DEFAULT, 'in-commerce:output.add', 11, 1, 1, 0);
 INSERT INTO Permissions VALUES (DEFAULT, 'in-commerce:output.edit', 11, 1, 1, 0);
 INSERT INTO Permissions VALUES (DEFAULT, 'in-commerce:search.view', 11, 1, 1, 0);
 INSERT INTO Permissions VALUES (DEFAULT, 'in-commerce:search.edit', 11, 1, 1, 0);
 INSERT INTO Permissions VALUES (DEFAULT, 'in-commerce:contacts.view', 11, 1, 1, 0);
 INSERT INTO Permissions VALUES (DEFAULT, 'in-commerce:contacts.add', 11, 1, 1, 0);
 INSERT INTO Permissions VALUES (DEFAULT, 'in-commerce:contacts.edit', 11, 1, 1, 0);
 INSERT INTO Permissions VALUES (DEFAULT, 'in-commerce:configuration_custom.view', 11, 1, 1, 0);
 INSERT INTO Permissions VALUES (DEFAULT, 'in-commerce:configuration_custom.add', 11, 1, 1, 0);
 INSERT INTO Permissions VALUES (DEFAULT, 'in-commerce:configuration_custom.edit', 11, 1, 1, 0);
 INSERT INTO Permissions VALUES (DEFAULT, 'in-commerce:configuration_custom.delete', 11, 1, 1, 0);
 INSERT INTO Permissions VALUES (DEFAULT, 'in-commerce:paymentlog.view', 11, 1, 1, 0);
 INSERT INTO Permissions VALUES (DEFAULT, 'in-commerce:downloadlog.view', 11, 1, 1, 0);
 INSERT INTO Permissions VALUES (DEFAULT, 'in-commerce:downloadlog.delete', 11, 1, 1, 0);
 INSERT INTO Permissions VALUES (DEFAULT, 'in-commerce:gift-certificates.view', 11, 1, 1, 0);
 INSERT INTO Permissions VALUES (DEFAULT, 'in-commerce:gift-certificates.add', 11, 1, 1, 0);
 INSERT INTO Permissions VALUES (DEFAULT, 'in-commerce:gift-certificates.edit', 11, 1, 1, 0);
 INSERT INTO Permissions VALUES (DEFAULT, 'in-commerce:gift-certificates.delete', 11, 1, 1, 0);
 INSERT INTO Permissions VALUES (DEFAULT, 'in-commerce:gift-certificates.advanced:approve', 11, 1, 1, 0);
 INSERT INTO Permissions VALUES (DEFAULT, 'in-commerce:gift-certificates.advanced:decline', 11, 1, 1, 0);
 INSERT INTO Permissions VALUES (DEFAULT, 'in-commerce:reports.view', 11, 1, 1, 0);
 INSERT INTO Permissions VALUES (DEFAULT, 'in-commerce:reports.add', 11, 1, 1, 0);
 
 INSERT INTO SearchConfig VALUES ('Products', 'OrgId', 0, 0, 'lu_fielddesc_prod_orgid', 'lc_field_orgid', 'In-Commerce', 'la_Text_Products', 19, DEFAULT, 0, 'text', NULL, NULL, NULL, NULL, NULL, NULL, NULL);
 INSERT INTO SearchConfig VALUES ('Products', 'NewItem', 0, 1, 'lu_fielddesc_prod_newitem', 'lu_field_newproduct', 'In-Commerce', 'la_Text_Products', 18, DEFAULT, 0, 'boolean', NULL, NULL, NULL, NULL, NULL, NULL, NULL);
 INSERT INTO SearchConfig VALUES ('Products', 'PopItem', 0, 1, 'lu_fielddesc_prod_popitem', 'lu_field_popproduct', 'In-Commerce', 'la_Text_Products', 17, DEFAULT, 0, 'boolean', NULL, NULL, NULL, NULL, NULL, NULL, NULL);
 INSERT INTO SearchConfig VALUES ('Products', 'HotItem', 0, 1, 'lu_fielddesc_prod_topseller', 'lc_field_topseller', 'In-Commerce', 'la_Text_Products', 16, DEFAULT, 0, 'boolean', NULL, NULL, NULL, NULL, NULL, NULL, NULL);
 INSERT INTO SearchConfig VALUES ('Products', 'EditorsPick', 0, 1, 'lu_fielddesc_prod_editorspick', 'lc_field_EditorsPick', 'In-Commerce', 'la_Text_Products', 14, DEFAULT, 0, 'boolean', NULL, NULL, NULL, NULL, NULL, NULL, NULL);
 INSERT INTO SearchConfig VALUES ('Products', 'CachedReviewsQty', 0, 0, 'lu_fielddesc_prod_cachedreviewsqty', 'lc_field_cachedreviewsqty', 'In-Commerce', 'la_Text_Products', 9, DEFAULT, 0, 'range', NULL, NULL, NULL, NULL, NULL, NULL, NULL);
 INSERT INTO SearchConfig VALUES ('Products', 'CachedVotesQty', 0, 0, 'lu_fielddesc_prod_cachedvotesqty', 'lc_field_cachedvotesqty', 'In-Commerce', 'la_Text_Products', 8, DEFAULT, 0, 'range', NULL, NULL, NULL, NULL, NULL, NULL, NULL);
 INSERT INTO SearchConfig VALUES ('Products', 'ProductId', 0, 0, 'lu_fielddesc_prod_productid', 'lu_field_productid', 'In-Commerce', 'la_Text_Products', 0, DEFAULT, 0, 'text', NULL, NULL, NULL, NULL, NULL, NULL, NULL);
 INSERT INTO SearchConfig VALUES ('Products', 'Name', 1, 1, 'lu_fielddesc_prod_producttitle', 'lu_field_producttitle', 'In-Commerce', 'la_Text_Products', 1, DEFAULT, 3, 'text', NULL, NULL, NULL, NULL, NULL, NULL, NULL);
 INSERT INTO SearchConfig VALUES ('Products', 'Description', 1, 1, 'lu_fielddesc_prod_description', 'lc_field_description', 'In-Commerce', 'la_Text_Products', 2, DEFAULT, 1, 'text', NULL, NULL, NULL, NULL, NULL, NULL, NULL);
 INSERT INTO SearchConfig VALUES ('Products', 'CreatedOn', 0, 1, 'lu_fielddesc_prod_createdon', 'lc_field_createdon', 'In-Commerce', 'la_Text_Products', 4, DEFAULT, 0, 'date', NULL, NULL, NULL, NULL, NULL, NULL, NULL);
 INSERT INTO SearchConfig VALUES ('Products', 'Modified', 0, 1, 'lu_fielddesc_prod_modified', 'lc_field_modified', 'In-Commerce', 'la_Text_Products', 5, DEFAULT, 0, 'date', NULL, NULL, NULL, NULL, NULL, NULL, NULL);
 INSERT INTO SearchConfig VALUES ('Products', 'Hits', 0, 1, 'lu_fielddesc_prod_qtysold', 'lc_field_qtysold', 'In-Commerce', 'la_Text_Products', 6, DEFAULT, 0, 'range', NULL, NULL, NULL, NULL, NULL, NULL, NULL);
 INSERT INTO SearchConfig VALUES ('Products', 'CachedRating', 0, 0, 'lu_fielddesc_prod_cachedrating', 'lc_field_cachedrating', 'In-Commerce', 'la_Text_Products', 7, DEFAULT, 0, 'range', NULL, NULL, NULL, NULL, NULL, NULL, NULL);
 INSERT INTO SearchConfig VALUES ('CustomFields', 'Features', 1, 0, 'la_Features', 'la_Features', 'In-Commerce', 'la_Text_CustomFields', 0, DEFAULT, 0, 'text', NULL, NULL, NULL, NULL, NULL, NULL, NULL);
 INSERT INTO SearchConfig VALUES ('Products', 'SKU', 1, 1, 'lu_fielddesc_prod_sku', 'lu_field_sku', 'In-Commerce', 'la_Text_Products', 0, DEFAULT, 0, 'text', NULL, NULL, NULL, NULL, NULL, NULL, NULL);
 INSERT INTO SearchConfig VALUES ('Products', 'DescriptionExcerpt', 1, 0, 'lu_fielddesc_prod_descriptionex', 'lc_field_descriptionex', 'In-Commerce', 'la_Text_Products', 2, DEFAULT, 1, 'text', NULL, NULL, NULL, NULL, NULL, NULL, NULL);
 INSERT INTO SearchConfig VALUES ('Products', 'ManufacturerId', 1, 1, 'lu_fielddesc_prod_manufacturer', 'lc_field_manufacturer', 'In-Commerce', 'la_Text_Products', 3, DEFAULT, 2, 'text', 'Manufacturers.Name', '{ForeignTable}.ManufacturerId={LocalTable}.ManufacturerId', NULL, NULL, NULL, NULL, NULL);
 INSERT INTO SearchConfig VALUES ('Products', 'Price', 1, 1, 'lu_fielddesc_prod_price', 'lu_field_price', 'In-Commerce', 'la_Text_Products', 23, DEFAULT, 2, 'range', 'CALC:MIN( IF({PREFIX}ProductsDiscounts.Type = 1, {PREFIX}ProductsPricing.Price - {PREFIX}ProductsDiscounts.Amount, IF({PREFIX}ProductsDiscounts.Type = 2, ({PREFIX}ProductsPricing.Price * (1-{PREFIX}ProductsDiscounts.Amount/100)), {PREFIX}ProductsPricing.Price ) ) )', '{PREFIX}ProductsPricing ON {PREFIX}ProductsPricing.ProductId = {PREFIX}Products.ProductId AND {PREFIX}ProductsPricing.IsPrimary = 1 LEFT JOIN {PREFIX}ProductsDiscountItems ON {PREFIX}ProductsDiscountItems.ItemResourceId = {PREFIX}Products.ResourceId LEFT JOIN {PREFIX}ProductsDiscounts ON {PREFIX}ProductsDiscounts.DiscountId = {PREFIX}ProductsDiscountItems.DiscountId AND {PREFIX}ProductsDiscounts.Status = 1 AND {PREFIX}ProductsDiscountItems.ItemType = 1 AND ( {PREFIX}ProductsDiscounts.GroupId IN ({USER_GROUPS},NULL) AND ( ({PREFIX}ProductsDiscounts.Start IS NULL OR {PREFIX}ProductsDiscounts.Start < UNIX_TIMESTAMP()) AND ({PREFIX}ProductsDiscounts.Start IS NULL OR {PREFIX}ProductsDiscounts.End > UNIX_TIMESTAMP()) ) )', NULL, NULL, NULL, NULL, NULL);
 INSERT INTO SearchConfig VALUES ('CustomFields', 'Availability', 0, 0, 'la_Availability', 'la_Availability', 'In-Commerce', 'la_Text_CustomFields', 0, DEFAULT, 0, 'text', NULL, NULL, NULL, NULL, NULL, NULL, NULL);
 
 INSERT INTO ShippingQuoteEngines VALUES (1, 'Intershipper.com', 0, 0, 0, 'a:21:{s:12:"AccountLogin";N;s:15:"AccountPassword";s:0:"";s:10:"UPSEnabled";i:1;s:10:"UPSAccount";N;s:11:"UPSInvoiced";N;s:10:"FDXEnabled";i:1;s:10:"FDXAccount";N;s:10:"DHLEnabled";i:1;s:10:"DHLAccount";N;s:11:"DHLInvoiced";i:0;s:10:"USPEnabled";i:1;s:10:"USPAccount";N;s:11:"USPInvoiced";i:0;s:10:"ARBEnabled";i:1;s:10:"ARBAccount";N;s:11:"ARBInvoiced";N;s:10:"1DYEnabled";i:1;s:10:"2DYEnabled";i:1;s:10:"3DYEnabled";i:1;s:10:"GNDEnabled";i:1;s:10:"ShipMethod";s:3:"DRP";}', 'Intershipper');
 INSERT INTO ShippingQuoteEngines VALUES ( DEFAULT, 'USPS.com', 0, 0, 0, 'a:21:{s:12:"AccountLogin";s:0:"";s:15:"AccountPassword";N;s:10:"UPSEnabled";N;s:10:"UPSAccount";s:0:"";s:11:"UPSInvoiced";N;s:10:"FDXEnabled";N;s:10:"FDXAccount";s:0:"";s:10:"DHLEnabled";N;s:10:"DHLAccount";s:0:"";s:11:"DHLInvoiced";N;s:10:"USPEnabled";N;s:10:"USPAccount";s:0:"";s:11:"USPInvoiced";N;s:10:"ARBEnabled";N;s:10:"ARBAccount";s:0:"";s:11:"ARBInvoiced";N;s:10:"1DYEnabled";N;s:10:"2DYEnabled";N;s:10:"3DYEnabled";N;s:10:"GNDEnabled";N;s:10:"ShipMethod";N;}', 'USPS' ) ;
 
 DELETE FROM SystemCache WHERE VarName = 'config_files';
 
 INSERT INTO ImportScripts VALUES (DEFAULT, 'Products from CSV file [In-Commerce]', '', 'p', 'In-Commerce', '', 'CSV', '1');
 
 INSERT INTO ItemFilters VALUES
 	(DEFAULT, 'p', 'ManufacturerId', 'checkbox', 1, NULL),
 	(DEFAULT, 'p', 'Price', 'range', 1, 10),
 	(DEFAULT, 'p', 'EditorsPick', 'radio', 1, NULL);
 
 INSERT INTO Modules VALUES ('In-Commerce', 'modules/in-commerce/', 'p', DEFAULT, 1, 4, 'in-commerce/', 2, NULL, NULL);
Index: branches/5.3.x
===================================================================
--- branches/5.3.x	(revision 15670)
+++ branches/5.3.x	(revision 15671)

Property changes on: branches/5.3.x
___________________________________________________________________
Added: svn:ignore
## -0,0 +1,2 ##
+.idea
+atlassian-ide-plugin.xml
Modified: svn:mergeinfo
## -0,0 +0,2 ##
   Merged /w/in-commerce/releases/5.2.1-B1:r15631-15670
   Merged /w/in-commerce/branches/5.2.x:r15492-15630