PageRenderTime 65ms CodeModel.GetById 17ms RepoModel.GetById 0ms app.codeStats 0ms

/app/code/core/Mage/Usa/Model/Shipping/Carrier/Ups.php

https://bitbucket.org/andrewjleavitt/magestudy
PHP | 1048 lines | 834 code | 128 blank | 86 comment | 95 complexity | 3a6283b339759118f8b56de7ff58d2f8 MD5 | raw file
Possible License(s): CC-BY-SA-3.0, LGPL-2.1, GPL-2.0, WTFPL
  1. <?php
  2. /**
  3. * Magento
  4. *
  5. * NOTICE OF LICENSE
  6. *
  7. * This source file is subject to the Open Software License (OSL 3.0)
  8. * that is bundled with this package in the file LICENSE.txt.
  9. * It is also available through the world-wide-web at this URL:
  10. * http://opensource.org/licenses/osl-3.0.php
  11. * If you did not receive a copy of the license and are unable to
  12. * obtain it through the world-wide-web, please send an email
  13. * to license@magentocommerce.com so we can send you a copy immediately.
  14. *
  15. * DISCLAIMER
  16. *
  17. * Do not edit or add to this file if you wish to upgrade Magento to newer
  18. * versions in the future. If you wish to customize Magento for your
  19. * needs please refer to http://www.magentocommerce.com for more information.
  20. *
  21. * @category Mage
  22. * @package Mage_Usa
  23. * @copyright Copyright (c) 2010 Magento Inc. (http://www.magentocommerce.com)
  24. * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
  25. */
  26. /**
  27. * UPS shipping rates estimation
  28. *
  29. * @category Mage
  30. * @package Mage_Usa
  31. * @author Magento Core Team <core@magentocommerce.com>
  32. */
  33. class Mage_Usa_Model_Shipping_Carrier_Ups
  34. extends Mage_Usa_Model_Shipping_Carrier_Abstract
  35. implements Mage_Shipping_Model_Carrier_Interface
  36. {
  37. protected $_code = 'ups';
  38. protected $_request = null;
  39. protected $_result = null;
  40. protected $_xmlAccessRequest = null;
  41. protected $_defaultCgiGatewayUrl = 'http://www.ups.com:80/using/services/rave/qcostcgi.cgi';
  42. /**
  43. * Base currency rate
  44. *
  45. * @var double
  46. */
  47. protected $_baseCurrencyRate;
  48. public function collectRates(Mage_Shipping_Model_Rate_Request $request)
  49. {
  50. if (!$this->getConfigFlag('active')) {
  51. return false;
  52. }
  53. $this->setRequest($request);
  54. $this->_result = $this->_getQuotes();
  55. $this->_updateFreeMethodQuote($request);
  56. return $this->getResult();
  57. }
  58. public function setRequest(Mage_Shipping_Model_Rate_Request $request)
  59. {
  60. $this->_request = $request;
  61. $r = new Varien_Object();
  62. if ($request->getLimitMethod()) {
  63. $r->setAction($this->getCode('action', 'single'));
  64. $r->setProduct($request->getLimitMethod());
  65. } else {
  66. $r->setAction($this->getCode('action', 'all'));
  67. $r->setProduct('GND'.$this->getConfigData('dest_type'));
  68. }
  69. if ($request->getUpsPickup()) {
  70. $pickup = $request->getUpsPickup();
  71. } else {
  72. $pickup = $this->getConfigData('pickup');
  73. }
  74. $r->setPickup($this->getCode('pickup', $pickup));
  75. if ($request->getUpsContainer()) {
  76. $container = $request->getUpsContainer();
  77. } else {
  78. $container = $this->getConfigData('container');
  79. }
  80. $r->setContainer($this->getCode('container', $container));
  81. if ($request->getUpsDestType()) {
  82. $destType = $request->getUpsDestType();
  83. } else {
  84. $destType = $this->getConfigData('dest_type');
  85. }
  86. $r->setDestType($this->getCode('dest_type', $destType));
  87. if ($request->getOrigCountry()) {
  88. $origCountry = $request->getOrigCountry();
  89. } else {
  90. $origCountry = Mage::getStoreConfig(Mage_Shipping_Model_Config::XML_PATH_ORIGIN_COUNTRY_ID, $this->getStore());
  91. }
  92. $r->setOrigCountry(Mage::getModel('directory/country')->load($origCountry)->getIso2Code());
  93. if ($request->getOrigRegionCode()) {
  94. $origRegionCode = $request->getOrigRegionCode();
  95. } else {
  96. $origRegionCode = Mage::getStoreConfig(Mage_Shipping_Model_Config::XML_PATH_ORIGIN_REGION_ID, $this->getStore());
  97. if (is_numeric($origRegionCode)) {
  98. $origRegionCode = Mage::getModel('directory/region')->load($origRegionCode)->getCode();
  99. }
  100. }
  101. $r->setOrigRegionCode($origRegionCode);
  102. if ($request->getOrigPostcode()) {
  103. $r->setOrigPostal($request->getOrigPostcode());
  104. } else {
  105. $r->setOrigPostal(Mage::getStoreConfig(Mage_Shipping_Model_Config::XML_PATH_ORIGIN_POSTCODE, $this->getStore()));
  106. }
  107. if ($request->getOrigCity()) {
  108. $r->setOrigCity($request->getOrigCity());
  109. } else {
  110. $r->setOrigCity(Mage::getStoreConfig(Mage_Shipping_Model_Config::XML_PATH_ORIGIN_CITY, $this->getStore()));
  111. }
  112. if ($request->getDestCountryId()) {
  113. $destCountry = $request->getDestCountryId();
  114. } else {
  115. $destCountry = self::USA_COUNTRY_ID;
  116. }
  117. //for UPS, puero rico state for US will assume as puerto rico country
  118. if ($destCountry==self::USA_COUNTRY_ID && ($request->getDestPostcode()=='00912' || $request->getDestRegionCode()==self::PUERTORICO_COUNTRY_ID)) {
  119. $destCountry = self::PUERTORICO_COUNTRY_ID;
  120. }
  121. // For UPS, Guam state of the USA will be represented by Guam country
  122. if ($destCountry == self::USA_COUNTRY_ID && $request->getDestRegionCode() == self::GUAM_REGION_CODE) {
  123. $destCountry = self::GUAM_COUNTRY_ID;
  124. }
  125. $r->setDestCountry(Mage::getModel('directory/country')->load($destCountry)->getIso2Code());
  126. $r->setDestRegionCode($request->getDestRegionCode());
  127. if ($request->getDestPostcode()) {
  128. $r->setDestPostal($request->getDestPostcode());
  129. } else {
  130. }
  131. $weight = $this->getTotalNumOfBoxes($request->getPackageWeight());
  132. $weight = $this->_getCorrectWeight($weight);
  133. $r->setWeight($weight);
  134. if ($request->getFreeMethodWeight()!=$request->getPackageWeight()) {
  135. $r->setFreeMethodWeight($request->getFreeMethodWeight());
  136. }
  137. $r->setValue($request->getPackageValue());
  138. $r->setValueWithDiscount($request->getPackageValueWithDiscount());
  139. if ($request->getUpsUnitMeasure()) {
  140. $unit = $request->getUpsUnitMeasure();
  141. } else {
  142. $unit = $this->getConfigData('unit_of_measure');
  143. }
  144. $r->setUnitMeasure($unit);
  145. $this->_rawRequest = $r;
  146. return $this;
  147. }
  148. /**
  149. * Get correct weigt.
  150. *
  151. * Namely:
  152. * Checks the current weight to comply with the minimum weight standards set by the carrier.
  153. * Then strictly rounds the weight up until the first significant digit after the decimal point.
  154. *
  155. * @param float|integer|double $weight
  156. * @return float
  157. */
  158. protected function _getCorrectWeight($weight)
  159. {
  160. $minWeight = $this->getConfigData('min_package_weight');
  161. if($weight < $minWeight){
  162. $weight = $minWeight;
  163. }
  164. //rounds a number to one significant figure
  165. $weight = ceil($weight*10) / 10;
  166. return $weight;
  167. }
  168. public function getResult()
  169. {
  170. return $this->_result;
  171. }
  172. protected function _getQuotes()
  173. {
  174. switch ($this->getConfigData('type')) {
  175. case 'UPS':
  176. return $this->_getCgiQuotes();
  177. case 'UPS_XML':
  178. return $this->_getXmlQuotes();
  179. }
  180. return null;
  181. }
  182. protected function _setFreeMethodRequest($freeMethod)
  183. {
  184. $r = $this->_rawRequest;
  185. $weight = $this->getTotalNumOfBoxes($r->getFreeMethodWeight());
  186. $weight = $this->_getCorrectWeight($weight);
  187. $r->setWeight($weight);
  188. $r->setAction($this->getCode('action', 'single'));
  189. $r->setProduct($freeMethod);
  190. }
  191. protected function _getCgiQuotes()
  192. {
  193. $r = $this->_rawRequest;
  194. $params = array(
  195. 'accept_UPS_license_agreement' => 'yes',
  196. '10_action' => $r->getAction(),
  197. '13_product' => $r->getProduct(),
  198. '14_origCountry' => $r->getOrigCountry(),
  199. '15_origPostal' => $r->getOrigPostal(),
  200. 'origCity' => $r->getOrigCity(),
  201. '19_destPostal' => 'US' == $r->getDestCountry() ? substr($r->getDestPostal(), 0, 5) : $r->getDestPostal(), // UPS returns error for zip+4 US codes
  202. '22_destCountry' => $r->getDestCountry(),
  203. '23_weight' => $r->getWeight(),
  204. '47_rate_chart' => $r->getPickup(),
  205. '48_container' => $r->getContainer(),
  206. '49_residential' => $r->getDestType(),
  207. 'weight_std' => strtolower($r->getUnitMeasure()),
  208. );
  209. $params['47_rate_chart'] = $params['47_rate_chart']['label'];
  210. $responseBody = $this->_getCachedQuotes($params);
  211. if ($responseBody === null) {
  212. $debugData = array('request' => $params);
  213. try {
  214. $url = $this->getConfigData('gateway_url');
  215. if (!$url) {
  216. $url = $this->_defaultCgiGatewayUrl;
  217. }
  218. $client = new Zend_Http_Client();
  219. $client->setUri($url);
  220. $client->setConfig(array('maxredirects'=>0, 'timeout'=>30));
  221. $client->setParameterGet($params);
  222. $response = $client->request();
  223. $responseBody = $response->getBody();
  224. $debugData['result'] = $responseBody;
  225. $this->_setCachedQuotes($params, $responseBody);
  226. }
  227. catch (Exception $e) {
  228. $debugData['result'] = array('error' => $e->getMessage(), 'code' => $e->getCode());
  229. $responseBody = '';
  230. }
  231. $this->_debug($debugData);
  232. }
  233. return $this->_parseCgiResponse($responseBody);
  234. }
  235. public function getShipmentByCode($code,$origin = null){
  236. if($origin===null){
  237. $origin = $this->getConfigData('origin_shipment');
  238. }
  239. $arr = $this->getCode('originShipment',$origin);
  240. if(isset($arr[$code]))
  241. return $arr[$code];
  242. else
  243. return false;
  244. }
  245. protected function _parseCgiResponse($response)
  246. {
  247. $costArr = array();
  248. $priceArr = array();
  249. $errorTitle = Mage::helper('usa')->__('Unknown error');
  250. if (strlen(trim($response))>0) {
  251. $rRows = explode("\n", $response);
  252. $allowedMethods = explode(",", $this->getConfigData('allowed_methods'));
  253. foreach ($rRows as $rRow) {
  254. $r = explode('%', $rRow);
  255. switch (substr($r[0],-1)) {
  256. case 3: case 4:
  257. if (in_array($r[1], $allowedMethods)) {
  258. $responsePrice = Mage::app()->getLocale()->getNumber($r[8]);
  259. $costArr[$r[1]] = $responsePrice;
  260. $priceArr[$r[1]] = $this->getMethodPrice($responsePrice, $r[1]);
  261. }
  262. break;
  263. case 5:
  264. $errorTitle = $r[1];
  265. break;
  266. case 6:
  267. if (in_array($r[3], $allowedMethods)) {
  268. $responsePrice = Mage::app()->getLocale()->getNumber($r[10]);
  269. $costArr[$r[3]] = $responsePrice;
  270. $priceArr[$r[3]] = $this->getMethodPrice($responsePrice, $r[3]);
  271. }
  272. break;
  273. }
  274. }
  275. asort($priceArr);
  276. }
  277. $result = Mage::getModel('shipping/rate_result');
  278. $defaults = $this->getDefaults();
  279. if (empty($priceArr)) {
  280. $error = Mage::getModel('shipping/rate_result_error');
  281. $error->setCarrier('ups');
  282. $error->setCarrierTitle($this->getConfigData('title'));
  283. //$error->setErrorMessage($errorTitle);
  284. $error->setErrorMessage($this->getConfigData('specificerrmsg'));
  285. $result->append($error);
  286. } else {
  287. foreach ($priceArr as $method=>$price) {
  288. $rate = Mage::getModel('shipping/rate_result_method');
  289. $rate->setCarrier('ups');
  290. $rate->setCarrierTitle($this->getConfigData('title'));
  291. $rate->setMethod($method);
  292. $method_arr = $this->getCode('method', $method);
  293. $rate->setMethodTitle(Mage::helper('usa')->__($method_arr));
  294. $rate->setCost($costArr[$method]);
  295. $rate->setPrice($price);
  296. $result->append($rate);
  297. }
  298. }
  299. #echo "<pre>".print_r($result,1)."</pre>";
  300. return $result;
  301. }
  302. /*
  303. public function isEligibleForFree($method)
  304. {
  305. return $method=='GND' || $method=='GNDCOM' || $method=='GNDRES';
  306. }
  307. */
  308. public function getCode($type, $code='')
  309. {
  310. $codes = array(
  311. 'action'=>array(
  312. 'single'=>'3',
  313. 'all'=>'4',
  314. ),
  315. 'originShipment'=>array(
  316. // United States Domestic Shipments
  317. 'United States Domestic Shipments' => array(
  318. '01' => Mage::helper('usa')->__('UPS Next Day Air'),
  319. '02' => Mage::helper('usa')->__('UPS Second Day Air'),
  320. '03' => Mage::helper('usa')->__('UPS Ground'),
  321. '07' => Mage::helper('usa')->__('UPS Worldwide Express'),
  322. '08' => Mage::helper('usa')->__('UPS Worldwide Expedited'),
  323. '11' => Mage::helper('usa')->__('UPS Standard'),
  324. '12' => Mage::helper('usa')->__('UPS Three-Day Select'),
  325. '13' => Mage::helper('usa')->__('UPS Next Day Air Saver'),
  326. '14' => Mage::helper('usa')->__('UPS Next Day Air Early A.M.'),
  327. '54' => Mage::helper('usa')->__('UPS Worldwide Express Plus'),
  328. '59' => Mage::helper('usa')->__('UPS Second Day Air A.M.'),
  329. '65' => Mage::helper('usa')->__('UPS Saver'),
  330. ),
  331. // Shipments Originating in United States
  332. 'Shipments Originating in United States' => array(
  333. '01' => Mage::helper('usa')->__('UPS Next Day Air'),
  334. '02' => Mage::helper('usa')->__('UPS Second Day Air'),
  335. '03' => Mage::helper('usa')->__('UPS Ground'),
  336. '07' => Mage::helper('usa')->__('UPS Worldwide Express'),
  337. '08' => Mage::helper('usa')->__('UPS Worldwide Expedited'),
  338. '11' => Mage::helper('usa')->__('UPS Standard'),
  339. '12' => Mage::helper('usa')->__('UPS Three-Day Select'),
  340. '14' => Mage::helper('usa')->__('UPS Next Day Air Early A.M.'),
  341. '54' => Mage::helper('usa')->__('UPS Worldwide Express Plus'),
  342. '59' => Mage::helper('usa')->__('UPS Second Day Air A.M.'),
  343. '65' => Mage::helper('usa')->__('UPS Saver'),
  344. ),
  345. // Shipments Originating in Canada
  346. 'Shipments Originating in Canada' => array(
  347. '01' => Mage::helper('usa')->__('UPS Express'),
  348. '02' => Mage::helper('usa')->__('UPS Expedited'),
  349. '07' => Mage::helper('usa')->__('UPS Worldwide Express'),
  350. '08' => Mage::helper('usa')->__('UPS Worldwide Expedited'),
  351. '11' => Mage::helper('usa')->__('UPS Standard'),
  352. '12' => Mage::helper('usa')->__('UPS Three-Day Select'),
  353. '14' => Mage::helper('usa')->__('UPS Express Early A.M.'),
  354. '65' => Mage::helper('usa')->__('UPS Saver'),
  355. ),
  356. // Shipments Originating in the European Union
  357. 'Shipments Originating in the European Union' => array(
  358. '07' => Mage::helper('usa')->__('UPS Express'),
  359. '08' => Mage::helper('usa')->__('UPS Expedited'),
  360. '11' => Mage::helper('usa')->__('UPS Standard'),
  361. '54' => Mage::helper('usa')->__('UPS Worldwide Express PlusSM'),
  362. '65' => Mage::helper('usa')->__('UPS Saver'),
  363. ),
  364. // Polish Domestic Shipments
  365. 'Polish Domestic Shipments' => array(
  366. '07' => Mage::helper('usa')->__('UPS Express'),
  367. '08' => Mage::helper('usa')->__('UPS Expedited'),
  368. '11' => Mage::helper('usa')->__('UPS Standard'),
  369. '54' => Mage::helper('usa')->__('UPS Worldwide Express Plus'),
  370. '65' => Mage::helper('usa')->__('UPS Saver'),
  371. '82' => Mage::helper('usa')->__('UPS Today Standard'),
  372. '83' => Mage::helper('usa')->__('UPS Today Dedicated Courrier'),
  373. '84' => Mage::helper('usa')->__('UPS Today Intercity'),
  374. '85' => Mage::helper('usa')->__('UPS Today Express'),
  375. '86' => Mage::helper('usa')->__('UPS Today Express Saver'),
  376. ),
  377. // Puerto Rico Origin
  378. 'Puerto Rico Origin' => array(
  379. '01' => Mage::helper('usa')->__('UPS Next Day Air'),
  380. '02' => Mage::helper('usa')->__('UPS Second Day Air'),
  381. '03' => Mage::helper('usa')->__('UPS Ground'),
  382. '07' => Mage::helper('usa')->__('UPS Worldwide Express'),
  383. '08' => Mage::helper('usa')->__('UPS Worldwide Expedited'),
  384. '14' => Mage::helper('usa')->__('UPS Next Day Air Early A.M.'),
  385. '54' => Mage::helper('usa')->__('UPS Worldwide Express Plus'),
  386. '65' => Mage::helper('usa')->__('UPS Saver'),
  387. ),
  388. // Shipments Originating in Mexico
  389. 'Shipments Originating in Mexico' => array(
  390. '07' => Mage::helper('usa')->__('UPS Express'),
  391. '08' => Mage::helper('usa')->__('UPS Expedited'),
  392. '54' => Mage::helper('usa')->__('UPS Express Plus'),
  393. '65' => Mage::helper('usa')->__('UPS Saver'),
  394. ),
  395. // Shipments Originating in Other Countries
  396. 'Shipments Originating in Other Countries' => array(
  397. '07' => Mage::helper('usa')->__('UPS Express'),
  398. '08' => Mage::helper('usa')->__('UPS Worldwide Expedited'),
  399. '11' => Mage::helper('usa')->__('UPS Standard'),
  400. '54' => Mage::helper('usa')->__('UPS Worldwide Express Plus'),
  401. '65' => Mage::helper('usa')->__('UPS Saver')
  402. )
  403. ),
  404. 'method'=>array(
  405. '1DM' => Mage::helper('usa')->__('Next Day Air Early AM'),
  406. '1DML' => Mage::helper('usa')->__('Next Day Air Early AM Letter'),
  407. '1DA' => Mage::helper('usa')->__('Next Day Air'),
  408. '1DAL' => Mage::helper('usa')->__('Next Day Air Letter'),
  409. '1DAPI' => Mage::helper('usa')->__('Next Day Air Intra (Puerto Rico)'),
  410. '1DP' => Mage::helper('usa')->__('Next Day Air Saver'),
  411. '1DPL' => Mage::helper('usa')->__('Next Day Air Saver Letter'),
  412. '2DM' => Mage::helper('usa')->__('2nd Day Air AM'),
  413. '2DML' => Mage::helper('usa')->__('2nd Day Air AM Letter'),
  414. '2DA' => Mage::helper('usa')->__('2nd Day Air'),
  415. '2DAL' => Mage::helper('usa')->__('2nd Day Air Letter'),
  416. '3DS' => Mage::helper('usa')->__('3 Day Select'),
  417. 'GND' => Mage::helper('usa')->__('Ground'),
  418. 'GNDCOM' => Mage::helper('usa')->__('Ground Commercial'),
  419. 'GNDRES' => Mage::helper('usa')->__('Ground Residential'),
  420. 'STD' => Mage::helper('usa')->__('Canada Standard'),
  421. 'XPR' => Mage::helper('usa')->__('Worldwide Express'),
  422. 'WXS' => Mage::helper('usa')->__('Worldwide Express Saver'),
  423. 'XPRL' => Mage::helper('usa')->__('Worldwide Express Letter'),
  424. 'XDM' => Mage::helper('usa')->__('Worldwide Express Plus'),
  425. 'XDML' => Mage::helper('usa')->__('Worldwide Express Plus Letter'),
  426. 'XPD' => Mage::helper('usa')->__('Worldwide Expedited'),
  427. ),
  428. 'pickup'=>array(
  429. 'RDP' => array("label"=>'Regular Daily Pickup',"code"=>"01"),
  430. 'OCA' => array("label"=>'On Call Air',"code"=>"07"),
  431. 'OTP' => array("label"=>'One Time Pickup',"code"=>"06"),
  432. 'LC' => array("label"=>'Letter Center',"code"=>"19"),
  433. 'CC' => array("label"=>'Customer Counter',"code"=>"03"),
  434. ),
  435. 'container'=>array(
  436. 'CP' => '00', // Customer Packaging
  437. 'ULE' => '01', // UPS Letter Envelope
  438. 'UT' => '03', // UPS Tube
  439. 'UEB' => '21', // UPS Express Box
  440. 'UW25' => '24', // UPS Worldwide 25 kilo
  441. 'UW10' => '25', // UPS Worldwide 10 kilo
  442. ),
  443. 'container_description'=>array(
  444. 'CP' => Mage::helper('usa')->__('Customer Packaging'),
  445. 'ULE' => Mage::helper('usa')->__('UPS Letter Envelope'),
  446. 'UT' => Mage::helper('usa')->__('UPS Tube'),
  447. 'UEB' => Mage::helper('usa')->__('UPS Express Box'),
  448. 'UW25' => Mage::helper('usa')->__('UPS Worldwide 25 kilo'),
  449. 'UW10' => Mage::helper('usa')->__('UPS Worldwide 10 kilo'),
  450. ),
  451. 'dest_type'=>array(
  452. 'RES' => '01', // Residential
  453. 'COM' => '02', // Commercial
  454. ),
  455. 'dest_type_description'=>array(
  456. 'RES' => Mage::helper('usa')->__('Residential'),
  457. 'COM' => Mage::helper('usa')->__('Commercial'),
  458. ),
  459. 'unit_of_measure'=>array(
  460. 'LBS' => Mage::helper('usa')->__('Pounds'),
  461. 'KGS' => Mage::helper('usa')->__('Kilograms'),
  462. ),
  463. );
  464. if (!isset($codes[$type])) {
  465. // throw Mage::exception('Mage_Shipping', Mage::helper('usa')->__('Invalid UPS CGI code type: %s', $type));
  466. return false;
  467. } elseif (''===$code) {
  468. return $codes[$type];
  469. }
  470. if (!isset($codes[$type][$code])) {
  471. // throw Mage::exception('Mage_Shipping', Mage::helper('usa')->__('Invalid UPS CGI code for type %s: %s', $type, $code));
  472. return false;
  473. } else {
  474. return $codes[$type][$code];
  475. }
  476. }
  477. protected function _getXmlQuotes()
  478. {
  479. $url = $this->getConfigData('gateway_xml_url');
  480. $this->setXMLAccessRequest();
  481. $xmlRequest=$this->_xmlAccessRequest;
  482. $r = $this->_rawRequest;
  483. $params = array(
  484. 'accept_UPS_license_agreement' => 'yes',
  485. '10_action' => $r->getAction(),
  486. '13_product' => $r->getProduct(),
  487. '14_origCountry' => $r->getOrigCountry(),
  488. '15_origPostal' => $r->getOrigPostal(),
  489. 'origCity' => $r->getOrigCity(),
  490. 'origRegionCode' => $r->getOrigRegionCode(),
  491. '19_destPostal' => 'US' == $r->getDestCountry() ? substr($r->getDestPostal(), 0, 5) : $r->getDestPostal(), // UPS returns error for zip+4 US codes
  492. '22_destCountry' => $r->getDestCountry(),
  493. 'destRegionCode' => $r->getDestRegionCode(),
  494. '23_weight' => $r->getWeight(),
  495. '47_rate_chart' => $r->getPickup(),
  496. '48_container' => $r->getContainer(),
  497. '49_residential' => $r->getDestType(),
  498. );
  499. if ($params['10_action'] == '4') {
  500. $params['10_action'] = 'Shop';
  501. $serviceCode = null; // Service code is not relevant when we're asking ALL possible services' rates
  502. } else {
  503. $params['10_action'] = 'Rate';
  504. $serviceCode = $r->getProduct() ? $r->getProduct() : '';
  505. }
  506. $serviceDescription = $serviceCode ? $this->getShipmentByCode($serviceCode) : '';
  507. $xmlRequest .= <<< XMLRequest
  508. <?xml version="1.0"?>
  509. <RatingServiceSelectionRequest xml:lang="en-US">
  510. <Request>
  511. <TransactionReference>
  512. <CustomerContext>Rating and Service</CustomerContext>
  513. <XpciVersion>1.0</XpciVersion>
  514. </TransactionReference>
  515. <RequestAction>Rate</RequestAction>
  516. <RequestOption>{$params['10_action']}</RequestOption>
  517. </Request>
  518. <PickupType>
  519. <Code>{$params['47_rate_chart']['code']}</Code>
  520. <Description>{$params['47_rate_chart']['label']}</Description>
  521. </PickupType>
  522. <Shipment>
  523. XMLRequest;
  524. if ($serviceCode !== null) {
  525. $xmlRequest .= "<Service>" .
  526. "<Code>{$serviceCode}</Code>" .
  527. "<Description>{$serviceDescription}</Description>" .
  528. "</Service>";
  529. }
  530. $xmlRequest .= <<< XMLRequest
  531. <Shipper>
  532. XMLRequest;
  533. if ($this->getConfigFlag('negotiated_active') && ($shipper = $this->getConfigData('shipper_number')) ) {
  534. $xmlRequest .= "<ShipperNumber>{$shipper}</ShipperNumber>";
  535. }
  536. $xmlRequest .= <<< XMLRequest
  537. <Address>
  538. <City>{$params['origCity']}</City>
  539. <PostalCode>{$params['15_origPostal']}</PostalCode>
  540. <CountryCode>{$params['14_origCountry']}</CountryCode>
  541. <StateProvinceCode>{$params['origRegionCode']}</StateProvinceCode>
  542. </Address>
  543. </Shipper>
  544. <ShipTo>
  545. <Address>
  546. <PostalCode>{$params['19_destPostal']}</PostalCode>
  547. <CountryCode>{$params['22_destCountry']}</CountryCode>
  548. <ResidentialAddress>{$params['49_residential']}</ResidentialAddress>
  549. <StateProvinceCode>{$params['destRegionCode']}</StateProvinceCode>
  550. XMLRequest;
  551. $xmlRequest .= ($params['49_residential']==='01' ? "<ResidentialAddressIndicator>{$params['49_residential']}</ResidentialAddressIndicator>" : '');
  552. $xmlRequest .= <<< XMLRequest
  553. </Address>
  554. </ShipTo>
  555. <ShipFrom>
  556. <Address>
  557. <PostalCode>{$params['15_origPostal']}</PostalCode>
  558. <CountryCode>{$params['14_origCountry']}</CountryCode>
  559. <StateProvinceCode>{$params['origRegionCode']}</StateProvinceCode>
  560. </Address>
  561. </ShipFrom>
  562. <Package>
  563. <PackagingType><Code>{$params['48_container']}</Code></PackagingType>
  564. <PackageWeight>
  565. <UnitOfMeasurement><Code>{$r->getUnitMeasure()}</Code></UnitOfMeasurement>
  566. <Weight>{$params['23_weight']}</Weight>
  567. </PackageWeight>
  568. </Package>
  569. XMLRequest;
  570. if ($this->getConfigFlag('negotiated_active')) {
  571. $xmlRequest .= "<RateInformation><NegotiatedRatesIndicator/></RateInformation>";
  572. }
  573. $xmlRequest .= <<< XMLRequest
  574. </Shipment>
  575. </RatingServiceSelectionRequest>
  576. XMLRequest;
  577. $xmlResponse = $this->_getCachedQuotes($xmlRequest);
  578. if ($xmlResponse === null) {
  579. $debugData = array('request' => $xmlRequest);
  580. try {
  581. $ch = curl_init();
  582. curl_setopt($ch, CURLOPT_URL, $url);
  583. curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
  584. curl_setopt($ch, CURLOPT_HEADER, 0);
  585. curl_setopt($ch, CURLOPT_POST, 1);
  586. curl_setopt($ch, CURLOPT_POSTFIELDS, $xmlRequest);
  587. curl_setopt($ch, CURLOPT_TIMEOUT, 30);
  588. curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, (boolean)$this->getConfigFlag('mode_xml'));
  589. $xmlResponse = curl_exec ($ch);
  590. $debugData['result'] = $xmlResponse;
  591. $this->_setCachedQuotes($xmlRequest, $xmlResponse);
  592. }
  593. catch (Exception $e) {
  594. $debugData['result'] = array('error' => $e->getMessage(), 'code' => $e->getCode());
  595. $xmlResponse = '';
  596. }
  597. $this->_debug($debugData);
  598. }
  599. return $this->_parseXmlResponse($xmlResponse);
  600. }
  601. /**
  602. * Get base currency rate
  603. *
  604. * @param string $code
  605. * @return double
  606. */
  607. protected function _getBaseCurrencyRate($code)
  608. {
  609. if (!$this->_baseCurrencyRate) {
  610. $this->_baseCurrencyRate = Mage::getModel('directory/currency')
  611. ->load($code)
  612. ->getAnyRate($this->_request->getBaseCurrency()->getCode());
  613. }
  614. return $this->_baseCurrencyRate;
  615. }
  616. protected function _parseXmlResponse($xmlResponse)
  617. {
  618. $costArr = array();
  619. $priceArr = array();
  620. if (strlen(trim($xmlResponse))>0) {
  621. $xml = new Varien_Simplexml_Config();
  622. $xml->loadString($xmlResponse);
  623. $arr = $xml->getXpath("//RatingServiceSelectionResponse/Response/ResponseStatusCode/text()");
  624. $success = (int)$arr[0];
  625. if ($success===1) {
  626. $arr = $xml->getXpath("//RatingServiceSelectionResponse/RatedShipment");
  627. $allowedMethods = explode(",", $this->getConfigData('allowed_methods'));
  628. // Negotiated rates
  629. $negotiatedArr = $xml->getXpath("//RatingServiceSelectionResponse/RatedShipment/NegotiatedRates");
  630. $negotiatedActive = $this->getConfigFlag('negotiated_active')
  631. && $this->getConfigData('shipper_number')
  632. && !empty($negotiatedArr);
  633. $allowedCurrencies = Mage::getModel('directory/currency')->getConfigAllowCurrencies();
  634. foreach ($arr as $shipElement){
  635. $code = (string)$shipElement->Service->Code;
  636. #$shipment = $this->getShipmentByCode($code);
  637. if (in_array($code, $allowedMethods)) {
  638. if ($negotiatedActive) {
  639. $cost = $shipElement->NegotiatedRates->NetSummaryCharges->GrandTotal->MonetaryValue;
  640. } else {
  641. $cost = $shipElement->TotalCharges->MonetaryValue;
  642. }
  643. //convert price with Origin country currency code to base currency code
  644. $successConversion = true;
  645. $responseCurrencyCode = (string) $shipElement->TotalCharges->CurrencyCode;
  646. if ($responseCurrencyCode) {
  647. if (in_array($responseCurrencyCode, $allowedCurrencies)) {
  648. $cost *= $this->_getBaseCurrencyRate($responseCurrencyCode);
  649. } else {
  650. $errorTitle = Mage::helper('directory')
  651. ->__('Can\'t convert rate from "%s-%s".',
  652. $responseCurrencyCode,
  653. $this->_request->getPackageCurrency()->getCode());
  654. $error = Mage::getModel('shipping/rate_result_error');
  655. $error->setCarrier('ups');
  656. $error->setCarrierTitle($this->getConfigData('title'));
  657. $error->setErrorMessage($errorTitle);
  658. $successConversion = false;
  659. }
  660. }
  661. if ($successConversion) {
  662. $costArr[$code] = $cost;
  663. $priceArr[$code] = $this->getMethodPrice(floatval($cost),$code);
  664. }
  665. }
  666. }
  667. } else {
  668. $arr = $xml->getXpath("//RatingServiceSelectionResponse/Response/Error/ErrorDescription/text()");
  669. $errorTitle = (string)$arr[0][0];
  670. $error = Mage::getModel('shipping/rate_result_error');
  671. $error->setCarrier('ups');
  672. $error->setCarrierTitle($this->getConfigData('title'));
  673. Mage::log($errorTitle);
  674. $error->setErrorMessage($this->getConfigData('specificerrmsg'));
  675. }
  676. }
  677. $result = Mage::getModel('shipping/rate_result');
  678. $defaults = $this->getDefaults();
  679. if (empty($priceArr)) {
  680. $error = Mage::getModel('shipping/rate_result_error');
  681. $error->setCarrier('ups');
  682. $error->setCarrierTitle($this->getConfigData('title'));
  683. if(!isset($errorTitle)){
  684. $errorTitle = Mage::helper('usa')->__('Cannot retrieve shipping rates');
  685. }
  686. Mage::log($errorTitle);
  687. $error->setErrorMessage($this->getConfigData('specificerrmsg'));
  688. $result->append($error);
  689. } else {
  690. foreach ($priceArr as $method=>$price) {
  691. $rate = Mage::getModel('shipping/rate_result_method');
  692. $rate->setCarrier('ups');
  693. $rate->setCarrierTitle($this->getConfigData('title'));
  694. $rate->setMethod($method);
  695. $method_arr = $this->getShipmentByCode($method);
  696. $rate->setMethodTitle($method_arr);
  697. $rate->setCost($costArr[$method]);
  698. $rate->setPrice($price);
  699. $result->append($rate);
  700. }
  701. }
  702. return $result;
  703. }
  704. public function getTracking($trackings)
  705. {
  706. $return = array();
  707. if (!is_array($trackings)) {
  708. $trackings = array($trackings);
  709. }
  710. if ($this->getConfigData('type')=='UPS') {
  711. $this->_getCgiTracking($trackings);
  712. } elseif ($this->getConfigData('type')=='UPS_XML'){
  713. $this->setXMLAccessRequest();
  714. $this->_getXmlTracking($trackings);
  715. }
  716. return $this->_result;
  717. }
  718. protected function setXMLAccessRequest()
  719. {
  720. $userid = $this->getConfigData('username');
  721. $userid_pass = $this->getConfigData('password');
  722. $access_key = $this->getConfigData('access_license_number');
  723. $this->_xmlAccessRequest = <<<XMLAuth
  724. <?xml version="1.0"?>
  725. <AccessRequest xml:lang="en-US">
  726. <AccessLicenseNumber>$access_key</AccessLicenseNumber>
  727. <UserId>$userid</UserId>
  728. <Password>$userid_pass</Password>
  729. </AccessRequest>
  730. XMLAuth;
  731. }
  732. protected function _getCgiTracking($trackings)
  733. {
  734. //ups no longer support tracking for data streaming version
  735. //so we can only reply the popup window to ups.
  736. $result = Mage::getModel('shipping/tracking_result');
  737. $defaults = $this->getDefaults();
  738. foreach($trackings as $tracking){
  739. $status = Mage::getModel('shipping/tracking_result_status');
  740. $status->setCarrier('ups');
  741. $status->setCarrierTitle($this->getConfigData('title'));
  742. $status->setTracking($tracking);
  743. $status->setPopup(1);
  744. $status->setUrl("http://wwwapps.ups.com/WebTracking/processInputRequest?HTMLVersion=5.0&error_carried=true&tracknums_displayed=5&TypeOfInquiryNumber=T&loc=en_US&InquiryNumber1=$tracking&AgreeToTermsAndConditions=yes");
  745. $result->append($status);
  746. }
  747. $this->_result = $result;
  748. return $result;
  749. }
  750. protected function _getXmlTracking($trackings)
  751. {
  752. $url = $this->getConfigData('tracking_xml_url');
  753. foreach($trackings as $tracking){
  754. $xmlRequest=$this->_xmlAccessRequest;
  755. /*
  756. * RequestOption==>'activity' or '1' to request all activities
  757. */
  758. $xmlRequest .= <<<XMLAuth
  759. <?xml version="1.0" ?>
  760. <TrackRequest xml:lang="en-US">
  761. <Request>
  762. <RequestAction>Track</RequestAction>
  763. <RequestOption>activity</RequestOption>
  764. </Request>
  765. <TrackingNumber>$tracking</TrackingNumber>
  766. <IncludeFreight>01</IncludeFreight>
  767. </TrackRequest>
  768. XMLAuth;
  769. $debugData = array('request' => $xmlRequest);
  770. try {
  771. $ch = curl_init();
  772. curl_setopt($ch, CURLOPT_URL, $url);
  773. curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
  774. curl_setopt($ch, CURLOPT_HEADER, 0);
  775. curl_setopt($ch, CURLOPT_POST, 1);
  776. curl_setopt($ch, CURLOPT_POSTFIELDS, $xmlRequest);
  777. curl_setopt($ch, CURLOPT_TIMEOUT, 30);
  778. $xmlResponse = curl_exec ($ch);
  779. $debugData['result'] = $xmlResponse;
  780. curl_close ($ch);
  781. }
  782. catch (Exception $e) {
  783. $debugData['result'] = array('error' => $e->getMessage(), 'code' => $e->getCode());
  784. $xmlResponse = '';
  785. }
  786. $this->_debug($debugData);
  787. $this->_parseXmlTrackingResponse($tracking, $xmlResponse);
  788. }
  789. return $this->_result;
  790. }
  791. protected function _parseXmlTrackingResponse($trackingvalue, $xmlResponse)
  792. {
  793. $errorTitle = 'Unable to retrieve tracking';
  794. $resultArr = array();
  795. $packageProgress = array();
  796. if ($xmlResponse) {
  797. $xml = new Varien_Simplexml_Config();
  798. $xml->loadString($xmlResponse);
  799. $arr = $xml->getXpath("//TrackResponse/Response/ResponseStatusCode/text()");
  800. $success = (int)$arr[0][0];
  801. if($success===1){
  802. $arr = $xml->getXpath("//TrackResponse/Shipment/Service/Description/text()");
  803. $resultArr['service'] = (string)$arr[0];
  804. $arr = $xml->getXpath("//TrackResponse/Shipment/PickupDate/text()");
  805. $resultArr['shippeddate'] = (string)$arr[0];
  806. $arr = $xml->getXpath("//TrackResponse/Shipment/Package/PackageWeight/Weight/text()");
  807. $weight = (string)$arr[0];
  808. $arr = $xml->getXpath("//TrackResponse/Shipment/Package/PackageWeight/UnitOfMeasurement/Code/text()");
  809. $unit = (string)$arr[0];
  810. $resultArr['weight'] = "{$weight} {$unit}";
  811. $activityTags = $xml->getXpath("//TrackResponse/Shipment/Package/Activity");
  812. if ($activityTags) {
  813. $i=1;
  814. foreach ($activityTags as $activityTag) {
  815. $addArr=array();
  816. if (isset($activityTag->ActivityLocation->Address->City)) {
  817. $addArr[] = (string)$activityTag->ActivityLocation->Address->City;
  818. }
  819. if (isset($activityTag->ActivityLocation->Address->StateProvinceCode)) {
  820. $addArr[] = (string)$activityTag->ActivityLocation->Address->StateProvinceCode;
  821. }
  822. if (isset($activityTag->ActivityLocation->Address->CountryCode)) {
  823. $addArr[] = (string)$activityTag->ActivityLocation->Address->CountryCode;
  824. }
  825. $dateArr = array();
  826. $date = (string)$activityTag->Date;//YYYYMMDD
  827. $dateArr[] = substr($date,0,4);
  828. $dateArr[] = substr($date,4,2);
  829. $dateArr[] = substr($date,-2,2);
  830. $timeArr = array();
  831. $time = (string)$activityTag->Time;//HHMMSS
  832. $timeArr[] = substr($time,0,2);
  833. $timeArr[] = substr($time,2,2);
  834. $timeArr[] = substr($time,-2,2);
  835. if($i==1){
  836. $resultArr['status'] = (string)$activityTag->Status->StatusType->Description;
  837. $resultArr['deliverydate'] = implode('-',$dateArr);//YYYY-MM-DD
  838. $resultArr['deliverytime'] = implode(':',$timeArr);//HH:MM:SS
  839. $resultArr['deliverylocation'] = (string)$activityTag->ActivityLocation->Description;
  840. $resultArr['signedby'] = (string)$activityTag->ActivityLocation->SignedForByName;
  841. if ($addArr) {
  842. $resultArr['deliveryto']=implode(', ',$addArr);
  843. }
  844. }else{
  845. $tempArr=array();
  846. $tempArr['activity'] = (string)$activityTag->Status->StatusType->Description;
  847. $tempArr['deliverydate'] = implode('-',$dateArr);//YYYY-MM-DD
  848. $tempArr['deliverytime'] = implode(':',$timeArr);//HH:MM:SS
  849. if ($addArr) {
  850. $tempArr['deliverylocation']=implode(', ',$addArr);
  851. }
  852. $packageProgress[] = $tempArr;
  853. }
  854. $i++;
  855. }
  856. $resultArr['progressdetail'] = $packageProgress;
  857. }
  858. } else {
  859. $arr = $xml->getXpath("//TrackResponse/Response/Error/ErrorDescription/text()");
  860. $errorTitle = (string)$arr[0][0];
  861. }
  862. }
  863. if (!$this->_result) {
  864. $this->_result = Mage::getModel('shipping/tracking_result');
  865. }
  866. $defaults = $this->getDefaults();
  867. if ($resultArr) {
  868. $tracking = Mage::getModel('shipping/tracking_result_status');
  869. $tracking->setCarrier('ups');
  870. $tracking->setCarrierTitle($this->getConfigData('title'));
  871. $tracking->setTracking($trackingvalue);
  872. $tracking->addData($resultArr);
  873. $this->_result->append($tracking);
  874. } else {
  875. $error = Mage::getModel('shipping/tracking_result_error');
  876. $error->setCarrier('ups');
  877. $error->setCarrierTitle($this->getConfigData('title'));
  878. $error->setTracking($trackingvalue);
  879. $error->setErrorMessage($errorTitle);
  880. $this->_result->append($error);
  881. }
  882. return $this->_result;
  883. }
  884. public function getResponse()
  885. {
  886. $statuses = '';
  887. if ($this->_result instanceof Mage_Shipping_Model_Tracking_Result){
  888. if ($trackings = $this->_result->getAllTrackings()) {
  889. foreach ($trackings as $tracking){
  890. if($data = $tracking->getAllData()){
  891. if (isset($data['status'])) {
  892. $statuses .= Mage::helper('usa')->__($data['status']);
  893. } else {
  894. $statuses .= Mage::helper('usa')->__($data['error_message']);
  895. }
  896. }
  897. }
  898. }
  899. }
  900. if (empty($statuses)) {
  901. $statuses = Mage::helper('usa')->__('Empty response');
  902. }
  903. return $statuses;
  904. }
  905. /**
  906. * Get allowed shipping methods
  907. *
  908. * @return array
  909. */
  910. public function getAllowedMethods()
  911. {
  912. $allowed = explode(',', $this->getConfigData('allowed_methods'));
  913. $arr = array();
  914. $isByCode = $this->getConfigData('type') == 'UPS_XML';
  915. foreach ($allowed as $k) {
  916. $arr[$k] = $isByCode ? $this->getShipmentByCode($k) : $this->getCode('method', $k);
  917. }
  918. return $arr;
  919. }
  920. }