Index: branches/5.2.x/units/product_options/product_options_helper.php =================================================================== diff -u -N -r13845 -r14099 --- branches/5.2.x/units/product_options/product_options_helper.php (.../product_options_helper.php) (revision 13845) +++ branches/5.2.x/units/product_options/product_options_helper.php (.../product_options_helper.php) (revision 14099) @@ -1,6 +1,6 @@ Application->GetTempName($table, 'prefix:p'); $sql = 'SELECT * FROM '.$table.' WHERE ProductId = '.$product_id; - $conn =& $this->Application->GetADODBConnection(); - $mapping[$product_id] = $conn->Query($sql, 'ProductOptionId'); + + $mapping[$product_id] = $this->Conn->Query($sql, 'ProductOptionId'); } + return $mapping[$product_id][$key]; } Index: branches/5.2.x/units/files/files_config.php =================================================================== diff -u -N -r14089 -r14099 --- branches/5.2.x/units/files/files_config.php (.../files_config.php) (revision 14089) +++ branches/5.2.x/units/files/files_config.php (.../files_config.php) (revision 14099) @@ -1,6 +1,6 @@ true, 'AutoClone' => true, - 'ListSQLs' => Array ( - '' => 'SELECT * FROM %s', - ), // key - special, value - list select sql + 'ListSQLs' => Array ( '' => 'SELECT * FROM %s'), + 'ItemSQLs' => Array ( '' => 'SELECT * FROM %s'), - 'ItemSQLs' => Array ( - '' => 'SELECT * FROM %s', - ), - 'ListSortings' => Array ( '' => Array ( 'ForcedSorting' => Array ('IsPrimary' => 'desc', 'Priority' => 'desc'), Index: branches/5.2.x/units/product_option_combinations/product_option_combinations_event_handler.php =================================================================== diff -u -N -r13845 -r14099 --- branches/5.2.x/units/product_option_combinations/product_option_combinations_event_handler.php (.../product_option_combinations_event_handler.php) (revision 13845) +++ branches/5.2.x/units/product_option_combinations/product_option_combinations_event_handler.php (.../product_option_combinations_event_handler.php) (revision 14099) @@ -1,6 +1,6 @@ getObject(); + /* @var $object kDBItem */ $salt = $fields['Combination']; ksort($salt); $object->Load(crc32(serialize($salt)), 'CombinationCRC'); $object->SetFieldsFromHash($fields); $this->customProcessing($event,'before'); - if ($object->Loaded) { // Update if such combination already exists + if ( $object->isLoaded() ) { // Update if such combination already exists if( $object->Update() ) { $this->customProcessing($event,'after'); - $event->status=erSUCCESS; + $event->status=kEvent::erSUCCESS; } } else { if( $object->Create($event->getEventParam('ForceCreateId')) ) { $this->customProcessing($event,'after'); - $event->status=erSUCCESS; + $event->status=kEvent::erSUCCESS; } } } @@ -127,12 +128,14 @@ if (!$recursed) { $object =& $event->getObject(); + /* @var $object kDBItem */ + $edit_id = $object->GetId(); $salt = $fields['Combination']; ksort($salt); // try to load combination by salt - if loaded, it will update the combination $object->Load(crc32(serialize($salt)), 'CombinationCRC'); - if (!$object->Loaded) { + if ( !$object->isLoaded() ) { $object->Load($edit_id); } $object->SetFieldsFromHash($fields); @@ -141,11 +144,16 @@ if( $object->Update() ) { $this->customProcessing($event,'after'); - $event->status=erSUCCESS; + $event->status=kEvent::erSUCCESS; } } } + /** + * Enter description here... + * + * @param kEvent $event + */ function OnCreate(&$event) { $object =& $event->getObject( Array('skip_autoload' => true) ); @@ -156,9 +164,9 @@ list($id,$field_values) = each($items_info); $object->SetFieldsFromHash($field_values); if (!$object->Validate()) { - $event->status = erFAIL; + $event->status = kEvent::erFAIL; $event->redirect = false; - $this->Application->SetVar($event->Prefix_Special.'_SaveEvent','OnCreate'); + $this->Application->SetVar($event->getPrefixSpecial().'_SaveEvent','OnCreate'); $object->setID($id); return; } @@ -180,7 +188,7 @@ $object->SetFieldsFromHash($field_values); if (!$object->Validate()) { - $event->status = erFAIL; + $event->status = kEvent::erFAIL; $event->redirect = false; return; } @@ -190,11 +198,11 @@ if( $object->Update($id) ) { $this->customProcessing($event, 'after'); - $event->status=erSUCCESS; + $event->status=kEvent::erSUCCESS; } else { - $event->status=erFAIL; + $event->status=kEvent::erFAIL; $event->redirect=false; break; }*/ @@ -225,9 +233,9 @@ if($auto_load && !$skip_autload) $this->LoadItem($event); $actions =& $this->Application->recallObject('kActions'); - $actions->Set($event->Prefix_Special.'_GoTab', ''); + $actions->Set($event->getPrefixSpecial().'_GoTab', ''); - $actions->Set($event->Prefix_Special.'_GoId', ''); + $actions->Set($event->getPrefixSpecial().'_GoId', ''); } function LoadItem(&$event) @@ -241,7 +249,7 @@ if ($object->Load($id) ) { $actions =& $this->Application->recallObject('kActions'); - $actions->Set($event->Prefix_Special.'_id', $object->GetId() ); + $actions->Set($event->getPrefixSpecial().'_id', $object->GetId() ); } else { @@ -315,14 +323,18 @@ if ($this->Conn->GetOne($sql) == 2) { $live_object =& $this->Application->recallObject($event->Prefix.'.itemlive', null, Array('skip_autoload' => true)); + /* @var $live_object kDBItem */ + $live_object->SwitchToLive(); $live_object->Load($id); $temp_object =& $this->Application->recallObject($event->Prefix.'.itemtemp', null, Array('skip_autoload' => true)); + /* @var $temp_object kDBItem */ + $temp_object->SwitchToTemp(); $temp_object->Load($id); - $temp_object->SetDBFieldsFromHash($live_object->FieldValues, Array('QtyInStock','QtyReserved','QtyBackOrdered','QtyOnOrder')); + $temp_object->SetDBFieldsFromHash($live_object->GetFieldValues(), Array('QtyInStock','QtyReserved','QtyBackOrdered','QtyOnOrder')); $temp_object->Update(); } } Index: branches/5.2.x/units/shipping_quote_engines/shipping_quote_engine.php =================================================================== diff -u -N -r14089 -r14099 --- branches/5.2.x/units/shipping_quote_engines/shipping_quote_engine.php (.../shipping_quote_engine.php) (revision 14089) +++ branches/5.2.x/units/shipping_quote_engines/shipping_quote_engine.php (.../shipping_quote_engine.php) (revision 14099) @@ -1,6 +1,6 @@ initProperties(); } Index: branches/5.2.x/units/shipping/shipping_event_handler.php =================================================================== diff -u -N -r14089 -r14099 --- branches/5.2.x/units/shipping/shipping_event_handler.php (.../shipping_event_handler.php) (revision 14089) +++ branches/5.2.x/units/shipping/shipping_event_handler.php (.../shipping_event_handler.php) (revision 14099) @@ -1,6 +1,6 @@ OnPreSave($event); - $event->status=erSUCCESS; + $event->status=kEvent::erSUCCESS; } function OnSave(&$event) Index: branches/5.2.x/units/reports/reports_event_handler.php =================================================================== diff -u -N -r13845 -r14099 --- branches/5.2.x/units/reports/reports_event_handler.php (.../reports_event_handler.php) (revision 13845) +++ branches/5.2.x/units/reports/reports_event_handler.php (.../reports_event_handler.php) (revision 14099) @@ -1,6 +1,6 @@ Application->recallObject($object->Fields[$search_field]['formatter']); + $formatter =& $this->Application->recallObject( $object->GetFieldOption($search_field, 'formatter') ); $value_ts = $formatter->Parse($full_value, $search_field, $object); - $pseudo = getArrayValue($object->FieldErrors, $search_field, 'pseudo'); - if ($pseudo) { - unset($object->FieldErrors[$search_field]); // remove error! + + if ( $object->GetErrorPseudo($search_field) ) { // invalid format -> ignore this date in search + $object->RemoveError($search_field); + return false; } return $value_ts; @@ -672,7 +673,7 @@ $chart->setTitle($this->Application->RecallVar('graph_metric')); $chart->render(); - $event->status = erSTOP; + $event->status = kEvent::erSTOP; } /** Generates png-chart output @@ -734,7 +735,7 @@ $Plot->setGraphCaptionRatio(0.7); $chart->render(); - $event->status = erSTOP; + $event->status = kEvent::erSTOP; } Index: branches/5.2.x/units/gateways/gw_classes/rightconnect.php =================================================================== diff -u -N -r13845 -r14099 --- branches/5.2.x/units/gateways/gw_classes/rightconnect.php (.../rightconnect.php) (revision 13845) +++ branches/5.2.x/units/gateways/gw_classes/rightconnect.php (.../rightconnect.php) (revision 14099) @@ -1,6 +1,6 @@ Application->ConfigValue('Smtp_AdminMailFrom'); - $this->gw_responce = curl_post($gw_params['submit_url'], $post_fields); + $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'] @@ -208,7 +213,7 @@ unset($gw_responce[$field_index]); } $this->parsed_responce = $ret; - return array_merge_recursive2($ret, $gw_responce); // returns unparsed fields with they original indexes together with parsed ones + return kUtil::array_merge_recursive($ret, $gw_responce); // returns unparsed fields with they original indexes together with parsed ones } function getGWResponce() Index: branches/5.2.x/units/addresses/addresses_event_handler.php =================================================================== diff -u -N -r13845 -r14099 --- branches/5.2.x/units/addresses/addresses_event_handler.php (.../addresses_event_handler.php) (revision 13845) +++ branches/5.2.x/units/addresses/addresses_event_handler.php (.../addresses_event_handler.php) (revision 14099) @@ -1,6 +1,6 @@ isLoaded() || !$this->checkItemStatus($event)) { // not trivially loaded object OR not current user address - $event->status = erPERM_FAIL; + $event->status = kEvent::erPERM_FAIL; return ; } @@ -288,7 +288,7 @@ function OnBeforeItemCreate(&$event) { if (!$this->Application->LoggedIn()) { - $event->status = erPERM_FAIL; + $event->status = kEvent::erPERM_FAIL; return ; } @@ -314,7 +314,7 @@ if (!$object->isLoaded() || !$this->checkItemStatus($event)) { // not trivially loaded object OR not current user address - $event->status = erPERM_FAIL; + $event->status = kEvent::erPERM_FAIL; return ; } } Index: branches/5.2.x/install/upgrades.php =================================================================== diff -u -N -r14089 -r14099 --- branches/5.2.x/install/upgrades.php (.../upgrades.php) (revision 14089) +++ branches/5.2.x/install/upgrades.php (.../upgrades.php) (revision 14099) @@ -1,6 +1,6 @@ dependencies = Array ( '4.3.9' => Array ('Core' => '4.3.9'), Index: branches/5.2.x/units/reports/reports_tag_processor.php =================================================================== diff -u -N -r13845 -r14099 --- branches/5.2.x/units/reports/reports_tag_processor.php (.../reports_tag_processor.php) (revision 13845) +++ branches/5.2.x/units/reports/reports_tag_processor.php (.../reports_tag_processor.php) (revision 14099) @@ -1,6 +1,6 @@ Application->recallObject('rep.params', null, Array('skip_autoload' => true)); - $object->ID = 1; + /* @var $object kDBItem */ + + $object->setID(1); $object->SetDBField('Metric', $metric); // echo '
';
Index: branches/5.2.x/units/affiliate_plans_brackets/affiliate_plans_brackets_tag_processor.php
===================================================================
diff -u -N -r13845 -r14099
--- branches/5.2.x/units/affiliate_plans_brackets/affiliate_plans_brackets_tag_processor.php	(.../affiliate_plans_brackets_tag_processor.php)	(revision 13845)
+++ branches/5.2.x/units/affiliate_plans_brackets/affiliate_plans_brackets_tag_processor.php	(.../affiliate_plans_brackets_tag_processor.php)	(revision 14099)
@@ -1,6 +1,6 @@
 Application->recallObject( $this->getPrefixSpecial() );
+			/* @var $br_object kDBItem */
 
 			$br_data = $this->Application->GetVar( $this->getPrefixSpecial(true) );
 			$linked_info = $br_object->getLinkedInfo($this->Special);
@@ -62,7 +63,7 @@
 
 				$main_object =& $this->Application->recallObject($linked_info['ParentPrefix'].'.'.$this->Special);
 				$plan_type = $main_object->GetDBField('PlanType');
-				$limits_format = ($plan_type == 2) ? '%d' : $br_object->Fields['FromAmount']['format'];
+				$limits_format = ($plan_type == 2) ? '%d' : $br_object->GetFieldOption('FromAmount', 'format');
 
 				// this is needed to find next id
 				$br_data_copy = $br_data;
Index: branches/5.2.x/units/shipping/shipping_tag_processor.php
===================================================================
diff -u -N -r13845 -r14099
--- branches/5.2.x/units/shipping/shipping_tag_processor.php	(.../shipping_tag_processor.php)	(revision 13845)
+++ branches/5.2.x/units/shipping/shipping_tag_processor.php	(.../shipping_tag_processor.php)	(revision 14099)
@@ -1,6 +1,6 @@
 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';
@@ -114,7 +117,7 @@
 
 				if($res == false)
 				{
-					$costs_object->SetDefaultValues();
+					$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 );
Index: branches/5.2.x/units/gateways/gw_classes/paypal_direct.php
===================================================================
diff -u -N -r13845 -r14099
--- branches/5.2.x/units/gateways/gw_classes/paypal_direct.php	(.../paypal_direct.php)	(revision 13845)
+++ branches/5.2.x/units/gateways/gw_classes/paypal_direct.php	(.../paypal_direct.php)	(revision 14099)
@@ -1,6 +1,6 @@
 ';
 //			print_r($post_fields);
 //			exit;
-			$this->gw_responce = curl_post($gw_params['submit_url'], $post_fields);
+
+			$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);
@@ -169,7 +175,11 @@
 
 				if( $this->IsTestMode() ) $post_fields['x_test_request'] = 'True';
 
-				$this->gw_responce = curl_post($gw_params['submit_url'], $post_fields);
+				$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']
Index: branches/5.2.x/units/gateways/gw_classes/worldpay.php
===================================================================
diff -u -N -r13845 -r14099
--- branches/5.2.x/units/gateways/gw_classes/worldpay.php	(.../worldpay.php)	(revision 13845)
+++ branches/5.2.x/units/gateways/gw_classes/worldpay.php	(.../worldpay.php)	(revision 14099)
@@ -1,6 +1,6 @@
 Application->GetVar('transStatus') == 'Y' ? 1 : 0;
-			echo curl_post($this->Application->GetVar($transaction_status ? 'MC_return_page' : 'MC_cancel_return_page'), '', null, 'GET');
 
+    		$curl_helper =& $this->Application->recallObject('CurlHelper');
+			/* @var $curl_helper kCurlHelper */
+
+			$url = $this->Application->GetVar($transaction_status ? 'MC_return_page' : 'MC_cancel_return_page');
+			echo $curl_helper->Send($url);
+
     		return $transaction_status;
 		}
 	}
\ No newline at end of file
Index: branches/5.2.x/units/files/files.php
===================================================================
diff -u -N -r13845 -r14099
--- branches/5.2.x/units/files/files.php	(.../files.php)	(revision 13845)
+++ branches/5.2.x/units/files/files.php	(.../files.php)	(revision 14099)
@@ -1,6 +1,6 @@
 Load($id);
 			$upload_dir = $this->Fields['FilePath']['upload_dir'];
Index: branches/5.2.x/units/orders/orders_config.php
===================================================================
diff -u -N -r14089 -r14099
--- branches/5.2.x/units/orders/orders_config.php	(.../orders_config.php)	(revision 14089)
+++ branches/5.2.x/units/orders/orders_config.php	(.../orders_config.php)	(revision 14099)
@@ -1,6 +1,6 @@
 	Array ('class' => 'OrdersTagProcessor', 'file' => 'orders_tag_processor.php', 'build_event' => 'OnBuild'),
 					'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' => ''),
+					),
+
 					'Hooks'				=>	Array (
 						Array (
 							'Mode' => hAFTER,
Index: branches/5.2.x/units/pricing/pricing_event_handler.php
===================================================================
diff -u -N -r13845 -r14099
--- branches/5.2.x/units/pricing/pricing_event_handler.php	(.../pricing_event_handler.php)	(revision 13845)
+++ branches/5.2.x/units/pricing/pricing_event_handler.php	(.../pricing_event_handler.php)	(revision 14099)
@@ -1,6 +1,6 @@
 Application->GetVar('pr_tang'))
 		{
 			$object =& $event->GetObject();
+			/* @var $object kDBItem */
 
 			$group_id = $this->Application->getVar('group_id');
 			if($group_id>0){
@@ -180,7 +181,6 @@
 			{
 
 				if (in_array($item_id, $stored_ids)) { //if it's already exist
-					$object->SetDefaultValues();
 					$object->Load($item_id);
 					$object->SetFieldsFromHash($values);
 					if (!$object->Validate()) {
@@ -190,24 +190,24 @@
 					}
 					if( $object->Update($item_id) )
 					{
-						$event->status=erSUCCESS;
+						$event->status=kEvent::erSUCCESS;
 					}
 					else
 					{
-						$event->status=erFAIL;
+						$event->status=kEvent::erFAIL;
 						$event->redirect=false;
 						break;
 					}
 					unset($stored_ids[array_search($item_id, $stored_ids)]);
 				}
 				else {
-					$object->SetDefaultValues();
+					$object->Clear();
 					$object->SetFieldsFromHash($values);
 					$object->SetDBField('ProductId', $this->Application->GetVar("p_id"));
 
 					if( $object->Create() )
 					{
-						$event->status=erSUCCESS;
+						$event->status=kEvent::erSUCCESS;
 					}
 				}
 			}
@@ -361,7 +361,7 @@
 			$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->redirect_params = Array('opener' => 's'); //stay!
+		$event->setRedirectParams(Array('opener' => 's'), true);
 	}
 
 	/**
Index: branches/5.2.x/units/zones/zones_event_handler.php
===================================================================
diff -u -N -r13845 -r14099
--- branches/5.2.x/units/zones/zones_event_handler.php	(.../zones_event_handler.php)	(revision 13845)
+++ branches/5.2.x/units/zones/zones_event_handler.php	(.../zones_event_handler.php)	(revision 14099)
@@ -1,6 +1,6 @@
 GetObject();
-		$object->SetDBField('ZoneID', $this->Application->GetVar('zone_id') );
-		$object->ID = $this->Application->GetVar('zone_id');
-	}*/
-
 	/**
 	 * Enter description here...
 	 *
@@ -206,10 +198,6 @@
 
 			default:
 		}
-//		if($this->Application->GetVar('z_OriginalSaveEvent'))
-//		{
-//			$this->Application->SetVar($event->Prefix_Special.'_SaveEvent', $this->Application->GetVar('z_OriginalSaveEvent'));
-//		}
 	}
 
 	function OnMassDelete(&$event)
Index: branches/5.2.x/units/gateways/gw_classes/gw_base.php
===================================================================
diff -u -N -r13845 -r14099
--- branches/5.2.x/units/gateways/gw_classes/gw_base.php	(.../gw_base.php)	(revision 13845)
+++ branches/5.2.x/units/gateways/gw_classes/gw_base.php	(.../gw_base.php)	(revision 14099)
@@ -1,6 +1,6 @@
 Conn =& $this->Application->GetADODBConnection();
-		}
-
 		/**
 		 * Returns payment form submit url
 		 *
@@ -153,7 +139,7 @@
 		 */
 		function IsTestMode()
 		{
-			return defined('DEBUG_MODE') && constOn('DBG_PAYMENT_GW');
+			return defined('DEBUG_MODE') && kUtil::constOn('DBG_PAYMENT_GW');
 		}
 
 		/**
Index: branches/5.2.x/units/zones/zones_tag_processor.php
===================================================================
diff -u -N -r13845 -r14099
--- branches/5.2.x/units/zones/zones_tag_processor.php	(.../zones_tag_processor.php)	(revision 13845)
+++ branches/5.2.x/units/zones/zones_tag_processor.php	(.../zones_tag_processor.php)	(revision 14099)
@@ -1,6 +1,6 @@
 Application->StoreVar('gw_success_template',$tag_params['return_template']);
 			$this->Application->StoreVar('gw_cancel_template',$tag_params['cancel_template']);
 
-			$banks_query = $gw_params['request_url'].'?a=banklist';
+			$curl_helper =& $this->Application->recallObject('CurlHelper');
+			/* @var $curl_helper kCurlHelper */
+			
+			$banks = $curl_helper->Send($gw_params['request_url'].'?a=banklist');
 
-			$banks = curl_post($banks_query, null, null, 'GET');
-
 			$parser =& $this->Application->recallObject('kXMLHelper');
 			/* @var $parser kXMLHelper */
 			$bank_data =& $parser->Parse($banks);
@@ -83,8 +84,12 @@
 			$fields['returnurl'] = $this->getNotificationUrl() . '?order_id='.$item_data['OrderId'];
 			$fields['reporturl'] = $this->getNotificationUrl() . '?mode=report&order_id='.$item_data['OrderId'];
 
-			$transaction_xml = curl_post($gw_params['request_url'], $fields, null, 'GET');
+			$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);
@@ -124,7 +129,12 @@
 				$fields['transaction_id'] =  $this->Application->GetVar('transaction_id');
 				$fields['bank_id'] = $this->Application->GetVar('ideal_nl_bank_id');
 
-				$check_xml = curl_post($gw_params['request_url'], $fields, null, 'GET');
+				$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);
Index: branches/5.2.x/units/destinations/dst_event_handler.php
===================================================================
diff -u -N -r13845 -r14099
--- branches/5.2.x/units/destinations/dst_event_handler.php	(.../dst_event_handler.php)	(revision 13845)
+++ branches/5.2.x/units/destinations/dst_event_handler.php	(.../dst_event_handler.php)	(revision 14099)
@@ -1,6 +1,6 @@
 Create() ) {
 					$this->customProcessing($event, 'after');
-					$event->status = erSUCCESS;
+					$event->status = kEvent::erSUCCESS;
 				}
 				else {
-					$event->status = erFAIL;
+					$event->status = kEvent::erFAIL;
 					$event->redirect = false;
-					$this->Application->SetVar($event->Prefix_Special.'_SaveEvent','OnCreate');
+					$this->Application->SetVar($event->getPrefixSpecial().'_SaveEvent','OnCreate');
 					$object->setID(0);
 				}
 			}
Index: branches/5.2.x/units/coupons/coupons_event_handler.php
===================================================================
diff -u -N -r13845 -r14099
--- branches/5.2.x/units/coupons/coupons_event_handler.php	(.../coupons_event_handler.php)	(revision 13845)
+++ branches/5.2.x/units/coupons/coupons_event_handler.php	(.../coupons_event_handler.php)	(revision 14099)
@@ -1,6 +1,6 @@
 Load($code, 'Code');
 
 		if (!$object->isLoaded()) {
-			$event->status = erFAIL;
+			$event->status = kEvent::erFAIL;
 			$this->Application->SetVar('set_checkout_error', 4);
 			$event->redirect = false; // check!!!
 			return ;
 		}
