[ Index ]

PHP Cross Reference of osCMax 2.0.4

title

Body

[close]

/includes/modules/shipping/ -> upsxml.php (source)

   1  <?php
   2  /*
   3  $Id: upsxml.php 3 2006-05-27 04:59:07Z user $
   4  
   5      Original Copyright 2006 osCMax2003 Torin Walker
   6      This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License
   7      as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version.
   8      This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
   9      warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  10      See the GNU General Public License for more details.
  11      You should have received a copy of the GNU General Public License along with this program;
  12      If not, you may obtain one by writing to and requesting one from:
  13      The Free Software Foundation, Inc.,
  14      59 Temple Place, Suite 330,
  15      Boston, MA 02111-1307 USA
  16  
  17      Written by Torin Walker.
  18      Some code/style borrowed from both Fritz Clapp's UPS Choice 1.7 Module,
  19      and Kelvin, Kenneth, and Tom St.Croix's Canada Post 3.1 Module.
  20      Insurance support by Joe McFrederick
  21  */
  22  
  23  // Incorporate the XML conversion library 
  24    if (PHP_VERSION >= '5.0.0') { // PHP 5 does not need to use call-time pass by reference
  25      require_once  (DIR_WS_CLASSES . 'xml_5.php');
  26    } else {
  27      require_once  (DIR_WS_CLASSES . 'xml.php');
  28    }
  29  
  30  class upsxml {
  31      var $code, $title, $description, $icon, $enabled, $types, $boxcount;
  32  
  33      //***************
  34      function upsxml() {
  35          global $order, $packing;
  36          $this->code = 'upsxml';
  37          $this->title = MODULE_SHIPPING_UPSXML_RATES_TEXT_TITLE;
  38          $this->description = MODULE_SHIPPING_UPSXML_RATES_TEXT_DESCRIPTION;
  39          $this->sort_order = MODULE_SHIPPING_UPSXML_RATES_SORT_ORDER;
  40          $this->icon = DIR_WS_ICONS . 'shipping_ups.gif';
  41          $this->tax_class = MODULE_SHIPPING_UPSXML_RATES_TAX_CLASS;
  42          $this->enabled = ((MODULE_SHIPPING_UPSXML_RATES_STATUS == 'True') ? true : false);
  43          $this->access_key = MODULE_SHIPPING_UPSXML_RATES_ACCESS_KEY;
  44          $this->access_username = MODULE_SHIPPING_UPSXML_RATES_USERNAME;
  45          $this->access_password = MODULE_SHIPPING_UPSXML_RATES_PASSWORD;
  46          $this->access_account_number = MODULE_SHIPPING_UPSXML_RATES_UPS_ACCOUNT_NUMBER;
  47          $this->use_negotiated_rates = MODULE_SHIPPING_UPSXML_RATES_USE_NEGOTIATED_RATES;
  48          $this->origin = MODULE_SHIPPING_UPSXML_RATES_ORIGIN;
  49          $this->origin_city = MODULE_SHIPPING_UPSXML_RATES_CITY;
  50          $this->origin_stateprov = MODULE_SHIPPING_UPSXML_RATES_STATEPROV;
  51          $this->origin_country = MODULE_SHIPPING_UPSXML_RATES_COUNTRY;
  52          $this->origin_postalcode = MODULE_SHIPPING_UPSXML_RATES_POSTALCODE;
  53          $this->pickup_method = MODULE_SHIPPING_UPSXML_RATES_PICKUP_METHOD;
  54          $this->package_type = MODULE_SHIPPING_UPSXML_RATES_PACKAGE_TYPE;
  55  // the variables for unit weight, unit length, and dimensions support were moved to
  56  // shop admin -> Configuration -> Shipping/Packaging in
  57  // version 1.3.0. Run the configuration_shipping.sql to add these to your configuration
  58          if (defined('SHIPPING_UNIT_WEIGHT')) {
  59          $this->unit_weight = SHIPPING_UNIT_WEIGHT;
  60          } else {
  61  // for those who will undoubtedly forget or not know how to run the configuration_shipping.sql
  62  // we will set the default to pounds (LBS) and inches (IN)
  63          $this->unit_weight = 'LBS';
  64          }
  65          if (defined('SHIPPING_UNIT_LENGTH')) {
  66          $this->unit_length = SHIPPING_UNIT_LENGTH;
  67          } else {
  68            $this->unit_length = 'IN';
  69          }
  70          if (defined('SHIPPING_DIMENSIONS_SUPPORT') && SHIPPING_DIMENSIONS_SUPPORT == 'Ready-to-ship only') {
  71            $this->dimensions_support = 1;
  72          } elseif (defined('SHIPPING_DIMENSIONS_SUPPORT') && SHIPPING_DIMENSIONS_SUPPORT == 'With product dimensions') {
  73            $this->dimensions_support = 2;
  74          } else {
  75            $this->dimensions_support = 0;
  76          }
  77          $this->email_errors = ((MODULE_SHIPPING_UPSXML_EMAIL_ERRORS == 'Yes') ? true : false);
  78          $this->handling_type = MODULE_SHIPPING_UPSXML_HANDLING_TYPE;
  79          $this->handling_fee = MODULE_SHIPPING_UPSXML_RATES_HANDLING;
  80          $this->quote_type = MODULE_SHIPPING_UPSXML_RATES_QUOTE_TYPE;
  81          $this->customer_classification = MODULE_SHIPPING_UPSXML_RATES_CUSTOMER_CLASSIFICATION_CODE;
  82          $this->protocol = 'https';
  83          $this->host = ((MODULE_SHIPPING_UPSXML_RATES_MODE == 'Test') ? 'wwwcie.ups.com' : 'www.ups.com');
  84          $this->port = '443';
  85          $this->path = '/ups.app/xml/Rate';
  86          $this->transitpath = '/ups.app/xml/TimeInTransit';
  87          $this->version = 'UPSXML Rate 1.0001';
  88          $this->transitversion = 'UPSXML Time In Transit 1.0002';
  89          $this->timeout = '60';
  90          $this->xpci_version = '1.0001';
  91          $this->transitxpci_version = '1.0002';
  92          $this->items_qty = 0;
  93          $this->timeintransit = '0';
  94          $this->timeInTransitView = MODULE_SHIPPING_UPSXML_RATES_TIME_IN_TRANSIT_VIEW;
  95          $this->weight_for_timeintransit = '0';
  96          $now_unix_time = mktime(date("H"), date("i"), date("s"), date("m"), date("d"), date("Y"));
  97          $this->today_unix_time = $now_unix_time;
  98          $this->today = date("Ymd");
  99          // insurance addition
 100          if (MODULE_SHIPPING_UPSXML_INSURE == 'False') { 
 101            $this->pkgvalue = 100; 
 102            } else {
 103            $this->pkgvalue = ceil($order->info['subtotal']); // is divided by number of boxes later
 104            }
 105          // end insurance addition
 106          // to enable logging, create an empty "upsxml.log" file at the location you set below, give it write permissions (777) and uncomment the next line
 107  //        $this->logfile = '/srv/www/htdocs/catalog/includes/modules/shipping/upsxml.log';
 108          
 109          // to enable logging of just the errors, do as above but call the file upsxml_error.log
 110  //        $this->ups_error_file = '/srv/www/htdocs/catalog/includes/modules/shipping/upsxml_error.log';
 111          // when cURL is not compiled into PHP (Windows users, some Linux users)
 112          // you can set the next variable to "1" and then exec(curl -d $xmlRequest, $xmlResponse)
 113          // will be used
 114          $this->use_exec = '0';
 115  
 116          if (($this->enabled == true) && ((int)MODULE_SHIPPING_UPSXML_RATES_ZONE > 0)) {
 117              $check_flag = false;
 118              $check_query = tep_db_query("select zone_id from " . TABLE_ZONES_TO_GEO_ZONES . " where geo_zone_id = '" . MODULE_SHIPPING_UPSXML_RATES_ZONE . "' and zone_country_id = '" . $order->delivery['country']['id'] . "' order by zone_id");
 119              while ($check = tep_db_fetch_array($check_query)) {
 120                  if ($check['zone_id'] < 1) {
 121                      $check_flag = true;
 122                      break;
 123                  } elseif ($check['zone_id'] == $order->delivery['zone_id']) {
 124                      $check_flag = true;
 125                      break;
 126                  }
 127              }
 128              if ($check_flag == false) {
 129                  $this->enabled = false;
 130              }
 131          }
 132  
 133          // Available pickup types - set in admin
 134          $this->pickup_methods = array(
 135              'Daily Pickup' => '01',
 136              'Customer Counter' => '03',
 137              'One Time Pickup' => '06',
 138              'On Call Air Pickup' => '07',
 139              'Suggested Retail Rates (UPS Store)' => '11',
 140              'Letter Center' => '19',
 141              'Air Service Center' => '20'
 142          );
 143  
 144          // Available package types
 145          $this->package_types = array(
 146              'UPS Letter' => '01',
 147              'Package' => '02',
 148              'UPS Tube' => '03',
 149              'UPS Pak' => '04',
 150              'UPS Express Box' => '21',
 151              'UPS 25kg Box' => '24',
 152              'UPS 10kg Box' => '25'
 153          );
 154  
 155          // Human-readable Service Code lookup table. The values returned by the Rates and Service "shop" method are numeric.
 156          // Using these codes, and the administratively defined Origin, the proper human-readable service name is returned.
 157          // Note: The origin specified in the admin configuration affects only the product name as displayed to the user.
 158          $this->service_codes = array(
 159              // US Origin
 160              'US Origin' => array(
 161                  '01' => MODULE_SHIPPING_UPSXML_SERVICE_CODE_US_ORIGIN_01,
 162                  '02' => MODULE_SHIPPING_UPSXML_SERVICE_CODE_US_ORIGIN_02,
 163                  '03' => MODULE_SHIPPING_UPSXML_SERVICE_CODE_US_ORIGIN_03,
 164                  '07' => MODULE_SHIPPING_UPSXML_SERVICE_CODE_US_ORIGIN_07,
 165                  '08' => MODULE_SHIPPING_UPSXML_SERVICE_CODE_US_ORIGIN_08,
 166                  '11' => MODULE_SHIPPING_UPSXML_SERVICE_CODE_US_ORIGIN_11,
 167                  '12' => MODULE_SHIPPING_UPSXML_SERVICE_CODE_US_ORIGIN_12,
 168                  '13' => MODULE_SHIPPING_UPSXML_SERVICE_CODE_US_ORIGIN_13,
 169                  '14' => MODULE_SHIPPING_UPSXML_SERVICE_CODE_US_ORIGIN_14,
 170                  '54' => MODULE_SHIPPING_UPSXML_SERVICE_CODE_US_ORIGIN_54,
 171                  '59' => MODULE_SHIPPING_UPSXML_SERVICE_CODE_US_ORIGIN_59,
 172                  '65' => MODULE_SHIPPING_UPSXML_SERVICE_CODE_US_ORIGIN_65
 173              ),
 174              // Canada Origin
 175              'Canada Origin' => array(
 176                  '01' => MODULE_SHIPPING_UPSXML_SERVICE_CODE_CANADA_ORIGIN_01,
 177                  '02' => MODULE_SHIPPING_UPSXML_SERVICE_CODE_CANADA_ORIGIN_02,
 178                  '07' => MODULE_SHIPPING_UPSXML_SERVICE_CODE_CANADA_ORIGIN_07,
 179                  '08' => MODULE_SHIPPING_UPSXML_SERVICE_CODE_CANADA_ORIGIN_08,
 180                  '11' => MODULE_SHIPPING_UPSXML_SERVICE_CODE_CANADA_ORIGIN_11,
 181                  '12' => MODULE_SHIPPING_UPSXML_SERVICE_CODE_CANADA_ORIGIN_12,
 182                  '13' => MODULE_SHIPPING_UPSXML_SERVICE_CODE_CANADA_ORIGIN_13,
 183                  '14' => MODULE_SHIPPING_UPSXML_SERVICE_CODE_CANADA_ORIGIN_14,
 184                  // service code 54 gone after January 2, 2007
 185                  '54' => MODULE_SHIPPING_UPSXML_SERVICE_CODE_CANADA_ORIGIN_54,
 186                  '65' => MODULE_SHIPPING_UPSXML_SERVICE_CODE_CANADA_ORIGIN_65
 187              ),
 188              // European Union Origin
 189              'European Union Origin' => array(
 190                  '07' => MODULE_SHIPPING_UPSXML_SERVICE_CODE_EU_ORIGIN_07,
 191                  '11' => MODULE_SHIPPING_UPSXML_SERVICE_CODE_EU_ORIGIN_11,
 192                  '54' => MODULE_SHIPPING_UPSXML_SERVICE_CODE_EU_ORIGIN_54,
 193                  '65' => MODULE_SHIPPING_UPSXML_SERVICE_CODE_EU_ORIGIN_65,
 194                  // next three services Poland domestic only (Stolica)
 195                  '82' => MODULE_SHIPPING_UPSXML_SERVICE_CODE_EU_ORIGIN_82,
 196                  '83' => MODULE_SHIPPING_UPSXML_SERVICE_CODE_EU_ORIGIN_83,
 197                  '84' => MODULE_SHIPPING_UPSXML_SERVICE_CODE_EU_ORIGIN_84
 198              ),
 199              // Puerto Rico Origin
 200              'Puerto Rico Origin' => array(
 201                  '01' => MODULE_SHIPPING_UPSXML_SERVICE_CODE_PR_ORIGIN_01,
 202                  '02' => MODULE_SHIPPING_UPSXML_SERVICE_CODE_PR_ORIGIN_02,
 203                  '03' => MODULE_SHIPPING_UPSXML_SERVICE_CODE_PR_ORIGIN_03,
 204                  '07' => MODULE_SHIPPING_UPSXML_SERVICE_CODE_PR_ORIGIN_07,
 205                  '08' => MODULE_SHIPPING_UPSXML_SERVICE_CODE_PR_ORIGIN_08,
 206                  '14' => MODULE_SHIPPING_UPSXML_SERVICE_CODE_PR_ORIGIN_14,
 207                  '54' => MODULE_SHIPPING_UPSXML_SERVICE_CODE_PR_ORIGIN_54,
 208                  '65' => MODULE_SHIPPING_UPSXML_SERVICE_CODE_PR_ORIGIN_65
 209              ),
 210              // Mexico Origin
 211              'Mexico Origin' => array(
 212                  '07' => MODULE_SHIPPING_UPSXML_SERVICE_CODE_MEXICO_ORIGIN_07,
 213                  '08' => MODULE_SHIPPING_UPSXML_SERVICE_CODE_MEXICO_ORIGIN_08,
 214                  '54' => MODULE_SHIPPING_UPSXML_SERVICE_CODE_MEXICO_ORIGIN_54,
 215                  '65' => MODULE_SHIPPING_UPSXML_SERVICE_CODE_MEXICO_ORIGIN_65
 216              ),
 217              // All other origins
 218              'All other origins' => array(
 219                  // service code 7 seems to be gone after January 2, 2007
 220                  '07' => MODULE_SHIPPING_UPSXML_SERVICE_CODE_OTHER_ORIGIN_07,
 221                  '08' => MODULE_SHIPPING_UPSXML_SERVICE_CODE_OTHER_ORIGIN_08,
 222                  '54' => MODULE_SHIPPING_UPSXML_SERVICE_CODE_OTHER_ORIGIN_54,
 223                  '65' => MODULE_SHIPPING_UPSXML_SERVICE_CODE_PR_ORIGIN_65
 224              )
 225          );
 226      } // end function upsxml
 227  
 228      // class methods
 229      function quote($method = '') {
 230          global $HTTP_POST_VARS, $order, $shipping_weight, $shipping_num_boxes, $total_weight, $boxcount, $cart, $packing;
 231          // UPS purports that if the origin is left out, it defaults to the account's location. Yeah, right.
 232          $state = $order->delivery['state'];
 233          $zone_query = tep_db_query("select zone_code from " . TABLE_ZONES . " where zone_name = '" .  tep_db_input($order->delivery['state']) . "'");
 234          if (tep_db_num_rows($zone_query)) {
 235              $zone = tep_db_fetch_array($zone_query);
 236              $state = $zone['zone_code'];
 237          }
 238          $this->_upsOrigin(MODULE_SHIPPING_UPSXML_RATES_CITY, MODULE_SHIPPING_UPSXML_RATES_STATEPROV, MODULE_SHIPPING_UPSXML_RATES_COUNTRY, MODULE_SHIPPING_UPSXML_RATES_POSTALCODE);
 239          $this->_upsDest($order->delivery['city'], $state, $order->delivery['country']['iso_code_2'], $order->delivery['postcode']);
 240          
 241  // the check on $packing being an object will puzzle people who do things wrong (no changes when 
 242  // you enable dimensional support without changing checkout_shipping.php) but better be safe
 243          if ($this->dimensions_support > 0 && is_object($packing)) {
 244            $boxValue = 0;
 245            $totalWeight = $packing->getTotalWeight();
 246            $shipping_num_boxes = $packing->getNumberOfBoxes();
 247            $boxesToShip = $packing->getPackedBoxes();
 248               for ($i = 0; $i < count($boxesToShip); $i++) {
 249                  if (MODULE_SHIPPING_UPSXML_INSURE == 'False') {
 250  // to avoid the addition of an insurance fee a hardcoded pkgValue (see above around line 93)
 251  // of 100 is used when no insurance is wanted
 252                    $boxesToShip[$i]['item_price'] = $this->pkgvalue; 
 253                  } 
 254                  $this->_addItem($boxesToShip[$i]['item_length'], $boxesToShip[$i]['item_width'], $boxesToShip[$i]['item_height'], $boxesToShip[$i]['item_weight'], $boxesToShip[$i]['item_price']);
 255                  } // end for ($i = 0; $i < count($boxesToShip); $i++)
 256          } else {
 257              // The old method. Let osCommerce tell us how many boxes, plus the weight of each (or total? - might be sw/num boxes)
 258              $this->items_qty = 0; //reset quantities
 259              if (MODULE_SHIPPING_UPSXML_INSURE == 'False') {
 260                 for ($i = 0; $i < $shipping_num_boxes; $i++) {
 261                    $this->_addItem(0, 0, 0, $shipping_weight, $this->pkgvalue);
 262                 }
 263              } else {
 264  // $this->pkgvalue has been set as order subtotal around line 86, it will cause overcharging
 265  // of insurance if not divided by the number of boxes
 266                 for ($i = 0; $i < $shipping_num_boxes; $i++) {
 267                    $this->_addItem(0, 0, 0, $shipping_weight, number_format(($this->pkgvalue/$shipping_num_boxes), 2, '.', ''));
 268                 }
 269              } // end if/else  (MODULE_SHIPPING_UPSXML_INSURE == 'False')
 270          }
 271  
 272        // BOF Time In Transit: used for expected delivery dates
 273        // is skipped when set to "Not" in the admin
 274        if ($this->timeInTransitView != 'Not') {
 275          if ($this->dimensions_support > 0) {
 276              $this->weight_for_timeintransit = round($totalWeight,1);
 277          } else {
 278              $this->weight_for_timeintransit = round($shipping_num_boxes * $shipping_weight,1);
 279          }
 280          // Added to workaround time in transit error 270033 if total weight of packages is over 150lbs or 70kgs
 281          if (($this->weight_for_timeintransit > 150) && ($this->unit_weight == "LBS")) {
 282            $this->weight_for_timeintransit = 150;          
 283          } else if (($this->weight_for_timeintransit > 70) && ($this->unit_weight == "KGS")) {
 284            $this->weight_for_timeintransit = 70;          
 285          }
 286          // debug only:
 287          /*  echo '<pre>Packages and variables:<br />';
 288           print_r($this);
 289           echo '<br />';
 290           exit; */
 291          // make sure that when TimeinTransit fails to get results (error or not available)
 292          // this is not obvious to the client
 293          $_upsGetTimeServicesResult = $this->_upsGetTimeServices();
 294          if ($_upsGetTimeServicesResult != false && is_array($_upsGetTimeServicesResult)) {
 295          $this->servicesTimeintransit = $_upsGetTimeServicesResult;
 296          }
 297          if ($this->logfile) {
 298              error_log("------------------------------------------\n", 3, $this->logfile);
 299              error_log("Time in Transit: " . $this->timeintransit . "\n", 3, $this->logfile);
 300          }
 301        } // end if ($this->timeInTransitView != 'Not') 
 302        // EOF Time In Transit
 303  
 304          $upsQuote = $this->_upsGetQuote();
 305          if ((is_array($upsQuote)) && (sizeof($upsQuote) > 0)) {
 306            if (defined('MODULE_SHIPPING_UPSXML_WEIGHT1') &&  MODULE_SHIPPING_UPSXML_WEIGHT1 == 'False') {
 307              $this->quotes = array('id' => $this->code, 'module' => $this->title);
 308              usort($upsQuote, array($this, "rate_sort_func"));
 309            } else {
 310              if ($this->dimensions_support > 0) {
 311                  $this->quotes = array('id' => $this->code, 'module' => $this->title . ' (' . $this->boxCount . ($this->boxCount > 1 ? ' pkg(s), ' : ' pkg, ') . round($totalWeight,0) . ' ' . strtolower($this->unit_weight) . ' total)');
 312              } else {
 313                  $this->quotes = array('id' => $this->code, 'module' => $this->title . ' (' . $shipping_num_boxes . ($this->boxCount > 1 ? ' pkg(s) x ' : ' pkg x ') . round($shipping_weight,0) . ' ' . strtolower($this->unit_weight) . ' total)');
 314              }
 315              usort($upsQuote, array($this, "rate_sort_func"));
 316            } // end else/if if (defined('MODULE_SHIPPING_UPSXML_WEIGHT1')
 317              $methods = array();
 318              for ($i=0; $i < sizeof($upsQuote); $i++) {
 319                  list($type, $cost) = each($upsQuote[$i]);
 320                  // BOF limit choices, behaviour changed from versions < 1.2
 321                  if ($this->exclude_choices($type)) continue;
 322                  // EOF limit choices
 323                  if ( $method == '' || $method == $type ) {
 324                      $_type = $type;
 325  
 326                      if ($this->timeInTransitView == "Raw") {
 327                        if (isset($this->servicesTimeintransit[$type])) {
 328                          $_type = $_type . ", ".$this->servicesTimeintransit[$type]["date"];
 329                        }        
 330                      } else {
 331                        if (isset($this->servicesTimeintransit[$type])) {
 332                          $eta_array = explode("-", $this->servicesTimeintransit[$type]["date"]);
 333                          $months = array (" ", "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December");
 334                          $eta_arrival_date = $months[(int)$eta_array[1]]." ".$eta_array[2].", ".$eta_array[0];
 335                          $_type .= ", <acronym title='Estimated Delivery Date'>EDD</acronym>: ".$eta_arrival_date;
 336                        }          
 337                      }                    
 338                      
 339                      // changed to make handling percentage based
 340                      if ($this->handling_type == "Percentage") {
 341                          $methods[] = array('id' => $type, 'title' => $_type, 'cost' => ((($this->handling_fee * $cost)/100) + $cost));
 342                      } else {
 343                          $methods[] = array('id' => $type, 'title' => $_type, 'cost' => ($this->handling_fee + $cost));
 344                      }
 345                  }
 346              }
 347              if ($this->tax_class > 0) {
 348                  $this->quotes['tax'] = tep_get_tax_rate($this->tax_class, $order->delivery['country']['id'], $order->delivery['zone_id']);
 349              }
 350              $this->quotes['methods'] = $methods;
 351          } else {
 352              if ( $upsQuote != false ) {
 353                  $errmsg = $upsQuote;
 354              } else {
 355                  $errmsg = MODULE_SHIPPING_UPSXML_RATES_TEXT_UNKNOWN_ERROR;
 356              }
 357              $errmsg .= '<br>' . MODULE_SHIPPING_UPSXML_RATES_TEXT_IF_YOU_PREFER . ' ' . STORE_NAME.' via <a href="mailto:'.STORE_OWNER_EMAIL_ADDRESS.'"><u>Email</U></a>.';
 358              $this->quotes = array('module' => $this->title, 'error' => $errmsg);
 359          }
 360          if (tep_not_null($this->icon)) {
 361              $this->quotes['icon'] = tep_image($this->icon, $this->title);
 362          }
 363          return $this->quotes;
 364      }
 365  
 366      //**************
 367      function check() {
 368          if (!isset($this->_check)) {
 369              $check_query = tep_db_query("select configuration_value from " . TABLE_CONFIGURATION . " where configuration_key = 'MODULE_SHIPPING_UPSXML_RATES_STATUS'");
 370              $this->_check = tep_db_num_rows($check_query);
 371          }
 372          return $this->_check;
 373      }
 374  
 375      //**************
 376      function install() {
 377          tep_db_query("insert into " . TABLE_CONFIGURATION . " (configuration_title, configuration_key, configuration_value, configuration_description, configuration_group_id, sort_order, set_function, date_added) values ('Enable UPS Shipping', 'MODULE_SHIPPING_UPSXML_RATES_STATUS', 'True', 'Do you want to offer UPS shipping?', '6', '0', 'tep_cfg_select_option(array(\'True\', \'False\'), ', now())");
 378          tep_db_query("insert into " . TABLE_CONFIGURATION . " (configuration_title, configuration_key, configuration_value, configuration_description, configuration_group_id, sort_order, date_added) values ('UPS Rates Access Key', 'MODULE_SHIPPING_UPSXML_RATES_ACCESS_KEY', '', 'Enter the XML rates access key assigned to you by UPS.', '6', '1', now())");
 379          tep_db_query("insert into " . TABLE_CONFIGURATION . " (configuration_title, configuration_key, configuration_value, configuration_description, configuration_group_id, sort_order, date_added) values ('UPS Rates Username', 'MODULE_SHIPPING_UPSXML_RATES_USERNAME', '', 'Enter your UPS Services account username.', '6', '2', now())");
 380          tep_db_query("insert into " . TABLE_CONFIGURATION . " (configuration_title, configuration_key, configuration_value, configuration_description, configuration_group_id, sort_order, date_added) values ('UPS Rates Password', 'MODULE_SHIPPING_UPSXML_RATES_PASSWORD', '', 'Enter your UPS Services account password.', '6', '3', now())");
 381          tep_db_query("insert into " . TABLE_CONFIGURATION . " (configuration_title, configuration_key, configuration_value, configuration_description, configuration_group_id, sort_order, set_function, date_added) values ('Pickup Method', 'MODULE_SHIPPING_UPSXML_RATES_PICKUP_METHOD', 'Daily Pickup', 'How do you give packages to UPS (only used when origin is US)?', '6', '4', 'tep_cfg_select_option(array(\'Daily Pickup\', \'Customer Counter\', \'One Time Pickup\', \'On Call Air Pickup\', \'Letter Center\', \'Air Service Center\', \'Suggested Retail Rates (UPS Store)\'), ', now())");
 382          tep_db_query("insert into " . TABLE_CONFIGURATION . " (configuration_title, configuration_key, configuration_value, configuration_description, configuration_group_id, sort_order, set_function, date_added) values ('Packaging Type', 'MODULE_SHIPPING_UPSXML_RATES_PACKAGE_TYPE', 'Package', 'What kind of packaging do you use?', '6', '5', 'tep_cfg_select_option(array(\'Package\', \'UPS Letter\', \'UPS Tube\', \'UPS Pak\', \'UPS Express Box\', \'UPS 25kg Box\', \'UPS 10kg box\'), ', now())");
 383          tep_db_query("insert into " . TABLE_CONFIGURATION . " (configuration_title, configuration_key, configuration_value, configuration_description, configuration_group_id, sort_order, set_function, date_added) values ('Customer Classification Code', 'MODULE_SHIPPING_UPSXML_RATES_CUSTOMER_CLASSIFICATION_CODE', '01', '01 - If you are billing to a UPS account and have a daily UPS pickup, 03 - If you do not have a UPS account or you are billing to a UPS account but do not have a daily pickup, 04 - If you are shipping from a retail outlet (only used when origin is US)', '6', '6', 'tep_cfg_select_option(array(\'01\', \'03\', \'04\'), ', now())");
 384          tep_db_query("insert into " . TABLE_CONFIGURATION . " (configuration_title, configuration_key, configuration_value, configuration_description, configuration_group_id, sort_order, set_function, date_added) values ('Shipping Origin', 'MODULE_SHIPPING_UPSXML_RATES_ORIGIN', 'US Origin', 'What origin point should be used (this setting affects only what UPS product names are shown to the user)', '6', '7', 'tep_cfg_select_option(array(\'US Origin\', \'Canada Origin\', \'European Union Origin\', \'Puerto Rico Origin\', \'Mexico Origin\', \'All other origins\'), ', now())");
 385          tep_db_query("insert into " . TABLE_CONFIGURATION . " (configuration_title, configuration_key, configuration_value, configuration_description, configuration_group_id, sort_order, date_added) values ('Origin City', 'MODULE_SHIPPING_UPSXML_RATES_CITY', '', 'Enter the name of the origin city.', '6', '8', now())");
 386          tep_db_query("insert into " . TABLE_CONFIGURATION . " (configuration_title, configuration_key, configuration_value, configuration_description, configuration_group_id, sort_order, date_added) values ('Origin State/Province', 'MODULE_SHIPPING_UPSXML_RATES_STATEPROV', '', 'Enter the two-letter code for your origin state/province.', '6', '9', now())");
 387          tep_db_query("insert into " . TABLE_CONFIGURATION . " (configuration_title, configuration_key, configuration_value, configuration_description, configuration_group_id, sort_order, date_added) values ('Origin Country', 'MODULE_SHIPPING_UPSXML_RATES_COUNTRY', '', 'Enter the two-letter code for your origin country.', '6', '10', now())");
 388          tep_db_query("insert into " . TABLE_CONFIGURATION . " (configuration_title, configuration_key, configuration_value, configuration_description, configuration_group_id, sort_order, date_added) values ('Origin Zip/Postal Code', 'MODULE_SHIPPING_UPSXML_RATES_POSTALCODE', '', 'Enter your origin zip/postalcode.', '6', '11', now())");
 389          tep_db_query("insert into " . TABLE_CONFIGURATION . " (configuration_title, configuration_key, configuration_value, configuration_description, configuration_group_id, sort_order, set_function, date_added) values ('Test or Production Mode', 'MODULE_SHIPPING_UPSXML_RATES_MODE', 'Test', 'Use this module in Test or Production mode?', '6', '12', 'tep_cfg_select_option(array(\'Test\', \'Production\'), ', now())");
 390  // three configuration options were moved to shop Configuration -> Shipping/Packaging in v1.3.0
 391  // those are (and were renamed to -> ): 
 392  // MODULE_SHIPPING_UPSXML_RATES_UNIT_WEIGHT (LBS/KG) -> SHIPPING_UNIT_WEIGHT
 393  // MODULE_SHIPPING_UPSXML_RATES_UNIT_LENGTH (IN/CM) -> SHIPPING_UNIT_LENGTH
 394  // MODULE_SHIPPING_UPSXML_DIMENSIONS_SUPPORT -> SHIPPING_DIMENSIONS_SUPPORT
 395          tep_db_query("insert into " . TABLE_CONFIGURATION . " (configuration_title, configuration_key, configuration_value, configuration_description, configuration_group_id, sort_order, set_function, date_added) values ('Quote Type', 'MODULE_SHIPPING_UPSXML_RATES_QUOTE_TYPE', 'Commercial', 'Quote for Residential or Commercial Delivery', '6', '15', 'tep_cfg_select_option(array(\'Commercial\', \'Residential\'), ', now())");
 396         // next two keys added to be able to use negotiated rates (available from UPS since about July 2006)
 397          tep_db_query("insert into " . TABLE_CONFIGURATION . " (configuration_title, configuration_key, configuration_value, configuration_description, configuration_group_id, sort_order, set_function, date_added) values ('Negotiated rates', 'MODULE_SHIPPING_UPSXML_RATES_USE_NEGOTIATED_RATES', 'False', 'Do you receive discounted rates from UPS and want to use these for shipping quotes? <b>Note:</b>  You need to enter your UPS account number below.', '6', '25', 'tep_cfg_select_option(array(\'True\', \'False\'), ', now())");
 398          tep_db_query("insert into " . TABLE_CONFIGURATION . " (configuration_title, configuration_key, configuration_value, configuration_description, configuration_group_id, sort_order, date_added) values ('UPS Account Number', 'MODULE_SHIPPING_UPSXML_RATES_UPS_ACCOUNT_NUMBER', '', 'Enter your UPS Account number when you have and want to use negotiated rates.', '6', '26', now())");
 399          // added for handling type selection
 400          tep_db_query("insert into " . TABLE_CONFIGURATION . " (configuration_title, configuration_key, configuration_value, configuration_description, configuration_group_id, sort_order, set_function, date_added) values ('Handling Type', 'MODULE_SHIPPING_UPSXML_HANDLING_TYPE', 'Flat Fee', 'Handling type for this shipping method.', '6', '16', 'tep_cfg_select_option(array(\'Flat Fee\', \'Percentage\'), ', now())");
 401          tep_db_query("insert into " . TABLE_CONFIGURATION . " (configuration_title, configuration_key, configuration_value, configuration_description, configuration_group_id, sort_order, date_added) values ('Handling Fee', 'MODULE_SHIPPING_UPSXML_RATES_HANDLING', '0', 'Handling fee for this shipping method.', '6', '16', now())");
 402          tep_db_query("insert into " . TABLE_CONFIGURATION . " (configuration_title, configuration_key, configuration_value, configuration_description, configuration_group_id, sort_order, date_added) values ('UPS Currency Code', 'MODULE_SHIPPING_UPSXML_CURRENCY_CODE', '', 'Enter the 3 letter currency code for your country of origin. United States (USD)', '6', '2', now())");
 403          tep_db_query("insert into " . TABLE_CONFIGURATION . " (configuration_title, configuration_key, configuration_value, configuration_description, configuration_group_id, sort_order, set_function, date_added) values ('Enable Insurance', 'MODULE_SHIPPING_UPSXML_INSURE', 'True', 'Do you want to insure packages shipped by UPS?', '6', '22', 'tep_cfg_select_option(array(\'True\', \'False\'), ', now())");
 404          tep_db_query("insert into " . TABLE_CONFIGURATION . " (configuration_title, configuration_key, configuration_value, configuration_description, configuration_group_id, sort_order, use_function, set_function, date_added) values ('Tax Class', 'MODULE_SHIPPING_UPSXML_RATES_TAX_CLASS', '0', 'Use the following tax class on the shipping fee.', '6', '17', 'tep_get_tax_class_title', 'tep_cfg_pull_down_tax_classes(', now())");
 405          tep_db_query("insert into " . TABLE_CONFIGURATION . " (configuration_title, configuration_key, configuration_value, configuration_description, configuration_group_id, sort_order, use_function, set_function, date_added) values ('Shipping Zone', 'MODULE_SHIPPING_UPSXML_RATES_ZONE', '0', 'If a zone is selected, only enable this shipping method for that zone.', '6', '18', 'tep_get_zone_class_title', 'tep_cfg_pull_down_zone_classes(', now())");
 406          tep_db_query("insert into " . TABLE_CONFIGURATION . " (configuration_title, configuration_key, configuration_value, configuration_description, configuration_group_id, sort_order, date_added) values ('Sort order of display.', 'MODULE_SHIPPING_UPSXML_RATES_SORT_ORDER', '0', 'Sort order of display. Lowest is displayed first.', '6', '19', now())");
 407          // add key for disallowed shipping methods
 408          tep_db_query("insert into " . TABLE_CONFIGURATION . " ( configuration_title, configuration_key, configuration_value, configuration_description, configuration_group_id, sort_order, use_function, set_function, date_added) values ('Disallowed Shipping Methods', 'MODULE_SHIPPING_UPSXML_TYPES', '', 'Select the UPS services <span style=\'color: red; font-weight: bold\'>not</span> to be offered.', '6', '20', 'get_multioption_upsxml',  'upsxml_cfg_select_multioption_indexed(array(\'US_01\', \'US_02\', \'US_03\', \'US_07\', \'US_54\', \'US_08\', \'CAN_01\', \'US_11\', \'US_12\', \'US_13\', \'US_14\', \'CAN_02\', \'US_59\', \'US_65\', \'CAN_14\', \'MEX_54\', \'EU_82\', \'EU_83\', \'EU_84\'), ',  now())");
 409          // add key for shipping delay, changed the constant from SHIPPING_DAYS_DELAY in v1.3.0
 410          tep_db_query("insert into " . TABLE_CONFIGURATION . " ( configuration_id, configuration_title, configuration_key, configuration_value, configuration_description, configuration_group_id, sort_order, last_modified, date_added, use_function, set_function) values ('', 'Shipping Delay', 'MODULE_SHIPPING_UPSXML_SHIPPING_DAYS_DELAY', '1', 'How many days from when an order is placed to when you ship it (Decimals are allowed). Arrival date estimations are based on this value.', '6', '21', NULL, now(), NULL, NULL)");
 411          // add key for enabling email error messages
 412          tep_db_query("insert into " . TABLE_CONFIGURATION . " (configuration_title, configuration_key, configuration_value, configuration_description, configuration_group_id, sort_order, set_function, date_added) values ('Email UPS errors', 'MODULE_SHIPPING_UPSXML_EMAIL_ERRORS', 'Yes', 'Do you want to receive UPS errors by email?', '6', '24', 'tep_cfg_select_option(array(\'Yes\', \'No\'), ', now())");
 413          // add key for time in transit view type
 414          tep_db_query("insert into " . TABLE_CONFIGURATION . " (configuration_title, configuration_key, configuration_value, configuration_description, configuration_group_id, sort_order, set_function, date_added) values ('Time in Transit View Type', 'MODULE_SHIPPING_UPSXML_RATES_TIME_IN_TRANSIT_VIEW', 'Not', 'If and how the module should display the time in transit to the customer.', '6', '16', 'tep_cfg_select_option(array(\'Not\',\'Raw\', \'Detailed\'), ', now())");
 415          tep_db_query("insert into " . TABLE_CONFIGURATION . " (configuration_title, configuration_key, configuration_value, configuration_description, configuration_group_id, sort_order, set_function, date_added) values ('Display Weight', 'MODULE_SHIPPING_UPSXML_WEIGHT1', 'True', 'Do you want to show number of packages and package weight?', '6', '27', 'tep_cfg_select_option(array(\'True\', \'False\'), ', now())");
 416      }
 417  
 418      //****************
 419      function remove() {
 420          tep_db_query("delete from " . TABLE_CONFIGURATION . " where configuration_key in ('" . implode("', '", $this->keys()) . "')");
 421      }
 422  
 423      //*************
 424      function keys() {
 425          return array('MODULE_SHIPPING_UPSXML_RATES_STATUS', 'MODULE_SHIPPING_UPSXML_RATES_ACCESS_KEY', 'MODULE_SHIPPING_UPSXML_RATES_USERNAME', 'MODULE_SHIPPING_UPSXML_RATES_PASSWORD', 'MODULE_SHIPPING_UPSXML_RATES_PICKUP_METHOD', 'MODULE_SHIPPING_UPSXML_RATES_PACKAGE_TYPE', 'MODULE_SHIPPING_UPSXML_RATES_CUSTOMER_CLASSIFICATION_CODE', 'MODULE_SHIPPING_UPSXML_RATES_ORIGIN', 'MODULE_SHIPPING_UPSXML_RATES_CITY', 'MODULE_SHIPPING_UPSXML_RATES_STATEPROV', 'MODULE_SHIPPING_UPSXML_RATES_COUNTRY', 'MODULE_SHIPPING_UPSXML_RATES_POSTALCODE', 'MODULE_SHIPPING_UPSXML_RATES_MODE', 'MODULE_SHIPPING_UPSXML_RATES_QUOTE_TYPE', 'MODULE_SHIPPING_UPSXML_RATES_USE_NEGOTIATED_RATES', 'MODULE_SHIPPING_UPSXML_RATES_UPS_ACCOUNT_NUMBER', 'MODULE_SHIPPING_UPSXML_HANDLING_TYPE', 'MODULE_SHIPPING_UPSXML_RATES_HANDLING', 'MODULE_SHIPPING_UPSXML_INSURE', 'MODULE_SHIPPING_UPSXML_CURRENCY_CODE', 'MODULE_SHIPPING_UPSXML_RATES_TAX_CLASS', 'MODULE_SHIPPING_UPSXML_RATES_ZONE', 'MODULE_SHIPPING_UPSXML_RATES_SORT_ORDER', 'MODULE_SHIPPING_UPSXML_TYPES', 'MODULE_SHIPPING_UPSXML_SHIPPING_DAYS_DELAY', 'MODULE_SHIPPING_UPSXML_EMAIL_ERRORS', 'MODULE_SHIPPING_UPSXML_RATES_TIME_IN_TRANSIT_VIEW', 'MODULE_SHIPPING_UPSXML_WEIGHT1');
 426      }
 427  
 428      //***********************
 429      function _upsProduct($prod){
 430          $this->_upsProductCode = $prod;
 431      }
 432  
 433      //**********************************************
 434      function _upsOrigin($city, $stateprov, $country, $postal){
 435          $this->_upsOriginCity = $city;
 436          $this->_upsOriginStateProv = $stateprov;
 437          $this->_upsOriginCountryCode = $country;
 438          $postal = str_replace(' ', '', $postal);
 439          if ($country == 'US') {
 440              $this->_upsOriginPostalCode = substr($postal, 0, 5);
 441          } else {
 442              $this->_upsOriginPostalCode = $postal;
 443          }
 444      }
 445  
 446      //**********************************************
 447      function _upsDest($city, $stateprov, $country, $postal) {
 448          $this->_upsDestCity = $city;
 449          $this->_upsDestStateProv = $stateprov;
 450          $this->_upsDestCountryCode = $country;
 451          $postal = str_replace(' ', '', $postal);
 452          if ($country == 'US') {
 453              $this->_upsDestPostalCode = substr($postal, 0, 5);
 454              $territories = array('AS','FM','GU','MH','MP','PR','PW','VI');
 455              if (in_array($this->_upsDestStateProv,$territories)) {
 456                $this->_upsDestCountryCode = $stateprov;
 457                }
 458          } else if ($country == 'BR') {
 459              $this->_upsDestPostalCode = substr($postal, 0, 5);
 460          } else {
 461              $this->_upsDestPostalCode = $postal;
 462          }
 463      }
 464  
 465      //************************
 466      function _upsAction($action) {
 467          // rate - Single Quote; shop - All Available Quotes
 468          $this->_upsActionCode = $action;
 469      }
 470  
 471      //********************************************
 472      // default value of 100 added for insurance (100 shouldn't trigger costs for insurance)
 473      function _addItem($length, $width, $height, $weight, $price = 0 ) {
 474          // Add box or item to shipment list. Round weights to 1 decimal places.
 475          if ((float)$weight < 1.0) {
 476              $weight = 1;
 477          } else {
 478              $weight = round($weight, 1);
 479          }
 480          $index = $this->items_qty;
 481          $this->item_length[$index] = ($length ? (string)$length : '0' );
 482          $this->item_width[$index] = ($width ? (string)$width : '0' );
 483          $this->item_height[$index] = ($height ? (string)$height : '0' );
 484          $this->item_weight[$index] = ($weight ? (string)$weight : '0' );
 485          $this->item_price[$index] = $price;
 486          $this->items_qty++;
 487      }
 488  
 489      //*********************
 490      function _upsGetQuote() {
 491  
 492          // Create the access request
 493          $accessRequestHeader =
 494          "<?xml version=\"1.0\"?>\n".
 495          "<AccessRequest xml:lang=\"en-US\">\n".
 496          "   <AccessLicenseNumber>". $this->access_key ."</AccessLicenseNumber>\n".
 497          "   <UserId>". $this->access_username ."</UserId>\n".
 498          "   <Password>". $this->access_password ."</Password>\n".
 499          "</AccessRequest>\n";
 500  
 501          $ratingServiceSelectionRequestHeader =
 502          "<?xml version=\"1.0\"?>\n".
 503          "<RatingServiceSelectionRequest xml:lang=\"en-US\">\n".
 504          "   <Request>\n".
 505          "       <TransactionReference>\n".
 506          "           <CustomerContext>Rating and Service</CustomerContext>\n".
 507          "           <XpciVersion>". $this->xpci_version ."</XpciVersion>\n".
 508          "       </TransactionReference>\n".
 509          "       <RequestAction>Rate</RequestAction>\n".
 510          "       <RequestOption>shop</RequestOption>\n".
 511          "   </Request>\n";
 512          // according to UPS the CustomerClassification and PickupType containers should
 513          // not be present when the origin country is non-US see:
 514          // http://forums.oscommerce.com/index.php?s=&showtopic=49382&view=findpost&p=730947
 515          if ($this->origin_country == 'US') {
 516          $ratingServiceSelectionRequestHeader .=
 517          "   <PickupType>\n".
 518          "       <Code>". $this->pickup_methods[$this->pickup_method] ."</Code>\n".
 519          "   </PickupType>\n";
 520          "   <CustomerClassification>\n".
 521          "       <Code>". $this->customer_classification ."</Code>\n".
 522          "   </CustomerClassification>\n";
 523          }
 524          $ratingServiceSelectionRequestHeader .=
 525          "   <Shipment>\n".
 526          "       <Shipper>\n";
 527          if ($this->use_negotiated_rates == 'True') {
 528          $ratingServiceSelectionRequestHeader .=
 529          "         <ShipperNumber>" . $this->access_account_number . "</ShipperNumber>\n";
 530          }
 531          $ratingServiceSelectionRequestHeader .=
 532          "           <Address>\n".
 533          "               <City>". $this->_upsOriginCity ."</City>\n".
 534          "               <StateProvinceCode>". $this->_upsOriginStateProv ."</StateProvinceCode>\n".
 535          "               <CountryCode>". $this->_upsOriginCountryCode ."</CountryCode>\n".
 536          "               <PostalCode>". $this->_upsOriginPostalCode ."</PostalCode>\n".
 537          "           </Address>\n".
 538          "       </Shipper>\n".
 539          "       <ShipTo>\n".
 540          "           <Address>\n".
 541          "               <City>". $this->_upsDestCity ."</City>\n".
 542          "               <StateProvinceCode>". $this->_upsDestStateProv ."</StateProvinceCode>\n".
 543          "               <CountryCode>". $this->_upsDestCountryCode ."</CountryCode>\n".
 544          "               <PostalCode>". $this->_upsDestPostalCode ."</PostalCode>\n".
 545          ($this->quote_type == "Residential" ? "<ResidentialAddressIndicator/>\n" : "") .
 546          "           </Address>\n".
 547          "       </ShipTo>\n";
 548          for ($i = 0; $i < $this->items_qty; $i++) {
 549  
 550              $ratingServiceSelectionRequestPackageContent .=
 551              "       <Package>\n".
 552              "           <PackagingType>\n".
 553              "               <Code>". $this->package_types[$this->package_type] ."</Code>\n".
 554              "           </PackagingType>\n";
 555              if ($this->dimensions_support > 0 && ($this->item_length[$i] > 0 ) && ($this->item_width[$i] > 0 ) && ($this->item_height[$i] > 0)) {
 556  
 557                  $ratingServiceSelectionRequestPackageContent .=
 558                  "           <Dimensions>\n".
 559                  "               <UnitOfMeasurement>\n".
 560                  "                   <Code>". $this->unit_length ."</Code>\n".
 561                  "               </UnitOfMeasurement>\n".
 562                  "               <Length>". $this->item_length[$i] ."</Length>\n".
 563                  "               <Width>". $this->item_width[$i] ."</Width>\n".
 564                  "               <Height>". $this->item_height[$i] ."</Height>\n".
 565                  "           </Dimensions>\n";
 566              }
 567  
 568              $ratingServiceSelectionRequestPackageContent .=
 569              "           <PackageWeight>\n".
 570              "               <UnitOfMeasurement>\n".
 571              "                   <Code>". $this->unit_weight ."</Code>\n".
 572              "               </UnitOfMeasurement>\n".
 573              "               <Weight>". $this->item_weight[$i] ."</Weight>\n".
 574              "           </PackageWeight>\n".
 575              "           <PackageServiceOptions>\n".
 576              //"               <COD>\n".
 577              //"                   <CODFundsCode>0</CODFundsCode>\n".
 578              //"                   <CODCode>3</CODCode>\n".
 579              //"                   <CODAmount>\n".
 580              //"                       <CurrencyCode>USD</CurrencyCode>\n".
 581              //"                       <MonetaryValue>1000</MonetaryValue>\n".
 582              //"                   </CODAmount>\n".
 583              //"               </COD>\n".
 584              "               <InsuredValue>\n".
 585              "                   <CurrencyCode>".MODULE_SHIPPING_UPSXML_CURRENCY_CODE."</CurrencyCode>\n".
 586              "                   <MonetaryValue>".$this->item_price[$i]."</MonetaryValue>\n".
 587              "               </InsuredValue>\n".
 588              "           </PackageServiceOptions>\n".
 589              "       </Package>\n";
 590          }
 591  
 592          $ratingServiceSelectionRequestFooter = '';
 593          //"   <ShipmentServiceOptions/>\n".
 594             if ($this->use_negotiated_rates == 'True') {
 595          $ratingServiceSelectionRequestFooter .=
 596              "       <RateInformation>\n".
 597              "         <NegotiatedRatesIndicator/>\n".
 598              "       </RateInformation>\n";
 599             }
 600          $ratingServiceSelectionRequestFooter .=
 601          "   </Shipment>\n";
 602          // according to UPS the CustomerClassification and PickupType containers should
 603          // not be present when the origin country is non-US see:
 604          // http://forums.oscommerce.com/index.php?s=&showtopic=49382&view=findpost&p=730947
 605          if ($this->origin_country == 'US') {
 606          $ratingServiceSelectionRequestFooter .=
 607                "   <CustomerClassification>\n".
 608                "       <Code>". $this->customer_classification ."</Code>\n".
 609                "   </CustomerClassification>\n";
 610          }
 611          $ratingServiceSelectionRequestFooter .=
 612          "</RatingServiceSelectionRequest>\n";
 613  
 614          $xmlRequest = $accessRequestHeader .
 615          $ratingServiceSelectionRequestHeader .
 616          $ratingServiceSelectionRequestPackageContent .
 617          $ratingServiceSelectionRequestFooter;
 618  
 619          //post request $strXML;
 620          $xmlResult = $this->_post($this->protocol, $this->host, $this->port, $this->path, $this->version, $this->timeout, $xmlRequest);
 621          // BOF testing with a response from UPS saved as a text file
 622          // needs commenting out the line above: $xmlResult = $this->_post($this->protocol, etcetera
 623  /*        $filename = '/srv/www/htdocs/catalog/includes/modules/shipping/example_response.xml';
 624          $fp = fopen($filename, "r") or die("couldn't open file");
 625          $xmlResult = "";
 626          while (! feof($fp)) {
 627            $xmlResult .= fgets($fp, 1024);
 628          } 
 629          // EOF testing with a text file */
 630          return $this->_parseResult($xmlResult);
 631      }
 632  
 633      //******************************************************************
 634      function _post($protocol, $host, $port, $path, $version, $timeout, $xmlRequest) {
 635          $url = $protocol."://".$host.":".$port.$path;
 636          if ($this->logfile) {
 637              error_log("------------------------------------------\n", 3, $this->logfile);
 638              error_log("DATE AND TIME: ".date('Y-m-d H:i:s')."\n", 3, $this->logfile);
 639              error_log("UPS URL: " . $url . "\n", 3, $this->logfile);
 640          }
 641          if (function_exists('exec') && $this->use_exec == '1' ) {
 642              exec('which curl', $curl_output);
 643              if ($curl_output) {
 644                  $curl_path = $curl_output[0];
 645              } else {
 646                  $curl_path = 'curl'; // change this if necessary
 647              }
 648              if ($this->logfile) {
 649                  error_log("UPS REQUEST using exec(): " . $xmlRequest . "\n", 3, $this->logfile);
 650              }
 651              // add option -k to the statement: $command = "".$curl_path." -k -d \"". etcetera if you get
 652              // curl error 60: error setting certificate verify locations
 653              // using addslashes was the only way to avoid UPS returning the 1001 error: The XML document is not well formed
 654              $command = "".$curl_path." -d \"".addslashes($xmlRequest)."\" ".$url."";
 655              exec($command, $xmlResponse);
 656              if ( empty($xmlResponse) && $this->logfile) { // using exec no curl errors can be retrieved
 657                  error_log("Error from cURL using exec() since there is no \$xmlResponse\n", 3, $this->logfile);
 658              }
 659              if ($this->logfile) {
 660                  error_log("UPS RESPONSE using exec(): " . $xmlResponse[0] . "\n", 3, $this->logfile);
 661              }
 662          } elseif ($this->use_exec == '1') { // if NOT (function_exists('exec') && $this->use_exec == '1'
 663              if ($this->logfile) {
 664                  error_log("Sorry, exec() cannot be called\n", 3, $this->logfile);
 665              }
 666          } else { // default behavior: cURL is assumed to be compiled in PHP
 667              $ch = curl_init();
 668              curl_setopt($ch, CURLOPT_URL, $url);
 669              // uncomment the next line if you get curl error 60: error setting certificate verify locations
 670              // curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0);
 671              // uncommenting the next line is most likely not necessary in case of error 60
 672              // curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0);
 673              curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
 674              curl_setopt($ch, CURLOPT_HEADER, 0);
 675              curl_setopt($ch, CURLOPT_POST, 1);
 676              curl_setopt($ch, CURLOPT_POSTFIELDS, $xmlRequest);
 677              curl_setopt($ch, CURLOPT_TIMEOUT, (int)$timeout);
 678  
 679              if ($this->logfile) {
 680                  error_log("UPS REQUEST: " . $xmlRequest . "\n", 3, $this->logfile);
 681              }
 682              $xmlResponse = curl_exec ($ch);
 683              if (curl_errno($ch) && $this->logfile) {
 684                  $error_from_curl = sprintf('Error [%d]: %s', curl_errno($ch), curl_error($ch));
 685                  error_log("Error from cURL: " . $error_from_curl . "\n", 3, $this->logfile);
 686              }
 687              // send email if enabled in the admin section
 688              if (curl_errno($ch) && $this->email_errors) {
 689                  $error_from_curl = sprintf('Error [%d]: %s', curl_errno($ch), curl_error($ch));
 690                  error_log("Error from cURL: " . $error_from_curl . " experienced by customer with id " . $_SESSION['customer_id'] . " on " . date('Y-m-d H:i:s'), 1, STORE_OWNER_EMAIL_ADDRESS);
 691              }
 692              // log errors to file ups_error.log when set
 693              if (curl_errno($ch) && $this->ups_error_file) {
 694                  $error_from_curl = sprintf('Error [%d]: %s', curl_errno($ch), curl_error($ch));
 695                  error_log(date('Y-m-d H:i:s')."\tcURL\t" . $error_from_curl . "\t" . $_SESSION['customer_id']."\n", 3, $this->ups_error_file);    
 696              }
 697              if ($this->logfile) {
 698                  error_log("UPS RESPONSE: " . $xmlResponse . "\n", 3, $this->logfile);
 699              }
 700              curl_close ($ch);
 701          }
 702  
 703          if(!$xmlResponse || strstr(strtolower(substr($xmlResponse, 0, 120)), "bad request"))  {
 704              /* Sometimes the UPS server responds with an HTML message (differing depending on whether the test server
 705                 or the production server is used) but both have in the title tag "Bad request".
 706                 Parsing this response will result in a fatal error:
 707                 Call to a member function on a non-object in /blabla/includes/classes/xmldocument.php on line 57
 708                 It only results in not showing Estimated Delivery Dates to the customer so avoiding the fatal error should do.
 709              */
 710              $xmlResponse = "<?xml version=\"1.0\"?>\n".
 711              "<RatingServiceSelectionResponse>\n".
 712              "   <Response>\n".
 713              "       <TransactionReference>\n".
 714              "           <CustomerContext>Rating and Service</CustomerContext>\n".
 715              "           <XpciVersion>1.0001</XpciVersion>\n".
 716              "       </TransactionReference>\n".
 717              "       <ResponseStatusCode>0</ResponseStatusCode>\n".
 718              "       <ResponseStatusDescription>". MODULE_SHIPPING_UPSXML_RATES_TEXT_COMM_UNKNOWN_ERROR ."</ResponseStatusDescription>\n".
 719              "   </Response>\n".
 720              "</RatingServiceSelectionResponse>\n";
 721              return $xmlResponse;
 722          }
 723          if ($this->use_exec == '1') {
 724              return $xmlResponse[0]; // $xmlResponse is an array in this case
 725          } else {
 726              return $xmlResponse;
 727          }
 728      }
 729  
 730      //*****************************
 731      function _parseResult($xmlResult) {
 732          // Parse XML message returned by the UPS post server.
 733          $doc = XML_unserialize ($xmlResult);
 734  
 735          // Get version. Must be xpci version 1.0001 or this might not work.
 736          $responseVersion = $doc['RatingServiceSelectionResponse']['Response']['TransactionReference']['XpciVersion'];
 737          if ($this->xpci_version != $responseVersion) {
 738              $message = MODULE_SHIPPING_UPSXML_RATES_TEXT_COMM_VERSION_ERROR;
 739              return $message;
 740          }
 741          // Get response code: 1 = SUCCESS, 0 = FAIL
 742          $responseStatusCode = $doc['RatingServiceSelectionResponse']['Response']['ResponseStatusCode'];
 743          if ($responseStatusCode != '1') {
 744              $errorMsg = $doc['RatingServiceSelectionResponse']['Response']['Error']['ErrorCode'];
 745              $errorMsg .= ": ";
 746              $errorMsg .= $doc['RatingServiceSelectionResponse']['Response']['Error']['ErrorDescription'];
 747              // send email if enabled in the admin section
 748              if ($this->email_errors) {
 749                  error_log("UPSXML Rates Error: " . $errorMsg . " experienced by customer with id " . $_SESSION['customer_id'] . " on " . date('Y-m-d H:i:s'), 1, STORE_OWNER_EMAIL_ADDRESS);
 750              }
 751              // log errors to file ups_error.log when set
 752              if ($this->ups_error_file) {
 753                  error_log(date('Y-m-d H:i:s')."\tRates\t" . $errorMsg . "\t" . $_SESSION['customer_id']."\n", 3, $this->ups_error_file);    
 754              }
 755                  return $errorMsg;
 756          }
 757  
 758          $ratedShipments = $doc['RatingServiceSelectionResponse']['RatedShipment'];
 759  
 760          $aryProducts = false;
 761          if (isset($doc['RatingServiceSelectionResponse']['RatedShipment'][0])) { // more than 1 rate
 762            for ($i = 0; $i < count($ratedShipments); $i++) {
 763              $serviceCode = $ratedShipments[$i]['Service']['Code'];
 764              if ($this->use_negotiated_rates == 'True' && isset($ratedShipments[$i]['NegotiatedRates']['NetSummaryCharges']['GrandTotal']['MonetaryValue'])) {
 765                  $totalCharge = $ratedShipments[$i]['NegotiatedRates']['NetSummaryCharges']['GrandTotal']['MonetaryValue'];
 766                } else {
 767  // either a negotiated rate was not given or the shipper does not get/wants any
 768                  $totalCharge = $ratedShipments[$i]['TotalCharges']['MonetaryValue'];
 769                }
 770                if (!($serviceCode && $totalCharge)) {
 771                  continue;
 772                } 
 773              $ratedPackages = $ratedShipments[0]['RatedPackage']; // only do this once for the first service given
 774              if (isset($ratedShipments[0]['RatedPackage'][0])) { // multidimensional array of packages
 775                $this->boxCount = count($ratedPackages);
 776              } else {
 777                $this->boxCount = 1; // if there is only one package count($ratedPackages) returns
 778                // the number of fields in the array like TransportationCharges and BillingWeight
 779              }
 780              $title = '';
 781              $title = $this->service_codes[$this->origin][$serviceCode];
 782              $aryProducts[$i] = array($title => $totalCharge);
 783            } // end for ($i = 0; $i < count($ratedShipments); $i++)
 784          } elseif (isset($doc['RatingServiceSelectionResponse']['RatedShipment'])) { // only 1 rate
 785            $serviceCode = $ratedShipments['Service']['Code'];
 786              if ($this->use_negotiated_rates == 'True' && isset($ratedShipments['NegotiatedRates']['NetSummaryCharges']['GrandTotal']['MonetaryValue'])) {
 787                  $totalCharge = $ratedShipments['NegotiatedRates']['NetSummaryCharges']['GrandTotal']['MonetaryValue'];
 788                } else {
 789  // either a negotiated rate was not given or the shipper does not get/wants any
 790                  $totalCharge = $ratedShipments['TotalCharges']['MonetaryValue'];
 791                }
 792                if (!($serviceCode && $totalCharge)) {
 793                  return $aryProducts; // is false
 794                } 
 795              $ratedPackages = $ratedShipments['RatedPackage']; // only do this once for the first service given
 796              if (isset($ratedShipments['RatedPackage'][0])) { // multidimensional array of packages
 797                $this->boxCount = count($ratedPackages);
 798              } else {
 799                $this->boxCount = 1; // if there is only one package count($ratedPackages) returns
 800                // the number of fields in the array like TransportationCharges and BillingWeight
 801              }
 802              $title = '';
 803              $title = $this->service_codes[$this->origin][$serviceCode];
 804              $aryProducts[] = array($title => $totalCharge);
 805          }
 806          return $aryProducts;
 807      }
 808  
 809      // BOF Time In Transit
 810  
 811      //********************
 812      function _upsGetTimeServices() {
 813  
 814          if (defined('MODULE_SHIPPING_UPSXML_SHIPPING_DAYS_DELAY')) {
 815              $shipdate = date("Ymd", $this->today_unix_time + (86400*MODULE_SHIPPING_UPSXML_SHIPPING_DAYS_DELAY));
 816              $day_of_the_week = date ("w", $this->today_unix_time + (86400*MODULE_SHIPPING_UPSXML_SHIPPING_DAYS_DELAY) ) ;
 817              if ($day_of_the_week == "0" || $day_of_the_week == "7") { // order supposed to leave on Sunday
 818                  $shipdate = date("Ymd", $this->today_unix_time + (86400*MODULE_SHIPPING_UPSXML_SHIPPING_DAYS_DELAY) + 86400);
 819              } elseif ($day_of_the_week == "6") { // order supposed to leave on Saturday
 820                  $shipdate = date("Ymd", $this->today_unix_time + (86400*MODULE_SHIPPING_UPSXML_SHIPPING_DAYS_DELAY) + 172800);
 821              } 
 822          } else {
 823              $shipdate = $this->today;
 824          }
 825  
 826          // Create the access request
 827          $accessRequestHeader =
 828          "<?xml version=\"1.0\"?>\n".
 829          "<AccessRequest xml:lang=\"en-US\">\n".
 830          "   <AccessLicenseNumber>". $this->access_key ."</AccessLicenseNumber>\n".
 831          "   <UserId>". $this->access_username ."</UserId>\n".
 832          "   <Password>". $this->access_password ."</Password>\n".
 833          "</AccessRequest>\n";
 834  
 835          $timeintransitSelectionRequestHeader =
 836          "<?xml version=\"1.0\"?>\n".
 837          "<TimeInTransitRequest xml:lang=\"en-US\">\n".
 838          "   <Request>\n".
 839          "       <TransactionReference>\n".
 840          "           <CustomerContext>Time in Transit</CustomerContext>\n".
 841          "           <XpciVersion>". $this->transitxpci_version ."</XpciVersion>\n".
 842          "       </TransactionReference>\n".
 843          "       <RequestAction>TimeInTransit</RequestAction>\n".
 844          "   </Request>\n".
 845          "   <TransitFrom>\n".
 846          "       <AddressArtifactFormat>\n".
 847          "           <PoliticalDivision2>". $this->origin_city ."</PoliticalDivision2>\n".
 848          "           <PoliticalDivision1>". $this->origin_stateprov ."</PoliticalDivision1>\n".
 849          "           <CountryCode>". $this->_upsOriginCountryCode ."</CountryCode>\n".
 850          "           <PostcodePrimaryLow>". $this->origin_postalcode ."</PostcodePrimaryLow>\n".
 851          "       </AddressArtifactFormat>\n".
 852          "   </TransitFrom>\n".
 853          "   <TransitTo>\n".
 854          "       <AddressArtifactFormat>\n".
 855          "           <PoliticalDivision2>". $this->_upsDestCity ."</PoliticalDivision2>\n".
 856          "           <PoliticalDivision1>". $this->_upsDestStateProv ."</PoliticalDivision1>\n".
 857          "           <CountryCode>". $this->_upsDestCountryCode ."</CountryCode>\n".
 858          "           <PostcodePrimaryLow>". $this->_upsDestPostalCode ."</PostcodePrimaryLow>\n".
 859          "           <PostcodePrimaryHigh>". $this->_upsDestPostalCode ."</PostcodePrimaryHigh>\n".
 860          "       </AddressArtifactFormat>\n".
 861          "   </TransitTo>\n".
 862          "   <ShipmentWeight>\n".
 863          "       <UnitOfMeasurement>\n".
 864          "           <Code>" . $this->unit_weight . "</Code>\n".
 865          "       </UnitOfMeasurement>\n".
 866          "       <Weight>" . $this->weight_for_timeintransit . "</Weight>\n".
 867          "   </ShipmentWeight>\n".
 868          "   <InvoiceLineTotal>\n".
 869          "       <CurrencyCode>" . MODULE_SHIPPING_UPSXML_CURRENCY_CODE . "</CurrencyCode>\n".
 870          "       <MonetaryValue>" . $this->pkgvalue . "</MonetaryValue>\n".
 871          "   </InvoiceLineTotal>\n".
 872          "   <PickupDate>" . $shipdate . "</PickupDate>\n".
 873          "</TimeInTransitRequest>\n";
 874  
 875          $xmlTransitRequest = $accessRequestHeader .
 876          $timeintransitSelectionRequestHeader;
 877  
 878          //post request $strXML;
 879          $xmlTransitResult = $this->_post($this->protocol, $this->host, $this->port, $this->transitpath, $this->transitversion, $this->timeout, $xmlTransitRequest);
 880          return $this->_transitparseResult($xmlTransitResult);
 881      }
 882  
 883      //***************************************
 884      
 885      // GM 11-15-2004: modified to return array with time for each service, as
 886      //                opposed to single transit time for hardcoded "GND" code
 887  
 888      function _transitparseResult($xmlTransitResult) {
 889           $transitTime = array();
 890  
 891          // Parse XML message returned by the UPS post server.
 892          $doc = XML_unserialize ($xmlTransitResult);
 893          // Get version. Must be xpci version 1.0001 or this might not work.
 894          // 1.0001 and 1.0002 seem to be very similar, forget about this for the moment
 895          /*        $responseVersion = $doc['TimeInTransitResponse']['Response']['TransactionReference']['XpciVersion'];
 896          if ($this->transitxpci_version != $responseVersion) {
 897              $message = MODULE_SHIPPING_UPSXML_RATES_TEXT_COMM_VERSION_ERROR;
 898              return $message;
 899          } */
 900          // Get response code. 1 = SUCCESS, 0 = FAIL
 901          $responseStatusCode = $doc['TimeInTransitResponse']['Response']['ResponseStatusCode'];
 902          if ($responseStatusCode != '1') {
 903              $errorMsg = $doc['TimeInTransitResponse']['Response']['Error']['ErrorCode'];
 904              $errorMsg .= ": ";
 905              $errorMsg .= $doc['TimeInTransitResponse']['Response']['Error']['ErrorDescription'];
 906              // send email if enabled in the admin section
 907              if ($this->email_errors) {
 908                  error_log("UPSXML TimeInTransit Error: " . $errorMsg . " experienced by customer with id " . $_SESSION['customer_id'] . " on " . date('Y-m-d H:i:s'), 1, STORE_OWNER_EMAIL_ADDRESS);
 909              }
 910              // log errors to file ups_error.log when set
 911              if ($this->ups_error_file) {
 912                  error_log(date('Y-m-d H:i:s')."\tTimeInTransit\t" . $errorMsg . "\t" . $_SESSION['customer_id'] ."\n", 3, $this->ups_error_file);    
 913              }
 914             //  return $errorMsg;
 915             return false;
 916          }
 917  
 918          if (isset($doc['TimeInTransitResponse']['TransitResponse']['ServiceSummary'][0])) { // more than one EDD
 919                 foreach ($doc['TimeInTransitResponse']['TransitResponse']['ServiceSummary'] as $key_index => $service_array) {
 920                      // index by description because that's all we can relate back to the service 
 921                      // with (though it can probably return the code as well but they are very
 922                      // different from those used by the Rates Service and there is a lot of 
 923                      // duplication so pretty useless)
 924                      $serviceDesc = $service_array['Service']['Description'];
 925                      // hack to get EDD for UPS Saver recognized (Time in Transit uses UPS Worldwide Saver
 926                      // but the service in Rates and Services is called UPS Saver)
 927                      if ($serviceDesc == "UPS Worldwide Saver") {
 928                        $serviceDesc = "UPS Saver";
 929                      }
 930                      // only date is used so why bother with days and guaranteed?
 931                      // $transitTime[$serviceDesc]["days"] = $serviceSummary[$s]->getValueByPath("EstimatedArrival/BusinessTransitDays");
 932                      $transitTime[$serviceDesc]['date'] = $service_array['EstimatedArrival']['Date'];
 933                      // $transitTime[$serviceDesc]["guaranteed"] = $serviceSummary[$s]->getValueByPath("Guaranteed/Code");
 934                  } // end foreach ($doc['TimeInTransitResponse']['ServiceSummary'] etc.
 935          } elseif (isset($doc['TimeInTransitResponse']['TransitResponse']['ServiceSummary'])) { // only one EDD
 936            $serviceDesc = $doc['TimeInTransitResponse']['TransitResponse']['ServiceSummary']['Service']['Description'];
 937            $transitTime[$serviceDesc]['date'] = $doc['TimeInTransitResponse']['TransitResponse']['ServiceSummary']['EstimatedArrival']['Date'];
 938          } else {
 939            $errorMsg = MODULE_SHIPPING_UPSXML_TIME_IN_TRANSIT_TEXT_NO_RATES;
 940              if ($this->ups_error_file) {
 941                  error_log(date('Y-m-d H:i:s')."\tTimeInTransit\t" . $errorMsg . "\t" . $_SESSION['customer_id'] ."\n", 3, $this->ups_error_file);    
 942              }
 943            return false;
 944          }
 945          if ($this->logfile) {
 946              error_log("------------------------------------------\n", 3, $this->logfile);
 947              foreach($transitTime as $desc => $time) {
 948                  error_log("Business Transit: " . $desc ." = ". $time["date"] . "\n", 3, $this->logfile);
 949              }
 950          }
 951          return $transitTime;
 952      }
 953  
 954      //EOF Time In Transit
 955   //  ***************************
 956    function exclude_choices($type) {
 957      // Used for exclusion of UPS shipping options, disallowed types are read from db (stored as 
 958      // short defines). The short defines are not used as such, to avoid collisions
 959      // with other shipping modules, they are prefixed with UPSXML_
 960      // These defines are found in the upsxml language file (UPSXML_US_01, UPSXML_CAN_14 etc.)
 961      $disallowed_types = explode(",", MODULE_SHIPPING_UPSXML_TYPES);
 962      if (strstr($type, "UPS")) {
 963          // this will chop off "UPS" from the beginning of the line - typically something like UPS Next Day Air (1 Business Days)
 964          $type_minus_ups = explode("UPS", $type );
 965          $type_root = trim($type_minus_ups[1]);
 966      } // end if (strstr($type, "UPS"):
 967      else { // service description does not contain UPS (unlikely)
 968          $type_root = trim($type);
 969      }
 970      for ($za = 0; $za < count ($disallowed_types); $za++ ) {
 971        // when no disallowed types are present, --none-- is in the db but causes an error because --none-- is
 972        // not added as a define
 973        if ($disallowed_types[$za] == '--none--' ) continue; 
 974          if ($type_root == constant('UPSXML_' . trim($disallowed_types[$za]))) {
 975              return true;
 976          } // end if ($type_root == constant(trim($disallowed_types[$za]))).
 977      }
 978      // if the type is not disallowed:
 979      return false;
 980    }
 981  // Next function used for sorting the shipping quotes on rate: low to high is default.
 982    function rate_sort_func ($a, $b) {
 983      
 984     $av = array_values($a);
 985     $av = $av[0];
 986     $bv = array_values($b);
 987     $bv = $bv[0];
 988  
 989  //  return ($av == $bv) ? 0 : (($av < $bv) ? 1 : -1); // for having the high rates first
 990    return ($av == $bv) ? 0 : (($av > $bv) ? 1 : -1); // low rates first
 991    
 992    }
 993  } // end class upsxml
 994  // Next two functions are used only in the admin for disallowed shipping options.
 995  // The (short) constants like US_12, CAN_14 are stored in the database
 996  // to stay below 255 characters. The defines themselves are found in the upsxml
 997  // language file prefixed with UPSXML_ to avoid collisions with other shipping modules.
 998  // They can be moved to admin/includes/function/general.php if you like but don't forget
 999  // to remove them from this file in future updates or you will get an error in the admin
