Index: branches/5.2.x/units/affiliate_plans/affiliate_plans_event_handler.php =================================================================== --- branches/5.2.x/units/affiliate_plans/affiliate_plans_event_handler.php (revision 16515) +++ branches/5.2.x/units/affiliate_plans/affiliate_plans_event_handler.php (revision 16516) @@ -1,126 +1,126 @@ Special == 'active' ) { + /** @var kDBList $object */ $object = $event->getObject(); - /* @var $object kDBList */ $object->addFilter('active', '%1$s.Enabled = 1'); } } /** * Enter description here... * * @param kEvent $event */ function OnSetPrimary($event) { $object = $event->getObject(); $object->SetDBField('IsPrimary', 1); $object->Update(); } /** * Occurs before updating item * * @param kEvent $event * @return void * @access protected */ protected function OnBeforeItemUpdate(kEvent $event) { parent::OnBeforeItemUpdate($event); $this->itemChanged($event); } /** * Occurs before creating item * * @param kEvent $event * @return void * @access protected */ protected function OnBeforeItemCreate(kEvent $event) { parent::OnBeforeItemCreate($event); $this->itemChanged($event); } /** * Occurs before item is changed * * @param kEvent $event */ function itemChanged($event) { + /** @var kDBItem $object */ $object = $event->getObject(); - /* @var $object kDBItem */ $live_table = $this->Application->getUnitOption($event->Prefix, 'TableName'); $plans_count = $this->Conn->GetOne('SELECT COUNT(*) FROM ' . $live_table); if ( !$plans_count ) { $object->SetDBField('IsPrimary', 1); } if ( $object->GetDBField('IsPrimary') && $object->Validate() ) { $sql = 'UPDATE ' . $this->Application->getUnitOption($event->Prefix, 'TableName') . ' SET IsPrimary = 0'; $this->Conn->Query($sql); $object->SetDBField($object->getStatusField(), 1); } } /** * Don't allow to delete primary affiliate plan * * @param kEvent $event * @param string $type * @return void * @access protected */ protected function customProcessing(kEvent $event, $type) { if ( $event->Name == 'OnMassDelete' && $type == 'before' ) { $ids = $event->getEventParam('ids'); $sql = 'SELECT ' . $this->Application->getUnitOption($event->Prefix, 'IDField') . ' FROM ' . $this->Application->getUnitOption($event->Prefix, 'TableName') . ' WHERE IsPrimary = 1'; $primary_id = $this->Conn->GetOne($sql); $ids = array_diff($ids, Array ($primary_id)); $event->setEventParam('ids', $ids); } } } \ No newline at end of file Index: branches/5.2.x/units/affiliate_plans_items/affiliate_plans_items_tag_processor.php =================================================================== --- branches/5.2.x/units/affiliate_plans_items/affiliate_plans_items_tag_processor.php (revision 16515) +++ branches/5.2.x/units/affiliate_plans_items/affiliate_plans_items_tag_processor.php (revision 16516) @@ -1,48 +1,48 @@ Application->getUnitOption($this->Prefix, 'TableName'); if ($this->Application->IsTempMode($this->Prefix)) { $table_name = $this->Application->GetTempName($table_name, 'prefix:' . $this->Prefix); } $sql = 'SELECT COUNT(*) FROM ' . $table_name . ' WHERE (ItemType = 0) AND (AffiliatePlanId = ' . $this->Application->GetVar('ap_id') . ')'; return $this->Conn->GetOne($sql); } function ItemIcon($params) { + /** @var kDBList $object */ $object = $this->getObject($params); - /* @var $object kDBList */ if ($object->GetDBField('ItemType') == 2) { $cat_object = $this->Application->recallObject('c'); $cat_object->Load( $object->GetDBField('CategoryId') ); $cat_tag_processor = $this->Application->recallObject('c_TagProcessor'); return $cat_tag_processor->ItemIcon(); } return parent::ItemIcon($params); } } \ No newline at end of file Index: branches/5.2.x/units/gateways/gw_event_handler.php =================================================================== --- branches/5.2.x/units/gateways/gw_event_handler.php (revision 16515) +++ branches/5.2.x/units/gateways/gw_event_handler.php (revision 16516) @@ -1,85 +1,85 @@ getPassedID($event); $event->setPseudoClass('_List'); $items_info = $this->Application->GetVar( $event->getPrefixSpecial(true) ); $PaymentType_info = $this->Application->GetVar( 'pt' ); $GWConfigValue = $this->Application->recallObject('gwfv'); $GWConfigValue->SetDBField('PaymentTypeId', $this->Application->GetVar('pt_id')); //deleting old values $sql = 'DELETE FROM '.$GWConfigValue->TableName.' WHERE PaymentTypeId = '.$this->Application->GetVar('pt_id'); $res = $this->Conn->Query($sql); //selecting fields for selected gateway only $sql = 'SELECT GWConfigFieldId FROM '.TABLE_PREFIX.'GatewayConfigFields WHERE GatewayId = '.$PaymentType_info[$this->Application->GetVar('pt_id')]['GatewayId']; $res = $this->Conn->GetCol($sql); if($items_info) { foreach($res as $gw_field_id) { $field_values = $items_info[$gw_field_id]; $field_values['GWConfigFieldId'] = $gw_field_id; $GWConfigValue->SetFieldsFromHash($field_values); if( $GWConfigValue->Create() ) { $event->status=kEvent::erSUCCESS; } else { $event->status=kEvent::erFAIL; break; } } } } protected function OnCheckGateways($event) { if ( !$this->Application->isAdminUser ) { return; } $gateways = glob(GW_CLASS_PATH . DIRECTORY_SEPARATOR . '*.php'); if ( !$gateways ) { return; } foreach ($gateways as $gateway_file) { $class_name = false; include_once($gateway_file); if ( !$class_name ) { continue; } + /** @var kGWBase $tmp */ $tmp = new $class_name(); - /* @var $tmp kGWBase */ $tmp->Install(); } } } \ No newline at end of file Index: branches/5.2.x/units/gateways/gw_classes/notify_scripts/google_checkout_notify.php =================================================================== --- branches/5.2.x/units/gateways/gw_classes/notify_scripts/google_checkout_notify.php (revision 16515) +++ branches/5.2.x/units/gateways/gw_classes/notify_scripts/google_checkout_notify.php (revision 16516) @@ -1,50 +1,50 @@ Init(); $sql = 'SELECT PaymentTypeId FROM '.TABLE_PREFIX.'PaymentTypes AS pt LEFT JOIN '.TABLE_PREFIX.'Gateways AS g ON g.GatewayId = pt.GatewayId WHERE g.ClassName = "kGWGoogleCheckout"'; $payment_type_id = $application->Conn->GetOne($sql); $application->SetVar('payment_type_id', $payment_type_id); // keep, because kGWGoogleCheckout::processNewOrderNotification relies on this + /** @var OrdersItem $order */ $order = $application->recallObject('ord', null, Array ('skip_autoload' => true)); - /* @var $order OrdersItem */ $gw_data = $order->getGatewayData($application->GetVar('payment_type_id')); $application->registerClass( $gw_data['ClassName'], GW_CLASS_PATH.'/'.$gw_data['ClassFile'] ); $gateway_object = $application->recallObject( $gw_data['ClassName'] ); $transaction_status = $gateway_object->processNotification($gw_data['gw_params']); $sql = 'UPDATE '.$order->TableName.' SET TransactionStatus = '.$transaction_status.' WHERE '.$order->IDField.' = '.$order->GetID(); $application->Conn->Query($sql); $order->SetDBField('TransactionStatus', $transaction_status); if ($transaction_status == 1) { $application->SetVar('ord_id', $order->GetID()); // used in OrdersEventHandler::UpdateOrderItem $application->HandleEvent(new kEvent('ord:OnCompleteOrder')); } $application->Done(); \ No newline at end of file Index: branches/5.2.x/units/gateways/gw_classes/notify_scripts/google_checkout_shippings.php =================================================================== --- branches/5.2.x/units/gateways/gw_classes/notify_scripts/google_checkout_shippings.php (revision 16515) +++ branches/5.2.x/units/gateways/gw_classes/notify_scripts/google_checkout_shippings.php (revision 16516) @@ -1,37 +1,38 @@ Init(); $sql = 'SELECT PaymentTypeId FROM '.TABLE_PREFIX.'PaymentTypes AS pt LEFT JOIN '.TABLE_PREFIX.'Gateways AS g ON g.GatewayId = pt.GatewayId WHERE g.ClassName = "kGWGoogleCheckout"'; $payment_type_id = $application->Conn->GetOne($sql); + /** @var OrdersItem $order */ $order = $application->recallObject('ord', null, Array ('skip_autoload' => true)); - /* @var $order OrdersItem */ $gw_data = $order->getGatewayData($payment_type_id); $application->registerClass( $gw_data['ClassName'], GW_CLASS_PATH.'/'.$gw_data['ClassFile'] ); + + /** @var kGWGoogleCheckout $gateway_object */ $gateway_object = $application->recallObject( $gw_data['ClassName'] ); - /* @var $gateway_object kGWGoogleCheckout */ $gateway_object->processNotification($gw_data['gw_params'], 'shippings'); $application->Done(); \ No newline at end of file Index: branches/5.2.x/units/gateways/gw_classes/paymentech.php =================================================================== --- branches/5.2.x/units/gateways/gw_classes/paymentech.php (revision 16515) +++ branches/5.2.x/units/gateways/gw_classes/paymentech.php (revision 16516) @@ -1,327 +1,327 @@ Array('Name' => 'Patmentech/Orbital', 'ClassName' => 'kPaymentechGW', 'ClassFile' => 'paymentech.php', 'RequireCCFields' => 1), 'ConfigFields' => Array( 'submit_url' => Array('Name' => 'Submit URL', 'Type' => 'text', 'ValueList' => '', 'Default' => ''), 'user_account' => Array('Name' => 'Merchant ID', 'Type' => 'text', 'ValueList' => '', 'Default' => ''), 'user_bin' => Array('Name' => 'BIN Number', 'Type' => 'text', 'ValueList' => '', 'Default' => ''), 'shipping_control' => Array('Name' => 'Shipping Control', 'Type' => 'select', 'ValueList' => '3=la_CreditDirect,4=la_CreditPreAuthorize', 'Default' => '3'), 'deny_cvv' => Array('Name' => 'Decline the following CVV response codes (ex: N,P)', 'Type' => 'text', 'ValueList' => '', 'Default' => 'N,P,S'), 'deny_avs' => Array('Name' => 'Decline the following AVS response codes (ex: 1,3,R,5,6,G)', 'Type' => 'text', 'ValueList' => '', 'Default' => '1,2,3,4,R,5,6,7,8,A,C,D,E,F,G,Z'), ) ); return $data; } function DirectPayment($item_data, $gw_params) { // if( $this->IsTestMode() ) $post_fields['x_test_request'] = 'True'; $data = array( //sys default 'TzCode' => 705, 'CurrencyCode' => 840, 'CurrencyExponent' => 2, 'TxDateTime' => '', //gateway will set current timestamp //merchant info 'MerchantID' => $gw_params['user_account'], 'BIN' => $gw_params['user_bin'], //transaction // A - Authorize Only // AC - Authorize & Capture // C - Prior Auth Capture 'MessageType' => $gw_params['shipping_control'] == SHIPPING_CONTROL_PREAUTH ? 'A' : 'AC', 'Amount' => str_replace('.', '', sprintf('%.2f', $item_data['TotalAmount'])), 'AccountNum' => $item_data['PaymentAccount'], //card num 'Exp' => str_replace('/', '', $item_data['PaymentCCExpDate']), //expiration 'CardSecVal' => $item_data['PaymentCVV2'], //cvv2 //customer info 'AVSname' => $item_data['PaymentNameOnCard'], 'AVSaddress1' => $item_data['BillingAddress1'], 'AVSaddress2' => $item_data['BillingAddress2'], 'AVScity' => $item_data['BillingCity'], 'AVSstate' => $item_data['BillingState'], 'AVSzip' => $item_data['BillingZip'], // order info 'OrderID' => $item_data['OrderNumber'], 'ECOrderNum' => $item_data['OrderNumber'], 'Comments' => 'Invoice #'.$item_data['OrderNumber'], 'ShippingRef' => '', ); + /** @var kCountryStatesHelper $cs_helper */ $cs_helper = $this->Application->recallObject('CountryStatesHelper'); - /* @var $cs_helper kCountryStatesHelper */ $data['AVScountryCode'] = $cs_helper->getCountryIso( $item_data['BillingCountry'] ); if ($data['AVScountryCode'] != 'US') { $data['AVSstate'] = ''; } $headers = Array( 'POST /AUTHORIZE HTTP/1.0', 'MIME-Version: 1.0', 'Content-type: application/PTI34', 'Content-transfer-encoding: text', 'Request-number: 1', 'Document-type: Request' ); $xml = $this->PrepareXML($data); $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; } function CheckCVV_AVS($gw_params) { $cvv_reject = explode(',', $gw_params['deny_cvv']); if (in_array(trim($this->parsed_responce['CVV2RespCode']), $cvv_reject)) { $this->parsed_responce['ApprovalStatus'] = 0; } $avs_reject = explode(',', $gw_params['deny_avs']); if (in_array(trim($this->parsed_responce['AVSRespCode']), $avs_reject)) { $this->parsed_responce['ApprovalStatus'] = 0; } } /** * Perform SALE type transaction direct from php script wihtout redirecting to 3rd-party website * * @param Array $item_data * @param Array $gw_params * @return bool */ function Charge($item_data, $gw_params) { $gw_responce = unserialize( $item_data['GWResult1'] ); if( ( strtoupper($gw_responce['MessageType']) == 'A') ) { $data = array( //sys default 'TzCode' => 705, 'CurrencyCode' => 840, 'CurrencyExponent' => 2, 'TxDateTime' => '', //gateway will set current timestamp //merchant info 'MerchantID' => $gw_params['user_account'], 'BIN' => $gw_params['user_bin'], //transaction // A - Authorize Only // AC - Authorize & Capture // C - Prior Auth Capture 'Amount' => str_replace('.', '', sprintf('%.2f', $item_data['TotalAmount'])), 'MessageType' => 'C', 'OrderID' => $gw_responce['OrderID'], 'TxRefNum' => $gw_responce['TxRefNum'], ); $headers = Array( 'POST /AUTHORIZE HTTP/1.0', 'MIME-Version: 1.0', 'Content-type: application/PTI34', 'Content-transfer-encoding: text', 'Request-number: 1', 'Document-type: Request' ); $xml = $this->PrepareXML($data); $this->setGWResponce($gw_params, $headers, $xml); $gw_responce = $this->parseGWResponce(null, $gw_params); return ($gw_responce['ProcStatus'] != 0 || $gw_responce['ApprovalStatus'] != 1) ? false : true; } else { return true; } } function setGWResponce($gw_params, $headers, $xml) { + /** @var kCurlHelper $curl_helper */ $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 * * @param string $gw_responce * @param Array $gw_params * @return Array */ function parseGWResponce($gw_responce = null, $gw_params) { if( !isset($gw_responce) ) $gw_responce = $this->gw_responce; $parser = $this->Application->recallObject('kXMLHelper'); $parser->Clear(); $res = $parser->Parse($gw_responce); $parsed = array(); $parsed['ProcStatus'] = $res->FindChildValue('ProcStatus'); $parsed['StatusMsg'] = $res->FindChildValue('StatusMsg'); $parsed['ApprovalStatus'] = $res->FindChildValue('ApprovalStatus'); $parsed['RespCode'] = $res->FindChildValue('RespCode'); $parsed['AuthCode'] = $res->FindChildValue('AuthCode'); $parsed['AVSRespCode'] = $res->FindChildValue('AVSRespCode'); $parsed['CVV2RespCode'] = $res->FindChildValue('CVV2RespCode'); $parsed['StatusMsg'] = $res->FindChildValue('StatusMsg'); $parsed['RespMsg'] = $res->FindChildValue('RespMsg'); $parsed['TxRefNum'] = $res->FindChildValue('TxRefNum'); $parsed['TxRefIdx'] = $res->FindChildValue('TxRefIdx'); $parsed['RespTime'] = $res->FindChildValue('RespTime'); $parsed['Amount'] = $res->FindChildValue('Amount'); $parsed['OrderID'] = $res->FindChildValue('OrderNumber'); $parsed['MessageType'] = $res->FindChildValue('CommonMandatoryResponse', 'MessageType'); $this->parsed_responce = $parsed; return $parsed; } function getErrorMsg() { $code = $this->parsed_responce['ApprovalStatus']; switch ($this->parsed_responce['ApprovalStatus']) { case '0': return 'The transaction has been declined'; case '1': return 'The transaction has been approved'; default: return 'An error has occured while processing the transaction ('.$this->parsed_responce['StatusMsg'].')'; } } function getGWResponce() { return serialize($this->parsed_responce); } function GetTestCCNumbers() { return array('4012888888881', '4055011111111111', '5454545454545454', '5405222222222226', '371449635398431', '6011000995500000', '36438999960016', '3566002020140006'); } function PrepareXML($data) { if ($data['MessageType'] == 'A' || $data['MessageType'] == 'AC') { $xml = << {$data['AccountNum']} {$data['MerchantID']} 001 {$data['BIN']} {$data['OrderID']} {$data['Amount']} {$data['Exp']} {$data['TxDateTime']} {$data['Comments']} {$data['ShippingRef']} {$data['CardSecVal']} {$data['ECOrderNum']} {$data['AVSname']} {$data['AVSaddress1']} {$data['AVSaddress2']} {$data['AVScity']} {$data['AVSstate']} {$data['AVSzip']} 02 END_XML; } elseif ($data['MessageType'] == 'C') { $xml = << {$data['MerchantID']} 001 {$data['BIN']} {$data['OrderID']} {$data['Amount']} {$data['TxDateTime']} {$data['TxRefNum']} END_XML; } return $xml; } } \ No newline at end of file Index: branches/5.2.x/units/gateways/gw_classes/paypal_direct.php =================================================================== --- branches/5.2.x/units/gateways/gw_classes/paypal_direct.php (revision 16515) +++ branches/5.2.x/units/gateways/gw_classes/paypal_direct.php (revision 16516) @@ -1,241 +1,241 @@ Array('Name' => 'PayPal Pro', 'ClassName' => 'kGWPaypalDirect', 'ClassFile' => 'paypal_direct.php', 'RequireCCFields' => 1), 'ConfigFields' => Array( 'submit_url' => Array('Name' => 'Submit URL', 'Type' => 'text', 'ValueList' => '', 'Default' => 'https://api-3t.paypal.com/nvp'), 'api_username' => Array('Name' => 'PayPal Pro API Username', 'Type' => 'text', 'ValueList' => '', 'Default' => ''), 'api_password' => Array('Name' => 'PayPal Pro API Password', 'Type' => 'text', 'ValueList' => '', 'Default' => ''), 'signature' => Array('Name' => 'PayPal Pro API Signature', 'Type' => 'text', 'ValueList' => '', 'Default' => ''), 'shipping_control' => Array('Name' => 'Shipping Control', 'Type' => 'select', 'ValueList' => '3=la_CreditDirect', 'Default' => '3'), ) ); return $data; } function DirectPayment($item_data, $gw_params) { $post_fields = Array(); // -- Login Information -- $post_fields['METHOD'] = 'DoDirectPayment'; $post_fields['VERSION'] = '52.0'; $post_fields['IPADDRESS'] = $this->Application->getClientIp(); $post_fields['USER'] = $gw_params['api_username']; $post_fields['PWD'] = $gw_params['api_password']; $post_fields['SIGNATURE'] = $gw_params['signature']; $post_fields['PAYMENTACTION'] = 'Sale'; $post_fields['AMT'] = sprintf('%.2f', $item_data['TotalAmount']); switch ($item_data['PaymentCardType']) { case 1: $post_fields['CREDITCARDTYPE'] = 'Visa'; break; case 2: $post_fields['CREDITCARDTYPE'] = 'MasterCard'; break; case 3: $post_fields['CREDITCARDTYPE'] = 'Amex'; break; case 4: $post_fields['CREDITCARDTYPE'] = 'Discover'; break; default: $this->parsed_responce['responce_reason_text'] = 'Invalid Credit Card Type'; return false; } $post_fields['ACCT'] = $item_data['PaymentAccount']; $date_parts = explode('/', $item_data['PaymentCCExpDate']); $post_fields['EXPDATE'] = $date_parts[0].'20'.$date_parts[1]; $post_fields['CVV2'] = $item_data['PaymentCVV2']; $names = explode(' ', $item_data['PaymentNameOnCard'], 2); $post_fields['FIRSTNAME'] = getArrayValue($names, 0); $post_fields['LASTNAME'] = getArrayValue($names, 1); $post_fields['STREET'] = $item_data['BillingAddress1']; $post_fields['STREET2'] = $item_data['BillingAddress2']; $post_fields['CITY'] = $item_data['BillingCity']; $post_fields['STATE'] = $item_data['BillingState']; + /** @var kCountryStatesHelper $cs_helper */ $cs_helper = $this->Application->recallObject('CountryStatesHelper'); - /* @var $cs_helper kCountryStatesHelper */ $post_fields['COUNTRYCODE'] = $cs_helper->getCountryIso( $item_data['BillingCountry'] ); $post_fields['ZIP'] = $item_data['BillingZip']; $post_fields['INVNUM'] = $item_data['OrderNumber']; $post_fields['CUSTOM'] = $item_data['PortalUserId']; /* $post_fields['x_encap_char'] = $gw_params['encapsulate_char']; $post_fields['x_relay_response'] = 'False'; $post_fields['x_type'] = $gw_params['shipping_control'] == SHIPPING_CONTROL_PREAUTH ? 'AUTH_ONLY' : 'AUTH_CAPTURE'; $post_fields['x_login'] = $gw_params['user_account']; $post_fields['x_tran_key'] = $gw_params['transaction_key']; if( $this->IsTestMode() ) $post_fields['x_test_request'] = 'True'; // -- Payment Details -- $names = explode(' ', $item_data['PaymentNameOnCard'], 2); $post_fields['x_first_name'] = getArrayValue($names, 0); $post_fields['x_last_name'] = getArrayValue($names, 1); $post_fields['x_amount'] = sprintf('%.2f', $item_data['TotalAmount']); $post_fields['x_company'] = $item_data['BillingCompany']; $post_fields['x_card_num'] = $item_data['PaymentAccount']; $post_fields['x_card_code'] = $item_data['PaymentCVV2']; $post_fields['x_exp_date'] = $item_data['PaymentCCExpDate']; $post_fields['x_address'] = $item_data['BillingAddress1'].' '.$item_data['BillingAddress2']; $post_fields['x_city'] = $item_data['BillingCity']; $post_fields['x_state'] = $item_data['BillingState']; $post_fields['x_zip'] = $item_data['BillingZip']; $recurring = getArrayValue($item_data, 'IsRecurringBilling') ? 'YES' : 'NO'; $post_fields['x_recurring_billing'] = $recurring; $billing_email = $item_data['BillingEmail']; if (!$billing_email) { $billing_email = $this->Conn->GetOne(' SELECT Email FROM '.$this->Application->getUnitOption('u', 'TableName').' WHERE PortalUserId = '.$this->Application->RecallVar('user_id')); } $post_fields['x_email'] = $billing_email; $post_fields['x_phone'] = $item_data['BillingPhone']; $post_fields['x_country'] = $cs_helper->getCountryIso( $item_data['BillingCountry'] ); $post_fields['x_cust_id'] = $item_data['PortalUserId']; $post_fields['x_invoice_num'] = $item_data['OrderNumber']; $post_fields['x_description'] = 'Invoice #'.$item_data['OrderNumber']; $post_fields['x_email_customer'] = 'FALSE'; */ // echo '
';
 //			print_r($post_fields);
 //			exit;
 
+			/** @var kCurlHelper $curl_helper */
 			$curl_helper = $this->Application->recallObject('CurlHelper');
-			/* @var $curl_helper kCurlHelper */
 
 			$curl_helper->SetPostData($post_fields);
 			$this->gw_responce = $curl_helper->Send($gw_params['submit_url']);
 
 //			echo $this->gw_responce;
 //			exit;
 			$gw_responce = $this->parseGWResponce(null, $gw_params);
 			// gw_error_msg: $gw_response['responce_reason_text']
 			// gw_error_code: $gw_response['responce_reason_code']
 //			echo '
';
 //			print_r($this->parsed_responce);
 //			exit;
 			return (isset($gw_responce['ACK']) && (substr($gw_responce['ACK'], 0, 7) == 'Success')) ? true : false;
 		}
 
 		/**
 		 * Perform SALE type transaction direct from php script wihtout redirecting to 3rd-party website
 		 *
 		 * @param Array $item_data
 		 * @param Array $gw_params
 		 * @return bool
 		 */
 /*
 		function Charge($item_data, $gw_params)
 		{
 			$gw_responce = unserialize( $item_data['GWResult1'] );
 
 			if( $item_data['PortalUserId'] != $gw_responce['customer_id'] ) return false;
 
 			if( ( strtolower($gw_responce['transaction_type']) == 'auth_only') )
 			{
 				$post_fields = Array();
 				// -- Login Information --
 				$post_fields['x_version']			=	'3.1';
 				$post_fields['x_delim_data']		=	'True';
 				$post_fields['x_encap_char']		=	$gw_params['encapsulate_char'];
 				$post_fields['x_relay_response']	=	'False';
 				$post_fields['x_type']				=	'PRIOR_AUTH_CAPTURE'; // $gw_params['shipping_control'] == SHIPPING_CONTROL_PREAUTH ? 'PRIOR_AUTH_CAPTURE' : 'AUTH_CAPTURE'; // AUTH_CAPTURE not fully impletemnted/needed here
 				$post_fields['x_login']				=	$gw_params['user_account'];
 				$post_fields['x_tran_key']			=	$gw_params['transaction_key'];
 				$post_fields['x_trans_id']			=	$gw_responce['transaction_id'];
 
 				if( $this->IsTestMode() ) $post_fields['x_test_request'] = 'True';
 
 				$curl_helper = $this->Application->recallObject('CurlHelper');
 
 				$curl_helper->SetPostData($post_fields);
 				$this->gw_responce = $curl_helper->Send($gw_params['submit_url']);
 
 				$gw_responce = $this->parseGWResponce(null, $gw_params);
 
 				// gw_error_msg: $gw_response['responce_reason_text']
 				// gw_error_code: $gw_response['responce_reason_code']
 				return (is_numeric($gw_responce['responce_code']) && $gw_responce['responce_code'] != 1 && !$this->IsTestMode()) ? false : true;
 			}
 			else
 			{
 				return true;
 			}
 		}
 */
 		/**
 		 * Parse previosly saved gw responce into associative array
 		 *
 		 * @param string $gw_responce
 		 * @param Array $gw_params
 		 * @return Array
 		 */
 		function parseGWResponce($gw_responce = null, $gw_params)
 		{
 			if( !isset($gw_responce) ) $gw_responce = $this->gw_responce;
 
 			if ($this->Application->isDebugMode()) {
 				$this->Application->Debugger->appendHTML('Curl Error #'.$GLOBALS['curl_errorno'].'; Error Message: '.$GLOBALS['curl_error']);
 
 				$this->Application->Debugger->appendHTML('Authorize.Net Responce:');
 				$this->Application->Debugger->dumpVars($gw_responce);
 			}
 
 			$a_responce = explode('&', $gw_responce);
 			$ret = Array();
 			foreach($a_responce as $field)
 			{
 				$pos = strpos($field, '=');
 				if ($pos) {
 					$ret[substr($field, 0, $pos)] = urldecode(substr($field, $pos + 1));
 				}
 			}
 			$this->parsed_responce = $ret;
 //			$ret['unparsed'] = $gw_responce;
 			return $ret;
 		}
 
 		function getGWResponce()
 		{
 			return serialize($this->parsed_responce);
 		}
 
 		function getErrorMsg()
 		{
 			return $this->parsed_responce['L_LONGMESSAGE0'];
 		}
 
 		function GetTestCCNumbers()
 		{
 			return array('370000000000002', '6011000000000012', '5424000000000015', '4007000000027', '4222222222222');
 		}
 	}
\ No newline at end of file
Index: branches/5.2.x/units/gateways/gw_classes/authorizenet.php
===================================================================
--- branches/5.2.x/units/gateways/gw_classes/authorizenet.php	(revision 16515)
+++ branches/5.2.x/units/gateways/gw_classes/authorizenet.php	(revision 16516)
@@ -1,180 +1,180 @@
 IsTestMode() ) $post_fields['x_test_request'] = 'True';
 
 			// -- Payment Details --
 			$names = explode(' ', $item_data['PaymentNameOnCard'], 2);
 			$post_fields['x_first_name']		=	getArrayValue($names, 0);
 			$post_fields['x_last_name']			=	getArrayValue($names, 1);
 			$post_fields['x_amount']			=	sprintf('%.2f', $item_data['TotalAmount']);
 			$post_fields['x_company']			=	$item_data['BillingCompany'];
 			$post_fields['x_card_num']			=	$item_data['PaymentAccount'];
 			$post_fields['x_card_code']			=	$item_data['PaymentCVV2'];
 			$post_fields['x_exp_date']			=	$item_data['PaymentCCExpDate'];
 			$post_fields['x_address']			=	$item_data['BillingAddress1'].' '.$item_data['BillingAddress2'];
 			$post_fields['x_city']				=	$item_data['BillingCity'];
 			$post_fields['x_state']				=	$item_data['BillingState'];
 			$post_fields['x_zip']				=	$item_data['BillingZip'];
 
 			$recurring = getArrayValue($item_data, 'IsRecurringBilling') ? 'YES' : 'NO';
 			$post_fields['x_recurring_billing'] = $recurring;
 
 			$billing_email = $item_data['BillingEmail'];
 			if (!$billing_email) {
 				$billing_email = $this->Conn->GetOne('	SELECT Email FROM '.$this->Application->getUnitOption('u', 'TableName').'
 											WHERE PortalUserId = '.$this->Application->RecallVar('user_id'));
 			}
 			$post_fields['x_email'] = $billing_email;
 			$post_fields['x_phone'] = $item_data['BillingPhone'];
 
+			/** @var kCountryStatesHelper $cs_helper */
 			$cs_helper = $this->Application->recallObject('CountryStatesHelper');
-			/* @var $cs_helper kCountryStatesHelper */
 
 			$post_fields['x_country']			=	$cs_helper->getCountryIso( $item_data['BillingCountry'] );
 			$post_fields['x_cust_id']			=	$item_data['PortalUserId'];
 			$post_fields['x_invoice_num']		=	$item_data['OrderNumber'];
 			$post_fields['x_description']		=	'Invoice #'.$item_data['OrderNumber'];
 			$post_fields['x_email_customer']	=	'FALSE';
 
+			/** @var kCurlHelper $curl_helper */
 			$curl_helper = $this->Application->recallObject('CurlHelper');
-			/* @var $curl_helper kCurlHelper */
 
 			$curl_helper->SetPostData($post_fields);
 			$this->gw_responce = $curl_helper->Send($gw_params['submit_url']);
 
 			$gw_responce = $this->parseGWResponce(null, $gw_params);
 
 			// gw_error_msg: $gw_response['responce_reason_text']
 			// gw_error_code: $gw_response['responce_reason_code']
 			return (is_numeric($gw_responce['responce_code']) && $gw_responce['responce_code'] == 1) ? true : false;
 		}
 
 		/**
 		 * Perform SALE type transaction direct from php script wihtout redirecting to 3rd-party website
 		 *
 		 * @param Array $item_data
 		 * @param Array $gw_params
 		 * @return bool
 		 */
 		function Charge($item_data, $gw_params)
 		{
 			$gw_responce = unserialize( $item_data['GWResult1'] );
 
 			if( ($item_data['PortalUserId'] != $gw_responce['customer_id']) && ($gw_repsponce['customer_id'] != USER_GUEST && !$this->Application->isAdmin)) return false;
 
 			if( ( strtolower($gw_responce['transaction_type']) == 'auth_only') )
 			{
 				$post_fields = Array();
 				// -- Login Information --
 				$post_fields['x_version']			=	'3.1';
 				$post_fields['x_delim_data']		=	'True';
 				$post_fields['x_encap_char']		=	$gw_params['encapsulate_char'];
 				$post_fields['x_relay_response']	=	'False';
 				$post_fields['x_type']				=	'PRIOR_AUTH_CAPTURE'; // $gw_params['shipping_control'] == SHIPPING_CONTROL_PREAUTH ? 'PRIOR_AUTH_CAPTURE' : 'AUTH_CAPTURE'; // AUTH_CAPTURE not fully impletemnted/needed here
 				$post_fields['x_login']				=	$gw_params['user_account'];
 				$post_fields['x_tran_key']			=	$gw_params['transaction_key'];
 				$post_fields['x_trans_id']			=	$gw_responce['transaction_id'];
 
 				if( $this->IsTestMode() ) $post_fields['x_test_request'] = 'True';
 
+				/** @var kCurlHelper $curl_helper */
 				$curl_helper = $this->Application->recallObject('CurlHelper');
-				/* @var $curl_helper kCurlHelper */
 
 				$curl_helper->SetPostData($post_fields);
 				$this->gw_responce = $curl_helper->Send($gw_params['submit_url']);
 
 				$gw_responce = $this->parseGWResponce(null, $gw_params);
 
 				// gw_error_msg: $gw_response['responce_reason_text']
 				// gw_error_code: $gw_response['responce_reason_code']
 				return (is_numeric($gw_responce['responce_code']) && $gw_responce['responce_code'] == 1) || $this->IsTestMode() ? true : false;
 			}
 			else
 			{
 				return true;
 			}
 		}
 
 		/**
 		 * Parse previosly saved gw responce into associative array
 		 *
 		 * @param string $gw_responce
 		 * @param Array $gw_params
 		 * @return Array
 		 */
 		function parseGWResponce($gw_responce = null, $gw_params)
 		{
 			if( !isset($gw_responce) ) $gw_responce = $this->gw_responce;
 
 			if ($this->Application->isDebugMode()) {
 				$this->Application->Debugger->appendHTML('Curl Error #'.$GLOBALS['curl_errorno'].'; Error Message: '.$GLOBALS['curl_error']);
 
 				$this->Application->Debugger->appendHTML('Authorize.Net Responce:');
 				$this->Application->Debugger->dumpVars($gw_responce);
 			}
 
 			$fields = Array('responce_code','responce_sub_code','responce_reason_code','responce_reason_text',
 							'approval_code','avs_result_code','transaction_id','invoice_number','description',
 							'amount','method','transaction_type','customer_id','first_name','last_name','company',
 							'address','city','state','zip','country','phone','fax','email');
 
 			$encapsulate_char = $gw_params['encapsulate_char'];
 			if($encapsulate_char)
 			{
 				$ec_length = strlen($encapsulate_char);
 				$gw_responce = substr($gw_responce, $ec_length, $ec_length * -1);
 			}
 
 			$gw_responce = explode($encapsulate_char.','.$encapsulate_char, $gw_responce);
 			$ret = Array();
 			foreach($fields as $field_index => $field_name)
 			{
 				$ret[$field_name] = $gw_responce[$field_index];
 				unset($gw_responce[$field_index]);
 			}
 			$this->parsed_responce = $ret;
 			return kUtil::array_merge_recursive($ret, $gw_responce); // returns unparsed fields with they original indexes together with parsed ones
 		}
 
 		function getGWResponce()
 		{
 			return serialize($this->parsed_responce);
 		}
 
 		function getErrorMsg()
 		{
 			return $this->parsed_responce['responce_reason_text'];
 		}
 
 		function GetTestCCNumbers()
 		{
 			return array('370000000000002', '6011000000000012', '5424000000000015', '4007000000027', '4222222222222');
 		}
 	}
