Page MenuHomeIn-Portal Phabricator

in-commerce
No OneTemporary

File Metadata

Created
Sun, Feb 2, 8:50 AM

in-commerce

Index: branches/5.1.x/units/gateways/gw_classes/google_checkout.php
===================================================================
--- branches/5.1.x/units/gateways/gw_classes/google_checkout.php (revision 14358)
+++ branches/5.1.x/units/gateways/gw_classes/google_checkout.php (revision 14359)
@@ -1,931 +1,940 @@
<?php
/**
* @version $Id$
* @package In-Commerce
* @copyright Copyright (C) 1997 - 2009 Intechnic. All rights reserved.
* @license Commercial License
* This software is protected by copyright law and international treaties.
* Unauthorized reproduction or unlicensed usage of the code of this program,
* or any portion of it may result in severe civil and criminal penalties,
* and will be prosecuted to the maximum extent possible under the law
* See http://www.in-portal.org/commercial-license for copyright notices and details.
*/
require_once GW_CLASS_PATH.'/gw_base.php';
$class_name = 'kGWGoogleCheckout'; // for automatic installation
class kGWGoogleCheckout extends kGWBase
{
var $gwParams = Array ();
function InstallData()
{
$data = array(
'Gateway' => Array('Name' => 'Google Checkout', 'ClassName' => 'kGWGoogleCheckout', 'ClassFile' => 'google_checkout.php', 'RequireCCFields' => 0),
'ConfigFields' => Array(
'submit_url' => Array('Name' => 'Submit URL', 'Type' => 'text', 'ValueList' => '', 'Default' => 'https://checkout.google.com/api/checkout/v2'),
'merchant_id' => Array('Name' => 'Google merchant ID', 'Type' => 'text', 'ValueList' => '', 'Default' => ''),
'merchant_key' => Array('Name' => 'Google merchant key', 'Type' => 'text', 'ValueList' => '', 'Default' => ''),
'shipping_control' => Array('Name' => 'Shipping Control', 'Type' => 'select', 'ValueList' => '3=la_CreditDirect,4=la_CreditPreAuthorize', 'Default' => 3),
)
);
return $data;
}
/**
* Returns payment form submit url
*
* @param Array $gw_params gateway params from payment type config
* @return string
*/
function getFormAction($gw_params)
{
return $gw_params['submit_url'].'/checkout/Merchant/'.$gw_params['merchant_id'];
}
/**
* Processed input data and convets it to fields understandable by gateway
*
* @param Array $item_data current order fields
* @param Array $tag_params additional params for gateway passed through tag
* @param Array $gw_params gateway params from payment type config
* @return Array
*/
function getHiddenFields($item_data, $tag_params, $gw_params)
{
$ret = Array();
$this->gwParams = $gw_params;
$cart_xml = $this->getCartXML($item_data);
$ret['cart'] = base64_encode($cart_xml);
$ret['signature'] = base64_encode( $this->CalcHmacSha1($cart_xml, $gw_params) );
return $ret;
}
function getCartXML($cart_fields)
{
// 1. prepare shopping cart content
$sql = 'SELECT *
FROM '.TABLE_PREFIX.'OrderItems oi
LEFT JOIN '.TABLE_PREFIX.'Products p ON p.ProductId = oi.ProductId
WHERE oi.OrderId = '.$cart_fields['OrderId'];
$order_items = $this->Conn->Query($sql);
$ml_formatter =& $this->Application->recallObject('kMultiLanguage');
/* @var $ml_formatter kMultiLanguage */
$cart_xml = Array ();
foreach ($order_items as $order_item) {
$cart_xml[] = ' <item>
<item-name>'.htmlspecialchars($order_item['ProductName']).'</item-name>
<item-description>'.htmlspecialchars($order_item[$ml_formatter->LangFieldName('DescriptionExcerpt')]).'</item-description>'.
$this->getPriceXML('unit-price', $order_item['Price']).'
<quantity>'.$order_item['Quantity'].'</quantity>
</item>';
}
$cart_xml = '<items>'.implode("\n", $cart_xml).'</items>';
// 2. add order identification info (for google checkout notification)
$cart_xml .= ' <merchant-private-data>
<session_id>'.$this->Application->GetSID().'</session_id>
<order_id>'.$cart_fields['OrderId'].'</order_id>
</merchant-private-data>';
// 3. add all shipping types (with no costs)
$sql = 'SELECT Name
FROM '.TABLE_PREFIX.'ShippingType
WHERE Status = '.STATUS_ACTIVE;
$shipping_types = $this->Conn->GetCol($sql);
$shipping_xml = '';
foreach ($shipping_types as $shipping_name) {
$shipping_xml .= ' <merchant-calculated-shipping name="'.htmlspecialchars($shipping_name).'">
<price currency="USD">0.00</price>
</merchant-calculated-shipping>';
}
$use_ssl = substr($this->gwParams['submit_url'], 0, 8) == 'https://' ? true : null;
$shipping_url = $this->getNotificationUrl('units/gateways/gw_classes/notify_scripts/google_checkout_shippings.php', $use_ssl);
$shipping_xml = '<merchant-checkout-flow-support>
<shipping-methods>'.$shipping_xml.'</shipping-methods>
<merchant-calculations>
<merchant-calculations-url>'.$shipping_url.'</merchant-calculations-url>
</merchant-calculations>
</merchant-checkout-flow-support>';
$xml = '<checkout-shopping-cart xmlns="http://checkout.google.com/schema/2">
<shopping-cart>'.$cart_xml.'</shopping-cart>
<checkout-flow-support>'.$shipping_xml.'</checkout-flow-support>
</checkout-shopping-cart>';
return $xml;
}
/**
* Returns price formatted as xml tag
*
* @param string $tag_name
* @param float $price
* @return string
*/
function getPriceXML($tag_name, $price)
{
$currency = $this->Application->RecallVar('curr_iso');
return '<'.$tag_name.' currency="'.$currency.'">'.sprintf('%.2f', $price).'</'.$tag_name.'>';
}
/**
* Calculates the cart's hmac-sha1 signature, this allows google to verify
* that the cart hasn't been tampered by a third-party.
*
* {@link http://code.google.com/apis/checkout/developer/index.html#create_signature}
*
* @param string $data the cart's xml
* @return string the cart's signature (in binary format)
*/
function CalcHmacSha1($data, $gw_params) {
$key = $gw_params['merchant_key'];
$blocksize = 64;
$hashfunc = 'sha1';
if (mb_strlen($key) > $blocksize) {
$key = pack('H*', $hashfunc($key));
}
$key = str_pad($key, $blocksize, chr(0x00));
$ipad = str_repeat(chr(0x36), $blocksize);
$opad = str_repeat(chr(0x5c), $blocksize);
$hmac = pack(
'H*', $hashfunc(
($key^$opad).pack(
'H*', $hashfunc(
($key^$ipad).$data
)
)
)
);
return $hmac;
}
/**
* Returns XML request, that GoogleCheckout posts to notification / shipping calculation scripts
*
* @return string
*/
function getRequestXML()
{
$xml_data = $GLOBALS['HTTP_RAW_POST_DATA'];
- if ($this->Application->isDebugMode()) {
- $fp = fopen(FULL_PATH.'/xml_request.html', 'a');
- fwrite($fp, '--- '.adodb_date('Y-m-d H:i:s').' ---'."\n".$xml_data);
- fclose($fp);
+ if ( $this->Application->isDebugMode() ) {
+ $this->toLog($xml_data, 'xml_request.html');
}
return $xml_data;
// for debugging
/*return '<order-state-change-notification xmlns="http://checkout.google.com/schema/2"
serial-number="c821426e-7caa-4d51-9b2e-48ef7ecd6423">
<google-order-number>434532759516557</google-order-number>
<new-financial-order-state>CHARGEABLE</new-financial-order-state>
<new-fulfillment-order-state>NEW</new-fulfillment-order-state>
<previous-financial-order-state>REVIEWING</previous-financial-order-state>
<previous-fulfillment-order-state>NEW</previous-fulfillment-order-state>
<timestamp>2007-03-19T15:06:29.051Z</timestamp>
</order-state-change-notification>';*/
}
/**
* Processes notifications from google checkout
*
* @param Array $gw_params
* @return int
*/
function processNotification($gw_params)
{
// parse xml & get order_id from there, like sella pay
$this->gwParams = $gw_params;
$xml_helper =& $this->Application->recallObject('kXMLHelper');
/* @var $xml_helper kXMLHelper */
$root_node =& $xml_helper->Parse( $this->getRequestXML() );
/* @var $root_node kXMLNode */
$this->Application->XMLHeader();
define('DBG_SKIP_REPORTING', 1);
$order_approvable = false;
switch ($root_node->Name) {
case 'MERCHANT-CALCULATION-CALLBACK':
$xml_responce = $this->getShippingXML($root_node);
break;
case 'NEW-ORDER-NOTIFICATION':
case 'RISK-INFORMATION-NOTIFICATION':
case 'ORDER-STATE-CHANGE-NOTIFICATION':
// http://code.google.com/apis/checkout/developer/Google_Checkout_XML_API_Notification_API.html#new_order_notifications
list ($order_approvable, $xml_responce) = $this->getNotificationResponceXML($root_node);
break;
}
echo $xml_responce;
- if ($this->Application->isDebugMode()) {
- $fp = fopen(FULL_PATH.'/xml_responce.html', 'a');
- fwrite($fp, '--- '.adodb_date('Y-m-d H:i:s').' ---'."\n".$xml_responce."\n");
- fclose($fp);
+ if ( $this->Application->isDebugMode() ) {
+ $this->toLog($xml_responce, 'xml_responce.html');
}
return $order_approvable ? 1 : 0;
}
/**
+ * Writes XML requests and responces to a file
+ *
+ * @param string $xml_data
+ * @param string $xml_file
+ */
+ function toLog($xml_data, $xml_file)
+ {
+ $fp = fopen( (defined('RESTRICTED') ? RESTRICTED : FULL_PATH) . '/' . $xml_file, 'a' );
+ fwrite($fp, '--- ' . adodb_date('Y-m-d H:i:s') . ' ---' . "\n" . $xml_data);
+ fclose($fp);
+ }
+
+ /**
* Processes notification
*
* @param kXMLNode $root_node
*/
function getNotificationResponceXML(&$root_node)
{
// we can get notification type by "$root_node->Name"
$order_approvable = false;
switch ($root_node->Name) {
case 'NEW-ORDER-NOTIFICATION':
$order_approvable = $this->processNewOrderNotification($root_node);
break;
case 'RISK-INFORMATION-NOTIFICATION':
$order_approvable = $this->processRiskInformationNotification($root_node);
break;
case 'ORDER-STATE-CHANGE-NOTIFICATION':
$order_approvable = $this->processOrderStateChangeNotification($root_node);
break;
}
// !!! globally set order id, so gw_responce.php will not fail in setting TransactionStatus
// 1. receive new order notification
// put address & payment type in our order using id found in merchant-private-data (Make order status: Incomplete)
// 2. receive risk information
// don't know what to do, just mark order some how (Make order status: Incomplete)
// 3. receive status change notification to CHARGEABLE (Make order status: Pending)
// only mark order status
// 4. admin approves order
// make api call, that changes order state (fulfillment-order-state) to PROCESSING or DELIVERED (see manual)
// 5. admin declines order
// make api call, that changes order state (fulfillment-order-state) to WILL_NOT_DELIVER
// Before you ship the items in an order, you should ensure that you have already received the new order notification for the order,
// the risk information notification for the order and an order state change notification informing you that the order's financial
// state has been updated to CHARGEABLE
return Array ($order_approvable, '<notification-acknowledgment xmlns="http://checkout.google.com/schema/2" serial-number="'.$root_node->Attributes['SERIAL-NUMBER'].'" />');
}
/**
* Returns shipping calculations and places part of shipping address into order (1st step)
*
* http://code.google.com/apis/checkout/developer/Google_Checkout_XML_API_Merchant_Calculations_API.html#Returning_Merchant_Calculation_Results
*
* @param kXMLNode $node
* @return string
*/
function getShippingXML(&$root_node)
{
// 1. extract data from xml
$search_nodes = Array (
'SHOPPING-CART:MERCHANT-PRIVATE-DATA',
'CALCULATE:ADDRESSES:ANONYMOUS-ADDRESS',
'CALCULATE:SHIPPING',
);
foreach ($search_nodes as $search_string) {
$found_node =& $root_node;
/* @var $found_node kXMLNode */
$search_string = explode(':', $search_string);
foreach ($search_string as $search_node) {
$found_node =& $found_node->FindChild($search_node);
}
$node_data = Array ();
$sub_node =& $found_node->firstChild;
/* @var $sub_node kXMLNode */
do {
if ($found_node->Name == 'SHIPPING') {
$node_data[] = $sub_node->Attributes['NAME'];
}
else {
$node_data[$sub_node->Name] = $sub_node->Data;
}
} while ( ($sub_node =& $sub_node->NextSibling()) );
switch ($found_node->Name) {
case 'MERCHANT-PRIVATE-DATA':
$order_id = $node_data['ORDER_ID'];
$session_id = $node_data['SESSION_ID'];
break;
case 'ANONYMOUS-ADDRESS':
$address_info = $node_data;
$address_id = $found_node->Attributes['ID'];
break;
case 'SHIPPING':
$process_shippings = $node_data;
break;
}
}
// 2. update shipping address in order
$order =& $this->Application->recallObject('ord', null, Array ('skip_autoload' => true));
/* @var $order OrdersItem */
$order->Load($order_id);
$shipping_address = Array (
'ShippingCity' => $address_info['CITY'],
'ShippingState' => $address_info['REGION'],
'ShippingZip' => $address_info['POSTAL-CODE'],
);
$cs_helper =& $this->Application->recallObject('CountryStatesHelper');
/* @var $cs_helper kCountryStatesHelper */
$shipping_address['ShippingCountry'] = $cs_helper->getCountryIso($address_info['COUNTRY-CODE'], true);
$order->SetDBFieldsFromHash($shipping_address);
$order->Update();
// 3. get shipping rates based on given address
$shipping_types_xml = '';
$shipping_types = $this->getOrderShippings($order);
// add available shipping types
foreach ($shipping_types as $shipping_type) {
$shipping_name = $shipping_type['ShippingName'];
$processable_shipping_index = array_search($shipping_name, $process_shippings);
if ($processable_shipping_index !== false) {
$shipping_types_xml .= '<result shipping-name="'.htmlspecialchars($shipping_name).'" address-id="'.$address_id.'">
<shipping-rate currency="USD">'.sprintf('%01.2f', $shipping_type['TotalCost']).'</shipping-rate>
<shippable>true</shippable>
</result>';
// remove available shipping type from processable list
unset($process_shippings[$processable_shipping_index]);
}
}
// add unavailable shipping types
foreach ($process_shippings as $shipping_name) {
$shipping_types_xml .= '<result shipping-name="'.htmlspecialchars($shipping_name).'" address-id="'.$address_id.'">
<shipping-rate currency="USD">0.00</shipping-rate>
<shippable>false</shippable>
</result>';
}
$shipping_types_xml = '<?xml version="1.0" encoding="UTF-8"?>
<merchant-calculation-results xmlns="http://checkout.google.com/schema/2">
<results>'.$shipping_types_xml.'</results>
</merchant-calculation-results>';
return $shipping_types_xml;
}
/**
* Places all information from google checkout into order (2nd step)
*
* @param kXMLNode $root_node
*/
function processNewOrderNotification(&$root_node)
{
// 1. extract data from xml
$search_nodes = Array (
'SHOPPING-CART:MERCHANT-PRIVATE-DATA',
'ORDER-ADJUSTMENT:SHIPPING:MERCHANT-CALCULATED-SHIPPING-ADJUSTMENT',
'BUYER-ID',
'GOOGLE-ORDER-NUMBER',
'BUYER-SHIPPING-ADDRESS',
'BUYER-BILLING-ADDRESS',
);
$user_address = Array ();
foreach ($search_nodes as $search_string) {
$found_node =& $root_node;
/* @var $found_node kXMLNode */
$search_string = explode(':', $search_string);
foreach ($search_string as $search_node) {
$found_node =& $found_node->FindChild($search_node);
}
$node_data = Array ();
if ($found_node->Children) {
$sub_node =& $found_node->firstChild;
/* @var $sub_node kXMLNode */
do {
$node_data[$sub_node->Name] = $sub_node->Data;
} while ( ($sub_node =& $sub_node->NextSibling()) );
}
switch ($found_node->Name) {
case 'MERCHANT-PRIVATE-DATA':
$order_id = $node_data['ORDER_ID'];
$session_id = $node_data['SESSION_ID'];
break;
case 'MERCHANT-CALCULATED-SHIPPING-ADJUSTMENT':
$shpipping_info = $node_data;
break;
case 'BUYER-ID':
$buyer_id = $found_node->Data;
break;
case 'GOOGLE-ORDER-NUMBER':
$google_order_number = $found_node->Data;
break;
case 'BUYER-SHIPPING-ADDRESS':
$user_address['Shipping'] = $node_data;
break;
case 'BUYER-BILLING-ADDRESS':
$user_address['Billing'] = $node_data;
break;
}
}
// 2. update shipping address in order
$order =& $this->Application->recallObject('ord', null, Array ('skip_autoload' => true));
/* @var $order OrdersItem */
$order->Load($order_id);
if (!$order->isLoaded()) {
return false;
}
// 2.1. this is 100% notification from google -> mark order with such payment type
$order->SetDBField('PaymentType', $this->Application->GetVar('payment_type_id'));
$this->parsed_responce = Array (
'GOOGLE-ORDER-NUMBER' => $google_order_number,
'BUYER-ID' => $buyer_id
);
// 2.2. save google checkout order information (maybe needed for future notification processing)
$order->SetDBField('GWResult1', serialize($this->parsed_responce));
$order->SetDBField('GoogleOrderNumber', $google_order_number);
// 2.3. set user-selected shipping type
$shipping_types = $this->getOrderShippings($order);
foreach ($shipping_types as $shipping_type) {
if ($shipping_type['ShippingName'] == $shpipping_info['SHIPPING-NAME']) {
$order->SetDBField('ShippingInfo', serialize(Array (1 => $shipping_type))); // minimal package number is 1
$order->SetDBField('ShippingCost', $shipping_type['TotalCost']); // set total shipping cost
break;
}
}
// 2.4. set full shipping & billing address
$address_mapping = Array (
'CONTACT-NAME' => 'To',
'COMPANY-NAME' => 'Company',
'EMAIL' => 'Email',
'PHONE' => 'Phone',
'FAX' => 'Fax',
'ADDRESS1' => 'Address1',
'ADDRESS2' => 'Address2',
'CITY' => 'City',
'REGION' => 'State',
'POSTAL-CODE' => 'Zip',
);
$cs_helper =& $this->Application->recallObject('CountryStatesHelper');
/* @var $cs_helper kCountryStatesHelper */
foreach ($user_address as $field_prefix => $address_details) {
foreach ($address_mapping as $src_field => $dst_field) {
$order->SetDBField($field_prefix.$dst_field, $address_details[$src_field]);
}
if (!$order->GetDBField($field_prefix.'Phone')) {
$order->SetDBField($field_prefix.'Phone', '-'); // required field
}
$order->SetDBField( $field_prefix.'Country', $cs_helper->getCountryIso($address_details['COUNTRY-CODE'], true) );
}
$order->SetDBField('OnHold', 1);
$order->SetDBField('Status', ORDER_STATUS_PENDING);
$order->Update();
// unlink order, that GoogleCheckout used from shopping cart on site
$sql = 'DELETE
FROM '.TABLE_PREFIX.'SessionData
WHERE VariableName = "ord_id" AND VariableValue = '.$order->GetID();
$this->Conn->Query($sql);
// simulate visiting shipping screen
$sql = 'UPDATE '.TABLE_PREFIX.'OrderItems
SET PackageNum = 1
WHERE OrderId = '.$order->GetID();
$this->Conn->Query($sql);
return false;
}
/**
* Saves risk information in order record (3rd step)
*
* @param kXMLNode $root_node
*/
function processRiskInformationNotification(&$root_node)
{
// 1. extract data from xml
$search_nodes = Array (
'GOOGLE-ORDER-NUMBER',
'RISK-INFORMATION',
);
foreach ($search_nodes as $search_string) {
$found_node =& $root_node;
/* @var $found_node kXMLNode */
$search_string = explode(':', $search_string);
foreach ($search_string as $search_node) {
$found_node =& $found_node->FindChild($search_node);
}
$node_data = Array ();
if ($found_node->Children) {
$sub_node =& $found_node->firstChild;
/* @var $sub_node kXMLNode */
do {
$node_data[$sub_node->Name] = $sub_node->Data;
} while ( ($sub_node =& $sub_node->NextSibling()) );
}
switch ($found_node->Name) {
case 'GOOGLE-ORDER-NUMBER':
$google_order_number = $found_node->Data;
break;
case 'RISK-INFORMATION':
$risk_information = $node_data;
unset( $risk_information['BILLING-ADDRESS'] );
break;
}
}
// 2. update shipping address in order
$order =& $this->Application->recallObject('ord', null, Array ('skip_autoload' => true));
/* @var $order OrdersItem */
$order->Load($google_order_number, 'GoogleOrderNumber');
if (!$order->isLoaded()) {
return false;
}
// 2.1. save risk information in order
$this->parsed_responce = unserialize($order->GetDBField('GWResult1'));
$this->parsed_responce = array_merge_recursive($this->parsed_responce, $risk_information);
$order->SetDBField('GWResult1', serialize($this->parsed_responce));
$order->Update();
return false;
}
/**
* Perform PREAUTH/SALE type transaction direct from php script wihtout redirecting to 3rd-party website
*
* @param Array $item_data
* @param Array $gw_params
* @return bool
*/
function DirectPayment($item_data, $gw_params)
{
$this->gwParams = $gw_params;
if ($gw_params['shipping_control'] == SHIPPING_CONTROL_PREAUTH) {
// when shipping control is Pre-Authorize -> do nothing and charge when admin approves order
return true;
}
$this->_chargeOrder($item_data);
return false;
}
/**
* Issue charge-order api call
*
* @param Array $item_data
* @return bool
*/
function _chargeOrder($item_data)
{
$charge_xml = ' <charge-order xmlns="http://checkout.google.com/schema/2" google-order-number="'.$item_data['GoogleOrderNumber'].'">
<amount currency="USD">'.sprintf('%.2f', $item_data['TotalAmount']).'</amount>
</charge-order>';
$root_node =& $this->executeAPICommand($charge_xml);
$this->parsed_responce = unserialize($item_data['GWResult1']);
if ($root_node->Name == 'REQUEST-RECEIVED') {
$this->parsed_responce['FINANCIAL-ORDER-STATE'] = 'CHARGING';
return true;
}
return false;
}
/**
* Perform SALE type transaction direct from php script wihtout redirecting to 3rd-party website
*
* @param Array $item_data
* @param Array $gw_params
* @return bool
*/
function Charge($item_data, $gw_params)
{
$this->gwParams = $gw_params;
if ($gw_params['shipping_control'] == SHIPPING_CONTROL_DIRECT) {
// when shipping control is Direct Payment -> do nothing and auto-charge on notification received
return true;
}
$this->_chargeOrder($item_data);
$order =& $this->Application->recallObject('ord.-item', null, Array ('skip_autoload' => true));
/* @var $order OrdersItem */
$order->Load($item_data['OrderId']);
if (!$order->isLoaded()) {
return false;
}
$order->SetDBField('OnHold', 1);
$order->Update();
return false;
}
/**
* Executes API command for order and returns result
*
* @param string $command_xml
* @return kXMLNode
*/
function &executeAPICommand($command_xml)
{
$submit_url = $this->gwParams['submit_url'].'/request/Merchant/'.$this->gwParams['merchant_id'];
$curl_helper =& $this->Application->recallObject('CurlHelper');
/* @var $curl_helper kCurlHelper */
$xml_helper =& $this->Application->recallObject('kXMLHelper');
/* @var $xml_helper kXMLHelper */
$curl_helper->SetPostData($command_xml);
$auth_options = Array (
CURLOPT_USERPWD => $this->gwParams['merchant_id'].':'.$this->gwParams['merchant_key'],
);
$curl_helper->setOptions($auth_options);
$xml_responce = $curl_helper->Send($submit_url);
$root_node =& $xml_helper->Parse($xml_responce);
/* @var $root_node kXMLNode */
return $root_node;
}
/**
* Marks order as pending, when it's google status becomes CHARGEABLE (4th step)
*
* @param kXMLNode $root_node
*/
function processOrderStateChangeNotification(&$root_node)
{
// 1. extract data from xml
$search_nodes = Array (
'GOOGLE-ORDER-NUMBER',
'NEW-FINANCIAL-ORDER-STATE',
'PREVIOUS-FINANCIAL-ORDER-STATE',
);
$order_state = Array ();
foreach ($search_nodes as $search_string) {
$found_node =& $root_node;
/* @var $found_node kXMLNode */
$search_string = explode(':', $search_string);
foreach ($search_string as $search_node) {
$found_node =& $found_node->FindChild($search_node);
}
switch ($found_node->Name) {
case 'GOOGLE-ORDER-NUMBER':
$google_order_number = $found_node->Data;
break;
case 'NEW-FINANCIAL-ORDER-STATE':
$order_state['new'] = $found_node->Data;
break;
case 'PREVIOUS-FINANCIAL-ORDER-STATE':
$order_state['old'] = $found_node->Data;
break;
}
}
// 2. update shipping address in order
$order =& $this->Application->recallObject('ord', null, Array ('skip_autoload' => true));
/* @var $order OrdersItem */
$order->Load($google_order_number, 'GoogleOrderNumber');
if (!$order->isLoaded()) {
return false;
}
$state_changed = ($order_state['old'] != $order_state['new']);
if ($state_changed) {
$order_charged = ($order_state['new'] == 'CHARGED') && ($order->GetDBField('Status') == ORDER_STATUS_PENDING);
$this->parsed_responce = unserialize($order->GetDBField('GWResult1'));
$this->parsed_responce['FINANCIAL-ORDER-STATE'] = $order_state['new'];
$order->SetDBField('GWResult1', serialize($this->parsed_responce));
if ($order_charged) {
// when using Pre-Authorize
$order->SetDBField('OnHold', 0);
}
$order->Update();
if ($order_charged) {
// when using Pre-Authorize
$order_eh =& $this->Application->recallObject('ord_EventHandler');
/* @var $order_eh OrdersEventHandler */
$order_eh->SplitOrder( new kEvent('ord:OnMassOrderApprove'), $order);
}
}
// update order record in "google_checkout_notify.php" only when such state change happens
$order_chargeable = ($order_state['new'] == 'CHARGEABLE') && $state_changed;
if ($order_chargeable) {
if ($this->gwParams['shipping_control'] == SHIPPING_CONTROL_PREAUTH) {
$order->SetDBField('OnHold', 0);
$order->Update();
}
$process_xml = '<process-order xmlns="http://checkout.google.com/schema/2" google-order-number="'.$order->GetDBField('GoogleOrderNumber').'"/>';
$root_node =& $this->executeAPICommand($process_xml);
}
return $order_chargeable;
}
/**
* Retrieves shipping types available for given order
*
* @param OrdersItem $order
* @return Array
*/
function getOrderShippings(&$order)
{
$weight_sql = 'IF(oi.Weight IS NULL, 0, oi.Weight * oi.Quantity)';
$query = ' SELECT
SUM(oi.Quantity) AS TotalItems,
SUM('.$weight_sql.') AS TotalWeight,
SUM(oi.Price * oi.Quantity) AS TotalAmount,
SUM(oi.Quantity) - SUM(IF(p.MinQtyFreePromoShipping > 0 AND p.MinQtyFreePromoShipping <= oi.Quantity, oi.Quantity, 0)) AS TotalItemsPromo,
SUM('.$weight_sql.') - SUM(IF(p.MinQtyFreePromoShipping > 0 AND p.MinQtyFreePromoShipping <= oi.Quantity, '.$weight_sql.', 0)) AS TotalWeightPromo,
SUM(oi.Price * oi.Quantity) - SUM(IF(p.MinQtyFreePromoShipping > 0 AND p.MinQtyFreePromoShipping <= oi.Quantity, oi.Price * oi.Quantity, 0)) AS TotalAmountPromo
FROM '.TABLE_PREFIX.'OrderItems oi
LEFT JOIN '.TABLE_PREFIX.'Products p ON oi.ProductId = p.ProductId
WHERE oi.OrderId = '.$order->GetID().' AND p.Type = 1';
$shipping_totals = $this->Conn->GetRow($query);
$this->Application->recallObject('ShippingQuoteEngine');
$quote_engine_collector =& $this->Application->recallObject('ShippingQuoteCollector');
/* @var $quote_engine_collector ShippingQuoteCollector */
$shipping_quote_params = Array(
'dest_country' => $order->GetDBField('ShippingCountry'),
'dest_state' => $order->GetDBField('ShippingState'),
'dest_postal' => $order->GetDBField('ShippingZip'),
'dest_city' => $order->GetDBField('ShippingCity'),
'dest_addr1' => '',
'dest_addr2' => '',
'dest_name' => 'user-' . $order->GetDBField('PortalUserId'),
'packages' => Array(
Array(
'package_key' => 'package1',
'weight' => $shipping_totals['TotalWeight'],
'weight_unit' => 'KG',
'length' => '',
'width' => '',
'height' => '',
'dim_unit' => 'IN',
'packaging' => 'BOX',
'contents' => 'OTR',
'insurance' => '0'
),
),
'amount' => $shipping_totals['TotalAmount'],
'items' => $shipping_totals['TotalItems'],
'limit_types' => serialize(Array ('ANY')),
'promo_params' => Array (
'items' => $shipping_totals['TotalItemsPromo'],
'amount' => $shipping_totals['TotalAmountPromo'],
'weight' => $shipping_totals['TotalWeightPromo'],
),
);
return $quote_engine_collector->GetShippingQuotes($shipping_quote_params);
}
/**
* Returns gateway responce from last operation
*
* @return string
*/
function getGWResponce()
{
return serialize($this->parsed_responce);
}
/**
* Informs payment gateway, that order has been shipped
*
* http://code.google.com/apis/checkout/developer/Google_Checkout_XML_API_Order_Level_Shipping.html#Deliver_Order
*
* @param Array $item_data
* @param Array $gw_params
* @return bool
*/
function OrderShipped($item_data, $gw_params)
{
$this->gwParams = $gw_params;
$shipping_info = unserialize($item_data['ShippingInfo']);
if (getArrayValue($shipping_info, 'Code')) {
$traking_carrier = '<carrier>'.$item_data['Code'].'</carrier>';
}
if ($item_data['ShippingTracking']) {
$tracking_data = '<tracking-data>'.$traking_carrier.'
<tracking-number>'.$item_data['ShippingTracking'].'</tracking-number>
</tracking-data>';
}
$ship_xml = ' <deliver-order xmlns="http://checkout.google.com/schema/2" google-order-number="'.$item_data['GoogleOrderNumber'].'">
'.$traking_data.'
<send-email>true</send-email>
</deliver-order>';
$root_node =& $this->executeAPICommand($ship_xml);
}
/**
* Informs payment gateway, that order has been declined
*
* @param Array $item_data
* @param Array $gw_params
* @return bool
*/
function OrderDeclined($item_data, $gw_params)
{
}
}
\ No newline at end of file
Index: branches/5.1.x/units/shipping_quote_engines/usps.php
===================================================================
--- branches/5.1.x/units/shipping_quote_engines/usps.php (revision 14358)
+++ branches/5.1.x/units/shipping_quote_engines/usps.php (revision 14359)
@@ -1,1325 +1,1334 @@
<?php
/**
* @version $Id$
* @package In-Commerce
* @copyright Copyright (C) 1997 - 2009 Intechnic. All rights reserved.
* @license Commercial License
* This software is protected by copyright law and international treaties.
* Unauthorized reproduction or unlicensed usage of the code of this program,
* or any portion of it may result in severe civil and criminal penalties,
* and will be prosecuted to the maximum extent possible under the law
* See http://www.in-portal.org/commercial-license for copyright notices and details.
*/
defined('FULL_PATH') or die('restricted access!');
define('MODULE_SHIPPING_USPS_TEXT_TITLE', 'United States Postal Service');
define('MODULE_SHIPPING_USPS_TEXT_DESCRIPTION', 'You will need to have registered an account with USPS. Click <a target="_blank" href="https://secure.shippingapis.com/registration/"><strong>HERE</strong></a> for registration details. USPS expects you to use pounds as weight measure for your products.');
define('MODULE_SHIPPING_USPS_TEXT_ERROR', 'An error occured with the USPS shipping calculations.<br>If you prefer to use USPS as your shipping method, please contact the store owner.');
define('MODULE_SHIPPING_USPS_TEXT_DAY', 'Day');
define('MODULE_SHIPPING_USPS_TEXT_DAYS', 'Days');
define('MODULE_SHIPPING_USPS_TEXT_WEEKS', 'Weeks');
define('MODULE_SHIPPING_USPS_STATUS', 'True'); // Do you want to offer USPS shipping?
define('MODULE_SHIPPING_USPS_SERVER', 'production'); // An account at USPS is needed to use the Production server // production othervise value may be 'test'
define('MODULE_SHIPPING_USPS_HANDLING', '0'); // Handling fee for this shipping method
define('MODULE_SHIPPING_USPS_TAX_CLASS', '0'); // Use the following tax class on the shipping fee
define('MODULE_SHIPPING_USPS_ZONE', '0'); // If a zone is selected, only enable this shipping method for that zone.
define('MODULE_SHIPPING_USPS_SORT_ORDER', '0'); // Sort order of display.
define('MODULE_SHIPPING_USPS_TYPES', 'PRIORITY, PARCEL'); // EXPRESS, FIRST CLASS, BMP, MEDIA 'Select the domestic services to be offered:
define('MODULE_SHIPPING_USPS_TYPES_INTL', 'EXPRESS MAIL INTERNATIONAL (EMS), EXPRESS MAIL INT, EXPRESS MAIL INT FLAT RATE ENV, PRIORITY MAIL INT, PRIORITY MAIL INT FLAT RATE ENV, PRIORITY MAILINT FLAT RATE BOX, FIRST-CLASS MAIL INT');// 'GLOBAL EXPRESS, GLOBAL EXPRESS NON-DOC RECT, GLOBAL EXPRESS NON-DOC NON-RECT, Select the international services to be offered:
define('MODULE_SHIPPING_USPS_OPTIONS', 'Display weight, Display transit time'); //
//configuration values for insurance
define('MODULE_SHIPPING_USPS_INS1', '1.65');// 'US/Canada insurance for totals $.01-$50.00
define('MODULE_SHIPPING_USPS_INS2', '2.05');// 'US/Canada insurance for totals $50.01-$100
define('MODULE_SHIPPING_USPS_INS3', '2.45');// 'US/Canada insurance for totals $100.01-$200
define('MODULE_SHIPPING_USPS_INS4', '4.60');// 'US/Canada insurance for totals $200.01-$300
define('MODULE_SHIPPING_USPS_INS5', '.90');// 'US/Canada insurance for every $100 over $300 (add)
define('MODULE_SHIPPING_USPS_INS6', '2.40');// 'International insurance for totals $.01-$50.00
define('MODULE_SHIPPING_USPS_INS7', '3.30');// 'International insurance for totals $50.01-$100
define('MODULE_SHIPPING_USPS_INS8', '4.20');// 'International insurance for totals $100.01-$200
define('MODULE_SHIPPING_USPS_INS9', '5.10');// 'International insurance for totals $200.01-$300
define('MODULE_SHIPPING_USPS_INS10', '.90');// 'International insurance for every $100 over $300 (add)
define('MODULE_SHIPPING_USPS_INSURE', 'True');// 'Insure packages shipped by USPS?
define('MODULE_SHIPPING_USPS_INSURE_TAX', 'True');// 'Insure tax on packages shipped by USPS?
-define('USPS_LOG_FILE', WRITEABLE .'/user_files/usps.log');
-
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 = '';
+
function USPS()
{
parent::kBase();
+ $this->logFilePath = (defined('RESTRICTED') ? RESTRICTED : WRITEABLE . '/user_files') . '/usps.log';
+
// EXPRESS, FIRST CLASS, PRIORITY, PARCEL, BMP, MEDIA
$this->types = Array(
'EXPRESS' => 'Express Mail',
'FIRST CLASS' => 'First Class Mail',
'PRIORITY' => 'Priority Mail',
'PARCEL' => 'Parcel Post',
'BPM' => 'Bound Printed Matter',
'MEDIA' => 'Media Mail'
);
$this->intl_types = Array(
// 'GLOBAL EXPRESS' => 'Global Express Guaranteed',
// 'GLOBAL EXPRESS NON-DOC RECT' => 'Global Express Guaranteed Non-Document Rectangular',
// 'GLOBAL EXPRESS NON-DOC NON-RECT' => 'Global Express Guaranteed Non-Document Non-Rectangular',
'EXPRESS MAIL INT' => 'Express Mail International (EMS)',
'EXPRESS MAIL INT FLAT RATE ENV' => 'Express Mail International (EMS) Flat Rate Envelope',
'PRIORITY MAIL INT' => 'Priority Mail International',
'PRIORITY MAIL INT FLAT RATE ENV' => 'Priority Mail International Flat Rate Envelope',
'PRIORITY MAIL INT FLAT RATE BOX' => 'Priority Mail International Flat Rate Box',
'FIRST-CLASS MAIL INT' => 'First-Class Mail International'
);
// get 2-symbol country code
$country = $this->Application->ConfigValue('Comm_Shipping_Country');
if ($country != '') {
$this->shipping_origin_country = $this->GetUSPSCountry($country, '');
}
$contact_name = trim($this->_prepare_xml_param($this->Application->ConfigValue('Comm_Contacts_Name')));
$split_pos = strpos($contact_name, ' ');
if ($split_pos === false) {
$this->store_first_name = $contact_name;
$this->store_last_name = '';
} else {
$this->store_first_name = substr($contact_name, 0, $split_pos);
$this->store_last_name = trim(substr($contact_name, $split_pos));
}
$this->company_name = $this->_prepare_xml_param($this->Application->ConfigValue('Comm_CompanyName'));
$this->store_name = $this->_prepare_xml_param($this->Application->ConfigValue('Comm_StoreName'));
$this->store_address1 = $this->_prepare_xml_param($this->Application->ConfigValue('Comm_Shipping_AddressLine1'));
$this->store_address2 = $this->_prepare_xml_param($this->Application->ConfigValue('Comm_Shipping_AddressLine2'));
if ($this->store_address2 == '') {
$this->store_address2 = $this->store_address1;
$this->store_address1 = '';
}
$this->store_city = $this->_prepare_xml_param($this->Application->ConfigValue('Comm_Shipping_City'));
$this->store_state = $this->_prepare_xml_param($this->Application->ConfigValue('Comm_Shipping_State'));
$zip = $this->_prepare_xml_param($this->Application->ConfigValue('Comm_Shipping_ZIP'));
$this->store_zip5 = substr($zip, 0, 5);
$this->store_zip4 = trim(substr($zip, 6), '-');
$this->store_phone = $this->_prepare_xml_param($this->Application->ConfigValue('Comm_Contacts_Phone'));
// get username and password fron config.
$a_params = $this->LoadParams();
$this->usps_userid = $a_params['AccountLogin'];
// Note by Erik: DO NOT CHANGE THIS ARRAY. It's values are sent to USPS service and any changes may impact class main functionality.
$this->countries = array(
'AF' => 'Afghanistan',
'AL' => 'Albania',
'DZ' => 'Algeria',
'AD' => 'Andorra',
'AO' => 'Angola',
'AI' => 'Anguilla',
'AG' => 'Antigua and Barbuda',
'AR' => 'Argentina',
'AM' => 'Armenia',
'AW' => 'Aruba',
'AU' => 'Australia',
'AT' => 'Austria',
'AZ' => 'Azerbaijan',
'BS' => 'Bahamas',
'BH' => 'Bahrain',
'BD' => 'Bangladesh',
'BB' => 'Barbados',
'BY' => 'Belarus',
'BE' => 'Belgium',
'BZ' => 'Belize',
'BJ' => 'Benin',
'BM' => 'Bermuda',
'BT' => 'Bhutan',
'BO' => 'Bolivia',
'BA' => 'Bosnia-Herzegovina',
'BW' => 'Botswana',
'BR' => 'Brazil',
'VG' => 'British Virgin Islands',
'BN' => 'Brunei Darussalam',
'BG' => 'Bulgaria',
'BF' => 'Burkina Faso',
'MM' => 'Burma',
'BI' => 'Burundi',
'KH' => 'Cambodia',
'CM' => 'Cameroon',
'CA' => 'Canada',
'CV' => 'Cape Verde',
'KY' => 'Cayman Islands',
'CF' => 'Central African Republic',
'TD' => 'Chad',
'CL' => 'Chile',
'CN' => 'China',
'CX' => 'Christmas Island (Australia)',
'CC' => 'Cocos Island (Australia)',
'CO' => 'Colombia',
'KM' => 'Comoros',
'CG' => 'Congo (Brazzaville),Republic of the',
'ZR' => 'Congo, Democratic Republic of the',
'CK' => 'Cook Islands (New Zealand)',
'CR' => 'Costa Rica',
'CI' => 'Cote d\'Ivoire (Ivory Coast)',
'HR' => 'Croatia',
'CU' => 'Cuba',
'CY' => 'Cyprus',
'CZ' => 'Czech Republic',
'DK' => 'Denmark',
'DJ' => 'Djibouti',
'DM' => 'Dominica',
'DO' => 'Dominican Republic',
'TP' => 'East Timor (Indonesia)',
'EC' => 'Ecuador',
'EG' => 'Egypt',
'SV' => 'El Salvador',
'GQ' => 'Equatorial Guinea',
'ER' => 'Eritrea',
'EE' => 'Estonia',
'ET' => 'Ethiopia',
'FK' => 'Falkland Islands',
'FO' => 'Faroe Islands',
'FJ' => 'Fiji',
'FI' => 'Finland',
'FR' => 'France',
'GF' => 'French Guiana',
'PF' => 'French Polynesia',
'GA' => 'Gabon',
'GM' => 'Gambia',
'GE' => 'Georgia, Republic of',
'DE' => 'Germany',
'GH' => 'Ghana',
'GI' => 'Gibraltar',
'GB' => 'Great Britain and Northern Ireland',
'GR' => 'Greece',
'GL' => 'Greenland',
'GD' => 'Grenada',
'GP' => 'Guadeloupe',
'GT' => 'Guatemala',
'GN' => 'Guinea',
'GW' => 'Guinea-Bissau',
'GY' => 'Guyana',
'HT' => 'Haiti',
'HN' => 'Honduras',
'HK' => 'Hong Kong',
'HU' => 'Hungary',
'IS' => 'Iceland',
'IN' => 'India',
'ID' => 'Indonesia',
'IR' => 'Iran',
'IQ' => 'Iraq',
'IE' => 'Ireland',
'IL' => 'Israel',
'IT' => 'Italy',
'JM' => 'Jamaica',
'JP' => 'Japan',
'JO' => 'Jordan',
'KZ' => 'Kazakhstan',
'KE' => 'Kenya',
'KI' => 'Kiribati',
'KW' => 'Kuwait',
'KG' => 'Kyrgyzstan',
'LA' => 'Laos',
'LV' => 'Latvia',
'LB' => 'Lebanon',
'LS' => 'Lesotho',
'LR' => 'Liberia',
'LY' => 'Libya',
'LI' => 'Liechtenstein',
'LT' => 'Lithuania',
'LU' => 'Luxembourg',
'MO' => 'Macao',
'MK' => 'Macedonia, Republic of',
'MG' => 'Madagascar',
'MW' => 'Malawi',
'MY' => 'Malaysia',
'MV' => 'Maldives',
'ML' => 'Mali',
'MT' => 'Malta',
'MQ' => 'Martinique',
'MR' => 'Mauritania',
'MU' => 'Mauritius',
'YT' => 'Mayotte (France)',
'MX' => 'Mexico',
'MD' => 'Moldova',
'MC' => 'Monaco (France)',
'MN' => 'Mongolia',
'MS' => 'Montserrat',
'MA' => 'Morocco',
'MZ' => 'Mozambique',
'NA' => 'Namibia',
'NR' => 'Nauru',
'NP' => 'Nepal',
'NL' => 'Netherlands',
'AN' => 'Netherlands Antilles',
'NC' => 'New Caledonia',
'NZ' => 'New Zealand',
'NI' => 'Nicaragua',
'NE' => 'Niger',
'NG' => 'Nigeria',
'KP' => 'North Korea (Korea, Democratic People\'s Republic of)',
'NO' => 'Norway',
'OM' => 'Oman',
'PK' => 'Pakistan',
'PA' => 'Panama',
'PG' => 'Papua New Guinea',
'PY' => 'Paraguay',
'PE' => 'Peru',
'PH' => 'Philippines',
'PN' => 'Pitcairn Island',
'PL' => 'Poland',
'PT' => 'Portugal',
'QA' => 'Qatar',
'RE' => 'Reunion',
'RO' => 'Romania',
'RU' => 'Russia',
'RW' => 'Rwanda',
'SH' => 'Saint Helena',
'KN' => 'Saint Kitts (St. Christopher and Nevis)',
'LC' => 'Saint Lucia',
'PM' => 'Saint Pierre and Miquelon',
'VC' => 'Saint Vincent and the Grenadines',
'SM' => 'San Marino',
'ST' => 'Sao Tome and Principe',
'SA' => 'Saudi Arabia',
'SN' => 'Senegal',
'YU' => 'Serbia-Montenegro',
'SC' => 'Seychelles',
'SL' => 'Sierra Leone',
'SG' => 'Singapore',
'SK' => 'Slovak Republic',
'SI' => 'Slovenia',
'SB' => 'Solomon Islands',
'SO' => 'Somalia',
'ZA' => 'South Africa',
'GS' => 'South Georgia (Falkland Islands)',
'KR' => 'South Korea (Korea, Republic of)',
'ES' => 'Spain',
'LK' => 'Sri Lanka',
'SD' => 'Sudan',
'SR' => 'Suriname',
'SZ' => 'Swaziland',
'SE' => 'Sweden',
'CH' => 'Switzerland',
'SY' => 'Syrian Arab Republic',
'TW' => 'Taiwan',
'TJ' => 'Tajikistan',
'TZ' => 'Tanzania',
'TH' => 'Thailand',
'TG' => 'Togo',
'TK' => 'Tokelau (Union) Group (Western Samoa)',
'TO' => 'Tonga',
'TT' => 'Trinidad and Tobago',
'TN' => 'Tunisia',
'TR' => 'Turkey',
'TM' => 'Turkmenistan',
'TC' => 'Turks and Caicos Islands',
'TV' => 'Tuvalu',
'UG' => 'Uganda',
'UA' => 'Ukraine',
'AE' => 'United Arab Emirates',
'UY' => 'Uruguay',
'UZ' => 'Uzbekistan',
'VU' => 'Vanuatu',
'VA' => 'Vatican City',
'VE' => 'Venezuela',
'VN' => 'Vietnam',
'WF' => 'Wallis and Futuna Islands',
'WS' => 'Western Samoa',
'YE' => 'Yemen',
'ZM' => 'Zambia',
'ZW' => 'Zimbabwe'
);
$this->countryinsure = array(
'AF' => 0,
'AL' => 0,
'DZ' => 2185,
'AD' => 5000,
'AO' => 0,
'AI' => 415,
'AG' => 60,
'AR' => 5000,
'AM' => 1350,
'AW' => 830,
'AU' => 3370,
'AT' => 5000,
'AZ' => 5000,
'BS' => 2795,
'BH' => 0,
'BD' => 5000,
'BB' => 220,
'BY' => 1323,
'BE' => 5000,
'BZ' => 1600,
'BJ' => 170,
'BM' => 440,
'BT' => 440,
'BO' => 0,
'BA' => 5000,
'BW' => 145,
'BR' => 5000,
'VG' => 165,
'BN' => 4405,
'BG' => 1030,
'BF' => 530,
'MM' => 4045,
'BI' => 790,
'KH' => 0,
'CM' => 5000,
'CA' => 675,
'CV' => 0,
'KY' => 0,
'CF' => 4405,
'TD' => 440,
'CL' => 0,
'CN' => 1130,
'CX' => 3370,
'CC' => 3370,
'CO' => 0,
'KM' => 690,
'CG' => 1685,
'ZR' => 0,
'CK' => 980,
'CR' => 0,
'CI' => 5000,
'HR' => 5000,
'CU' => 0,
'CY' => 5000,
'CZ' => 5000,
'DK' => 5000,
'DJ' => 880,
'DM' => 0,
'DO' => 0,
'TP' => 0,
'EC' => 0,
'EG' => 1685,
'SV' => 0,
'GQ' => 0,
'ER' => 0,
'EE' => 2020,
'ET' => 1000,
'FK' => 510,
'FO' => 5000,
'FJ' => 600,
'FI' => 5000,
'FR' => 5000,
'GF' => 5000,
'PF' => 1015,
'GA' => 485,
'GM' => 2575,
'GE' => 1350,
'DE' => 5000,
'GH' => 5000,
'GI' => 5000,
'GB' => 857,
'GR' => 5000,
'GL' => 5000,
'GD' => 350,
'GP' => 5000,
'GT' => 0,
'GN' => 875,
'GW' => 21,
'GY' => 10,
'HT' => 0,
'HN' => 0,
'HK' => 5000,
'HU' => 5000,
'IS' => 5000,
'IN' => 2265,
'ID' => 0,
'IR' => 0,
'IQ' => 0,
'IE' => 5000,
'IL' => 0,
'IT' => 5000,
'JM' => 0,
'JP' => 5000,
'JO' => 0,
'KZ' => 5000,
'KE' => 815,
'KI' => 0,
'KW' => 1765,
'KG' => 1350,
'LA' => 0,
'LV' => 1350,
'LB' => 440,
'LS' => 440,
'LR' => 440,
'LY' => 0,
'LI' => 5000,
'LT' => 5000,
'LU' => 5000,
'MO' => 4262,
'MK' => 2200,
'MG' => 675,
'MW' => 50,
'MY' => 1320,
'MV' => 0,
'ML' => 950,
'MT' => 5000,
'MQ' => 5000,
'MR' => 635,
'MU' => 270,
'YT' => 5000,
'MX' => 0,
'MD' => 1350,
'MC' => 5000,
'MN' => 440,
'MS' => 2200,
'MA' => 5000,
'MZ' => 0,
'NA' => 4405,
'NR' => 220,
'NP' => 0,
'NL' => 5000,
'AN' => 830,
'NC' => 1615,
'NZ' => 980,
'NI' => 440,
'NE' => 810,
'NG' => 205,
'KP' => 0,
'NO' => 0,
'OM' => 575,
'PK' => 270,
'PA' => 0,
'PG' => 445,
'PY' => 0,
'PE' => 0,
'PH' => 270,
'PN' => 0,
'PL' => 1350,
'PT' => 5000,
'QA' => 2515,
'RE' => 5000,
'RO' => 5000,
'RU' => 5000,
'RW' => 0,
'SH' => 170,
'KN' => 210,
'LC' => 400,
'PM' => 5000,
'VC' => 130,
'SM' => 5000,
'ST' => 440,
'SA' => 0,
'SN' => 865,
'YU' => 5000,
'SC' => 0,
'SL' => 0,
'SG' => 4580,
'SK' => 5000,
'SI' => 4400,
'SB' => 0,
'SO' => 440,
'ZA' => 1760,
'GS' => 510,
'KR' => 5000,
'ES' => 5000,
'LK' => 35,
'SD' => 0,
'SR' => 535,
'SZ' => 560,
'SE' => 5000,
'CH' => 5000,
'SY' => 3080,
'TW' => 1350,
'TJ' => 1350,
'TZ' => 230,
'TH' => 1350,
'TG' => 2190,
'TK' => 295,
'TO' => 515,
'TT' => 930,
'TN' => 2200,
'TR' => 880,
'TM' => 675,
'TC' => 0,
'TV' => 4715,
'UG' => 0,
'UA' => 5000,
'AE' => 5000,
'UY' => 0,
'UZ' => 5000,
'VU' => 0,
'VA' => 5000,
'VE' => 0,
'VN' => 0,
'WF' => 1615,
'WS' => 295,
'YE' => 0,
'ZM' => 540,
'ZW' => 600,
'US' => 5000
);
}
function SetInsurance()
{
$this->insurance_cost = 0;
// Insurance module by Kevin Shelton
// divide the value of the order among the packages based on the order total or subtotal depending on whether or not you have configured to insure tax
$shipping_weight = $this->order['ShippingWeight'];
$shipping_num_boxes = $this->order['ShippingNumBoxes'];
$costperpkg = $this->order['SubTotal'] / $shipping_num_boxes;
// retrieve the maximum allowed insurance for the destination country and if the package value exceeds it then set package value to the maximum allowed
$maxins = $this->countryinsure[$this->order['ShippingCountry']];
if ($costperpkg > $maxins) $costperpkg = $maxins;
// if insurance not allowed for destination or insurance is turned off add nothing to shipping cost
if (($maxins == 0) || (MODULE_SHIPPING_USPS_INSURE == 'False')) {
$insurance = 0;
}
// US and Canada share the same insurance calculation (though not the same maximum)
else if (($this->order['ShippingCountry'] == 'US') || ($this->order['ShippingCountry'] == 'CA'))
{
if ($costperpkg<=50) {
$insurance=MODULE_SHIPPING_USPS_INS1;
}
else if ($costperpkg<=100) {
$insurance=MODULE_SHIPPING_USPS_INS2;
}
else if ($costperpkg<=200) {
$insurance=MODULE_SHIPPING_USPS_INS3;
}
else if ($costperpkg<=300) {
$insurance=MODULE_SHIPPING_USPS_INS4;
}
else {
$insurance = MODULE_SHIPPING_USPS_INS4 + ((ceil($costperpkg/100) -3) * MODULE_SHIPPING_USPS_INS5);
}
}
// if insurance allowed and is not US or Canada then calculate international insurance
else {
if ($costperpkg<=50) {
$insurance=MODULE_SHIPPING_USPS_INS6;
}
else if ($costperpkg<=100) {
$insurance=MODULE_SHIPPING_USPS_INS7;
}
else if ($costperpkg<=200) {
$insurance=MODULE_SHIPPING_USPS_INS8;
}
else if ($costperpkg<=300) {
$insurance=MODULE_SHIPPING_USPS_INS9;
}
else {
$insurance = MODULE_SHIPPING_USPS_INS9 + ((ceil($costperpkg/100) - 3) * MODULE_SHIPPING_USPS_INS10);
}
}
// usps doesnt accept zero weight
$shipping_weight = ($shipping_weight < 0.1 ? 0.1 : $shipping_weight);
$shipping_pounds = floor ($shipping_weight);
$shipping_ounces = round(16 * ($shipping_weight - floor($shipping_weight)));
$this->_setWeight($shipping_pounds, $shipping_ounces);
// Added by Kevin Chen (kkchen@uci.edu); Fixes the Parcel Post Bug July 1, 2004
// Refer to http://www.usps.com/webtools/htm/Domestic-Rates.htm documentation
// Thanks Ryan
if($shipping_pounds > 35 || ($shipping_pounds == 0 && $shipping_ounces < 6)){
$this->_setMachinable('False');
}
else{
$this->_setMachinable('True');
}
$this->insurance_cost = $insurance;
// End Kevin Chen July 1, 2004
}
function _setService($service)
{
$this->service = $service;
}
function _setWeight($pounds, $ounces=0)
{
$this->pounds = $pounds;
$this->ounces = $ounces;
}
function _setContainer($container)
{
$this->container = $container;
}
function _setSize($size)
{
$this->size = $size;
}
function _setMachinable($machinable)
{
$this->machinable = $machinable;
}
function PhoneClean($phone)
{
$res = preg_replace('/[(]|[)]|[\-]|[ ]|[#]|[\.]|[a-z](.*)|[A-Z](.*)/g', '', $phone);
if ( strlen($res) > 10 ) {
$res = substr($res, 0, 10);
}
return $res != '' ? $res : $phone;
}
function GetQuote($method = '')
{
if ( isset($this->types[$method]) || in_array($method, $this->intl_types)) {
$this->_setService($method);
}
$this -> _setContainer('None');
$this -> _setSize('REGULAR');
$this -> SetInsurance(); // ???
if ($this->order['ShippingCountry'] == $this->shipping_origin_country) {
$request='<?xml version="1.0"?>';
// PASSWORD="'.$this->usps_password.'"
$request.= '<RateV3Request USERID="'.$this->usps_userid.'">';
$services_count = 0;
if (isset($this->service)) {
$this->types = array($this->service => $this->types[$this->service]);
}
$dest_zip = str_replace(' ', '', $this->order['ShippingZip']);
$dest_zip = substr($dest_zip, 0, 5);
reset($this->types);
$allowed_types = explode(", ", MODULE_SHIPPING_USPS_TYPES);
while (list($key, $value) = each($this->types))
{
if ( !in_array($key, $allowed_types) ) continue;
$request .= '<Package ID="'.$services_count.'">'.
'<Service>'.$key.'</Service>'.
'<ZipOrigination>'.$this->store_zip5.'</ZipOrigination>'.
'<ZipDestination>'.$dest_zip.'</ZipDestination>'.
'<Pounds>'.$this->pounds.'</Pounds>'.
'<Ounces>'.$this->ounces.'</Ounces>'.
'<Size>'.$this->size.'</Size>'.
'<Machinable>'.$this->machinable.'</Machinable>'.
'</Package>';
$services_count++;
}
$request .= '</RateV3Request>';
$api_query = 'RateV3';
}
else {
$request = '<IntlRateRequest USERID="'.$this->usps_userid.'">'.
'<Package ID="0">'.
'<Pounds>'.$this->pounds.'</Pounds>'.
'<Ounces>'.$this->ounces.'</Ounces>'.
'<MailType>Package</MailType>'.
'<Country>'.$this->countries[$this->order['ShippingCountry']].'</Country>'.
'</Package>'.
'</IntlRateRequest>';
$api_query = 'IntlRate';
}
$request = 'API='.$api_query.'&XML=' . urlencode($request);
$body = $this->PostQuery($request);
$body = str_replace(chr(146), '', $body); // for bad `
// check for errors
if (strpos($body, '<Error>') !== false) {
$errors = Array ();
preg_match_all('/<Number>(.*?)<\/Number>/s', $body, $error_numbers);
preg_match_all('/<Description>(.*?)<\/Description>/s', $body, $error_descriptions);
foreach ($error_numbers[1] as $index => $error_number) {
$errors[$index] = $error_descriptions[1][$index];
if ($this->Application->isDebugMode()) {
$errors[$index] .= ' (' . $error_number . ')';
}
}
$errors = array_unique($errors); // we may have same errors on many packages, so don't show duplicates
return Array('error' => implode('<br/>', $errors));
}
// parse response
$xml_helper =& $this->Application->recallObject('kXMLHelper');
/* @var $xml_helper kXMLHelper */
$root_node =& $xml_helper->Parse($body);
/* @var $root_node kXMLNode */
$rates = Array();
// Domestic shipping
if ($this->order['ShippingCountry'] == $this->shipping_origin_country) {
$i = 0;
$postage_node =& $root_node->FindChild('Package');
do {
// $parcel_node =& $postage_node->firstChild;
$service = $postage_node->FindChildValue('MailService');
if ( $service != '' ) {
$i++;
$rates[$i] = Array();
$rates[$i]['Title'] = $service;
$rates[$i]['Rate'] = $this->insurance_cost + $postage_node->FindChildValue('Rate');
}
}
while ( $postage_node =& $postage_node->NextSibling());
}
else {
// for International Rates !!!
$allowed_types = array();
foreach( explode(", ", MODULE_SHIPPING_USPS_TYPES_INTL) as $value ) {
$allowed_types[$value] = $this->intl_types[$value];
}
$i = 0;
$service_node =& $root_node->FindChild('Service');
do {
$service = trim($service_node->FindChildValue('SvcDescription'));
if( !in_array($service, $allowed_types) ) continue;
$i++;
if ( $service_node->FindChildValue('MaxWeight') >= $this->pounds ) {
$rates[$i] = Array();
$rates[$i]['Title'] = $service;
$rates[$i]['MaxDimensions'] = $service_node->FindChildValue('MaxDimensions');
$rates[$i]['MaxWeight'] = $service_node->FindChildValue('MaxWeight');
$rates[$i]['SvcCommitments'] = $service_node->FindChildValue('SvcCommitments');
$rates[$i]['Rate'] = $this->insurance_cost + $service_node->FindChildValue('Postage');
}
}
while ( $service_node =& $service_node->NextSibling());
}
// print_r($rates);
// die('here');
return $rates;
}
function PostOrder()
{
$request='';
$base_request = '';
$this->SetInsurance();
// $this->order['ShippingCountry'] = $this->GetUSPSCountry($this->order['ShippingCountry']);
// Domestic Order
if ($this->order['ShippingCountry'] == $this->shipping_origin_country) {
// $dest_zip = str_replace(' ', '', $this->order['ShippingZip5']);
$this->order['ShippingZip5'] = substr($this->order['ShippingZip5'], 0, 5);
$WeightInOunces = floor($this->pounds * 16 + $this->ounces);
$base_request ='
<Option>1</Option>
<ImageParameters></ImageParameters>
<FromName>'.$this->store_name.'</FromName>
<FromFirm>'.$this->company_name.'</FromFirm>
<FromAddress1>'.$this->store_address1.'</FromAddress1>
<FromAddress2>'.$this->store_address2.'</FromAddress2>
<FromCity>'.$this->store_city.'</FromCity>
<FromState>'.$this->store_state.'</FromState>
<FromZip5>'.$this->store_zip5.'</FromZip5>
<FromZip4>'.$this->store_zip4.'</FromZip4>
<ToName>'.$this->order['FirstName'].' '.$this->order['LastName'].'</ToName>
<ToFirm>'.$this->order['ShippingCompany'].'</ToFirm>
<ToAddress1>'.$this->order['ShippingAddress2'].'</ToAddress1>
<ToAddress2>'.$this->order['ShippingAddress1'].'</ToAddress2>
<ToCity>'.$this->order['ShippingCity'].'</ToCity>
<ToState>'.$this->order['ShippingState'].'</ToState>
<ToZip5>'.$this->order['ShippingZip5'].'</ToZip5>
<ToZip4>'.$this->order['ShippingZip4'].'</ToZip4>
<WeightInOunces>'.$WeightInOunces.'</WeightInOunces>
<ServiceType>'.$this->order['ShippingService'].'</ServiceType>
<ImageType>PDF</ImageType>
<LabelDate>'.date('m/d/Y',time()).'</LabelDate>
<CustomerRefNo></CustomerRefNo>
<AddressServiceRequested></AddressServiceRequested>
<SenderName></SenderName><SenderEMail></SenderEMail>
<RecipientName></RecipientName>
<RecipientEMail></RecipientEMail>
';
$api_query = 'DeliveryConfirmationV3';
$xml_request = 'DeliveryConfirmationV3.0Request';
}
else {
// International Order(s)
$shipping_service = strtolower($this->order['ShippingService']);
$base_request = '<Option/>
<ImageParameters/>
<FromFirstName>'.$this->store_first_name.'</FromFirstName>
<FromLastName>'.$this->store_last_name.'</FromLastName>
<FromFirm>'.$this->company_name.'</FromFirm>
<FromAddress1>'.$this->store_address1.'</FromAddress1>
<FromAddress2>'.$this->store_address2.'</FromAddress2>
<FromCity>'.$this->store_city.'</FromCity>
<FromState>'.$this->store_state.'</FromState>
<FromZip5>'.$this->store_zip5.'</FromZip5>
<FromPhone>'.$this->PhoneClean($this->store_phone).'</FromPhone>
<ToName>'.$this->order['FirstName'].' '.$this->order['LastName'].'</ToName>
<ToFirm>'.$this->order['ShippingCompany'].'</ToFirm>
<ToAddress1></ToAddress1>
<ToAddress2>'.$this->order['ShippingAddress2'].'</ToAddress2>
<ToAddress3>'.$this->order['ShippingAddress1'].'</ToAddress3>
<ToCity>'.$this->order['ShippingCity'].'</ToCity>';
if ( $this->order['ShippingProvince'] != '' ) {
$base_request.='
<ToProvince>'.$this->order['ShippingProvince'].'</ToProvince>';
}
$base_request.='
<ToCountry>'.$this->countries[$this->order['ShippingCountry']].'</ToCountry>
<ToPostalCode>'.$this->order['ShippingZip'].'</ToPostalCode>
<ToPOBoxFlag>N</ToPOBoxFlag>
<ToPhone>'.$this->PhoneClean($this->order['ShippingPhone']).'</ToPhone>
<ToFax>'.$this->PhoneClean($this->order['ShippingFax']).'</ToFax>
<ToEmail>'.$this->order['Email'].'</ToEmail>
<ShippingContents>';
// add items
foreach ( $this->order['Items'] as $k => $value ) {
$base_request.='
<ItemDetail>
<Description>Computer Parts</Description>
<Quantity>'.$value['Qty'].'</Quantity>
<Value>'.($value['Price'] * $value['Qty']).'</Value>
<NetPounds>'.$value['NetPounds'].'</NetPounds>
<NetOunces>'.$value['NetOunces'].'</NetOunces>
<HSTariffNumber>123456</HSTariffNumber>
<CountryOfOrigin>United States</CountryOfOrigin>
</ItemDetail>';
}
// end add items
$base_request.='
</ShippingContents>
<GrossPounds>'.$this->pounds.'</GrossPounds>
<GrossOunces>'.$this->ounces.'</GrossOunces>
<ContentType>MERCHANDISE</ContentType>
<Agreement>Y</Agreement>
<InvoiceNumber>'.$this->order['InvoiceNumber'].'</InvoiceNumber>
<ImageType>PDF</ImageType>
<ImageLayout>ALLINONEFILE</ImageLayout>
<LabelDate>'.date('m/d/Y',time()).'</LabelDate>
';
if (strpos($shipping_service, 'express') !== false) {
$xml_request = 'ExpressMailIntlRequest';
$api_query = 'ExpressMailIntl';
}
elseif (strpos($shipping_service, 'priority') !== false) {
$xml_request = 'PriorityMailIntlRequest';
$api_query = 'PriorityMailIntl';
}
else {
$xml_request = 'FirstClassMailIntlRequest';
$api_query = 'FirstClassMailIntl';
}
}
$request.= '<'.$xml_request.' USERID="'.$this->usps_userid.'">';
$request.= $base_request;
$request.= '</'.$xml_request.'>';
// die($request);
$request = 'API='.$api_query.'&XML='.urlencode($request);
$body = $this->PostQuery($request, 1);
// check for errors
if (strpos($body, '<Error>') !== false) {
$errors = Array ();
preg_match_all('/<Number>(.*?)<\/Number>/s', $body, $error_numbers);
preg_match_all('/<Description>(.*?)<\/Description>/s', $body, $error_descriptions);
foreach ($error_numbers[1] as $index => $error_number) {
$errors[$index] = Array ('error_number' => $error_number, 'error_description' => $error_descriptions[1][$index]);
}
// TODO: find a way to return other error messages in same package as well
return $errors[0];
}
// parse response
$xml_helper =& $this->Application->recallObject('kXMLHelper');
$root_node =& $xml_helper->Parse($body);
/* @var $root_node kXMLNode */
$Postage = 0;
$label_file = $TrackingNumber = $PostnetBarCode = '';
// Domestic shipping
if ($this->order['ShippingCountry'] == $this->shipping_origin_country ) {
$delivery_node =& $root_node->FindChild('DeliveryConfirmationV3.0Response');
do {
$TrackingNumber = $delivery_node->FindChildValue('DeliveryConfirmationNumber');
$PostnetBarCode = $delivery_node->FindChildValue('Postnet');
$DeliveryConfirmationLabel = base64_decode($delivery_node->FindChildValue('DeliveryConfirmationLabel'));
}
while ( $delivery_node =& $delivery_node->NextSibling());
}
else {
if (strpos($shipping_service, 'express') !== false) {
$node_title = 'ExpressMailIntlResponse';
}
elseif (strpos($shipping_service, 'priority') !== false) {
$node_title = 'PriorityMailIntlResponse';
}
else {
$node_title = 'FirstClassMailIntlResponse';
}
$delivery_node =& $root_node->FindChild($node_title);
$PostnetBarCode = $delivery_node->FindChildValue('BarcodeNumber');
$Postage = $delivery_node->FindChildValue('Postage');
$DeliveryConfirmationLabel = base64_decode($delivery_node->FindChildValue('LabelImage'));
}
if ( $TrackingNumber != '' ) {
$label_file = USPS_LABEL_FOLDER.$TrackingNumber.".pdf";
}
elseif ( $PostnetBarCode != '' ) {
$label_file = USPS_LABEL_FOLDER.$PostnetBarCode.".pdf";
}
if ( $label_file != '' ) {
$file_helper =& $this->Application->recallObject('FileHelper');
/* @var $file_helper FileHelper */
$file_helper->CheckFolder(USPS_LABEL_FOLDER);
if (!$handle = fopen($label_file, 'a')) echo "Cannot open file ($label_file)";
if ( @fwrite($handle, $DeliveryConfirmationLabel) === FALSE) echo "Cannot write to file ($label_file)";
}
return array('TrackingNumber' => $TrackingNumber, 'PostnetBarCode' => $PostnetBarCode, 'Postage' => $Postage);
}
function GetUSPSCountry($country, $default = 'US')
{
$cs_helper =& $this->Application->recallObject('CountryStatesHelper');
/* @var $cs_helper kCountryStatesHelper */
$country = $cs_helper->getCountryIso($country);
return $country == '' ? $default : $country;
}
function GetShippingQuotes($params = null)
{
$weights = Kg2Pounds($params['packages']['0']['weight']);
$weight = '';
$weight = $weights[0];
if ( $weights[1] != '' ) {
$weight.='.'.$weights[1];
}
$country = $this->GetUSPSCountry($params['dest_country']);
$this->order = Array();
$this->order['ShippingWeight'] = $weight;
$this->order['ShippingNumBoxes'] = 1;
$this->order['ShippingZip'] = $params['dest_postal'];
$this->order['SubTotal'] = $params['amount'];
$this->order['ShippingCountry'] = $country;
$shipping_types = Array();
$rates = $this->GetQuote();
if ( !isset($rates['error']) ) {
$this->Application->RemoveVar('sqe_error');
$i = 1;
foreach ($rates as $k => $rate ) {
$shipping_types['USPS_'.$i] = Array(
'ShippingId' => 'USPS_'.$i,
'TotalCost' => $rate['Rate'],
'ShippingName' => $rate['Title'],
'Type' => '1',
'CODFlat' => '0',
'CODPercent' => '0',
'PortalGroups' => ',15,',
'InsuranceFee' => '',
'COD' => '0',
'SelectedOnly' => '0',
'Code' => $rate['Title']
);
$i++;
}
}
else {
// for Front-End (shipping screen) and Admin (Shipping Tab on editing order)
$this->Application->StoreVar('sqe_error', $rates['error']);
}
$this->Application->StoreVar('current_usps_shipping_types', serialize($shipping_types));
return $shipping_types;
}
function TrackOrder($TrackingNumber='')
{
if ( $TrackingNumber != '' ) {
// http://testing.shippingapis.com/ShippingAPITest.dll?API=TrackV2&XML=<TrackFieldRequest USERID="402INTEC7634"><TrackID ID="EJ958083578US"></TrackID></TrackFieldRequest>
$request = '<TrackRequest USERID="'.$this->usps_userid.'"><TrackID ID="'.$TrackingNumber.'"></TrackID></TrackRequest>';
$api_query = 'TrackV2';
$request = 'API='.$api_query.'&XML='.urlencode($request);
$body = $this->PostQuery($request);
// check for errors
if (strpos($body, '<Error>') !== false) {
$errors = Array ();
preg_match_all('/<Number>(.*?)<\/Number>/s', $body, $error_numbers);
preg_match_all('/<Description>(.*?)<\/Description>/s', $body, $error_descriptions);
foreach ($error_numbers[1] as $index => $error_number) {
$errors[$index] = $error_descriptions[1][$index];
if ($this->Application->isDebugMode()) {
$errors[$index] .= ' (' . $error_number . ')';
}
}
$errors = array_unique($errors); // we may have same errors on many packages, so don't show duplicates
return Array('error' => implode('<br/>', $errors));
}
$xml_helper =& $this->Application->recallObject('kXMLHelper');
$root_node =& $xml_helper->Parse($body);
/* @var $root_node kXMLNode */
// Tracking Shipping
$delivery_node =& $root_node->FindChild('TrackInfo');
$TrackSummary = $delivery_node->FindChildValue('TrackSummary');
// echo ' TrackSummary ('.$TrackingNumber.') = '.$TrackSummary.'<br>';
return strpos($TrackSummary, 'delivered') !== false ? 1 : 0;
}
else
return false;
}
function ProcessTrackOrders()
{
$sql = sprintf('SELECT `OrderId`, `ShippingTracking` FROM %s WHERE `Status` > 3 AND `Delivered` = 0', TABLE_PREFIX.'Orders');
$orders = $this->Application->Conn->Query($sql);
foreach ( $orders as $k => $order ) {
// try to track order
if ( $order['ShippingTracking'] != '' && $this->TrackOrder($order['ShippingTracking']) ) {
$update_order = sprintf("UPDATE %s SET `Delivered` = 1 WHERE %s = %s",
TABLE_PREFIX.'Orders',
$this->Application->getUnitOption('ord', 'IDField'),
$order[$this->Application->getUnitOption('ord', 'IDField')]
);
$this->Application->Conn->Query($update_order);
}
}
}
function PostQuery($request, $secure=0)
{
switch (MODULE_SHIPPING_USPS_SERVER) {
case 'production':
$usps_server = $secure > 0 ? 'https://secure.shippingapis.com' : 'http://production.shippingapis.com' ;
$api_dll = 'ShippingAPI.dll';
break;
case 'test':
$usps_server = $secure > 0 ? 'https://secure.shippingapis.com' : 'http://testing.shippingapis.com';
$api_dll = 'ShippingAPITest.dll';
break;
}
$curl = curl_init();
curl_setopt($curl, CURLOPT_URL, $usps_server.'/'.$api_dll.'?'.$request);
curl_setopt($curl, CURLOPT_HEADER, 0);
curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
$body = curl_exec($curl);
curl_close($curl);
- if (defined('USPS_LOG_FILE')) {
- $filename = USPS_LOG_FILE;
- if ( !$fp = fopen($filename, "a") ) echo("Failed opening file $filename");
- }
- $request_url = sprintf("Date %s : IP %s\n\nPost\n\n%s\n\nReplay\n\n%s\n\n",
- date("m/d/Y H:i:s",time()),
- $_SERVER['REMOTE_ADDR'],
- $usps_server.'/'.$api_dll.'?'.urldecode($request),
- $body
- );
- if (defined('USPS_LOG_FILE')) {
- if (!fwrite($fp, $request_url)) echo("Failed writing to file $filename");
- fclose($fp);
+ if ($this->logFilePath) {
+ $fp = fopen($this->logFilePath, 'a');
+
+ if ($fp) {
+ $request_url = sprintf("Date %s : IP %s\n\nPost\n\n%s\n\nReplay\n\n%s\n\n",
+ adodb_date('m/d/Y H:i:s'),
+ $_SERVER['REMOTE_ADDR'],
+ $usps_server . '/' . $api_dll . '?' . urldecode($request),
+ $body
+ );
+
+ fwrite($fp, $request_url);
+ fclose($fp);
+ }
}
+
return $body;
}
/**
* Returns available shipping types
*
* @return Array
* @todo Get possible shipping types based on MODULE_SHIPPING_USPS_TYPES and MODULE_SHIPPING_USPS_TYPES_INTL consntants
*/
function GetAvailableTypes()
{
return Array (
Array (
'_ClassName' => get_class($this),
'_Id' => 'USPS',
'_Name' => 'USPS (Default)'
)
);
}
function LoadParams()
{
$sql = 'SELECT Properties FROM '.$this->Application->getUnitOption('sqe', 'TableName').'
WHERE ClassName="USPS"';
$db =& $this->Application->GetADODBConnection();
return unserialize($db->GetOne($sql));
}
function _prepare_xml_param($value) {
return strip_tags($value);
}
/**
* Returns virtual field names, that will be saved as properties
*
* @return Array
*/
function GetEngineFields()
{
return Array ('AccountLogin');
}
/**
* Creates new USPS order
*
* @param OrdersItem $object
* @param bool $dry_run
* @return Array
*/
function MakeOrder(&$object, $dry_run = false)
{
$ShippingInfo = unserialize($object->GetDBField('ShippingInfo'));
$ShippingCode = $USPSMethod = '';
$ShippingCountry = $this->GetUSPSCountry($object->GetDBField('ShippingCountry'));
$UserName = explode(" ", $object->GetDBField('ShippingTo'));
$item_table = TABLE_PREFIX.'OrderItems';
if ($this->Application->isAdminUser) {
// this strange contraption actually uses temp table from object (when in temp mode)
$order_table = $object->TableName;
$item_table = str_replace('Orders', 'OrderItems', $order_table);
}
$sOrder = Array (
'FirstName' => $UserName[0],
'LastName' => $UserName[1],
'ShippingCompany' => $object->GetDBField('ShippingCompany'),
'ShippingAddress1' => $object->GetDBField('ShippingAddress1'),
'ShippingAddress2' => $object->GetDBField('ShippingAddress2'),
'ShippingCity' => $object->GetDBField('ShippingCity'),
'ShippingZip' => $object->GetDBField('ShippingZip'),
'ShippingCountry' => $ShippingCountry,
'ShippingPhone' => $this->PhoneClean($object->GetDBField('ShippingPhone')),
'ShippingFax' => $this->PhoneClean($object->GetDBField('ShippingFax')),
'ShippingNumBoxes' => '1',
);
$sql = 'SELECT SUM(`Quantity` * `Weight`)
FROM ' . $item_table . '
WHERE ' . $object->IDField . ' = ' . $object->GetID();
$weight = $this->Application->Conn->GetOne($sql);
$f_weight = Kg2Pounds($weight);
$sOrder['ShippingWeight'] = $f_weight[0].'.'.$f_weight[1];
foreach ($ShippingInfo as $k => $ShippingRow) {
$ShippingCode = $ShippingRow['Code'];
}
if ( $object->GetDBField('ShippingCountry') == 'USA' ) {
$sOrder['ShippingState'] = $object->GetDBField('ShippingState');
$USPSMethod = $ShippingCode;
unset($sOrder['ShippingZip']);
$sOrder['ShippingZip5'] = substr(trim($object->GetDBField('ShippingZip')), 0, 5);
$sOrder['ShippingZip4'] = '';
$sOrder['SubTotal'] = $object->GetDBField('SubTotal');
}
else {
$USPSMethod = array_search($ShippingCode, $this->intl_types);
$sOrder['ShippingProvince'] = '';
if ( $ShippingCountry == 'CA' ) {
$sOrder['ShippingProvince'] = $object->GetField('ShippingState');
}
// add items
$sql = 'SELECT `Quantity`, `Weight`, `Price`
FROM ' . $item_table . '
WHERE ' . $object->IDField . ' = ' . $object->GetID();
$order_items = $this->Application->Conn->Query($sql);
$i = 1;
$Items = Array();
foreach ($order_items as $k => $order_item) {
$p_weight = Array();
$p_weight = Kg2Pounds($order_item['Weight']);
$Items[$i] = Array('Qty' => $order_item['Quantity'], 'Price' => $order_item['Price'], 'NetPounds' => $p_weight[0], 'NetOunces' => $p_weight[1]);
$i++;
}
$sOrder['Items'] = $Items;
$sOrder['InvoiceNumber'] = $object->GetDBField('OrderNumber');
}
$sOrder['ShippingService'] = $USPSMethod;
// make USPS order
$this->order = $sOrder;
$usps_data = $this->PostOrder();
// if errors
if ( array_key_exists('error_number', $usps_data) ) {
return $usps_data;
}
if ( array_key_exists('Postage', $usps_data) ) {
$ShippingPrice = '';
$ShippingPrice = $usps_data['Postage'];
}
$ShippingTracking = '';
if ( isset($usps_data['TrackingNumber']) && $usps_data['TrackingNumber'] != '' ) {
$ShippingTracking = $usps_data['TrackingNumber'];
}
if ( isset($usps_data['PostnetBarCode']) && $usps_data['PostnetBarCode'] != '' && $ShippingTracking == '' ) {
$ShippingTracking = $usps_data['PostnetBarCode'];
}
if ($dry_run == false) {
$object->SetDBField('ShippingTracking', $ShippingTracking);
$object->Update();
}
else {
$full_path = USPS_LABEL_FOLDER . $ShippingTracking . ".pdf";
if (file_exists($full_path)) {
unlink($full_path);
}
}
return $usps_data;
}
}
\ No newline at end of file
Index: branches/5.1.x/gw_notify.php
===================================================================
--- branches/5.1.x/gw_notify.php (revision 14358)
+++ branches/5.1.x/gw_notify.php (revision 14359)
@@ -1,65 +1,65 @@
<?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.
*/
define('GW_NOTIFY', 1);
define('REL_PATH', 'modules/in-commerce');
- define('FULL_PATH', realpath(dirname(__FILE__) . '/../..'));
+ define('FULL_PATH', realpath(dirname(__FILE__) . '/../..'));
include_once(FULL_PATH . '/core/kernel/startup.php');
-
+
$application =& kApplication::Instance();
$application->Init();
- /*
+
// for debugging payment gateway notifications, don't remove
- $fh = fopen(WRITEABLE . '/gw.log', 'a');
+ /*$fh = fopen((defined('RESTRICTED') ? RESTRICTED : WRITEABLE) . '/gw.log', 'a');
fwrite ($fh, "\n\n".date('d/m/y h:i:s').":\n");
foreach ($_REQUEST as $key => $val) {
fwrite($fh, "<input type=\"text\" name=\"$key\" value=\"$val\">\n");
}
- fclose($fh);
- */
-
+ fclose($fh);*/
+
+
$db =& $application->GetADODBConnection();
$application->setUnitOption('ord','AutoLoad',false);
$order =& $application->recallObject('ord');
-
+
$order_id = $application->GetVar('order_id');
if ($order_id) {
$order->Load($order_id);
}
-
+
$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 %s SET GWResult1 = %s WHERE %s = %s';
$sql = sprintf($sql, $order->TableName, $db->qstr($gateway_object->getGWResponce()), $order->IDField, $order->GetID() );
$db->Query($sql);
$order->SetDBField('GWResult1', $gateway_object->getGWResponce() );
$sql = 'UPDATE %s SET TransactionStatus = %s WHERE %s = %s';
$db->Query( sprintf($sql, $order->TableName, $transaction_status, $order->IDField, $order->GetID()) );
$order->SetDBField('TransactionStatus', $transaction_status);
if($transaction_status == 1)
{
$dummy_var = '10';
$application->HandleEvent($dummy_var, 'ord:OnCompleteOrder');
}
else {
$application->StoreVar('gw_error', $gateway_object->getErrorMsg());
}
$application->Done();
\ No newline at end of file

Event Timeline