1000  // about re-declaring functions
1001    function get_multioption_upsxml($values) {
1002           if (tep_not_null($values)) {
1003               $values_array = explode(',', $values);
1004               foreach ($values_array as $key => $_method) {
1005                 if ($_method == '--none--') {
1006                   $method = $_method;
1007                 } else {
1008                   $method = constant('UPSXML_' . trim($_method));
1009                 }
1010                 $readable_values_array[] = $method;
1011               }
1012               $readable_values = implode(', ', $readable_values_array);
1013               return $readable_values;
1014           } else {
1015             return '';
1016           }
1017    }
1018    
1019    function upsxml_cfg_select_multioption_indexed($select_array, $key_value, $key = '') {
1020      for ($i=0; $i<sizeof($select_array); $i++) {
1021        $name = (($key) ? 'configuration[' . $key . '][]' : 'configuration_value');
1022        $string .= '<br><input type="checkbox" name="' . $name . '" value="' . $select_array[$i] . '"';
1023        $key_values = explode( ", ", $key_value);
1024        if ( in_array($select_array[$i], $key_values) ) $string .= ' CHECKED';
1025        $string .= '> ' . constant('UPSXML_' . trim($select_array[$i]));
1026      } 
1027      $string .= '<input type="hidden" name="' . $name . '" value="--none--">';
1028      return $string;
1029    }
1030  ?>


Generated: Fri Jan 1 13:43:16 2010 Cross-referenced by PHPXref 0.7