\ No newline at end of file
Index: branches/5.2.x/units/gateways/gw_classes/google_checkout.php
===================================================================
--- branches/5.2.x/units/gateways/gw_classes/google_checkout.php	(revision 16515)
+++ branches/5.2.x/units/gateways/gw_classes/google_checkout.php	(revision 16516)
@@ -1,940 +1,942 @@
  Array('Name' => 'Google Checkout', 'ClassName' => 'kGWGoogleCheckout', 'ClassFile' => 'google_checkout.php', 'RequireCCFields' => 0),
 				'ConfigFields' => Array(
 					'submit_url' => Array('Name' => 'Submit URL', 'Type' => 'text', 'ValueList' => '', 'Default' => 'https://checkout.google.com/api/checkout/v2'),
 					'merchant_id' => Array('Name' => 'Google merchant ID', 'Type' => 'text', 'ValueList' => '', 'Default' => ''),
 					'merchant_key' => Array('Name' => 'Google merchant key', 'Type' => 'text', 'ValueList' => '', 'Default' => ''),
 					'shipping_control' => Array('Name' => 'Shipping Control', 'Type' => 'select', 'ValueList' => '3=la_CreditDirect,4=la_CreditPreAuthorize', 'Default' => 3),
 				)
 			);
 			return $data;
 		}
 
 		/**
 		 * Returns payment form submit url
 		 *
 		 * @param Array $gw_params gateway params from payment type config
 		 * @return string
 		 */
 		function getFormAction($gw_params)
 		{
 			return $gw_params['submit_url'].'/checkout/Merchant/'.$gw_params['merchant_id'];
 		}
 
 		/**
 		 * Processed input data and convets it to fields understandable by gateway
 		 *
 		 * @param Array $item_data current order fields
 		 * @param Array $tag_params additional params for gateway passed through tag
 		 * @param Array $gw_params gateway params from payment type config
 		 * @return Array
 		 */
 		function getHiddenFields($item_data, $tag_params, $gw_params)
 		{
 			$ret = Array();
 			$this->gwParams = $gw_params;
 
 			$cart_xml = $this->getCartXML($item_data);
 
 			$ret['cart'] = base64_encode($cart_xml);
     		$ret['signature'] = base64_encode( $this->CalcHmacSha1($cart_xml, $gw_params) );
 
 			return $ret;
 		}
 
 		function getCartXML($cart_fields)
 		{
 			// 1. prepare shopping cart content
 			$sql = 'SELECT *
 					FROM '.TABLE_PREFIX.'OrderItems oi
 					LEFT JOIN '.TABLE_PREFIX.'Products p ON p.ProductId = oi.ProductId
 					WHERE oi.OrderId = '.$cart_fields['OrderId'];
 			$order_items = $this->Conn->Query($sql);
 
+			/** @var kMultiLanguage $ml_formatter */
 			$ml_formatter = $this->Application->recallObject('kMultiLanguage');
-			/* @var $ml_formatter kMultiLanguage */
 
 			$cart_xml = Array ();
 			foreach ($order_items as $order_item) {
 				$cart_xml[] = '	
 					        		'.kUtil::escape($order_item['ProductName'], kUtil::ESCAPE_HTML).'
 					        		'.kUtil::escape($order_item[$ml_formatter->LangFieldName('DescriptionExcerpt')], kUtil::ESCAPE_HTML).''.
 									$this->getPriceXML('unit-price', $order_item['Price']).'
 					        		'.$order_item['Quantity'].'
 								';
 			}
 			$cart_xml = ''.implode("\n", $cart_xml).'';
 
 			// 2. add order identification info (for google checkout notification)
 			$cart_xml .= '	
 								'.$this->Application->GetSID().'
 								'.$cart_fields['OrderId'].'
 							';
 
 			// 3. add all shipping types (with no costs)
 			$sql = 'SELECT Name
 					FROM '.TABLE_PREFIX.'ShippingType
 					WHERE Status = '.STATUS_ACTIVE;
 			$shipping_types = $this->Conn->GetCol($sql);
 
 			$shipping_xml = '';
 			foreach ($shipping_types as $shipping_name) {
 				$shipping_xml .= '	
 										0.00
 									';
 			}
 
 			$use_ssl = substr($this->gwParams['submit_url'], 0, 8) == 'https://' ? true : null;
 			$shipping_url = $this->getNotificationUrl('units/gateways/gw_classes/notify_scripts/google_checkout_shippings.php', $use_ssl);
 
 			$shipping_xml = '
 								'.$shipping_xml.'
 					      		
 					      			'.$shipping_url.'
 					      		
 					    	';
 
 			$xml = '
 					  '.$cart_xml.'
 					  '.$shipping_xml.'
 					';
 
 			return $xml;
 		}
 
 		/**
 		 * Returns price formatted as xml tag
 		 *
 		 * @param string $tag_name
 		 * @param float $price
 		 * @return string
 		 */
 		function getPriceXML($tag_name, $price)
 		{
 			$currency = $this->Application->RecallVar('curr_iso');
 			return '<'.$tag_name.' currency="'.$currency.'">'.sprintf('%.2f', $price).'';
 		}
 
 	    /**
 	     * Calculates the cart's hmac-sha1 signature, this allows google to verify
 	     * that the cart hasn't been tampered by a third-party.
 	     *
 	     * {@link http://code.google.com/apis/checkout/developer/index.html#create_signature}
 	     *
 	     * @param string $data the cart's xml
 	     * @return string the cart's signature (in binary format)
 	     */
 	    function CalcHmacSha1($data, $gw_params) {
 	      $key = $gw_params['merchant_key'];
 	      $blocksize = 64;
 	      $hashfunc = 'sha1';
 	      if (mb_strlen($key) > $blocksize) {
 	        $key = pack('H*', $hashfunc($key));
 	      }
 	      $key = str_pad($key, $blocksize, chr(0x00));
 	      $ipad = str_repeat(chr(0x36), $blocksize);
 	      $opad = str_repeat(chr(0x5c), $blocksize);
 	      $hmac = pack(
 	                    'H*', $hashfunc(
 	                            ($key^$opad).pack(
 	                                    'H*', $hashfunc(
 	                                            ($key^$ipad).$data
 	                                    )
 	                            )
 	                    )
 	                );
 	      return $hmac;
 	    }
 
 	    /**
 	     * Returns XML request, that GoogleCheckout posts to notification / shipping calculation scripts
 	     *
 	     * @return string
 	     */
 	    function getRequestXML()
 	    {
 	    	$xml_data = file_get_contents('php://input');
 
 	    	if ( $this->Application->isDebugMode() ) {
 	    		$this->toLog($xml_data, 'xml_request.html');
 	    	}
 
 	    	return $xml_data;
 
 	    	// for debugging
 	    	/*return '
 					    434532759516557
 					    CHARGEABLE
 					    NEW
 					    REVIEWING
 					    NEW
 					    2007-03-19T15:06:29.051Z
 					';*/
 	    }
 
 	    /**
 	     * Processes notifications from google checkout
 	     *
 	     * @param Array $gw_params
 	     * @return int
 	     */
 		function processNotification($gw_params)
 		{
     		// parse xml & get order_id from there, like sella pay
     		$this->gwParams = $gw_params;
 
+    		/** @var kXMLHelper $xml_helper */
     		$xml_helper = $this->Application->recallObject('kXMLHelper');
-    		/* @var $xml_helper kXMLHelper */
 
+    		/** @var kXMLNode $root_node */
 			$root_node =& $xml_helper->Parse( $this->getRequestXML() );
-    		/* @var $root_node kXMLNode */
 
     		$this->Application->XMLHeader();
 			define('DBG_SKIP_REPORTING', 1);
 
 			$order_approvable = false;
 
 			switch ($root_node->Name) {
 				case 'MERCHANT-CALCULATION-CALLBACK':
 					$xml_responce = $this->getShippingXML($root_node);
 					break;
 
 				case 'NEW-ORDER-NOTIFICATION':
 				case 'RISK-INFORMATION-NOTIFICATION':
 				case 'ORDER-STATE-CHANGE-NOTIFICATION':
 					// http://code.google.com/apis/checkout/developer/Google_Checkout_XML_API_Notification_API.html#new_order_notifications
 					list ($order_approvable, $xml_responce) = $this->getNotificationResponceXML($root_node);
 					break;
 			}
 
 			echo $xml_responce;
 
 			if ( $this->Application->isDebugMode() ) {
 				$this->toLog($xml_responce, 'xml_responce.html');
 			}
 
     		return $order_approvable ? 1 : 0;
 		}
 
 		/**
 	     * Writes XML requests and responces to a file
 	     *
 	     * @param string $xml_data
 	     * @param string $xml_file
 	     */
 	    function toLog($xml_data, $xml_file)
 	    {
 	    	$fp = fopen( (defined('RESTRICTED') ? RESTRICTED : FULL_PATH) . '/' . $xml_file, 'a' );
 			fwrite($fp, '--- ' . adodb_date('Y-m-d H:i:s') . ' ---' . "\n" . $xml_data);
 			fclose($fp);
 	    }
 
 		/**
 		 * Processes notification
 		 *
 		 * @param kXMLNode $root_node
 		 */
 		function getNotificationResponceXML(&$root_node)
 		{
 			// we can get notification type by "$root_node->Name"
 
 			$order_approvable = false;
 			switch ($root_node->Name) {
 				case 'NEW-ORDER-NOTIFICATION':
 					$order_approvable = $this->processNewOrderNotification($root_node);
 					break;
 
 				case 'RISK-INFORMATION-NOTIFICATION':
 					$order_approvable = $this->processRiskInformationNotification($root_node);
 					break;
 
 				case 'ORDER-STATE-CHANGE-NOTIFICATION':
 					$order_approvable = $this->processOrderStateChangeNotification($root_node);
 					break;
 			}
 
 
 
 			// !!! globally set order id, so gw_responce.php will not fail in setting TransactionStatus
 
 			// 1. receive new order notification
 			// put address & payment type in our order using id found in merchant-private-data (Make order status: Incomplete)
 
 			// 2. receive risk information
 			// don't know what to do, just mark order some how (Make order status: Incomplete)
 
 			// 3. receive status change notification to CHARGEABLE (Make order status: Pending)
 			// only mark order status
 
 			// 4. admin approves order
 			// make api call, that changes order state (fulfillment-order-state) to PROCESSING or DELIVERED (see manual)
 
 			// 5. admin declines order
 			// make api call, that changes order state (fulfillment-order-state) to WILL_NOT_DELIVER
 
 			// Before you ship the items in an order, you should ensure that you have already received the new order notification for the order,
 			// the risk information notification for the order and an order state change notification informing you that the order's financial
 			// state has been updated to CHARGEABLE
 
 			return Array ($order_approvable, '');
 		}
 
 		/**
 		 * Returns shipping calculations and places part of shipping address into order (1st step)
 		 *
 		 * http://code.google.com/apis/checkout/developer/Google_Checkout_XML_API_Merchant_Calculations_API.html#Returning_Merchant_Calculation_Results
 		 *
 		 * @param kXMLNode $node
 		 * @return string
 		 */
 		function getShippingXML(&$root_node)
 		{
 			// 1. extract data from xml
 			$search_nodes = Array (
 				'SHOPPING-CART:MERCHANT-PRIVATE-DATA',
 				'CALCULATE:ADDRESSES:ANONYMOUS-ADDRESS',
 				'CALCULATE:SHIPPING',
 			);
 
 			foreach ($search_nodes as $search_string) {
+				/** @var kXMLNode $found_node */
 				$found_node =& $root_node;
-				/* @var $found_node kXMLNode */
 
 				$search_string = explode(':', $search_string);
 				foreach ($search_string as $search_node) {
 					$found_node =& $found_node->FindChild($search_node);
 				}
 
 				$node_data = Array ();
+
+				/** @var kXMLNode $sub_node */
 				$sub_node =& $found_node->firstChild;
-				/* @var $sub_node kXMLNode */
 
 				do {
 					if ($found_node->Name == 'SHIPPING') {
 						$node_data[] = $sub_node->Attributes['NAME'];
 					}
 					else {
 						$node_data[$sub_node->Name] = $sub_node->Data;
 					}
 				} while ( ($sub_node =& $sub_node->NextSibling()) );
 
 
 				switch ($found_node->Name) {
 					case 'MERCHANT-PRIVATE-DATA':
 						$order_id = $node_data['ORDER_ID'];
 						$session_id = $node_data['SESSION_ID'];
 						break;
 
 					case 'ANONYMOUS-ADDRESS':
 						$address_info = $node_data;
 						$address_id = $found_node->Attributes['ID'];
 						break;
 
 					case 'SHIPPING':
 						$process_shippings = $node_data;
 						break;
 				}
 			}
 
 			// 2. update shipping address in order
+			/** @var OrdersItem $order */
 			$order = $this->Application->recallObject('ord', null, Array ('skip_autoload' => true));
-			/* @var $order OrdersItem */
 
 			$order->Load($order_id);
 
 			$shipping_address = Array (
 				'ShippingCity' => $address_info['CITY'],
 				'ShippingState' => $address_info['REGION'],
 				'ShippingZip' => $address_info['POSTAL-CODE'],
 			);
 
+			/** @var kCountryStatesHelper $cs_helper */
 			$cs_helper = $this->Application->recallObject('CountryStatesHelper');
-			/* @var $cs_helper kCountryStatesHelper */
 
 			$shipping_address['ShippingCountry'] = $cs_helper->getCountryIso($address_info['COUNTRY-CODE'], true);
 
 			$order->SetDBFieldsFromHash($shipping_address);
 			$order->Update();
 
 			// 3. get shipping rates based on given address
 
 			$shipping_types_xml = '';
 			$shipping_types = $this->getOrderShippings($order);
 
 			// add available shipping types
 			foreach ($shipping_types as $shipping_type) {
 				$shipping_name = $shipping_type['ShippingName'];
 				$processable_shipping_index = array_search($shipping_name, $process_shippings);
 				if ($processable_shipping_index !== false) {
 					$shipping_types_xml .= '
 				    	        				'.sprintf('%01.2f', $shipping_type['TotalCost']).'
 				        	    				true
 				        					';
 
 					// remove available shipping type from processable list
 					unset($process_shippings[$processable_shipping_index]);
 				}
 			}
 
 			// add unavailable shipping types
 			foreach ($process_shippings as $shipping_name) {
 				$shipping_types_xml .= '
 											0.00
 				            				false
 				        				';
 			}
 
 			$shipping_types_xml = '
 									
 				  						'.$shipping_types_xml.'
 									';
 			return $shipping_types_xml;
 		}
 
 		/**
 		 * Places all information from google checkout into order (2nd step)
 		 *
 		 * @param kXMLNode $root_node
 		 */
 		function processNewOrderNotification(&$root_node)
 		{
 			// 1. extract data from xml
 			$search_nodes = Array (
 				'SHOPPING-CART:MERCHANT-PRIVATE-DATA',
 				'ORDER-ADJUSTMENT:SHIPPING:MERCHANT-CALCULATED-SHIPPING-ADJUSTMENT',
 				'BUYER-ID',
 				'GOOGLE-ORDER-NUMBER',
 				'BUYER-SHIPPING-ADDRESS',
 				'BUYER-BILLING-ADDRESS',
 			);
 
 			$user_address = Array ();
 			foreach ($search_nodes as $search_string) {
+				/** @var kXMLNode $found_node */
 				$found_node =& $root_node;
-				/* @var $found_node kXMLNode */
 
 				$search_string = explode(':', $search_string);
 				foreach ($search_string as $search_node) {
 					$found_node =& $found_node->FindChild($search_node);
 				}
 
 				$node_data = Array ();
 				if ($found_node->Children) {
+					/** @var kXMLNode $sub_node */
 					$sub_node =& $found_node->firstChild;
-					/* @var $sub_node kXMLNode */
 
 					do {
 						$node_data[$sub_node->Name] = $sub_node->Data;
 					} while ( ($sub_node =& $sub_node->NextSibling()) );
 				}
 
 				switch ($found_node->Name) {
 					case 'MERCHANT-PRIVATE-DATA':
 						$order_id = $node_data['ORDER_ID'];
 						$session_id = $node_data['SESSION_ID'];
 						break;
 
 					case 'MERCHANT-CALCULATED-SHIPPING-ADJUSTMENT':
 						$shpipping_info = $node_data;
 						break;
 
 					case 'BUYER-ID':
 						$buyer_id = $found_node->Data;
 						break;
 
 					case 'GOOGLE-ORDER-NUMBER':
 						$google_order_number = $found_node->Data;
 						break;
 
 					case 'BUYER-SHIPPING-ADDRESS':
 						$user_address['Shipping'] = $node_data;
 						break;
 
 					case 'BUYER-BILLING-ADDRESS':
 						$user_address['Billing'] = $node_data;
 						break;
 				}
 			}
 
 			// 2. update shipping address in order
+			/** @var OrdersItem $order */
 			$order = $this->Application->recallObject('ord', null, Array ('skip_autoload' => true));
-			/* @var $order OrdersItem */
 
 			$order->Load($order_id);
 
 			if (!$order->isLoaded()) {
 				return false;
 			}
 
 			// 2.1. this is 100% notification from google -> mark order with such payment type
 			$order->SetDBField('PaymentType', $this->Application->GetVar('payment_type_id'));
 
 			$this->parsed_responce = Array (
 				'GOOGLE-ORDER-NUMBER' => $google_order_number,
 				'BUYER-ID' => $buyer_id
 			);
 
 			// 2.2. save google checkout order information (maybe needed for future notification processing)
 			$order->SetDBField('GWResult1', serialize($this->parsed_responce));
 			$order->SetDBField('GoogleOrderNumber', $google_order_number);
 
 			// 2.3. set user-selected shipping type
 			$shipping_types = $this->getOrderShippings($order);
 
 			foreach ($shipping_types as $shipping_type) {
 				if ($shipping_type['ShippingName'] == $shpipping_info['SHIPPING-NAME']) {
 					$order->SetDBField('ShippingInfo', serialize(Array (1 => $shipping_type))); // minimal package number is 1
 					$order->SetDBField('ShippingCost', $shipping_type['TotalCost']); // set total shipping cost
 					break;
 				}
 			}
 
 			// 2.4. set full shipping & billing address
 			$address_mapping = Array (
 				'CONTACT-NAME' => 'To',
 				'COMPANY-NAME' => 'Company',
 				'EMAIL' => 'Email',
 				'PHONE' => 'Phone',
 				'FAX' => 'Fax',
 				'ADDRESS1' => 'Address1',
 				'ADDRESS2' => 'Address2',
 				'CITY' => 'City',
 				'REGION' => 'State',
 				'POSTAL-CODE' => 'Zip',
 			);
 
+			/** @var kCountryStatesHelper $cs_helper */
 			$cs_helper = $this->Application->recallObject('CountryStatesHelper');
-			/* @var $cs_helper kCountryStatesHelper */
 
 			foreach ($user_address as $field_prefix => $address_details) {
 				foreach ($address_mapping as $src_field => $dst_field) {
 					$order->SetDBField($field_prefix.$dst_field, $address_details[$src_field]);
 				}
 
 				if (!$order->GetDBField($field_prefix.'Phone')) {
 					$order->SetDBField($field_prefix.'Phone', '-'); // required field
 				}
 
 				$order->SetDBField( $field_prefix.'Country', $cs_helper->getCountryIso($address_details['COUNTRY-CODE'], true) );
 			}
 
 			$order->SetDBField('OnHold', 1);
 			$order->SetDBField('Status', ORDER_STATUS_PENDING);
 
 			$order->Update();
 
 			// unlink order, that GoogleCheckout used from shopping cart on site
 			$sql = 'DELETE
 					FROM '.TABLE_PREFIX.'UserSessionData
 					WHERE VariableName = "ord_id" AND VariableValue = '.$order->GetID();
 			$this->Conn->Query($sql);
 
 			// simulate visiting shipping screen
 			$sql = 'UPDATE '.TABLE_PREFIX.'OrderItems
 					SET PackageNum = 1
 					WHERE OrderId = '.$order->GetID();
 			$this->Conn->Query($sql);
 
 			return false;
 		}
 
 		/**
 		 * Saves risk information in order record (3rd step)
 		 *
 		 * @param kXMLNode $root_node
 		 */
 		function processRiskInformationNotification(&$root_node)
 		{
 			// 1. extract data from xml
 			$search_nodes = Array (
 				'GOOGLE-ORDER-NUMBER',
 				'RISK-INFORMATION',
 			);
 
 			foreach ($search_nodes as $search_string) {
+				/** @var kXMLNode $found_node */
 				$found_node =& $root_node;
-				/* @var $found_node kXMLNode */
 
 				$search_string = explode(':', $search_string);
 				foreach ($search_string as $search_node) {
 					$found_node =& $found_node->FindChild($search_node);
 				}
 
 				$node_data = Array ();
 				if ($found_node->Children) {
+					/** @var kXMLNode $sub_node */
 					$sub_node =& $found_node->firstChild;
-					/* @var $sub_node kXMLNode */
 
 					do {
 						$node_data[$sub_node->Name] = $sub_node->Data;
 					} while ( ($sub_node =& $sub_node->NextSibling()) );
 				}
 
 				switch ($found_node->Name) {
 					case 'GOOGLE-ORDER-NUMBER':
 						$google_order_number = $found_node->Data;
 						break;
 
 					case 'RISK-INFORMATION':
 						$risk_information = $node_data;
 						unset( $risk_information['BILLING-ADDRESS'] );
 						break;
 				}
 			}
 
 			// 2. update shipping address in order
+			/** @var OrdersItem $order */
 			$order = $this->Application->recallObject('ord', null, Array ('skip_autoload' => true));
-			/* @var $order OrdersItem */
 
 			$order->Load($google_order_number, 'GoogleOrderNumber');
 
 			if (!$order->isLoaded()) {
 				return false;
 			}
 
 			// 2.1. save risk information in order
 			$this->parsed_responce = unserialize($order->GetDBField('GWResult1'));
 			$this->parsed_responce = array_merge_recursive($this->parsed_responce, $risk_information);
 			$order->SetDBField('GWResult1', serialize($this->parsed_responce));
 
 			$order->Update();
 
 			return false;
 		}
 
 		/**
 		 * Perform PREAUTH/SALE type transaction direct from php script wihtout redirecting to 3rd-party website
 		 *
 		 * @param Array $item_data
 		 * @param Array $gw_params
 		 * @return bool
 		 */
 		function DirectPayment($item_data, $gw_params)
 		{
 			$this->gwParams = $gw_params;
 
 			if ($gw_params['shipping_control'] == SHIPPING_CONTROL_PREAUTH) {
 				// when shipping control is Pre-Authorize -> do nothing and charge when admin approves order
 				return true;
 			}
 
 			$this->_chargeOrder($item_data);
 
 			return false;
 		}
 
 		/**
 		 * Issue charge-order api call
 		 *
 		 * @param Array $item_data
 		 * @return bool
 		 */
 		function _chargeOrder($item_data)
 		{
 			$charge_xml = '	
 			    				'.sprintf('%.2f', $item_data['TotalAmount']).'
 							';
 
 			$root_node =& $this->executeAPICommand($charge_xml);
 
     		$this->parsed_responce = unserialize($item_data['GWResult1']);
 
     		if ($root_node->Name == 'REQUEST-RECEIVED') {
 				$this->parsed_responce['FINANCIAL-ORDER-STATE'] = 'CHARGING';
 				return true;
     		}
 
     		return false;
 		}
 
 		/**
 		 * Perform SALE type transaction direct from php script wihtout redirecting to 3rd-party website
 		 *
 		 * @param Array $item_data
 		 * @param Array $gw_params
 		 * @return bool
 		 */
 		function Charge($item_data, $gw_params)
 		{
 			$this->gwParams = $gw_params;
 
 			if ($gw_params['shipping_control'] == SHIPPING_CONTROL_DIRECT) {
 				// when shipping control is Direct Payment -> do nothing and auto-charge on notification received
 				return true;
 			}
 
 			$this->_chargeOrder($item_data);
 
+			/** @var OrdersItem $order */
 			$order = $this->Application->recallObject('ord.-item', null, Array ('skip_autoload' => true));
-			/* @var $order OrdersItem */
 
 			$order->Load($item_data['OrderId']);
 			if (!$order->isLoaded()) {
 				return false;
 			}
 
 			$order->SetDBField('OnHold', 1);
 			$order->Update();
 
 			return false;
 		}
 
 		/**
 		 * Executes API command for order and returns result
 		 *
 		 * @param string $command_xml
 		 * @return kXMLNode
 		 */
 		function &executeAPICommand($command_xml)
 		{
 			$submit_url = $this->gwParams['submit_url'].'/request/Merchant/'.$this->gwParams['merchant_id'];
 
+			/** @var kCurlHelper $curl_helper */
 			$curl_helper = $this->Application->recallObject('CurlHelper');
-			/* @var $curl_helper kCurlHelper */
 
+    		/** @var kXMLHelper $xml_helper */
 			$xml_helper = $this->Application->recallObject('kXMLHelper');
-    		/* @var $xml_helper kXMLHelper */
 
 			$curl_helper->SetPostData($command_xml);
 			$auth_options = Array (
 				CURLOPT_USERPWD => $this->gwParams['merchant_id'].':'.$this->gwParams['merchant_key'],
 			);
 			$curl_helper->setOptions($auth_options);
 
 			$xml_responce = $curl_helper->Send($submit_url);
 
+    		/** @var kXMLNode $root_node */
 			$root_node =& $xml_helper->Parse($xml_responce);
-    		/* @var $root_node kXMLNode */
 
     		return $root_node;
 		}
 
 		/**
 		 * Marks order as pending, when it's google status becomes CHARGEABLE (4th step)
 		 *
 		 * @param kXMLNode $root_node
 		 */
 		function processOrderStateChangeNotification(&$root_node)
 		{
 			// 1. extract data from xml
 			$search_nodes = Array (
 				'GOOGLE-ORDER-NUMBER',
 				'NEW-FINANCIAL-ORDER-STATE',
 				'PREVIOUS-FINANCIAL-ORDER-STATE',
 			);
 
 			$order_state = Array ();
 			foreach ($search_nodes as $search_string) {
+				/** @var kXMLNode $found_node */
 				$found_node =& $root_node;
-				/* @var $found_node kXMLNode */
 
 				$search_string = explode(':', $search_string);
 				foreach ($search_string as $search_node) {
 					$found_node =& $found_node->FindChild($search_node);
 				}
 
 				switch ($found_node->Name) {
 					case 'GOOGLE-ORDER-NUMBER':
 						$google_order_number = $found_node->Data;
 						break;
 
 					case 'NEW-FINANCIAL-ORDER-STATE':
 						$order_state['new'] = $found_node->Data;
 						break;
 
 					case 'PREVIOUS-FINANCIAL-ORDER-STATE':
 						$order_state['old'] = $found_node->Data;
 						break;
 				}
 			}
 
 			// 2. update shipping address in order
+			/** @var OrdersItem $order */
 			$order = $this->Application->recallObject('ord', null, Array ('skip_autoload' => true));
-			/* @var $order OrdersItem */
 
 			$order->Load($google_order_number, 'GoogleOrderNumber');
 
 			if (!$order->isLoaded()) {
 				return false;
 			}
 
 			$state_changed = ($order_state['old'] != $order_state['new']);
 
 			if ($state_changed) {
 				$order_charged = ($order_state['new'] == 'CHARGED') && ($order->GetDBField('Status') == ORDER_STATUS_PENDING);
 
 				$this->parsed_responce = unserialize($order->GetDBField('GWResult1'));
 				$this->parsed_responce['FINANCIAL-ORDER-STATE'] = $order_state['new'];
 				$order->SetDBField('GWResult1', serialize($this->parsed_responce));
 
 				if ($order_charged) {
 					// when using Pre-Authorize
 					$order->SetDBField('OnHold', 0);
 				}
 
 				$order->Update();
 
 				if ($order_charged) {
 					// when using Pre-Authorize
+					/** @var OrdersEventHandler $order_eh */
 					$order_eh = $this->Application->recallObject('ord_EventHandler');
-					/* @var $order_eh OrdersEventHandler */
 
 					$order_eh->SplitOrder( new kEvent('ord:OnMassOrderApprove'), $order);
 				}
 			}
 
 			// update order record in "google_checkout_notify.php" only when such state change happens
 			$order_chargeable = ($order_state['new'] == 'CHARGEABLE') && $state_changed;
 
 			if ($order_chargeable) {
 				if ($this->gwParams['shipping_control'] == SHIPPING_CONTROL_PREAUTH) {
 					$order->SetDBField('OnHold', 0);
 					$order->Update();
 				}
 
 				$process_xml = '';
 				$root_node =& $this->executeAPICommand($process_xml);
 			}
 
 			return $order_chargeable;
 		}
 
 		/**
 		 * Retrieves shipping types available for given order
 		 *
 		 * @param OrdersItem $order
 		 * @return Array
 		 */
 		function getOrderShippings(&$order)
 		{
 			$weight_sql = 'IF(oi.Weight IS NULL, 0, oi.Weight * oi.Quantity)';
 
 			$query = '	SELECT
 							SUM(oi.Quantity) AS TotalItems,
 							SUM('.$weight_sql.') AS TotalWeight,
 							SUM(oi.Price * oi.Quantity) AS TotalAmount,
 							SUM(oi.Quantity) - SUM(IF(p.MinQtyFreePromoShipping > 0 AND p.MinQtyFreePromoShipping <= oi.Quantity, oi.Quantity, 0)) AS TotalItemsPromo,
 							SUM('.$weight_sql.') - SUM(IF(p.MinQtyFreePromoShipping > 0 AND p.MinQtyFreePromoShipping <= oi.Quantity, '.$weight_sql.', 0)) AS TotalWeightPromo,
 							SUM(oi.Price * oi.Quantity) - SUM(IF(p.MinQtyFreePromoShipping > 0 AND p.MinQtyFreePromoShipping <= oi.Quantity, oi.Price * oi.Quantity, 0)) AS TotalAmountPromo
 						FROM '.TABLE_PREFIX.'OrderItems oi
 						LEFT JOIN '.TABLE_PREFIX.'Products p ON oi.ProductId = p.ProductId
 						WHERE oi.OrderId = '.$order->GetID().' AND p.Type = 1';
 			$shipping_totals = $this->Conn->GetRow($query);
 
 			$this->Application->recallObject('ShippingQuoteEngine');
+
+			/** @var ShippingQuoteCollector $quote_engine_collector */
 			$quote_engine_collector = $this->Application->recallObject('ShippingQuoteCollector');
-			/* @var $quote_engine_collector ShippingQuoteCollector */
 
 			$shipping_quote_params = Array(
 				'dest_country'	=>	$order->GetDBField('ShippingCountry'),
 				'dest_state'	=>	$order->GetDBField('ShippingState'),
 				'dest_postal'	=>	$order->GetDBField('ShippingZip'),
 				'dest_city'		=>	$order->GetDBField('ShippingCity'),
 				'dest_addr1'	=>	'',
 				'dest_addr2'	=>	'',
 				'dest_name'		=>	'user-' . $order->GetDBField('PortalUserId'),
 				'packages' 		=>	Array(
 										Array(
 											'package_key'	=>	'package1',
 											'weight'		=>	$shipping_totals['TotalWeight'],
 											'weight_unit'	=>	'KG',
 											'length'		=>	'',
 											'width'			=>	'',
 											'height'		=>	'',
 											'dim_unit'		=>	'IN',
 											'packaging'		=>	'BOX',
 											'contents'		=>	'OTR',
 											'insurance'		=>	'0'
 										),
 									),
 				'amount'		=>	$shipping_totals['TotalAmount'],
 				'items'			=>	$shipping_totals['TotalItems'],
 				'limit_types' 	=> 	serialize(Array ('ANY')),
 
 				'promo_params'	=>	Array (
 					'items'		=>	$shipping_totals['TotalItemsPromo'],
 					'amount'	=>	$shipping_totals['TotalAmountPromo'],
 					'weight'	=>	$shipping_totals['TotalWeightPromo'],
 				),
 			);
 
 			return $quote_engine_collector->GetShippingQuotes($shipping_quote_params);
 		}
 
 		/**
 		 * Returns gateway responce from last operation
 		 *
 		 * @return string
 		 */
 		function getGWResponce()
 		{
 			return serialize($this->parsed_responce);
 		}
 
 		/**
 		 * Informs payment gateway, that order has been shipped
 		 *
 		 * http://code.google.com/apis/checkout/developer/Google_Checkout_XML_API_Order_Level_Shipping.html#Deliver_Order
 		 *
 		 * @param Array $item_data
 		 * @param Array $gw_params
 		 * @return bool
 		 */
 		function OrderShipped($item_data, $gw_params)
 		{
 			$this->gwParams = $gw_params;
 
 			$shipping_info = unserialize($item_data['ShippingInfo']);
 			if (getArrayValue($shipping_info, 'Code')) {
 				$traking_carrier = ''.$item_data['Code'].'';
 			}
 
 			if ($item_data['ShippingTracking']) {
 				$tracking_data = ''.$traking_carrier.'
         							 '.$item_data['ShippingTracking'].'
         						  ';
 			}
 
 			$ship_xml = '	
 								'.$traking_data.'
     							true
 							';
 			$root_node =& $this->executeAPICommand($ship_xml);
 		}
 
 		/**
 		 * Informs payment gateway, that order has been declined
 		 *
 		 * @param Array $item_data
 		 * @param Array $gw_params
 		 * @return bool
 		 */
 		function OrderDeclined($item_data, $gw_params)
 		{
 
 		}
 	}
Index: branches/5.2.x/units/gateways/gw_classes/sella_guestpay.php
===================================================================
--- branches/5.2.x/units/gateways/gw_classes/sella_guestpay.php	(revision 16515)
+++ branches/5.2.x/units/gateways/gw_classes/sella_guestpay.php	(revision 16516)
@@ -1,163 +1,163 @@
  Array('Name' => 'Sella/GuestPay', 'ClassName' => 'kSellaGuestPayGW', 'ClassFile' => 'sella_guestpay.php', 'RequireCCFields' => 0),
 				'ConfigFields' => Array(
 					'merchant_id' => Array('Name' => 'Merchant ID', 'Type' => 'text', 'ValueList' => '', 'Default' => ''),
 					'merchant_country' => Array('Name' => 'Merchant Country Code', 'Type' => 'text', 'ValueList' => '', 'Default' => ''),
 					'currency_code' => Array('Name' => 'Currency Code', 'Type' => 'text', 'ValueList' => '', 'Default' => '978'),
 					'language_code' => Array('Name' => 'Language Code', 'Type' => 'text', 'ValueList' => '', 'Default' => '2'),
 					'shipping_control' => Array('Name' => 'Shipping Control', 'Type' => 'select', 'ValueList' => '3=la_CreditDirect,4=la_CreditPreAuthorize', 'Default' => '3'),
 				)
 			);
 			return $data;
 		}
 
 		/**
 		 * Returns payment form submit url
 		 *
 		 * @param Array $gw_params gateway params from payment type config
 		 * @return string
 		 */
 		function getFormAction($gw_params)
 		{
 			return 'https://ecomm.sella.it/gestpay/pagam.asp';
 		}
 
 		/**
 		 * Processed input data and convets it to fields understandable by gateway
 		 *
 		 * @param Array $item_data
 		 * @param Array $tag_params additional params for gateway passed through tag
 		 * @param Array $gw_params gateway params from payment type config
 		 * @return Array
 		 */
 		function getHiddenFields($item_data, $tag_params, $gw_params)
 		{
 			$a = $gw_params['merchant_id'];
 			$params['PAY1_UICCODE'] = $gw_params['currency_code'];
 			$params['PAY1_AMOUNT'] = $item_data['TotalAmount'];
 			$params['PAY1_SHOPTRANSACTIONID'] = $item_data['OrderId'];
 			$params['PAY1_IDLANGUAGE'] = $gw_params['language_code'];
 			$params['CUSTOM_INFO'] = $this->Application->GetSID().','.MD5($item_data['OrderId']);
 
 			$separator = '*P1*';
 			$b = array();
 			foreach ($params as $key=>$val) {
 				$b[] = $key.'='.kUtil::escape(trim($val), kUtil::ESCAPE_URL);
 			}
 			//the last one is CUSTOMINFO according to GW specs, passing the atosorigin-style 'caddie'
 			$b = join($separator, $b);
 			$url = 'https://ecomm.sella.it/CryptHTTPS/Encrypt.asp?a='.$a.'&b='.$b.'&c=2.0';
 
+			/** @var kCurlHelper $curl_helper */
 			$curl_helper = $this->Application->recallObject('CurlHelper');
-			/* @var $curl_helper kCurlHelper */
 
 			$res = $curl_helper->Send($url);
 
 			preg_match('/#cryptstring#(.*)#\/cryptstring#/', $res, $matches);
 			$b = $matches[1];
 
 			$res = '';
 			return $res;
 		}
 
 		function NeedPlaceButton($item_data, $tag_params, $gw_params)
 		{
 			return true;
 		}
 
 		function processNotification($gw_params)
 		{
 			$a = $gw_params['merchant_id'];
 			$b = $_GET['b'];
 			$url = 'https://ecomm.sella.it/CryptHTTPS/Decrypt.asp?a='.$a.'&b='.$b.'&c=2.0';
 
+			/** @var kCurlHelper $curl_helper */
 			$curl_helper = $this->Application->recallObject('CurlHelper');
-			/* @var $curl_helper kCurlHelper */
 
 			$ret = $curl_helper->Send($url);
 			$result = $this->parseGWResponce($ret, $gw_params);
 
 			list ($sid, $auth_code) = explode(',', $result['CUSTOM_INFO']);
 			$session = $this->Application->recallObject('Session');
 			$session->SID = $sid;
 
 			$order_id = $this->Conn->GetOne('SELECT OrderId FROM '.TABLE_PREFIX.'Orders WHERE md5(OrderId) = '.$this->Conn->qstr($auth_code));
 			$this->Application->SetVar('ord_id', $order_id);
 			$order = $this->Application->recallObject('ord');
 			$order->Load($order_id);
 
 			if ($this->Application->GetVar('sella_ok')) {
 				if ($result['PAY1_TRANSACTIONRESULT'] == 'OK') {
 					$this->Application->Redirect('in-commerce/checkout/checkout_success', null, '_FRONT_END_', 'index.php');
 				}
 				else {
 					$this->Application->SetVar('sella_error', 1);
 				}
 			}
 			if ($this->Application->GetVar('sella_error')) {
 				$this->Application->StoreVar('gw_error', $this->getErrorMsg());
 				$this->Application->Redirect('in-commerce/checkout/billing', null, '_FRONT_END_', 'index.php');
 			}
 
 			return $result['PAY1_TRANSACTIONRESULT'] == 'OK' ? 1 : 0;
 		}
 
 		function parseGWResponce($str, $gw_params)
 		{
 			if (preg_match('/#decryptstring#(.*)#\/decryptstring#/', $str, $matches)) {
 				$separator = '*P1*';
 				$pairs = explode($separator, $matches[1]);
 				foreach ($pairs as $a_pair) {
 					list($key, $val) = explode('=', $a_pair);
 					$result[$key] = $val;
 				}
 			}
 			elseif (preg_match('/#error#(.*)#\/error#/', $str, $matches))
 			{
 				$result['PAY1_ERRORDESCRIPTION'] = $matches[1];
 			}
 			else { //unknown error
 				$result['PAY1_ERRORDESCRIPTION'] = 'Unknown error';
 			}
 
 			$this->parsed_responce = $result;
 			return $result;
 		}
 
 		function getGWResponce()
 		{
 			return serialize($this->parsed_responce);
 		}
 
 		function getErrorMsg()
 		{
 			$msg = $this->parsed_responce['PAY1_ERRORDESCRIPTION'];
 			if (!$msg) {
 				if ($this->parsed_responce['response_code'] != 'OK') {
 					$msg = 'Transaction failed';
 				}
 			}
 			return $msg;
 		}
 	}