-//		$object->IDField = $this->Application->getUnitOption($event->Prefix, 'IDField');
-//		$object->ID = $object->GetDBField( $object->IDField );
 
 		$expire_date = $object->GetDBField('Expiration');
 		$number_of_use = $object->GetDBField('NumberOfUses');
 		if(	$object->GetDBField('Status') != 1 || ($expire_date && $expire_date < adodb_mktime()) ||
 			(isset($number_of_use) && $number_of_use <= 0))
 		{
-			$event->status = erFAIL;
+			$event->status = kEvent::erFAIL;
 			$this->Application->SetVar('set_checkout_error', 5);
 			$event->redirect->false;
 			return ;
Index: branches/5.2.x/units/affiliate_payment_types/affiliate_payment_types_event_handler.php
===================================================================
diff -u -N -r13845 -r14099
--- branches/5.2.x/units/affiliate_payment_types/affiliate_payment_types_event_handler.php	(.../affiliate_payment_types_event_handler.php)	(revision 13845)
+++ branches/5.2.x/units/affiliate_payment_types/affiliate_payment_types_event_handler.php	(.../affiliate_payment_types_event_handler.php)	(revision 14099)
@@ -1,6 +1,6 @@
 OnBeforeItemUpdate($event);
 		}
 
-		function OnMassDelete($event)
+		function OnMassDelete(&$event)
 		{
 			if ($this->Application->CheckPermission('SYSTEM_ACCESS.READONLY', 1)) {
-				$event->status = erFAIL;
+				$event->status = kEvent::erFAIL;
 				return;
 			}
 
Index: branches/5.2.x/units/affiliate_payments/affiliate_payments_event_handler.php
===================================================================
diff -u -N -r13845 -r14099
--- branches/5.2.x/units/affiliate_payments/affiliate_payments_event_handler.php	(.../affiliate_payments_event_handler.php)	(revision 13845)
+++ branches/5.2.x/units/affiliate_payments/affiliate_payments_event_handler.php	(.../affiliate_payments_event_handler.php)	(revision 14099)
@@ -1,6 +1,6 @@
 SetDBField('PaymentTypeId', $parent_object->GetDBField('PaymentTypeId'));
 			}
 
-			if($this->Application->GetVar($event->Prefix_Special.'_event') != 'OnNew' && $this->Application->GetVar($event->Prefix_Special.'_event') != 'OnCreate')
+			if($this->Application->GetVar($event->getPrefixSpecial().'_event') != 'OnNew' && $this->Application->GetVar($event->getPrefixSpecial().'_event') != 'OnCreate')
 			{
 				$options['options'][0] = '';
 			}
Index: branches/5.2.x/units/brackets/brackets_event_handler.php
===================================================================
diff -u -N -r13845 -r14099
--- branches/5.2.x/units/brackets/brackets_event_handler.php	(.../brackets_event_handler.php)	(revision 13845)
+++ branches/5.2.x/units/brackets/brackets_event_handler.php	(.../brackets_event_handler.php)	(revision 14099)
@@ -1,6 +1,6 @@
 Application->GetVar( $event->Prefix_Special );
+		$item_info = $this->Application->GetVar( $event->getPrefixSpecial() );
 		foreach($item_info as $id => $item_data)
 		{
 			if($item_info[$id]['Start_a'] === '' && $item_info[$id]['Start_b'] === '')
@@ -72,7 +72,7 @@
 			}
 			else
 			{
-				$item_info[$id]['Start'] = Pounds2Kg($item_info[$id]['Start_a'], $item_info[$id]['Start_b']);
+				$item_info[$id]['Start'] = kUtil::Pounds2Kg($item_info[$id]['Start_a'], $item_info[$id]['Start_b']);
 			}
 
 			if($item_info[$id]['End_a'] == '∞' || $item_info[$id]['End_a'] == '∞')
@@ -85,10 +85,10 @@
 			}
 			else
 			{
-				$item_info[$id]['End'] = Pounds2Kg($item_info[$id]['End_a'], $item_info[$id]['End_b']);
+				$item_info[$id]['End'] = kUtil::Pounds2Kg($item_info[$id]['End_a'], $item_info[$id]['End_b']);
 			}
 		}
-		$this->Application->SetVar( $event->Prefix_Special, $item_info );
+		$this->Application->SetVar( $event->getPrefixSpecial(), $item_info );
 	}
 
 	/**
@@ -181,18 +181,18 @@
 		$shipping_object =& $this->Application->recallObject('s');
 		if($lang_object->GetDBField('UnitSystem') == 2 && $shipping_object->GetDBField('Type') == 1)
 		{
-			$item_info = $this->Application->GetVar( $event->Prefix_Special );
+			$item_info = $this->Application->GetVar( $event->getPrefixSpecial() );
 			if(is_array($item_info))
 			{
 				foreach($item_info as $id => $values)
 				{
 					if($values['End'] == -1)
 					{
-						$item_info[$id]['End_a'] = -1 / POUND_TO_KG;
+						$item_info[$id]['End_a'] = -1 / kUtil::POUND_TO_KG;
 						$item_info[$id]['End_b'] = 0;
 					}
 				}
-				$this->Application->SetVar( $event->Prefix_Special, $item_info );
+				$this->Application->SetVar( $event->getPrefixSpecial(), $item_info );
 			}
 		}
 
Index: branches/5.2.x/units/coupon_items/coupon_items_event_handler.php
===================================================================
diff -u -N -r13845 -r14099
--- branches/5.2.x/units/coupon_items/coupon_items_event_handler.php	(.../coupon_items_event_handler.php)	(revision 13845)
+++ branches/5.2.x/units/coupon_items/coupon_items_event_handler.php	(.../coupon_items_event_handler.php)	(revision 14099)
@@ -1,6 +1,6 @@
 Create() ) {
 			$this->customProcessing($event, 'after');
-			$event->status = erSUCCESS;
-			$event->redirect_params = Array('opener' => 's'); //stay!
+			$event->status = kEvent::erSUCCESS;
+			$event->setRedirectParams(Array('opener' => 's'), true); //stay!
 		}
 		else {
-			$event->status = erFAIL;
-			$this->Application->SetVar($event->Prefix_Special.'_SaveEvent','OnCreate');
+			$event->status = kEvent::erFAIL;
+			$this->Application->SetVar($event->getPrefixSpecial().'_SaveEvent','OnCreate');
 			$object->setID(0);
 		}
 	}
Index: branches/5.2.x/units/order_items/order_items_event_handler.php
===================================================================
diff -u -N -r13845 -r14099
--- branches/5.2.x/units/order_items/order_items_event_handler.php	(.../order_items_event_handler.php)	(revision 13845)
+++ branches/5.2.x/units/order_items/order_items_event_handler.php	(.../order_items_event_handler.php)	(revision 14099)
@@ -1,6 +1,6 @@
 CallSubEvent('OnUpdate');
 			$event->redirect = false;
-			$event->redirect_params = Array('opener'=>'s','pass'=>'all');
+			$event->setRedirectParams(Array('opener'=>'s','pass'=>'all'), true);
 		}
 
 		/**
Index: branches/5.2.x/units/payment_type/payment_type_event_handler.php
===================================================================
diff -u -N -r13845 -r14099
--- branches/5.2.x/units/payment_type/payment_type_event_handler.php	(.../payment_type_event_handler.php)	(revision 13845)
+++ branches/5.2.x/units/payment_type/payment_type_event_handler.php	(.../payment_type_event_handler.php)	(revision 14099)
@@ -1,6 +1,6 @@
 Conn->Query('UPDATE '.$object->TableName.' SET IsPrimary = 0 ');
 			$this->Conn->Query('UPDATE '.$object->TableName.' SET IsPrimary = 1, Status = 1 WHERE PaymentTypeId = '.$id.' ');
 		}
-		$event->redirect_params = Array('opener' => 's'); //stay!
+		$event->setRedirectParams(Array('opener' => 's'), true);
 	}
 
 	function OnMassDecline(&$event)
@@ -84,7 +84,7 @@
 				if( $object->Update() )
 				{
 					$event->status=erSUCCESS;
-					$event->redirect_params = Array('opener' => 's'); //stay!
+					$event->setRedirectParams(Array('opener' => 's'), true);
 				}
 				else
 				{
Index: branches/5.2.x/units/currencies/currencies_event_handler.php
===================================================================
diff -u -N -r13845 -r14099
--- branches/5.2.x/units/currencies/currencies_event_handler.php	(.../currencies_event_handler.php)	(revision 13845)
+++ branches/5.2.x/units/currencies/currencies_event_handler.php	(.../currencies_event_handler.php)	(revision 14099)
@@ -1,6 +1,6 @@
 Application->CheckPermission('SYSTEM_ACCESS.READONLY', 1)) {
-			$event->status = erFAIL;
+			$event->status = kEvent::erFAIL;
 			return;
 		}
 
@@ -150,7 +150,7 @@
 	function OnUpdateRate(&$event)
 	{
 		if ($this->Application->CheckPermission('SYSTEM_ACCESS.READONLY', 1)) {
-			$event->status = erFAIL;
+			$event->status = kEvent::erFAIL;
 			return;
 		}
 
@@ -164,19 +164,21 @@
 		$rates =& $this->Application->recallObject($rates_class);
 
 		$rates->GetRatesData();
+
 		$object =& $event->getObject();
+		/* @var $object kDBItem */
+
 		$iso = $object->GetDBField('ISO');
 		$rates->StoreRates($iso);
 		if($rates->GetRate($iso, 'PRIMARY'))
 		{
-			$event->status=erSUCCESS;
+			$event->status=kEvent::erSUCCESS;
 		}
 		else
 		{
-			$event->status=erFAIL;
+			$event->status=kEvent::erFAIL;
 			$event->redirect=false;
-			$object->FieldErrors['RateToPrimary']['pseudo'] = 'couldnt_retrieve_rate';
-			$object->ErrorMsgs['couldnt_retrieve_rate'] = $this->Application->Phrase('la_couldnt_retrieve_rate');
+			$object->SetError('RateToPrimary', 'couldnt_retrieve_rate', 'la_couldnt_retrieve_rate');
 		}
 	}
 
@@ -188,7 +190,7 @@
 	function OnUpdateRates(&$event)
 	{
 		if ($this->Application->CheckPermission('SYSTEM_ACCESS.READONLY', 1)) {
-			$event->status = erFAIL;
+			$event->status = kEvent::erFAIL;
 			return;
 		}
 
Index: branches/5.2.x/units/gateways/gw_event_handler.php
===================================================================
diff -u -N -r13845 -r14099
--- branches/5.2.x/units/gateways/gw_event_handler.php	(.../gw_event_handler.php)	(revision 13845)
+++ branches/5.2.x/units/gateways/gw_event_handler.php	(.../gw_event_handler.php)	(revision 14099)
@@ -1,6 +1,6 @@
 SetFieldsFromHash($field_values);
 				if( $GWConfigValue->Create() )
 				{
-					$event->status=erSUCCESS;
+					$event->status=kEvent::erSUCCESS;
 				}
 				else
 				{
-					$event->status=erFAIL;
+					$event->status=kEvent::erFAIL;
 					break;
 				}
 			}
Index: branches/5.2.x/units/shipping_quote_engines/intershipper.php
===================================================================
diff -u -N -r13845 -r14099
--- branches/5.2.x/units/shipping_quote_engines/intershipper.php	(.../intershipper.php)	(revision 13845)
+++ branches/5.2.x/units/shipping_quote_engines/intershipper.php	(.../intershipper.php)	(revision 14099)
@@ -1,6 +1,6 @@
 LoadParams();
-		$db = $this->Application->GetADODBConnection();
 
 		$this->FlatSurcharge = $params['FlatSurcharge'];
 		$this->PercentSurcharge = $params['PercentSurcharge'];
@@ -239,8 +238,6 @@
 		if(!is_array($params)) $params = unserialize($params);
 		$params = $this->MergeParams($params);
 
-//		print_pre($params);
-
 		if($params == false)
 		{
 			trigger_error('Incorrect params given to intershipper engine', E_USER_WARNING);
@@ -256,8 +253,12 @@
 		xml_set_element_handler( $xml_parser, Array(&$this, 'startElement'), Array(&$this, 'endElement') );
 		xml_set_character_data_handler( $xml_parser, Array(&$this, 'characterData') );
 
-		$newdata = curl_post($target_url['url'], $target_url['uri']);
+		$curl_helper =& $this->Application->recallObject('CurlHelper');
+		/* @var $curl_helper kCurlHelper */
 
+		$curl_helper->SetPostData($target_url['uri']);
+		$newdata = $curl_helper->Send($target_url['url']);
+
  		$newdata = substr($newdata, strpos($newdata, '<'));
 
 		if (!xml_parse($xml_parser, $newdata, 1)) {
@@ -349,8 +350,8 @@
 	{
 		$sql = 'SELECT Properties, FlatSurcharge, PercentSurcharge FROM '.$this->Application->getUnitOption('sqe', 'TableName').'
 				WHERE Name="Intershipper.com"';
-		$db = $this->Application->GetADODBConnection();
-		$data = $db->GetRow($sql);
+		$data = $this->Conn->GetRow($sql);
+
 		$params = unserialize(getArrayValue($data, 'Properties'));
 		return array_merge($params, array('FlatSurcharge' => $data['FlatSurcharge'], 'PercentSurcharge' => $data['PercentSurcharge']));
 	}
Index: branches/5.2.x/units/coupons/coupons_tag_processor.php
===================================================================
diff -u -N -r13845 -r14099
--- branches/5.2.x/units/coupons/coupons_tag_processor.php	(.../coupons_tag_processor.php)	(revision 13845)
+++ branches/5.2.x/units/coupons/coupons_tag_processor.php	(.../coupons_tag_processor.php)	(revision 14099)
@@ -1,6 +1,6 @@
 Application->recallObject($this->getPrefixSpecial());
-			$formatter =& $this->Application->makeClass('kDateFormatter');
+			$object =& $this->getObject($params);
+			$formatter =& $this->Application->recallObject('kDateFormatter');
+
 			return $formatter->Format( adodb_mktime() + $this->Application->ConfigValue('Comm_DefaultCouponDuration') * 3600 * 24, 'Expiration_date', $object);
 		}
 
 		function DefaultExpTime($params){
-			$object = &$this->Application->recallObject($this->getPrefixSpecial());
-			$formatter =& $this->Application->makeClass('kDateFormatter');
+			$object =& $this->getObject($params);
+			$formatter =& $this->Application->recallObject('kDateFormatter');
+
 			return $formatter->Format( adodb_mktime() + $this->Application->ConfigValue('Comm_DefaultCouponDuration') * 3600 * 24, 'Expiration_time', $object);
 		}
 	}
\ No newline at end of file
Index: branches/5.2.x/units/shipping_quote_engines/custom_shipping_quote_engine.php
===================================================================
diff -u -N -r13845 -r14099
--- branches/5.2.x/units/shipping_quote_engines/custom_shipping_quote_engine.php	(.../custom_shipping_quote_engine.php)	(revision 13845)
+++ branches/5.2.x/units/shipping_quote_engines/custom_shipping_quote_engine.php	(.../custom_shipping_quote_engine.php)	(revision 14099)
@@ -1,6 +1,6 @@
 Application->GetADODBConnection();
 		$packages = $params['packages'];
 		$default_pack = array_shift($packages);
 		$query = $this->QueryShippingCost($params['dest_country'], $params['dest_state'], $params['dest_postal'], $default_pack['weight'], $params['items'], $params['amount'], $params['shipping_type'], $params['promo_params']);
-		$shipping_types = $db->Query($query, 'ShippingId');
+		$shipping_types = $this->Conn->Query($query, 'ShippingId');
 
 		if (!$this->Application->isAdminUser) {
 			$user_groups = explode(',', $this->Application->RecallVar('UserGroups'));
@@ -40,8 +39,6 @@
 
 	function QueryShippingCost($user_country, $user_state, $user_zip, $weight, $items, $amount, $shipping_type=null, $promo_params)
 	{
-		$db =& $this->Application->GetADODBConnection();
-
 		$cs_helper =& $this->Application->recallObject('CountryStatesHelper');
 		/* @var $cs_helper kCountryStatesHelper */
 
@@ -128,7 +125,7 @@
 												(sz.Type = 3 AND
 													(szd.StdDestId = '.$user_country_id.') '.# user country id
 													'AND
-													(szd.DestValue = '.$db->qstr($user_zip).') '.# user zip code
+													(szd.DestValue = '.$this->Conn->qstr($user_zip).') '.# user zip code
 												')
 											)
 											AND
Index: branches/5.2.x/units/shipping_quote_engines/shipping_quote_engine_event_handler.php
===================================================================
diff -u -N -r13845 -r14099
--- branches/5.2.x/units/shipping_quote_engines/shipping_quote_engine_event_handler.php	(.../shipping_quote_engine_event_handler.php)	(revision 13845)
+++ branches/5.2.x/units/shipping_quote_engines/shipping_quote_engine_event_handler.php	(.../shipping_quote_engine_event_handler.php)	(revision 14099)
@@ -1,6 +1,6 @@
 Name == 'OnMassApprove')
 		{
-			$event->status = erSUCCESS;
+			$event->status = kEvent::erSUCCESS;
 			$event->redirect = true;
 		}
 	}
Index: branches/5.2.x/units/product_options/product_options_tag_processor.php
===================================================================
diff -u -N -r13845 -r14099
--- branches/5.2.x/units/product_options/product_options_tag_processor.php	(.../product_options_tag_processor.php)	(revision 13845)
+++ branches/5.2.x/units/product_options/product_options_tag_processor.php	(.../product_options_tag_processor.php)	(revision 14099)
@@ -1,6 +1,6 @@
 GetId()]);
 				}
 				else { // radio buttons ?
-					$selected = unhtmlentities($options[$object->GetId()]) == $val;
+					$selected = kUtil::unhtmlentities($options[$object->GetId()]) == $val;
 				}
 			}
 			if ($selected) {
Index: branches/5.2.x/units/gateways/gw_classes/paypal.php
===================================================================
diff -u -N -r13845 -r14099
--- branches/5.2.x/units/gateways/gw_classes/paypal.php	(.../paypal.php)	(revision 13845)
+++ branches/5.2.x/units/gateways/gw_classes/paypal.php	(.../paypal.php)	(revision 14099)
@@ -1,6 +1,6 @@
  0, 'VERIFIED' => 1);
 
-			$n_status = curl_post($gw_params['submit_url'], $_POST); // INVALID, VERIFIED
+			$curl_helper =& $this->Application->recallObject('CurlHelper');
+			/* @var $curl_helper kCurlHelper */
+
+			$curl_helper->SetPostData($_POST);
+			$n_status = $curl_helper->Send($gw_params['submit_url']); // INVALID, VERIFIED
+
 			$n_status = $status_map[$n_status];
 
 			$success = ($n_status == 1) && ($payment_status == 'Completed') ? 1:0 ; // 1:0 is on purpose, false will result an SQL error !
@@ -194,10 +199,12 @@
 					$success = 0; //this will eliminate OnCompleteOrder in gw_notify!
 
 					$org_order = $this->Application->recallObject('ord.-original', 'ord', Array('skip_autoload' => true));
+					/* @var $org_order kDBItem */
+
 					$org_order->Load($field_values['OrderId']);
 
 					$order = $this->Application->recallObject('ord.-paypal', 'ord');
-					$order->SetDBFieldsFromHash($org_order->FieldValues);
+					$order->SetDBFieldsFromHash($org_order->GetFieldValues());
 					$order->SetDBField('SubTotal', $field_values['Price']);
 					$order->SetDBField('OriginalAmout', $field_values['Price']);
 					$order->SetDBField('OrderDate', adodb_mktime());
