Page MenuHomeIn-Portal Phabricator

in-commerce
No OneTemporary

File Metadata

Created
Tue, Apr 29, 6:00 PM

in-commerce

Index: branches/5.0.x/units/orders/orders_item.php
===================================================================
--- branches/5.0.x/units/orders/orders_item.php (revision 13208)
+++ branches/5.0.x/units/orders/orders_item.php (revision 13209)
@@ -1,529 +1,502 @@
<?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
{
function OrdersItem()
{
parent::kDBItem();
$this->ErrorMsgs['credit_card_validation_error'] = $this->Application->Phrase('lu_cc_validation_error');
$this->ErrorMsgs['credit_card_expired'] = $this->Application->Phrase('lu_cc_expired');
}
- function Load($id, $id_field_name=null)
- {
- if( $this->Special == 'sitem' && $id == null || (!$this->IsTempTable() && $id == 0))
- {
- $this->setID(0);
-
- $this->SetDBField('Number',-1);
- $this->SetDBField('SubNumber',-1);
- // load previously used search params from session
- $search_params = $this->Application->RecallVar('ord.search_search_filter');
- if($search_params)
- {
- $search_params = unserialize($search_params);
- foreach($search_params as $search_field => $search_params)
- {
- $this->SetField($search_field, $search_params['search_value']);
- }
- $this->UpdateFormattersSubFields(); // used for updating separate virtual date/time fields from DB timestamp (for example)
- }
- return true;
- }
- else
- {
- return parent::Load($id,$id_field_name);
- }
- }
-
/**
* Return error message for field
*
* @param string $field
* @return string
* @access public
*/
function GetErrorMsg($field)
{
if( $field != 'OrderNumber' ) return parent::GetErrorMsg($field);
$number['error'] = parent::GetErrorMsg('Number');
$number['pseudo'] = getArrayValue($this->FieldErrors['Number'], 'pseudo');
$subnumber['error'] = parent::GetErrorMsg('SubNumber');
$subnumber['pseudo'] = getArrayValue($this->FieldErrors['SubNumber'], 'pseudo');
// if pseudo match & not empty -> return 1st
// if one of pseudos not empty -> return it
// if we got one pseudo "bad_type" and other pseudo "required", then return "bad_type" error message
if( $number['pseudo'] && ($number['pseudo'] == $subnumber['pseudo']) )
{
return $number['error'];
}
if( $number['pseudo'] && !$subnumber['pseudo'] )
{
return $number['error'];
}
if( !$number['pseudo'] && $subnumber['pseudo'] )
{
return $subnumber['error'];
}
if( $number['pseudo'] == 'bad_type' )
{
return $number['error'];
}
if( $subnumber['pseudo'] == 'bad_type' )
{
return $subnumber['error'];
}
// $msg = '['.$number_error.'('.$number_pseudo.')] ['.$subnumber_error.'] ('.$subnumber_pseudo.')';
//
// return $msg;
}
function SetFieldsFromHash($hash, $set_fields=null)
{
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
*
* @return Array
*/
function getGatewayData($pt_id=null)
{
// get Gateway fields
if (!isset($pt_id) || !$pt_id) {
$pt_id = $this->GetDBField('PaymentType');
}
$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
*/
function HasTangibleItems()
{
$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;
}
/**
* Calculates tax value of order items based on billing & shipping country specified
*
* @return double
*/
function getTaxPercent()
{
$sql = 'SELECT DestId FROM '.TABLE_PREFIX.'StdDestinations WHERE DestType = %s AND DestAbbr = %s';
$shipping_country_id = (int) $this->Conn->GetOne( sprintf($sql, 1, $this->Conn->qstr($this->GetDBField('ShippingCountry') ) ) );
$shipping_state_id = (int) $this->Conn->GetOne( sprintf($sql, 2, $this->Conn->qstr($this->GetDBField('ShippingState') ) ) );
$shipping_zip = (string) $this->GetDBField('ShippingZip');
$billing_country_id = (int) $this->Conn->GetOne( sprintf($sql, 1, $this->Conn->qstr($this->GetDBField('BillingCountry') ) ) );
$billing_state_id = (int) $this->Conn->GetOne( sprintf($sql, 2, $this->Conn->qstr($this->GetDBField('BillingState') ) ) );
$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();
$subtotal = $this->GetDBField('AmountWithoutVAT');
$query = 'SELECT SUM(Quantity * 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');
$tax_exempt = $this->Conn->GetOne($query);
if ($tax_exempt) $subtotal -= $tax_exempt;
$this->SetDBField( 'VAT', round($subtotal * $tax['TaxValue'] / 100, 2) );
$this->UpdateTotals();
}
function UpdateTotals()
{
$total = 0;
$total += $this->GetDBField('SubTotal');
if ($this->GetDBField('ShippingTaxable')) $total += $this->GetDBField('ShippingCost');
if ($this->GetDBField('ProcessingTaxable')) $total += $this->GetDBField('ProcessingFee');
$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('VAT') +
$this->GetDBField('ProcessingFee') +
$this->GetDBField('InsuranceFee') -
$this->GetDBField('GiftCertificateDiscount');
}
/**
* Check field value by user-defined alghoritm
*
* @param string $field field name
* @param Array $params field options from config
* @return bool
*/
function CustomValidation($field, $params)
{
$res = true;
$res = $res && $this->ValidateCCNumber($field, $params);
$res = $res && $this->ValidateCCExpiration($field, $params);
return $res;
}
function requireCreditCard()
{
$pt_table = $this->Application->getUnitOption('pt', 'TableName');
$sql = 'SELECT RequireCCFields
FROM '.$pt_table.' pt
LEFT JOIN '.TABLE_PREFIX.'Gateways gw ON gw.GatewayId = pt.GatewayId
WHERE pt.PaymentTypeId = '.$this->GetDBField('PaymentType');
return $this->Conn->GetOne($sql);
}
/**
* Check if field value is valid credit card number against credit card type specified
*
* @param string $field field name
* @param Array $params field options from config
* @return bool
* @access private
*/
function ValidateCCNumber($field, $params)
{
$cardtype_field = getArrayValue($params, 'cardtype_field');
$value = $this->GetDBField($field);
if( !$cardtype_field || !$value || !$this->requireCreditCard() ) return true;
if ($this->Application->ConfigValue('Comm_MaskProcessedCreditCards')) {
$mask_found = strpos($value, str_repeat('X', 4)) !== false;
if ($this->Application->isAdminUser && $mask_found) {
// masked card numbers always appear valid in admin
return true;
}
}
if (defined('DEBUG_MODE') && constOn('DBG_PAYMENT_GW')) {
$gw_data = $this->getGatewayData();
$this->Application->registerClass( $gw_data['ClassName'], GW_CLASS_PATH.'/'.$gw_data['ClassFile'] );
$gateway_object =& $this->Application->recallObject( $gw_data['ClassName'] );
$test_numbers = $gateway_object->GetTestCCNumbers();
if (in_array($value, $test_numbers)) return true;
}
$error_field = isset($params['error_field']) ? $params['error_field'] : $field;
// '1' => 'Visa','2' => 'Mastercard', '3' => 'Amex', '4' => 'Discover', 5 => 'Diners Club', 6 => 'JBC'
// Innocent until proven guilty
$cc_valid = true;
// Get rid of any non-digits
$value = ereg_replace("[^[:digit:]]", '', $value);
// Perform card-specific checks, if applicable
switch( $this->GetDBField($cardtype_field) )
{
case 2: // MasterCard
$cc_valid = ereg("^5[1-5].{14}$", $value);
break;
case 1: // Visa
$cc_valid = ereg("^4.{15}$|^4.{12}$", $value);
break;
case 3: // American Express
$cc_valid = ereg("^3[47].{13}$", $value);
break;
case 4: // Discover
$cc_valid = ereg("^6011.{12}$", $value);
break;
case 5: // Diners Club
$cc_valid = ereg("^30[0-5].{11}$|^3[68].{12}$", $value);
break;
case 6: // JBC
$cc_valid = ereg("^3.{15}$|^2131|1800.{11}$", $value);
break;
default:
$this->FieldErrors[$error_field]['pseudo'] = 'credit_card_validation_error';
return false;
break;
}
// The Luhn formula works right to left, so reverse the number.
$value = strrev($value);
$total = 0;
for($x = 0; $x < strlen($value); $x++)
{
$digit = substr($value, $x, 1);
// If it's an odd digit, double it
if( $x / 2 != floor($x/2) )
{
$digit *= 2;
// If the result is two digits, add them
if( strlen($digit) == 2 )
{
$digit = substr($digit, 0, 1) + substr($digit, 1, 1);
}
}
// Add the current digit, doubled and added if applicable, to the Total
$total += $digit;
}
// If it passed (or bypassed) the card-specific check and the Total is
// evenly divisible by 10, it's cool!
if ($cc_valid && $total % 10 == 0)
{
return true;
}
else
{
$this->FieldErrors[$error_field]['pseudo'] = 'credit_card_validation_error';
return false;
}
}
/**
* Check if field value is non-expired credit card expiration date
*
* @param string $field field name
* @param Array $params field options from config
* @return bool
* @access private
*/
function ValidateCCExpiration($field, $params)
{
$formatter = getArrayValue($params, 'formatter');
if( ($formatter != 'kCCDateFormatter') || !$this->requireCreditCard() ) return true;
if(!$this->Application->isAdminUser) {
// validate expiration date only for front
if (preg_match('/([\d]{2})\/([\d]{2})/', $this->GetDBField($field), $rets)) {
$month = $rets[1];
$year = $rets[2];
$now_date = adodb_mktime(0, 0, 0, adodb_date('m'), adodb_date('d'), adodb_date('Y') );
$day_count = adodb_date('t', adodb_mktime(0, 0, 0, $month, 1, $year) );
$cc_date = adodb_mktime(23, 59, 59, $month, $day_count, $year);
if ($cc_date < $now_date) {
$error_field = isset($params['error_field']) ? $params['error_field'] : $field;
$this->FieldErrors[$error_field]['pseudo'] = 'credit_card_expired';
return false;
}
}
}
return true;
}
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);
$event->SetRedirectParam('checkout_error', 108);
}
$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);
}
}
\ No newline at end of file

Event Timeline