\ No newline at end of file
Index: branches/5.2.x/units/gateways/gw_classes/worldpay.php
===================================================================
--- branches/5.2.x/units/gateways/gw_classes/worldpay.php	(revision 16515)
+++ branches/5.2.x/units/gateways/gw_classes/worldpay.php	(revision 16516)
@@ -1,117 +1,117 @@
  Array('Name' => 'Worldpay', 'ClassName' => 'kGWWorldPay', 'ClassFile' => 'worldpay.php', 'RequireCCFields' => 0),
 				'ConfigFields' => Array(
 					'submit_url' => Array('Name' => 'Submit URL', 'Type' => 'text', 'ValueList' => '', 'Default' => 'https://select.worldpay.com/wcc/purchase'),
 					'instId' => Array('Name' => 'Installation ID', 'Type' => 'text', 'ValueList' => '', 'Default' => ''),
 					'callback_pw' => Array('Name' => 'Callback Password', 'Type' => 'text', 'ValueList' => '', 'Default' => ''),
 				)
 			);
 			return $data;
 		}
 
 		/**
 		 * Returns payment form submit url
 		 *
 		 * @param Array $gw_params gateway params from payment type config
 		 * @return string
 		 */
 		function getFormAction($gw_params)
 		{
 			return $gw_params['submit_url'];
 		}
 
 		/**
 		 * Processed input data and convets it to fields understandable by gateway
 		 *
 		 * @param Array $item_data
 		 * @param Array $tag_params additional params for gateway passed through tag
 		 * @param Array $gw_params gateway params from payment type config
 		 * @return Array
 		 */
 		function getHiddenFields($item_data, $tag_params, $gw_params)
 		{
 			$ret = Array();
 
 			$ret['instId'] = $gw_params['instId'];
 			$ret['cartId'] = $item_data['OrderNumber'];
 
 			if (!$this->IsTestMode()) {
 				$ret['amount'] = sprintf('%.2f', $item_data['TotalAmount']); // the total amount to be billed, in decimal form, without a currency symbol. (8 characters, decimal, 2 characters: Example: 99999999.99)
 			}
 			else {
 				$ret['testMode'] = 100; // 100 - success, 101 - failure
 				$ret['amount'] = 1;
 			}
 
 			$ret['currency'] = 'USD';
 			$ret['desc'] = 'Order #'.$item_data['OrderNumber'];
 
 			$ret['name'] = $item_data['BillingTo'];
 			$ret['address'] = $item_data['BillingAddress1'];
 			if ($item_data['BillingAddress2']) {
 				$ret['address'] .= '
'.$item_data['BillingAddress2'];
 			}
 			$ret['postcode'] = $item_data['BillingZip'];
 
+			/** @var kCountryStatesHelper $cs_helper */
 			$cs_helper = $this->Application->recallObject('CountryStatesHelper');
-			/* @var $cs_helper kCountryStatesHelper */
 
 			$ret['country'] = $cs_helper->getCountryIso( $item_data['BillingCountry'] );
 			$ret['tel'] = $item_data['BillingPhone'];
 			$ret['fax'] = $item_data['BillingFax'];
 			$ret['email'] = $item_data['BillingEmail'];
 			$ret['fixContact'] = 1; // contact-info not editable ?
 
 			$return_params = Array ('pass' => 'm', 'sid' => $this->Application->GetSID(), 'admin' => 1);
 			$ret['MC_return_page'] = $this->Application->HREF($tag_params['return_template'], '', $return_params);
 			$ret['MC_cancel_return_page'] = $this->Application->HREF($tag_params['cancel_template'], '', $return_params);
 			$ret['MC_callback'] = $this->getNotificationUrl() . '?sid='.$this->Application->GetSID().'&admin=1&order_id='.$item_data['OrderId'];
 
 			return $ret;
 		}
 
 		function processNotification($gw_params)
 		{
     		// http://support.worldpay.com/kb/integration_guides/junior/integration/help/appendicies/sjig_10100.html
     		// SubmitURL: https://select.worldpay.com/wcc/purchase
 			// for Notification to work do this in gateway Admin Console:
     		// Callback URL: 
     		// Callback enabled? [x]
     		// Use callback response?[x]
 			$transaction_verified = ($this->Application->GetVar('callbackPW') == $gw_params['callback_pw']);
     		if (!$transaction_verified) {
     			return 0;
     		}
 
     		$transaction_status = $this->Application->GetVar('transStatus') == 'Y' ? 1 : 0;
 
+			/** @var kCurlHelper $curl_helper */
     		$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/gateways/gw_classes/paypal.php
===================================================================
--- branches/5.2.x/units/gateways/gw_classes/paypal.php	(revision 16515)
+++ branches/5.2.x/units/gateways/gw_classes/paypal.php	(revision 16516)
@@ -1,269 +1,269 @@
 Application->RecallVar('curr_iso');
 			$available = explode(',', $gw_params['currency_code']);
 			$target = in_array($selected_cur, $available) ? $selected_cur : $available[0];
 
 			if( !$this->IsTestMode() )
 			{
 				$currency_iso = $gw_params['currency_code'];
 				$ret['amount'] = $this->ConvertCurrency($item_data['SubTotal'], $target);
 				$ret['shipping'] =  $this->ConvertCurrency($item_data['ShippingCost'], $target);
 				$ret['tax'] = $this->ConvertCurrency($item_data['VAT'], $target);
 			}
 			else
 			{
 				$ret['amount'] = 1;
 				$ret['shipping'] = 0;
 				$ret['tax'] = 0;
 			}
 
 			$ret['quantity'] = 1;
 			$ret['cancel_return'] = $this->Application->HREF($tag_params['cancel_template'],'',Array('pass'=>'m'));
 			$ret['return'] = $this->Application->HREF($tag_params['return_template'],'',Array('pass'=>'m'));
 			$ret['no_note'] = 1;	// customer is not prompted for notes
 			$ret['no_shipping'] = 1;	// customer is not prompted for shipping address
 			$ret['rm'] = 2;	// return method - POST
 			$ret['currency_code'] = $target;
 			$ret['invoice'] = $item_data['OrderNumber'];
 			$ret['business'] = $gw_params['business_account'];
 
 			// prepopulated fields
 			$ret['address_override'] = 1; // override user's stored address
 			$ret['email'] = $item_data['BillingEmail'];
 			list($first_name, $last_name) = explode(' ', $item_data['BillingTo']);
 			$ret['first_name'] = $first_name;
 			$ret['last_name'] = $last_name;
 			$ret['address1'] = $item_data['BillingAddress1'];
 			$ret['address2'] = $item_data['BillingAddress2'];
 			$ret['city'] = $item_data['BillingCity'];
 			$ret['state'] = $item_data['BillingState'];
 			$ret['zip'] = $item_data['BillingZip'];
 
+			/** @var kCountryStatesHelper $cs_helper */
 			$cs_helper = $this->Application->recallObject('CountryStatesHelper');
-			/* @var $cs_helper kCountryStatesHelper */
 
 			$ret['country'] = $cs_helper->getCountryIso( $item_data['BillingCountry'] );
 			$ret['notify_url'] = $this->getNotificationUrl() . '?sid=' . $this->Application->GetSID() . '&admin=1&order_id=' . $item_data['OrderId'];
 
 			$ret['cmd'] = '_xclick'; // act as "Buy Now" PayPal button
 			return $ret;
 		}
 
 		function getSubscriptionFields($item_data, $tag_params, $gw_params)
 		{
 
 			$ret = Array();
 			$ret['item_name'] = $item_data['item_name'];
 			$ret['item_number'] = $item_data['item_number'];
 			$ret['a1'] = $item_data['a1'];
 			$ret['p1'] = $item_data['p1'];
 			$ret['t1'] = $item_data['t1'];
 			$ret['a2'] = $item_data['a2'];
 			$ret['p2'] = $item_data['p2'];
 			$ret['t2'] = $item_data['t2'];
 
 			$ret['p3'] = $item_data['p3'];
 			$ret['t3'] = $item_data['t3'];
 			$ret['src'] = $item_data['src'];
 			$ret['sra'] = $item_data['sra'];
 			$ret['srt'] = $item_data['srt'];
 
 			$ret['custom'] = $item_data['OrderId'];
 
 			$currency_iso = $gw_params['currency_code'];
 			$ret['a3'] = $this->ConvertCurrency($item_data['a3'], $currency_iso);;
 			$ret['tax'] = $this->ConvertCurrency($item_data['VAT'], $currency_iso);
 			if( $this->Application->isDebugMode() )
 			{
 
 			}
 			else
 			{
 
 			}
 
 //			$ret['quantity'] = 1;
 			$ret['cancel_return'] = $this->Application->HREF($tag_params['cancel_template'],'',Array('pass'=>'m'));
 			$ret['return'] = $this->Application->HREF($tag_params['return_template'],'',Array('pass'=>'m'));
 			$ret['no_note'] = 1;	// customer is not prompted for notes
 			$ret['no_shipping'] = 1;	// customer is not prompted for shipping address
 			$ret['rm'] = 2;	// return method - POST
 			$ret['currency_code'] = $gw_params['currency_code'];
 			$ret['invoice'] = $item_data['OrderNumber'];
 			$ret['business'] = $gw_params['business_account'];
 
 			// prepopulated fields
 			$ret['address_override'] = 1; // override user's stored address
 			$ret['email'] = $item_data['BillingEmail'];
 			list($first_name, $last_name) = explode(' ', $item_data['BillingTo']);
 			$ret['first_name'] = $first_name;
 			$ret['last_name'] = $last_name;
 			$ret['address1'] = $item_data['BillingAddress1'];
 			$ret['address2'] = $item_data['BillingAddress2'];
 			$ret['city'] = $item_data['BillingCity'];
 			$ret['state'] = $item_data['BillingState'];
 			$ret['zip'] = $item_data['BillingZip'];
 
+			/** @var kCountryStatesHelper $cs_helper */
 			$cs_helper = $this->Application->recallObject('CountryStatesHelper');
-			/* @var $cs_helper kCountryStatesHelper */
 
 			$ret['country'] = $cs_helper->getCountryIso( $item_data['BillingCountry'] );
 			$ret['notify_url'] = $this->getNotificationUrl() . '?sid='.$this->Application->GetSID().'&admin=1&order_id='.$item_data['OrderId'].'&payment_type_id='.$tag_params['payment_type_id'];
 			$ret['cmd'] = '_xclick-subscriptions'; // act as "Buy Now" PayPal button
 
 			$real_ret = array();
 			foreach ($ret as $key => $val)
 			{
 				if ($val == '') continue;
 				$real_ret[$key] = $val;
 			}
 
 			return $real_ret;
 		}
 
 		function processNotification($gw_params)
 		{
 			$payment_status = $_POST['payment_status']; // save payment_status for later proceeding
 
 			$_POST['cmd'] = '_notify-validate';
 
 			// status, of that PayPal server really has sent such notification to us
 			$status_map = Array('INVALID' => 0, 'VERIFIED' => 1);
 
+			/** @var kCurlHelper $curl_helper */
 			$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 !
 
 			if (!$success) return;
 
 			$type = $_POST['txn_type'];
 			switch ($type)
 			{
 				case 'subscr_signup':
 					break;
 				case 'subscr_cancel':
 					break;
 				case 'subscr_failed':
 					break;
 				case 'subscr_payment':
 					$field_values = $this->Conn->GetRow('SELECT * FROM '.TABLE_PREFIX.'OrderItems WHERE OrderItemId = '.$_POST['item_number']);
 					$this->Application->HandleEvent(new kEvent('p:OnSubscriptionApprove', array('field_values' => $field_values)));
 					$success = 0; //this will eliminate OnCompleteOrder in gw_notify!
 
+					/** @var kDBItem $org_order */
 					$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->GetFieldValues());
 					$order->SetDBField('SubTotal', $field_values['Price']);
 					$order->SetDBField('OriginalAmout', $field_values['Price']);
 					$order->SetDBField('OrderDate', adodb_mktime());
 					$order->UpdateFormattersSubFields();
 
 					$dup_item = false;
 					if ($org_order->GetDBField('Status') >= ORDER_STATUS_PROCESSED) {
 						$sql = 'SELECT MAX(SubNumber) FROM '.TABLE_PREFIX.'Orders WHERE Number = '.$org_order->GetDBField('Number');
 						$num = $this->Conn->GetOne($sql) + 1;
 						$order->SetDBField('SubNumber', $num);
 						$dup_item = true;
 					}
 					else {
 						$sql = 'SELECT MAX(Number) FROM '.TABLE_PREFIX.'Orders';
 						$num = $this->Conn->GetOne($sql) + 1;
 						$order->SetDBField('Number', $num);
 						$order->SetDBField('SubNumber', 0);
 					}
 					$order->SetDBField('PaymentType', $this->Application->GetVar('payment_type_id'));
 					$info = array(
 						'BillingTo' => $_POST['first_name'].' '.$_POST['last_name'],
 						'BillingCompany' => 'n/a (PayPal)',
 						'BillingPhone' => 'n/a (PayPal)',
 						'BillingFax' => '',
 						'BillingEmail' => $_POST['payer_email'],
 						'BillingAddress1' => 'n/a (PayPal)',
 						'BillingCity' => 'n/a (PayPal)',
 						'BillingState' => 'n/a (PayPal)',
 						'BillingZip' => 'n/a (PayPal)',
 						'BillingCountry' => '???',
 					);
 
 					// TODO: maybe this should be SetDBFieldsFromHash instead, because all data comes from inside.
 					$order->SetFieldsFromHash($info);
 
 					$order->SetDBField('Status', ORDER_STATUS_PROCESSED);
 
 					$order->Create();
 					if ($dup_item) {
 						$query = 'INSERT INTO '.TABLE_PREFIX.'OrderItems
 											(OrderId, ProductId, ProductName, Quantity, QuantityReserved, FlatPrice, Price, BackOrderFlag, Weight, ShippingTypeId, ItemData, OptionsSalt)
 											SELECT
 												'.$order->GetId().' AS OrderId, ProductId, ProductName, Quantity, QuantityReserved, FlatPrice, Price, BackOrderFlag, Weight, ShippingTypeId, ItemData, OptionsSalt
 											FROM '.TABLE_PREFIX.'OrderItems
 											WHERE OrderItemId = '.$field_values['OrderItemId'];
 					}
 					else {
 						$query = 'UPDATE '.TABLE_PREFIX.'OrderItems SET OrderId = %s WHERE OrderItemId = %s';
 						$query = sprintf($query, $order->GetId(), $field_values['OrderItemId']);
 					}
 					$this->Conn->Query($query);
 
 					break;
 				case 'subscr_eot':
 					break;
 				case 'subscr_modify':
 					break;
 			}
 
 			return $success;
 		}
 	}
Index: branches/5.2.x/units/gateways/gw_classes/gw_base.php
===================================================================
--- branches/5.2.x/units/gateways/gw_classes/gw_base.php	(revision 16515)
+++ branches/5.2.x/units/gateways/gw_classes/gw_base.php	(revision 16516)
@@ -1,261 +1,261 @@
 Application->ProcessParsedTag('m', 'FormAction', Array() );
 		}
 
 		/**
 		 * Processed input data and convets it to fields understandable by gateway
 		 *
 		 * @param Array $item_data
 		 * @param Array $tag_params additional params for gateway passed through tag
 		 * @param Array $gw_params gateway params from payment type config
 		 * @return Array
 		 */
 		function getHiddenFields($item_data, $tag_params, $gw_params)
 		{
 			return Array(	'events[ord]' => 'OnCompleteOrder',
 							'success_template' => $tag_params['return_template'],
 							'failure_template' => $tag_params['cancel_template']);
 		}
 
 		function NeedPlaceButton($item_data, $tag_params, $gw_params)
 		{
 			return true;
 		}
 
 		/**
 		 * Process notification about payment from payment gateway
 		 *
 		 * @param Array $gw_params
 		 * @return bool
 		 */
 		function processNotification($gw_params)
 		{
 
 		}
 
 		/**
 		 * Perform PREAUTH/SALE type transaction direct from php script wihtout redirecting to 3rd-party website
 		 *
 		 * @param Array $item_data
 		 * @param Array $gw_params
 		 * @return bool
 		 */
 		function DirectPayment($item_data, $gw_params)
 		{
 			return true;
 		}
 
 		/**
 		 * Perform SALE type transaction direct from php script wihtout redirecting to 3rd-party website
 		 *
 		 * @param Array $item_data
 		 * @param Array $gw_params
 		 * @return bool
 		 */
 		function Charge($item_data, $gw_params)
 		{
 			return true;
 		}
 
 		/**
 		 * Informs payment gateway, that order has been shipped
 		 *
 		 * @param Array $item_data
 		 * @param Array $gw_params
 		 * @return bool
 		 */
 		function OrderShipped($item_data, $gw_params)
 		{
 
 		}
 
 		/**
 		 * Informs payment gateway, that order has been declined
 		 *
 		 * @param Array $item_data
 		 * @param Array $gw_params
 		 * @return bool
 		 */
 		function OrderDeclined($item_data, $gw_params)
 		{
 
 		}
 
 		/**
 		 * Returns gateway responce from last operation
 		 *
 		 * @return string
 		 */
 		function getGWResponce()
 		{
 			return $this->gw_responce;
 		}
 
 		/**
 		 * Parse previously saved gw responce into associative array
 		 *
 		 * @param string $gw_responce
 		 * @param Array $gw_params
 		 * @return Array
 		 */
 		function parseGWResponce($gw_responce, $gw_params)
 		{
 			return $this->gw_responce;
 		}
 
 		/**
 		 * Returns true if we should use testing mode
 		 *
 		 * @return bool
 		 */
 		function IsTestMode()
 		{
 			return defined('DEBUG_MODE') && kUtil::constOn('DBG_PAYMENT_GW');
 		}
 
 		/**
 		 * Convery primary currency to selected (if they are the same, converter will just return)
 		 *
 		 * @param double $value
 		 * @param string $iso
 		 * @param bool $format_value
 		 * @return double
 		 */
 		function ConvertCurrency($value, $iso, $format_value = true)
 		{
+			/** @var CurrencyRates $converter */
 			$converter = $this->Application->recallObject('CurrencyRates');
-			/* @var $converter CurrencyRates */
 
 			$value = $converter->Convert($value, 'PRIMARY', $iso);
 			return $format_value ? sprintf('%.2f', $value) : $value;
 		}
 
 		function InstallData()
 		{
 			return array();
 		}
 
 		function Install()
 		{
 			if ($this->IsInstalled()) {
 				return;
 			}
 
 			$data = $this->InstallData();
 			if (!$data) {
 				return ;
 			}
 
 			// 1. create gateway record
 			$fields_hash = Array ();
 			$gw_fields = Array ('Name', 'ClassName', 'ClassFile', 'RequireCCFields');
 			foreach ($gw_fields as $gw_field) {
 				$fields_hash[$gw_field] = $data['Gateway'][$gw_field];
 			}
 			$this->Conn->doInsert($fields_hash, TABLE_PREFIX.'Gateways');
 			$gw_id = $this->Conn->getInsertID();
 
 			// 2. create DISABLED payment type, that uses this gateway (used for storing configuration properties of gateway)
+			/** @var kDBItem $payment_type */
 			$payment_type = $this->Application->recallObject('pt.-item', null, Array ('skip_autoload' => true));
-			/* @var $payment_type kDBItem */
 
 			$payment_type->Clear();
 			$fields_hash = Array (
 				'Name' => $data['Gateway']['Name'],
 				'l' . $this->Application->GetDefaultLanguageId() . '_Description' => $data['Gateway']['Name'],
 				'BuiltIn' => 1,
 				'GatewayId' => $gw_id,
 			);
 			$payment_type->SetDBFieldsFromHash($fields_hash);
 			$created = $payment_type->Create();
 			if (!$created) {
 				return ;
 			}
 
 			// 3. create gateway configuration fields
 			foreach ($data['ConfigFields'] as $field => $properties) {
 				$fields_hash = Array (
 					'SystemFieldName' => $field,
 					'GatewayId' => $gw_id,
 					'FieldName' => $properties['Name'],
 					'ElementType' => $properties['Type'],
 					'ValueList' => $properties['ValueList'],
 				);
 				$this->Conn->doInsert($fields_hash, TABLE_PREFIX.'GatewayConfigFields');
 				$fld_id = $this->Conn->getInsertID();
 
 				// 4. set default value for configuration property of gateway
 				$fields_hash = Array (
 					'GWConfigFieldId' => $fld_id,
 					'PaymentTypeId' => $payment_type->GetID(),
 					'Value' => $properties['Default'],
 				);
 				$this->Conn->doInsert($fields_hash, TABLE_PREFIX.'GatewayConfigValues');
 			}
 		}
 
 		function IsInstalled()
 		{
 			$data = $this->InstallData();
 			if (!$data) {
 				return true;
 			}
 
 			$sql = 'SELECT GatewayId
 					FROM '.TABLE_PREFIX.'Gateways
 					WHERE ClassName = '.$this->Conn->qstr($data['Gateway']['ClassName']);
 			return $this->Conn->GetOne($sql);
 		}
 
 		function getErrorMsg()
 		{
 			return '';
 		}
 
 		function gettestccnumbers()
 		{
 			return array();
 		}
 
 		function getNotificationUrl($script = 'gw_notify.php', $use_ssl = null)
 		{
 			// custom path can be: units/gateways/gw_classes/notify_scripts/google_checkout_shippings.php'
 
 			$ret = MODULES_PATH . '/in-commerce/' . $script;
 			$ret = preg_replace('/^' . preg_quote(FULL_PATH . '/', '/') . '/', $this->Application->BaseURL('', $use_ssl), $ret);
 
 			return str_replace(DIRECTORY_SEPARATOR, '/', $ret);
 		}
 	}
\ No newline at end of file
Index: branches/5.2.x/units/gateways/gw_classes/ideal_nl.php
===================================================================
--- branches/5.2.x/units/gateways/gw_classes/ideal_nl.php	(revision 16515)
+++ branches/5.2.x/units/gateways/gw_classes/ideal_nl.php	(revision 16516)
@@ -1,170 +1,170 @@
  Array('Name' => 'iDEAL.nl', 'ClassName' => 'kGWiDEALnl', 'ClassFile' => 'ideal_nl.php', 'RequireCCFields' => 0),
 				'ConfigFields' => Array(
 					'partner_id' => Array('Name' => 'Partner ID', 'Type' => 'text', 'ValueList' => '', 'Default' => ''),
 					'request_url' => Array('Name' => 'Request URL', 'Type' => 'text', 'ValueList' => '', 'Default' => 'http://www.mollie.nl/xml/ideals'),
 					'shipping_control' => Array('Name' => 'Shipping Control', 'Type' => 'select', 'ValueList' => '3=la_CreditDirect,4=la_CreditPreAuthorize', 'Default' => '3'),
 				)
 			);
 			return $data;
 		}
 
 		/**
 		 * Processed input data and convets it to fields understandable by gateway
 		 *
 		 * @param Array $item_data
 		 * @param Array $tag_params additional params for gateway passed through tag
 		 * @param Array $gw_params gateway params from payment type config
 		 * @return Array
 		 */
 		function getHiddenFields($item_data, $tag_params, $gw_params)
 		{
 			$this->Application->StoreVar('gw_success_template',$tag_params['return_template']);
 			$this->Application->StoreVar('gw_cancel_template',$tag_params['cancel_template']);
 
+			/** @var kCurlHelper $curl_helper */
 			$curl_helper = $this->Application->recallObject('CurlHelper');
-			/* @var $curl_helper kCurlHelper */
 
 			$banks = $curl_helper->Send($gw_params['request_url'].'?a=banklist');
 
+			/** @var kXMLHelper $parser */
 			$parser = $this->Application->recallObject('kXMLHelper');
-			/* @var $parser kXMLHelper */
 			$bank_data =& $parser->Parse($banks);
 
 			$bank_data->FindChild('response');
 			$banks = array();
 			foreach ($bank_data->Children as $a_child) {
 				if ($a_child->Name != 'BANK') continue;
 				$banks[$a_child->FindChildValue('bank_id')] = $a_child->FindChildValue('bank_name');
 			}
 
 			$ret = $this->Application->Phrase('lu_Select_iDEAL_bank').': ';
 			$ret .= ''."\n";
 			return $ret;
 		}
 
 		function DirectPayment($item_data, $gw_params)
 		{
 			$fields = array();
 
 			$fields['a'] = 'fetch';
 			$fields['partnerid'] = $gw_params['partner_id'];
 			$txt_amount = sprintf("%.2f", $item_data['TotalAmount']);
 			$fields['amount'] = str_replace( Array('.', ','), '', $txt_amount);
 			$fields['bank_id'] = $this->Application->GetVar('ideal_nl_bank_id');
 			$fields['description'] = 'Invoice #'.$item_data['OrderNumber'];
 			$fields['returnurl'] = $this->getNotificationUrl() . '?order_id='.$item_data['OrderId'];
 			$fields['reporturl'] = $this->getNotificationUrl() . '?mode=report&order_id='.$item_data['OrderId'];
 
+			/** @var kCurlHelper $curl_helper */
 			$curl_helper = $this->Application->recallObject('CurlHelper');
-			/* @var $curl_helper kCurlHelper */
 
 			$curl_helper->SetRequestData($fields);
 			$transaction_xml = $curl_helper->Send($gw_params['request_url']);
 
+			/** @var kXMLHelper $parser */
 			$parser = $this->Application->recallObject('kXMLHelper');
-			/* @var $parser kXMLHelper */
 			$trans_data =& $parser->Parse($transaction_xml);
 			$transaction_id = $trans_data->FindChildValue('transaction_id');
 			$url = $trans_data->FindChildValue('url');
 
 			if ($transaction_id && $url) {
 				$this->Application->Redirect('external:'.$url);
 			}
 			else {
 				$error_msg = $trans_data->FindChildValue('message');
 				$this->parsed_responce['XML'] = $transaction_xml;
 				$this->Application->SetVar('failure_template', $this->Application->RecallVar('gw_cancel_template'));
 				$this->parsed_responce['MESSAGE'] = $error_msg ? $error_msg : 'Unknown gateway error ('.kUtil::escape($transaction_xml, kUtil::ESCAPE_HTML).')';
 				return false;
 			}
 
 			return true;
 		}
 
 		function getErrorMsg()
 		{
 			return $this->parsed_responce['MESSAGE'];
 		}
 
 		function getGWResponce()
 		{
 			return serialize($this->parsed_responce);
 		}
 
 		function processNotification($gw_params)
 		{
 			// silent mode
 			if ($this->Application->GetVar('mode') == 'report') {
 				$fields = array();
 
 				$fields['a'] = 'check';
 				$fields['partnerid'] = $gw_params['partner_id'];
 				$fields['transaction_id'] =  $this->Application->GetVar('transaction_id');
 				$fields['bank_id'] = $this->Application->GetVar('ideal_nl_bank_id');
 
+				/** @var kCurlHelper $curl_helper */
 				$curl_helper = $this->Application->recallObject('CurlHelper');
-				/* @var $curl_helper kCurlHelper */
 
 				$curl_helper->SetRequestData($fields);
 				$check_xml = $curl_helper->Send($gw_params['request_url']);
 
+				/** @var kXMLHelper $parser */
 				$parser = $this->Application->recallObject('kXMLHelper');
-				/* @var $parser kXMLHelper */
 				$trans_data =& $parser->Parse($check_xml);
 
 				$response = $trans_data->FindChild('order');
 				foreach ($response->Children as $a_child) {
 					$this->parsed_responce[$a_child->Name] = $a_child->Data;
 				}
 				$this->parsed_responce['XML'] = $check_xml;
 
 				$result = $trans_data->FindChildValue('payed') == 'true' ? 1:0;
 				return $result;
 			}
 			else {
 				$order = $this->Application->recallObject('ord');
 				if ($order->GetDBField('Status') == ORDER_STATUS_INCOMPLETE) {
 					// error
 					$t = $this->Application->RecallVar('gw_cancel_template');
 					$this->parsed_responce = unserialize($order->GetDBField('GWResult1'));
 					$this->Application->StoreVar('gw_error', $this->getErrorMsg());
 					$this->Application->Redirect($t, array('pass'=>'m', 'm_cat_id'=>0));
 				}
 				else {
 					// ok
 					$t = $this->Application->RecallVar('gw_success_template');
 					$this->Application->Redirect($t, array('pass'=>'m', 'm_cat_id'=>0));
 
 				}
 			}
 		}
 	}
\ No newline at end of file
Index: branches/5.2.x/units/gateways/gw_classes/rightconnect.php
===================================================================
--- branches/5.2.x/units/gateways/gw_classes/rightconnect.php	(revision 16515)
+++ branches/5.2.x/units/gateways/gw_classes/rightconnect.php	(revision 16516)
@@ -1,224 +1,224 @@
 Conn->Query($query);
 			$id = $this->Conn->getInsertID();
 
 			$query = "INSERT INTO `".TABLE_PREFIX."GatewayConfigFields` ( `GWConfigFieldId` , `SystemFieldName` , `FieldName` , `ElementType` , `ValueList` , `GatewayId` )
 								VALUES (
 								'', 'submit_url', 'Submit URL', 'text', '', '$id'
 								), (
 								'', 'user_account', 'User Account', 'text', '', '$id'
 								), (
 								'', 'password', 'User Account', 'text', '', '$id'
 								),
 								(
 								'', 'encapsulate_char', 'Encapsualte Char', 'text', '', '$id'
 								)";
 			$this->Conn->Query($query);
 		}*/
 
 		function DirectPayment($item_data, $gw_params)
 		{
 
 			/*$post_fields["card_holder"] = "test test";
 			$post_fields["cardtype"] = "Visa";
 			$post_fields["card_number"] = "4444333322221111";
 			$post_fields["cvv2"] = "123";
 			$post_fields["exp_mon"] = "05";
 			$post_fields["exp_year"] = "05";
 			$post_fields["address1"] = "test";
 			$post_fields["city"] = "test";
 			$post_fields["state"] = "CA";
 			$post_fields["zip"] = "90069";
 			$post_fields["country"] = "USA";
 			$post_fields["firstname"] = "test";
 			$post_fields["lastname"] = "test";
 			$post_fields["email"] = "customer@yourdomain.com";
 			$post_fields["merchant_account"] = "demo";
 			$post_fields["trans_amount"] = "8.98";
 			$post_fields["user1"] = "DELIM";
 			$post_fields["ALIAS"] = "www.yourdomain.com";
 			$post_fields["customer_ip"] = $this->Application->getClientIp();
 			$post_fields["ADMIN_EMAIL"] = "admin@yourdomain.com";*/
 
 
 			$post_fields = Array();
 			// -- Login Information --
 			//$post_fields['x_version']			=	'3.1';
 			$post_fields["user1"] = "DELIM";
 
 			//$post_fields['x_type']				=	$gw_params['shipping_control'] == SHIPPING_CONTROL_PREAUTH ? 'AUTH_ONLY' : 'AUTH_CAPTURE';
 
 			$post_fields['merchant_account']	=	$gw_params['user_account'];
 			$post_fields['merchant_pass']			=	$gw_params['password'];
 
 			if( $this->IsTestMode() ) $post_fields['x_test_request'] = 'True';
 
 			// -- Payment Details --
 			$names = explode(' ', $item_data['BillingTo'], 2);
 			$post_fields['firstname']		=	getArrayValue($names, 0);
 			$post_fields['lastname']			=	getArrayValue($names, 1);
 			$post_fields['trans_amount']			=	sprintf('%.2f', $item_data['TotalAmount']);
 
 			//$post_fields['x_company']			=	$item_data['BillingCompany'];
 
 			$post_fields['card_number']			=	$item_data['PaymentAccount'];
 			$post_fields['card_holder']			=	$item_data['PaymentNameOnCard'];
 			$post_fields['cvv2']			=	$item_data['PaymentCVV2'];
 
 			list($exp_mon,$exp_year) = explode('/', $item_data['PaymentCCExpDate']);
 			$post_fields['exp_mon']			=	$exp_mon;
 			$post_fields['exp_year']			=	$exp_year;
 
 			$post_fields['address1']			=	$item_data['BillingAddress1'];
 			$post_fields['address2']			=	$item_data['BillingAddress2'];
 			$post_fields['city']				=	$item_data['BillingCity'];
 			$post_fields['state']				=	$item_data['BillingState'];
 			$post_fields['zip']				=	$item_data['BillingZip'];
 
 			$post_fields['country']			=	$item_data['BillingCountry'];
 
 			$post_fields['user2']			=	$item_data['PortalUserId'];
 			$post_fields['user3']		=	$item_data['OrderNumber'];
 			$post_fields['customer_email']	=	'FALSE';
 
 			$post_fields['customer_addr'] = $item_data['OrderIP']; // according to fields list in doc
 			$post_fields['customer_ip'] = $item_data['OrderIP']; // according to example from doc
 			$post_fields["email"] = $item_data['BillingEmail'];
 			$post_fields["ADMIN_EMAIL"] = $this->Application->ConfigValue('DefaultEmailSender');
 
+			/** @var kCurlHelper $curl_helper */
 			$curl_helper = $this->Application->recallObject('CurlHelper');
-			/* @var $curl_helper kCurlHelper */
 
 			$curl_helper->SetPostData($post_fields);
 			$this->gw_responce = $curl_helper->Send($gw_params['submit_url']);
 
 			$gw_responce = $this->parseGWResponce(null, $gw_params);
 
 			// gw_error_msg: $gw_response['responce_reason_text']
 			// gw_error_code: $gw_response['responce_reason_code']
 			return ($gw_responce['responce_code'] != 1) ? false : true;
 		}
 
 		/**
 		 * Captures Authorized transaction by transaction ID
 		 *
 		 * @param Array $item_data
 		 * @param Array $gw_params
 		 * @return bool
 		 */
 		function Charge($item_data, $gw_params)
 		{
 			return true;
 		}
 
 		/**
 		 * Parse previosly saved gw responce into associative array
 		 *
 		 * @param string $gw_responce
 		 * @param Array $gw_params
 		 * @return Array
 		 */
 		function parseGWResponce($gw_responce = null, $gw_params)
 		{
 			if( !isset($gw_responce) ) $gw_responce = $this->gw_responce;
 
 			$fields = Array(
 							'responce_code',  				// 0
 							'responce_sub_code',			// 1
 							'responce_reason_code',		// 2
 							'responce_reason_text',		// 3
 							'approval_code',					// 4
 							'avs_result_code',				// 5
 							'transaction_id',					// 6
 							'fraud_score',						// 7
 							'not_used8',							// 8
 							'amount',									// 9
 							'not_used10',							// 10
 							'transaction_type',				// 11
 							'not_used_customer_id',		// 12
 							'first_name',							// 13
 							'last_name',							// 14
 							'not_documented_empty_field', // 15 !!!!!!!!!!! DOES NOT MATCH DOCUMENTATION
 							'address',								// 16
 							'city',										// 17
 							'state',									// 18
 							'zip',										// 19
 							'country',								// 20
 							'phone',									// 21
 							'fax',										// 22
 							'email',									// 23
 							'ship_name',							// 24
 							'not_used25',							// 25
 							'not_used26',							// 26
 							'ship_address',						// 27
 							'ship_city',							// 28
 							'ship_state',							// 29
 							'ship_zip',								// 30
 							'ship_country',						// 31
 							'tax',										// 32
 							'not_used32',							// 33
 							'not_used33',							// 34
 							'not_used34',							// 35
 							'not_used35',							// 36
 							'not_used36',							// 37
 							'cvv_responce',						// 38
 							'receipt_number',					// 39
 							'passthru1',							// 40
 							'passthru2',							// 41
 							'passthru3',							// 42
 							'passthru4',							// 43
 							'passthru5',							// 44
 							'passthru6',							// 45
 							'passthru7',							// 46
 							'passthru8',							// 47
 							'passthru9',							// 48
 							'passthru10',							// 49
 							);
 
 			$encapsulate_char = $gw_params['encapsulate_char'];
 			if($encapsulate_char)
 			{
 				$ec_length = strlen($encapsulate_char);
 				$gw_responce = substr($gw_responce, $ec_length, $ec_length * -1);
 			}
 
 			$gw_responce = explode($encapsulate_char.','.$encapsulate_char, $gw_responce);
 			$ret = Array();
 			foreach($fields as $field_index => $field_name)
 			{
 				$ret[$field_name] = $gw_responce[$field_index];
 				unset($gw_responce[$field_index]);
 			}
 			$this->parsed_responce = $ret;
 			return kUtil::array_merge_recursive($ret, $gw_responce); // returns unparsed fields with they original indexes together with parsed ones
 		}
 
 		function getGWResponce()
 		{
 			return serialize($this->parsed_responce);
 		}
 
 	}