Index: branches/5.2.x/units/orders/order_calculator.php
===================================================================
diff -u -N
--- branches/5.2.x/units/orders/order_calculator.php	(revision 0)
+++ branches/5.2.x/units/orders/order_calculator.php	(revision 14099)
@@ -0,0 +1,850 @@
+reset();
+		}
+
+		/**
+		 * Sets order manager instance to calculator
+		 *
+		 * @param OrderManager $manager
+		 */
+		public function setManager(&$manager)
+		{
+			$this->manager =& $manager;
+		}
+
+		public function reset()
+		{
+			$this->items = Array ();
+		}
+
+		/**
+		 * Returns order object used in order manager
+		 *
+		 * @return OrdersItem
+		 */
+		protected function &getOrder()
+		{
+			$order =& $this->manager->getOrder();
+
+			return $order;
+		}
+
+		/**
+		 * Sets error from last operation
+		 *
+		 * @param int $error_code
+		 */
+		protected function setError($error_code)
+		{
+			$this->manager->setError($error_code);
+		}
+
+		/**
+		 * Perform order calculations and prepares operations for order manager
+		 *
+		 */
+		public function calculate()
+		{
+			$this->queryItems();
+			$this->groupItems();
+
+			$this->generateOperations();
+			$this->applyWholeOrderFlatDiscount();
+		}
+
+		/**
+		 * Groups order items, when requested
+		 *
+		 * @return Array
+		 */
+		protected function groupItems()
+		{
+			$skipped_items = Array ();
+
+			foreach ($this->items as $item_id => $item_data) {
+				if ( in_array($item_id, $skipped_items) ) {
+					continue;
+				}
+
+				$group_items = $this->getItemsToGroupWith($item_id);
+
+				if (!$group_items) {
+					continue;
+				}
+
+				foreach ($group_items as $group_item_id) {
+					$this->items[$item_id]['Quantity'] += $this->items[$group_item_id]['Quantity'];
+					$this->items[$group_item_id]['Quantity'] = 0;
+				}
+
+				$items_skipped = array_merge($items_skipped, $group_items);
+			}
+		}
+
+		/**
+		 * Returns order item ids, that can be grouped with given order item id
+		 *
+		 * @param int $target_item_id
+		 * @return Array
+		 * @see OrderCalculator::canBeGrouped
+		 */
+		protected function getItemsToGroupWith($target_item_id)
+		{
+			$ret = Array ();
+
+			foreach ($this->items as $item_id => $item_data) {
+				if ( $this->canBeGrouped($this->items[$item_id], $this->items[$target_item_id]) ) {
+					$ret[] = $item_id;
+				}
+			}
+
+			return array_diff($ret, Array ($target_item_id));
+		}
+
+		/**
+		 * Checks if 2 given order items can be grouped together
+		 *
+		 * @param Array $src_item
+		 * @param Array $dst_item
+		 * @return bool
+		 */
+		public function canBeGrouped($src_item, $dst_item)
+		{
+			if ($dst_item['Type'] != PRODUCT_TYPE_TANGIBLE) {
+				return false;
+			}
+
+			return ($src_item['ProductId'] == $dst_item['ProductId']) && ($src_item['OptionsSalt'] == $dst_item['OptionsSalt']);
+		}
+
+		/**
+		 * Retrieves order contents from database
+		 *
+		 */
+		protected function queryItems()
+		{
+			$poc_table = $this->Application->getUnitOption('poc', 'TableName');
+
+			$query = '	SELECT 	oi.ProductId, oi.OptionsSalt, oi.ItemData, oi.Quantity,
+								IF(p.InventoryStatus = ' . ProductInventory::BY_OPTIONS . ', poc.QtyInStock, p.QtyInStock) AS QtyInStock,
+								p.QtyInStockMin, p.BackOrder, p.InventoryStatus,
+								p.Type, oi.OrderItemId
+						FROM ' . $this->getTable('orditems') . ' AS oi
+						LEFT JOIN ' . TABLE_PREFIX . 'Products AS p ON oi.ProductId = p.ProductId
+						LEFT JOIN ' . $poc_table . ' poc ON (poc.CombinationCRC = oi.OptionsSalt) AND (oi.ProductId = poc.ProductId)
+						WHERE oi.OrderId = ' . $this->getOrder()->GetID();
+
+			$this->items = $this->Conn->Query($query, 'OrderItemId');
+		}
+
+		/**
+		 * Generates operations and returns true, when something was changed
+		 *
+		 * @return bool
+		 */
+		protected function generateOperations()
+		{
+			$this->manager->resetOperationTotals();
+
+			foreach ($this->items as $item) {
+				$this->ensureMinQty($item);
+
+				$to_order = $back_order = 0;
+				$available = $this->getAvailableQty($item);
+
+				if ( $this->allowBackordering($item) ) {
+					// split order into order & backorder
+					if ($item['BackOrder'] == ProductBackorder::ALWAYS) {
+						$to_order = $available = 0;
+						$back_order = $item['Quantity'];
+					}
+					elseif ($item['BackOrder'] == ProductBackorder::AUTO) {
+						$to_order = $available;
+						$back_order = $item['Quantity'] - $available;
+					}
+
+					$qty = $to_order + $back_order;
+
+					$price = $this->getPlainProductPrice($item, $qty);
+					$cost = $this->getProductCost($item, $qty);
+					$discount_info = $this->getDiscountInfo( $item['ProductId'], $price, $qty );
+
+					$this->manager->addOperation($item, 0, $to_order, $price, $cost, $discount_info);
+					$this->manager->addOperation($item, 1, $back_order, $price, $cost, $discount_info);
+				}
+				else {
+					// store as normal order (and remove backorder)
+					// we could get here with backorder=never then we should order only what's available
+					$to_order = min($item['Quantity'], $available);
+
+					$price = $this->getPlainProductPrice($item, $to_order);
+					$cost = $this->getProductCost($item, $to_order);
+					$discount_info = $this->getDiscountInfo( $item['ProductId'], $price, $to_order );
+
+					$this->manager->addOperation($item, 0, $to_order, $price, $cost, $discount_info, $item['OrderItemId']);
+					$this->manager->addOperation($item, 1, 0, $price, $cost, $discount_info); // remove backorder record
+
+					if ($to_order < $item['Quantity']) {
+						// ordered less, then requested -> inform user
+						$this->setError($to_order > 0 ? 2 : 3);
+					}
+				}
+			}
+		}
+
+		/**
+		 * Adds product to order (not to db)
+		 *
+		 * @param Array $item
+		 * @param kCatDBItem $product
+		 * @param int $qty
+		 */
+		public function addProduct($item, &$product, $qty)
+		{
+			$this->updateItemDataFromProduct($item, $product);
+
+			$price = $this->getPlainProductPrice($item, $qty);
+			$cost = $this->getProductCost($item, $qty);
+			$discount_info = $this->getDiscountInfo( $item['ProductId'], $price, $qty );
+
+			$this->manager->addOperation( $item, 0, $qty, $price, $cost, $discount_info, $item['OrderItemId'] );
+		}
+
+		/**
+		 * Apply whole order flat discount after sub-total been calculated
+		 *
+		 */
+		protected function applyWholeOrderFlatDiscount()
+		{
+			$sub_total_flat = $this->manager->getOperationTotal('SubTotalFlat');
+			$flat_discount = min( $sub_total_flat, $this->getWholeOrderPlainDiscount($global_discount_id) );
+			$coupon_flat_discount = min( $sub_total_flat, $this->getWholeOrderCouponDiscount() );
+
+			if ($coupon_flat_discount && $coupon_flat_discount > $flat_discount) {
+				$global_discount_type = 'coupon';
+				$flat_discount = $coupon_flat_discount;
+				$global_discount_id = $coupon_id;
+			}
+			else {
+				$global_discount_type = 'discount';
+			}
+
+			$sub_total = $this->manager->getOperationTotal('SubTotal');
+
+			if ($sub_total_flat - $sub_total < $flat_discount) {
+				// individual item discounts together are smaller when order flat discount
+				$this->manager->setOperationTotal('CouponDiscount', $flat_discount == $coupon_flat_discount ? $flat_discount : 0);
+				$this->manager->setOperationTotal('SubTotal', $sub_total_flat - $flat_discount);
+
+				// replace discount for each operation
+				foreach ($this->operations as $index => $operation) {
+					$discounted_price = ($operation['Price'] / $sub_total_flat) * $sub_total;
+					$this->operations[$index]['DiscountInfo'] = Array ($global_discount_id, $global_discount_type, $discounted_price, 0);
+				}
+			}
+		}
+
+		/**
+		 * Returns discount information for given product price and qty
+		 *
+		 * @param int $product_id
+		 * @param float $price
+		 * @param int $qty
+		 * @return Array
+		 */
+		protected function getDiscountInfo($product_id, $price, $qty)
+		{
+			$discounted_price = $this->getDiscountedProductPrice($product_id, $price, $discount_id);
+			$couponed_price = $this->getCouponDiscountedPrice($product_id, $price);
+
+			if ($couponed_price < $discounted_price) {
+				$discount_type = 'coupon';
+				$discount_id = $coupon_id;
+
+				$discounted_price =	$couponed_price;
+				$coupon_discount = ($price - $couponed_price) * $qty;
+			}
+			else {
+				$coupon_discount = 0;
+				$discount_type = 'discount';
+			}
+
+			return Array ($discount_id, $discount_type, $discounted_price, $coupon_discount);
+		}
+
+		/**
+		 * Returns product qty, available for ordering
+		 *
+		 * @param Array $item
+		 * @return int
+		 */
+		protected function getAvailableQty($item)
+		{
+			if ( $item['InventoryStatus'] == ProductInventory::DISABLED ) {
+				// always available
+				return $item['Quantity'] * 2;
+			}
+
+			return max(0, $item['QtyInStock'] - $item['QtyInStockMin']);
+		}
+
+		/**
+		 * Checks, that product in given order item can be backordered
+		 *
+		 * @param Array $item
+		 * @return bool
+		 */
+		protected function allowBackordering($item)
+		{
+			if ($item['BackOrder'] == ProductBackorder::ALWAYS) {
+				return true;
+			}
+
+			$available = $this->getAvailableQty($item);
+			$backordering = $this->Application->ConfigValue('Comm_Enable_Backordering');
+
+			return $backordering && ($item['Quantity'] > $available) && ($item['BackOrder'] == ProductBackorder::AUTO);
+		}
+
+		/**
+		 * Make sure, that user can't order less, then minimal required qty of product
+		 *
+		 * @param Array $item
+		 */
+		protected function ensureMinQty(&$item)
+		{
+			$sql = 'SELECT MIN(MinQty)
+					FROM ' . TABLE_PREFIX . 'ProductsPricing
+					WHERE ProductId = ' . $item['ProductId'];
+			$min_qty = max(1, $this->Conn->GetOne($sql));
+
+			$qty = $item['Quantity'];
+
+			if ($qty > 0 && $qty < $min_qty) {
+				// qty in cart increased to meat minimal qry requirements of given product
+				$this->setError(6);
+				$item['Quantity'] = $min_qty;
+			}
+		}
+
+		/**
+		 * Return product price for given qty, taking no discounts into account
+		 *
+		 * @param Array $item
+		 * @param int $qty
+		 * @return float
+		 */
+		public function getPlainProductPrice($item, $qty)
+		{
+			$item_data = $this->getItemData($item);
+
+			if ( isset($item_data['ForcePrice']) ) {
+				return $item_data['ForcePrice'];
+			}
+
+			$pricing_id = $this->getPriceBracketByQty($item, $qty);
+
+			$sql = 'SELECT Price
+					FROM ' . TABLE_PREFIX . 'ProductsPricing
+					WHERE PriceId = ' . $pricing_id;
+			$price = (float)$this->Conn->GetOne($sql);
+
+			if ( isset($item_data['Options']) ) {
+				$price += $this->getOptionPriceAddition($price, $item_data);
+				$price = $this->getCombinationPriceOverride($price, $item_data);
+			}
+
+			return max($price, 0);
+		}
+
+		/**
+		 * Return product cost for given qty, taking no discounts into account
+		 *
+		 * @param Array $item
+		 * @param int $qty
+		 * @return float
+		 */
+		public function getProductCost($item, $qty)
+		{
+			$pricing_id = $this->getPriceBracketByQty($item, $qty);
+
+			$sql = 'SELECT Cost
+					FROM ' . TABLE_PREFIX . 'ProductsPricing
+					WHERE PriceId = ' . $pricing_id;
+
+			return (float)$this->Conn->GetOne($sql);
+		}
+
+		/**
+		 * Return product price for given qty, taking no discounts into account
+		 *
+		 * @param Array $item
+		 * @param int $qty
+		 * @return float
+		 */
+		protected function getPriceBracketByQty($item, $qty)
+		{
+			$orderby_clause = '';
+			$where_clause = Array ();
+			$product_id = $item['ProductId'];
+
+			if ( $this->usePriceBrackets($item) ) {
+				$user_id = $this->getOrder()->GetDBField('PortalUserId');
+
+				$where_clause = Array (
+					'GroupId IN (' . $this->Application->getUserGroups($user_id) . ')',
+					'pp.ProductId = ' . $product_id,
+					'pp.MinQty <= ' . $qty,
+					$qty . ' < pp.MaxQty OR pp.MaxQty = -1',
+				);
+
+				$orderby_clause = $this->getPriceBracketOrderClause($user_id);
+			}
+			else {
+				$item_data = $this->getItemData($item);
+
+				$where_clause = Array(
+					'pp.ProductId = ' . $product_id,
+					'pp.PriceId = ' . $this->getPriceBracketFromRequest($product_id, $item_data),
+				);
+			}
+
+			$sql = 'SELECT pp.PriceId
+					FROM ' . TABLE_PREFIX . 'ProductsPricing AS pp
+					LEFT JOIN ' . TABLE_PREFIX . 'Products AS p ON p.ProductId = pp.ProductId
+					WHERE (' . implode(') AND (', $where_clause) . ')';
+
+			if ($orderby_clause) {
+				$sql .= ' ORDER BY ' . $orderby_clause;
+			}
+
+			return (float)$this->Conn->GetOne($sql);
+		}
+
+		/**
+		 * Checks if price brackets should be used in price calculations
+		 *
+		 * @param Array $item
+		 * @return bool
+		 */
+		protected function usePriceBrackets($item)
+		{
+			return $item['Type'] == PRODUCT_TYPE_TANGIBLE;
+		}
+
+		/**
+		 * Return product pricing id for given product.
+		 * If not passed - return primary pricing ID
+		 *
+		 * @param int $product_id
+		 * @return int
+		 */
+		public function getPriceBracketFromRequest($product_id, $item_data)
+		{
+			if ( !is_array($item_data) ) {
+				$item_data = unserialize($item_data);
+			}
+
+			// remembered pricing during checkout
+			if ( isset($item_data['PricingId']) && $item_data['PricingId'] ) {
+				return $item_data['PricingId'];
+			}
+
+			// selected pricing from product detail page
+			$price_id = $this->Application->GetVar('pr_id');
+
+			if ($price_id) {
+				return $price_id;
+			}
+
+			$sql = 'SELECT PriceId
+					FROM ' . TABLE_PREFIX . 'ProductsPricing
+					WHERE ProductId = ' . $product_id . ' AND IsPrimary = 1';
+
+			return $this->Conn->GetOne($sql);
+		}
+
+		/**
+		 * Returns order clause for price bracket selection based on configration
+		 *
+		 * @param int $user_id
+		 * @return string
+		 */
+		protected function getPriceBracketOrderClause($user_id)
+		{
+			if ($this->Application->ConfigValue('Comm_PriceBracketCalculation') == 1) {
+				// if we have to stick to primary group, then its pricing will go first,
+				// but if there is no pricing for primary group, then next optimal will be taken
+				$primary_group = $this->getUserPrimaryGroup($user_id);
+
+				return '( IF(GroupId = ' . $primary_group . ', 1, 2) ) ASC, pp.Price ASC';
+			}
+
+			return 'pp.Price ASC';
+		}
+
+		/**
+		 * Returns addition to product price based on used product option
+		 *
+		 * @param float $price
+		 * @param Array $item_data
+		 * @return float
+		 */
+		protected function getOptionPriceAddition($price, $item_data)
+		{
+			$addtion = 0;
+
+			$opt_helper =& $this->Application->recallObject('kProductOptionsHelper');
+			/* @var $opt_helper kProductOptionsHelper */
+
+			foreach ($item_data['Options'] as $opt => $val) {
+				$sql = 'SELECT *
+						FROM ' . TABLE_PREFIX . 'ProductOptions
+						WHERE ProductOptionId = ' . $opt;
+				$data = $this->Conn->GetRow($sql);
+
+				$parsed = $opt_helper->ExplodeOptionValues($data);
+
+				if (!$parsed) {
+					continue;
+				}
+
+				$conv_prices = $parsed['Prices'];
+				$conv_price_types = $parsed['PriceTypes'];
+
+				if ( is_array($val) ) {
+					foreach ($val as $a_val) {
+						$a_val = kUtil::unhtmlentities($a_val);
+
+						if ( isset($conv_prices[$a_val]) && $conv_prices[$a_val] ) {
+							if ( $conv_price_types[$a_val] == '$' ) {
+								$addtion += $conv_prices[$a_val];
+							}
+							elseif ($conv_price_types[$a_val] == '%') {
+								$addtion += $price * $conv_prices[$a_val] / 100;
+							}
+						}
+					}
+				}
+				else {
+					$a_val = kUtil::unhtmlentities($val);
+
+					if ( isset($conv_prices[$a_val]) && $conv_prices[$a_val] ) {
+						if ($conv_price_types[$a_val] == '$') {
+							$addtion += $conv_prices[$a_val];
+						}
+						elseif ($conv_price_types[$a_val] == '%') {
+							$addtion += $price * $conv_prices[$a_val] / 100;
+						}
+					}
+				}
+			}
+
+			return $addtion;
+		}
+
+		/**
+		 * Returns product price after applying combination price override
+		 *
+		 * @param float $price
+		 * @param Array $item_data
+		 * @return float
+		 */
+		protected function getCombinationPriceOverride($price, $item_data)
+		{
+			$combination_salt = $this->generateOptionsSalt( $item_data['Options'] );
+
+			if (!$combination_salt) {
+				return $price;
+			}
+
+			$sql = 'SELECT *
+					FROM ' . TABLE_PREFIX . 'ProductOptionCombinations
+					WHERE CombinationCRC = ' . $combination_salt;
+			$combination = $this->Conn->GetRow($sql);
+
+			if (!$combination) {
+				return $price;
+			}
+
+			switch ( $combination['PriceType'] ) {
+				case OptionCombinationPriceType::EQUALS:
+					return $combination['Price'];
+					break;
+
+				case OptionCombinationPriceType::FLAT:
+					return $price + $combination['Price'];
+					break;
+
+				case OptionCombinationPriceType::PECENT:
+					return $price * (1 + $combination['Price'] / 100);
+					break;
+			}
+
+			return $price;
+		}
+
+		/**
+		 * Generates salt for given option set
+		 *
+		 * @param Array $options
+		 * @return int
+		 */
+		public function generateOptionsSalt($options)
+		{
+			$opt_helper =& $this->Application->recallObject('kProductOptionsHelper');
+			/* @var $opt_helper kProductOptionsHelper */
+
+			return $opt_helper->OptionsSalt($options, true);
+		}
+
+		/**
+		 * Return product price for given qty, taking possible discounts into account
+		 *
+		 * @param int $product_id
+		 * @param int $price
+		 * @param int $discount_id
+		 * @return float
+		 */
+		public function getDiscountedProductPrice($product_id, $price, &$discount_id)
+		{
+			$discount_id = 0;
+			$user_id = $this->getOrder()->GetDBField('PortalUserId');
+
+			$join_clause = Array (
+				'd.DiscountId = di.DiscountId',
+				'di.ItemType = ' . DiscountItemType::PRODUCT . ' OR (di.ItemType = ' . DiscountItemType::WHOLE_ORDER . ' AND d.Type = ' . DiscountType::PERCENT . ')',
+				'd.Status = ' . STATUS_ACTIVE,
+				'd.GroupId IN (' . $this->Application->getUserGroups($user_id) . ')',
+				'd.Start IS NULL OR d.Start < ' . $this->getOrder()->GetDBField('OrderDate'),
+				'd.End IS NULL OR d.End > ' . $this->getOrder()->GetDBField('OrderDate'),
+			);
+
+			$sql = 'SELECT
+						CASE d.Type
+							WHEN ' . DiscountType::FLAT . ' THEN ' . $price . ' - d.Amount
+							WHEN ' . DiscountType::PERCENT . ' THEN ' . $price . ' * (1 - d.Amount / 100)
+							ELSE ' . $price . '
+						END, d.DiscountId
+					FROM ' . TABLE_PREFIX . 'Products AS p
+					LEFT JOIN ' . TABLE_PREFIX . 'ProductsDiscountItems AS di ON (di.ItemResourceId = p.ResourceId) OR (di.ItemType = ' . DiscountItemType::WHOLE_ORDER . ')
+					LEFT JOIN ' . TABLE_PREFIX . 'ProductsDiscounts AS d ON (' . implode(') AND (', $join_clause) . ')
+					WHERE (p.ProductId = ' . $product_id . ') AND (d.DiscountId IS NOT NULL)';
+			$pricing = $this->Conn->GetCol($sql, 'DiscountId');
+
+			if (!$pricing) {
+				return $price;
+			}
+
+			// get minimal price + discount
+			$discounted_price = min($pricing);
+			$pricing = array_flip($pricing);
+			$discount_id = $pricing[$discounted_price];
+
+			// optimal discount, but prevent negative price
+			return max( min($discounted_price, $price), 0 );
+		}
+
+		public function getWholeOrderPlainDiscount(&$discount_id)
+		{
+			$discount_id = 0;
+			$user_id = $this->getOrder()->GetDBField('PortalUserId');
+
+			$join_clause = Array (
+				'd.DiscountId = di.DiscountId',
+				'di.ItemType = ' . DiscountItemType::WHOLE_ORDER . ' AND d.Type = ' . DiscountType::FLAT,
+				'd.Status = ' . STATUS_ACTIVE,
+				'd.GroupId IN (' . $this->Application->getUserGroups($user_id) . ')',
+				'd.Start IS NULL OR d.Start < ' . $this->getOrder()->GetDBField('OrderDate'),
+				'd.End IS NULL OR d.End > ' . $this->getOrder()->GetDBField('OrderDate'),
+			);
+
+			$sql = 'SELECT d.Amount AS Discount, d.DiscountId
+					FROM ' . TABLE_PREFIX . 'ProductsDiscountItems AS di
+					LEFT JOIN ' . TABLE_PREFIX . 'ProductsDiscounts AS d ON (' . implode(') AND (', $join_clause) . ')
+					WHERE d.DiscountId IS NOT NULL';
+			$pricing = $this->Conn->GetCol($sql, 'DiscountId');
+
+			if (!$pricing) {
+				return 0;
+			}
+
+			$discounted_price = max($pricing);
+			$pricing = array_flip($pricing);
+			$discount_id = $pricing[$discounted_price];
+
+			return max($discounted_price, 0);
+		}
+
+		public function getCouponDiscountedPrice($product_id, $price)
+		{
+			if ( !$this->getCoupon() ) {
+				return $price;
+			}
+
+			$join_clause = Array (
+				'c.CouponId = ci.CouponId',
+				'ci.ItemType = ' . CouponItemType::PRODUCT . ' OR (ci.ItemType = ' . CouponItemType::WHOLE_ORDER . ' AND c.Type = ' . CouponType::PERCENT . ')',
+			);
+
+			$sql = 'SELECT
+						MIN(
+							CASE c.Type
+								WHEN ' . CouponType::FLAT . ' THEN ' . $price . ' - c.Amount
+								WHEN ' . CouponType::PERCENT . ' THEN ' . $price . ' * (1 - c.Amount / 100)
+								ELSE ' . $price . '
+							END
+						)
+					FROM ' . TABLE_PREFIX . 'Products AS p
+					LEFT JOIN ' . TABLE_PREFIX . 'ProductsCouponItems AS ci ON (ci.ItemResourceId = p.ResourceId) OR (ci.ItemType = ' . CouponItemType::WHOLE_ORDER . ')
+					LEFT JOIN ' . TABLE_PREFIX . 'ProductsCoupons AS c ON (' . implode(') AND (', $join_clause) . ')
+					WHERE p.ProductId = ' . $product_id . ' AND ci.CouponId = ' . $this->getCoupon() . '
+					GROUP BY p.ProductId';
+
+			$coupon_price = $this->Conn->GetOne($sql);
+
+			if ($coupon_price === false) {
+				return $price;
+			}
+
+			return max( min($price, $coupon_price), 0 );
+		}
+
+		public function getWholeOrderCouponDiscount()
+		{
+			if ( !$this->getCoupon() ) {
+				return 0;
+			}
+
+			$where_clause = Array (
+				'ci.CouponId = ' . $this->getCoupon(),
+				'ci.ItemType = ' . CouponItemType::WHOLE_ORDER,
+				'c.Type = ' . CouponType::FLAT,
+			);
+
+			$sql = 'SELECT Amount
+					FROM ' . TABLE_PREFIX . 'ProductsCouponItems AS ci
+					LEFT JOIN ' . TABLE_PREFIX . 'ProductsCoupons AS c ON c.CouponId = ci.CouponId
+					WHERE (' . implode(') AND (', $where_clause) . ')';
+
+			return $this->Conn->GetOne($sql);
+		}
+
+		protected function getCoupon()
+		{
+			return $this->getOrder()->GetDBField('CouponId');
+		}
+
+		/**
+		 * Returns primary group of given user
+		 *
+		 * @param int $user_id
+		 * @return int
+		 */
+		protected function getUserPrimaryGroup($user_id)
+		{
+			if ($user_id > 0) {
+				$sql = 'SELECT GroupId
+						FROM ' . TABLE_PREFIX . 'UserGroup
+						WHERE PortalUserId = ' . $user_id . ' AND PrimaryGroup = 1';
+				return $this->Conn->GetOne($sql);
+			}
+
+			return $this->Application->ConfigValue('User_LoggedInGroup');
+		}
+
+		/**
+		 * Returns ItemData associated with given order item
+		 *
+		 * @param Array $item
+		 * @return Array
+		 */
+		protected function getItemData($item)
+		{
+			$item_data = $item['ItemData'];
+
+			if ( is_array($item_data) ) {
+				return $item_data;
+			}
+
+			return $item_data ? unserialize($item_data) : Array ();
+		}
+
+		/**
+		 * Sets ItemData according to product
+		 *
+		 * @param Array $item
+		 * @param kCatDBItem $product
+		 */
+		protected function updateItemDataFromProduct(&$item, &$product)
+		{
+			$item_data = $this->getItemData($item);
+			$item_data['IsRecurringBilling'] = $product->GetDBField('IsRecurringBilling');
+
+			// it item is processed in order using new style, then put such mark in orderitem record
+			$processing_data = $product->GetDBField('ProcessingData');
+
+			if ($processing_data) {
+				$processing_data = unserialize($processing_data);
+
+				if ( isset($processing_data['HasNewProcessing']) ) {
+					$item_data['HasNewProcessing'] = 1;
+				}
+			}
+
+			$item['ItemData'] = serialize($item_data);
+		}
+
+		/**
+		 * Returns table name according to order temp mode
+		 *
+		 * @param string $prefix
+		 * @return string
+		 */
+		protected function getTable($prefix)
+		{
+			return $this->manager->getTable($prefix);
+		}
+	}
\ No newline at end of file
Index: branches/5.2.x/units/brackets/brackets_tag_processor.php
===================================================================
diff -u -N -r13845 -r14099
--- branches/5.2.x/units/brackets/brackets_tag_processor.php	(.../brackets_tag_processor.php)	(revision 13845)
+++ branches/5.2.x/units/brackets/brackets_tag_processor.php	(.../brackets_tag_processor.php)	(revision 14099)
@@ -1,6 +1,6 @@
 Application->recallObject($linked_info['ParentPrefix'].'.'.$this->Special);
 //			$plan_type = $main_object->GetDBField('PlanType');
