HERE for registration details. USPS expects you to use pounds as weight measure for your products.');
define('MODULE_SHIPPING_USPS_TEXT_ERROR', 'An error occured with the USPS shipping calculations.
If you prefer to use USPS as your shipping method, please contact the store owner.');
define('MODULE_SHIPPING_USPS_TEXT_DAY', 'Day');
define('MODULE_SHIPPING_USPS_TEXT_DAYS', 'Days');
define('MODULE_SHIPPING_USPS_TEXT_WEEKS', 'Weeks');
define('MODULE_SHIPPING_USPS_STATUS', 'True'); // Do you want to offer USPS shipping?
define('MODULE_SHIPPING_USPS_SERVER', 'production'); // An account at USPS is needed to use the Production server // production othervise value may be 'test'
define('MODULE_SHIPPING_USPS_HANDLING', '0'); // Handling fee for this shipping method
define('MODULE_SHIPPING_USPS_TAX_CLASS', '0'); // Use the following tax class on the shipping fee
define('MODULE_SHIPPING_USPS_ZONE', '0'); // If a zone is selected, only enable this shipping method for that zone.
define('MODULE_SHIPPING_USPS_SORT_ORDER', '0'); // Sort order of display.
define('MODULE_SHIPPING_USPS_TYPES', 'PRIORITY, PARCEL'); // EXPRESS, FIRST CLASS, BMP, MEDIA 'Select the domestic services to be offered:
define('MODULE_SHIPPING_USPS_TYPES_INTL', 'EXPRESS MAIL INTERNATIONAL (EMS), EXPRESS MAIL INT, EXPRESS MAIL INT FLAT RATE ENV, PRIORITY MAIL INT, PRIORITY MAIL INT FLAT RATE ENV, PRIORITY MAILINT FLAT RATE BOX, FIRST-CLASS MAIL INT');// 'GLOBAL EXPRESS, GLOBAL EXPRESS NON-DOC RECT, GLOBAL EXPRESS NON-DOC NON-RECT, Select the international services to be offered:
define('MODULE_SHIPPING_USPS_OPTIONS', 'Display weight, Display transit time'); //
//configuration values for insurance
define('MODULE_SHIPPING_USPS_INS1', '1.65');// 'US/Canada insurance for totals $.01-$50.00
define('MODULE_SHIPPING_USPS_INS2', '2.05');// 'US/Canada insurance for totals $50.01-$100
define('MODULE_SHIPPING_USPS_INS3', '2.45');// 'US/Canada insurance for totals $100.01-$200
define('MODULE_SHIPPING_USPS_INS4', '4.60');// 'US/Canada insurance for totals $200.01-$300
define('MODULE_SHIPPING_USPS_INS5', '.90');// 'US/Canada insurance for every $100 over $300 (add)
define('MODULE_SHIPPING_USPS_INS6', '2.40');// 'International insurance for totals $.01-$50.00
define('MODULE_SHIPPING_USPS_INS7', '3.30');// 'International insurance for totals $50.01-$100
define('MODULE_SHIPPING_USPS_INS8', '4.20');// 'International insurance for totals $100.01-$200
define('MODULE_SHIPPING_USPS_INS9', '5.10');// 'International insurance for totals $200.01-$300
define('MODULE_SHIPPING_USPS_INS10', '.90');// 'International insurance for every $100 over $300 (add)
define('MODULE_SHIPPING_USPS_INSURE', 'True');// 'Insure packages shipped by USPS?
define('MODULE_SHIPPING_USPS_INSURE_TAX', 'True');// 'Insure tax on packages shipped by USPS?
class USPS extends ShippingQuoteEngine
{
var $countries, $pounds, $ounces, $insurance_cost = 0, $shipping_origin_country, $store_first_name, $store_last_name, $company_name, $store_name, $store_address1, $store_address2, $store_city, $store_state, $store_zip5, $store_zip4, $store_phone, $usps_userid;
var $order = Array();
var $types = Array();
var $intl_types = Array();
/**
* Path to a request log file
*
* @var string
*/
var $logFilePath = '';
/**
* Creates USPS processing class
*
*/
public function __construct()
{
parent::__construct();
$this->logFilePath = (defined('RESTRICTED') ? RESTRICTED : WRITEABLE . '/user_files') . '/usps.log';
// EXPRESS, FIRST CLASS, PRIORITY, PARCEL, BMP, MEDIA
$this->types = Array(
'EXPRESS' => 'Express Mail',
'FIRST CLASS' => 'First Class Mail',
'PRIORITY' => 'Priority Mail',
'PARCEL' => 'Parcel Post',
'BPM' => 'Bound Printed Matter',
'MEDIA' => 'Media Mail'
);
$this->intl_types = Array(
// 'GLOBAL EXPRESS' => 'Global Express Guaranteed',
// 'GLOBAL EXPRESS NON-DOC RECT' => 'Global Express Guaranteed Non-Document Rectangular',
// 'GLOBAL EXPRESS NON-DOC NON-RECT' => 'Global Express Guaranteed Non-Document Non-Rectangular',
'EXPRESS MAIL INT' => 'Express Mail International (EMS)',
'EXPRESS MAIL INT FLAT RATE ENV' => 'Express Mail International (EMS) Flat Rate Envelope',
'PRIORITY MAIL INT' => 'Priority Mail International',
'PRIORITY MAIL INT FLAT RATE ENV' => 'Priority Mail International Flat Rate Envelope',
'PRIORITY MAIL INT FLAT RATE BOX' => 'Priority Mail International Flat Rate Box',
'FIRST-CLASS MAIL INT' => 'First-Class Mail International'
);
// get 2-symbol country code
$country = $this->Application->ConfigValue('Comm_Shipping_Country');
if ($country != '') {
$this->shipping_origin_country = $this->GetUSPSCountry($country, '');
}
$contact_name = trim($this->_prepare_xml_param($this->Application->ConfigValue('Comm_Contacts_Name')));
$split_pos = strpos($contact_name, ' ');
if ($split_pos === false) {
$this->store_first_name = $contact_name;
$this->store_last_name = '';
} else {
$this->store_first_name = substr($contact_name, 0, $split_pos);
$this->store_last_name = trim(substr($contact_name, $split_pos));
}
$this->company_name = $this->_prepare_xml_param($this->Application->ConfigValue('Comm_CompanyName'));
$this->store_name = $this->_prepare_xml_param($this->Application->ConfigValue('Comm_StoreName'));
$this->store_address1 = $this->_prepare_xml_param($this->Application->ConfigValue('Comm_Shipping_AddressLine1'));
$this->store_address2 = $this->_prepare_xml_param($this->Application->ConfigValue('Comm_Shipping_AddressLine2'));
if ($this->store_address2 == '') {
$this->store_address2 = $this->store_address1;
$this->store_address1 = '';
}
$this->store_city = $this->_prepare_xml_param($this->Application->ConfigValue('Comm_Shipping_City'));
$this->store_state = $this->_prepare_xml_param($this->Application->ConfigValue('Comm_Shipping_State'));
$zip = $this->_prepare_xml_param($this->Application->ConfigValue('Comm_Shipping_ZIP'));
$this->store_zip5 = substr($zip, 0, 5);
$this->store_zip4 = trim(substr($zip, 6), '-');
$this->store_phone = $this->_prepare_xml_param($this->Application->ConfigValue('Comm_Contacts_Phone'));
// get username and password fron config.
$a_params = $this->LoadParams();
$this->usps_userid = $a_params['AccountLogin'];
// Note by Erik: DO NOT CHANGE THIS ARRAY. It's values are sent to USPS service and any changes may impact class main functionality.
$this->countries = array(
'AF' => 'Afghanistan',
'AL' => 'Albania',
'DZ' => 'Algeria',
'AD' => 'Andorra',
'AO' => 'Angola',
'AI' => 'Anguilla',
'AG' => 'Antigua and Barbuda',
'AR' => 'Argentina',
'AM' => 'Armenia',
'AW' => 'Aruba',
'AU' => 'Australia',
'AT' => 'Austria',
'AZ' => 'Azerbaijan',
'BS' => 'Bahamas',
'BH' => 'Bahrain',
'BD' => 'Bangladesh',
'BB' => 'Barbados',
'BY' => 'Belarus',
'BE' => 'Belgium',
'BZ' => 'Belize',
'BJ' => 'Benin',
'BM' => 'Bermuda',
'BT' => 'Bhutan',
'BO' => 'Bolivia',
'BA' => 'Bosnia-Herzegovina',
'BW' => 'Botswana',
'BR' => 'Brazil',
'VG' => 'British Virgin Islands',
'BN' => 'Brunei Darussalam',
'BG' => 'Bulgaria',
'BF' => 'Burkina Faso',
'MM' => 'Burma',
'BI' => 'Burundi',
'KH' => 'Cambodia',
'CM' => 'Cameroon',
'CA' => 'Canada',
'CV' => 'Cape Verde',
'KY' => 'Cayman Islands',
'CF' => 'Central African Republic',
'TD' => 'Chad',
'CL' => 'Chile',
'CN' => 'China',
'CX' => 'Christmas Island (Australia)',
'CC' => 'Cocos Island (Australia)',
'CO' => 'Colombia',
'KM' => 'Comoros',
'CG' => 'Congo (Brazzaville),Republic of the',
'ZR' => 'Congo, Democratic Republic of the',
'CK' => 'Cook Islands (New Zealand)',
'CR' => 'Costa Rica',
'CI' => 'Cote d\'Ivoire (Ivory Coast)',
'HR' => 'Croatia',
'CU' => 'Cuba',
'CY' => 'Cyprus',
'CZ' => 'Czech Republic',
'DK' => 'Denmark',
'DJ' => 'Djibouti',
'DM' => 'Dominica',
'DO' => 'Dominican Republic',
'TP' => 'East Timor (Indonesia)',
'EC' => 'Ecuador',
'EG' => 'Egypt',
'SV' => 'El Salvador',
'GQ' => 'Equatorial Guinea',
'ER' => 'Eritrea',
'EE' => 'Estonia',
'ET' => 'Ethiopia',
'FK' => 'Falkland Islands',
'FO' => 'Faroe Islands',
'FJ' => 'Fiji',
'FI' => 'Finland',
'FR' => 'France',
'GF' => 'French Guiana',
'PF' => 'French Polynesia',
'GA' => 'Gabon',
'GM' => 'Gambia',
'GE' => 'Georgia, Republic of',
'DE' => 'Germany',
'GH' => 'Ghana',
'GI' => 'Gibraltar',
'GB' => 'Great Britain and Northern Ireland',
'GR' => 'Greece',
'GL' => 'Greenland',
'GD' => 'Grenada',
'GP' => 'Guadeloupe',
'GT' => 'Guatemala',
'GN' => 'Guinea',
'GW' => 'Guinea-Bissau',
'GY' => 'Guyana',
'HT' => 'Haiti',
'HN' => 'Honduras',
'HK' => 'Hong Kong',
'HU' => 'Hungary',
'IS' => 'Iceland',
'IN' => 'India',
'ID' => 'Indonesia',
'IR' => 'Iran',
'IQ' => 'Iraq',
'IE' => 'Ireland',
'IL' => 'Israel',
'IT' => 'Italy',
'JM' => 'Jamaica',
'JP' => 'Japan',
'JO' => 'Jordan',
'KZ' => 'Kazakhstan',
'KE' => 'Kenya',
'KI' => 'Kiribati',
'KW' => 'Kuwait',
'KG' => 'Kyrgyzstan',
'LA' => 'Laos',
'LV' => 'Latvia',
'LB' => 'Lebanon',
'LS' => 'Lesotho',
'LR' => 'Liberia',
'LY' => 'Libya',
'LI' => 'Liechtenstein',
'LT' => 'Lithuania',
'LU' => 'Luxembourg',
'MO' => 'Macao',
'MK' => 'Macedonia, Republic of',
'MG' => 'Madagascar',
'MW' => 'Malawi',
'MY' => 'Malaysia',
'MV' => 'Maldives',
'ML' => 'Mali',
'MT' => 'Malta',
'MQ' => 'Martinique',
'MR' => 'Mauritania',
'MU' => 'Mauritius',
'YT' => 'Mayotte (France)',
'MX' => 'Mexico',
'MD' => 'Moldova',
'MC' => 'Monaco (France)',
'MN' => 'Mongolia',
'MS' => 'Montserrat',
'MA' => 'Morocco',
'MZ' => 'Mozambique',
'NA' => 'Namibia',
'NR' => 'Nauru',
'NP' => 'Nepal',
'NL' => 'Netherlands',
'AN' => 'Netherlands Antilles',
'NC' => 'New Caledonia',
'NZ' => 'New Zealand',
'NI' => 'Nicaragua',
'NE' => 'Niger',
'NG' => 'Nigeria',
'KP' => 'North Korea (Korea, Democratic People\'s Republic of)',
'NO' => 'Norway',
'OM' => 'Oman',
'PK' => 'Pakistan',
'PA' => 'Panama',
'PG' => 'Papua New Guinea',
'PY' => 'Paraguay',
'PE' => 'Peru',
'PH' => 'Philippines',
'PN' => 'Pitcairn Island',
'PL' => 'Poland',
'PT' => 'Portugal',
'QA' => 'Qatar',
'RE' => 'Reunion',
'RO' => 'Romania',
'RU' => 'Russia',
'RW' => 'Rwanda',
'SH' => 'Saint Helena',
'KN' => 'Saint Kitts (St. Christopher and Nevis)',
'LC' => 'Saint Lucia',
'PM' => 'Saint Pierre and Miquelon',
'VC' => 'Saint Vincent and the Grenadines',
'SM' => 'San Marino',
'ST' => 'Sao Tome and Principe',
'SA' => 'Saudi Arabia',
'SN' => 'Senegal',
'YU' => 'Serbia-Montenegro',
'SC' => 'Seychelles',
'SL' => 'Sierra Leone',
'SG' => 'Singapore',
'SK' => 'Slovak Republic',
'SI' => 'Slovenia',
'SB' => 'Solomon Islands',
'SO' => 'Somalia',
'ZA' => 'South Africa',
'GS' => 'South Georgia (Falkland Islands)',
'KR' => 'South Korea (Korea, Republic of)',
'ES' => 'Spain',
'LK' => 'Sri Lanka',
'SD' => 'Sudan',
'SR' => 'Suriname',
'SZ' => 'Swaziland',
'SE' => 'Sweden',
'CH' => 'Switzerland',
'SY' => 'Syrian Arab Republic',
'TW' => 'Taiwan',
'TJ' => 'Tajikistan',
'TZ' => 'Tanzania',
'TH' => 'Thailand',
'TG' => 'Togo',
'TK' => 'Tokelau (Union) Group (Western Samoa)',
'TO' => 'Tonga',
'TT' => 'Trinidad and Tobago',
'TN' => 'Tunisia',
'TR' => 'Turkey',
'TM' => 'Turkmenistan',
'TC' => 'Turks and Caicos Islands',
'TV' => 'Tuvalu',
'UG' => 'Uganda',
'UA' => 'Ukraine',
'AE' => 'United Arab Emirates',
'UY' => 'Uruguay',
'UZ' => 'Uzbekistan',
'VU' => 'Vanuatu',
'VA' => 'Vatican City',
'VE' => 'Venezuela',
'VN' => 'Vietnam',
'WF' => 'Wallis and Futuna Islands',
'WS' => 'Western Samoa',
'YE' => 'Yemen',
'ZM' => 'Zambia',
'ZW' => 'Zimbabwe'
);
$this->countryinsure = array(
'AF' => 0,
'AL' => 0,
'DZ' => 2185,
'AD' => 5000,
'AO' => 0,
'AI' => 415,
'AG' => 60,
'AR' => 5000,
'AM' => 1350,
'AW' => 830,
'AU' => 3370,
'AT' => 5000,
'AZ' => 5000,
'BS' => 2795,
'BH' => 0,
'BD' => 5000,
'BB' => 220,
'BY' => 1323,
'BE' => 5000,
'BZ' => 1600,
'BJ' => 170,
'BM' => 440,
'BT' => 440,
'BO' => 0,
'BA' => 5000,
'BW' => 145,
'BR' => 5000,
'VG' => 165,
'BN' => 4405,
'BG' => 1030,
'BF' => 530,
'MM' => 4045,
'BI' => 790,
'KH' => 0,
'CM' => 5000,
'CA' => 675,
'CV' => 0,
'KY' => 0,
'CF' => 4405,
'TD' => 440,
'CL' => 0,
'CN' => 1130,
'CX' => 3370,
'CC' => 3370,
'CO' => 0,
'KM' => 690,
'CG' => 1685,
'ZR' => 0,
'CK' => 980,
'CR' => 0,
'CI' => 5000,
'HR' => 5000,
'CU' => 0,
'CY' => 5000,
'CZ' => 5000,
'DK' => 5000,
'DJ' => 880,
'DM' => 0,
'DO' => 0,
'TP' => 0,
'EC' => 0,
'EG' => 1685,
'SV' => 0,
'GQ' => 0,
'ER' => 0,
'EE' => 2020,
'ET' => 1000,
'FK' => 510,
'FO' => 5000,
'FJ' => 600,
'FI' => 5000,
'FR' => 5000,
'GF' => 5000,
'PF' => 1015,
'GA' => 485,
'GM' => 2575,
'GE' => 1350,
'DE' => 5000,
'GH' => 5000,
'GI' => 5000,
'GB' => 857,
'GR' => 5000,
'GL' => 5000,
'GD' => 350,
'GP' => 5000,
'GT' => 0,
'GN' => 875,
'GW' => 21,
'GY' => 10,
'HT' => 0,
'HN' => 0,
'HK' => 5000,
'HU' => 5000,
'IS' => 5000,
'IN' => 2265,
'ID' => 0,
'IR' => 0,
'IQ' => 0,
'IE' => 5000,
'IL' => 0,
'IT' => 5000,
'JM' => 0,
'JP' => 5000,
'JO' => 0,
'KZ' => 5000,
'KE' => 815,
'KI' => 0,
'KW' => 1765,
'KG' => 1350,
'LA' => 0,
'LV' => 1350,
'LB' => 440,
'LS' => 440,
'LR' => 440,
'LY' => 0,
'LI' => 5000,
'LT' => 5000,
'LU' => 5000,
'MO' => 4262,
'MK' => 2200,
'MG' => 675,
'MW' => 50,
'MY' => 1320,
'MV' => 0,
'ML' => 950,
'MT' => 5000,
'MQ' => 5000,
'MR' => 635,
'MU' => 270,
'YT' => 5000,
'MX' => 0,
'MD' => 1350,
'MC' => 5000,
'MN' => 440,
'MS' => 2200,
'MA' => 5000,
'MZ' => 0,
'NA' => 4405,
'NR' => 220,
'NP' => 0,
'NL' => 5000,
'AN' => 830,
'NC' => 1615,
'NZ' => 980,
'NI' => 440,
'NE' => 810,
'NG' => 205,
'KP' => 0,
'NO' => 0,
'OM' => 575,
'PK' => 270,
'PA' => 0,
'PG' => 445,
'PY' => 0,
'PE' => 0,
'PH' => 270,
'PN' => 0,
'PL' => 1350,
'PT' => 5000,
'QA' => 2515,
'RE' => 5000,
'RO' => 5000,
'RU' => 5000,
'RW' => 0,
'SH' => 170,
'KN' => 210,
'LC' => 400,
'PM' => 5000,
'VC' => 130,
'SM' => 5000,
'ST' => 440,
'SA' => 0,
'SN' => 865,
'YU' => 5000,
'SC' => 0,
'SL' => 0,
'SG' => 4580,
'SK' => 5000,
'SI' => 4400,
'SB' => 0,
'SO' => 440,
'ZA' => 1760,
'GS' => 510,
'KR' => 5000,
'ES' => 5000,
'LK' => 35,
'SD' => 0,
'SR' => 535,
'SZ' => 560,
'SE' => 5000,
'CH' => 5000,
'SY' => 3080,
'TW' => 1350,
'TJ' => 1350,
'TZ' => 230,
'TH' => 1350,
'TG' => 2190,
'TK' => 295,
'TO' => 515,
'TT' => 930,
'TN' => 2200,
'TR' => 880,
'TM' => 675,
'TC' => 0,
'TV' => 4715,
'UG' => 0,
'UA' => 5000,
'AE' => 5000,
'UY' => 0,
'UZ' => 5000,
'VU' => 0,
'VA' => 5000,
'VE' => 0,
'VN' => 0,
'WF' => 1615,
'WS' => 295,
'YE' => 0,
'ZM' => 540,
'ZW' => 600,
'US' => 5000
);
}
function SetInsurance()
{
$this->insurance_cost = 0;
// Insurance module by Kevin Shelton
// divide the value of the order among the packages based on the order total or subtotal depending on whether or not you have configured to insure tax
$shipping_weight = $this->order['ShippingWeight'];
$shipping_num_boxes = $this->order['ShippingNumBoxes'];
$costperpkg = $this->order['SubTotal'] / $shipping_num_boxes;
// retrieve the maximum allowed insurance for the destination country and if the package value exceeds it then set package value to the maximum allowed
$maxins = $this->countryinsure[$this->order['ShippingCountry']];
if ($costperpkg > $maxins) $costperpkg = $maxins;
// if insurance not allowed for destination or insurance is turned off add nothing to shipping cost
if (($maxins == 0) || (MODULE_SHIPPING_USPS_INSURE == 'False')) {
$insurance = 0;
}
// US and Canada share the same insurance calculation (though not the same maximum)
else if (($this->order['ShippingCountry'] == 'US') || ($this->order['ShippingCountry'] == 'CA'))
{
if ($costperpkg<=50) {
$insurance=MODULE_SHIPPING_USPS_INS1;
}
else if ($costperpkg<=100) {
$insurance=MODULE_SHIPPING_USPS_INS2;
}
else if ($costperpkg<=200) {
$insurance=MODULE_SHIPPING_USPS_INS3;
}
else if ($costperpkg<=300) {
$insurance=MODULE_SHIPPING_USPS_INS4;
}
else {
$insurance = MODULE_SHIPPING_USPS_INS4 + ((ceil($costperpkg/100) -3) * MODULE_SHIPPING_USPS_INS5);
}
}
// if insurance allowed and is not US or Canada then calculate international insurance
else {
if ($costperpkg<=50) {
$insurance=MODULE_SHIPPING_USPS_INS6;
}
else if ($costperpkg<=100) {
$insurance=MODULE_SHIPPING_USPS_INS7;
}
else if ($costperpkg<=200) {
$insurance=MODULE_SHIPPING_USPS_INS8;
}
else if ($costperpkg<=300) {
$insurance=MODULE_SHIPPING_USPS_INS9;
}
else {
$insurance = MODULE_SHIPPING_USPS_INS9 + ((ceil($costperpkg/100) - 3) * MODULE_SHIPPING_USPS_INS10);
}
}
// usps doesnt accept zero weight
$shipping_weight = ($shipping_weight < 0.1 ? 0.1 : $shipping_weight);
$shipping_pounds = floor ($shipping_weight);
$shipping_ounces = round(16 * ($shipping_weight - floor($shipping_weight)));
$this->_setWeight($shipping_pounds, $shipping_ounces);
// Added by Kevin Chen (kkchen@uci.edu); Fixes the Parcel Post Bug July 1, 2004
// Refer to http://www.usps.com/webtools/htm/Domestic-Rates.htm documentation
// Thanks Ryan
if($shipping_pounds > 35 || ($shipping_pounds == 0 && $shipping_ounces < 6)){
$this->_setMachinable('False');
}
else{
$this->_setMachinable('True');
}
$this->insurance_cost = $insurance;
// End Kevin Chen July 1, 2004
}
function _setService($service)
{
$this->service = $service;
}
function _setWeight($pounds, $ounces=0)
{
$this->pounds = $pounds;
$this->ounces = $ounces;
}
function _setContainer($container)
{
$this->container = $container;
}
function _setSize($size)
{
$this->size = $size;
}
function _setMachinable($machinable)
{
$this->machinable = $machinable;
}
function PhoneClean($phone)
{
$res = preg_replace('/[(]|[)]|[\-]|[ ]|[#]|[\.]|[a-z](.*)|[A-Z](.*)/g', '', $phone);
if ( strlen($res) > 10 ) {
$res = substr($res, 0, 10);
}
return $res != '' ? $res : $phone;
}
function GetQuote($method = '')
{
if ( isset($this->types[$method]) || in_array($method, $this->intl_types)) {
$this->_setService($method);
}
$this -> _setContainer('None');
$this -> _setSize('REGULAR');
$this -> SetInsurance(); // ???
if ($this->order['ShippingCountry'] == $this->shipping_origin_country) {
$request='';
// PASSWORD="'.$this->usps_password.'"
$request.= '';
$services_count = 0;
if (isset($this->service)) {
$this->types = array($this->service => $this->types[$this->service]);
}
$dest_zip = str_replace(' ', '', $this->order['ShippingZip']);
$dest_zip = substr($dest_zip, 0, 5);
reset($this->types);
$allowed_types = explode(", ", MODULE_SHIPPING_USPS_TYPES);
while (list($key, $value) = each($this->types))
{
if ( !in_array($key, $allowed_types) ) continue;
$request .= ''.
''.$key.''.
''.$this->store_zip5.''.
''.$dest_zip.''.
''.$this->pounds.''.
''.$this->ounces.''.
''.$this->size.''.
''.$this->machinable.''.
'';
$services_count++;
}
$request .= '';
$api_query = 'RateV3';
}
else {
$request = ''.
''.
''.$this->pounds.''.
''.$this->ounces.''.
'Package'.
''.$this->countries[$this->order['ShippingCountry']].''.
''.
'';
$api_query = 'IntlRate';
}
$request = 'API='.$api_query.'&XML=' . urlencode($request);
$body = $this->PostQuery($request);
$body = str_replace(chr(146), '', $body); // for bad `
// check for errors
if (strpos($body, '') !== false) {
$errors = Array ();
preg_match_all('/(.*?)<\/Number>/s', $body, $error_numbers);
preg_match_all('/(.*?)<\/Description>/s', $body, $error_descriptions);
foreach ($error_numbers[1] as $index => $error_number) {
$errors[$index] = $error_descriptions[1][$index];
if ($this->Application->isDebugMode()) {
$errors[$index] .= ' (' . $error_number . ')';
}
}
$errors = array_unique($errors); // we may have same errors on many packages, so don't show duplicates
return Array('error' => implode('
', $errors));
}
// parse response
$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 ='
'.$this->store_name.'
'.$this->company_name.'
'.$this->store_address1.'
'.$this->store_address2.'
'.$this->store_city.'
'.$this->store_state.'
'.$this->store_zip5.'
'.$this->store_zip4.'
'.$this->order['FirstName'].' '.$this->order['LastName'].'
'.$this->order['ShippingCompany'].'
'.$this->order['ShippingAddress2'].'
'.$this->order['ShippingAddress1'].'
'.$this->order['ShippingCity'].'
'.$this->order['ShippingState'].'
'.$this->order['ShippingZip5'].'
'.$this->order['ShippingZip4'].'
'.$WeightInOunces.'
'.$this->order['ShippingService'].'
PDF
'.date('m/d/Y',time()).'
';
$api_query = 'DeliveryConfirmationV3';
$xml_request = 'DeliveryConfirmationV3.0Request';
}
else {
// International Order(s)
$shipping_service = strtolower($this->order['ShippingService']);
$base_request = '
'.$this->store_first_name.'
'.$this->store_last_name.'
'.$this->company_name.'
'.$this->store_address1.'
'.$this->store_address2.'
'.$this->store_city.'
'.$this->store_state.'
'.$this->store_zip5.'
'.$this->PhoneClean($this->store_phone).'
'.$this->order['FirstName'].' '.$this->order['LastName'].'
'.$this->order['ShippingCompany'].'
'.$this->order['ShippingAddress2'].'
'.$this->order['ShippingAddress1'].'
'.$this->order['ShippingCity'].'';
if ( $this->order['ShippingProvince'] != '' ) {
$base_request.='
'.$this->order['ShippingProvince'].'';
}
$base_request.='
'.$this->countries[$this->order['ShippingCountry']].'
'.$this->order['ShippingZip'].'
N
'.$this->PhoneClean($this->order['ShippingPhone']).'
'.$this->PhoneClean($this->order['ShippingFax']).'
'.$this->order['Email'].'
';
// add items
foreach ( $this->order['Items'] as $k => $value ) {
$base_request.='
Computer Parts
'.$value['Qty'].'
'.($value['Price'] * $value['Qty']).'
'.$value['NetPounds'].'
'.$value['NetOunces'].'
123456
United States
';
}
// end add items
$base_request.='
'.$this->pounds.'
'.$this->ounces.'
MERCHANDISE
Y
'.$this->order['InvoiceNumber'].'
PDF
ALLINONEFILE
'.date('m/d/Y',time()).'
';
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, '') !== false) {
$errors = Array ();
preg_match_all('/(.*?)<\/Number>/s', $body, $error_numbers);
preg_match_all('/(.*?)<\/Description>/s', $body, $error_descriptions);
foreach ($error_numbers[1] as $index => $error_number) {
$errors[$index] = 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 = kUtil::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=
$request = '';
$api_query = 'TrackV2';
$request = 'API='.$api_query.'&XML='.urlencode($request);
$body = $this->PostQuery($request);
// check for errors
if (strpos($body, '') !== false) {
$errors = Array ();
preg_match_all('/(.*?)<\/Number>/s', $body, $error_numbers);
preg_match_all('/(.*?)<\/Description>/s', $body, $error_descriptions);
foreach ($error_numbers[1] as $index => $error_number) {
$errors[$index] = $error_descriptions[1][$index];
if ($this->Application->isDebugMode()) {
$errors[$index] .= ' (' . $error_number . ')';
}
}
$errors = array_unique($errors); // we may have same errors on many packages, so don't show duplicates
return Array('error' => implode('
', $errors));
}
$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.'
';
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 ($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"';
$params = $this->Conn->GetOne($sql);
return unserialize($params);
}
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 = kUtil::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 = kUtil::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;
}
}