\ No newline at end of file
Index: branches/5.2.x/units/gateways/gw_tag_processor.php
===================================================================
--- branches/5.2.x/units/gateways/gw_tag_processor.php	(revision 16515)
+++ branches/5.2.x/units/gateways/gw_tag_processor.php	(revision 16516)
@@ -1,127 +1,127 @@
 Application->GetVar('pt_id');
 		$GWConfigValue = $this->Application->recallObject('gwfv');
 
 		$sql = 'SELECT Value, GWConfigFieldId FROM '.$GWConfigValue->TableName.' WHERE PaymentTypeId = '.$payment_type_id;
 		$this->ConfigValues = $this->Conn->GetCol($sql,'GWConfigFieldId');
 	}
 
 	function gwConfigValue($params)
 	{
+		/** @var kDBItem $object */
 		$object = $this->getObject($params);
-		/* @var $object kDBItem */
 
 		$id = $object->GetID();
 
 		$value = isset($this->ConfigValues[$id]) ? $this->ConfigValues[$id] : '';
 		if ( !array_key_exists('no_special', $params) || !$params['no_special'] ) {
 			$value = kUtil::escape($value);
 		}
 
 		if ( getArrayValue($params, 'checked') ) {
 			$value = ($value == 1) ? 'checked' : '';
 		}
 
 		return $value;
 	}
 
 	function PrintList($params)
 	{
 		$list = $this->Application->recallObject( $this->getPrefixSpecial(), $this->Prefix.'_List', $params);
 		$id_field = $this->Application->getUnitOption($this->Prefix,'IDField');
 
 		$list->Query();
 		$list->GoFirst();
 
 		$block_params=$this->prepareTagParams($params);
 		$block_params['name']=$params['block'];
 		$block_params['pass_params']='true';
 
 		$payment_type_object = $this->Application->recallObject('pt');
 
 		$o = '';
 
 		while (!$list->EOL())
 		{
 			$this->Application->SetVar( $this->getPrefixSpecial().'_id', $list->GetDBField($id_field) );
 
 			$display_style = $payment_type_object->GetDBField('GatewayId') == $list->GetDBField('GatewayId') ? 'table-row' : 'none';
 			$block_params['input_block'] = $params['input_block_prefix'].$list->GetDBField('ElementType');
 			$block_params['gateway_id'] = $list->GetDBField('GatewayId');
 			$block_params['display'] = $display_style;
 
 			$o .= $this->Application->ParseBlock($block_params, 1);
 
 			$list->GoNext();
 		}
 
 		return $o;
 	}
 
 	/**
 	 * Prints list a all possible field options
 	 *
 	 * @param Array $params
 	 * @return string
 	 * @access protected
 	 */
 	protected function PredefinedOptions($params)
 	{
+		/** @var kDBItem $object */
 		$object = $this->getObject($params);
-		/* @var $object kDBItem */
 
 		$block_params = $this->prepareTagParams($params);
 		$block_params['name'] = $this->SelectParam($params, 'render_as,block');
 		$block_params['pass_params'] = 'true';
 
 		$o = '';
 		$value = $this->gwConfigValue($params);
 		$options = explode(',', $object->GetDBField('ValueList'));
 
 		foreach ($options as $key_val) {
 			list($key, $val) = explode('=', $key_val);
 			$block_params['key'] = $key;
 			$block_params['option'] = $val;
 			$block_params['selected'] = ($key == $value ? ' ' . $params['selected'] : '');
 			$block_params['PrefixSpecial'] = $this->getPrefixSpecial();
 			$o .= $this->Application->ParseBlock($block_params, 1);
 		}
 
 		return $o;
 	}
 }
\ No newline at end of file
Index: branches/5.2.x/units/downloads/download_helper.php
===================================================================
--- branches/5.2.x/units/downloads/download_helper.php	(revision 16515)
+++ branches/5.2.x/units/downloads/download_helper.php	(revision 16516)
@@ -1,77 +1,77 @@
 Application->RecallVar('user_id').'
 							AND ProductId = '.$product_id;
 			return $this->Conn->GetOne($sql);
 		}
 
 		function SendFile($file_id, $product_id)
 		{
+			/** @var kDBItem $file_object */
 			$file_object = $this->Application->recallObject('file', null, Array('skip_autoload' => true));
-			/* @var $file_object kDBItem */
 
 			$sql = $file_id ?
 						'SELECT FileId, FilePath, RealPath, MIMEType FROM '.$this->Application->getUnitOption('file', 'TableName').'
 							WHERE FileId = '.$file_id :
 						'SELECT FileId, FilePath, RealPath, MIMEType FROM '.$this->Application->getUnitOption('file', 'TableName').'
 							WHERE ProductId = '.$product_id.' AND IsPrimary = 1';
 			$file_info = $this->Conn->GetRow($sql);
 
 			$field_options = $file_object->GetFieldOptions('RealPath');
 			$file_info['real_path'] = FULL_PATH.$field_options['upload_dir'].'/'.$file_info['RealPath'];
 			$file_info = $this->DoSendFile($file_info);
 			return $file_info;
 		}
 
 		function DoSendFile($file_info)
 		{
 			$this->Application->setContentType(kUtil::mimeContentType($file_info['real_path']), false);
 			header('Content-Disposition: attachment; filename="' . $file_info['FilePath'] . '"');
 			header('Content-Length: ' . filesize($file_info['real_path']));
 
 			$file_info['download_start'] = adodb_mktime();
 			readfile($file_info['real_path']);
 			flush();
 			$file_info['download_end'] = adodb_mktime(); // this is incorrect
 			define('SKIP_OUT_COMPRESSION', 1);
 			return $file_info;
 		}
 
 		function LogDownload($product_id, $file_info)
 		{
 			$down_object = $this->Application->recallObject('down', null, Array('skip_autoload' => true));
 			$user_object = $this->Application->recallObject('u.current');
 			$product_object = $this->Application->recallObject( 'p' );
 
 			$down_object->SetDBField('PortalUserId', $this->Application->RecallVar('user_id'));
 			$down_object->SetDBField('Username', $user_object->GetDBField('Username'));
 			$down_object->SetDBField('ProductId', $product_id);
 			$down_object->SetDBField('ProductName', $product_object->GetField('Name'));
 			$down_object->SetDBField('FileId', $file_info['FileId']);
 			$down_object->SetDBField('Filename', $file_info['FilePath']);
 			$down_object->SetDBField('IPAddress', $this->Application->getClientIp());
 			$down_object->SetDBField('StartedOn_date', $file_info['download_start']);
 			$down_object->SetDBField('StartedOn_time', $file_info['download_start']);
 
 			$down_object->Create();
 		}
 
 	}
\ No newline at end of file
Index: branches/5.2.x/units/product_options/product_options_event_handler.php
===================================================================
--- branches/5.2.x/units/product_options/product_options_event_handler.php	(revision 16515)
+++ branches/5.2.x/units/product_options/product_options_event_handler.php	(revision 16516)
@@ -1,110 +1,110 @@
 getEventParam('selectable_only');
 
 			if ( $selectable_only ) {
+				/** @var kDBList $object */
 				$object = $event->getObject();
-				/* @var $object kDBList */
 
 				$object->addFilter('types_filter', 'OptionType IN (1,3,6)');
 			}
 		}
 
 		/**
 		 * Updates temp_id to live_id in options combinations
 		 *
 		 * !Not called when "po" doesn't have subitems (temp handler problem)
 		 *
 		 * @param kEvent $event
 		 * @return void
 		 * @access protected
 		 */
 		protected function OnAfterCopyToLive(kEvent $event)
 		{
 			parent::OnAfterCopyToLive($event);
 
 			$id = $event->getEventParam('id');
 			$temp_id = $event->getEventParam('temp_id');
 
 			if ( $id == $temp_id ) {
 				return;
 			}
 
 			$poc_table = $this->Application->GetTempName(TABLE_PREFIX . 'ProductOptionCombinations', 'prefix:p');
 
 			$sql = 'SELECT *
 			FROM ' . $poc_table;
 			$combs = $this->Conn->Query($sql);
 
 			foreach ($combs as $a_comb) {
 				$comb_data = unserialize($a_comb['Combination']);
 				$n_combs = array ();
 				foreach ($comb_data as $key => $val) {
 					$n_key = $key == $temp_id ? $id : $key;
 					$n_combs[$n_key] = $val;
 				}
 				ksort($n_combs);
 				$n_combs = serialize($n_combs);
 				$n_crc = kUtil::crc32($n_combs);
 				$sql = 'UPDATE ' . $poc_table . '
 						SET
 							Combination = ' . $this->Conn->qstr($n_combs) . ',
 							CombinationCRC = ' . $n_crc . '
 						WHERE CombinationId = ' . $a_comb['CombinationId'];
 				$this->Conn->Query($sql);
 			}
 		}
 
 		/**
 		 * Occurs after an item has been cloned
 		 * Id of newly created item is passed as event' 'id' param
 		 *
 		 * @param kEvent $event
 		 * @return void
 		 * @access protected
 		 */
 		protected function OnAfterClone(kEvent $event)
 		{
 			parent::OnAfterClone($event);
 
 			$id = $event->getEventParam('id');
 			$org_id = $event->getEventParam('original_id');
 
 			// storing original to new ids mapping to use in poc:OnBeforeClone
 			$options_mapping = $this->Application->GetVar('poc_mapping');
 			if ( !$options_mapping ) {
 				$options_mapping = array ();
 			}
 
 			$options_mapping[$org_id] = $id;
 			$this->Application->SetVar('poc_mapping', $options_mapping);
 		}
 
 	}
\ No newline at end of file
Index: branches/5.2.x/units/product_options/product_options_tag_processor.php
===================================================================
--- branches/5.2.x/units/product_options/product_options_tag_processor.php	(revision 16515)
+++ branches/5.2.x/units/product_options/product_options_tag_processor.php	(revision 16516)
@@ -1,176 +1,176 @@
 getObject($params);
-		/* @var $object kDBItem */
 
+		/** @var kProductOptionsHelper $opt_helper */
 		$opt_helper = $this->Application->recallObject('kProductOptionsHelper');
-		/* @var $opt_helper kProductOptionsHelper */
 
 		$parsed = $opt_helper->ExplodeOptionValues($object->GetFieldValues());
 		if ( !$parsed ) {
 			return '';
 		}
 
 		$values = $parsed['Values'];
 		$conv_prices = $parsed['Prices'];
 		$conv_price_types = $parsed['PriceTypes'];
 
 		$options =& $this->GetOptions();
 
 		$mode = $this->SelectParam($params, 'mode');
 		$combination_prefix = $this->SelectParam($params, 'combination_prefix');
 		$combination_field = $this->SelectParam($params, 'combination_field');
 
 		if ( $mode == 'selected' ) {
+			/** @var kDBItem $comb */
 			$comb = $this->Application->recallObject($combination_prefix);
-			/* @var $comb kDBItem */
 
 			$options = unserialize($comb->GetDBField($combination_field));
 		}
 
 		$block_params['name'] = $params['render_as'];
 		$block_params['selected'] = '';
 		$block_params['pass_params'] = 1;
 
+		/** @var LanguagesItem $lang */
 		$lang = $this->Application->recallObject('lang.current');
-		/* @var $lang LanguagesItem */
 
 		$o = '';
 		$first_selected = false;
 
 		foreach ($values as $option) {
 //			list($val, $label) = explode('|', $option);
 			$val = $option;
 
 			if ( getArrayValue($params, 'js') ) {
 				$block_params['id'] = kUtil::escape($val, kUtil::ESCAPE_JS);
 				$block_params['value'] = kUtil::escape($val);
 			}
 			else {
 				$block_params['id'] = kUtil::escape($val);
 				$block_params['value'] = kUtil::escape($val);
 			}
 
 			if ( $conv_prices[$val] ) {
 				if ( $conv_price_types[$val] == '$' && !getArrayValue($params, 'js') && !getArrayValue($params, 'no_currency') ) {
 					$iso = $this->GetISO($params['currency']);
 					$value = sprintf("%.2f", $this->ConvertCurrency($conv_prices[$val], $iso));
 
 					$value = $this->AddCurrencySymbol($lang->formatNumber($value, 2), $iso, true); // true to force sign
 					$block_params['price'] = $value;
 					$block_params['price_type'] = '';
 					$block_params['sign'] = ''; //sign is included in the formatted value
 				}
 				else {
 					$block_params['price'] = isset($params['js']) ? $conv_prices[$val] : $lang->formatNumber($conv_prices[$val], 2);
 					$block_params['price_type'] = $conv_price_types[$val];
 					$block_params['sign'] = $conv_prices[$val] >= 0 ? '+' : '-';
 				}
 			}
 			else {
 				$block_params['price'] = '';
 				$block_params['price_type'] = '';
 				$block_params['sign'] = '';
 			}
 
 			/*if ($mode == 'selected') {
 				$selected = $combination[$object->GetID()] == $val;
 			}
 			else*/
 			$selected = false;
 
 			if ( !$options && isset($params['preselect_first']) && $params['preselect_first'] && !$first_selected ) {
 				$selected = true;
 				$first_selected = true;
 			}
 
 			if ( is_array($options) ) {
 				$option_value = array_key_exists($object->GetID(), $options) ? $options[$object->GetID()] : '';
 
 				if ( $object->GetDBField('OptionType') == OptionType::CHECKBOX ) {
 					$selected = is_array($option_value) && in_array(kUtil::escape($val), $option_value);
 				}
 				else { // radio buttons ?
 					// TODO: Not sure why we're unescaping.
 					$selected = kUtil::unescape($option_value, kUtil::ESCAPE_HTML) == $val;
 				}
 			}
 
 			if ( $selected ) {
 				if ( $mode == 'selected' ) {
 					if ( $object->GetDBField('OptionType') != OptionType::CHECKBOX ) {
 						$block_params['selected'] = ' selected="selected" ';
 					}
 					else {
 						$block_params['selected'] = ' checked="checked" ';
 					}
 				}
 				else {
 					switch ($object->GetDBField('OptionType')) {
 						case OptionType::DROPDOWN:
 							$block_params['selected'] = ' selected="selected" ';
 							break;
 						case OptionType::RADIO:
 						case OptionType::CHECKBOX:
 							$block_params['selected'] = ' checked="checked" ';
 							break;
 					}
 				}
 			}
 			else {
 				$block_params['selected'] = '';
 			}
 
 			$o .= $this->Application->ParseBlock($block_params);
 		}
 
 		return $o;
 	}
 
 	function &GetOptions()
 	{
 		$opt_data = $this->Application->GetVar('options');
 		$options = getArrayValue($opt_data, $this->Application->GetVar('p_id'));
 		if (!$options && $this->Application->GetVar('orditems_id')) {
+			/** @var kDBItem $ord_item */
 			$ord_item = $this->Application->recallObject('orditems.-opt', null, Array ('skip_autoload' => true));
-			/* @var $ord_item kDBItem */
 
 			$ord_item->Load($this->Application->GetVar('orditems_id'));
 			$item_data = unserialize($ord_item->GetDBField('ItemData'));
 			$options = getArrayValue($item_data, 'Options');
 		}
 		return $options;
 	}
 
 	function OptionData($params)
 	{
+		/** @var kDBItem $object */
 		$object = $this->getObject($params);
-		/* @var $object kDBItem */
 
 		$options =& $this->GetOptions();
 
 		return getArrayValue($options, $object->GetID());
 	}
 
 	function ListOptions($params)
 	{
 		return $this->PrintList2($params);
 	}
 }
Index: branches/5.2.x/units/pricing/pricing_event_handler.php
===================================================================
--- branches/5.2.x/units/pricing/pricing_event_handler.php	(revision 16515)
+++ branches/5.2.x/units/pricing/pricing_event_handler.php	(revision 16516)
@@ -1,525 +1,525 @@
  Array ('subitem' => 'add|edit'),
 			'OnInfinity' => Array ('subitem' => 'add|edit'),
 			'OnArrange' => Array ('subitem' => 'add|edit'),
 			'OnDeleteBrackets' => Array ('subitem' => 'add|edit'),
 		);
 
 		$this->permMapping = array_merge($this->permMapping, $permissions);
 	}
 
 	/**
 	 * Define alternative event processing method names
 	 *
 	 * @return void
 	 * @see kEventHandler::$eventMethods
 	 * @access protected
 	 */
 	protected function mapEvents()
 	{
 		parent::mapEvents();	// ensure auto-adding of approve/decline and so on events
 
 		$brackets_events = Array(
 			'OnMoreBrackets' => 'PricingBracketsAction',
 			'OnArrange' => 'PricingBracketsAction',
 			'OnInfinity' => 'PricingBracketsAction',
 			'OnDeleteBrackets' => 'PricingBracketsAction',
 		);
 
 		$this->eventMethods = array_merge($this->eventMethods, $brackets_events);
 	}
 
 	function PricingBracketsAction($event)
 	{
 		$event->redirect=false;
 		$temp = $this->Application->GetVar($event->getPrefixSpecial(true));
 
 //		$object = $event->getObject();
 //		$formatter = $this->Application->recallObject('kFormatter');
 //		$temp = $formatter->TypeCastArray($temp, $object);
 
 		//uasort($temp, 'pr_bracket_comp');
 		$bracket = $this->Application->recallObject($event->getPrefixSpecial());
 		foreach($temp as $id => $record)
 		{
 			if( $record['MaxQty'] == '∞' || $record['MaxQty'] == '∞')
 			{
 				$temp[$id]['MaxQty'] = -1;
 			}
 		}
 
 		$group_id = $this->Application->getVar('group_id');
 		if($group_id>0){
 			$where_group=' GroupId = '.$group_id.' ';
 		}
 		else {
 			$where_group= ' TRUE ';
 		}
 
 		switch ($event->Name)
 		{
 			case 'OnMoreBrackets':
 
 				$new_id = (int)$this->Conn->GetOne('SELECT MIN('.$bracket->IDField.') FROM '.$bracket->TableName);
 				if($new_id > 0) $new_id = 0;
 				do
 				{
 					$new_id--;
 				} while
 				($this->check_array($this->Application->GetVar($event->getPrefixSpecial(true)), 'PriceId', $new_id));
 
 
 				$last_max_qty = $this->Conn->GetOne('SELECT MAX(MaxQty) FROM '.$bracket->TableName.' WHERE '.$where_group);
 				$min_qty = $this->Conn->GetOne('SELECT MIN(MaxQty) FROM '.$bracket->TableName.' WHERE '.$where_group);
 
 				if ($min_qty==-1) $last_max_qty = -1;
 				if (!$last_max_qty) $last_max_qty=1;
 
 				for($i = $new_id; $i > $new_id - 5; $i--)
 				{
 					$temp[$i]['PriceId'] = $i;
 					$temp[$i]['MinQty'] = ($i == $new_id-4 && $last_max_qty != -1) ? $last_max_qty : '';
 					$temp[$i]['MaxQty'] = ($i == $new_id-4 && $last_max_qty != -1) ? -1 : '';
 					$temp[$i]['Price'] = '';
 					$temp[$i]['Cost'] = '';
 					$temp[$i]['Points'] = '';
 					$temp[$i]['Negotiated'] = '0';
 					$temp[$i]['IsPrimary'] = '0';
 					$temp[$i]['GroupId'] = $group_id;
 				}
 
 				$this->Application->SetVar($event->getPrefixSpecial(true), $temp);
 				$event->CallSubEvent('OnPreSaveBrackets');
 				break;
 
 			case 'OnArrange':
 				$temp=$this->OnArrangeBrackets($event, $temp, $bracket);
 				$this->Application->SetVar($event->getPrefixSpecial(true), $temp);
 				$event->CallSubEvent('OnPreSaveBrackets');
 				break;
 
 			case 'OnInfinity':
 				$temp=$this->OnArrangeBrackets($event, $temp, $bracket);
 				$this->Application->SetVar($event->getPrefixSpecial(true), $temp);
 				$event->CallSubEvent('OnPreSaveBrackets');
 
 				$infinite_exists = $this->Conn->GetOne('SELECT count(*) FROM '.$bracket->TableName.' WHERE MaxQty=-1 '.' AND '.$where_group);
 
 				if($infinite_exists==0){
 					reset($temp);
 					$last_bracket=end($temp);
 					$new_id = (int)$this->Conn->GetOne('SELECT MIN('.$bracket->IDField.') FROM '.$bracket->TableName);
 
 					$brackets_exist = (int)$this->Conn->GetOne('SELECT COUNT(*) FROM '.$bracket->TableName.' WHERE '.$where_group);
 
 					if($new_id > 0) $new_id = 0;
 					do
 					{
 						$new_id--;
 					} while
 					($this->check_array($this->Application->GetVar($event->getPrefixSpecial(true)), 'PriceId', $new_id));
 
 
 					$infinite_bracket['PriceId'] = $new_id;
 					$infinite_bracket['MinQty'] = ($brackets_exist>0)?$last_bracket['MaxQty']:1;
 					$infinite_bracket['MaxQty'] = '-1';
 					$infinite_bracket['Price'] = '';
 					$infinite_bracket['Cost'] = '';
 					$infinite_bracket['Points'] = '';
 					$infinite_bracket['Negotiated'] = '0';
 					$infinite_bracket['IsPrimary'] = '0';
 					$infinite_bracket['GroupId'] = $group_id;
 					$temp[$new_id]=$infinite_bracket;
 					reset($temp);
 				}
 
 				$this->Application->SetVar($event->getPrefixSpecial(true), $temp);
 				$event->CallSubEvent('OnPreSaveBrackets');
 				break;
 
 			case 'OnDeleteBrackets':
 				if ($group_id) {
 					$temp = ''; // delete all pricings from "pr_tang" var
 
 					$sql = 'DELETE FROM ' . $bracket->TableName . '
 							WHERE ProductId = ' . $this->Application->GetVar('p_id') . ' AND GroupId = ' . $group_id;
 					$this->Conn->Query($sql);
 				}
 				break;
 
 			default:
 		}
 
 		$this->Application->SetVar($event->getPrefixSpecial(true), $temp); // store pr_tang var
 	}
 
 	function OnPreSaveBrackets(kEvent $event)
 	{
 		if( $this->Application->GetVar('pr_tang') ) {
 
+			/** @var kDBItem $object */
 			$object = $event->getObject();
-			/* @var $object kDBItem */
 
 			$product_id = $this->Application->GetVar('p_id');
 			$group_id = $this->Application->getVar('group_id');
 
 			$sql = 'SELECT PriceId
 					FROM ' . $object->TableName . '
 					WHERE ProductId = ' . $product_id . ' ' . ($group_id? 'AND GroupId = ' . $group_id : '');
 			$stored_ids = $this->Conn->GetCol($sql);
 
 			$items_info = $this->Application->GetVar( $event->getPrefixSpecial(true) ); // get pr_tang var
 			uasort($items_info, 'pr_bracket_comp');
 
 			foreach ($items_info as $item_id => $field_values) {
 
 				if (in_array($item_id, $stored_ids)) { //if it's already exist
 					$object->Load($item_id);
 					$object->SetFieldsFromHash($field_values);
 					$event->setEventParam('form_data', $field_values);
 
 					if (!$object->Validate()) {
 						unset($stored_ids[array_search($item_id, $stored_ids)]);
 						$event->redirect = false;
 						continue;
 					}
 					if( $object->Update($item_id) ) {
 						$event->status=kEvent::erSUCCESS;
 					}
 					else {
 						$event->status=kEvent::erFAIL;
 						$event->redirect=false;
 						break;
 					}
 					unset($stored_ids[array_search($item_id, $stored_ids)]);
 				}
 				else {
 					$object->Clear(0);
 					$object->SetFieldsFromHash($field_values);
 					$event->setEventParam('form_data', $field_values);
 
 					$object->SetDBField('ProductId', $product_id);
 
 					if( $object->Create() ) {
 						$event->status=kEvent::erSUCCESS;
 					}
 				}
 			}
 
 			// delete
 			foreach ($stored_ids as $stored_id) {
 				$this->Conn->Query('DELETE FROM ' . $object->TableName . ' WHERE PriceId = ' . $stored_id);
 			}
 
 		}
 	}
 
 	/**
 	 * Apply custom processing to item
 	 *
 	 * @param kEvent $event
 	 * @param string $type
 	 * @return void
 	 * @access protected
 	 */
 	protected function customProcessing(kEvent $event, $type)
 	{
+		/** @var kDBItem $bracket */
 		$bracket = $event->getObject();
-		/* @var $bracket kDBItem */
 
 		switch ($type) {
 			case 'before':
 				$bracket->SetDBField('ProductId', $this->Application->GetVar('p_id'));
 
 				if ( $bracket->GetDBField('MaxQty') == '∞' || $bracket->GetDBField('MaxQty') == '∞' ) {
 					$bracket->SetDBField('MaxQty', -1);
 				}
 				break;
 		}
 	}
 
 	function OnArrangeBrackets($event, &$temp, &$bracket)
 	{
 		$temp_orig = $temp;
 		reset($temp);
 		if (is_array($temp))
 		{
 			// array to store max values (2nd column)
 			$end_values = Array();
 
 			// get minimal value of Min
 			$first_elem=current($temp);
 			$start = $first_elem['MinQty'];
 			if (!$start){
 				$start = 1;
 			}
 			foreach($temp as $id => $record)
 			{
 
 				/*
 				This 3-ifs logic fixes collision with invalid input values having
 				1 pricing record.
 				The logic is:
 				1) If we got Max less than Min, we set Min to 1 that gives us
 				integrity.
 				2) If we got equal values for Min and Max, we set range 1..Max like
 				in previous. But if Min was 1 and Max was 1 we set full range 1..infinity
 				3) If we got Max = 0 we just set it tom infinity because we can't
 				guess what user meant
 				*/
 
 				if (sizeof($temp) == 1 && $record['MinQty'] > ($record['MaxQty'] == -1 ? $record['MinQty']+1 : $record['MaxQty']) ){
 					$record['MinQty'] = 1;
 					$temp[$id]['MinQty'] = 1;
 					$start = 1;
 				}
 
 				if (sizeof($temp) == 1 && $record['MinQty'] == $record['MaxQty']){
 					if ($record['MaxQty'] == 1){
 						$record['MaxQty'] = -1;
 						$temp[$id]['MaxQty'] = -1;
 					}
 					else {
 						$record['MinQty'] = 1;
 						$temp[$id]['MinQty'] = 1;
 					}
 				}
 
 				if (sizeof($temp) == 1 && $record['MaxQty'] == 0){
 					$record['MaxQty'] = -1;
 					$temp[$id]['MaxQty'] = -1;
 				}
 
 				if(
 				// MAX is less than start
 				($record['MaxQty'] <= $start && $record['MaxQty'] != -1) ||
 				// Max is empty
 				!$record['MaxQty'] ||
 				// Max already defined in $end_values
 				(array_search($record['MaxQty'], $end_values) !== false)
 				) {	// then delete from brackets list
 					unset($temp[$id]);
 				}
 				else {	// this is when ok - add to end_values list
 					$end_values[] = $record['MaxQty'];
 				}
 			}
 
 			// sort brackets by 2nd column (Max values)
 			uasort($temp, 'pr_bracket_comp');
 			reset($temp);
 			$first_item=each($temp);
 			$first_item_key=$first_item['key'];
 
 			$group_id = $this->Application->getVar('group_id');
 
 
 			$default_group = $this->Application->ConfigValue('User_LoggedInGroup');
 			if($group_id>0){
 				$where_group=' AND GroupId = '.$group_id.' ';
 			}
 
 			$ids = $this->Conn->GetCol('SELECT PriceId FROM '.$bracket->TableName.' WHERE ProductId='.$this->Application->GetVar('p_id').' '.$where_group);
 			if(is_array($ids)) {
 				usort($ids, 'pr_bracket_id_sort');
 			}
 			$min_id = min( min($ids) - 1, -1 );
 
 
 			foreach($temp as $key => $record)
 			{
 				$temp[$key]['MinQty']=$start;
 				$temp[$key]['IsPrimary']=0;
 				$temp[$key]['GroupId']=$group_id;
 				$start=$temp[$key]['MaxQty'];
 
 			}
 			if ($temp[$first_item_key]['GroupId'] == $default_group) {
 				$temp[$first_item_key]['IsPrimary']=1;
 			}
 
 		}
 		return $temp;
 	}
 
 	/**
 	 * Set's price as primary for product
 	 *
 	 * @param kEvent $event
 	 */
 	function OnSetPrimary($event)
 	{
 		$object = $event->getObject( Array('skip_autoload' => true) );
 		$this->StoreSelectedIDs($event);
 		$ids=$this->getSelectedIDs($event);
 		if($ids)
 		{
 			$id = array_shift($ids);
 			$table_info = $object->getLinkedInfo();
 
 			$this->Conn->Query('UPDATE '.$object->TableName.' SET IsPrimary = 0 WHERE '.$table_info['ForeignKey'].' = '.$table_info['ParentId']);
 			$this->Conn->Query('UPDATE '.$object->TableName.' SET IsPrimary = 1 WHERE ('.$table_info['ForeignKey'].' = '.$table_info['ParentId'].') AND (PriceId = '.$id.')');
 		}
 		$event->SetRedirectParam('opener', 's');
 	}
 
 	/**
 	 * Resets primary mark for other prices of given product, when current pricing is primary
 	 *
 	 * @param kEvent $event
 	 * @return void
 	 * @access protected
 	 */
 	protected function OnBeforeItemUpdate(kEvent $event)
 	{
 		parent::OnBeforeItemUpdate($event);
 
+		/** @var kDBItem $object */
 		$object = $event->getObject();
-		/* @var $object kDBItem */
 
 		if ( $object->GetDBField('IsPrimary') == 1 ) {
 			// make all prices non primary, when this one is
 			$sql = 'UPDATE ' . $object->TableName . '
 					SET IsPrimary = 0
 					WHERE (ProductId = ' . $object->GetDBField('ProductId') . ') AND (' . $object->IDField . ' <> ' . $object->GetID() . ')';
 			$this->Conn->Query($sql);
 		}
 	}
 
 	/**
 	 * Occurs before creating item
 	 *
 	 * @param kEvent $event
 	 * @return void
 	 * @access protected
 	 */
 	protected function OnBeforeItemCreate(kEvent $event)
 	{
 		parent::OnBeforeItemCreate($event);
 
+		/** @var kDBItem $object */
 		$object = $event->getObject();
-		/* @var $object kDBItem */
 
 		$table_info = $object->getLinkedInfo($event->Special);
 
 		$table_info['ParentId'] = ($table_info['ParentId'] ? $table_info['ParentId'] : 0);
 
 		if ( $object->GetDBField('IsPrimary') == 1 ) {
 			$sql = 'UPDATE ' . $object->TableName . '
 					SET IsPrimary = 0
 					WHERE ' . $table_info['ForeignKey'] . ' = ' . $table_info['ParentId'];
 			$this->Conn->Query($sql);
 		}
 		else {
 			$sql = 'SELECT COUNT(*)
 					FROM ' . $object->TableName . '
 					WHERE ' . $table_info['ForeignKey'] . ' = ' . $table_info['ParentId'];
 			$prices_qty = $this->Conn->GetOne($sql);
 
 			if ( $prices_qty == 0 ) {
 				$object->SetDBField('IsPrimary', 1);
 			}
 		}
 	}
 
 	/**
 	 * Apply any custom changes to list's sql query
 	 *
 	 * @param kEvent $event
 	 * @return void
 	 * @access protected
 	 * @see kDBEventHandler::OnListBuild()
 	 */
 	protected function SetCustomQuery(kEvent $event)
 	{
+		/** @var kDBList $object */
 		$object = $event->getObject();
-		/* @var $object kDBList */
 
 		if ( $this->Application->isAdminUser ) {
 			return;
 		}
 
 		if ( $this->Application->ConfigValue('Comm_PriceBracketCalculation') == 1 ) {
 			$sql = 'SELECT PrimaryGroupId
 					FROM ' . TABLE_PREFIX . 'Users
 					WHERE PortalUserId = ' . $this->Application->GetVar('u_id');
 			$pricing_group = $this->Conn->GetOne($sql);
 
 			if ( $pricing_group ) {
 				$sql = 'SELECT COUNT(*)
 						FROM ' . TABLE_PREFIX . 'ProductsPricing
 						WHERE ProductId = ' . $this->Application->GetVar('p_id') . ' AND GroupId = ' . $pricing_group . ' AND Price IS NOT NULL';
 				$pricing_for_group_exists = $this->Conn->GetOne($sql);
 			}
 
 			if ( !$pricing_group || !$pricing_for_group_exists ) {
 				$pricing_group = $this->Application->ConfigValue('User_LoggedInGroup');
 			}
 		}
 		else {
 			$user_groups = $this->Application->RecallVar('UserGroups');
 
 			//$cheapest_group = $this->Conn->GetOne('SELECT GroupId FROM '.$object->TableName.' WHERE ProductId='.$this->Application->GetVar('p_id').' AND Price IS NOT NULL AND GroupId IN ('.$user_groups.') AND MinQty = 1 GROUP BY GroupId ORDER BY Price ASC');
 
 			$sql = 'SELECT PriceId, Price, GroupId
 					FROM ' . $object->TableName . '
 					WHERE ProductId = ' . $this->Application->GetVar('p_id') . ' AND Price IS NOT NULL AND GroupId IN (' . $user_groups . ')
 					ORDER BY GroupId ASC, MinQty ASC';
 			$effective_brackets = $this->Conn->Query($sql, 'PriceId');
 
 			$group_prices = array ();
 			$min_price = -1;
 			$cheapest_group = 0;
 
 			foreach ($effective_brackets as $bracket) {
 				if ( !isset($group_prices[$bracket['GroupId']]) ) {
 					$group_prices[$bracket['GroupId']] = $bracket['Price'];
 					if ( $bracket['Price'] < $min_price || $min_price == -1 ) {
 						$min_price = $bracket['Price'];
 						$cheapest_group = $bracket['GroupId'];
 					}
 				}
 			}
 
 			if ( !$cheapest_group ) {
 				$cheapest_group = $this->Application->ConfigValue('User_LoggedInGroup');
 			}
 
 			$pricing_group = $cheapest_group;
 		}
 
 		$object->addFilter('price_user_group', $object->TableName . '.GroupId=' . $pricing_group);
 	}
 
 }