-//			$limits_format = ($plan_type == 2) ? '%d' : $br_object->Fields['Start']['format'];
+//			$limits_format = ($plan_type == 2) ? '%d' : $br_object->getFieldOption('Start', 'format');
 
 			// this is needed to find next id
 			$br_data_copy = $br_data;
@@ -111,7 +111,7 @@
 					}
 					else
 					{
-						list($block_params['min_a'], $block_params['min_b']) = Kg2Pounds($block_params['min']);
+						list($block_params['min_a'], $block_params['min_b']) = kUtil::Kg2Pounds($block_params['min']);
 					}
 
 					if($block_params['max'] == '∞')
@@ -121,7 +121,7 @@
 					}
 					else
 					{
-						list($block_params['max_a'], $block_params['max_b']) = Kg2Pounds($block_params['max']);
+						list($block_params['max_a'], $block_params['max_b']) = kUtil::Kg2Pounds($block_params['max']);
 					}
 				}
 
Index: branches/5.2.x/units/order_items/order_items_tag_processor.php
===================================================================
diff -u -N -r13845 -r14099
--- branches/5.2.x/units/order_items/order_items_tag_processor.php	(.../order_items_tag_processor.php)	(revision 13845)
+++ branches/5.2.x/units/order_items/order_items_tag_processor.php	(.../order_items_tag_processor.php)	(revision 14099)
@@ -1,6 +1,6 @@
  $val) {
 			if (!is_array($val)) {
-				$val = unhtmlentities($val);
+				$val = kUtil::unhtmlentities($val);
 			}
 			$key_data = $opt_helper->ConvertKey($opt, $object->GetDBField('ProductId'));
 
@@ -165,7 +165,7 @@
 		$i = 0;
 		foreach ($values as $val) {
 			$i++;
-			$val = unhtmlentities($val);
+			$val = kUtil::unhtmlentities($val);
 			$block_params['value'] = htmlspecialchars($val);
 			if ($price_types[$val] == '$') {
 				$iso = $this->GetISO($params['currency']);
@@ -212,7 +212,7 @@
 		$product_object =& $this->Application->recallObject('p', 'p', Array('skip_autoload' => true));
 		/* @var $product_object kCatDBItem */
 
-		$product_id = $product_object->GetID();		
+		$product_id = $product_object->GetID();
 		$product_id_get = $this->Application->GetVar('p_id');
 
 		while (!$list->EOL()) {
Index: branches/5.2.x/admin_templates/user_order_item_tab.tpl
===================================================================
diff -u -N -r13845 -r14099
--- branches/5.2.x/admin_templates/user_order_item_tab.tpl	(.../user_order_item_tab.tpl)	(revision 13845)
+++ branches/5.2.x/admin_templates/user_order_item_tab.tpl	(.../user_order_item_tab.tpl)	(revision 14099)
@@ -20,7 +20,7 @@
 		$Catalog.setCurrentCategory('', );
 		$Catalog.saveSearch('', '', '');
 
-		
+		
 
 		Grids[''].SetDependantToolbarButtons( new Array('edit','delete'));
 		$Catalog.setViewMenu('');
Index: branches/5.2.x/units/products/products_config.php
===================================================================
diff -u -N -r14089 -r14099
--- branches/5.2.x/units/products/products_config.php	(.../products_config.php)	(revision 14089)
+++ branches/5.2.x/units/products/products_config.php	(.../products_config.php)	(revision 14099)
@@ -1,6 +1,6 @@
 	Array (
 						'Groups' => Array (
-							Array ('mode' => 'AND', 'filters' => Array ('show_new'), 'type' => HAVING_FILTER),
-							Array ('mode' => 'AND', 'filters' => Array ('show_hot'), 'type' => HAVING_FILTER),
-							Array ('mode' => 'AND', 'filters' => Array ('show_pop'), 'type' => HAVING_FILTER),
-							Array ('mode' => 'AND', 'filters' => Array ('show_pick'), 'type' => WHERE_FILTER),
+							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'  ),
Index: branches/5.2.x/units/currencies/currency_rates.php
===================================================================
diff -u -N -r13845 -r14099
--- branches/5.2.x/units/currencies/currency_rates.php	(.../currency_rates.php)	(revision 13845)
+++ branches/5.2.x/units/currencies/currency_rates.php	(.../currency_rates.php)	(revision 14099)
@@ -1,6 +1,6 @@
 GetRatesData();
 	}
@@ -32,13 +37,11 @@
 		$primary = $this->Application->GetPrimaryCurrency();
 
 		if ($rates === false) {
-			$conn =& $this->Application->GetADODBConnection();
-
-			$conn->nextQueryCachable = true;
+			$this->Conn->nextQueryCachable = true;
 			$sql = 'SELECT ISO, RateToPrimary
 					FROM ' . $this->Application->getUnitOption('curr', 'TableName') . '
 					WHERE Status = ' . STATUS_ACTIVE;
-			$rates = $conn->Query($sql);
+			$rates = $this->Conn->Query($sql);
 
 			$this->Application->setCache($cache_key, $rates);
 		}
@@ -117,10 +120,11 @@
 
 class kBankLVCurrencyRates extends kCurrencyRates  {
 
-	function kBankLVCurrencyRates()
+	public function __construct()
 	{
 		$this->RateSource = 'http://www.bank.lv/ValutuKursi/XML/xml.cfm';
-		parent::kCurrencyRates();
+
+		parent::__construct();
 	}
 
 	function GetRatesData()
@@ -168,10 +172,11 @@
 
 class kECBCurrencyRates extends kCurrencyRates  {
 
-	function kECBCurrencyRates()
+	public function __construct()
 	{
 		$this->RateSource = 'http://www.ecb.int/stats/eurofxref/eurofxref-daily.xml';
-		parent::kCurrencyRates();
+
+		parent::__construct();
 	}
 
 	function GetRatesData()
@@ -210,10 +215,11 @@
 
 class kFRNYCurrencyRates extends kCurrencyRates  {
 
-	function kFRNYCurrencyRates()
+	public function __construct()
 	{
 		$this->RateSource = 'http://www.ny.frb.org/markets/fxrates/FXtoXML.cfm?FEXdate=%s&FEXtime=1200';
-		parent::kCurrencyRates();
+
+		parent::__construct();
 	}
 
 	function GetRatesData()
Index: branches/5.2.x/units/taxes/taxes_event_handler.php
===================================================================
diff -u -N -r13845 -r14099
--- branches/5.2.x/units/taxes/taxes_event_handler.php	(.../taxes_event_handler.php)	(revision 13845)
+++ branches/5.2.x/units/taxes/taxes_event_handler.php	(.../taxes_event_handler.php)	(revision 14099)
@@ -1,6 +1,6 @@
 GetObject();
-		$object->SetDBField('ZoneID', $this->Application->GetVar('zone_id') );
-		$object->ID = $this->Application->GetVar('zone_id');
-	}*/
-
 	/**
 	 * Enter description here...
 	 *
@@ -226,23 +218,8 @@
 
 			default:
 		}
-		/*if($this->Application->GetVar('tax_OriginalSaveEvent'))
-		{
-			$this->Application->SetVar($event->Prefix_Special.'_SaveEvent', $this->Application->GetVar('tax_OriginalSaveEvent'));
-		}*/
 
-
 		$event->CallSubEvent("OnPreSave");
-/*
-			$child_event = new kEvent();
-			$child_event->Prefix = "tax";
-			$child_event->Special = "";
-			$child_event->Prefix_Special = "tax";
-			$child_event->redirect = false;
-			$child_event->Name = "OnPreSave";
-
-			$this->Application->HandleEvent( $child_event);		*/
-
 	}
 
 	function OnMassDelete(&$event)
Index: branches/5.2.x/units/payment_type_currencies/payment_type_currencies_event_handler.php
===================================================================
diff -u -N -r13845 -r14099
--- branches/5.2.x/units/payment_type_currencies/payment_type_currencies_event_handler.php	(.../payment_type_currencies_event_handler.php)	(revision 13845)
+++ branches/5.2.x/units/payment_type_currencies/payment_type_currencies_event_handler.php	(.../payment_type_currencies_event_handler.php)	(revision 14099)
@@ -1,6 +1,6 @@
 Create() ) {
 					$this->customProcessing($event, 'after');
-					$event->status = erSUCCESS;
+					$event->status = kEvent::erSUCCESS;
 				}
 				else {
-					$event->status = erFAIL;
+					$event->status = kEvent::erFAIL;
 					$event->redirect = false;
-					$this->Application->SetVar($event->Prefix_Special . '_SaveEvent', 'OnCreate');
+					$this->Application->SetVar($event->getPrefixSpecial() . '_SaveEvent', 'OnCreate');
 					$object->setID(0);
 				}
 			}
Index: branches/5.2.x/units/taxes/taxes_tag_processor.php
===================================================================
diff -u -N -r13845 -r14099
--- branches/5.2.x/units/taxes/taxes_tag_processor.php	(.../taxes_tag_processor.php)	(revision 13845)
+++ branches/5.2.x/units/taxes/taxes_tag_processor.php	(.../taxes_tag_processor.php)	(revision 14099)
@@ -1,6 +1,6 @@
 FieldErrors[$field_name]['pseudo'] = 'required';
+				$object->SetError($field_name, 'required');
 				return '';
 			}
 			else {
-				if (isset($object->Fields[$field_name]['required']) && $object->Fields[$field_name]['required']) {
+				if ( $object->isRequired($field_name) ) {
 					foreach ($value as $key=>$val)
 					{
 						if ($val == '') {
-							$object->FieldErrors[$field_name]['pseudo'] = 'required';
+							$object->SetError($field_name, 'required');
 						}
 					}
 				}
Index: branches/5.2.x/units/shipping_quote_engines/usps.php
===================================================================
diff -u -N -r14089 -r14099
--- branches/5.2.x/units/shipping_quote_engines/usps.php	(.../usps.php)	(revision 14089)
+++ branches/5.2.x/units/shipping_quote_engines/usps.php	(.../usps.php)	(revision 14099)
@@ -1,6 +1,6 @@
 types = Array(
@@ -1013,7 +1017,7 @@
 
 	function GetShippingQuotes($params = null)
 	{
-		$weights = Kg2Pounds($params['packages']['0']['weight']);
+		$weights = kUtil::Kg2Pounds($params['packages']['0']['weight']);
 		$weight = '';
 		$weight = $weights[0];
 		if ( $weights[1] != '' ) {
@@ -1179,8 +1183,9 @@
 	{
 		$sql = 'SELECT Properties FROM '.$this->Application->getUnitOption('sqe', 'TableName').'
 				WHERE ClassName="USPS"';
-		$db =& $this->Application->GetADODBConnection();
-		return unserialize($db->GetOne($sql));
+		$params = $this->Conn->GetOne($sql);
+
+		return unserialize($params);
 	}
 
 	function _prepare_xml_param($value) {
@@ -1238,7 +1243,7 @@
 				WHERE ' . $object->IDField . ' = ' . $object->GetID();
 		$weight = $this->Application->Conn->GetOne($sql);
 
-		$f_weight = Kg2Pounds($weight);
+		$f_weight = kUtil::Kg2Pounds($weight);
 		$sOrder['ShippingWeight'] = $f_weight[0].'.'.$f_weight[1];
 
 		foreach ($ShippingInfo as $k => $ShippingRow) {
@@ -1273,7 +1278,7 @@
 
 			foreach ($order_items as $k => $order_item) {
 				$p_weight = Array();
-				$p_weight = Kg2Pounds($order_item['Weight']);
+				$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++;
 			}
Index: branches/5.2.x/units/discount_items/discount_items_event_handler.php
===================================================================
diff -u -N -r13845 -r14099
--- branches/5.2.x/units/discount_items/discount_items_event_handler.php	(.../discount_items_event_handler.php)	(revision 13845)
+++ branches/5.2.x/units/discount_items/discount_items_event_handler.php	(.../discount_items_event_handler.php)	(revision 14099)
@@ -1,6 +1,6 @@
 Create() ) {
 			$this->customProcessing($event,'after');
-			$event->status = erSUCCESS;
-			$event->redirect_params = Array('opener' => 's'); //stay!
+			$event->status = kEvent::erSUCCESS;
+			$event->setRedirectParams(Array('opener' => 's'), true);
 		}
 		else {
-			$event->status = erFAIL;
-			$this->Application->SetVar($event->Prefix_Special.'_SaveEvent','OnCreate');
+			$event->status = kEvent::erFAIL;
+			$this->Application->SetVar($event->getPrefixSpecial().'_SaveEvent','OnCreate');
 			$object->setID(0);
 		}
 	}
Index: branches/5.2.x/units/products/products_event_handler.php
===================================================================
diff -u -N -r14089 -r14099
--- branches/5.2.x/units/products/products_event_handler.php	(.../products_event_handler.php)	(revision 14089)
+++ branches/5.2.x/units/products/products_event_handler.php	(.../products_event_handler.php)	(revision 14099)
@@ -1,6 +1,6 @@
 getObject();
+		/* @var $object kDBItem */
 
 		$object->SetFieldsFromHash( $this->getSubmittedFields($event) );
 
@@ -107,7 +108,8 @@
 
 		$object->Validate();
 
-		if (!isset($object->FieldErrors['Qty']['pseudo'])){
+		if ( !$object->GetErrorPseudo('Qty') ){
+			// only update, when no error on that field
 			$this->modifyInventory($event->Name, $object, $object->GetDBField('Qty'), $combination_id);
 		}
 
@@ -276,7 +278,7 @@
 
 			//reserve what's possible in any case
 			$this->Application->HandleEvent( $event, 'ord:OnReserveItems' );
-			if ($event->status == erSUCCESS) { //
+			if ($event->status == kEvent::erSUCCESS) { //
 				//in case the order is ready to process - process it
 				$this->Application->HandleEvent( $event, 'ord:OnOrderProcess' );
 			}
@@ -287,14 +289,18 @@
 	{
 		$id = $event->getEventParam('id');
 		$product =& $this->Application->recallObject($event->Prefix.'.itemlive', null, Array('skip_autoload' => true));
+		/* @var $product kCatDBItem */
+
 		$product->SwitchToLive();
 		if (!$product->Load($id)) return ; // this will make sure New product will not be overwritten with empty data
 
 		$temp =& $this->Application->recallObject($event->Prefix.'.itemtemp', null, Array('skip_autoload' => true));
+		/* @var $temp kCatDBItem */
+
 		$temp->SwitchToTemp();
 		$temp->Load($id);
 
-		$temp->SetDBFieldsFromHash($product->FieldValues, Array('QtyInStock','QtyReserved','QtyBackOrdered','QtyOnOrder'));
+		$temp->SetDBFieldsFromHash($product->GetFieldValues(), Array('QtyInStock','QtyReserved','QtyBackOrdered','QtyOnOrder'));
 		$temp->Update();
 	}
 
@@ -308,7 +314,7 @@
 	function OnSave(&$event)
 	{
 		$res = parent::OnSave($event);
-		if ($event->status == erSUCCESS) {
+		if ($event->status == kEvent::erSUCCESS) {
 			$this->RunScheduledInventoryActions($event);
 		}
 		return $res;
@@ -322,14 +328,19 @@
 	}
 
 
+	/**
+	 * Enter description here...
+	 *
+	 * @param kEvent $event
+	 */
 	function OnPreSaveAndGo(&$event) {
 
 		$event->CallSubEvent('OnPreSave');
 		$this->LoadItem($event);
 		$object =& $event->getObject();
 		$from_type = $object->GetDBField('Type');
-		if ($event->status==erSUCCESS) {
-			$this->Application->SetVar($event->Prefix_Special.'_id', $this->Application->GetVar($event->getPrefixSpecial(true).'_GoId'));
+		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');
 
@@ -554,10 +565,12 @@
 	 */
 	function OnRateProduct(&$event)
 	{
-		$event->redirect_params = Array('pass' => 'all,p');
+		$event->setRedirectParams(Array('pass' => 'all,p'), true);
 		$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
@@ -603,23 +616,33 @@
 		}
 		else
 		{
-			$event->status == erFAIL;
+			$event->status == kEvent::erFAIL;
 			$event->redirect=false;
-			$object->FieldErrors['CachedRating']['pseudo'] = 'too_frequent';
-			$object->ErrorMsgs['too_frequent'] = $this->Application->Phrase('lu_ferror_rate_duplicate');
+			$object->SetError('CachedRating', 'too_frequent', 'lu_ferror_rate_duplicate');
 		}
 	}
 
+	/**
+	 * Enter description here...
+	 *
+	 * @param kEvent $event
+	 */
 	function OnCancelAction(&$event)
 	{
-		$event->redirect_params = Array('pass' => 'all,p');
+		$event->setRedirectParams(Array('pass' => 'all,p'), true);
 		$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');
@@ -639,23 +662,21 @@
 			$email_event = &$this->Application->EmailEventUser('PRODUCT.SUGGEST', $user_id, $send_params);
 			$email_event = &$this->Application->EmailEventAdmin('PRODUCT.SUGGEST');
 
-			if ($email_event->status == erSUCCESS){
-				$event->redirect_params = array('opener' => 's', 'pass' => 'all');
+			if ($email_event->status == kEvent::erSUCCESS){
+				$event->setRedirectParams(Array('opener' => 's', 'pass' => 'all'), true);
 				$event->redirect = $this->Application->GetVar('template_success');
 			}
 			else {
-//					$event->redirect_params = array('opener' => 's', 'pass' => 'all');
+//					$event->setRedirectParams(Array('opener' => 's', 'pass' => 'all'), true);
 //					$event->redirect = $this->Application->GetVar('template_fail');
 
-				$object->ErrorMsgs['send_error'] = $this->Application->Phrase('lu_email_send_error');
-				$object->FieldErrors['Email']['pseudo'] = 'send_error';
-				$event->status = erFAIL;
+				$object->SetError('Email', 'send_error', 'lu_email_send_error');
+				$event->status = kEvent::erFAIL;
 			}
 	    }
 	    else {
-			$object->ErrorMsgs['invalid_email'] = $this->Application->Phrase('lu_InvalidEmail');
-			$object->FieldErrors['Email']['pseudo'] = 'invalid_email';
-			$event->status = erFAIL;
+			$object->SetError('Email', 'invalid_email', 'lu_InvalidEmail');
+			$event->status = kEvent::erFAIL;
 	    }
 	}
 
@@ -1119,9 +1140,7 @@
 	{
 		//$event->CallSubEvent('OnUpdate');
 		$event->redirect = false;
-		//$event->redirect_params = Array('opener'=>'s','pass'=>'all,p');
-
-
+		//$event->setRedirectParams(Array('opener'=>'s','pass'=>'all,p'), true);
 	}
 
 	/**
@@ -1168,7 +1187,7 @@
 
 		$product_includes_in = $this->Conn->GetOne('SELECT COUNT(*) FROM '.TABLE_PREFIX.'Products WHERE PackageContent LIKE "%|'.$object->GetID().'%"');
 		if ($product_includes_in > 0){
-			$event->status=erFAIL;
+			$event->status=kEvent::erFAIL;
 		}
 	}
 
@@ -1185,7 +1204,7 @@
 			'__VIRTUAL__Price' => 'Price',
 			'__VIRTUAL__Cost' => 'Cost',
 		);
-		return array_merge_recursive2($columns, $new_columns);
+		return array_merge($columns, $new_columns);
 	}
 
 /**
@@ -1209,10 +1228,10 @@
 
 		$event->redirect = $this->Application->GetVar('t');
 		// pass ID too, in case if product is created by OnPreSave call to ensure proper editing
-		$event->redirect_params =	Array(
+		$event->setRedirectParams(	Array(
 											'pass' => 'all',
 											$event->getPrefixSpecial(true).'_id' => $object->GetID(),
-									);
+									), true);
 	}
 
 
Index: branches/5.2.x/units/affiliates/affiliates_event_handler.php
===================================================================
diff -u -N -r13845 -r14099
--- branches/5.2.x/units/affiliates/affiliates_event_handler.php	(.../affiliates_event_handler.php)	(revision 13845)
+++ branches/5.2.x/units/affiliates/affiliates_event_handler.php	(.../affiliates_event_handler.php)	(revision 14099)
@@ -1,6 +1,6 @@
 Application->GetVar('AgreeToAffiliateTerms') )
 			{
 				$this->Application->SetVar('MustAgreeToTerms', 1);
-				$event->MasterEvent->status = erFATAL;
+				$event->MasterEvent->status = kEvent::erFATAL;
 			}
 
 			if($require_affiliate && !$this->Application->GetVar('SSN') )
 			{
 				$this->Application->SetVar('SSNRequiredError', 1);
-				$event->MasterEvent->status = erFATAL;
+				$event->MasterEvent->status = kEvent::erFATAL;
 			}
 
-			if( ($event->MasterEvent->status == erFATAL) && $items_info ) $user_object->Validate();
+			if( ($event->MasterEvent->status == kEvent::erFATAL) && $items_info ) $user_object->Validate();
 		}
 
 		/**
@@ -245,7 +245,7 @@
 		 */
 		function OnRegisterAsAffiliate(&$event)
 		{
-			if($this->Application->GetVar('RegisterAsAffiliate') != 'on' || $event->MasterEvent->status != erSUCCESS)
+			if($this->Application->GetVar('RegisterAsAffiliate') != 'on' || $event->MasterEvent->status != kEvent::erSUCCESS)
 			{
 				return;
 			}
@@ -272,14 +272,14 @@
 			if(!$this->Application->GetVar('AgreeToAffiliateTerms'))
 			{
 				$this->Application->SetVar('MustAgreeToTerms', 1);
-				$event->status = erFATAL;
+				$event->status = kEvent::erFATAL;
 			}
 			if(!$this->Application->GetVar('SSN'))
 			{
 				$this->Application->SetVar('SSNRequiredError', 1);
-				$event->status = erFATAL;
+				$event->status = kEvent::erFATAL;
 			}
-			if($event->status == erFATAL)
+			if($event->status == kEvent::erFATAL)
 			{
 				return;
 			}
@@ -318,7 +318,7 @@
 			$email_event_admin =& $this->Application->EmailEventAdmin('AFFILIATE.PAYMENT.TYPE.CHANGED');
 
 			$event->redirect = $this->Application->GetVar('next_template');
-			$event->status = erSUCCESS;
+			$event->status = kEvent::erSUCCESS;
 		}
 
 		/**
@@ -392,7 +392,7 @@
 
 			if ($affiliate_ids && defined('DEBUG_MODE') && DEBUG_MODE && $this->Application->isDebugMode()) {
 				$this->Application->Debugger->appendHTML('Affiliates Pending Totals Reset: ');
-				print_pre($affiliate_ids);
+				$this->Application->Debugger->dumpVars($affiliate_ids);
 			}
 
 			$sql = 'UPDATE '.$affil_table.' SET AccumulatedAmount = 0, ItemsSold = 0, LastOrderDate = %s WHERE AffiliateId IN (%s)';
@@ -452,7 +452,7 @@
 		function iterateItems(&$event)
 		{
 			if ($this->Application->CheckPermission('SYSTEM_ACCESS.READONLY', 1)) {
-				$event->status = erFAIL;
+				$event->status = kEvent::erFAIL;
 				return;
 			}
 
@@ -499,12 +499,12 @@
 								$email_event_admin =& $this->Application->EmailEventAdmin('AFFILIATE.REGISTRATION.DENIED');
 								break;
 						}
-						$event->status=erSUCCESS;
-						$event->redirect_params = Array('opener' => 's'); //stay!
+						$event->status=kEvent::erSUCCESS;
+						$event->setRedirectParams(Array('opener' => 's'), true); //stay!
 					}
 					else
 					{
-						$event->status=erFAIL;
+						$event->status=kEvent::erFAIL;
 						$event->redirect=false;
 						break;
 					}
Index: branches/5.2.x/units/gateways/gw_classes/authorizenet.php
===================================================================
diff -u -N -r13845 -r14099
--- branches/5.2.x/units/gateways/gw_classes/authorizenet.php	(.../authorizenet.php)	(revision 13845)
+++ branches/5.2.x/units/gateways/gw_classes/authorizenet.php	(.../authorizenet.php)	(revision 14099)
@@ -1,6 +1,6 @@
 gw_responce = curl_post($gw_params['submit_url'], $post_fields);
+			$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']
@@ -99,7 +104,12 @@
 
 				if( $this->IsTestMode() ) $post_fields['x_test_request'] = 'True';
 
-				$this->gw_responce = curl_post($gw_params['submit_url'], $post_fields);
+				$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']
@@ -150,7 +160,7 @@
 				unset($gw_responce[$field_index]);
 			}
 			$this->parsed_responce = $ret;
-			return array_merge_recursive2($ret, $gw_responce); // returns unparsed fields with they original indexes together with parsed ones
+			return kUtil::array_merge_recursive($ret, $gw_responce); // returns unparsed fields with they original indexes together with parsed ones
 		}
 
 		function getGWResponce()
Index: branches/5.2.x/units/products/products_tag_processor.php
===================================================================
diff -u -N -r13845 -r14099
--- branches/5.2.x/units/products/products_tag_processor.php	(.../products_tag_processor.php)	(revision 13845)
+++ branches/5.2.x/units/products/products_tag_processor.php	(.../products_tag_processor.php)	(revision 14099)
@@ -1,6 +1,6 @@
 Application->GetADODBConnection();
-		return $conn->GetOne("SELECT Name FROM ".TABLE_PREFIX."Category WHERE CategoryId=".$this->Application->GetVar("m_cat_id"));
+	function CurrentCategory($params)
+	{
+		$sql = "SELECT Name
+				FROM ".TABLE_PREFIX."Category
+				WHERE CategoryId=".$this->Application->GetVar("m_cat_id");
+
+		return $this->Conn->GetOne($sql);
 	}
 
 	function RateForm($params)
@@ -260,9 +264,9 @@
 
 	function SearchMoreLink($params)
 	{
-		$object =& $this->Application->recallObject( $this->getPrefixSpecial() , $this->Prefix.'_List', $params );
+		$object =& $this->GetList($params);
 		$o = '';
-		if($object->PerPage < $this->SearchResultsCount())
+		if($object->GetPerPage() < $this->SearchResultsCount())
 		{
 			$o = $this->Application->ParseBlock( Array('name' => $params['block']) );
 		}
@@ -333,20 +337,6 @@
 		return $main_processor->T($params);
 	}
 
-	/*
-	function MoreLink($params)
-	{
-		$object =& $this->Application->recallObject( $this->getPrefixSpecial() , $this->Prefix.'_List', $params );
-		$favorites_tag_processor =& $this->Application->recallObject('fav_TagProcessor');
-		$o = '';
-		if($object->PerPage < $favorites_tag_processor->FavoriteProductCount( Array('filter' => 'all') ))
-		{
-			$o = $this->Application->ParseBlock( Array('name' => $params['block']) );
-		}
-		return $o;
-	}
-	*/
-
 	function GetMarkedVal($params)
 	{
 		$list =& $this->GetList($params);
Index: branches/5.2.x/units/gift_certificates/gift_certificates_tp.php
===================================================================
diff -u -N -r13845 -r14099
--- branches/5.2.x/units/gift_certificates/gift_certificates_tp.php	(.../gift_certificates_tp.php)	(revision 13845)
+++ branches/5.2.x/units/gift_certificates/gift_certificates_tp.php	(.../gift_certificates_tp.php)	(revision 14099)
@@ -1,6 +1,6 @@
 Application->recallObject($this->getPrefixSpecial());
-		$formatter =& $this->Application->makeClass('kDateFormatter');
+		$object =& $this->getObject($params);
+		$formatter =& $this->Application->recallObject('kDateFormatter');
+
 		return $formatter->Format( adodb_mktime() + $this->Application->ConfigValue('Comm_DefaultCouponDuration') * 3600 * 24, 'Expiration_date', $object);
 	}
 
 	function DefaultExpTime($params)
 	{
-		$object = &$this->Application->recallObject($this->getPrefixSpecial());
-		$formatter =& $this->Application->makeClass('kDateFormatter');
+		$object =& $this->getObject($params);
+		$formatter =& $this->Application->recallObject('kDateFormatter');
+
 		return $formatter->Format( adodb_mktime() + $this->Application->ConfigValue('Comm_DefaultCouponDuration') * 3600 * 24, 'Expiration_time', $object);
 	}
 
Index: branches/5.2.x/units/orders/orders_item.php
===================================================================
diff -u -N -r13845 -r14099
--- branches/5.2.x/units/orders/orders_item.php	(.../orders_item.php)	(revision 13845)
+++ branches/5.2.x/units/orders/orders_item.php	(.../orders_item.php)	(revision 14099)
@@ -1,6 +1,6 @@
 ErrorMsgs['credit_card_validation_error'] = $this->Application->Phrase('lu_cc_validation_error');
 			$this->ErrorMsgs['credit_card_expired'] = $this->Application->Phrase('lu_cc_expired');
 		}
@@ -30,15 +31,15 @@
 		 * @return string
 		 * @access public
 		 */
-		function GetErrorMsg($field)
+		public function GetErrorMsg($field, $force_escape = null)
 		{
-			if( $field != 'OrderNumber' ) return parent::GetErrorMsg($field);
+			if( $field != 'OrderNumber' ) return parent::GetErrorMsg($field, $force_escape);
 
-			$number['error'] = parent::GetErrorMsg('Number');
-			$number['pseudo'] = getArrayValue($this->FieldErrors['Number'], 'pseudo');
+			$number['error'] = parent::GetErrorMsg('Number', $force_escape);
+			$number['pseudo'] = $this->GetErrorPseudo('Number');
 
-			$subnumber['error'] = parent::GetErrorMsg('SubNumber');
-			$subnumber['pseudo'] = getArrayValue($this->FieldErrors['SubNumber'], 'pseudo');
+			$subnumber['error'] = parent::GetErrorMsg('SubNumber', $force_escape);
+			$subnumber['pseudo'] = $this->GetErrorPseudo('SubNumber');
 
 			// if pseudo match & not empty -> return 1st
 			// if one of pseudos not empty -> return it
@@ -293,7 +294,7 @@
 				}
 			}
 
-			if (defined('DEBUG_MODE') && constOn('DBG_PAYMENT_GW')) {
+			if (defined('DEBUG_MODE') && kUtil::constOn('DBG_PAYMENT_GW')) {
 				$gw_data = $this->getGatewayData();
 				$this->Application->registerClass( $gw_data['ClassName'], GW_CLASS_PATH.'/'.$gw_data['ClassFile'] );
 				$gateway_object =& $this->Application->recallObject( $gw_data['ClassName'] );
@@ -307,7 +308,7 @@
 			// Innocent until proven guilty
 			$cc_valid = true;
 
-			//  Get rid of any non-digits			
+			//  Get rid of any non-digits
 			$value = preg_replace('/[^\d]/', '', $value);
 
 			//  Perform card-specific checks, if applicable
@@ -338,7 +339,7 @@
 					break;
 
 				default:
-					$this->FieldErrors[$error_field]['pseudo'] = 'credit_card_validation_error';
+					$this->SetError($error_field, 'credit_card_validation_error');
 					return false;
 					break;
 			}
@@ -376,7 +377,7 @@
 			}
 			else
 			{
-				$this->FieldErrors[$error_field]['pseudo'] = 'credit_card_validation_error';
+				$this->SetError($error_field, 'credit_card_validation_error');
 				return false;
 			}
 		}
@@ -405,7 +406,7 @@
 
 					if ($cc_date < $now_date) {
 						$error_field = isset($params['error_field']) ? $params['error_field'] : $field;
-						$this->FieldErrors[$error_field]['pseudo'] = 'credit_card_expired';
+						$this->SetError($error_field, 'credit_card_expired');
 
 						return false;
 					}
Index: branches/5.2.x/units/taxesdestinations/taxes_dst_event_handler.php
===================================================================
diff -u -N -r13845 -r14099
--- branches/5.2.x/units/taxesdestinations/taxes_dst_event_handler.php	(.../taxes_dst_event_handler.php)	(revision 13845)
+++ branches/5.2.x/units/taxesdestinations/taxes_dst_event_handler.php	(.../taxes_dst_event_handler.php)	(revision 14099)
@@ -1,6 +1,6 @@
 Create() ) {
 					$this->customProcessing($event,'after');
-					$event->status = erSUCCESS;
 				}
 				else {
-					$event->status = erFAIL;
+					$event->status = kEvent::erFAIL;
 					$event->redirect = false;
-					$this->Application->SetVar($event->Prefix_Special.'_SaveEvent','OnCreate');
+					$this->Application->SetVar($event->getPrefixSpecial().'_SaveEvent','OnCreate');
 					$object->setID(0);
 				}
 			}
Index: branches/5.2.x/units/shipping_costs/shipping_costs_event_handler.php
===================================================================
diff -u -N -r13845 -r14099
--- branches/5.2.x/units/shipping_costs/shipping_costs_event_handler.php	(.../shipping_costs_event_handler.php)	(revision 13845)
+++ branches/5.2.x/units/shipping_costs/shipping_costs_event_handler.php	(.../shipping_costs_event_handler.php)	(revision 14099)
@@ -1,6 +1,6 @@
 Create() ) {
 					$this->customProcessing($event,'after');
-					$event->status = erSUCCESS;
+					$event->status = kEvent::erSUCCESS;
 				}
 				else {
-					$event->status = erFAIL;
+					$event->status = kEvent::erFAIL;
 					$event->redirect = false;
-					$this->Application->SetVar($event->Prefix_Special.'_SaveEvent','OnCreate');
+					$this->Application->SetVar($event->getPrefixSpecial().'_SaveEvent','OnCreate');
 					$object->setID(0);
 				}
 			}
@@ -146,7 +146,7 @@
 	/*	$shipping_event = new kEvent();
 		$shipping_event->Init('s');
 		$shipping_event->Name = 'OnPreSave';
-		$shipping_event->status = erFATAL;
+		$shipping_event->status = kEvent::erFATAL;
 		$this->Application->HandleEvent(&$shipping_event);*/
 	}
 
@@ -165,7 +165,7 @@
 		$sql = 'DELETE FROM '.$object->TableName.' WHERE ZoneID IN ('.implode(',', $res).')';
 		$this->Conn->Query($sql);
 
-		$event->redirect_params = Array('opener' => 's', 'pass_events' => false);
+		$event->setRedirectParams(Array('opener' => 's', 'pass_events' => false), true);
 		$event->status=erSUCCESS;
 	}
 
@@ -190,11 +190,16 @@
 		}
 	}
 
+	/**
+	 * Enter description here...
+	 *
+	 * @param kEvent $event
+	 */
 	function OnSaveCreated(&$event)
 	{
 		$event->CallSubEvent('OnCreate');
 		$event->redirect = false;
-		$event->redirect_params = Array('opener'=>'s','pass'=>'all');
+		$event->setRedirectParams(Array('opener'=>'s','pass'=>'all'), true);
 	}
 
 	function OnAfterCopyToTemp(&$event)
@@ -207,7 +212,7 @@
 		$lang_object =& $this->Application->recallObject('lang.current');
 		// by weight and US/UK system - we need to store recalculated price per Kg cause shipping calculation is done per Kg!
 		if ($shipping_obj->GetDBField('Type') == 1 && $lang_object->GetDBField('UnitSystem') == 2) {
-			$object->SetDBField('PerUnit', $object->GetDBField('PerUnit') * POUND_TO_KG);
+			$object->SetDBField('PerUnit', $object->GetDBField('PerUnit') * kUtil::POUND_TO_KG);
 			$object->Update(null, true);
 		}
 	}
