Index: branches/5.2.x/units/orders/orders_item.php
===================================================================
--- branches/5.2.x/units/orders/orders_item.php	(revision 16241)
+++ branches/5.2.x/units/orders/orders_item.php	(revision 16242)
@@ -1,380 +1,387 @@
 <?php
 /**
 * @version	$Id$
 * @package	In-Commerce
 * @copyright	Copyright (C) 1997 - 2009 Intechnic. All rights reserved.
 * @license	Commercial License
 * This software is protected by copyright law and international treaties.
 * Unauthorized reproduction or unlicensed usage of the code of this program,
 * or any portion of it may result in severe civil and criminal penalties,
 * and will be prosecuted to the maximum extent possible under the law
 * See http://www.in-portal.org/commercial-license for copyright notices and details.
 */
 
 	defined('FULL_PATH') or die('restricted access!');
 
 	class OrdersItem extends kDBItem
 	{
 
 		/**
 		 * Sets item' fields corresponding to elements in passed $hash values.
 		 * The function sets current item fields to values passed in $hash, by matching $hash keys with field names
 		 * of current item. If current item' fields are unknown {@link kDBItem::PrepareFields()} is called before actually setting the fields
 		 *
 		 * @param Array $hash       Fields hash.
 		 * @param Array $set_fields Optional param, field names in target object to set, other fields will be skipped
 		 *
 		 * @return void
 		 */
 		public function SetFieldsFromHash($hash, $set_fields = Array ())
 		{
 			parent::SetFieldsFromHash($hash, $set_fields);
 
 			$options = $this->GetFieldOptions('PaymentCCExpDate');
 
 			if ( $this->GetDirtyField($options['month_field']) || $this->GetDirtyField($options['year_field']) ) {
 				$this->SetDirtyField('PaymentCCExpDate', 0);
 				$this->SetField('PaymentCCExpDate', 0);
 			}
 		}
 
 		/**
 		 * Returns gateway data based on payment type used in order
 		 *
 		 * @param int $pt_id
 		 * @return Array
 		 * @access public
 		 */
 		public function getGatewayData($pt_id = null)
 		{
 			// get Gateway fields
 			if ( !isset($pt_id) || !$pt_id ) {
 				$pt_id = $this->GetDBField('PaymentType');
 
 				if ( !$pt_id ) {
 					// no Payment Type Id found for this order - escape SQL fatal below
 					return false;
 				}
 			}
 
 			$pt_table = $this->Application->getUnitOption('pt', 'TableName');
 
 			$sql = 'SELECT GatewayId
 					FROM %s
 					WHERE PaymentTypeId = %s';
 			$gw_id = $this->Conn->GetOne(sprintf($sql, $pt_table, $pt_id));
 
 			$sql = 'SELECT *
 					FROM %s
 					WHERE GatewayId = %s';
 			$ret = $this->Conn->GetRow(sprintf($sql, TABLE_PREFIX . 'Gateways', $gw_id));
 
 			// get Gateway parameters based on payment type
 			$gwf_table = $this->Application->getUnitOption('gwf', 'TableName');
 			$gwfv_table = $this->Application->getUnitOption('gwfv', 'TableName');
 
 			$sql = 'SELECT gwfv.Value, gwf.SystemFieldName
 					FROM %s gwf
 					LEFT JOIN %s gwfv ON gwf.GWConfigFieldId = gwfv.GWConfigFieldId
 					WHERE gwfv.PaymentTypeId = %s AND gwf.GatewayId = %s';
 			$ret['gw_params'] = $this->Conn->GetCol(sprintf($sql, $gwf_table, $gwfv_table, $pt_id, $gw_id), 'SystemFieldName');
 
 			$ret['gw_params']['gateway_id'] = $gw_id;
 
 			if ( $this->GetDBField('IsRecurringBilling') && $this->Application->ConfigValue('Comm_AutoProcessRecurringOrders') ) {
 				if ( isset($ret['gw_params']['shipping_control']) ) {
 					$ret['gw_params']['shipping_control'] = SHIPPING_CONTROL_DIRECT;
 				}
 			}
 
 			return $ret;
 		}
 
 		/**
 		 * Checks if tangible items are present in order
 		 *
-		 * @return bool
+		 * @return boolean
 		 */
-		function HasTangibleItems()
+		public function HasTangibleItems()
 		{
+			$oi_table = TABLE_PREFIX . 'OrderItems';
+
+			if ( $this->IsTempTable() ) {
+				$oi_table = $this->Application->GetTempName($oi_table, 'prefix:' . $this->Prefix);
+			}
+
 			$sql = 'SELECT COUNT(*)
-					FROM '.TABLE_PREFIX.'OrderItems orditems
-					LEFT JOIN '.TABLE_PREFIX.'Products p ON p.ProductId = orditems.ProductId
-					WHERE (orditems.OrderId = '.$this->GetID().') AND (p.Type = '.PRODUCT_TYPE_TANGIBLE.')';
-			return $this->Conn->GetOne($sql) ? true : false;
+					FROM ' . $oi_table . ' orditems
+					LEFT JOIN ' . TABLE_PREFIX . 'Products p ON p.ProductId = orditems.ProductId
+					WHERE (orditems.OrderId = ' . $this->GetID() . ') AND (p.Type = ' . PRODUCT_TYPE_TANGIBLE . ')';
+
+			return $this->Conn->GetOne($sql) > 0;
 		}
 
 		/**
 		 * Calculates tax value of order items based on billing & shipping country specified
 		 *
 		 * @return double
 		 */
 		function getTaxPercent()
 		{
 			$cs_helper = $this->Application->recallObject('CountryStatesHelper');
 			/* @var $cs_helper kCountryStatesHelper */
 
 			$shipping_country_id = $cs_helper->getCountryStateId($this->GetDBField('ShippingCountry'), DESTINATION_TYPE_COUNTRY);
 			$shipping_state_id = $cs_helper->getCountryStateId($this->GetDBField('ShippingState'), DESTINATION_TYPE_STATE);
 			$shipping_zip = (string) $this->GetDBField('ShippingZip');
 
 			$billing_country_id = $cs_helper->getCountryStateId($this->GetDBField('BillingCountry'), DESTINATION_TYPE_COUNTRY);
 			$billing_state_id =  $cs_helper->getCountryStateId($this->GetDBField('BillingState'), DESTINATION_TYPE_STATE);
 			$billing_zip = (string) $this->GetDBField('BillingZip');
 
 			/*
 			$dest_ids = array_diff( array_unique( Array( $shipping_country_id, $shipping_state_id, $billing_country_id, $billing_state_id ) ), Array(0) );
 			$dest_values = array_diff( array_unique( Array( $this->Conn->qstr($shipping_zip), $this->Conn->qstr($billing_zip) ) ), Array('\'\'') );
 			*/
 
 			$tax = false;
 			$sql = 'SELECT tx.*
 				FROM '.$this->Application->getUnitOption('tax', 'TableName').' tx
 				LEFT JOIN '.$this->Application->getUnitOption('taxdst', 'TableName').' txd ON tx.TaxZoneId = txd.TaxZoneId
 				WHERE
 					(	txd.StdDestId IN ('.$shipping_country_id.','.$shipping_state_id.')
 						AND
 						( (txd.DestValue = "" OR txd.DestValue IS NULL)
 							OR
 							txd.DestValue = '.$this->Conn->qstr($shipping_zip).'
 						)
 					)
 					OR
 					(	txd.StdDestId IN ('.$billing_country_id.','.$billing_state_id.')
 						AND
 						( (txd.DestValue = "" OR txd.DestValue IS NULL)
 							OR
 							txd.DestValue = '.$this->Conn->qstr($billing_zip).'
 						)
 					)
 
 				ORDER BY tx.TaxValue DESC';
 
 			$tax = $this->Conn->GetRow($sql);
 			if ($tax == false) {
 				$tax['TaxValue'] = 0;
 				$tax['ApplyToShipping'] = 0;
 				$tax['ApplyToProcessing'] = 0;
 			}
 
 			return $tax;
 		}
 
 		function RecalculateTax()
 		{
 			$tax = $this->getTaxPercent();
 			$this->SetDBField('VATPercent', $tax['TaxValue']);
 			$this->SetDBField('ShippingTaxable', $tax['ApplyToShipping']);
 			$this->SetDBField('ProcessingTaxable', $tax['ApplyToProcessing']);
 			$this->UpdateTotals();
 
 			if ( !$this->GetDBField('VATIncluded') ) {
 				$subtotal = $this->GetDBField('AmountWithoutVAT');
 
 				$tax_exempt = $this->getTaxExempt();
 
 				if ( $tax_exempt ) {
 					$subtotal -= $tax_exempt;
 				}
 
 				$this->SetDBField('VAT', round($subtotal * $tax['TaxValue'] / 100, 2));
 				$this->UpdateTotals();
 			}
 		}
 
 		/**
 		 * Returns order amount, that is excluded from tax calculations
 		 *
 		 * @return float
 		 * @access protected
 		 */
 		protected function getTaxExempt()
 		{
 			$sql = 'SELECT SUM(oi.Quantity * oi.Price)
 					FROM ' . TABLE_PREFIX . 'OrderItems AS oi
 					LEFT JOIN ' . TABLE_PREFIX . 'Products AS p ON p.ProductId = oi.ProductId
 					WHERE p.Type = 6 AND oi.OrderId = ' . $this->GetDBField('OrderId');
 
 			return $this->Conn->GetOne($sql);
 		}
 
 		function UpdateTotals()
 		{
 			$total = 0;
 			$total += $this->GetDBField('SubTotal');
 
 			if ( $this->GetDBField('ShippingTaxable') ) {
 				$total += $this->GetDBField('ShippingCost');
 			}
 
 			if ( $this->GetDBField('ProcessingTaxable') ) {
 				$total += $this->GetDBField('ProcessingFee');
 			}
 
 			if ( $this->GetDBField('VATIncluded') ) {
 				$tax_exempt = $this->getTaxExempt();
 
 				$vat_percent = $this->GetDBField('VATPercent');
 				$this->SetDBField('VAT', round(($total - $tax_exempt) * $vat_percent / (100 + $vat_percent), 2));
 				$this->SetDBField('AmountWithoutVAT', $total - $this->GetDBField('VAT'));
 			}
 			else {
 				$this->SetDBField('AmountWithoutVAT', $total);
 				$total += $this->GetDBField('VAT');
 			}
 
 			if ( !$this->GetDBField('ShippingTaxable') ) {
 				$total += $this->GetDBField('ShippingCost');
 			}
 
 			if ( !$this->GetDBField('ProcessingTaxable') ) {
 				$total += $this->GetDBField('ProcessingFee');
 			}
 
 			$total += $this->GetDBField('InsuranceFee');
 
 			$this->SetDBField('TotalAmount', $total);
 		}
 
 		function getTotalAmount()
 		{
 			return 	$this->GetDBField('SubTotal') +
 					$this->GetDBField('ShippingCost') +
 					($this->GetDBField('VATIncluded') ? 0 : $this->GetDBField('VAT')) +
 					$this->GetDBField('ProcessingFee') +
 					$this->GetDBField('InsuranceFee') -
 					$this->GetDBField('GiftCertificateDiscount');
 		}
 
 		function requireCreditCard()
 		{
 			$sql = 'SELECT RequireCCFields
 					FROM ' . $this->Application->getUnitOption('pt', 'TableName') . ' pt
 					LEFT JOIN '.TABLE_PREFIX.'Gateways gw ON gw.GatewayId = pt.GatewayId
 					WHERE pt.PaymentTypeId = ' . $this->GetDBField('PaymentType');
 
 			return $this->Conn->GetOne($sql);
 		}
 
 		function getNextSubNumber()
 		{
 			$table = $this->Application->GetLiveName($this->TableName);
 			$sql = 'SELECT MAX(SubNumber) FROM '.$table.' WHERE Number = '.$this->GetDBField('Number');
 			return $this->Conn->GetOne($sql) + 1;
 		}
 
 		function ResetAddress($prefix)
 		{
 			$fields = Array('To','Company','Phone','Fax','Email','Address1','Address2','City','State','Zip','Country');
 			foreach($fields as $field)
 			{
 				$this->SetDBField($prefix.$field, $this->Fields[$prefix.$field]['default']);
 			}
 		}
 
 		function IsProfileAddress($address_type)
 		{
 			return $this->Application->GetVar($this->Prefix.'_IsProfileAddress');
 		}
 
 		// ===== Gift Certificates Related =====
 		function RecalculateGift($event)
 		{
 			$gc_id = $this->GetDBField('GiftCertificateId');
 			if ($gc_id < 1) {
 				return;
 			}
 
 			$gc = $this->Application->recallObject('gc', null, Array('skip_autoload' => true));
 			/* @var $gc kDBItem */
 
 			$gc->Load($gc_id);
 
 			if ($gc->GetDBField('Status') == gcDISABLED) {
 				// disabled GC
 				$this->SetDBField('GiftCertificateId', 0);
 				$this->SetDBField('GiftCertificateDiscount', 0);
 				// disabled
 				return;
 			}
 
 			$debit = $gc->GetDBField('Debit') + $this->GetDBField('GiftCertificateDiscount');
 
 			$this->UpdateTotals();
 
 			$total = $this->GetDBField('TotalAmount');
 			$gift_certificate_discount = $debit >= $total ? $total : $debit;
 
 			$this->SetDBField('TotalAmount', $total - $gift_certificate_discount);
 			$this->GetDBField('GiftCertificateDiscount', $gift_certificate_discount);
 
 			$debit -= $gift_certificate_discount;
 			$gc->SetDBField('Debit', $debit);
 
 			$gc->SetDBField('Status', $debit > 0 ? gcENABLED : gcUSED);
 			$gc->Update();
 
 			if ($gift_certificate_discount == 0) {
 				$this->RemoveGiftCertificate($object);
 				$this->setCheckoutError(OrderCheckoutErrorType::GIFT_CERTIFICATE, OrderCheckoutError::GC_REMOVED_AUTOMATICALLY);
 			}
 
 			$this->SetDBField('GiftCertificateDiscount', $gift_certificate_discount);
 		}
 
 		function RemoveGiftCertificate()
 		{
 			$gc_id = $this->GetDBField('GiftCertificateId');
 
 			$gc = $this->Application->recallObject('gc', null, Array('skip_autoload' => true));
 			/* @var $gc kDBItem */
 
 			$gc->Load($gc_id);
 
 			$debit = $gc->GetDBField('Debit') + $this->GetDBField('GiftCertificateDiscount');
 
 			if ($gc->isLoaded() && ($debit > 0)) {
 				$gc->SetDBField('Debit', $debit);
 				$gc->SetDBField('Status', gcENABLED);
 				$gc->Update();
 			}
 
 			$this->SetDBField('GiftCertificateId', 0);
 			$this->SetDBField('GiftCertificateDiscount', 0);
 		}
 
 		/**
 		 * Sets checkout error
 		 *
 		 * @param int $error_type = {product,coupon,gc}
 		 * @param int $error_code
 		 * @param int $product_id - {ProductId}:{OptionsSalt}:{BackOrderFlag}:{FieldName}
 		 */
 		function setCheckoutError($error_type, $error_code, $product_id = null)
 		{
 			$errors = $this->Application->RecallVar('checkout_errors');
 			$errors = $errors ? unserialize($errors) : Array ();
 
 			if ( isset($product_id) ) {
 				$error_type .= ':' . $product_id;
 
 				// any error takes priority over FIELD_UPDATE_SUCCESS error
 				if ( isset($errors[$error_type]) && $error_code == OrderCheckoutError::FIELD_UPDATE_SUCCESS ) {
 					return ;
 				}
 			}
 
 			if ( is_numeric($error_code) ) {
 				$errors[$error_type] = $error_code;
 			}
 			else {
 				unset($errors[$error_type]);
 			}
 
 			if ( $this->Application->isDebugMode() ) {
 				$this->Application->Debugger->appendHTML('CO_ERROR: ' . $error_type . ' - ' . $error_code);
 			}
 
 			$this->Application->StoreVar('checkout_errors', serialize($errors));
 		}
 	}