Index: branches/5.2.x/units/pricing/pricing_tag_processor.php
===================================================================
--- branches/5.2.x/units/pricing/pricing_tag_processor.php	(revision 16515)
+++ branches/5.2.x/units/pricing/pricing_tag_processor.php	(revision 16516)
@@ -1,166 +1,166 @@
 Application->recallObject($params['PrefixSpecial']);
 		$price = $object->GetField('Price');
 
 		// display selected currency by default
 		if (!isset($params['currency']) || $params['currency'] == 'selected') {
 			$iso = $this->Application->RecallVar('curr_iso');
 		}
 		elseif ($params['currency'] == 'primary') {
 			$iso = 'USD';
 		}
 		else { //explicit currency
 			$iso = $params['currency'];
 		}
 
 		// convert primary currency to selected (if they are the same, converter will just return)
 
+		/** @var CurrencyRates $converter */
 		$converter = $this->Application->recallObject('CurrencyRates');
-		/* @var $converter CurrencyRates */
 
 		$price = $converter->Convert($price, 'PRIMARY', $iso);
 
 		$currency = $this->Application->recallObject('curr.-'.$iso, null, Array('skip_autoload' => true));
 		if( !$currency->isLoaded() ) $currency->Load($iso, 'ISO');
 
 		$symbol = $currency->GetDBField('Symbol');
 		if (!$symbol) $symbol = $currency->GetDBField('ISO');
 		$formatted = '';
 		if ($currency->GetDBField('SymbolPosition') == 0) {
 			$formatted .= $symbol;
 		}
 		$formatted .= $price;
 		if ($currency->GetDBField('SymbolPosition') == 1) {
 			$formatted .= $symbol;
 		}
 
 		return $formatted;
 	}
 
 	function Product_ListPriceBrackets($params)
 	{
 		return $this->PrintList2($params);
 	}
 
 	function Field($params)
 	{
 		$field = $this->SelectParam($params, 'name,field');
 		$value = parent::Field($params);
 		if (($field == 'MaxQty') && ($value == -1)) {
 			$value = '∞';
 		}
 		return $value;
 	}
 
 	function Product_HasQuantityPricing($params)
 	{
 		return (int)$this->TotalRecords($params) > 1;
 	}
 
 
 	function ShowPricingForm($params)
 	{
 		$br_object = $this->getObject( Array('skip_autoload' => true) );
 
 		$br_data = $this->Application->GetVar("pr_tang");
 
 		$group_id = $this->Application->getVar('group_id');
 		if($group_id>0){
 			$where_group=' AND GroupId = '.$group_id.' ';
 		}
 
 		if(!$br_data)
 		{
 			$sql = 	'SELECT * FROM '.$br_object->TableName.' WHERE ProductId = '.$this->Application->GetVar('p_id').' '.$where_group;
 			$brackets = $this->Conn->Query($sql, 'PriceId');
 
 			usort($brackets, 'pr_bracket_comp');
 
+			/** @var kDBItem $dummy */
 			$dummy = $this->Application->recallObject($this->Prefix.'.-dummy', null, array('skip_autoload' => true));
-			/* @var $dummy kDBItem */
 
 			foreach($brackets as $id => $values)
 			{
 				foreach($values as $value_key=>$value_val){
 					$dummy->SetDBField($value_key, $value_val);
 					$brackets[$id][$value_key] = $dummy->GetField($value_key);
 				}
 			}
 
 			$br_data=$brackets;
 			$this->Application->SetVar($this->getPrefixSpecial(true), $brackets);
 		}
 		else
 		{
 			usort($br_data , 'pr_bracket_comp');
 
 		}
 
 		$ret = '';
 		if( is_array($br_data) )
 		{
 
 			$block_params=$this->prepareTagParams($params);
 			$block_params['IdField']='PriceId';
 			$block_params['name'] = $params['block'];
 			$first = true;
 
 			// this is needed to find next id
 			$br_data_copy=$br_data;
 			foreach($br_data as $id => $values)
 			{
 
 				foreach($values as $value_key=>$value_val){
 					$block_params[$value_key] = $value_val;
 				}
 				reset($values);
 
 				next($br_data_copy);
 				$next_bracket=current($br_data_copy);
 
 				$block_params['id']	= $values["PriceId"];
 				$block_params['min']	= ($id == -1) ? ($values['MinQty'] ? $values['MinQty'] : 0) : $values['MinQty'];
 				$block_params['max'] = ($values['MaxQty'] == -1) ? '∞' : $values['MaxQty'];
 				$block_params['next_min_id']=$next_bracket['PriceId'];
 
 				if ($first)
 				{
 					$block_params['first'] = 1;
 					$first = false;
 				}
 				else
 				{
 					$block_params['first'] = 0;
 				}
 				$ret .= $this->Application->ParseBlock($block_params, 1);
 			}
 		}
 		return $ret;
 	}
 
 	function AddToCartLink($params)
 	{
 		$value = $this->Field(array('name'=>'PriceId'));
 		//$this->Application->SetVar('p_id', $this->Application->GetVar($this->getPrefixSpecial().'_id'));
 		$this->Application->SetVar('pr_id', $value);
 		return $this->Application->HREF($params['template'], '', Array('pass' => 'm,p,pr,ord', 'ord_event' => 'OnAddToCart'));
 	}
 }
\ No newline at end of file
Index: branches/5.2.x/units/reports/reports_event_handler.php
===================================================================
--- branches/5.2.x/units/reports/reports_event_handler.php	(revision 16515)
+++ branches/5.2.x/units/reports/reports_event_handler.php	(revision 16516)
@@ -1,848 +1,848 @@
  Array ('self' => 'view'),
 			'OnUpdateConfig' => Array ('self' => 'view'),
 			'OnChangeStatistics' => Array ('self' => 'view'),
 			'OnPieChart' => Array ('self' => 'view'),
 			'OnPrintChart' => Array ('self' => 'view'),
 			'OnExportReport' => Array ('self' => 'view'),
 		);
 
 		$this->permMapping = array_merge($this->permMapping, $permissions);
 	}
 
 	function OnRunReport(kEvent $event)
 	{
 		$this->Application->LinkVar('reports_finish_t');
 		$progress_t = $this->Application->GetVar('progress_t');
 		$event->redirect = $progress_t;
 
 		$field_values = $this->getSubmittedFields($event);
 
 		/** @var kDBItem $object */
 		$object = $event->getObject( Array('skip_autoload' => true) );
 		$object->SetFieldsFromHash($field_values);
 		$event->setEventParam('form_data', $field_values);
 
 		$object->UpdateFormattersMasterFields();
 
 		$field_values['offset'] = 0;
 		$table_name = TABLE_PREFIX.'ses_'.$this->Application->GetSID().'_SaleReport';
 		$field_values['table_name'] = $table_name;
 		$this->Conn->Query('DROP TABLE IF EXISTS '.$table_name);
 
 		$filter_value = '';
 		$from = $object->GetDBField('FromDateTime');
 		$to = $object->GetDBField('ToDateTime');
 
 		$day_seconds = 23 * 60 * 60 + 59 * 60 + 59;
 		if ($from && !$to) {
 			$to = $from + $day_seconds;
 		}
 		elseif (!$from && $to) {
 			$from = $to - $day_seconds;
 		}
 
 		if ($from && $to) {
 			$filter_value = 'AND o.OrderDate >= '.$from.' AND o.OrderDate <= '.$to;
 		}
 
 		$ebay_table_fields = '';
 		$ebay_joins = '';
 		$ebay_query_fields = '';
 
 		$user_id = $this->Application->RecallVar('user_id');
 		$sql = 'DELETE FROM '.TABLE_PREFIX.'UserPersistentSessionData
 			WHERE
 				PortalUserId = "'.$user_id.'"
 				AND VariableName LIKE \'rep_columns_%\'';
 		$this->Conn->Query($sql);
 
 		if ($this->Application->isModuleEnabled('in-auction'))
 		{
 			if (in_array($field_values['ReportType'], Array(1,5)))  // not overall.
 			{
 				$ebay_table_fields = ',
 					StoreQty int(11) NOT NULL DEFAULT 0,
 					eBayQty int(11) NOT NULL DEFAULT 0,
 					StoreAmount double(10,4) NOT NULL DEFAULT 0,
 					eBayAmount double(10,4) NOT NULL DEFAULT 0,
 					StoreProfit double(10,4) NOT NULL DEFAULT 0,
 					eBayProfit double(10,4) NOT NULL DEFAULT 0';
 
 				$ebay_joins = '
 					LEFT JOIN '.TABLE_PREFIX.'eBayOrderItems AS eod
 					ON od.OptionsSalt = eod.OptionsSalt
 				';
 
 				$ebay_query_fields = ',
 					SUM(IF(ISNULL(eod.OptionsSalt), od.Quantity, 0)) as StoreQty,
 					SUM(IF(ISNULL(eod.OptionsSalt), 0, od.Quantity)) as eBayQty,
 					SUM(IF(ISNULL(eod.OptionsSalt), od.Price * od.Quantity, 0)) as StoreAmount,
 					SUM(IF(ISNULL(eod.OptionsSalt), 0, od.Price * od.Quantity)) as eBayAmount,
 					SUM(IF(ISNULL(eod.OptionsSalt), (od.Price - od.Cost) * od.Quantity, 0)) as StoreProfit,
 					SUM(IF(ISNULL(eod.OptionsSalt), 0, (od.Price - od.Cost) * od.Quantity)) as eBayProfit
 				';
 			}
 
 		}
 
 		if ($field_values['ReportType'] == 1) { // by Category
 			$q = 'CREATE TABLE '.$table_name.' (
 							CategoryId int(11) NOT NULL DEFAULT 0,
 							Qty int(11) NOT NULL DEFAULT 0,
 							Cost double(10,4) NOT NULL DEFAULT 0,
 							Amount double(10,4) NOT NULL DEFAULT 0,
 							Tax double(10,4) NOT NULL DEFAULT 0,
 							Shipping double(10,4) NOT NULL DEFAULT 0,
 							Processing double(10,4) NOT NULL DEFAULT 0,
 							Profit double(10,4) NOT NULL DEFAULT 0
 							'.$ebay_table_fields.'
 						)';
 			$field_values['total'] = $this->Conn->GetOne('SELECT COUNT(*) FROM '.TABLE_PREFIX.'Categories');
 			$this->Conn->Query($q);
 
 			$q = 'INSERT INTO '.$field_values['table_name'].'
 						SELECT
 							c.CategoryId,
 							SUM(od.Quantity) as Qty,
 							SUM(od.Cost * od.Quantity) as Cost,
 							SUM(od.Price * od.Quantity) as SaleAmount,
 							SUM(o.VAT * od.Price * od.Quantity / o.SubTotal) as Tax,
 							SUM(o.ShippingCost * od.Price * od.Quantity / o.SubTotal) as Shipping,
 							SUM(o.ProcessingFee * od.Price * od.Quantity / o.SubTotal) as Processing,
 							SUM((od.Price - od.Cost) * od.Quantity) as Profit'
 							.$ebay_query_fields.'
 						FROM '.TABLE_PREFIX.'Orders AS o
 						LEFT JOIN '.TABLE_PREFIX.'OrderItems AS od
 						ON od.OrderId = o.OrderId
 						LEFT JOIN '.TABLE_PREFIX.'Products AS p
 						ON p.ProductId = od.ProductId
 						LEFT JOIN '.TABLE_PREFIX.'CategoryItems AS ci
 						ON ci.ItemResourceId = p.ResourceId
 						LEFT JOIN '.TABLE_PREFIX.'Categories AS c
 						ON c.CategoryId = ci.CategoryId
 						'.$ebay_joins.'
 						WHERE
 							o.Status IN (4,6)
 							AND
 							ci.PrimaryCat = 1
 							'.$filter_value.'
 						GROUP BY c.CategoryId
 						HAVING NOT ISNULL(CategoryId)
 						';
 			$this->Conn->Query($q);
 		}
 		elseif ($field_values['ReportType'] == 2) { // by User
 			$q = 'CREATE TABLE '.$table_name.' (
 							PortalUserId int(11) NOT NULL DEFAULT 0,
 							Qty int(11) NOT NULL DEFAULT 0,
 							Cost double(10,4) NOT NULL DEFAULT 0,
 							Amount double(10,4) NOT NULL DEFAULT 0,
 							Tax double(10,4) NOT NULL DEFAULT 0,
 							Shipping double(10,4) NOT NULL DEFAULT 0,
 							Processing double(10,4) NOT NULL DEFAULT 0,
 							Profit double(10,4) NOT NULL DEFAULT 0
 						)';
 			$field_values['total'] = $this->Conn->GetOne('SELECT COUNT(*) FROM '.TABLE_PREFIX.'Categories');
 			$this->Conn->Query($q);
 
 			$q = 'INSERT INTO '.$field_values['table_name'].'
 						SELECT
 							u.PortalUserId,
 							SUM(od.Quantity) as Qty,
 							SUM(od.Cost * od.Quantity) as Cost,
 							SUM(od.Price * od.Quantity) as SaleAmount,
 							SUM(o.VAT * od.Price * od.Quantity / o.SubTotal) as Tax,
 							SUM(o.ShippingCost * od.Price * od.Quantity / o.SubTotal) as Shipping,
 							SUM(o.ProcessingFee * od.Price * od.Quantity / o.SubTotal) as Processing,
 							SUM((od.Price - od.Cost) * od.Quantity) as Profit
 						FROM '.TABLE_PREFIX.'Orders AS o
 						LEFT JOIN '.TABLE_PREFIX.'OrderItems AS od
 						ON od.OrderId = o.OrderId
 						LEFT JOIN '.TABLE_PREFIX.'Users AS u
 						ON u.PortalUserId = o.PortalUserId
 						WHERE
 							o.Status IN (4,6)
 							'.$filter_value.'
 						GROUP BY u.PortalUserId
 						HAVING NOT ISNULL(PortalUserId)
 						';
 			$this->Conn->Query($q);
 		}
 		elseif ($field_values['ReportType'] == 5) { // by Product
 			$q = 'CREATE TABLE '.$table_name.' (
 							ProductId int(11) NOT NULL DEFAULT 0,
 							Qty int(11) NOT NULL DEFAULT 0,
 							Cost double(10,4) NOT NULL DEFAULT 0,
 							Amount double(10,4) NOT NULL DEFAULT 0,
 							Tax double(10,4) NOT NULL DEFAULT 0,
 							Shipping double(10,4) NOT NULL DEFAULT 0,
 							Processing double(10,4) NOT NULL DEFAULT 0,
 							Profit double(10,4) NOT NULL DEFAULT 0'
 							.$ebay_table_fields.'
 						)';
 			$field_values['total'] = $this->Conn->GetOne('SELECT COUNT(*) FROM '.TABLE_PREFIX.'Products');
 			$this->Conn->Query($q);
 
 			$q = 'INSERT INTO '.$field_values['table_name'].'
 						SELECT
 							p.ProductId,
 							SUM(od.Quantity) as Qty,
 							SUM(od.Cost * od.Quantity) as Cost,
 							SUM(od.Price * od.Quantity) as SaleAmount,
 							SUM(o.VAT * od.Price * od.Quantity / o.SubTotal) as Tax,
 							SUM(o.ShippingCost * od.Price * od.Quantity / o.SubTotal) as Shipping,
 							SUM(o.ProcessingFee * od.Price * od.Quantity / o.SubTotal) as Processing,
 							SUM((od.Price - od.Cost)  * od.Quantity) as Profit'
 							.$ebay_query_fields.'
 						FROM '.TABLE_PREFIX.'Orders AS o
 						LEFT JOIN '.TABLE_PREFIX.'OrderItems AS od
 						ON od.OrderId = o.OrderId
 						LEFT JOIN '.TABLE_PREFIX.'Products AS p
 						ON p.ProductId = od.ProductId
 						'.$ebay_joins.'
 						WHERE
 							o.Status IN (4,6)
 							'.$filter_value.'
 						GROUP BY p.ProductId
 						HAVING NOT ISNULL(ProductId)
 						';
 			$this->Conn->Query($q);
 		}
 		elseif ($field_values['ReportType'] == 12) { // Overall
 			$q = 'CREATE TABLE '.$table_name.' (
 							Marketplace tinyint(1) NOT NULL DEFAULT 0,
 							Qty int(11) NOT NULL DEFAULT 0,
 							Cost double(10,4) NOT NULL DEFAULT 0,
 							Amount double(10,4) NOT NULL DEFAULT 0,
 							Tax double(10,4) NOT NULL DEFAULT 0,
 							Shipping double(10,4) NOT NULL DEFAULT 0,
 							Processing double(10,4) NOT NULL DEFAULT 0,
 							Profit double(10,4) NOT NULL DEFAULT 0
 						)';
 			$this->Conn->Query($q);
 
 			if ($this->Application->isModuleEnabled('in-auction'))
 			{
 				$field_values['total'] = 2;
 
 				$q = 'INSERT INTO '.$field_values['table_name'].'
 							SELECT
 								1 AS Marketplace,
 								SUM(IF(ISNULL(eod.OptionsSalt), od.Quantity, 0)) as Qty,
 								SUM(IF(ISNULL(eod.OptionsSalt), od.Cost * od.Quantity, 0)) as Cost,
 								SUM(IF(ISNULL(eod.OptionsSalt), od.Price * od.Quantity, 0)) as SaleAmount,
 								SUM(IF(ISNULL(eod.OptionsSalt), o.VAT * od.Price * od.Quantity / o.SubTotal, 0)) as Tax,
 								SUM(IF(ISNULL(eod.OptionsSalt), o.ShippingCost * od.Price * od.Quantity / o.SubTotal, 0)) as Shipping,
 								SUM(IF(ISNULL(eod.OptionsSalt), o.ProcessingFee * od.Price * od.Quantity / o.SubTotal, 0)) as Processing,
 								SUM(IF(ISNULL(eod.OptionsSalt), (od.Price - od.Cost)  * od.Quantity, 0)) as Profit
 							FROM '.TABLE_PREFIX.'Orders AS o
 							LEFT JOIN '.TABLE_PREFIX.'OrderItems AS od
 							ON od.OrderId = o.OrderId
 							LEFT JOIN '.TABLE_PREFIX.'eBayOrderItems AS eod
 							ON od.OptionsSalt = eod.OptionsSalt
 							WHERE
 								o.Status IN (4,6)
 								'.$filter_value;
 				$this->Conn->Query($q);
 
 
 				$q = 'INSERT INTO '.$field_values['table_name'].'
 							SELECT
 								2 AS Marketplace,
 								SUM(IF(ISNULL(eod.OptionsSalt), 0, od.Quantity)) as Qty,
 								SUM(IF(ISNULL(eod.OptionsSalt), 0, od.Cost * od.Quantity)) as Cost,
 								SUM(IF(ISNULL(eod.OptionsSalt), 0, od.Price * od.Quantity)) as SaleAmount,
 								SUM(IF(ISNULL(eod.OptionsSalt), 0, o.VAT * od.Price * od.Quantity / o.SubTotal)) as Tax,
 								SUM(IF(ISNULL(eod.OptionsSalt), 0, o.ShippingCost * od.Price * od.Quantity / o.SubTotal)) as Shipping,
 								SUM(IF(ISNULL(eod.OptionsSalt), 0, o.ProcessingFee * od.Price * od.Quantity / o.SubTotal)) as Processing,
 								SUM(IF(ISNULL(eod.OptionsSalt), 0, (od.Price - od.Cost)  * od.Quantity)) as Profit
 							FROM '.TABLE_PREFIX.'Orders AS o
 							LEFT JOIN '.TABLE_PREFIX.'OrderItems AS od
 							ON od.OrderId = o.OrderId
 							LEFT JOIN '.TABLE_PREFIX.'eBayOrderItems AS eod
 							ON od.OptionsSalt = eod.OptionsSalt
 							WHERE
 								o.Status IN (4,6)
 								'.$filter_value;
 				$this->Conn->Query($q);
 			} else {
 				$field_values['total'] = 1;
 				$q = 'INSERT INTO '.$field_values['table_name'].'
 							SELECT
 								1 AS Marketplace,
 								SUM(od.Quantity) as Qty,
 								SUM(od.Cost * od.Quantity) as Cost,
 								SUM(od.Price * od.Quantity) as SaleAmount,
 								SUM(o.VAT * od.Price * od.Quantity / o.SubTotal) as Tax,
 								SUM(o.ShippingCost * od.Price * od.Quantity / o.SubTotal) as Shipping,
 								SUM(o.ProcessingFee * od.Price * od.Quantity / o.SubTotal) as Processing,
 								SUM((od.Price - od.Cost)  * od.Quantity) as Profit
 							FROM '.TABLE_PREFIX.'Orders AS o
 							LEFT JOIN '.TABLE_PREFIX.'OrderItems AS od
 							ON od.OrderId = o.OrderId
 							WHERE
 								o.Status IN (4,6)
 								'.$filter_value;
 				$this->Conn->Query($q);
 
 			}
 		}
 
 		$vars = array('rep_Page', 'rep_Sort1', 'rep_Sort1_Dir', 'rep_Sort2', 'rep_Sort2_Dir');
 		foreach ($vars as $var_name) {
 			$this->Application->RemoveVar($var_name);
 		}
 
 		//temporary
 		$event->redirect = $this->Application->GetVar('reports_finish_t');
 
 		$field_values['from'] = $from;
 		$field_values['to'] = $to;
 
 		$this->Application->StoreVar('report_options', serialize($field_values));
 	}
 
 	function OnUpdateConfig($event)
 	{
 		$report = $this->Application->RecallVar('report_options');
 		if (!$report) {
 			return ;
 		}
 
 		$field_values = unserialize($report);
 
 		$rep_options = $this->Application->getUnitOptions('rep');
 		$new_options = Array ();
 
 		$new_options['TableName'] = $field_values['table_name'];
 
 		$new_options['Fields'] = Array (
 			'Qty' => Array ('type' => 'float', 'formatter' => 'kFormatter', 'format' => '%d', 'default' => 0, 'totals' => 'sum'),
 			'Cost' => Array ('type' => 'float', 'formatter' => 'kFormatter', 'format' => '%.2f', 'default' => 0, 'totals' => 'sum'),
 			'Amount' => Array ('type' => 'float', 'formatter' => 'kFormatter', 'format' => '%.2f', 'default' => 0, 'totals' => 'sum'),
 			'Tax' => Array ('type' => 'float', 'formatter' => 'kFormatter', 'format' => '%.2f', 'default' => 0, 'totals' => 'sum'),
 			'Shipping' => Array ('type' => 'float', 'formatter' => 'kFormatter', 'format' => '%.2f', 'default' => 0, 'totals' => 'sum'),
 			'Processing' => Array ('type' => 'float', 'formatter' => 'kFormatter', 'format' => '%.2f', 'default' => 0, 'totals' => 'sum'),
 			'Profit' => Array ('type' => 'float', 'formatter' => 'kFormatter', 'format' => '%.2f', 'default' => 0, 'totals' => 'sum'),
 		);
 
 		if ( $this->Application->isModuleEnabled('in-auction') ) {
 			if ( in_Array ($field_values['ReportType'], Array (1, 5)) ) {
 				$new_options['Fields'] += Array (
 					'StoreQty' => Array ('type' => 'int', 'formatter' => 'kFormatter', 'format' => '%d', 'default' => 0, 'totals' => 'sum'),
 					'StoreAmount' => Array ('type' => 'float', 'formatter' => 'kFormatter', 'format' => '%.2f', 'default' => 0, 'totals' => 'sum'),
 					'StoreProfit' => Array ('type' => 'float', 'formatter' => 'kFormatter', 'format' => '%.2f', 'default' => 0, 'totals' => 'sum'),
 					'eBayQty' => Array ('type' => 'int', 'formatter' => 'kFormatter', 'format' => '%d', 'default' => 0, 'totals' => 'sum'),
 					'eBayAmount' => Array ('type' => 'float', 'formatter' => 'kFormatter', 'format' => '%.2f', 'default' => 0, 'totals' => 'sum'),
 					'eBayProfit' => Array ('type' => 'float', 'formatter' => 'kFormatter', 'format' => '%.2f', 'default' => 0, 'totals' => 'sum'),
 				);
 			}
 		}
 
 		if ($field_values['ReportType'] == 1) { // by Category
 
 			$new_options['ListSQLs'][''] =
 				'SELECT %1$s.* %2$s FROM %1$s
 				 LEFT JOIN '.TABLE_PREFIX.'Categories AS c
 				 ON c.CategoryId = %1$s.CategoryId';
 			$new_options['Grids']['Default'] = Array (
 				'Icons' => Array (
 					'default' => 'icon16_item.png',
 					'module' => 'core',
 				),
 				'Fields' => Array (
 					'CategoryName' => Array ('title' => 'la_col_CategoryName', 'filter_block' => 'grid_like_filter'),
 					'Qty' => Array ('td_style' => 'text-align: center', 'total' => 'sum', 'filter_block' => 'grid_range_filter'),
 					'StoreQty' => Array ('title' => 'la_col_StoreQty', 'td_style' => 'text-align: center', 'total' => 'sum', 'filter_block' => 'grid_range_filter'),
 					'eBayQty' => Array ('title' => 'la_col_eBayQty', 'td_style' => 'text-align: center', 'total' => 'sum', 'filter_block' => 'grid_range_filter'),
 					'Cost' => Array ('td_style' => 'text-align: right', 'total' => 'sum', 'hidden' => 1, 'filter_block' => 'grid_range_filter'),
 					'Amount' => Array ('title' => 'la_col_GMV', 'td_style' => 'text-align: right', 'total' => 'sum', 'filter_block' => 'grid_range_filter'),
 					'StoreAmount' => Array ('title' => 'la_col_StoreGMV', 'td_style' => 'text-align: right', 'total' => 'sum', 'filter_block' => 'grid_range_filter'),
 					'eBayAmount' => Array ('title' => 'la_col_eBayGMV', 'td_style' => 'text-align: right', 'total' => 'sum', 'filter_block' => 'grid_range_filter'),
 					'Tax' => Array ('title' => 'la_col_Tax', 'td_style' => 'text-align: right', 'total' => 'sum', 'hidden' => 1, 'filter_block' => 'grid_range_filter'),
 					'Shipping' => Array ('title' => 'la_col_Shipping', 'td_style' => 'text-align: right', 'total' => 'sum', 'hidden' => 1, 'filter_block' => 'grid_range_filter'),
 					'Processing' => Array ('title' => 'la_col_Processing', 'td_style' => 'text-align: right', 'total' => 'sum', 'hidden' => 1, 'filter_block' => 'grid_range_filter'),
 					'Profit' => Array ('title' => 'la_col_Profit', 'td_style' => 'text-align: right', 'total' => 'sum', 'filter_block' => 'grid_range_filter'),
 					'StoreProfit' => Array ('title' => 'la_col_StoreProfit', 'td_style' => 'text-align: right', 'total' => 'sum', 'filter_block' => 'grid_range_filter'),
 					'eBayProfit' => Array ('title' => 'la_col_eBayProfit', 'td_style' => 'text-align: right', 'total' => 'sum', 'filter_block' => 'grid_range_filter'),
 				),
 
 			);
 
 			if (!$this->Application->isModuleEnabled('in-auction')) {
 				$a_fields =& $new_options['Grids']['Default']['Fields'];
 				unset($a_fields['StoreQty']);
 				unset($a_fields['eBayQty']);
 				unset($a_fields['StoreAmount']);
 				unset($a_fields['eBayAmount']);
 				unset($a_fields['StoreProfit']);
 				unset($a_fields['eBayProfit']);
 			}
 
 			$new_options['VirtualFields'] = array_merge($rep_options['VirtualFields'], Array (
 				'CategoryName' => Array ('type' => 'string', 'default' => ''),
 	            'Metric' => Array (
 	            	'type' => 'int',
 	            	'formatter' => 'kOptionsFormatter',
 	            	'options' => $this->GetMetricOptions($new_options, 'CategoryName'),
 	            	'use_phrases' => 1,
 	            	'default' => 0,
 	            ),
 			));
 
 			$lang = $this->Application->GetVar('m_lang');
 
 			// products root category
 			$products_category_id = $this->Application->findModule('Name', 'In-Commerce', 'RootCat');
 			// get root category name
 			$sql = 'SELECT LENGTH(l' . $lang . '_CachedNavbar)
 					FROM ' . TABLE_PREFIX . 'Categories
 					WHERE CategoryId = '.$products_category_id;
 			$root_length = $this->Conn->GetOne($sql) + 4;
 
 			$new_options['CalculatedFields'][''] = array(
 				'CategoryName' => 'REPLACE(SUBSTR(c.l'.$lang.'_CachedNavbar, '.$root_length.'), "&|&", " > ")',
 			);
 		}
 		elseif ($field_values['ReportType'] == 2) { // by User
 			$new_options['ListSQLs'][''] =
 				'SELECT %1$s.* %2$s FROM %1$s
 				 LEFT JOIN '.TABLE_PREFIX.'Users AS u
 				 ON u.PortalUserId = %1$s.PortalUserId';
 
 			$new_options['Grids']['Default'] = Array (
 				'Icons' => Array (
 								'default' => 'icon16_item.png',
 								'module' => 'core',
 							),
 				'Fields' => Array (
 					'Login' => Array ('filter_block' => 'grid_like_filter'),
 					'FirstName' => Array ('filter_block' => 'grid_like_filter'),
 					'LastName' => Array ('filter_block' => 'grid_like_filter'),
 					'Qty' => Array ('td_style' => 'text-align: center', 'total' => 'sum', 'filter_block' => 'grid_range_filter'),
 					'Cost' => Array ('td_style' => 'text-align: right', 'total' => 'sum', 'filter_block' => 'grid_range_filter'),
 					'Amount' => Array ('title' => 'la_col_GMV', 'td_style' => 'text-align: right', 'total' => 'sum', 'filter_block' => 'grid_range_filter'),
 					'Tax' => Array ('title' => 'la_col_Tax', 'td_style' => 'text-align: right', 'total' => 'sum', 'filter_block' => 'grid_range_filter'),
 					'Shipping' => Array ('title' => 'la_col_Shipping', 'td_style' => 'text-align: right', 'total' => 'sum', 'filter_block' => 'grid_range_filter'),
 					'Processing' => Array ('title' => 'la_col_Processing', 'td_style' => 'text-align: right', 'total' => 'sum', 'filter_block' => 'grid_range_filter'),
 					'Profit' => Array ('title' => 'la_col_Profit', 'td_style' => 'text-align: right', 'total' => 'sum', 'filter_block' => 'grid_range_filter'),
 				),
 			);
 
 			$new_options['VirtualFields'] = array_merge($rep_options['VirtualFields'], Array (
 				'Login' => Array ('type' => 'string', 'default' => ''),
 				'FirstName' => Array ('type' => 'string', 'default' => ''),
 				'LastName' => Array ('type' => 'string', 'default' => ''),
 			));
 
 			$new_options['CalculatedFields'][''] = Array (
 				'Login' => 'u.Username',
 				'FirstName' => 'u.FirstName',
 				'LastName' => 'u.LastName',
 			);
 		}
 		elseif ($field_values['ReportType'] == 5) { // by Product
 
 			$new_options['ListSQLs'][''] =
 				'SELECT %1$s.* %2$s FROM %1$s
 				 LEFT JOIN '.TABLE_PREFIX.'Products AS p
 				 ON p.ProductId = %1$s.ProductId';
 
 			$new_options['Grids']['Default'] = Array (
 				'Icons' => Array (
 					'default' => 'icon16_item.png',
 					'module' => 'core',
 					),
 				'Fields' => Array (
 					'ProductName' => Array ('title' => 'la_col_ProductName', 'filter_block' => 'grid_like_filter'),
 					'Qty' => Array ('td_style' => 'text-align: center', 'total' => 'sum', 'filter_block' => 'grid_range_filter'),
 					'StoreQty' => Array ('title' => 'la_col_StoreQty', 'td_style' => 'text-align: center', 'total' => 'sum', 'filter_block' => 'grid_range_filter'),
 					'eBayQty' => Array ('title' => 'la_col_eBayQty', 'td_style' => 'text-align: center', 'total' => 'sum', 'filter_block' => 'grid_range_filter'),
 					'Cost' => Array ('td_style' => 'text-align: right', 'total' => 'sum', 'hidden' => 1, 'filter_block' => 'grid_range_filter'),
 					'Amount' => Array ('title' => 'la_col_GMV', 'td_style' => 'text-align: right', 'total' => 'sum', 'filter_block' => 'grid_range_filter'),
 					'StoreAmount' => Array ('title' => 'la_col_StoreGMV', 'td_style' => 'text-align: right', 'total' => 'sum', 'filter_block' => 'grid_range_filter'),
 					'eBayAmount' => Array ('title' => 'la_col_eBayGMV', 'td_style' => 'text-align: right', 'total' => 'sum', 'filter_block' => 'grid_range_filter'),
 					'Tax' => Array ('title' => 'la_col_Tax', 'td_style' => 'text-align: right', 'total' => 'sum', 'hidden' => 1, 'filter_block' => 'grid_range_filter'),
 					'Shipping' => Array ('title' => 'la_col_Shipping', 'td_style' => 'text-align: right', 'total' => 'sum', 'hidden' => 1, 'filter_block' => 'grid_range_filter'),
 					'Processing' => Array ('title' => 'la_col_Processing', 'td_style' => 'text-align: right', 'total' => 'sum', 'hidden' => 1, 'filter_block' => 'grid_range_filter'),
 					'Profit' => Array ('title' => 'la_col_Profit', 'td_style' => 'text-align: right', 'total' => 'sum', 'filter_block' => 'grid_range_filter'),
 					'StoreProfit' => Array ('title' => 'la_col_StoreProfit', 'td_style' => 'text-align: right', 'total' => 'sum', 'filter_block' => 'grid_range_filter'),
 					'eBayProfit' => Array ('title' => 'la_col_eBayProfit', 'td_style' => 'text-align: right', 'total' => 'sum', 'filter_block' => 'grid_range_filter'),
 				),
 
 			);
 
 			if (!$this->Application->isModuleEnabled('in-auction'))
 			{
 				$a_fields =& $new_options['Grids']['Default']['Fields'];
 				unset($a_fields['StoreQty']);
 				unset($a_fields['eBayQty']);
 				unset($a_fields['StoreAmount']);
 				unset($a_fields['eBayAmount']);
 				unset($a_fields['StoreProfit']);
 				unset($a_fields['eBayProfit']);
 			}
 
 
 			$new_options['VirtualFields'] = array_merge($rep_options['VirtualFields'], Array (
 				'ProductName' => Array ('type' => 'string', 'default' => ''),
 	            'Metric' => Array (
 	            	'type' => 'int',
 	            	'formatter' => 'kOptionsFormatter',
 	            	'options' => $this->GetMetricOptions($new_options, 'ProductName'),
 	            	'use_phrases' => 1,
 	            	'default' => 0
 	            ),
 			));
 
 			$lang = $this->Application->GetVar('m_lang');
 
 			$new_options['CalculatedFields'][''] = Array (
 				'ProductName' => 'p.l'.$lang.'_Name',
 			);
 		}
 		elseif ($field_values['ReportType'] == 12) { // Overall
 
 			$new_options['ListSQLs'][''] =
 				'SELECT %1$s.* %2$s FROM %1$s';
 
 			$new_options['Fields']['Marketplace'] = Array (
 				'formatter' => 'kOptionsFormatter',
 				'options' => Array (
 					1 => 'la_OnlineStore',
 					2 => 'la_eBayMarketplace',
 				),
 				'use_phrases' => 1,
 				'default' => 1
 			);
 
 			$new_options['Grids']['Default'] = Array(
 				'Icons' => Array(
 					'default' => 'icon16_item.png',
 					'module' => 'core',
 				),
 				'Fields' => Array(
 					'Marketplace' => Array ('title' => 'la_col_Marketplace', 'filter_block' => 'grid_options_filter'),
 					'Qty' => Array ('td_style' => 'text-align: center', 'total' => 'sum', 'filter_block' => 'grid_range_filter'),
 					'Cost' => Array ('td_style' => 'text-align: right', 'total' => 'sum', 'filter_block' => 'grid_range_filter'),
 					'Amount' => Array ('title' => 'la_col_GMV', 'td_style' => 'text-align: right', 'total' => 'sum', 'filter_block' => 'grid_range_filter'),
 					'Tax' => Array ('title' => 'la_col_Tax', 'td_style' => 'text-align: right', 'total' => 'sum', 'filter_block' => 'grid_range_filter'),
 					'Shipping' => Array ('title' => 'la_col_Shipping', 'td_style' => 'text-align: right', 'total' => 'sum', 'filter_block' => 'grid_range_filter'),
 					'Processing' => Array ('title' => 'la_col_Processing', 'td_style' => 'text-align: right', 'total' => 'sum', 'filter_block' => 'grid_range_filter'),
 					'Profit' => Array ('title' => 'la_col_Profit', 'td_style' => 'text-align: right', 'total' => 'sum', 'filter_block' => 'grid_range_filter'),
 				),
 
 			);
 
 
 			$new_options['VirtualFields'] = array_merge($rep_options['VirtualFields'], array(
 	            'Metric' => Array (
 	            	'type' => 'int',
 	            	'formatter' => 'kOptionsFormatter',
 	            	'options' => $this->GetMetricOptions($new_options, 'Marketplace'),
 	            	'use_phrases' => 1,
 	            	'default' => 0
 	            ),
 			));
 
 			$lang = $this->Application->GetVar('m_lang');
 
 		}
 
 		$new_options['ListSortings'] = Array(
 			'' => Array(
 				'Sorting' => Array('Amount' => 'desc'),
 			)
 		);
 
 		foreach ($new_options as $key => $val) {
 			$this->Application->setUnitOption('rep', $key, $val);
 		}
 	}
 
 	/**
 	 * Enter description here...
 	 *
 	 * @param kdbItem $object
 	 * @param string $search_field
 	 * @param string $value
 	 * @param string $type
 	 */
 	function processRangeField(&$object, $search_field, $type)
 	{
 		$value = $object->GetField($search_field);
 		if (!$value) return false;
 
 		$lang_current = $this->Application->recallObject('lang.current');
 		$dt_separator = getArrayValue($object->GetFieldOptions($search_field), 'date_time_separator');
 		if (!$dt_separator) {
 			$dt_separator = ' ';
 		}
 
 		$time = ($type == 'from') ? adodb_mktime(0, 0, 0) : adodb_mktime(23, 59, 59);
 		$time = adodb_date($lang_current->GetDBField('InputTimeFormat'), $time);
 
 		$full_value = $value.$dt_separator.$time;
 
 		$formatter = $this->Application->recallObject( $object->GetFieldOption($search_field, 'formatter') );
 
 		$value_ts = $formatter->Parse($full_value, $search_field, $object);
 
 		if ( $object->GetErrorPseudo($search_field) ) {
 			// invalid format -> ignore this date in search
 			$object->RemoveError($search_field);
 
 			return false;
 		}
 		return $value_ts;
 	}
 
 	/**
 	 * Generate Metric Field Options
 	 *
 	 * @param array $a_config_options
 	 * @param string $exclude_field
 	 */
 	function GetMetricOptions(&$a_config_options, $exclude_field)
 	{
 		$a_ret = Array();
 		foreach ($a_config_options['Grids']['Default']['Fields'] AS $field => $a_options)
 		{
 			if ($field == $exclude_field)
 			{
 				continue;
 			}
 			$a_ret[$field] = $a_options['title'];
 		}
 		return $a_ret;
 	}
 
 	function OnChangeStatistics($event)
 	{
 		$this->Application->StoreVar('ChartMetric', $this->Application->GetVar('metric'));
 	}
 
 	function OnPieChart($event)
 	{
 
 		$ChartHelper = $this->Application->recallObject('ChartHelper');
 
 		$this->Application->setContentType('image/png');
 
 		$width = $event->getEventParam('width');
 		if (!$width) {
 			$width = 800;
 		}
 
 		$height = $event->getEventParam('height');
 		if (!$height) {
 			$height = 600;
 		}
 
 		$a_data = unserialize($this->Application->RecallVar('graph_data'));
 		$chart = new LibchartPieChart($width, $height);
 
 		$dataSet = new LibchartXYDataSet();
 		foreach ($a_data AS $key=>$a_values)
 		{
 			$dataSet->addPoint(new LibchartPoint($a_values['Name'], $a_values['Metric']));
 //			$dataSet->addPoint(new LibchartPoint($a_values['Name'].' ('.$a_values['Metric'].')', $a_values['Metric']));
 		}
 
 		$chart->setDataSet($dataSet);
 
 		$chart->setTitle($this->Application->RecallVar('graph_metric'));
 		$chart->render();
 		$event->status = kEvent::erSTOP;
 	}
 
 	/** Generates png-chart output
 	 *
 	 * @param kEvent $event
 	 */
 
 	function OnPrintChart($event)
 	{
 		$ChartHelper = $this->Application->recallObject('ChartHelper');
 
 		$this->Application->setContentType('image/png');
 
 		$width = $this->Application->GetVar('width');
 		if ($width == 0)
 		{
 			$width = 800;
 		}
 
 		$height = $this->Application->GetVar('height');
 		if ($height == 0)
 		{
 			$height = 400;
 		}
 
 		$chart = new LibchartLineChart($width, $height);
 
 		$a_labels = unserialize($this->Application->RecallVar('graph_labels'));
 
 		if ($this->Application->isModuleEnabled('in-auction'))
 		{
 			$serie1 = new LibchartXYDataSet();
 			$a_serie = unserialize($this->Application->RecallVar('graph_serie1'));
 			foreach ($a_labels AS $key=>$value)
 			{
 				$serie1->addPoint(new LibchartPoint($value, $a_serie[$key]));
 			}
 		}
 
 		$serie2 = new LibchartXYDataSet();
 		$a_serie = unserialize($this->Application->RecallVar('graph_serie2'));
 		foreach ($a_labels AS $key=>$value)
 		{
 			$serie2->addPoint(new LibchartPoint($value, $a_serie[$key]));
 		}
 
 		$dataSet = new LibchartXYSeriesDataSet();
 		if ($this->Application->isModuleEnabled('in-auction'))
 		{
 			$dataSet->addSerie($this->Application->RecallVar('graph_serie1_label'), $serie1);
 		}
 
 		$dataSet->addSerie($this->Application->RecallVar('graph_serie2_label'), $serie2);
 
 		$chart->setDataSet($dataSet);
 
 		$chart->setTitle($this->Application->RecallVar('graph_metric'));
 		$Plot =& $chart->getPlot();
 		$Plot->setGraphCaptionRatio(0.7);
 		$chart->render();
 
 		$event->status = kEvent::erSTOP;
 
 	}
 
 	function OnExportReport($event)
 	{
+		/** @var kDBList $report */
 		$report = $this->Application->recallObject($event->getPrefixSpecial(),'rep_List',Array('skip_counting'=>true,'per_page'=>-1) );
-		/* @var $report kDBList*/
 
+		/** @var kDBItem $ReportItem */
 		$ReportItem = $this->Application->recallObject('rep.item', 'rep', Array('skip_autoload' => true));
-		/* @var $ReportItem kDBItem*/
 
  		$a_grids = $this->Application->getUnitOption('rep', 'Grids');
  		$a_fields = $a_grids['Default']['Fields'];
 		$ret = '';
 
 		foreach ($a_fields AS $field => $a_props)
 		{
 			$ret .= ''.$field.'';
 		}
 
 		$ret = substr($ret, 0, strlen($ret) - 5).'';
 
 
 		$report->Query(true);
 		$report->GoFirst();
 
 		$counter = 0;
 		$a_totals = Array();
 
 		foreach ($a_fields AS $field => $a_props) {
 			$counter++;
 			if ($counter == 1)
 			{
 				continue;
 			}
 			$a_totals[$field] = 0;
 		}
 
 		foreach($report->Records as $a_row) {
 			// TODO: maybe this should be SetDBFieldsFromHash instead, because all data comes from inside.
 			$ReportItem->SetFieldsFromHash($a_row);
 			$row = '';
 			foreach ($a_fields AS $field => $a_props)
 			{
 				$row .= ''.$ReportItem->GetField($field).'';
 				$a_totals[$field] += $a_row[$field];
 			}
 			$ret .= substr($row, 0, strlen($row) - 5).'';
 		}
 
 		// totals
 		// TODO: maybe this should be SetDBFieldsFromHash instead, because all data comes from inside.
 		$ReportItem->SetFieldsFromHash($a_totals);
 		$counter = 0;
 		foreach ($a_fields AS $field => $a_props)
 		{
 			$counter++;
 			if ($counter == 1)
 			{
 				$row = '';
 				continue;
 			}
 			$row .= ''.$ReportItem->GetField($field).'';
 		}
 		$ret .= substr($row, 0, strlen($row) - 5).'';
 
 		$ret = str_replace("\r",'', $ret);
 		$ret = str_replace("\n",'', $ret);
 		$ret = str_replace('"','\'\'', $ret);
 
 		$ret = str_replace('','"', $ret);
 		$ret = str_replace('',',', $ret);
 		$ret = str_replace('',"\r", $ret);
 
 		$report_options = unserialize($this->Application->RecallVar('report_options'));
 
 		switch ($report_options['ReportType'])
 		{
 			case 1:
 				$file_name = '-ByCategory';
 				break;
 			case 2:
 				$file_name = '-ByUser';
 				break;
 			case 5:
 				$file_name = '-ByProduct';
 				break;
 			case 12:
 				$file_name = '';
 				break;
 		}
 
 		header("Content-type: application/txt");
 		header("Content-length: ".(string)strlen($ret));
 		header("Content-Disposition: attachment; filename=\"".html_entity_decode('SalesReport'.$file_name.'-'.date('d-M-Y').'.csv')."\"");
 		header("Pragma: no-cache"); //some IE-fixing stuff
 		echo $ret;
 		exit();
 	}
 }