@@ -223,7 +228,7 @@
 		$lang_object =& $this->Application->recallObject('lang.current');
 		// by weight and US/UK system - we need to store recalculated price per Kg cause shipping calculation is done per Kg!
 		if ($shipping_obj->GetDBField('Type') == 1 && $lang_object->GetDBField('UnitSystem') == 2) {
-			$object->SetDBField('PerUnit', $object->GetDBField('PerUnit') / POUND_TO_KG);
+			$object->SetDBField('PerUnit', $object->GetDBField('PerUnit') / kUtil::POUND_TO_KG);
 			$object->Update(null, true);
 		}
 	}
Index: branches/5.2.x/units/orders/orders_event_handler.php
===================================================================
diff -u -N -r14089 -r14099
--- branches/5.2.x/units/orders/orders_event_handler.php	(.../orders_event_handler.php)	(revision 14089)
+++ branches/5.2.x/units/orders/orders_event_handler.php	(.../orders_event_handler.php)	(revision 14099)
@@ -1,6 +1,6 @@
 MasterEvent->status == erSUCCESS) ) return false;
+		if( !($event->MasterEvent->status == kEvent::erSUCCESS) ) return false;
 
 		$ses_id = $this->Application->RecallVar('front_order_id');
 		if($ses_id)
@@ -245,7 +245,7 @@
 	 */
 	function OnUserLogin(&$event)
 	{
-		if( !($event->MasterEvent->status == erSUCCESS) ) {
+		if( !($event->MasterEvent->status == kEvent::erSUCCESS) ) {
 			return false;
 		}
 
@@ -280,14 +280,20 @@
 		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'] );
 
-		$payment_result = $gateway_object->DirectPayment($order->FieldValues, $gw_data['gw_params']);
+		$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);
@@ -374,9 +380,9 @@
 
 			//$this->Application->StoreVar('gw_error', getArrayValue($charge_result, 'data', 'responce_reason_text') );
 			$event->redirect = $this->Application->GetVar('failure_template');
-			$event->redirect_params['m_cat_id'] = 0;
+			$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 = erFAIL;
+				$event->status = kEvent::erFAIL;
 			}
 			return false;
 		}
@@ -420,7 +426,7 @@
 			$this->Application->StoreVar('last_order_user', $order->GetDBField('Username'));
 
 			$event->redirect = $this->Application->GetVar('success_template');
-			$event->redirect_params['m_cat_id'] = 0;
+			$event->SetRedirectParam('m_cat_id', 0);
 		}
 		else
 		{
@@ -506,7 +512,7 @@
 		$this->OnUpdateCart($event);
 		if ($event->getEventParam('RecalculateChangedCart'))
 		{
-			$event->SetRedirectParam('checkout_error', $event->redirect_params['checkout_error']);
+			$event->SetRedirectParam('checkout_error', $event->getRedirectParam('checkout_error'));
 		}
 		else
 		{
@@ -537,7 +543,7 @@
 			$event->redirect = $this->Application->GetVar('next_step_template');
 
 			$order_id = $this->Application->GetVar('order_id');
-			if($order_id !== false) $event->redirect_params['ord_id'] = $order_id;
+			if($order_id !== false) $event->SetRedirectParam('ord_id', $order_id);
 		}
 	}
 
@@ -610,10 +616,10 @@
 			return true;
 		}
 		else {
-			$event->redirect_params = Array('opener' => 's');
+			$event->setRedirectParams(Array('opener' => 's'), true);
 		}
 
-		if ($event->status == erSUCCESS) {
+		if ($event->status == kEvent::erSUCCESS) {
 			$this->createMissingAddresses($event);
 		}
 		else {
@@ -770,14 +776,14 @@
 			// of orders with items added through admin when approving them
 			$this->AddItemToOrder($event, $item_id, $qty, $this->Application->isAdminUser ? 1 : null);
 		}
-		if ($event->status == erSUCCESS && !$event->redirect) {
-			$event->redirect_params['pass'] = 'm';
-			$event->redirect_params['pass_category'] = 0; //otherwise mod-rewrite shop-cart URL will include category
+		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->redirect_params['opener'] = 'u';
+				$event->SetRedirectParam('opener', 'u');
 			}
 		}
 	}
@@ -861,11 +867,11 @@
 		}
 
 		if ($result) {
-			$event->status = erSUCCESS;
+			$event->status = kEvent::erSUCCESS;
 			$event->redirect = $this->Application->isAdminUser ? true : $this->Application->GetVar('shop_cart_template');
 		}
 		else {
-			$event->status = erFAIL;
+			$event->status = kEvent::erFAIL;
 		}
 		return $result;
 	}
@@ -902,8 +908,8 @@
 		$ord_item->SetDBField('OptionsSalt', $this->OptionsSalt($options));
 		$ord_item->Update();
 		$event->CallSubEvent('OnRecalculateItems');
-		if ($event->status == erSUCCESS && $this->Application->isAdminUser) {
-			$event->redirect_params['opener'] = 'u';
+		if ($event->status == kEvent::erSUCCESS && $this->Application->isAdminUser) {
+			$event->SetRedirectParam('opener', 'u');
 		}
 	}
 
@@ -1179,6 +1185,7 @@
 	function SetStepRequiredFields(&$event)
 	{
 		$order =& $event->getObject();
+		/* @var $order OrdersItem */
 
 		$cs_helper =& $this->Application->recallObject('CountryStatesHelper');
 		/* @var $cs_helper kCountryStatesHelper */
@@ -1202,7 +1209,7 @@
 			$has_tangibles = $order->HasTangibleItems();
 			$req_fields = array('ShippingTo', 'ShippingAddress1', 'ShippingCity', 'ShippingZip', 'ShippingCountry', 'ShippingPhone');
 			foreach ($req_fields as $field) {
-				$order->Fields[$field]['required'] = $has_tangibles;
+				$order->setRequired($field, $has_tangibles);
 			}
 
 			$order->setRequired('ShippingState', $cs_helper->CountryHasStates( $field_values['ShippingCountry'] ));
@@ -1212,7 +1219,7 @@
 		if ($this->Application->GetVar('check_billing_address')) {
 			$req_fields = array('BillingTo', 'BillingAddress1', 'BillingCity', 'BillingZip', 'BillingCountry', 'BillingPhone');
 			foreach ($req_fields as $field) {
-				$order->Fields[$field]['required'] = true;
+				$order->setRequired($field, true);
 			}
 
 			$order->setRequired('BillingState', $cs_helper->CountryHasStates( $field_values['BillingCountry'] ));
@@ -1235,7 +1242,7 @@
 			}
 
 			foreach ($req_fields as $field) {
-				$order->Fields[$field]['required'] = true;
+				$order->setRequired($field, true);
 			}
 		}
 	}
@@ -1334,7 +1341,7 @@
 
 		$combinations = $this->queryCombinations($order_items);
 
-		$event->status = erSUCCESS;
+		$event->status = kEvent::erSUCCESS;
 		while (!$order_items->EOL()) {
 			$rec = $order_items->getCurrentRecord();
 			$product_object->Load( $rec['ProductId'] );
@@ -1350,7 +1357,7 @@
 				// 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 = erFAIL; // if we can't reserve the full lack
+			if ($to_reserve < $lack) $event->status = kEvent::erFAIL; // if we can't reserve the full lack
 
 			//reserve in order
 			$order_item->SetDBFieldsFromHash($rec);
@@ -1366,7 +1373,7 @@
 
 				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->FieldValues;
+					$combinations[ $rec['ProductId'].'_'.$rec['OptionsSalt'] ] = $inv_object->GetFieldValues();
 				}
 			}
 			$order_items->GoNext();