Index: branches/5.2.x/units/reports/reports_tag_processor.php
===================================================================
--- branches/5.2.x/units/reports/reports_tag_processor.php	(revision 16515)
+++ branches/5.2.x/units/reports/reports_tag_processor.php	(revision 16516)
@@ -1,438 +1,438 @@
 CalcReport($params);
 
 		if ($field_values['offset'] == $field_values['total']) {
 			$this->Application->Redirect($this->Application->RecallVar('reports_finish_t'));
 			$this->Application->RemoveVar('report_options');
 		}
 		else {
 			$this->Application->StoreVar('report_options', serialize($field_values));
 		}
 
 		return $field_values['offset']  * 100 / $field_values['total'];
 	}
 
 	function CalcReport($params)
 	{
 		$field_values = unserialize($this->Application->RecallVar('report_options'));
 		$per_step = 20;
 
 		$cats = $this->Conn->Query('SELECT * FROM '.TABLE_PREFIX.'Categories ORDER BY CategoryId LIMIT '.$field_values['offset'].', '.$per_step);
 
 		foreach ($cats as $a_cat) {
 			if ($field_values['Recursive']) {
 				$cat_filter = 'c.ParentPath LIKE '.$this->Conn->qstr($a_cat['ParentPath'].'%');
 			}
 			else {
 				$cat_filter = 'c.CategoryId = '.$a_cat['CategoryId'];
 			}
 
 			$q = 'INSERT INTO '.$field_values['table_name'].'
 						SELECT
 							c.CategoryId,
 							SUM(od.Quantity) as Qty,
 							SUM(od.Cost) as Cost,
 							SUM(od.Price) as SaleAmount,
 							0 as Tax,
 							0 as Shipping,
 							0 as Processing,
 							SUM(od.Price - od.Cost) as Profit
 						FROM '.TABLE_PREFIX.'Orders AS o
 						LEFT JOIN '.TABLE_PREFIX.'OrderItems AS od
 						ON od.OrderId = o.OrderId
 						LEFT JOIN '.TABLE_PREFIX.'Products AS p
 						ON p.ProductId = od.ProductId
 						LEFT JOIN '.TABLE_PREFIX.'CategoryItems AS ci
 						ON ci.ItemResourceId = p.ResourceId
 						LEFT JOIN '.TABLE_PREFIX.'Categories AS c
 						ON c.CategoryId = ci.CategoryId
 						WHERE
 							o.Status = 4
 							AND
 							ci.PrimaryCat = 1
 							AND
 							'.$cat_filter.'
 						GROUP BY c.CategoryId';
 			$this->Conn->Query($q);
 
 			$field_values['offset']++;
 		}
 
 		return $field_values;
 	}
 
 	function ReportTypeEquals($params)
 	{
 		$field_values = unserialize($this->Application->RecallVar('report_options'));
 		return ($field_values['ReportType'] == $params['value']);
 	}
 
 	function CalculateChart($params)
 	{
 
 		$a_report_options = unserialize($this->Application->RecallVar('report_options'));
 		$metric = $this->Application->RecallVar('ChartMetric');
 		if ($metric == '')
 		{
 			// get first option from unit config
 			$a_virtual_fields = $this->Application->getUnitOption('rep', 'VirtualFields');
 			foreach ($a_virtual_fields['Metric']['options'] AS $field => $label)
 			{
 				$metric = $field;
 				break;
 			}
 		}
 
 
+		/** @var kDBItem $object */
 		$object = $this->Application->recallObject('rep.params', null, Array('skip_autoload' => true));
-		/* @var $object kDBItem */
 
 		$object->setID(1);
 		$object->SetDBField('Metric', $metric);
 
 		if (!($a_report_options['from'] && $a_report_options['to'])) {
 			// calculate from & to as extreme order dates
 			$sql = 'SELECT MAX(OrderDate) AS date_to, MIN(OrderDate) AS date_frm
 				FROM '.TABLE_PREFIX.'Orders
 				WHERE
 					Status IN (4,6)
 			';
 			$a_dates = $this->Conn->GetRow($sql);
 			$a_report_options['from'] = adodb_mktime(0, 0, 0, date('m', $a_dates['date_frm']), date('d', $a_dates['date_frm']), date('Y', $a_dates['date_frm']));
 			$a_report_options['to'] = adodb_mktime(0, 0, 0, date('m', $a_dates['date_to']), date('d', $a_dates['date_to']) + 1, date('Y', $a_dates['date_to'])) - 1;
 		}
 
 		$filter_value = 'AND o.OrderDate >= '.$a_report_options['from'].' AND o.OrderDate <= '.$a_report_options['to'];
 
 
 		if ($a_report_options['ReportType'] == 12)
 		{
 			// Overall
 
 			$selected_days = round(($a_report_options['to'] - $a_report_options['from'] + 1) / 3600 / 24);
 			// determine date interval
 			if ($selected_days < 2)
 			{
 				$step_seconds = 3600;
 				$step_labels = Array();
 				for ($i=0; $i<24; $i++)
 				{
 					$hour = str_pad($i, 2, '0', STR_PAD_LEFT);
 					$step_labels[$i] = $hour;
 				}
 			} elseif (
 				($selected_days < 31)
 				|| (date('mY', $a_report_options['from']) == date('mY', $a_report_options['to']))
 			)
 			{
 				$step_seconds = 24*3600;
 				$step_labels = Array();
 				$curr_date = $a_report_options['from'];
 				while ($curr_date <= $a_report_options['to'])
 				{
 					$curr_date += $step_seconds;
 					$step_labels[] = date('d-M', $curr_date);
 				}
 			} else {
 				$start_year = date('Y', $a_report_options['from']);
 				$start_month = date('m', $a_report_options['from']);
 				$end_month_year = date('Ym', $a_report_options['to']);
 				// big interval - move from date to the first day ot the month
 				$a_report_options['from'] = adodb_mktime(0, 0, 0, date('m', $a_report_options['from']), 1, date('Y', $a_report_options['from']));
 				$curr_time = $a_report_options['from'];
 				while (date('Ym', $curr_time) <= $end_month_year)
 				{
 					$step_labels[date('Ym', $curr_time)] = date('M-Y', $curr_time);
 					// add month
 					$curr_time = adodb_mktime(0,0,0, date('m', $curr_time) + 1, 1, date('Y', $curr_time));
 				}
 				$step_seconds = 0;
 			}
 
 			$a_expressions = Array(
 				'Qty' => 'od.Quantity',
 				'Cost' => 'od.Cost * od.Quantity',
 				'Amount' => 'od.Price * od.Quantity',
 				'Tax' => 'o.VAT * od.Price * od.Quantity / o.SubTotal',
 				'Shipping' => 'o.ShippingCost * od.Price * od.Quantity / o.SubTotal',
 				'Processing' => 'o.ProcessingFee * od.Price * od.Quantity / o.SubTotal',
 				'Profit' => '(od.Price - od.Cost)  * od.Quantity',
 			);
 
 			if ($step_seconds)
 			{
 				$period_sql = 'FLOOR(
 								(o.OrderDate - '.$a_report_options['from'].')
 								/'.$step_seconds.'
 							)';
 			} else {
 				$period_sql = 'CONCAT(YEAR(FROM_UNIXTIME(o.OrderDate)),LPAD(MONTH(FROM_UNIXTIME(o.OrderDate)), 2, \'0\'))';
 			}
 
 			if ($this->Application->isModuleEnabled('in-auction'))
 			{
 				$sql = 'SELECT
 							'.$period_sql.' AS Period,
 							SUM(IF(ISNULL(eod.OptionsSalt), '.$a_expressions[$metric].', 0)) as StoreMetric,
 							SUM(IF(ISNULL(eod.OptionsSalt), 0, '.$a_expressions[$metric].')) as eBayMetric
 					FROM '.TABLE_PREFIX.'Orders AS o
 					LEFT JOIN '.TABLE_PREFIX.'OrderItems AS od
 					ON od.OrderId = o.OrderId
 					LEFT JOIN '.TABLE_PREFIX.'eBayOrderItems AS eod
 					ON od.OptionsSalt = eod.OptionsSalt
 					WHERE
 						o.Status IN (4,6)
 						'.$filter_value.'
 						GROUP BY Period';
 			} else 	{
 
 				$sql = 'SELECT
 							'.$period_sql.' AS Period,
 							SUM('.$a_expressions[$metric].') as StoreMetric,
 							0 as eBayMetric
 					FROM '.TABLE_PREFIX.'Orders AS o
 					LEFT JOIN '.TABLE_PREFIX.'OrderItems AS od
 					ON od.OrderId = o.OrderId
 					WHERE
 						o.Status IN (4,6)
 						'.$filter_value.'
 						GROUP BY Period';
 
 			}
 
 			$a_data = $this->Conn->Query($sql, 'Period');
 
 			// create series array
 			$a_serie1 = Array();
 			$a_serie2 = Array();
 			foreach ($step_labels AS $key => $label)
 			{
 				$a_serie1[$key] = (isset($a_data[$key]['eBayMetric']) && !is_null($a_data[$key]['eBayMetric'])) ? $a_data[$key]['eBayMetric'] : 0;
 				$a_serie2[$key] = (isset($a_data[$key]['StoreMetric']) && !is_null($a_data[$key]['StoreMetric'])) ? $a_data[$key]['StoreMetric'] : 0;
 			}
 
 			$show_date_from = date('m/d/Y', $a_report_options['from']);
 			$show_date_to = date('m/d/Y', $a_report_options['to']);
 			$show_date = ($show_date_from == $show_date_to) ? $show_date_to : $show_date_from.' - '.$show_date_to;
 
 			$this->Application->StoreVar('graph_metric', $object->GetField('Metric').' :: ('.$show_date.') :: '.DOMAIN);
 			$this->Application->StoreVar('graph_serie1', serialize($a_serie1));
 			$this->Application->StoreVar('graph_serie2', serialize($a_serie2));
 
 			$this->Application->StoreVar('graph_serie1_label', $this->Application->Phrase('la_eBayMarketplace'));
 			$this->Application->StoreVar('graph_serie2_label', $this->Application->Phrase('la_OnlineStore'));
 			$this->Application->StoreVar('graph_labels', serialize($step_labels));
 
 			return;
 
 		}
 
 
 		$ebay_joins = '';
 		if ($this->Application->isModuleEnabled('in-auction'))
 		{
 			$ebay_joins = '
 				LEFT JOIN '.TABLE_PREFIX.'eBayOrderItems AS eod
 				ON od.OptionsSalt = eod.OptionsSalt
 			';
 		}
 
 		if ($a_report_options['ReportType'] == 1)
 		{
 			// pie chart by category
 
 			$a_expressions = Array(
 				'Qty' => 'od.Quantity',
 				'Cost' => 'od.Cost * od.Quantity',
 				'Amount' => 'od.Price * od.Quantity',
 				'Tax' => 'o.VAT * od.Price * od.Quantity / o.SubTotal',
 				'Shipping' => 'o.ShippingCost * od.Price * od.Quantity / o.SubTotal',
 				'Processing' => 'o.ProcessingFee * od.Price * od.Quantity / o.SubTotal',
 				'Profit' => '(od.Price - od.Cost)  * od.Quantity',
 				'StoreQty' => 'IF(ISNULL(eod.OptionsSalt), od.Quantity, 0)',
 				'eBayQty' => 'IF(ISNULL(eod.OptionsSalt), 0, od.Quantity)',
 				'StoreAmount' => 'IF(ISNULL(eod.OptionsSalt), od.Price * od.Quantity, 0)',
 				'eBayAmount' => 'IF(ISNULL(eod.OptionsSalt), 0, od.Price * od.Quantity)',
 				'StoreProfit' => 'IF(ISNULL(eod.OptionsSalt), (od.Price - od.Cost) * od.Quantity, 0)',
 				'eBayProfit' => 'IF(ISNULL(eod.OptionsSalt), 0, (od.Price - od.Cost) * od.Quantity)',
 			);
 
 			$lang = $this->Application->GetVar('m_lang');
 
 			$sql = 'SELECT
 						LEFT(c.l'.$lang.'_Name, 60) AS Name,
 						c.CategoryId,
 						SUM('.$a_expressions[$metric].') as Metric
 				FROM '.TABLE_PREFIX.'Orders AS o
 				LEFT JOIN '.TABLE_PREFIX.'OrderItems AS od
 				ON od.OrderId = o.OrderId
 				LEFT JOIN '.TABLE_PREFIX.'Products AS p
 				ON p.ProductId = od.ProductId
 				LEFT JOIN '.TABLE_PREFIX.'CategoryItems AS ci
 				ON ci.ItemResourceId = p.ResourceId
 				LEFT JOIN '.TABLE_PREFIX.'Categories AS c
 				ON c.CategoryId = ci.CategoryId
 				'.$ebay_joins.'
 				WHERE
 					o.Status IN (4,6)
 					'.$filter_value.'
 				GROUP BY c.CategoryId
 				HAVING NOT ISNULL(CategoryId)
 				ORDER BY Metric DESC
 				LIMIT 0,8
 				';
 			$a_data = $this->Conn->Query($sql, 'CategoryId');
 
 			$other_metric = 0;
 			if (count($a_data) > 7)
 			{
 				// gather ids for "others" call
 				$ids = join(',', array_keys($a_data));
 				$sql = 'SELECT
 							SUM('.$a_expressions[$metric].')
 					FROM '.TABLE_PREFIX.'Orders AS o
 					LEFT JOIN '.TABLE_PREFIX.'OrderItems AS od
 					ON od.OrderId = o.OrderId
 					LEFT JOIN '.TABLE_PREFIX.'Products AS p
 					ON p.ProductId = od.ProductId
 					LEFT JOIN '.TABLE_PREFIX.'CategoryItems AS ci
 					ON ci.ItemResourceId = p.ResourceId
 					LEFT JOIN '.TABLE_PREFIX.'Categories AS c
 					ON c.CategoryId = ci.CategoryId
 					'.$ebay_joins.'
 					WHERE
 						o.Status IN (4,6)
 						'.$filter_value.'
 						AND c.CategoryId NOT IN ('.$ids.')
 					';
 				$other_metric = $this->Conn->GetOne($sql);
 				if ($other_metric != 0)
 				{
 					$a_data[0] = Array(
 						'Metric' => $other_metric,
 						'Name' => $this->Application->Phrase('la_text_Others'),
 					);
 				}
 			}
 
 
 			$show_date_from = date('m/d/Y', $a_report_options['from']);
 			$show_date_to = date('m/d/Y', $a_report_options['to']);
 			$show_date = ($show_date_from == $show_date_to) ? $show_date_to : $show_date_from.' - '.$show_date_to;
 
 			$this->Application->StoreVar('graph_metric', $this->Application->Phrase('la_text_ReportByTopProductCategories').' '.$object->GetField('Metric').' :: ('.$show_date.') :: '.DOMAIN);
 			$this->Application->StoreVar('graph_data', serialize($a_data));
 			return;
 		}
 
 
 		if ($a_report_options['ReportType'] == 5)
 		{
 			// pie chart by product
 
 			$a_expressions = Array(
 				'Qty' => 'od.Quantity',
 				'Cost' => 'od.Cost * od.Quantity',
 				'Amount' => 'od.Price * od.Quantity',
 				'Tax' => 'o.VAT * od.Price * od.Quantity / o.SubTotal',
 				'Shipping' => 'o.ShippingCost * od.Price * od.Quantity / o.SubTotal',
 				'Processing' => 'o.ProcessingFee * od.Price * od.Quantity / o.SubTotal',
 				'Profit' => '(od.Price - od.Cost)  * od.Quantity',
 				'StoreQty' => 'IF(ISNULL(eod.OptionsSalt), od.Quantity, 0)',
 				'eBayQty' => 'IF(ISNULL(eod.OptionsSalt), 0, od.Quantity)',
 				'StoreAmount' => 'IF(ISNULL(eod.OptionsSalt), od.Price * od.Quantity, 0)',
 				'eBayAmount' => 'IF(ISNULL(eod.OptionsSalt), 0, od.Price * od.Quantity)',
 				'StoreProfit' => 'IF(ISNULL(eod.OptionsSalt), (od.Price - od.Cost) * od.Quantity, 0)',
 				'eBayProfit' => 'IF(ISNULL(eod.OptionsSalt), 0, (od.Price - od.Cost) * od.Quantity)',
 			);
 
 			$lang = $this->Application->GetVar('m_lang');
 
 			$sql = 'SELECT
 						LEFT(p.l'.$lang.'_Name, 60) AS Name,
 						p.ProductId,
 						SUM('.$a_expressions[$metric].') as Metric
 				FROM '.TABLE_PREFIX.'Orders AS o
 				LEFT JOIN '.TABLE_PREFIX.'OrderItems AS od
 				ON od.OrderId = o.OrderId
 				LEFT JOIN '.TABLE_PREFIX.'Products AS p
 				ON p.ProductId = od.ProductId
 				'.$ebay_joins.'
 				WHERE
 					o.Status IN (4,6)
 					'.$filter_value.'
 				GROUP BY p.ProductId
 				HAVING NOT ISNULL(ProductId)
 				ORDER BY Metric DESC
 				LIMIT 0,8
 				';
 			$a_data = $this->Conn->Query($sql, 'ProductId');
 
 			$other_metric = 0;
 			if (count($a_data) > 7)
 			{
 				// gather ids for "others" call
 				$ids = join(',', array_keys($a_data));
 				$sql = 'SELECT
 							SUM('.$a_expressions[$metric].')
 					FROM '.TABLE_PREFIX.'Orders AS o
 					LEFT JOIN '.TABLE_PREFIX.'OrderItems AS od
 					ON od.OrderId = o.OrderId
 					LEFT JOIN '.TABLE_PREFIX.'Products AS p
 					ON p.ProductId = od.ProductId
 					'.$ebay_joins.'
 					WHERE
 						o.Status IN (4,6)
 						'.$filter_value.'
 						AND p.ProductId NOT IN ('.$ids.')
 					';
 				$other_metric = $this->Conn->GetOne($sql);
 				if ($other_metric != 0)
 				{
 					$a_data[0] = Array(
 						'Metric' => $other_metric,
 						'Name' => $this->Application->Phrase('la_Others'),
 					);
 				}
 			}
 
 
 			$show_date_from = date('m/d/Y', $a_report_options['from']);
 			$show_date_to = date('m/d/Y', $a_report_options['to']);
 			$show_date = ($show_date_from == $show_date_to) ? $show_date_to : $show_date_from.' - '.$show_date_to;
 
 			$this->Application->StoreVar('graph_metric', $this->Application->Phrase('la_text_ReportByTopProducts').' '.$object->GetField('Metric').' :: ('.$show_date.') :: '.DOMAIN);
 			$this->Application->StoreVar('graph_data', serialize($a_data));
 		}
 
 	}
 
 	function GetRandom($params)
 	{
 		return rand(1,10000000);
 	}
 
 	function IsPHPxOrGreater($params)
 	{
 		$curver = explode(".", phpversion());
 		return ($curver[0] >= $params['version']);
 	}
 }
\ No newline at end of file
Index: branches/5.2.x/units/brackets/brackets_event_handler.php
===================================================================
--- branches/5.2.x/units/brackets/brackets_event_handler.php	(revision 16515)
+++ branches/5.2.x/units/brackets/brackets_event_handler.php	(revision 16516)
@@ -1,231 +1,231 @@
  Array ('subitem' => 'add|edit'),
 			'OnInfinity' => Array ('subitem' => 'add|edit'),
 			'OnArrange' => Array ('subitem' => 'add|edit'),
 		);
 
 		$this->permMapping = array_merge($this->permMapping, $permissions);
 	}
 
 	/**
 	 * Apply some special processing to object being
 	 * recalled before using it in other events that
 	 * call prepareObject
 	 *
 	 * @param kDBItem|kDBList $object
 	 * @param kEvent $event
 	 * @return void
 	 * @access protected
 	 */
 	protected function prepareObject(&$object, kEvent $event)
 	{
 		if ( $this->Application->GetVar('s_id') === false ) {
 			return;
 		}
 
+		/** @var kDBItem $shipping_object */
 		$shipping_object = $this->Application->recallObject('s');
-		/* @var $shipping_object kDBItem */
 
+		/** @var LanguagesItem $lang_object */
 		$lang_object = $this->Application->recallObject('lang.current');
-		/* @var $lang_object LanguagesItem */
 
 		if ( $lang_object->GetDBField('UnitSystem') == 2 && $shipping_object->GetDBField('Type') == 1 ) {
 			$fields = Array ('Start', 'End');
 
+			/** @var kUnitFormatter $formatter */
 			$formatter = $this->Application->recallObject('kUnitFormatter');
-			/* @var $formatter kUnitFormatter */
 
 			foreach ($fields as $field) {
 				$object->SetFieldOption($field, 'formatter', 'kUnitFormatter');
 				$options = $object->GetFieldOptions($field);
 
 				$formatter->prepareOptions($field, $options, $object);
 			}
 		}
 	}
 
 	function prepareBrackets($event)
 	{
+		/** @var LanguagesItem $lang_object */
 		$lang_object = $this->Application->recallObject('lang.current');
-		/* @var $lang_object LanguagesItem */
 
+		/** @var kDBItem $shipping_object */
 		$shipping_object = $this->Application->recallObject('s');
-		/* @var $shipping_object kDBItem */
 
 		if ( $lang_object->GetDBField('UnitSystem') != 2 || $shipping_object->GetDBField('Type') != 1 ) {
 			return;
 		}
 
 		$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'] === '' ) {
 				$item_info[$id]['Start'] = '';
 			}
 			else {
 				$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'] == '∞' ) {
 				$item_info[$id]['End'] = '∞';
 			}
 			elseif ( $item_info[$id]['End_a'] === '' && $item_info[$id]['End_b'] === '' ) {
 				$item_info[$id]['End'] = '';
 			}
 			else {
 				$item_info[$id]['End'] = kUtil::Pounds2Kg($item_info[$id]['End_a'], $item_info[$id]['End_b']);
 			}
 		}
 
 		$this->Application->SetVar($event->getPrefixSpecial(), $item_info);
 	}
 
 	/**
 	 * Adds additional 5 empty brackets
 	 *
 	 * @param kEvent $event
 	 */
 	function OnMoreBrackets($event)
 	{
 		$brackets_helper =& $this->getHelper($event);
 
 		$brackets_helper->OnMoreBrackets($event);
 	}
 
 	/**
 	 * Arrange brackets
 	 *
 	 * @param kEvent $event
 	 */
 	function OnArrange($event)
 	{
 		$brackets_helper =& $this->getHelper($event);
 
 		$brackets_helper->arrangeBrackets($event);
 		$event->CallSubEvent('OnPreSaveBrackets');
 	}
 
 	/**
 	 * Arrange infinity brackets
 	 *
 	 * @param kEvent $event
 	 */
 	function OnInfinity($event)
 	{
 		$brackets_helper =& $this->getHelper($event);
 
 		$brackets_helper->arrangeBrackets($event);
 		$event->CallSubEvent('OnPreSaveBrackets');
 
 		$brackets_helper->OnInfinity($event);
 		$event->CallSubEvent('OnPreSaveBrackets');
 	}
 
 	/**
 	 * Initializes kBracketsHelper class based on event
 	 *
 	 * @param kEvent $event
 	 * @param bool $event_readonly
 	 * @return kBracketsHelper
 	 */
 	protected function &getHelper($event, $event_readonly = false)
 	{
+		/** @var kDBItem $shipping_object */
 		$shipping_object = $this->Application->recallObject('s');
-		/* @var $shipping_object kDBItem */
 
 		$default_start = $shipping_object->GetDBField('Type') == 1 ? 0 : 1;
 
 		if ( !$event_readonly ) {
 			$this->prepareBrackets($event);
 			$event->redirect = false;
 		}
 
+		/** @var kBracketsHelper $brackets_helper */
 		$brackets_helper = $this->Application->recallObject('BracketsHelper');
-		/* @var $brackets_helper kBracketsHelper */
 
 		$brackets_helper->InitHelper('Start', 'End', Array (), $default_start);
 
 		return $brackets_helper;
 	}
 
 	/**
 	 * Occurs before updating item
 	 *
 	 * @param kEvent $event
 	 * @return void
 	 * @access protected
 	 */
 	protected function OnBeforeItemUpdate(kEvent $event)
 	{
 		parent::OnBeforeItemUpdate($event);
 
+		/** @var kDBItem $object */
 		$object = $event->getObject();
-		/* @var $object kDBItem */
 
 		$linked_info = $object->getLinkedInfo();
 		$object->SetDBField($linked_info['ParentTableKey'], $linked_info['ParentId']);
 
 		$brackets_helper =& $this->getHelper($event, true);
 		$brackets_helper->replaceInfinity($event);
 	}
 
 	/**
 	 * Enter description here...
 	 *
 	 * @param kEvent $event
 	 */
 	function OnPreSaveBrackets($event)
 	{
+		/** @var LanguagesItem $lang_object */
 		$lang_object = $this->Application->recallObject('lang.current');
-		/* @var $lang_object LanguagesItem */
 
+		/** @var kDBItem $shipping_object */
 		$shipping_object = $this->Application->recallObject('s');
-		/* @var $shipping_object kDBItem */
 
 		if ( $lang_object->GetDBField('UnitSystem') == 2 && $shipping_object->GetDBField('Type') == 1 ) {
 			$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 / kUtil::POUND_TO_KG;
 						$item_info[$id]['End_b'] = 0;
 					}
 				}
 				$this->Application->SetVar($event->getPrefixSpecial(), $item_info);
 			}
 		}
 
 		$brackets_helper =& $this->getHelper($event, true);
 		$brackets_helper->OnPreSaveBrackets($event);
 	}
 
 }