@@ -1376,7 +1383,7 @@
 
 	function OnOrderPrint(&$event)
 	{
-		$event->redirect_params = Array('opener'=>'s');
+		$event->setRedirectParams(Array('opener'=>'s'), true);
 	}
 
 	/**
@@ -1440,7 +1447,7 @@
 				$this->DoPlaceOrder($event);
 			}
 		}
-		$event->status = erSUCCESS;
+		$event->status = kEvent::erSUCCESS;
 
 	}
 
@@ -1563,7 +1570,7 @@
 
 			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->FieldValues;
+				$combinations[ $rec['ProductId'].'_'.$rec['OptionsSalt'] ] = $inv_object->GetFieldValues();
 			}
 
 			$order_items->GoNext();
@@ -1609,7 +1616,7 @@
 			$product_h =& $this->Application->recallObject('p_EventHandler');
 			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->FieldValues;
+				$combinations[ $rec['ProductId'].'_'.$rec['OptionsSalt'] ] = $inv_object->GetFieldValues();
 
 				// using freed qty to fullfill possible backorders
 				$product_h->FullfillBackOrders($product_object, $inv_object->GetID());
@@ -1637,7 +1644,7 @@
 	function MassInventoryAction(&$event)
 	{
 		if ($this->Application->CheckPermission('SYSTEM_ACCESS.READONLY', 1)) {
-			$event->status = erFAIL;
+			$event->status = kEvent::erFAIL;
 			return;
 		}
 
@@ -1659,7 +1666,7 @@
 	function InventoryAction(&$event)
 	{
 		if ($this->Application->CheckPermission('SYSTEM_ACCESS.READONLY', 1)) {
-			$event->status = erFAIL;
+			$event->status = kEvent::erFAIL;
 			return;
 		}
 
@@ -1692,7 +1699,7 @@
 		$object->SetDBField('Status', $event_status_map[$event->Name]);
 
 		$set_new_status = false;
-		$event->status = erSUCCESS;
+		$event->status = kEvent::erSUCCESS;
 
 		$email_params = $this->OrderEmailParams($object);
 
@@ -1719,7 +1726,7 @@
 				$this->Application->registerClass( $gw_data['ClassName'], GW_CLASS_PATH.'/'.$gw_data['ClassFile'] );
 				$gateway_object =& $this->Application->recallObject( $gw_data['ClassName'] );
 
-				$charge_result = $gateway_object->Charge($object->FieldValues, $gw_data['gw_params']);
+				$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);
@@ -1779,7 +1786,7 @@
 					$this->Application->registerClass( $gw_data['ClassName'], GW_CLASS_PATH.'/'.$gw_data['ClassFile'] );
 					$gateway_object =& $this->Application->recallObject( $gw_data['ClassName'] );
 
-					$gateway_object->OrderDeclined($object->FieldValues, $gw_data['gw_params']);
+					$gateway_object->OrderDeclined($object->GetFieldValues(), $gw_data['gw_params']);
 				}
 
 				// !!! LOOK HERE !!!
@@ -1832,7 +1839,7 @@
 					$this->Application->registerClass( $gw_data['ClassName'], GW_CLASS_PATH.'/'.$gw_data['ClassFile'] );
 					$gateway_object =& $this->Application->recallObject( $gw_data['ClassName'] );
 
-					$gateway_object->OrderShipped($object->FieldValues, $gw_data['gw_params']);
+					$gateway_object->OrderShipped($object->GetFieldValues(), $gw_data['gw_params']);
 				}
 				else {
 					$sqe_errors = $this->Application->RecallVar('sqe_errors');
@@ -1847,10 +1854,10 @@
 			case 'OnOrderProcess':
 				if ($this->ReadyToProcess($object->GetID())) {
 					$event->CallSubEvent('OnReserveItems');
-					if ($event->status == erSUCCESS) $set_new_status = true;
+					if ($event->status == kEvent::erSUCCESS) $set_new_status = true;
 					$email_event_user =& $this->Application->EmailEventUser('BACKORDER.PROCESS', $object->GetDBField('PortalUserId'), $email_params);
 				} else {
-					$event->status = erFAIL;
+					$event->status = kEvent::erFAIL;
 				}
 				break;
 		}
@@ -1930,8 +1937,8 @@
 
 		foreach($search_filter as $filter_name => $filter_params)
 		{
-			$filter_type = $filter_params['type'] == 'where' ? WHERE_FILTER : HAVING_FILTER;
-			$object->addFilter($filter_name, $filter_params['value'], $filter_type, FLT_VIEW);
+			$filter_type = $filter_params['type'] == 'where' ? kDBList::WHERE_FILTER : kDBList::HAVING_FILTER;
+			$object->addFilter($filter_name, $filter_params['value'], $filter_type, kDBList::FLT_VIEW);
 		}
 	}
 
@@ -2391,7 +2398,7 @@
 			if ($this->UseTempTables($event) && $next_sub_number == 0) {
 				$sub_order =& $order;
 			}
-			$sub_order->SetDBFieldsFromHash($order->FieldValues);
+			$sub_order->SetDBFieldsFromHash($order->GetFieldValues());
 			$sub_order->SetDBField('SubNumber', $next_sub_number);
 			$sub_order->SetDBField('SubTotal', $sub_order_data['TotalAmount']);
 
@@ -2559,121 +2566,6 @@
 		}
 	}
 
-	/**
-	 * Updates product info in shopping cart
-	 *
-	 * @param kEvent $event
-	 * @param unknown_type $prod_id
-	 * @param unknown_type $back_order
-	 * @param unknown_type $qty
-	 * @param unknown_type $price
-	 * @param unknown_type $discounted_price
-	 * @param unknown_type $discount_type
-	 * @param unknown_type $discount_id
-	 * @param unknown_type $order_item_id
-	 * @param unknown_type $options_salt
-	 * @param unknown_type $passed_item_data
-	 * @param unknown_type $cost
-	 * @return unknown
-	 */
-	function UpdateOrderItem(&$event, $prod_id, $back_order, $qty, $price, $discounted_price, $discount_type, $discount_id, $order_item_id = 0, $options_salt = 0, $passed_item_data=null, $cost=0)
-	{
-		$price = (float) $price;
-		$discounted_price = (float) $discounted_price;
-		$qty = (int) $qty;
-
-		$ord_id = $this->getPassedId($event);
-
-		$table_prefix = $this->TablePrefix($event);
-
-		if($order_item_id)
-		{
-			$query = '	SELECT OrderItemId, Quantity, FlatPrice, Price, BackOrderFlag, ItemData FROM '.$table_prefix.'OrderItems
-						WHERE OrderItemId = '.$order_item_id;
-		}
-		else
-		{
-			// try to load specified Product by its Id and BackOrderFlag in the order
-			$query = 'SELECT OrderItemId, Quantity, FlatPrice, Price, BackOrderFlag, ItemData FROM '.$table_prefix.'OrderItems
-								WHERE
-									OrderId = '.$ord_id.'
-									AND
-									ProductId = '.$prod_id.'
-									AND
-									BackOrderFlag '.($back_order ? ' >= 1' : ' = 0').'
-									AND
-									OptionsSalt = '.$options_salt;
-		}
-		$item_row = $this->Conn->GetRow($query);
-		$item_id = $item_row['OrderItemId'];
-
-		$object =& $this->Application->recallObject('orditems.-item', null, Array('skip_autoload' => true));
-		$item_data = $item_row['ItemData'];
-		if($item_data)
-		{
-			$item_data = unserialize($item_data);
-		}
-		$orig_discount_type = (int)getArrayValue($item_data, 'DiscountType');
-		$orig_discount_id = (int)getArrayValue($item_data, 'DiscountId');
-
-		if ($item_id) { // if Product already exists in the order
-			if ($qty > 0 &&
-				$item_row['Quantity'] == $qty &&
-				round($item_row['FlatPrice'], 3) == round($price, 3) &&
-				round($item_row['Price'], 3) == round($discounted_price, 3)	&&
-				$orig_discount_type == $discount_type &&
-				$orig_discount_id == $discount_id)
-			{
-				return false;
-			}
-			$object->Load($item_id);
-			if ($qty > 0) { // Update Price by _TOTAL_ qty
-				$object->SetDBField('Quantity', $qty);
-				$object->SetDBField('FlatPrice', $price );
-				$object->SetDBField('Price', $discounted_price );
-				$object->SetDBField('Cost', $cost);
-				if($item_data = $object->GetDBField('ItemData'))
-				{
-					$item_data = unserialize($item_data);
-				}
-				else
-				{
-					$item_data = Array();
-				}
-				$item_data['DiscountType'] = $discount_type;
-				$item_data['DiscountId'] = $discount_id;
-				$object->SetDBField('ItemData', serialize($item_data));
-				$object->Update();
-			}
-			else { // delete products with 0 qty
-				$object->Delete();
-			}
-		}
-		elseif ($qty > 0) { // if we are adding product
-			$product =& $this->Application->recallObject('p', null, Array ('skip_autoload' => true));
-			$product->Load($prod_id);
-			$object->SetDBField('ProductId', $prod_id);
-			$object->SetDBField('ProductName', $product->GetField('Name'));
-			$object->SetDBField('Quantity', $qty);
-			$object->SetDBField('FlatPrice', $price );
-			$object->SetDBField('Price', $discounted_price );
-			$object->SetDBField('Cost', $cost);
-			$object->SetDBField('OrderId', $ord_id);
-			$object->SetDBField('BackOrderFlag', $back_order);
-			if ($passed_item_data && !is_array($passed_item_data)) {
-				$passed_item_data = unserialize($passed_item_data);
-			}
-//			$item_data = Array('DiscountType' => $discount_type, 'DiscountId' => $discount_id);
-			$item_data = $passed_item_data;
-			$object->SetDBField('ItemData', serialize($item_data));
-			$object->Create();
-		}
-		else {
-			return false; // item requiring to set qty to 0, meaning already does not exist
-		}
-		return true;
-	}
-
 	function OptionsSalt($options, $comb_only=false)
 	{
 		$helper =& $this->Application->recallObject('kProductOptionsHelper');
@@ -2716,111 +2608,16 @@
 			return false;
 		}
 
-		$ord_id = $order->GetID();
+		$manager =& $this->Application->recallObject('OrderManager');
+		/* @var $manager OrderManager */
 
-		if ($item_data = $event->getEventParam('ItemData')) {
-			$item_data = unserialize($item_data);
-		}
-		else {
-			$item_data = Array ();
-		}
+		$manager->setOrder($order);
+		$manager->addProduct($product, $event->getEventParam('ItemData'), $qty, $package_num);
 
-		$options = getArrayValue($item_data, 'Options');
-		if (!$this->CheckOptions($event, $options, $item_id, $qty, $product->GetDBField('OptionsSelectionMode'))) return;
-
-		// Checking if such product already exists in the cart
-		$keys['OrderId'] = $ord_id;
-		$keys['ProductId'] = $product->GetId();
-
-		if (isset($item_data['Options'])) {
-			$options_salt = $this->OptionsSalt($item_data['Options']);
-			$keys['OptionsSalt'] = $options_salt;
-		}
-		else {
-			$options_salt = null;
-		}
-
-		$exists = $object->Load($keys);
-
-		$object->SetDBField('ProductId', $product->GetId());
-		$object->SetDBField('ProductName', $product->GetField('l'.$this->Application->GetDefaultLanguageId().'_Name'));
-		$object->SetDBField('Weight', $product->GetDBField('Weight'));
-		if (isset($item_data['Options'])) {
-			$object->SetDBField('OptionsSalt', $options_salt);
-		}
-
-		if (isset($package_num)) {
-			$object->SetDBField('PackageNum', $package_num);
-		}
-
-		if($product->GetDBField('Type') == PRODUCT_TYPE_TANGIBLE || $product->GetDBField('Type') == 6)
-		{
-			$object->SetDBField('Quantity', $object->GetDBField('Quantity') + $qty);
-		}
-		else // Types: 2,3,4
-		{
-			$object->SetDBField('Quantity', $qty); // 1
-			$exists = false;
-		}
-
-		if (isset($item_data['ForcePrice'])) {
-			$price = $item_data['ForcePrice'];
-		}
-		else {
-			$price = $this->GetPlainProductPrice($product->GetId(), $object->GetDBField('Quantity'), $product->GetDBField('Type'), $order, $options_salt, $item_data);
-		}
-
-		$cost = $this->GetProductCost($product->GetId(), $object->GetDBField('Quantity'), $product->GetDBField('Type'), $options_salt, $item_data);
-		$object->SetDBField('FlatPrice', $price);
-		$couponed_price = $this->GetCouponDiscountedPrice($order->GetDBField('CouponId'), $product->GetId(), $price);
-		$discounted_price = $this->GetDiscountedProductPrice($product->GetId(), $price, $discount_id, $order);
-		if( $couponed_price < $discounted_price )
-		{
-			$discounted_price = $couponed_price;
-			$discount_type = 'coupon';
-			$discount_id = $order->GetDBField('CouponId');
-		}
-		else
-		{
-			$discount_type = 'discount';
-			$discount_id = $discount_id;
-		}
-
-		$item_data['DiscountType'] = $discount_type;
-		$item_data['DiscountId'] = $discount_id;
-		$item_data['IsRecurringBilling'] = $product->GetDBField('IsRecurringBilling');
-
-		// it item is processed in order using new style, then put such mark in orderitem record
-		$processing_data = $product->GetDBField('ProcessingData');
-		if ($processing_data) {
-			$processing_data = unserialize($processing_data);
-			if (getArrayValue($processing_data, 'HasNewProcessing')) {
-				$item_data['HasNewProcessing'] = 1;
-			}
-		}
-		$object->SetDBField('ItemData', serialize($item_data));
-
-		$object->SetDBField('Price', $discounted_price);	// will be retrieved later
-		$object->SetDBField('Cost', $cost);
-
-		$object->SetDBField('BackOrderFlag', 0); // it will be updated in OnRecalculateItems later if needed
-		$object->SetDBField('OrderId', $ord_id);
-
-		if ($exists) {
-			if ($qty > 0) {
-				$object->Update();
-			}
-			else {
-				$object->Delete();
-			}
-		}
-		else {
-			$object->Create();
-		}
-
 		$this->Application->HandleEvent($ord_event, 'ord:OnRecalculateItems');
+
 		/*if ($ord_event->getEventParam('RecalculateChangedCart') && !$this->Application->isAdmin) {
-			$event->SetRedirectParam('checkout_error', $ord_event->redirect_params['checkout_error']);
+			$event->SetRedirectParam('checkout_error', $ord_event->getRedirectParam('checkout_error'));
 		}*/
 	}
 