\ No newline at end of file
Index: branches/5.2.x/units/brackets/brackets_tag_processor.php
===================================================================
--- branches/5.2.x/units/brackets/brackets_tag_processor.php	(revision 16515)
+++ branches/5.2.x/units/brackets/brackets_tag_processor.php	(revision 16516)
@@ -1,202 +1,202 @@
 SelectParam($params, 'name,field');
 
 		if ( ($field == 'Start' || $field == 'End') && $value == -1 ) {
 			$value = '∞';
 		}
 
 		return $value;
 	}
 
 	function ShowBracketsForm($params)
 	{
+		/** @var kDBItem $shipping_object */
 		$shipping_object = $this->Application->recallObject('s');
-		/* @var $shipping_object kDBItem */
 
 		$default_start = ($shipping_object->GetDBField('Type') == 1) ? 0 : 1;
 
+		/** @var kBracketsHelper $brackets_helper */
 		$brackets_helper = $this->Application->recallObject('BracketsHelper');
-		/* @var $brackets_helper kBracketsHelper */
 
 		$brackets_helper->InitHelper('Start', 'End', Array(), $default_start );
 
 		$br_object = $this->Application->recallObject( $this->getPrefixSpecial() );
 
 		$event = new kEvent($this->getPrefixSpecial(true) . ':OnArrange');
 		$br_data = $brackets_helper->getBrackets($event);
 		$linked_info = $br_object->getLinkedInfo($this->Special);
 
 		if (!$br_data) {
 			$sql = 	'SELECT * FROM '.$br_object->TableName.' WHERE '.$linked_info['ForeignKey'].' = '.$linked_info['ParentId'];
 			$brackets = $this->Conn->Query($sql, $br_object->IDField);
 
 			usort($brackets, Array(&$brackets_helper, 'compareBrackets'));
 
+			/** @var kDBItem $dummy */
 			$dummy = $this->Application->recallObject($this->Prefix.'.-dummy', null, array('skip_autoload' => true));
-			/* @var $dummy kDBItem */
 
 			// performs number formatting
 			foreach($brackets as $id => $values)
 			{
 				foreach($values as $value_key=>$value_val){
 					$dummy->SetDBField($value_key, $value_val);
 					$brackets[$id][$value_key] = $dummy->GetField($value_key);
 				}
 			}
 
 			$br_data = $brackets;
 			$brackets_helper->setBrackets($event, $brackets);
 		}
 		else {
 			usort($br_data, Array(&$brackets_helper, 'compareBrackets'));
 			$br_data = $brackets_helper->formatBrackets($br_data);
 		}
 
 		$ret = '';
 		if ( is_array($br_data) ) {
 			$block_params = $this->prepareTagParams($params);
 			$block_params['IdField'] = $br_object->IDField;
 			$block_params['name'] = $params['block'];
 			$first = true;
 
 			$main_object = $this->Application->recallObject($linked_info['ParentPrefix'].'.'.$this->Special);
 //			$plan_type = $main_object->GetDBField('PlanType');
 //			$limits_format = ($plan_type == 2) ? '%d' : $br_object->getFieldOption('Start', 'format');
 
 			// this is needed to find next id
 			$br_data_copy = $br_data;
 			foreach($br_data as $id => $values)
 			{
 
 				foreach($values as $value_key => $value_val)
 				{
 					$block_params[$value_key] = $value_val;
 				}
 				reset($values);
 
 				next($br_data_copy);
 				$next_bracket = current($br_data_copy);
 
 //				$values['Start'] = sprintf($limits_format, $values['Start']);
 //				$values['End'] = sprintf($limits_format, $values['End']);
 
 				$block_params['id']	= $values[$br_object->IDField];
 				$block_params['min'] = ($id == -1) ? ($values['Start'] ? $values['Start'] : 0) : $values['Start'];
 				$block_params['max'] = ($values['End'] == -1) ? '∞' : $values['End'];
 				$block_params['next_min_id'] = $next_bracket[$br_object->IDField];
 
 				$lang_object = $this->Application->recallObject('lang.current');
 				if($lang_object->GetDBField('UnitSystem') == 2 && $main_object->GetDBField('Type') == 1)
 				{
 					if($block_params['min'] === '')
 					{
 						$block_params['min_a'] = '';
 						$block_params['min_b'] = '';
 					}
 					else
 					{
 						list($block_params['min_a'], $block_params['min_b']) = kUtil::Kg2Pounds($block_params['min']);
 					}
 
 					if($block_params['max'] == '∞')
 					{
 						$block_params['max_a'] = '∞';
 						$block_params['max_b'] = '';
 					}
 					else
 					{
 						list($block_params['max_a'], $block_params['max_b']) = kUtil::Kg2Pounds($block_params['max']);
 					}
 				}
 
 				if($first)
 				{
 					$block_params['first'] = 1;
 					$first = false;
 				}
 				else
 				{
 					$block_params['first'] = 0;
 				}
 				$ret .= $this->Application->ParseBlock($block_params, 1);
 			}
 		}
 		return $ret;
 	}
 
 
 	/*
 	function ShowBracketsForm($params)
 	{
 		$br_object = $this->Application->recallObject( $this->getPrefixSpecial() );
 
 		$br_data = $this->Application->GetVar('br');
 
 		if(!$br_data)
 		{
 			$sql = 	'SELECT * FROM '.$br_object->TableName.
 					' WHERE ShippingTypeID = '.$this->Application->GetVar('s_id');
 			$brackets = $this->Conn->Query($sql, 'BracketId');
 			usort($brackets, 'bracket_comp');
 
 			$br_data = array_reverse($brackets);
 			$this->Application->SetVar('br', $br_data);
 		}
 		else
 		{
 			$br_data = array_reverse($br_data);
 		}
 
 		$ret = '';
 		if( is_array($br_data) )
 		{
 			$i = -count($br_data);
 			ksort($br_data);
 			foreach($br_data as $record)
 			{
 				$temp_sorted[$i] = $record;
 				$i++;
 			}
 			$br_data = array_reverse($temp_sorted, true);
 
 			$block_params['name'] = $params['block'];
 			$first = true;
 			foreach($br_data as $id => $values)
 			{
 				$block_params['id']	= $id;
 				$block_params['start']	= ($id == -1) ? ($values['Start'] ? $values['Start'] : 0) : $values['Start'];
 				$block_params['end'] = ($values['End'] == -1) ? '∞' : $values['End'];
 				if ($first)
 				{
 					$block_params['first'] = 1;
 					$first = false;
 				}
 				else
 				{
 					$block_params['first'] = 0;
 				}
 				$ret .= $this->Application->ParseBlock($block_params);
 			}
 		}
 		return $ret;
 	}*/
 }
\ No newline at end of file
Index: branches/5.2.x/units/payment_type_currencies/payment_type_currencies_event_handler.php
===================================================================
--- branches/5.2.x/units/payment_type_currencies/payment_type_currencies_event_handler.php	(revision 16515)
+++ branches/5.2.x/units/payment_type_currencies/payment_type_currencies_event_handler.php	(revision 16516)
@@ -1,63 +1,63 @@
 Application->GetVar('currency_list');
 
 			if ( !$currency_id_list ) {
 				return;
 			}
 
+			/** @var kDBItem $object */
 			$object = $event->getObject(Array ('skip_autoload' => true));
-			/* @var $object kDBItem */
 
 			$pt_id = $this->Application->GetVar('pt_id');
 
 			if ( $pt_id === false ) {
 				return;
 			}
 
 			$sql = 'DELETE FROM ' . $object->TableName . '
 					WHERE PaymentTypeId = ' . $pt_id;
 			$this->Conn->Query($sql);
 
 			foreach ($currency_id_list as $id) {
 				$object->SetDBField('CurrencyId', $id);
 				$object->SetDBField('PaymentTypeId', $pt_id);
 				$this->customProcessing($event, 'before');
 
 				if ( $object->Create() ) {
 					$this->customProcessing($event, 'after');
 					$event->status = kEvent::erSUCCESS;
 				}
 				else {
 					$event->status = kEvent::erFAIL;
 					$event->redirect = false;
 					$this->Application->SetVar($event->getPrefixSpecial() . '_SaveEvent', 'OnCreate');
 					$object->setID(0);
 				}
 			}
 		}
 	}
\ No newline at end of file
Index: branches/5.2.x/units/helpers/order_helper.php
===================================================================
--- branches/5.2.x/units/helpers/order_helper.php	(revision 16515)
+++ branches/5.2.x/units/helpers/order_helper.php	(revision 16516)
@@ -1,250 +1,250 @@
 Application->RecallVar('checkout_errors');
 
 			$ret = Array (
 				'order' => Array (
 					'CouponId' => (int)$object->GetDBField('CouponId'),
 					'CouponName' => (string)$object->GetDBField('CouponName'),
 					'GiftCertificateId' => (int)$object->GetDBField('GiftCertificateDiscount'),
 					'GiftCertificateDiscount' => $this->convertCurrency($object->GetDBField('GiftCertificateDiscount'), $currency),
 					'DiscountTotal' => $this->convertCurrency($object->GetDBField('DiscountTotal'), $currency),
 					'SubTotal' => $this->convertCurrency($object->GetDBField('SubTotal'), $currency),
 				),
 				'items' => Array (),
 				'errors' => $errors ? unserialize($errors) : Array (),
 			);
 
+			/** @var kDBList $items */
 			$items = $this->Application->recallObject('orditems', 'orditems_List', Array ('per_page' => -1));
-			/* @var $items kDBList */
 
 			$items->Query();
 			$items->GoFirst();
 
 			$ret['order']['ItemsInCart'] = array_sum( $items->GetCol('Quantity') );
 
 			if ( $items->EOL() ) {
 				return $ret;
 			}
 
+			/** @var kCatDBItem $product */
 			$product = $this->Application->recallObject('p', null, Array ('skip_autoload' => true));
-			/* @var $product kCatDBItem */
 
 			$sql =  $product->GetSelectSQL() . '
 					WHERE ' . $product->TableName . '.' . $product->IDField . ' IN (' . implode(',', $items->GetCol('ProductId')) . ')';
 			$products = $this->Conn->Query($sql, $product->IDField);
 
 			while ( !$items->EOL() ) {
 				// prepare product from order item
 				$product->LoadFromHash( $products[ $items->GetDBField('ProductId') ] );
 				$this->Application->SetVar('orditems_id', $items->GetID()); // for edit/delete links using GET
 
 				// weird code from orditems:PrintList
 				$this->Application->SetVar('p_id', $product->GetID());
 				$this->Application->SetVar('m_cat_id', $product->GetDBField('CategoryId'));
 
 				// collect order item info
 				$url_params = Array (
 					'p_id' => $product->GetID(),
 					'm_cat_id' => $product->GetDBField('CategoryId'),
 					'pass' => 'm,p',
 				);
 
 				$product_url = $this->Application->HREF('__default__', '', $url_params);
 
 				$item_data = $items->GetDBField('ItemData');
 				$item_data = $item_data ? unserialize($item_data) : Array ();
 
 				$row_index = $items->GetDBField('ProductId') . ':' . $items->GetDBField('OptionsSalt') . ':' . $items->GetDBField('BackOrderFlag');
 
+				/** @var ImageHelper $image_helper */
 				$image_helper = $this->Application->recallObject('ImageHelper');
-				/* @var $image_helper ImageHelper */
 
 				// TODO: find a way to specify thumbnail size & default image
 
 				$ret['items'][$row_index] = Array (
 					'product_url' => $product_url,
 					'product_type' => $product->GetDBField('Type'),
 					'options' => isset($item_data['Options']) ? $item_data['Options'] : false,
 					'free_promo_shipping' => $this->eligibleForFreePromoShipping($items),
 
 					'fields' => Array (
 						'OrderItemId' => $items->GetDBField('OrderItemId'),
 						'ProductName' => $items->GetDBField('ProductName'),
 						'PrimaryImage' => $product->GetField('PrimaryImage', 'resize:58x58;default:img/no_picture.gif'),
 						'BackOrderFlag' => (int)$items->GetDBField('BackOrderFlag'),
 						'FlatPrice' => $this->convertCurrency($items->GetDBField('FlatPrice'), $currency),
 						'Price' => $this->convertCurrency($items->GetDBField('Price'), $currency),
 						'Quantity' => (int)$items->GetDBField('Quantity'),
 						'Virtual' => (int)$items->GetDBField('Virtual'),
 						'Type' => (int)$product->GetDBField('Type'),
 
 						'cust_Availability' => $product->GetDBField('cust_Availability'),
 					),
 				);
 
 				$items->GoNext();
 			}
 
 			if ( $remove_errors ) {
 				$this->Application->RemoveVar('checkout_errors');
 			}
 
 			return $ret;
 		}
 
 		function convertCurrency($amount, $currency)
 		{
+			/** @var CurrencyRates $converter */
 			$converter = $this->Application->recallObject('CurrencyRates');
-			/* @var $converter CurrencyRates */
 
 			// convert primary currency to selected (if they are the same, converter will just return)
 			return (float)$converter->Convert($amount, 'PRIMARY', $this->getISO($currency));
 		}
 
 		function getISO($currency)
 		{
 			if ($currency == 'selected') {
 				$iso = $this->Application->RecallVar('curr_iso');
 			}
 			elseif ($currency == 'primary' || $currency == '') {
 				$iso = $this->Application->GetPrimaryCurrency();
 			}
 			else { //explicit currency
 				$iso = strtoupper($currency);
 			}
 
 			return $iso;
 		}
 
 		/**
 		 * Checks, that given order item is eligible  for free promo shipping
 		 *
 		 * @param kDBItem|kDBList $order_item
 		 * @return bool
 		 */
 		function eligibleForFreePromoShipping(&$order_item)
 		{
 			if ( $order_item->GetDBField('Type') != PRODUCT_TYPE_TANGIBLE ) {
 				return false;
 			}
 
 			$free_shipping = $order_item->GetDBField('MinQtyFreePromoShipping');
 
 			return $free_shipping > 0 && $free_shipping <= $order_item->GetDBField('Quantity');
 		}
 
 		/**
 		 * Returns a template, that will be used to continue shopping from "shopping cart" template
 		 *
 		 * @param string $template
 		 * @return string
 		 * @access public
 		 */
 		public function getContinueShoppingTemplate($template = '')
 		{
 			if ( !$template || $template == '__default__' ) {
 				$template = $this->Application->RecallVar('continue_shopping');
 			}
 
 			if ( !$template ) {
 				$template = 'in-commerce/index';
 			}
 
 			return $template;
 		}
 
 		/**
 		 * Detects credit card type by it's number.
 		 *
 		 * @param string $number Credit card number.
 		 *
 		 * @return     integer
 		 * @deprecated
 		 */
 		public function getCreditCartType($number)
 		{
 			@trigger_error(
 				'Usage of deprecated method OrderHelper::getCreditCartType. Use OrderHelper::getCreditCardType.',
 				E_USER_DEPRECATED
 			);
 
 			return $this->getCreditCardType($number);
 		}
 
 		/**
 		 * Detects credit card type by it's number.
 		 *
 		 * @param string $number Credit card number.
 		 *
 		 * @return integer
 		 */
 		public function getCreditCardType($number)
 		{
 			// Get rid of any non-digits.
 			$number = preg_replace('/[^\d]/', '', $number);
 
 			$mapping = Array (
 				'/^4.{15}$|^4.{12}$/' => 1, // Visa
 				'/^5[1-5].{14}$/' => 2, // MasterCard
 				'/^3[47].{13}$/' => 3, // American Express
 				'/^6011.{12}$/' => 4, // Discover
 				'/^30[0-5].{11}$|^3[68].{12}$/' => 5, // Diners Club
 				'/^3.{15}$|^2131|1800.{11}$/' => 6, // JBC
 			);
 
 			foreach ($mapping as $number_regex => $card_type) {
 				if ( preg_match($number_regex, $number) ) {
 					return $card_type;
 				}
 			}
 
 			return false;
 		}
 
 		/**
 		 * Extracts fields, used to created user from order
 		 *
 		 * @param OrdersItem $order
 		 * @param string $field_prefix
 		 * @return Array
 		 * @access public
 		 */
 		public function getUserFields(&$order, $field_prefix = 'Billing')
 		{
 			$fields_hash = Array ();
 			$names = explode(' ', $order->GetDBField($field_prefix . 'To'), 2);
 
 			$fields_hash['FirstName'] = (string)getArrayValue($names, 0);
 			$fields_hash['LastName'] = (string)getArrayValue($names, 1);
 
 			$order_fields = Array (
 				'Company', 'Phone', 'Fax', 'Email', 'Address1' => 'Street',
 				'Address2' => 'Street2', 'City', 'State', 'Zip', 'Country'
 			);
 
 			foreach ($order_fields as $src_field => $dst_field) {
 				if ( is_numeric($src_field) ) {
 					$src_field = $dst_field;
 				}
 
 				$fields_hash[$dst_field] = $order->GetDBField($field_prefix . $src_field);
 			}
 
 			return $fields_hash;
 		}
 	}
Index: branches/5.2.x/units/helpers/ecb_currency_rates.php
===================================================================
--- branches/5.2.x/units/helpers/ecb_currency_rates.php	(revision 16515)
+++ branches/5.2.x/units/helpers/ecb_currency_rates.php	(revision 16516)
@@ -1,56 +1,56 @@
 RateSource = 'http://www.ecb.int/stats/eurofxref/eurofxref-daily.xml';
 
 		parent::__construct();
 	}
 
 	function GetRatesData()
 	{
 		$xml_parser = xml_parser_create();
 
+		/** @var kCurlHelper $curl_helper */
 		$curl_helper = $this->Application->recallObject('CurlHelper');
-		/* @var $curl_helper kCurlHelper */
 
 		$xml = $curl_helper->Send($this->RateSource);
 
 		xml_parse_into_struct($xml_parser, $xml, $struct, $index);
 		$data_res = Array();
 		foreach($struct as $element)
 		{
 			if(isset($element['attributes']) && isset($element['attributes']['CURRENCY']))
 			{
 				$currency = $element['attributes']['CURRENCY'];
 				$data_res[$currency]['ID'] = $currency;
 				$data_res[$currency]['TARGET'] = 'EUR';
 				$data_res[$currency]['UNITS'] = 1;
 				$data_res[$currency]['RATE'] = ($element['attributes']['RATE'] == 0) ? 0 : 1 / $element['attributes']['RATE'];
 			}
 		}
 		if(!$data_res['EUR'])
 		{
 			$data_res['EUR']['ID'] = 'EUR';
 			$data_res['EUR']['UNITS'] = 1;
 			$data_res['EUR']['TARGET'] = 'EUR';
 			$data_res['EUR']['RATE'] = 1;
 		}
 		$this->ExchangeRates = $data_res;
 	}
 }
Index: branches/5.2.x/units/helpers/bank_lv_currency_rates.php
===================================================================
--- branches/5.2.x/units/helpers/bank_lv_currency_rates.php	(revision 16515)
+++ branches/5.2.x/units/helpers/bank_lv_currency_rates.php	(revision 16516)
@@ -1,65 +1,65 @@
 RateSource = 'http://www.bank.lv/ValutuKursi/XML/xml.cfm';
 
 		parent::__construct();
 	}
 
 	function GetRatesData()
 	{
 		$xml_parser = xml_parser_create();
 
+		/** @var kCurlHelper $curl_helper */
 		$curl_helper = $this->Application->recallObject('CurlHelper');
-		/* @var $curl_helper kCurlHelper */
 
 		$xml = $curl_helper->Send($this->RateSource);
 
 		xml_parse_into_struct($xml_parser, $xml, $struct, $index);
 		$data_res = Array();
 		$currency = '';
 		foreach($struct as $element)
 		{
 			switch($element['tag'])
 			{
 				case 'ID':
 					$currency = $element['value'];
 					$data_res[$currency]['ID'] = $currency;
 					$data_res[$currency]['TARGET'] = 'LVL';
 				break;
 				case 'UNITS':
 					$data_res[$currency]['UNITS'] = $element['value'];
 				break;
 				case 'RATE':
 					$data_res[$currency]['RATE'] = $element['value'];
 				break;
 				default:
 			}
 		}
 
 		if(!$data_res['LVL'])
 		{
 			$data_res['LVL']['ID'] = 'LVL';
 			$data_res['LVL']['UNITS'] = 1;
 			$data_res['LVL']['TARGET'] = 'LVL';
 			$data_res['LVL']['RATE'] = 1;
 		}
 		$this->ExchangeRates = $data_res;
 	}
 }
Index: branches/5.2.x/units/helpers/frny_currency_rates.php
===================================================================
--- branches/5.2.x/units/helpers/frny_currency_rates.php	(revision 16515)
+++ branches/5.2.x/units/helpers/frny_currency_rates.php	(revision 16516)
@@ -1,86 +1,86 @@
 RateSource = 'http://www.ny.frb.org/markets/fxrates/FXtoXML.cfm?FEXdate=%s&FEXtime=1200';
 
 		parent::__construct();
 	}
 
 	function GetRatesData()
 	{
+		/** @var kCurlHelper $curl_helper */
 		$curl_helper = $this->Application->recallObject('CurlHelper');
-		/* @var $curl_helper kCurlHelper */
 
 		for($i = 0; $i < 10; $i++)
 		{
 			$time = adodb_mktime() - $i * 3600 * 24;
 			$source_file = sprintf($this->RateSource, adodb_date('Y-m-d', $time));
 			$xml = $curl_helper->Send($source_file);
 
 			$xml_parser = xml_parser_create();
 			xml_parse_into_struct($xml_parser, $xml, $struct, $index);
 			foreach($struct as $element)
 			{
 				if($element['tag'] == 'FRBNY:DATASET')
 				{
 					break;
 				}
 			}
 			if($element['type'] == 'open')
 			{
 				break;
 			}
 		}
 		if($element['type'] != 'open')
 		{
 			return false;
 		}
 
 		foreach($struct as $element)
 		{
 			switch($element['tag'])
 			{
 				case 'FRBNY:SERIES':
 					$currency = $element['attributes']['UNIT'];
 					if($currency)
 					{
 						$data_res[$currency]['ID'] = $currency;
 						$data_res[$currency]['UNITS'] = 1;
 					}
 				break;
 				case 'FRBNY:CURR':
 					$data_res[$currency]['TARGET'] = $element['value'];
 				break;
 				case 'FRBNY:OBS_VALUE':
 					$data_res[$currency]['RATE'] = ($element['value'] == 0) ? 0 : 1 / $element['value'];
 				break;
 				default:
 			}
 		}
 		if(!$data_res['USD'])
 		{
 			$data_res['USD']['ID'] = 'USD';
 			$data_res['USD']['UNITS'] = 1;
 			$data_res['USD']['TARGET'] = 'USD';
 			$data_res['USD']['RATE'] = 1;
 		}
 		$this->ExchangeRates = $data_res;
 	}
 
 }
Index: branches/5.2.x/units/helpers/currency_rates.php
===================================================================
--- branches/5.2.x/units/helpers/currency_rates.php	(revision 16515)
+++ branches/5.2.x/units/helpers/currency_rates.php	(revision 16516)
@@ -1,153 +1,153 @@
 GetRatesData();
 	}
 
 	function GetRatesData()
 	{
 		$cache_key = 'currency_rates[%CurrSerial%]';
 		$rates = $this->Application->getCache($cache_key);
 		$primary = $this->Application->GetPrimaryCurrency();
 
 		if ($rates === false) {
 			$this->Conn->nextQueryCachable = true;
 			$sql = 'SELECT ISO, RateToPrimary
 					FROM ' . $this->Application->getUnitOption('curr', 'TableName') . '
 					WHERE Status = ' . STATUS_ACTIVE;
 			$rates = $this->Conn->Query($sql);
 
 			$this->Application->setCache($cache_key, $rates);
 		}
 
 		foreach ($rates as $rate) {
 			$this->SetRate($primary, $rate['ISO'], $rate['RateToPrimary']);
 		}
 	}
 
 	function GetRate($source_cur, $target_cur, $units = 1)
 	{
 		$source_cur = ($source_cur == 'PRIMARY') ? $this->Application->GetPrimaryCurrency() : $source_cur;
 		$target_cur = ($target_cur == 'PRIMARY') ? $this->Application->GetPrimaryCurrency() : $target_cur;
 		if($source_cur == $target_cur)
 		{
 			return 1;
 		}
 
 		if($this->ExchangeRates[$target_cur]['TARGET'] == $source_cur)
 		{
 			$rate = ($this->ExchangeRates[$target_cur]['RATE'] ==  0) ? false : 1 / $this->ExchangeRates[$target_cur]['RATE'];
 		}
 		elseif($this->ExchangeRates[$source_cur]['TARGET'] == $target_cur)
 		{
 			$rate = $this->ExchangeRates[$source_cur]['RATE'];
 		}
 		else
 		{
 			$rate = ($this->ExchangeRates[$target_cur]['RATE'] == 0) ? false : $this->ExchangeRates[$source_cur]['RATE'] / $this->ExchangeRates[$target_cur]['RATE'];
 		}
 		$rate *= $units;
 		return $rate;
 	}
 
 	function Convert($amount, $source_cur, $target_cur)
 	{
 		return $amount * $this->GetRate($source_cur, $target_cur);
 	}
 
 	function AddCurrencySymbol($value, $iso, $decimal_tag = '')
 	{
 		static $decimal_separator = false;
 
 		$cache_key = 'iso_masks[%CurrSerial%]';
 		$iso_masks = $this->Application->getCache($cache_key);
 
 		if ( $iso_masks === false ) {
 			$this->Conn->nextQueryCachable = true;
 			$symbol_sql = 'IF(COALESCE(Symbol, "") = "", CONCAT(ISO, " "), Symbol)';
 
 			$sql = 'SELECT IF(SymbolPosition = 0, CONCAT(' . $symbol_sql . ', "%s"), CONCAT("%s", ' . $symbol_sql . ')), LOWER(ISO) AS ISO
 					FROM ' . $this->Application->getUnitOption('curr', 'TableName') . '
 					WHERE Status = ' . STATUS_ACTIVE;
 			$iso_masks = $this->Conn->GetCol($sql, 'ISO');
 			$this->Application->setCache($cache_key, $iso_masks);
 		}
 
 		if ( $decimal_tag ) {
 			if ( $decimal_separator === false ) {
+				/** @var LanguagesItem $language */
 				$language = $this->Application->recallObject('lang.current');
-				/* @var $language LanguagesItem */
 
 				$decimal_separator = $language->GetDBField('DecimalPoint');
 			}
 
 			list ($integer_part, $decimal_part) = explode($decimal_separator, $value);
 			$value = $integer_part . $decimal_separator . '<' . $decimal_tag . '>' . $decimal_part . '';
 		}
 
 		$iso = strtolower($iso);
 
 		return array_key_exists($iso, $iso_masks) ? sprintf($iso_masks[$iso], $value) : $value;
 	}
 
 	function SetRate($source_cur, $target_cur, $rate, $units = 1)
 	{
 		$this->ExchangeRates[$target_cur]['TARGET']	= $source_cur;
 		$this->ExchangeRates[$target_cur]['ID']		= $target_cur;
 		$this->ExchangeRates[$target_cur]['RATE']	= $rate;
 		$this->ExchangeRates[$target_cur]['UNITS']	= $units;
 	}
 
 	function StoreRates($currencies=null)
 	{
+		/** @var kDBItem $curr_object */
 		$curr_object = $this->Application->recallObject('curr', null, Array ('skip_autoload' => true));
-		/* @var $curr_object kDBItem */
 
 		if ($currencies) {
 			if (!is_array($currencies)) {
 				$currencies = explode(',', $currencies);
 			}
 		}
 		else {
 			$currencies = array_keys($this->ExchangeRates);
 		}
 
 		foreach ($currencies as $id) {
 			$rate = $this->GetRate($id, 'PRIMARY');
 			if ($rate) {
 				$curr_object->Clear();
 				$curr_object->Load($id, 'ISO');
 				$curr_object->SetDBField('RateToPrimary', $rate);
 				$curr_object->SetDBField('Modified_date', adodb_mktime());
 				$curr_object->SetDBField('Modified_time', adodb_mktime());
 				$curr_object->Update();
 			}
 		}
 	}
 }
Index: branches/5.2.x/units/files/files_event_handler.php
===================================================================
--- branches/5.2.x/units/files/files_event_handler.php	(revision 16515)
+++ branches/5.2.x/units/files/files_event_handler.php	(revision 16516)
@@ -1,188 +1,188 @@
 Special == 'downl' ) {
 			return '';
 		}
 
 		return parent::getMainSpecial($event);
 	}
 
 	/**
 	 * Apply any custom changes to list's sql query
 	 *
 	 * @param kEvent $event
 	 * @return void
 	 * @access protected
 	 * @see kDBEventHandler::OnListBuild()
 	 */
 	protected function SetCustomQuery(kEvent $event)
 	{
 		parent::SetCustomQuery($event);
 
+		/** @var kDBList $object */
 		$object = $event->getObject();
-		/* @var $object kDBList */
 
 		switch ($event->Special) {
 			case 'downl':
 				$object->addFilter('is_active', '%1$s.Status = 1');
 				break;
 		}
 	}
 
 	/**
 	 * Occurs before updating item
 	 *
 	 * @param kEvent $event
 	 * @return void
 	 * @access protected
 	 */
 	protected function OnBeforeItemUpdate(kEvent $event)
 	{
 		parent::OnBeforeItemUpdate($event);
 
 		$this->itemChanged($event);
 	}
 
 	/**
 	 * Occurs before creating item
 	 *
 	 * @param kEvent $event
 	 * @return void
 	 * @access protected
 	 */
 	protected function OnBeforeItemCreate(kEvent $event)
 	{
 		parent::OnBeforeItemCreate($event);
 
 		$this->itemChanged($event);
 
+		/** @var kDBItem $object */
 		$object = $event->getObject();
-		/* @var $object kDBItem */
 
 		$parent_info = $object->getLinkedInfo($event->Special);
 
 		$sql = 'SELECT FileId
 				FROM ' . $object->TableName . '
 				WHERE IsPrimary = 1 AND ' . $parent_info['ForeignKey'] . ' = ' . $parent_info['ParentId'];
 		$file_id = $this->Conn->GetOne($sql);
 
 		if ( !$file_id ) {
 			$object->SetDBField('IsPrimary', 1);
 			$object->SetDBField('Status', 1);
 		}
 
 		$object->SetDBField('AddedById', $this->Application->RecallVar('user_id'));
 	}
 
 	/**
 	 * Occurs before item is changed
 	 *
 	 * @param kEvent $event
 	 */
 	function itemChanged($event)
 	{
+		/** @var kDBItem $object */
 		$object = $event->getObject();
-		/* @var $object kDBItem */
 
 		if ( $object->GetDBField('IsPrimary') ) {
 			$parent_info = $object->getLinkedInfo($event->Special);
 
 			$sql = 'UPDATE ' . $object->TableName . '
 					SET IsPrimary = 0
 					WHERE ' . $parent_info['ForeignKey'] . ' = ' . $parent_info['ParentId'];
 			$this->Conn->Query($sql);
 
 			$object->SetDBField('Status', 1);
 		}
 
 		if ( $object->GetDBField('Name') == '' ) {
 			$object->SetDBField('Name', $object->GetDBField('FilePath'));
 		}
 	}
 
 	/**
 	 * Enter description here...
 	 *
 	 * @param kEvent $event
 	 */
 	function OnSetPrimary($event)
 	{
 		$ids = $this->StoreSelectedIDs($event);
 		$id = array_shift($ids);
 
+		/** @var kDBItem $object */
 		$object = $event->getObject( Array('skip_autoload' => true) );
-		/* @var $object kDBItem */
 
 		$object->Load($id);
 
 		$object->SetDBField('IsPrimary', 1);
 		$object->Update();
 	}
 
 	/**
 	 * Don't allow to delete primary product file, when there are no more files
 	 *
 	 * @param kEvent $event
 	 * @param string $type
 	 * @return void
 	 * @access protected
 	 */
 	protected function customProcessing(kEvent $event, $type)
 	{
 		if ( $event->Name == 'OnMassDelete' && $type == 'before' ) {
 			$ids = $event->getEventParam('ids');
 
+			/** @var kDBItem $object */
 			$object = $event->getObject();
-			/* @var $object kDBItem */
 
 			$parent_info = $object->getLinkedInfo($event->Special);
 
 			$sql = 'SELECT FileId
 					FROM ' . $object->TableName . '
 					WHERE IsPrimary = 1 AND ' . $parent_info['ForeignKey'] . ' = ' . $parent_info['ParentId'];
 			$primary_file_id = $this->Conn->GetOne($sql);
 
 			if ( $primary_file_id ) {
 				$file_id_index = array_search($primary_file_id, $ids);
 
 				if ( $file_id_index ) {
 					// allow deleting of primary product file, when there is another file to make primary
 					$sql = 'SELECT COUNT(*)
 							FROM ' . $object->TableName . '
 							WHERE IsPrimary = 0 AND ' . $parent_info['ForeignKey'] . ' = ' . $parent_info['ParentId'];
 					$non_primary_file_count = $this->Conn->GetOne($sql);
 
 					if ( $non_primary_file_count ) {
 						unset($ids[$file_id_index]);
 					}
 				}
 			}
 
 			$event->setEventParam('ids', $ids);
 		}
 	}
 }
\ No newline at end of file
Index: branches/5.2.x/units/affiliate_payments/affiliate_payments_event_handler.php
===================================================================
--- branches/5.2.x/units/affiliate_payments/affiliate_payments_event_handler.php	(revision 16515)
+++ branches/5.2.x/units/affiliate_payments/affiliate_payments_event_handler.php	(revision 16516)
@@ -1,138 +1,138 @@
 Special == 'log' ) {
 				return ;
 			}
 
 			$parent_info = $object->getLinkedInfo();
 
+			/** @var kDBItem $parent_object */
 			$parent_object = $this->Application->recallObject($parent_info['ParentPrefix']);
-			/* @var $parent_object kDBItem */
 
 			$options = $object->GetFieldOptions('PaymentTypeId');
 
 			if ( $parent_object->isLoaded() ) {
 				$options['default'] = $parent_object->GetDBField('PaymentTypeId');
 				$object->SetDBField('PaymentTypeId', $parent_object->GetDBField('PaymentTypeId'));
 			}
 
 			if ( $this->Application->GetVar($event->getPrefixSpecial() . '_event') != 'OnNew' && $this->Application->GetVar($event->getPrefixSpecial() . '_event') != 'OnCreate' ) {
 				$options['options'][0] = '';
 			}
 
 			$object->setFieldOptions('PaymentTypeId', $options);
 		}
 
 		/**
 		 * Set's fields based on affiliate currently being edited
 		 *
 		 * @param kEvent $event
 		 * @return void
 		 * @access protected
 		 */
 		protected function OnNew(kEvent $event)
 		{
 			parent::OnNew($event);
 
+			/** @var kDBItem $affiliate */
 			$affiliate = $this->Application->recallObject('affil');
-			/* @var $affiliate kDBItem */
 
+			/** @var kDBItem $object */
 			$object = $event->getObject(Array ('skip_autoload' => true));
-			/* @var $object kDBItem */
 
 			$object->SetDBField('Amount', $affiliate->GetDBField('AmountToPay'));
 			$object->SetDBField('AffiliateId', $affiliate->GetID());
 		}
 
 		/**
 		 * Updates Affiliate Record On Successfully payment creation
 		 *
 		 * @param kEvent $event
 		 * @return void
 		 * @access protected
 		 */
 		protected function OnAfterItemCreate(kEvent $event)
 		{
 			parent::OnAfterItemCreate($event);
 
+			/** @var kDBItem $object */
 			$object = $event->getObject();
-			/* @var $object kDBItem */
 
 			$parent_info = $object->getLinkedInfo();
 
 			$sql = 'SELECT MAX(PaymentDate)
 					FROM ' . $object->TableName . '
 					WHERE ' . $parent_info['ParentTableKey'] . ' = ' . $parent_info['ParentId'];
 			$payment_date = $this->Conn->GetOne($sql);
 
+			/** @var kDBItem $affiliate */
 			$affiliate = $this->Application->recallObject('affil');
-			/* @var $affiliate kDBItem */
 
 			$affiliate->SetDBField('AmountToPay', $affiliate->GetDBField('AmountToPay') - $object->GetDBField('Amount'));
 			$affiliate->SetDBField('LastPaymentDate_date', $payment_date);
 			$affiliate->SetDBField('LastPaymentDate_time', $payment_date);
 			$affiliate->Update();
 		}
 
 		/**
 		 * Apply any custom changes to list's sql query
 		 *
 		 * @param kEvent $event
 		 * @return void
 		 * @access protected
 		 * @see kDBEventHandler::OnListBuild()
 		 */
 		protected function SetCustomQuery(kEvent $event)
 		{
 			parent::SetCustomQuery($event);
 
+			/** @var kDBList $object */
 			$object = $event->getObject();
-			/* @var $object kDBList */
 
 			if ( $event->Special == 'log' ) {
 				$object->removeFilter('parent_filter');
 			}
 
 			$types = $event->getEventParam('types');
 			if ( $types == 'my_payments' ) {
 				$user_id = $this->Application->RecallVar('user_id');
 				$object->removeFilter('parent_filter');
 				$object->addFilter('my_payments', 'au.PortalUserId = ' . $user_id);
 			}
 
 			if ( $types == 'myvisitororders' ) {
 				$user_id = $this->Application->RecallVar('user_id');
 				$object->addFilter('myitems_orders', 'ord.OrderId IS NOT NULL');
 				$object->addFilter('myitems_user1', 'au.PortalUserId = ' . $user_id);
 				$object->addFilter('myitems_user2', 'au.PortalUserId > 0');
 			}
 		}
 
 	}
\ No newline at end of file
Index: branches/5.2.x/units/destinations/dst_event_handler.php
===================================================================
--- branches/5.2.x/units/destinations/dst_event_handler.php	(revision 16515)
+++ branches/5.2.x/units/destinations/dst_event_handler.php	(revision 16516)
@@ -1,136 +1,136 @@
 getObject(Array ('skip_autoload' => true));
-		/* @var $object kDBItem */
 
 		// creates multiple db records from single request (OnCreate event only creates 1 record)
 		$items_info = $this->Application->GetVar($event->getPrefixSpecial(true));
 
 		if ( !$items_info ) {
 			return;
 		}
 
 		foreach ($items_info as $field_values) {
 			$object->setID(0);
 			$object->SetFieldsFromHash($field_values);
 			$event->setEventParam('form_data', $field_values);
 			$this->customProcessing($event, 'before');
 
 			if ( $object->Create() ) {
 				$this->customProcessing($event, 'after');
 				$event->status = kEvent::erSUCCESS;
 			}
 			else {
 				$event->status = kEvent::erFAIL;
 				$event->redirect = false;
 				$this->Application->SetVar($event->getPrefixSpecial() . '_SaveEvent', 'OnCreate');
 				$object->setID(0);
 			}
 		}
 	}
 
 	/**
 	 * Apply custom processing to item
 	 *
 	 * @param kEvent $event
 	 * @param string $type
 	 * @return void
 	 * @access protected
 	 */
 	protected function customProcessing(kEvent $event, $type)
 	{
 		if ( $type != 'before' ) {
 			return;
 		}
 
+		/** @var kDBItem $object */
 		$object = $event->getObject();
-		/* @var $object kDBItem */
 
 		$events = $this->Application->GetVar('events');
 
 		if ( $events['z'] == 'OnUpdate' ) {
 			$object->SetDBField('ShippingZoneId', $this->Application->GetVar('z_id'));
 		}
 
+		/** @var kDBItem $zone_object */
 		$zone_object = $this->Application->recallObject('z');
-		/* @var $zone_object kDBItem */
 
 		if ( $zone_object->GetDBField('Type') == 3 ) {
 			$object->SetDBField('StdDestId', $this->Application->GetVar('ZIPCountry'));
 		}
 	}
 
 	 /**
 	 *
 	 *
 	 * @param kEvent $event
 	 */
 	function OnZoneUpdate($event) {
 
+		/** @var kDBItem $object */
 		$object = $event->getObject();
-		/* @var $object kDBItem */
 
+		/** @var kDBItem $zone_object */
 		$zone_object = $this->Application->recallObject('z');
-		/* @var $zone_object kDBItem */
 
 		$zone_id = (int)$zone_object->GetID();
 		$zone_type = $zone_object->GetDBField('Type');
 
 		$delete_zones_sql = 'DELETE FROM '.$object->TableName.' WHERE ShippingZoneId = '.$zone_id;
 		$this->Conn->Query($delete_zones_sql);
 
 		if ($zone_id != 0){
 			$delete_zones_sql = 'DELETE FROM '.$object->TableName.' WHERE ShippingZoneId = 0';
 			$this->Conn->Query($delete_zones_sql);
 		}
 
 		$selected_destinations = $this->Application->GetVar('selected_destinations');
 		$selected_destinations_array = explode(',', $selected_destinations);
 		$selected_destinations_array = array_unique($selected_destinations_array);
 		foreach ($selected_destinations_array as $key => $dest_id) {
 
 					if ($zone_object->GetDBField('Type') == 3){
 						list ($zone_dest_id, $dest_value) = explode('|', $dest_id);
 						$dest_id = $this->Application->GetVar('CountrySelector');
 					}
 					else {
 						$dest_value = '';
 					}
 
 					if ($dest_id > 0){
 						$object->SetDBField('ShippingZoneId', $zone_id);
 						$object->SetDBField('StdDestId', $dest_id);
 						$object->SetDBField('DestValue', $dest_value);
 						$object->Create();
 					}
 
 		}
 
 
 	}
 
 }
Index: branches/5.2.x/units/affiliate_payment_types/affiliate_payment_types_event_handler.php
===================================================================
--- branches/5.2.x/units/affiliate_payment_types/affiliate_payment_types_event_handler.php	(revision 16515)
+++ branches/5.2.x/units/affiliate_payment_types/affiliate_payment_types_event_handler.php	(revision 16516)
@@ -1,123 +1,123 @@
 Application->isAdmin ) {
+				/** @var kDBList $object */
 				$object = $event->getObject();
-				/* @var $object kDBList */
 
 				$object->addFilter('active', '%1$s.Status = ' . STATUS_ACTIVE);
 			}
 		}
 
 		/**
 		 * Enter description here...
 		 *
 		 * @param kEvent $event
 		 */
 		function OnSetPrimary($event)
 		{
+			/** @var kDBItem $object */
 			$object = $event->getObject();
-			/* @var $object kDBItem */
 
 			$object->SetDBField('IsPrimary', 1);
 			$object->Update();
 		}
 
 
 		/**
 		 * Ensures, that user have only one "use as billing" / "use as shipping" address
 		 *
 		 * @param kEvent $event
 		 * @return void
 		 * @access protected
 		 */
 		protected function OnBeforeItemUpdate(kEvent $event)
 		{
 			parent::OnBeforeItemUpdate($event);
 
 			$this->itemChanged($event);
 		}
 
 		/**
 		 * Occurs before creating item
 		 *
 		 * @param kEvent $event
 		 * @return void
 		 * @access protected
 		 */
 		protected function OnBeforeItemCreate(kEvent $event)
 		{
 			parent::OnBeforeItemCreate($event);
 
 			$this->itemChanged($event);
 		}
 
 		/**
 		 * Occurs before item is changed
 		 *
 		 * @param kEvent $event
 		 */
 		function itemChanged($event)
 		{
+			/** @var kDBItem $object */
 			$object = $event->getObject();
-			/* @var $object kDBItem */
 
 			if ( $object->GetDBField('IsPrimary') && $object->Validate() ) {
 				$sql = 'UPDATE ' . $this->Application->getUnitOption($event->Prefix, 'TableName') . '
 						SET IsPrimary = 0';
 				$this->Conn->Query($sql);
 
 				$object->SetDBField($object->getStatusField(), 1);
 			}
 		}
 
 		/**
 		 * Don't allow to delete primary affiliate payment type
 		 *
 		 * @param kEvent $event
 		 * @param string $type
 		 * @return void
 		 * @access protected
 		 */
 		protected function customProcessing(kEvent $event, $type)
 		{
 			if ( $event->Name == 'OnMassDelete' && $type == 'before' ) {
 				$ids = $event->getEventParam('ids');
 
 				$sql = 'SELECT ' . $this->Application->getUnitOption($event->Prefix, 'IDField') . '
 						FROM ' . $this->Application->getUnitOption($event->Prefix, 'TableName') . '
 						WHERE IsPrimary = 1';
 				$primary_id = $this->Conn->GetOne($sql);
 
 				$ids = array_diff($ids, Array ($primary_id));
 
 				$event->setEventParam('ids', $ids);
 			}
 		}
 	}
\ No newline at end of file
Index: branches/5.2.x/units/affiliate_payment_types/affiliate_payment_types_tp.php
===================================================================
--- branches/5.2.x/units/affiliate_payment_types/affiliate_payment_types_tp.php	(revision 16515)
+++ branches/5.2.x/units/affiliate_payment_types/affiliate_payment_types_tp.php	(revision 16516)
@@ -1,51 +1,51 @@
 Application->recallObject( $params['prefix'] );
-		/* @var $affiliate kDBItem */
 
 		$payment_type = $affiliate->GetDBField( $params['field'] );
 
 		if ( $payment_type ) {
+			/** @var kDBList $object */
 			$object = $this->getObject($params);
-			/* @var $object kDBList */
 
 			return $payment_type == $object->GetID();
 		}
 
 		if ( !$checked ) {
 			// make first listed affiliate payment type selected
 			$checked = true;
 
 			return true;
 		}
 
 		return false;
 	}
 }
\ No newline at end of file
Index: branches/5.2.x/units/shipping_quote_engines/usps.php
===================================================================
--- branches/5.2.x/units/shipping_quote_engines/usps.php	(revision 16515)
+++ branches/5.2.x/units/shipping_quote_engines/usps.php	(revision 16516)
@@ -1,1339 +1,1341 @@
 HERE for registration details. USPS expects you to use pounds as weight measure for your products.');
 define('MODULE_SHIPPING_USPS_TEXT_ERROR', 'An error occured with the USPS shipping calculations.
If you prefer to use USPS as your shipping method, please contact the store owner.'); define('MODULE_SHIPPING_USPS_TEXT_DAY', 'Day'); define('MODULE_SHIPPING_USPS_TEXT_DAYS', 'Days'); define('MODULE_SHIPPING_USPS_TEXT_WEEKS', 'Weeks'); define('MODULE_SHIPPING_USPS_STATUS', 'True'); // Do you want to offer USPS shipping? define('MODULE_SHIPPING_USPS_SERVER', 'production'); // An account at USPS is needed to use the Production server // production othervise value may be 'test' define('MODULE_SHIPPING_USPS_HANDLING', '0'); // Handling fee for this shipping method define('MODULE_SHIPPING_USPS_TAX_CLASS', '0'); // Use the following tax class on the shipping fee define('MODULE_SHIPPING_USPS_ZONE', '0'); // If a zone is selected, only enable this shipping method for that zone. define('MODULE_SHIPPING_USPS_SORT_ORDER', '0'); // Sort order of display. define('MODULE_SHIPPING_USPS_TYPES', 'PRIORITY, PARCEL'); // EXPRESS, FIRST CLASS, BMP, MEDIA 'Select the domestic services to be offered: define('MODULE_SHIPPING_USPS_TYPES_INTL', 'EXPRESS MAIL INTERNATIONAL (EMS), EXPRESS MAIL INT, EXPRESS MAIL INT FLAT RATE ENV, PRIORITY MAIL INT, PRIORITY MAIL INT FLAT RATE ENV, PRIORITY MAILINT FLAT RATE BOX, FIRST-CLASS MAIL INT');// 'GLOBAL EXPRESS, GLOBAL EXPRESS NON-DOC RECT, GLOBAL EXPRESS NON-DOC NON-RECT, Select the international services to be offered: define('MODULE_SHIPPING_USPS_OPTIONS', 'Display weight, Display transit time'); // //configuration values for insurance define('MODULE_SHIPPING_USPS_INS1', '1.65');// 'US/Canada insurance for totals $.01-$50.00 define('MODULE_SHIPPING_USPS_INS2', '2.05');// 'US/Canada insurance for totals $50.01-$100 define('MODULE_SHIPPING_USPS_INS3', '2.45');// 'US/Canada insurance for totals $100.01-$200 define('MODULE_SHIPPING_USPS_INS4', '4.60');// 'US/Canada insurance for totals $200.01-$300 define('MODULE_SHIPPING_USPS_INS5', '.90');// 'US/Canada insurance for every $100 over $300 (add) define('MODULE_SHIPPING_USPS_INS6', '2.40');// 'International insurance for totals $.01-$50.00 define('MODULE_SHIPPING_USPS_INS7', '3.30');// 'International insurance for totals $50.01-$100 define('MODULE_SHIPPING_USPS_INS8', '4.20');// 'International insurance for totals $100.01-$200 define('MODULE_SHIPPING_USPS_INS9', '5.10');// 'International insurance for totals $200.01-$300 define('MODULE_SHIPPING_USPS_INS10', '.90');// 'International insurance for every $100 over $300 (add) define('MODULE_SHIPPING_USPS_INSURE', 'True');// 'Insure packages shipped by USPS? define('MODULE_SHIPPING_USPS_INSURE_TAX', 'True');// 'Insure tax on packages shipped by USPS? class USPS extends ShippingQuoteEngine { var $countries, $pounds, $ounces, $insurance_cost = 0, $shipping_origin_country, $store_first_name, $store_last_name, $company_name, $store_name, $store_address1, $store_address2, $store_city, $store_state, $store_zip5, $store_zip4, $store_phone, $usps_userid; var $order = Array(); var $types = Array(); var $intl_types = Array(); /** * Path to a request log file * * @var string */ var $logFilePath = ''; /** * Creates USPS processing class * */ public function __construct() { parent::__construct(); $this->logFilePath = (defined('RESTRICTED') ? RESTRICTED : WRITEABLE . '/user_files') . '/usps.log'; // EXPRESS, FIRST CLASS, PRIORITY, PARCEL, BMP, MEDIA $this->types = Array( 'EXPRESS' => 'Express Mail', 'FIRST CLASS' => 'First Class Mail', 'PRIORITY' => 'Priority Mail', 'PARCEL' => 'Parcel Post', 'BPM' => 'Bound Printed Matter', 'MEDIA' => 'Media Mail' ); $this->intl_types = Array( // 'GLOBAL EXPRESS' => 'Global Express Guaranteed', // 'GLOBAL EXPRESS NON-DOC RECT' => 'Global Express Guaranteed Non-Document Rectangular', // 'GLOBAL EXPRESS NON-DOC NON-RECT' => 'Global Express Guaranteed Non-Document Non-Rectangular', 'EXPRESS MAIL INT' => 'Express Mail International (EMS)', 'EXPRESS MAIL INT FLAT RATE ENV' => 'Express Mail International (EMS) Flat Rate Envelope', 'PRIORITY MAIL INT' => 'Priority Mail International', 'PRIORITY MAIL INT FLAT RATE ENV' => 'Priority Mail International Flat Rate Envelope', 'PRIORITY MAIL INT FLAT RATE BOX' => 'Priority Mail International Flat Rate Box', 'FIRST-CLASS MAIL INT' => 'First-Class Mail International' ); // get 2-symbol country code $country = $this->Application->ConfigValue('Comm_Shipping_Country'); if ($country != '') { $this->shipping_origin_country = $this->GetUSPSCountry($country, ''); } $contact_name = trim($this->_prepare_xml_param($this->Application->ConfigValue('Comm_Contacts_Name'))); $split_pos = strpos($contact_name, ' '); if ($split_pos === false) { $this->store_first_name = $contact_name; $this->store_last_name = ''; } else { $this->store_first_name = substr($contact_name, 0, $split_pos); $this->store_last_name = trim(substr($contact_name, $split_pos)); } $this->company_name = $this->_prepare_xml_param($this->Application->ConfigValue('Comm_CompanyName')); $this->store_name = $this->_prepare_xml_param($this->Application->ConfigValue('Comm_StoreName')); $this->store_address1 = $this->_prepare_xml_param($this->Application->ConfigValue('Comm_Shipping_AddressLine1')); $this->store_address2 = $this->_prepare_xml_param($this->Application->ConfigValue('Comm_Shipping_AddressLine2')); if ($this->store_address2 == '') { $this->store_address2 = $this->store_address1; $this->store_address1 = ''; } $this->store_city = $this->_prepare_xml_param($this->Application->ConfigValue('Comm_Shipping_City')); $this->store_state = $this->_prepare_xml_param($this->Application->ConfigValue('Comm_Shipping_State')); $zip = $this->_prepare_xml_param($this->Application->ConfigValue('Comm_Shipping_ZIP')); $this->store_zip5 = substr($zip, 0, 5); $this->store_zip4 = trim(substr($zip, 6), '-'); $this->store_phone = $this->_prepare_xml_param($this->Application->ConfigValue('Comm_Contacts_Phone')); // get username and password fron config. $a_params = $this->LoadParams(); $this->usps_userid = $a_params['AccountLogin']; // Note by Erik: DO NOT CHANGE THIS ARRAY. It's values are sent to USPS service and any changes may impact class main functionality. $this->countries = array( 'AF' => 'Afghanistan', 'AL' => 'Albania', 'DZ' => 'Algeria', 'AD' => 'Andorra', 'AO' => 'Angola', 'AI' => 'Anguilla', 'AG' => 'Antigua and Barbuda', 'AR' => 'Argentina', 'AM' => 'Armenia', 'AW' => 'Aruba', 'AU' => 'Australia', 'AT' => 'Austria', 'AZ' => 'Azerbaijan', 'BS' => 'Bahamas', 'BH' => 'Bahrain', 'BD' => 'Bangladesh', 'BB' => 'Barbados', 'BY' => 'Belarus', 'BE' => 'Belgium', 'BZ' => 'Belize', 'BJ' => 'Benin', 'BM' => 'Bermuda', 'BT' => 'Bhutan', 'BO' => 'Bolivia', 'BA' => 'Bosnia-Herzegovina', 'BW' => 'Botswana', 'BR' => 'Brazil', 'VG' => 'British Virgin Islands', 'BN' => 'Brunei Darussalam', 'BG' => 'Bulgaria', 'BF' => 'Burkina Faso', 'MM' => 'Burma', 'BI' => 'Burundi', 'KH' => 'Cambodia', 'CM' => 'Cameroon', 'CA' => 'Canada', 'CV' => 'Cape Verde', 'KY' => 'Cayman Islands', 'CF' => 'Central African Republic', 'TD' => 'Chad', 'CL' => 'Chile', 'CN' => 'China', 'CX' => 'Christmas Island (Australia)', 'CC' => 'Cocos Island (Australia)', 'CO' => 'Colombia', 'KM' => 'Comoros', 'CG' => 'Congo (Brazzaville),Republic of the', 'ZR' => 'Congo, Democratic Republic of the', 'CK' => 'Cook Islands (New Zealand)', 'CR' => 'Costa Rica', 'CI' => 'Cote d\'Ivoire (Ivory Coast)', 'HR' => 'Croatia', 'CU' => 'Cuba', 'CY' => 'Cyprus', 'CZ' => 'Czech Republic', 'DK' => 'Denmark', 'DJ' => 'Djibouti', 'DM' => 'Dominica', 'DO' => 'Dominican Republic', 'TP' => 'East Timor (Indonesia)', 'EC' => 'Ecuador', 'EG' => 'Egypt', 'SV' => 'El Salvador', 'GQ' => 'Equatorial Guinea', 'ER' => 'Eritrea', 'EE' => 'Estonia', 'ET' => 'Ethiopia', 'FK' => 'Falkland Islands', 'FO' => 'Faroe Islands', 'FJ' => 'Fiji', 'FI' => 'Finland', 'FR' => 'France', 'GF' => 'French Guiana', 'PF' => 'French Polynesia', 'GA' => 'Gabon', 'GM' => 'Gambia', 'GE' => 'Georgia, Republic of', 'DE' => 'Germany', 'GH' => 'Ghana', 'GI' => 'Gibraltar', 'GB' => 'Great Britain and Northern Ireland', 'GR' => 'Greece', 'GL' => 'Greenland', 'GD' => 'Grenada', 'GP' => 'Guadeloupe', 'GT' => 'Guatemala', 'GN' => 'Guinea', 'GW' => 'Guinea-Bissau', 'GY' => 'Guyana', 'HT' => 'Haiti', 'HN' => 'Honduras', 'HK' => 'Hong Kong', 'HU' => 'Hungary', 'IS' => 'Iceland', 'IN' => 'India', 'ID' => 'Indonesia', 'IR' => 'Iran', 'IQ' => 'Iraq', 'IE' => 'Ireland', 'IL' => 'Israel', 'IT' => 'Italy', 'JM' => 'Jamaica', 'JP' => 'Japan', 'JO' => 'Jordan', 'KZ' => 'Kazakhstan', 'KE' => 'Kenya', 'KI' => 'Kiribati', 'KW' => 'Kuwait', 'KG' => 'Kyrgyzstan', 'LA' => 'Laos', 'LV' => 'Latvia', 'LB' => 'Lebanon', 'LS' => 'Lesotho', 'LR' => 'Liberia', 'LY' => 'Libya', 'LI' => 'Liechtenstein', 'LT' => 'Lithuania', 'LU' => 'Luxembourg', 'MO' => 'Macao', 'MK' => 'Macedonia, Republic of', 'MG' => 'Madagascar', 'MW' => 'Malawi', 'MY' => 'Malaysia', 'MV' => 'Maldives', 'ML' => 'Mali', 'MT' => 'Malta', 'MQ' => 'Martinique', 'MR' => 'Mauritania', 'MU' => 'Mauritius', 'YT' => 'Mayotte (France)', 'MX' => 'Mexico', 'MD' => 'Moldova', 'MC' => 'Monaco (France)', 'MN' => 'Mongolia', 'MS' => 'Montserrat', 'MA' => 'Morocco', 'MZ' => 'Mozambique', 'NA' => 'Namibia', 'NR' => 'Nauru', 'NP' => 'Nepal', 'NL' => 'Netherlands', 'AN' => 'Netherlands Antilles', 'NC' => 'New Caledonia', 'NZ' => 'New Zealand', 'NI' => 'Nicaragua', 'NE' => 'Niger', 'NG' => 'Nigeria', 'KP' => 'North Korea (Korea, Democratic People\'s Republic of)', 'NO' => 'Norway', 'OM' => 'Oman', 'PK' => 'Pakistan', 'PA' => 'Panama', 'PG' => 'Papua New Guinea', 'PY' => 'Paraguay', 'PE' => 'Peru', 'PH' => 'Philippines', 'PN' => 'Pitcairn Island', 'PL' => 'Poland', 'PT' => 'Portugal', 'QA' => 'Qatar', 'RE' => 'Reunion', 'RO' => 'Romania', 'RU' => 'Russia', 'RW' => 'Rwanda', 'SH' => 'Saint Helena', 'KN' => 'Saint Kitts (St. Christopher and Nevis)', 'LC' => 'Saint Lucia', 'PM' => 'Saint Pierre and Miquelon', 'VC' => 'Saint Vincent and the Grenadines', 'SM' => 'San Marino', 'ST' => 'Sao Tome and Principe', 'SA' => 'Saudi Arabia', 'SN' => 'Senegal', 'YU' => 'Serbia-Montenegro', 'SC' => 'Seychelles', 'SL' => 'Sierra Leone', 'SG' => 'Singapore', 'SK' => 'Slovak Republic', 'SI' => 'Slovenia', 'SB' => 'Solomon Islands', 'SO' => 'Somalia', 'ZA' => 'South Africa', 'GS' => 'South Georgia (Falkland Islands)', 'KR' => 'South Korea (Korea, Republic of)', 'ES' => 'Spain', 'LK' => 'Sri Lanka', 'SD' => 'Sudan', 'SR' => 'Suriname', 'SZ' => 'Swaziland', 'SE' => 'Sweden', 'CH' => 'Switzerland', 'SY' => 'Syrian Arab Republic', 'TW' => 'Taiwan', 'TJ' => 'Tajikistan', 'TZ' => 'Tanzania', 'TH' => 'Thailand', 'TG' => 'Togo', 'TK' => 'Tokelau (Union) Group (Western Samoa)', 'TO' => 'Tonga', 'TT' => 'Trinidad and Tobago', 'TN' => 'Tunisia', 'TR' => 'Turkey', 'TM' => 'Turkmenistan', 'TC' => 'Turks and Caicos Islands', 'TV' => 'Tuvalu', 'UG' => 'Uganda', 'UA' => 'Ukraine', 'AE' => 'United Arab Emirates', 'UY' => 'Uruguay', 'UZ' => 'Uzbekistan', 'VU' => 'Vanuatu', 'VA' => 'Vatican City', 'VE' => 'Venezuela', 'VN' => 'Vietnam', 'WF' => 'Wallis and Futuna Islands', 'WS' => 'Western Samoa', 'YE' => 'Yemen', 'ZM' => 'Zambia', 'ZW' => 'Zimbabwe' ); $this->countryinsure = array( 'AF' => 0, 'AL' => 0, 'DZ' => 2185, 'AD' => 5000, 'AO' => 0, 'AI' => 415, 'AG' => 60, 'AR' => 5000, 'AM' => 1350, 'AW' => 830, 'AU' => 3370, 'AT' => 5000, 'AZ' => 5000, 'BS' => 2795, 'BH' => 0, 'BD' => 5000, 'BB' => 220, 'BY' => 1323, 'BE' => 5000, 'BZ' => 1600, 'BJ' => 170, 'BM' => 440, 'BT' => 440, 'BO' => 0, 'BA' => 5000, 'BW' => 145, 'BR' => 5000, 'VG' => 165, 'BN' => 4405, 'BG' => 1030, 'BF' => 530, 'MM' => 4045, 'BI' => 790, 'KH' => 0, 'CM' => 5000, 'CA' => 675, 'CV' => 0, 'KY' => 0, 'CF' => 4405, 'TD' => 440, 'CL' => 0, 'CN' => 1130, 'CX' => 3370, 'CC' => 3370, 'CO' => 0, 'KM' => 690, 'CG' => 1685, 'ZR' => 0, 'CK' => 980, 'CR' => 0, 'CI' => 5000, 'HR' => 5000, 'CU' => 0, 'CY' => 5000, 'CZ' => 5000, 'DK' => 5000, 'DJ' => 880, 'DM' => 0, 'DO' => 0, 'TP' => 0, 'EC' => 0, 'EG' => 1685, 'SV' => 0, 'GQ' => 0, 'ER' => 0, 'EE' => 2020, 'ET' => 1000, 'FK' => 510, 'FO' => 5000, 'FJ' => 600, 'FI' => 5000, 'FR' => 5000, 'GF' => 5000, 'PF' => 1015, 'GA' => 485, 'GM' => 2575, 'GE' => 1350, 'DE' => 5000, 'GH' => 5000, 'GI' => 5000, 'GB' => 857, 'GR' => 5000, 'GL' => 5000, 'GD' => 350, 'GP' => 5000, 'GT' => 0, 'GN' => 875, 'GW' => 21, 'GY' => 10, 'HT' => 0, 'HN' => 0, 'HK' => 5000, 'HU' => 5000, 'IS' => 5000, 'IN' => 2265, 'ID' => 0, 'IR' => 0, 'IQ' => 0, 'IE' => 5000, 'IL' => 0, 'IT' => 5000, 'JM' => 0, 'JP' => 5000, 'JO' => 0, 'KZ' => 5000, 'KE' => 815, 'KI' => 0, 'KW' => 1765, 'KG' => 1350, 'LA' => 0, 'LV' => 1350, 'LB' => 440, 'LS' => 440, 'LR' => 440, 'LY' => 0, 'LI' => 5000, 'LT' => 5000, 'LU' => 5000, 'MO' => 4262, 'MK' => 2200, 'MG' => 675, 'MW' => 50, 'MY' => 1320, 'MV' => 0, 'ML' => 950, 'MT' => 5000, 'MQ' => 5000, 'MR' => 635, 'MU' => 270, 'YT' => 5000, 'MX' => 0, 'MD' => 1350, 'MC' => 5000, 'MN' => 440, 'MS' => 2200, 'MA' => 5000, 'MZ' => 0, 'NA' => 4405, 'NR' => 220, 'NP' => 0, 'NL' => 5000, 'AN' => 830, 'NC' => 1615, 'NZ' => 980, 'NI' => 440, 'NE' => 810, 'NG' => 205, 'KP' => 0, 'NO' => 0, 'OM' => 575, 'PK' => 270, 'PA' => 0, 'PG' => 445, 'PY' => 0, 'PE' => 0, 'PH' => 270, 'PN' => 0, 'PL' => 1350, 'PT' => 5000, 'QA' => 2515, 'RE' => 5000, 'RO' => 5000, 'RU' => 5000, 'RW' => 0, 'SH' => 170, 'KN' => 210, 'LC' => 400, 'PM' => 5000, 'VC' => 130, 'SM' => 5000, 'ST' => 440, 'SA' => 0, 'SN' => 865, 'YU' => 5000, 'SC' => 0, 'SL' => 0, 'SG' => 4580, 'SK' => 5000, 'SI' => 4400, 'SB' => 0, 'SO' => 440, 'ZA' => 1760, 'GS' => 510, 'KR' => 5000, 'ES' => 5000, 'LK' => 35, 'SD' => 0, 'SR' => 535, 'SZ' => 560, 'SE' => 5000, 'CH' => 5000, 'SY' => 3080, 'TW' => 1350, 'TJ' => 1350, 'TZ' => 230, 'TH' => 1350, 'TG' => 2190, 'TK' => 295, 'TO' => 515, 'TT' => 930, 'TN' => 2200, 'TR' => 880, 'TM' => 675, 'TC' => 0, 'TV' => 4715, 'UG' => 0, 'UA' => 5000, 'AE' => 5000, 'UY' => 0, 'UZ' => 5000, 'VU' => 0, 'VA' => 5000, 'VE' => 0, 'VN' => 0, 'WF' => 1615, 'WS' => 295, 'YE' => 0, 'ZM' => 540, 'ZW' => 600, 'US' => 5000 ); } function SetInsurance() { $this->insurance_cost = 0; // Insurance module by Kevin Shelton // divide the value of the order among the packages based on the order total or subtotal depending on whether or not you have configured to insure tax $shipping_weight = $this->order['ShippingWeight']; $shipping_num_boxes = $this->order['ShippingNumBoxes']; $costperpkg = $this->order['SubTotal'] / $shipping_num_boxes; // retrieve the maximum allowed insurance for the destination country and if the package value exceeds it then set package value to the maximum allowed $maxins = $this->countryinsure[$this->order['ShippingCountry']]; if ($costperpkg > $maxins) $costperpkg = $maxins; // if insurance not allowed for destination or insurance is turned off add nothing to shipping cost if (($maxins == 0) || (MODULE_SHIPPING_USPS_INSURE == 'False')) { $insurance = 0; } // US and Canada share the same insurance calculation (though not the same maximum) else if (($this->order['ShippingCountry'] == 'US') || ($this->order['ShippingCountry'] == 'CA')) { if ($costperpkg<=50) { $insurance=MODULE_SHIPPING_USPS_INS1; } else if ($costperpkg<=100) { $insurance=MODULE_SHIPPING_USPS_INS2; } else if ($costperpkg<=200) { $insurance=MODULE_SHIPPING_USPS_INS3; } else if ($costperpkg<=300) { $insurance=MODULE_SHIPPING_USPS_INS4; } else { $insurance = MODULE_SHIPPING_USPS_INS4 + ((ceil($costperpkg/100) -3) * MODULE_SHIPPING_USPS_INS5); } } // if insurance allowed and is not US or Canada then calculate international insurance else { if ($costperpkg<=50) { $insurance=MODULE_SHIPPING_USPS_INS6; } else if ($costperpkg<=100) { $insurance=MODULE_SHIPPING_USPS_INS7; } else if ($costperpkg<=200) { $insurance=MODULE_SHIPPING_USPS_INS8; } else if ($costperpkg<=300) { $insurance=MODULE_SHIPPING_USPS_INS9; } else { $insurance = MODULE_SHIPPING_USPS_INS9 + ((ceil($costperpkg/100) - 3) * MODULE_SHIPPING_USPS_INS10); } } // usps doesnt accept zero weight $shipping_weight = ($shipping_weight < 0.1 ? 0.1 : $shipping_weight); $shipping_pounds = floor ($shipping_weight); $shipping_ounces = round(16 * ($shipping_weight - floor($shipping_weight))); $this->_setWeight($shipping_pounds, $shipping_ounces); // Added by Kevin Chen (kkchen@uci.edu); Fixes the Parcel Post Bug July 1, 2004 // Refer to http://www.usps.com/webtools/htm/Domestic-Rates.htm documentation // Thanks Ryan if($shipping_pounds > 35 || ($shipping_pounds == 0 && $shipping_ounces < 6)){ $this->_setMachinable('False'); } else{ $this->_setMachinable('True'); } $this->insurance_cost = $insurance; // End Kevin Chen July 1, 2004 } function _setService($service) { $this->service = $service; } function _setWeight($pounds, $ounces=0) { $this->pounds = $pounds; $this->ounces = $ounces; } function _setContainer($container) { $this->container = $container; } function _setSize($size) { $this->size = $size; } function _setMachinable($machinable) { $this->machinable = $machinable; } function PhoneClean($phone) { $res = preg_replace('/[(]|[)]|[\-]|[ ]|[#]|[\.]|[a-z](.*)|[A-Z](.*)/g', '', $phone); if ( strlen($res) > 10 ) { $res = substr($res, 0, 10); } return $res != '' ? $res : $phone; } function GetQuote($method = '') { if ( isset($this->types[$method]) || in_array($method, $this->intl_types)) { $this->_setService($method); } $this -> _setContainer('None'); $this -> _setSize('REGULAR'); $this -> SetInsurance(); // ??? if ($this->order['ShippingCountry'] == $this->shipping_origin_country) { $request=''; // PASSWORD="'.$this->usps_password.'" $request.= ''; $services_count = 0; if (isset($this->service)) { $this->types = array($this->service => $this->types[$this->service]); } $dest_zip = str_replace(' ', '', $this->order['ShippingZip']); $dest_zip = substr($dest_zip, 0, 5); reset($this->types); $allowed_types = explode(", ", MODULE_SHIPPING_USPS_TYPES); while (list($key, $value) = each($this->types)) { if ( !in_array($key, $allowed_types) ) continue; $request .= ''. ''.$key.''. ''.$this->store_zip5.''. ''.$dest_zip.''. ''.$this->pounds.''. ''.$this->ounces.''. ''.$this->size.''. ''.$this->machinable.''. ''; $services_count++; } $request .= ''; $api_query = 'RateV3'; } else { $request = ''. ''. ''.$this->pounds.''. ''.$this->ounces.''. 'Package'. ''.$this->countries[$this->order['ShippingCountry']].''. ''. ''; $api_query = 'IntlRate'; } $request = 'API='.$api_query.'&XML=' . kUtil::escape($request, kUtil::ESCAPE_URL); $body = $this->PostQuery($request); $body = str_replace(chr(146), '', $body); // for bad ` // check for errors if (strpos($body, '') !== false) { $errors = Array (); preg_match_all('/(.*?)<\/Number>/s', $body, $error_numbers); preg_match_all('/(.*?)<\/Description>/s', $body, $error_descriptions); foreach ($error_numbers[1] as $index => $error_number) { $errors[$index] = $error_descriptions[1][$index]; if ($this->Application->isDebugMode()) { $errors[$index] .= ' (' . $error_number . ')'; } } $errors = array_unique($errors); // we may have same errors on many packages, so don't show duplicates return Array('error' => implode('
', $errors)); } // parse response + /** @var kXMLHelper $xml_helper */ $xml_helper = $this->Application->recallObject('kXMLHelper'); - /* @var $xml_helper kXMLHelper */ + /** @var kXMLNode $root_node */ $root_node =& $xml_helper->Parse($body); - /* @var $root_node kXMLNode */ $rates = Array(); // Domestic shipping if ($this->order['ShippingCountry'] == $this->shipping_origin_country) { $i = 0; $postage_node =& $root_node->FindChild('Package'); do { // $parcel_node =& $postage_node->firstChild; $service = $postage_node->FindChildValue('MailService'); if ( $service != '' ) { $i++; $rates[$i] = Array(); $rates[$i]['Title'] = $service; $rates[$i]['Rate'] = $this->insurance_cost + $postage_node->FindChildValue('Rate'); } } while ( $postage_node =& $postage_node->NextSibling()); } else { // for International Rates !!! $allowed_types = array(); foreach( explode(", ", MODULE_SHIPPING_USPS_TYPES_INTL) as $value ) { $allowed_types[$value] = $this->intl_types[$value]; } $i = 0; $service_node =& $root_node->FindChild('Service'); do { $service = trim($service_node->FindChildValue('SvcDescription')); if( !in_array($service, $allowed_types) ) continue; $i++; if ( $service_node->FindChildValue('MaxWeight') >= $this->pounds ) { $rates[$i] = Array(); $rates[$i]['Title'] = $service; $rates[$i]['MaxDimensions'] = $service_node->FindChildValue('MaxDimensions'); $rates[$i]['MaxWeight'] = $service_node->FindChildValue('MaxWeight'); $rates[$i]['SvcCommitments'] = $service_node->FindChildValue('SvcCommitments'); $rates[$i]['Rate'] = $this->insurance_cost + $service_node->FindChildValue('Postage'); } } while ( $service_node =& $service_node->NextSibling()); } // print_r($rates); // die('here'); return $rates; } function PostOrder() { $request=''; $base_request = ''; $this->SetInsurance(); // $this->order['ShippingCountry'] = $this->GetUSPSCountry($this->order['ShippingCountry']); // Domestic Order if ($this->order['ShippingCountry'] == $this->shipping_origin_country) { // $dest_zip = str_replace(' ', '', $this->order['ShippingZip5']); $this->order['ShippingZip5'] = substr($this->order['ShippingZip5'], 0, 5); $WeightInOunces = floor($this->pounds * 16 + $this->ounces); $base_request =' '.$this->store_name.' '.$this->company_name.' '.$this->store_address1.' '.$this->store_address2.' '.$this->store_city.' '.$this->store_state.' '.$this->store_zip5.' '.$this->store_zip4.' '.$this->order['FirstName'].' '.$this->order['LastName'].' '.$this->order['ShippingCompany'].' '.$this->order['ShippingAddress2'].' '.$this->order['ShippingAddress1'].' '.$this->order['ShippingCity'].' '.$this->order['ShippingState'].' '.$this->order['ShippingZip5'].' '.$this->order['ShippingZip4'].' '.$WeightInOunces.' '.$this->order['ShippingService'].' PDF '.date('m/d/Y',time()).' '; $api_query = 'DeliveryConfirmationV3'; $xml_request = 'DeliveryConfirmationV3.0Request'; } else { // International Order(s) $shipping_service = strtolower($this->order['ShippingService']); $base_request = '