@@ -2872,7 +2669,7 @@
 	 */
 	function OnRecalculateItems(&$event)
 	{
-		if (is_object($event->MasterEvent) && ($event->MasterEvent->status != erSUCCESS)) {
+		if (is_object($event->MasterEvent) && ($event->MasterEvent->status != kEvent::erSUCCESS)) {
 			// e.g. master order update failed, don't recalculate order products
 			return ;
 		}
@@ -2898,235 +2695,42 @@
 			return;
 		}
 
-		$table_prefix = $this->TablePrefix($event);
+		$manager =& $this->Application->recallObject('OrderManager');
+		/* @var $manager OrderManager */
 
-		// process only tangible products here
-		$poc_table = $this->Application->getUnitOption('poc', 'TableName');
-		$query = '	SELECT 	oi.ProductId, oi.OptionsSalt, oi.ItemData, SUM(oi.Quantity) AS Quantity,
-							IF(p.InventoryStatus = 2, poc.QtyInStock, p.QtyInStock) AS QtyInStock,
-							p.QtyInStockMin, p.BackOrder, p.InventoryStatus
-					FROM '.$table_prefix.'OrderItems AS oi
-					LEFT JOIN '.TABLE_PREFIX.'Products AS p ON oi.ProductId = p.ProductId
-					LEFT JOIN '.$poc_table.' poc ON (poc.CombinationCRC = oi.OptionsSalt) AND (oi.ProductId = poc.ProductId)
-							WHERE (oi.OrderId = '.$ord_id.') AND (p.Type = 1)
-							GROUP BY oi.ProductId, OptionsSalt';
-		$items = $this->Conn->Query($query);
+		$manager->setOrder($order);
+		$result = $manager->calculate();
 
-		$result = false;
-		$cost_total = 0;
-		$sub_total = 0;
-		$sub_total_flat = 0;
-		$coupon_discount = 0;
-		$pending_operations = Array();
-
-		$backordering = $this->Application->ConfigValue('Comm_Enable_Backordering');
-		$coupon_id = $order->GetDBField('CouponId');
-
-		foreach ($items as $row) {
-			$a_item_data = isset($row['ItemData']) ? unserialize($row['ItemData']) : Array();
-
-			$min_qty = $this->GetMinQty($row['ProductId']);
-			if ($row['Quantity'] > 0 && $row['Quantity'] < $min_qty) {
-				$row['Quantity'] = $min_qty;
-				$event->SetRedirectParam('checkout_error', 6);
-			}
-
-			$back_order = 0;
-			$to_order = 0;
-			if (!$row['InventoryStatus']) {
-				$available = $row['Quantity']*2; // always available;
-			}
-			else {
-				// if there are not enough qty AND backorder is auto or backorder is always
-				$available = $row['QtyInStock'] - $row['QtyInStockMin'];
-				$available = max(0, $available); // just in case
-			}
-			if (
-					$backordering && // backordering generally enabled
-					(
-						($row['Quantity'] > $available)
-						&&
-						($row['BackOrder'] == 2) //auto
-					)
-					||
-					$row['BackOrder'] == 1 // always
-				)
-			{ // split order into order & backorder
-				if ($row['BackOrder'] == 1) { //Always backorder
-					$available = 0;
-					$to_order = 0;
-					$back_order = $row['Quantity'];
-				}
-				else { //Auto
-					$to_order = $available;
-					$back_order = $row['Quantity'] - $available;
-				}
-
-				if (isset($a_item_data['ForcePrice'])) {
-					$price = $a_item_data['ForcePrice'];
-				}
-				else {
-					$price = $this->GetPlainProductPrice( $row['ProductId'], $to_order + $back_order, 1, $order, $row['OptionsSalt'], $row['ItemData'] );
-				}
-				$cost = $this->GetProductCost( $row['ProductId'], $to_order + $back_order, 1, $row['OptionsSalt'], $row['ItemData'] );
-				$discounted_price = $this->GetDiscountedProductPrice( $row['ProductId'], $price, $discount_id, $order );
-				$couponed_price = $this->GetCouponDiscountedPrice( $coupon_id, $row['ProductId'], $price );
-				if($couponed_price < $discounted_price)
-				{
-					$discounted_price =	$couponed_price;
-					$coupon_discount += ($price - $couponed_price) * ($to_order + $back_order);
-					$discount_type = 'coupon';
-					$discount_id = $coupon_id;
-				}
-				else
-				{
-					$discount_type = 'discount';
-				}
-				$pending_operations[] = Array( $row['ProductId'], 0, $to_order, $price, $discounted_price, $discount_type, $discount_id, 0, $row['OptionsSalt'], $row['ItemData'], $cost );
-				$pending_operations[] = Array( $row['ProductId'], 1, $back_order, $price, $discounted_price, $discount_type, $discount_id, 0, $row['OptionsSalt'], $row['ItemData'], $cost);
-			}
-			else { // store as normal order (and remove backorder)
-				// we could get here with backorder=never then we should order only what's available
-				$to_order = min($row['Quantity'], $available);
-				if (isset($a_item_data['ForcePrice'])) {
-					$price = $a_item_data['ForcePrice'];
-				}
-				else {
-					$price = $this->GetPlainProductPrice( $row['ProductId'], $to_order + $back_order, 1, $order, $row['OptionsSalt'], $row['ItemData'] );
-				}
-				$cost = $this->GetProductCost( $row['ProductId'], $to_order + $back_order, 1, $row['OptionsSalt'], $row['ItemData'] );
-				$discounted_price = $this->GetDiscountedProductPrice( $row['ProductId'], $price, $discount_id, $order );
-				$couponed_price = $this->GetCouponDiscountedPrice( $coupon_id, $row['ProductId'], $price );
-				if($couponed_price < $discounted_price)
-				{
-					$discounted_price =	$couponed_price;
-					$coupon_discount += ($price - $couponed_price) * ($to_order + $back_order);
-					$discount_type = 'coupon';
-					$discount_id = $coupon_id;
-				}
-				else
-				{
-					$discount_type = 'discount';
-				}
-				$pending_operations[] = Array( $row['ProductId'], 0, $to_order, $price, $discounted_price, $discount_type, $discount_id, 0, $row['OptionsSalt'], $row['ItemData'], $cost );
-				$pending_operations[] = Array( $row['ProductId'], 1, 0, $price, $discounted_price, $discount_type, $discount_id, 0, $row['OptionsSalt'], $row['ItemData'], $cost );	// this removes backorders
-				if ($to_order < $row['Quantity']) { // has changed
-					if ($to_order > 0) {
-						$event->SetRedirectParam('checkout_error', 2);
-					}
-					else {
-						$event->SetRedirectParam('checkout_error', 3);
-					}
-					$result = true;
-				}
-			}
-			$sub_total_flat += ($to_order + $back_order) * $price;
-			$sub_total += ($to_order + $back_order) * $discounted_price;
-			$cost_total += ($to_order + $back_order) * $cost;
+		if ( $manager->getError() ) {
+			$event->SetRedirectParam('checkout_error', $manager->getError());
 		}
 
-		// process subscriptions, services and downloadable: begin
-		$poc_table = $this->Application->getUnitOption('poc', 'TableName');
-		$query = '	SELECT oi.OrderItemId, oi.ProductId, oi.Quantity, oi.OptionsSalt, oi.ItemData,
-					IF(p.InventoryStatus = 2, poc.QtyInStock, p.QtyInStock) AS QtyInStock,
-					p.QtyInStockMin, p.BackOrder, p.InventoryStatus, p.Type
-					FROM '.$table_prefix.'OrderItems AS oi
-					LEFT JOIN '.TABLE_PREFIX.'Products AS p ON oi.ProductId = p.ProductId
-					LEFT JOIN '.$poc_table.' poc ON (poc.CombinationCRC = oi.OptionsSalt) AND (oi.ProductId = poc.ProductId)
-							WHERE (oi.OrderId = '.$ord_id.') AND (p.Type IN (2,3,4,5,6))';
-		$items = $this->Conn->Query($query);
-
-		foreach ($items as $row)
-		{
-			$a_item_data = isset($row['ItemData']) ? unserialize($row['ItemData']) : Array();
-			if (isset($a_item_data['ForcePrice'])) {
-				$price = $a_item_data['ForcePrice'];
-			}
-			else {
-				$price = $this->GetPlainProductPrice( $row['ProductId'], $row['Quantity'], $row['Type'], $order, $row['OptionsSalt'], $row['ItemData'] );
-			}
-			$cost = $this->GetProductCost( $row['ProductId'], $row['Quantity'], $row['Type'], $row['OptionsSalt'], $row['ItemData'] );
-			$discounted_price = $this->GetDiscountedProductPrice( $row['ProductId'], $price, $discount_id, $order );
-			$couponed_price = $this->GetCouponDiscountedPrice( $coupon_id, $row['ProductId'], $price );
-			if($couponed_price < $discounted_price)
-			{
-				$discounted_price =	$couponed_price;
-				$coupon_discount += ($price - $couponed_price);
-				$discount_type = 'coupon';
-				$discount_id = $coupon_id;
-			}
-			else
-			{
-				$discount_type = 'discount';
-			}
-			$pending_operations[] = Array( $row['ProductId'], 0, $row['Quantity'], $price, $discounted_price, $discount_type, $discount_id, $row['OrderItemId'], 0, $row['ItemData'], $cost );
-
-			$sub_total_flat += $price * $row['Quantity'];
-			$sub_total += $discounted_price * $row['Quantity'];
-			$cost_total += $cost * $row['Quantity'];
-		}
-		// process subscriptions, services and downloadable: end
-
-		$flat_discount = $this->GetWholeOrderPlainDiscount($global_discount_id, $order);
-		$flat_discount = ($flat_discount < $sub_total_flat) ? $flat_discount : $sub_total_flat;
-		$coupon_flat_discount = $this->GetWholeOrderCouponDiscount($coupon_id);
-		$coupon_flat_discount = ($coupon_flat_discount < $sub_total_flat) ? $coupon_flat_discount : $sub_total_flat;
-		if($coupon_flat_discount && $coupon_flat_discount > $flat_discount)
-		{
-			$flat_discount = $coupon_flat_discount;
-			$global_discount_type = 'coupon';
-			$global_discount_id = $coupon_id;
-		}
-		else
-		{
-			$global_discount_type = 'discount';
-		}
-		if($sub_total_flat - $sub_total < $flat_discount)
-		{
-			$coupon_discount = ($flat_discount == $coupon_flat_discount) ? $flat_discount : 0;
-			$sub_total = $sub_total_flat - $flat_discount;
-			foreach ($pending_operations as $operation_row)
-			{
-				list($product_id, $backorder, $qty, $price, $discounted_price, $dummy, $dummy, $order_item_id, $options_salt, $item_data, $cost) = $operation_row;
-				$new_price = ($price / $sub_total_flat) * $sub_total;
-				$result = $this->UpdateOrderItem($event, $product_id, $backorder, $qty, $price, $new_price, $global_discount_type, $global_discount_id, $order_item_id, $options_salt, $item_data, $cost) || $result;
-			}
-		}
-		else
-		{
-			foreach ($pending_operations as $operation_row)
-			{
-				list($product_id, $backorder, $qty, $price, $discounted_price, $discount_type, $discount_id, $order_item_id, $options_salt, $item_data, $cost) = $operation_row;
-				$result = $this->UpdateOrderItem($event, $product_id, $backorder, $qty, $price, $discounted_price, $discount_type, $discount_id, $order_item_id, $options_salt, $item_data, $cost) || $result;
-			}
-		}
-
-		$order->SetDBField('SubTotal', $sub_total);
-		$order->SetDBField('CostTotal', $cost_total);
-	//	$this->CalculateDiscount($event);
-		$order->SetDBField('DiscountTotal', $sub_total_flat - $sub_total);
-
-		if($coupon_id && $coupon_discount == 0)
-		{
+		if ($order->GetDBField('CouponId') && $order->GetDBField('CouponDiscount') == 0) {
 			$this->RemoveCoupon($order);
 			$event->SetRedirectParam('checkout_error', 8);
 		}
-		$order->SetDBField('CouponDiscount', $coupon_discount);
 
-		if ($result) $this->UpdateShippingOption($event);
+		if ($result) {
+			$this->UpdateShippingOption($event);
+		}
+
 		$this->UpdateShippingTotal($event);
 
 		$this->RecalculateProcessingFee($event);
 		$this->RecalculateTax($event);
 		$this->RecalculateGift($event);
 
-		if ($event->Name != 'OnAfterItemUpdate') $order->Update();
+		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')) {
+		if ($result && ($event->getEventParam('checkout_error') === false)) {
 			$event->SetRedirectParam('checkout_error', 1);
 		}
 
@@ -3152,301 +2756,7 @@
 		return $cost['TotalCost'];
 	}*/
 
-	function GetMinQty($p_id)
-	{
-		$query = 'SELECT
-							MIN(pp.MinQty)
-							FROM '.TABLE_PREFIX.'ProductsPricing AS pp
-							WHERE pp.ProductId = '.$p_id;
-		$min_qty = $this->Conn->GetOne($query);
-		if (!$min_qty) return 1;
-		return $min_qty;
-	}
-
 	/**
-	 * Return product cost for given qty, taking no discounts into account
-	 *
-	 * @param int $p_id ProductId
-	 * @param int $qty Quantity
-	 * @return float
-	 */
-	function GetProductCost($p_id, $qty, $product_type, $options_salt=null, $item_data=null)
-	{
-		$user_groups = $this->Application->RecallVar('UserGroups');
-		if($product_type == 1)
-		{
-			// $where_clause = 'pp.ProductId = '.$p_id.' AND pp.MinQty <= '.$qty;
-			// $orderby_clause = 'ORDER BY ('.$qty.' - pp.MinQty) ASC';
-			$where_clause = 'GroupId IN ('.$user_groups.') AND pp.ProductId = '.$p_id.' AND pp.MinQty <= '.$qty.' AND ('.$qty.' < pp.MaxQty OR pp.MaxQty=-1)';
-			$orderby_clause = 'ORDER BY pp.Price ASC';
-		}
-		else
-		{
-			$price_id = $this->GetPricingId($p_id, $item_data);
-			$where_clause = 'pp.ProductId = '.$p_id.' AND pp.PriceId = '.$price_id;
-			$orderby_clause = '';
-		}
-
-		$sql = 'SELECT Cost
-				FROM '.TABLE_PREFIX.'ProductsPricing AS pp
-				LEFT JOIN '.TABLE_PREFIX.'Products AS p
-				ON p.ProductId = pp.ProductId
-				WHERE '.$where_clause.'
-				'.$orderby_clause;
-
-		// GROUP BY pp.ProductId - removed, this it qty pricing is caclucated incorrectly !!!
-
-		$cost = $this->Conn->GetOne($sql);
-		if (!$cost) $price = 0;
-
-		return $cost;
-	}
-
-	/**
-	 * Return product price for given qty, taking no discounts into account
-	 *
-	 * @param int $p_id ProductId
-	 * @param int $qty Quantity
-	 * @return float
-	 */
-	function GetPlainProductPrice($p_id, $qty, $product_type, &$order_object, $options_salt=null, $item_data=null)
-	{
-		$user_id = $order_object->GetDBField('PortalUserId');
-		$user_groups = $this->Application->getUserGroups($user_id);
-
-		if($product_type == 1)
-		{
-			// $where_clause = 'pp.ProductId = '.$p_id.' AND pp.MinQty <= '.$qty;
-			// $orderby_clause = 'ORDER BY ('.$qty.' - pp.MinQty) ASC';
-			$where_clause = 'GroupId IN ('.$user_groups.') AND pp.ProductId = '.$p_id.' AND pp.MinQty <= '.$qty.' AND ('.$qty.' < pp.MaxQty OR pp.MaxQty=-1)';
-
-			// if we have to stick ti primary group this order by clause force its pricing to go first,
-			// but if there is no pricing for primary group it will take next optimal
-			if ($this->Application->ConfigValue('Comm_PriceBracketCalculation') == 1){
-				if ($user_id <= 0) {
-					$primary_group = $this->Application->ConfigValue('User_LoggedInGroup'); // actually this is Everyone
-				}
-				else {
-					$primary_group = $this->Conn->GetOne('SELECT GroupId FROM '.TABLE_PREFIX.'UserGroup WHERE PortalUserId='.$user_id.' AND PrimaryGroup=1');
-				}
-				$orderby_clause = 'ORDER BY (IF(GroupId='.$primary_group.',1,2)) ASC, pp.Price ASC';
-			}
-			else {
-				$orderby_clause = 'ORDER BY pp.Price ASC';
-			}
-
-		}
-		else
-		{
-			$price_id = $this->GetPricingId($p_id, $item_data);
-			$where_clause = 'pp.ProductId = '.$p_id.' AND pp.PriceId = '.$price_id;
-			$orderby_clause = '';
-		}
-
-		$sql = 'SELECT Price
-				FROM '.TABLE_PREFIX.'ProductsPricing AS pp
-				LEFT JOIN '.TABLE_PREFIX.'Products AS p
-				ON p.ProductId = pp.ProductId
-				WHERE '.$where_clause.'
-				'.$orderby_clause;
-
-		// GROUP BY pp.ProductId - removed, this it qty pricing is caclucated incorrectly !!!
-
-		$price = $this->Conn->GetOne($sql);
-		if (!$price) $price = 0;
-
-		if (isset($item_data) && !is_array($item_data)) {
-			$item_data = unserialize($item_data);
-		}
-
-		if (isset($item_data['Options'])) {
-			$addtion = 0;
-			$opt_helper =& $this->Application->recallObject('kProductOptionsHelper');
-			foreach ($item_data['Options'] as $opt => $val) {
-				$data = $this->Conn->GetRow('SELECT * FROM '.TABLE_PREFIX.'ProductOptions WHERE ProductOptionId = '.$opt);
-
-				$parsed = $opt_helper->ExplodeOptionValues($data);
-				if (!$parsed) continue;
-				$conv_prices = $parsed['Prices'];
-				$conv_price_types = $parsed['PriceTypes'];
-
-				if (is_array($val)) {
-					foreach ($val as $a_val) {
-						if (isset($conv_prices[unhtmlentities($a_val)]) && $conv_prices[unhtmlentities($a_val)]) {
-							if ($conv_price_types[unhtmlentities($a_val)] == '$') {
-								$addtion += $conv_prices[unhtmlentities($a_val)];
-							}
-							elseif ($conv_price_types[unhtmlentities($a_val)] == '%') {
-								$addtion += $price * $conv_prices[unhtmlentities($a_val)] / 100;
-							}
-						}
-					}
-				}
-				else {
-					if (isset($conv_prices[unhtmlentities($val)]) && $conv_prices[unhtmlentities($val)]) {
-						if ($conv_price_types[unhtmlentities($val)] == '$') {
-							$addtion += $conv_prices[unhtmlentities($val)];
-						}
-						elseif ($conv_price_types[unhtmlentities($val)] == '%') {
-							$addtion += $price * $conv_prices[unhtmlentities($val)] / 100;
-						}
-					}
-				}
-			}
-			$price += $addtion;
-		}
-
-		$comb_salt = $this->OptionsSalt( getArrayValue($item_data, 'Options'), 1);
-		if ($comb_salt) {
-			$query = 'SELECT * FROM '.TABLE_PREFIX.'ProductOptionCombinations WHERE CombinationCRC = '.$comb_salt;
-			$comb = $this->Conn->GetRow($query);
-			if ($comb) {
-				switch ($comb['PriceType']) {
-					case 1: // = override
-						$price = $comb['Price'];
-						break;
-					case 2: // flat
-						$price = $price + $comb['Price'];
-						break;
-					case 3: // percent
-						$price = $price * (1 + $comb['Price'] / 100);
-						break;
-				}
-			}
-		}
-
-		return max($price, 0);
-	}
-
-	/**
-	 * Return product price for given qty, taking possible discounts into account
-	 *
-	 * @param int $p_id ProductId
-	 * @param int $qty Quantity
-	 * @return float
-	 */
-	function GetDiscountedProductPrice($p_id, $price, &$discount_id, &$order_object)
-	{
-		$discount_id = 0;
-		$user_id = $order_object->GetDBField('PortalUserId');
-		$user_groups = $this->Application->getUserGroups($user_id);
-		$sql = '
-				SELECT
-					IF(pd.Type = 1,
-				 		'.$price.' - pd.Amount,
-				 		IF(pd.Type = 2,
-				 			('.$price.' * (1-pd.Amount/100)),
-				 			'.$price.'
-						)
-					) AS DiscountedPrice,
-					pd.DiscountId
-				FROM '.TABLE_PREFIX.'Products AS p
-				LEFT JOIN '.TABLE_PREFIX.'ProductsDiscountItems AS pdi ON
-					pdi.ItemResourceId = p.ResourceId OR pdi.ItemType = 0
-				LEFT JOIN '.TABLE_PREFIX.'ProductsDiscounts AS pd ON
-					pd.DiscountId = pdi.DiscountId
-					AND
-					(pdi.ItemType = 1 OR (pdi.ItemType = 0 AND pd.Type = 2))
-					AND
-					pd.Status = 1
-					AND
-					(	pd.GroupId IN ('.$user_groups.') AND
-						( (pd.Start IS NULL OR pd.Start < UNIX_TIMESTAMP())
-								AND
-							(pd.End IS NULL OR pd.End > UNIX_TIMESTAMP())
-						)
-					)
-				WHERE p.ProductId = '.$p_id.' AND pd.DiscountId IS NOT NULL
-			';
-
-		$pricing = $this->Conn->GetCol($sql, 'DiscountId');
-		if (!$pricing) return $price;
-
-		$discounted_price = min($pricing);
-		$pricing = array_flip($pricing);
-		$discount_id = $pricing[$discounted_price];
-
-		$discounted_price = min($discounted_price, $price);
-		return max($discounted_price, 0);
-	}
-
-	function GetCouponDiscountedPrice($coupon_id, $p_id, $price)
-	{
-		if(!$coupon_id) return $price;
-
-		$sql = '
-				SELECT
-					'.$price.' AS Price,
-					MIN(IF(pc.Type = 1,
-				 		'.$price.' - pc.Amount,
-				 		IF(pc.Type = 2,
-				 			('.$price.' * (1-pc.Amount/100)),
-				 			'.$price.'
-						)
-					)) AS DiscountedPrice
-				FROM '.TABLE_PREFIX.'Products AS p
-				LEFT JOIN '.TABLE_PREFIX.'ProductsCouponItems AS pci ON
-					pci.ItemResourceId = p.ResourceId OR pci.ItemType = 0
-				LEFT JOIN '.TABLE_PREFIX.'ProductsCoupons AS pc ON
-					pc.CouponId = pci.CouponId
-					AND
-					(pci.ItemType = 1 OR (pci.ItemType = 0 AND pc.Type = 2))
-				WHERE p.ProductId = '.$p_id.' AND pci.CouponId = '.$coupon_id.'
-				GROUP BY p.ProductId
-			';
-
-		$pricing = $this->Conn->GetRow($sql);
-		if ($pricing === false) return $price;
-		$price = min($pricing['Price'], $pricing['DiscountedPrice']);
-		return max($price, 0);
-	}
-
-	function GetWholeOrderPlainDiscount(&$discount_id, &$order_object)
-	{
-		$user_id = $order_object->GetDBField('PortalUserId');
-		$user_groups = $this->Application->getUserGroups($user_id);
-		$sql = '
-				SELECT pd.Amount AS Discount, pd.DiscountId
-				FROM '.TABLE_PREFIX.'ProductsDiscountItems AS pdi
-				LEFT JOIN '.TABLE_PREFIX.'ProductsDiscounts AS pd
-				ON
-					pd.DiscountId = pdi.DiscountId
-					AND
-					pdi.ItemType = 0 AND pd.Type = 1
-					AND
-					pd.Status = 1
-					AND
-					(	pd.GroupId IN ('.$user_groups.') AND
-						( (pd.Start IS NULL OR pd.Start < '.$order_object->GetDBField('OrderDate').')
-								AND
-							(pd.End IS NULL OR pd.End > '.$order_object->GetDBField('OrderDate').')
-						)
-					)
-				WHERE pd.DiscountId IS NOT NULL
-			';
-		$pricing = $this->Conn->GetCol($sql, 'DiscountId');
-		if (!$pricing) return 0;
-
-		$discounted_price = max($pricing);
-		$pricing = array_flip($pricing);
-		$discount_id = $pricing[$discounted_price];
-
-		return max($discounted_price, 0);
-	}
-
-	function GetWholeOrderCouponDiscount($coupon_id)
-	{
-		if (!$coupon_id) return 0;
-
-		$sql = 'SELECT Amount
-				FROM '.TABLE_PREFIX.'ProductsCouponItems AS pci
-				LEFT JOIN '.TABLE_PREFIX.'ProductsCoupons AS pc
-				ON pc.CouponId = pci.CouponId
-				WHERE pci.CouponId = '.$coupon_id.' AND pci.ItemType = 0 AND pc.Type = 1';
-		return $this->Conn->GetOne($sql);
-	}
-
-	/**
 	 * Return product pricing id for given product, if not passed - return primary pricing ID
 	 *
 	 * @param int $product_id ProductId
@@ -3579,7 +2889,12 @@
 	function RecalculateTax(&$event)
 	{
 		$object =& $event->getObject();
-		if ($object->GetDBField('Status') > ORDER_STATUS_PENDING) return;
+		/* @var $object OrdersItem */
+
+		if ($object->GetDBField('Status') > ORDER_STATUS_PENDING) {
+			return;
+		}
+
 		$object->RecalculateTax();
 	}
 
@@ -3600,10 +2915,12 @@
 	function UpdateTotals(&$event)
 	{
 		$object =& $event->getObject();
+		/* @var $object OrdersItem */
+
 		$object->UpdateTotals();
 	}
 
-	function CalculateDiscount(&$event)
+	/*function CalculateDiscount(&$event)
 	{
 		$object =& $event->getObject();
 
@@ -3645,7 +2962,7 @@
 
 		$object->SetDBField('CouponDiscount', $discount_amount);
 		return $discount_amount;
-	}
+	}*/
 
 	/**
 	 * Jumps to selected order in order's list from search tab
@@ -3698,11 +3015,11 @@
 				$object->SetDBField('Status', ORDER_STATUS_PENDING);
 				if( $object->Update() )
 				{
-					$event->status=erSUCCESS;
+					$event->status=kEvent::erSUCCESS;
 				}
 				else
 				{
-					$event->status=erFAIL;
+					$event->status=kEvent::erFAIL;
 					$event->redirect=false;
 					break;
 				}
@@ -3772,7 +3089,7 @@
 				$order->Load($order_id);
 				$this->Application->HandleEvent($complete_event, $event->Prefix.'.recurring:OnCompleteOrder' );
 
-				if ($complete_event->status == erSUCCESS) {
+				if ($complete_event->status == kEvent::erSUCCESS) {
 					//send recurring ok email
 					$email_event_user 	=& $this->Application->EmailEventUser('ORDER.RECURRING.PROCESSED', $order->GetDBField('PortalUserId'), $this->OrderEmailParams($order));
 					$email_event_admin 	=& $this->Application->EmailEventAdmin('ORDER.RECURRING.PROCESSED');
@@ -3992,13 +3309,14 @@
 			'__VIRTUAL__SubtotalWithoutDiscount' =>	'SubtotalWithoutDiscount',
 			'__VIRTUAL__OrderNumber' => 'OrderNumber',
 			);
-		return array_merge_recursive2($columns, $new_columns);
+
+		return array_merge($columns, $new_columns);
 	}
 
 	function OnSave(&$event)
 	{
 		$res = parent::OnSave($event);
-		if ($event->status == erSUCCESS) {
+		if ($event->status == kEvent::erSUCCESS) {
 			$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');
@@ -4089,7 +3407,7 @@
 	 */
 	function OnDownloadLabel(&$event)
 	{
-		$event->status = erSTOP;
+		$event->status = kEvent::erSTOP;
 		ini_set('memory_limit', '300M');
 		ini_set('max_execution_time', '0');
 
Index: branches/5.2.x/units/orders/orders_tag_processor.php
===================================================================
diff -u -N -r14089 -r14099
--- branches/5.2.x/units/orders/orders_tag_processor.php	(.../orders_tag_processor.php)	(revision 14089)
+++ branches/5.2.x/units/orders/orders_tag_processor.php	(.../orders_tag_processor.php)	(revision 14099)
@@ -1,6 +1,6 @@
 Application->recallObject('orditems', 'orditems_List');
 			/* @var $object kDBList */
 
-			return $object->RecordsCount;
+			return $object->GetRecordsCount();
 		}
 
 		function CartNotEmpty($params)
@@ -356,7 +356,7 @@
 				}
 				elseif ($regional->GetDBField('UnitSystem') == 2)
 				{
-					list($pounds, $ounces) = Kg2Pounds($block_params['weight']);
+					list($pounds, $ounces) = kUtil::Kg2Pounds($block_params['weight']);
 					$block_params['weight'] = 	$pounds.' '.$this->Application->Phrase('lu_pounds').' '.
 												$ounces.' '.$this->Application->Phrase('lu_ounces');
 				}
@@ -967,7 +967,7 @@
 			$gateway_object =& $this->Application->recallObject( $gw_data['ClassName'] );
 
 			$tpl = ''."\n";
-			$hidden_fields = $gateway_object->getHiddenFields($object->FieldValues, $params, $gw_data['gw_params']);
+			$hidden_fields = $gateway_object->getHiddenFields($object->GetFieldValues(), $params, $gw_data['gw_params']);
 
 			$ret = '';
 			if (!is_array($hidden_fields)) {
@@ -988,7 +988,7 @@
 			$this->Application->registerClass( $gw_data['ClassName'], GW_CLASS_PATH.'/'.$gw_data['ClassFile'] );
 			$gateway_object =& $this->Application->recallObject( $gw_data['ClassName'] );
 
-			return $gateway_object->NeedPlaceButton($object->FieldValues, $params, $gw_data['gw_params']);
+			return $gateway_object->NeedPlaceButton($object->GetFieldValues(), $params, $gw_data['gw_params']);
 		}
 
 		function HasGatewayError($params)
@@ -1215,7 +1215,7 @@
 			$addr_list->Query();
 
 			$object =& $this->getObject();
-			if (!$addr_list->CheckAddress($object->FieldValues, $address_type)) {
+			if (!$addr_list->CheckAddress($object->GetFieldValues(), $address_type)) {
 				$addr_list->CopyAddress($address_id, $address_type);
 			}
 		}
@@ -1258,7 +1258,7 @@
 			$cycle = ceil($order_item_data['Duration'] / 86400);
 			$cycle_units = 'D';
 
-			$item_data = $object->FieldValues;
+			$item_data = $object->GetFieldValues();
 			$item_data['item_name'] = $order_item['ProductName'];
 			$item_data['item_number'] = $order_item['OrderItemId'];
 			$item_data['custom'] = $order_item['OrderId'];
@@ -1308,7 +1308,7 @@
 
 			$max = $this->Application->ConfigValue('MaxAddresses');
 
-			return $max <= 0 ? true : $address_list->RecordsCount < $max;
+			return $max <= 0 ? true : $address_list->GetRecordsCount() < $max;
 		}
 
 		function FreePromoShippingAvailable($params)
@@ -1368,7 +1368,7 @@
 
 				case 2:
 					// uk system -> convert to pounds
-					list($pounds, $ounces) = Kg2Pounds($total_weight);
+					list($pounds, $ounces) = kUtil::Kg2Pounds($total_weight);
 					$total_weight = $pounds.' '.$this->Application->Phrase('lu_pounds').' '.$ounces.' '.$this->Application->Phrase('lu_ounces');
 					break;
 			}
Index: branches/5.2.x/units/sections/section_eh.php
===================================================================
diff -u -N -r14089 -r14099
--- branches/5.2.x/units/sections/section_eh.php	(.../section_eh.php)	(revision 14089)
+++ branches/5.2.x/units/sections/section_eh.php	(.../section_eh.php)	(revision 14099)
@@ -1,6 +1,6 @@
 Application->getUnitOption($event->MasterEvent->Prefix, 'Fields');
-			$this->Application->setUnitOption($event->MasterEvent->Prefix, 'Fields', array_merge_recursive2($fields, $new_fields));
+			$this->Application->setUnitOption($event->MasterEvent->Prefix, 'Fields', array_merge($fields, $new_fields));
 
 			$new_columns = Array (
 				'BillingCountry' => Array ('title' => 'la_col_BillingCountry', 'filter_block' => 'grid_options_filter', 'width' => 250, ),
@@ -89,12 +89,12 @@
 			);
 
 			$grids = $this->Application->getUnitOption($event->MasterEvent->Prefix, 'Grids');
-			$grids['Default']['Fields'] = array_merge_recursive2($grids['Default']['Fields'], $new_columns);
+			$grids['Default']['Fields'] = array_merge($grids['Default']['Fields'], $new_columns);
 			$this->Application->setUnitOption($event->MasterEvent->Prefix, 'Grids', $grids);
 
 			if (!$this->Application->isAdmin && is_object($this->Application->siteDomain)) {
 				// re-configure object, because it's recalled before kUnitConfigReader::AfterConfigRead is called
-				$this->Application->siteDomain->defineFields();
+				$this->Application->siteDomain->Configure();
 			}
 		}
 
Index: branches/5.2.x/units/reports/reports_config.php
===================================================================
diff -u -N -r14089 -r14099
--- branches/5.2.x/units/reports/reports_config.php	(.../reports_config.php)	(revision 14089)
+++ branches/5.2.x/units/reports/reports_config.php	(.../reports_config.php)	(revision 14099)
@@ -1,6 +1,6 @@
 	Array('formatter' => 'kDateFormatter', 'default' => '', 'filter_type' => 'range_from', 'filter_field' => 'OrderDate' ),
 						'ToDateTime'	=>	Array('formatter' => 'kDateFormatter', 'default' => '', 'filter_type' => 'range_to', 'filter_field' => 'OrderDate', 'empty_time' => adodb_mktime(23,59,59) ),
 						'Recursive' => Array (
-					    	'type' => 'int', 
-					    	'formatter' => 'kOptionsFormatter', 
+					    	'type' => 'int',
+					    	'formatter' => 'kOptionsFormatter',
 					    	'options' => Array (0 => 'la_No', 1 => 'la_Yes'),
 					    	'use_phrases' => 1, 'not_null' => 1, 'default' => 1,
 						),
 						'SkipEmpty' => Array (
-					    	'type' => 'int', 
-					    	'formatter' => 'kOptionsFormatter', 
+					    	'type' => 'int',
+					    	'formatter' => 'kOptionsFormatter',
 					    	'options' => Array (0 => 'la_No', 1 => 'la_Yes'),
 					    	'use_phrases' => 1, 'not_null' => 1, 'default' => 1,
 						),
Index: branches/5.2.x/units/shipping/shipping_config.php
===================================================================
diff -u -N -r14089 -r14099
--- branches/5.2.x/units/shipping/shipping_config.php	(.../shipping_config.php)	(revision 14089)
+++ branches/5.2.x/units/shipping/shipping_config.php	(.../shipping_config.php)	(revision 14099)
@@ -1,6 +1,6 @@
 	Array ('type' => 'float', 'formatter' => 'kFormatter', 'not_null' => 1, 'format' => '%.2f', 'default' => 0),
 						'IsFreePromoShipping' => Array (
 							'type' => 'int',
-							'formatter' => 'kOptionsFormatter', 
+							'formatter' => 'kOptionsFormatter',
 							'options' => Array (0 => 'la_No', 1 => 'la_Yes', ), 'use_phrases' => 1,
 							'default' => 0, 'not_null' => 1,
 						),
 						'InsuranceFee' => Array ('type' => 'float', 'default' => null),
 						'InsuranceType' => Array (
 							'type' => 'int',
 							'formatter' => 'kOptionsFormatter',
-							'options' => Array (2 => 'la_Percent', 1 => 'la_Flat',), 'use_phrases' => 1, 
+							'options' => Array (2 => 'la_Percent', 1 => 'la_Flat',), 'use_phrases' => 1,
 							'not_null' => 1, 'default' => 2
 						),
 					),
Index: branches/5.2.x/units/orders/order_manager.php
===================================================================
diff -u -N
--- branches/5.2.x/units/orders/order_manager.php	(revision 0)
+++ branches/5.2.x/units/orders/order_manager.php	(revision 14099)
@@ -0,0 +1,482 @@
+ 'state_changed',
+            2 => 'qty_unavailable',
+            3 => 'outofstock',
+            4 => 'invalid_code',
+            5 => 'code_expired',
+            6 => 'min_qty',
+            7 => 'code_removed',
+            8 => 'code_removed_automatically',
+            9 => 'changed_after_login',
+            10 => 'coupon_applied',
+            104 => 'invalid_gc_code',
+            105 => 'gc_code_expired',
+            107 => 'gc_code_removed',
+            108 => 'gc_code_removed_automatically',
+            110 => 'gift_certificate_applied',
+         );
+
+		/**
+		 * Order, used in calculator
+		 *
+		 * @var OrdersItem
+		 */
+		protected $order = null;
+
+		/**
+		 * Order calculator instance
+		 *
+		 * @var OrderCalculator
+		 */
+		protected $calculator = null;
+
+		/**
+		 * Operations to be performed on order items later
+		 *
+		 * @var Array
+		 */
+		protected $operations = Array ();
+
+		/**
+		 * Totals override
+		 *
+		 * @var Array
+		 */
+		protected $totalsOverride = Array ();
+
+		public function __construct()
+		{
+			parent::__construct();
+
+			$this->calculator =& $this->Application->makeClass('OrderCalculator');
+			$this->calculator->setManager($this);
+
+			$this->reset();
+		}
+
+		/**
+		 * Sets order to be used in calculator
+		 *
+		 * @param OrdersItem $order
+		 */
+		public function setOrder(&$order)
+		{
+			$this->order =& $order;
+
+			$this->reset();
+		}
+
+		function reset()
+		{
+			$this->errorCode = 0;
+			$this->operations = Array ();
+			$this->totalsOverride = Array ();
+
+			$this->calculator->reset();
+		}
+
+		public function resetOperationTotals()
+		{
+			$this->totalsOverride = Array ();
+		}
+
+		/**
+		 * Sets error from last operation
+		 *
+		 * @param int $error_code
+		 */
+		public function setError($error_code)
+		{
+			$this->errorCode = $error_code;
+		}
+
+		/**
+		 * Sets error from last operation
+		 *
+		 * @return int
+		 */
+		public function getError()
+		{
+			return $this->errorCode;
+		}
+
+		/**
+		 * Returns order object reference
+		 *
+		 * @return OrdersItem
+		 */
+		public function &getOrder()
+		{
+			return $this->order;
+		}
+
+		/**
+		 * Calculates given order
+		 *
+		 */
+		public function calculate()
+		{
+			$this->calculator->calculate();
+
+			$changed = $this->applyOperations() || ($this->getError() > 0);
+			$this->setOrderTotals();
+
+			return $changed;
+		}
+
+		public function addOperation($item, $backorder_flag, $qty, $price, $cost, $discount_info, $order_item_id = 0)
+		{
+			$operation = Array (
+				'ProductId' => $item['ProductId'],
+				'BackOrderFlag' => $backorder_flag,
+				'Quantity' => $qty,
+				'Price' => $price,
+				'Cost' => $cost,
+				'DiscountInfo' => $discount_info,
+				'OrderItemId' => $order_item_id,
+				'OptionsSalt' => $item['OptionsSalt'],
+				'ItemData' => $item['ItemData'],
+				'PackageNum' => array_key_exists('PackageNum', $item) ? $item['PackageNum'] : 1,
+			);
+
+			$this->operations[] = $operation;
+		}
+
+		/**
+		 * Returns total based on added operations
+		 *
+		 * @param string $type
+		 * @return float
+		 */
+		public function getOperationTotal($type)
+		{
+			if ( isset($this->totalsOverride[$type]) ) {
+				return $this->totalsOverride[$type];
+			}
+
+			$ret = 0;
+
+			foreach ($this->operations as $operation) {
+				if ($type == 'SubTotalFlat') {
+					$ret += $operation['Quantity'] * $operation['Price'];
+				}
+				elseif ($type == 'CostTotal') {
+					$ret += $operation['Quantity'] * $operation['Cost'];
+				}
+				elseif ($type == 'SubTotal') {
+					$ret += $operation['Quantity'] * $operation['DiscountInfo'][2]; // discounted price
+				}
+				elseif ($type == 'CouponDiscount') {
+					$ret += $operation['DiscountInfo'][3];
+				}
+			}
+
+			return $ret;
+		}
+
+		public function setOperationTotal($type, $value)
+		{
+			$this->totalsOverride[$type] = $value;
+		}
+
+		/**
+		 * Apply scheduled operations
+		 *
+		 */
+		public function applyOperations()
+		{
+			$ret = false;
+
+			$order_item =& $this->Application->recallObject('orditems.-item', null, Array('skip_autoload' => true));
+			/* @var $order_item kDBItem */
+
+			foreach ($this->operations as $operation) {
+				$item = $this->getOrderItemByOperation($operation);
+				$item_id = $item['OrderItemId'];
+
+				if ($item_id) { // if Product already exists in the order
+					if ( $this->noChangeRequired($item, $operation) ) {
+						continue;
+					}
+
+					$order_item->Load($item_id);
+
+					if ($operation['Quantity'] > 0) { // Update Price by _TOTAL_ qty
+						$item_data = $order_item->GetDBField('ItemData');
+						$item_data = $item_data ? unserialize($item_data) : Array ();
+						$item_data['DiscountId'] = $operation['DiscountInfo'][0];
+						$item_data['DiscountType'] = $operation['DiscountInfo'][1];
+
+
+						$fields_hash = Array (
+							'Quantity' => $operation['Quantity'],
+							'FlatPrice' => $operation['Price'],
+							'Price' => $operation['DiscountInfo'][2],
+							'Cost' => $operation['Cost'],
+							'ItemData' => serialize($item_data),
+						);
+
+						$order_item->SetDBFieldsFromHash($fields_hash);
+						$order_item->Update();
+					}
+					else { // delete products with 0 qty
+						$order_item->Delete();
+					}
+				}
+				elseif ($operation['Quantity'] > 0) {
+					// if we are adding product
+					// discounts are saved from OrdersEvetnHandler::AddItemToOrder method
+					$item_data = $operation['ItemData'];
+					$item_data = $item_data ? unserialize($item_data) : Array ();
+					$item_data['DiscountId'] = $operation['DiscountInfo'][0];
+					$item_data['DiscountType'] = $operation['DiscountInfo'][1];
+
+					$fields_hash = Array (
+						'ProductId' => $operation['ProductId'],
+						'ProductName' => $this->getProductField( $operation['ProductId'], 'Name' ),
+						'Quantity' => $operation['Quantity'],
+						'FlatPrice' => $operation['Price'],
+						'Price' => $operation['DiscountInfo'][2],
+						'Cost' => $operation['Cost'],
+						'Weight' => $this->getProductField( $operation['ProductId'], 'Weight' ),
+						'OrderId' => $this->order->GetID(),
+						'BackOrderFlag' => $operation['BackOrderFlag'],
+						'ItemData' => serialize($item_data),
+						'PackageNum' => $operation['PackageNum'],
+					);
+
+					$order_item->SetDBFieldsFromHash($fields_hash);
+					$order_item->Create();
+				}
+				else {
+					// item requiring to set qty to 0, meaning already does not exist
+					continue;
+				}
+
+				$ret = true;
+			}
+
+			return $ret;
+		}
+
+		/**
+		 * Sets order fields, containing total values
+		 *
+		 */
+		public function setOrderTotals()
+		{
+			$sub_total = $this->getOperationTotal('SubTotal');
+			$this->order->SetDBField('SubTotal', $sub_total);
+
+			$cost_total = $this->getOperationTotal('CostTotal');
+			$this->order->SetDBField('CostTotal', $cost_total);
+
+			$sub_total_flat = $this->getOperationTotal('SubTotalFlat');
+			$this->order->SetDBField('DiscountTotal', $sub_total_flat - $sub_total);
+
+			$coupon_discount = $this->getOperationTotal('CouponDiscount');
+			$this->order->SetDBField('CouponDiscount', $coupon_discount);
+		}
+
+		/**
+		 * Returns exising order item data, based on operation details
+		 *
+		 * @param Array $operation
+		 * @return Array
+		 */
+		protected function getOrderItemByOperation($operation)
+		{
+			if ( $operation['OrderItemId'] ) {
+				$where_clause = Array (
+					'OrderItemId = ' . $operation['OrderItemId'],
+				);
+			}
+			else {
+				$where_clause = Array (
+					'OrderId = ' . $this->order->GetID(),
+					'ProductId = ' . $operation['ProductId'],
+					'BackOrderFlag ' . ($operation['BackOrderFlag'] ? ' >= 1' : ' = 0'),
+					'OptionsSalt = ' . $operation['OptionsSalt'],
+				);
+			}
+
+			$sql = 'SELECT OrderItemId, Quantity, FlatPrice, Price, BackOrderFlag, ItemData
+					FROM ' . $this->getTable('orditems') . '
+					WHERE (' . implode(') AND (', $where_clause) . ')';
+
+			return $this->Conn->GetRow($sql);
+		}
+
+		/**
+		 * Checks, that there are no database changes required to order item from operation
+		 *
+		 * @param Array $item
+		 * @param Array $operation
+		 * @return bool
+		 */
+		protected function noChangeRequired($item, $operation)
+		{
+			$item_data = $item['ItemData'] ? unserialize( $item['ItemData'] ) : Array ();
+
+			$conditions = Array (
+				$operation['Quantity'] > 0,
+				$item['Quantity'] == $operation['Quantity'],
+				round($item['FlatPrice'], 3) == round($operation['Price'], 3),
+				round($item['Price'], 3) == round($operation['DiscountInfo'][2], 3),
+				(string)getArrayValue($item_data, 'DiscountType') == $operation['DiscountInfo'][1],
+				(int)getArrayValue($item_data, 'DiscountId') == $operation['DiscountInfo'][0],
+			);
+
+			foreach ($conditions as $condition) {
+				if (!$condition) {
+					return false;
+				}
+			}
+
+			return true;
+		}
+
+		/**
+		 * Returns product name by id
+		 *
+		 * @param int $product_id
+		 * @param string $field
+		 * @return string
+		 */
+		protected function getProductField($product_id, $field)
+		{
+			$product =& $this->Application->recallObject('p', null, Array ('skip_autoload' => true));
+			/* @var $product kCatDBItem */
+
+			if ( !$product->isLoaded() || ($product->GetID() != $product_id) ) {
+				$product->Load($product_id);
+			}
+
+			return $field == 'Name' ? $product->GetField($field) : $product->GetDBField($field);
+		}
+
+		/**
+		 * Returns table name according to order temp mode
+		 *
+		 * @param string $prefix
+		 * @return string
+		 */
+		public function getTable($prefix)
+		{
+			$table_name = $this->Application->getUnitOption($prefix, 'TableName');
+
+			if ( $this->order->IsTempTable() ) {
+				return $this->Application->GetTempName($table_name, 'prefix:' . $this->order->Prefix);
+			}
+
+			return $table_name;
+		}
+
+		/**
+		 * Adds product to order
+		 *
+		 * @param kCatDBItem $product
+		 * @param string $item_data
+		 * @param int $qty
+		 * @param int $package_num
+		 */
+		public function addProduct(&$product, $item_data, $qty = null, $package_num = null)
+		{
+			if ( !isset($qty) ) {
+				$qty = 1;
+			}
+
+			$item = $this->getItemFromProduct($product, $item_data);
+			$order_item = $this->getOrderItem($item);
+
+			if ( $this->calculator->canBeGrouped($item, $item) && $order_item ) {
+				$qty += $order_item['Quantity'];
+			}
+
+			$item['OrderItemId'] = $order_item ? $order_item['OrderItemId'] : 0;
+
+			if ( isset($package_num) ) {
+				$item['PackageNum'] = $package_num;
+			}
+
+			$this->calculator->addProduct($item, $product, $qty);
+			$this->applyOperations();
+		}
+
+		/**
+		 * Returns virtual $item based on given product
+		 *
+		 * @param kCatDBItem $product
+		 * @param string $item_data
+		 * @return Array
+		 */
+		protected function getItemFromProduct(&$product, $item_data)
+		{
+			$item_data_array = unserialize($item_data);
+
+			$options = isset($item_data_array['Options']) ? $item_data_array['Options'] : false;
+			$options_salt = $options ? $this->calculator->generateOptionsSalt($options) : 0;
+
+			$item = Array (
+				'ProductId' => $product->GetID(),
+				'OptionsSalt' => $options_salt,
+				'ItemData' => $item_data,
+				'Type' => $product->GetDBField('Type'),
+				'OrderItemId' => 0,
+			);
+
+			return $item;
+		}
+
+		/**
+		 * Returns OrderItem formed from $item
+		 *
+		 * @param Array $item
+		 * @return Array
+		 */
+		protected function getOrderItem($item)
+		{
+			$where_clause = Array (
+				'OrderId = ' . $this->order->GetID(),
+				'ProductId = ' . $item['ProductId'],
+			);
+
+			if ( $item['OptionsSalt'] ) {
+				$where_clause[] = 'OptionsSalt = ' . $item['OptionsSalt'];
+			}
+
+			$sql = 'SELECT Quantity, OrderItemId
+					FROM ' . $this->getTable('orditems') . '
+					WHERE (' . implode(') AND (', $where_clause) . ')';
+
+			return $this->Conn->GetRow($sql);
+		}
+	}
\ No newline at end of file
Index: branches/5.2.x/units/files/files_event_handler.php
===================================================================
diff -u -N -r13845 -r14099
--- branches/5.2.x/units/files/files_event_handler.php	(.../files_event_handler.php)	(revision 13845)
+++ branches/5.2.x/units/files/files_event_handler.php	(.../files_event_handler.php)	(revision 14099)
@@ -1,6 +1,6 @@
 status=erSUCCESS;
+		$event->status=kEvent::erSUCCESS;
 
 		$temp =& $this->Application->recallObject($event->getPrefixSpecial().'_TempHandler', 'kTempTablesHandler');
 
Index: branches/5.2.x/units/affiliate_plans/affiliate_plans_event_handler.php
===================================================================
diff -u -N -r13845 -r14099
--- branches/5.2.x/units/affiliate_plans/affiliate_plans_event_handler.php	(.../affiliate_plans_event_handler.php)	(revision 13845)
+++ branches/5.2.x/units/affiliate_plans/affiliate_plans_event_handler.php	(.../affiliate_plans_event_handler.php)	(revision 14099)
@@ -1,6 +1,6 @@
 OnBeforeItemUpdate($event);
 		}
 
-		function OnMassDelete($event)
+		function OnMassDelete(&$event)
 		{
 			if ($this->Application->CheckPermission('SYSTEM_ACCESS.READONLY', 1)) {
-				$event->status = erFAIL;
+				$event->status = kEvent::erFAIL;
 				return;
 			}
 
Index: branches/5.2.x/units/gateways/gw_classes/sella_guestpay.php
===================================================================
diff -u -N -r13845 -r14099
--- branches/5.2.x/units/gateways/gw_classes/sella_guestpay.php	(.../sella_guestpay.php)	(revision 13845)
+++ branches/5.2.x/units/gateways/gw_classes/sella_guestpay.php	(.../sella_guestpay.php)	(revision 14099)
@@ -1,6 +1,6 @@
 Application->recallObject('CurlHelper');
+			/* @var $curl_helper kCurlHelper */
 
+			$res = $curl_helper->Send($url);
+
 			preg_match('/#cryptstring#(.*)#\/cryptstring#/', $res, $matches);
 			$b = $matches[1];
 
@@ -89,7 +92,10 @@
 			$b = $_REQUEST['b'];
 			$url = 'https://ecomm.sella.it/CryptHTTPS/Decrypt.asp?a='.$a.'&b='.$b.'&c=2.0';
 
-			$ret = curl_post($url, array(), null, 'GET');
+			$curl_helper =& $this->Application->recallObject('CurlHelper');
+			/* @var $curl_helper kCurlHelper */
+
+			$ret = $curl_helper->Send($url);
 			$result = $this->parseGWResponce($ret);
 
 			list ($sid, $auth_code) = explode(',', $result['CUSTOM_INFO']);
Index: branches/5.2.x/units/affiliate_plans_items/affiliate_plans_items_event_handler.php
===================================================================
diff -u -N -r13845 -r14099
--- branches/5.2.x/units/affiliate_plans_items/affiliate_plans_items_event_handler.php	(.../affiliate_plans_items_event_handler.php)	(revision 13845)
+++ branches/5.2.x/units/affiliate_plans_items/affiliate_plans_items_event_handler.php	(.../affiliate_plans_items_event_handler.php)	(revision 14099)
@@ -1,6 +1,6 @@
 Create() ) {
 				$this->customProcessing($event, 'after');
-				$event->status = erSUCCESS;
-				$event->redirect_params = Array('opener' => 's'); //stay!
+				$event->status = kEvent::erSUCCESS;
+				$event->setRedirectParams(Array('opener' => 's'), true); //stay!
 			}
 			else {
-				$event->status = erFAIL;
-				$this->Application->SetVar($event->Prefix_Special.'_SaveEvent','OnCreate');
+				$event->status = kEvent::erFAIL;
+				$this->Application->SetVar($event->getPrefixSpecial().'_SaveEvent','OnCreate');
 				$object->setID(0);
 			}
 		}
Index: branches/5.2.x/units/gift_certificates/gift_certificates_eh.php
===================================================================
diff -u -N -r13845 -r14099
--- branches/5.2.x/units/gift_certificates/gift_certificates_eh.php	(.../gift_certificates_eh.php)	(revision 13845)
+++ branches/5.2.x/units/gift_certificates/gift_certificates_eh.php	(.../gift_certificates_eh.php)	(revision 14099)
@@ -1,6 +1,6 @@
 Load($code, 'Code');
 
 		if (!$object->isLoaded()) {
-			$event->status = erFAIL;
+			$event->status = kEvent::erFAIL;
 			$this->Application->SetVar('set_checkout_error', 104);
 			$event->redirect = false; // check!!!
 			return ;
@@ -110,7 +110,7 @@
 		if(	$object->GetDBField('Status') != 1 || ($expire_date && $expire_date < adodb_mktime()) ||
 		($debit <= 0))
 		{
-			$event->status = erFAIL;
+			$event->status = kEvent::erFAIL;
 			$this->Application->SetVar('set_checkout_error', 105);
 			$event->redirect->false;
 			return ;
@@ -201,7 +201,7 @@
 	{
 		parent::OnSave($event);
 
-		if ($event->status == erSUCCESS) {
+		if ($event->status == kEvent::erSUCCESS) {
  			$object =& $event->getObject();
  			/* @var $object kDBItem */
 
Index: branches/5.2.x/units/gateways/gw_classes/paymentech.php
===================================================================
diff -u -N -r13845 -r14099
--- branches/5.2.x/units/gateways/gw_classes/paymentech.php	(.../paymentech.php)	(revision 13845)
+++ branches/5.2.x/units/gateways/gw_classes/paymentech.php	(.../paymentech.php)	(revision 14099)
@@ -1,6 +1,6 @@
 PrepareXML($data);
-			$this->gw_responce = curl_post($gw_params['submit_url'], $xml, $headers);
+
+			$this->setGWResponce($gw_params, $headers, $xml);
 			$gw_responce = $this->parseGWResponce(null, $gw_params);
+
 			$this->CheckCVV_AVS($gw_params);
 			return ($this->parsed_responce['ProcStatus'] != 0 || $this->parsed_responce['ApprovalStatus'] != 1) ? false : true;
 		}
@@ -150,7 +152,8 @@
 				);
 
 				$xml = $this->PrepareXML($data);
-				$this->gw_responce = curl_post($gw_params['submit_url'], $xml, $headers);
+
+				$this->setGWResponce($gw_params, $headers, $xml);
 				$gw_responce = $this->parseGWResponce(null, $gw_params);
 
 				return ($gw_responce['ProcStatus'] != 0 || $gw_responce['ApprovalStatus'] != 1) ? false : true;
@@ -161,6 +164,17 @@
 			}
 		}
 
+		function setGWResponce($gw_params, $headers, $xml)
+		{
+			$curl_helper =& $this->Application->recallObject('CurlHelper');
+			/* @var $curl_helper kCurlHelper */
+
+			$curl_helper->SetHeaders($headers);
+			$curl_helper->SetPostData($xml);
+
+			$this->gw_responce = $curl_helper->Send( $gw_params['submit_url'] );
+		}
+
 		/**
 		 * Parse previosly saved gw responce into associative array
 		 *