PageRenderTime 51ms CodeModel.GetById 16ms RepoModel.GetById 0ms app.codeStats 0ms

/app/code/core/Mage/GoogleCheckout/Model/Api/Xml/Checkout.php

https://bitbucket.org/andrewjleavitt/magestudy
PHP | 1135 lines | 786 code | 116 blank | 233 comment | 72 complexity | 87c92af0839ed1cd4aa2203fa49fe136 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_GoogleCheckout
  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. * Google Checkout XML API processing model
  28. *
  29. * @category Mage
  30. * @package Mage_GoogleCheckout
  31. * @author Magento Core Team <core@magentocommerce.com>
  32. */
  33. class Mage_GoogleCheckout_Model_Api_Xml_Checkout extends Mage_GoogleCheckout_Model_Api_Xml_Abstract
  34. {
  35. /**
  36. * Representation value of item weight unit
  37. */
  38. const ITEM_WEIGHT_UNIT = 'LB';
  39. /**
  40. * Representation value of item size unit
  41. */
  42. const ITEM_SIZE_UNIT = 'IN';
  43. /**
  44. * Google checkout namespace URI
  45. */
  46. const CHECKOUT_SHOPPING_CART_XMLNS = 'http://checkout.google.com/schema/2';
  47. /**
  48. * @deprecated after 0.8.16100
  49. *
  50. * @var string
  51. */
  52. protected $_currency;
  53. /**
  54. * Define if shipping rates already calculated
  55. *
  56. * @var boolean
  57. */
  58. protected $_shippingCalculated = false;
  59. /**
  60. * API URL getter
  61. *
  62. * @return string
  63. */
  64. protected function _getApiUrl()
  65. {
  66. $url = $this->_getBaseApiUrl();
  67. $url .= 'merchantCheckout/Merchant/' . $this->getMerchantId();
  68. return $url;
  69. }
  70. /**
  71. * Send checkout data to google
  72. *
  73. * @return Mage_GoogleCheckout_Model_Api_Xml_Checkout
  74. */
  75. public function checkout()
  76. {
  77. $quote = $this->getQuote();
  78. if (!($quote instanceof Mage_Sales_Model_Quote)) {
  79. Mage::throwException('Invalid quote');
  80. }
  81. $xmlns = self::CHECKOUT_SHOPPING_CART_XMLNS;
  82. $xml = <<<EOT
  83. <checkout-shopping-cart xmlns="{$xmlns}">
  84. <shopping-cart>
  85. {$this->_getItemsXml()}
  86. {$this->_getMerchantPrivateDataXml()}
  87. {$this->_getCartExpirationXml()}
  88. </shopping-cart>
  89. <checkout-flow-support>
  90. {$this->_getMerchantCheckoutFlowSupportXml()}
  91. </checkout-flow-support>
  92. <order-processing-support>
  93. {$this->_getRequestInitialAuthDetailsXml()}
  94. </order-processing-support>
  95. </checkout-shopping-cart>
  96. EOT;
  97. $result = $this->_call($xml);
  98. $this->setRedirectUrl($result->{'redirect-url'});
  99. return $this;
  100. }
  101. /**
  102. * Retrieve quote items in XML format
  103. *
  104. * @return string
  105. */
  106. protected function _getItemsXml()
  107. {
  108. $xml = <<<EOT
  109. <items>
  110. EOT;
  111. foreach ($this->getQuote()->getAllItems() as $item) {
  112. if ($item->getParentItem()) {
  113. continue;
  114. }
  115. $taxClass = ($item->getTaxClassId() == 0) ? 'none' : $item->getTaxClassId();
  116. $weight = (float) $item->getWeight();
  117. $weightUnit = self::ITEM_WEIGHT_UNIT;
  118. $xml .= <<<EOT
  119. <item>
  120. <merchant-item-id><![CDATA[{$item->getSku()}]]></merchant-item-id>
  121. <item-name><![CDATA[{$item->getName()}]]></item-name>
  122. <item-description><![CDATA[{$item->getDescription()}]]></item-description>
  123. <unit-price currency="{$this->getCurrency()}">{$item->getBaseCalculationPrice()}</unit-price>
  124. <quantity>{$item->getQty()}</quantity>
  125. <item-weight unit="{$weightUnit}" value="{$weight}" />
  126. <tax-table-selector>{$taxClass}</tax-table-selector>
  127. {$this->_getDigitalContentXml($item->getIsVirtual())}
  128. {$this->_getMerchantPrivateItemDataXml($item)}
  129. </item>
  130. EOT;
  131. }
  132. $billingAddress = $this->getQuote()->getBillingAddress();
  133. $shippingAddress = $this->getQuote()->getShippingAddress();
  134. $shippingDiscount = (float)$shippingAddress->getBaseDiscountAmount();
  135. $billingDiscount = (float)$billingAddress->getBaseDiscountAmount();
  136. $discount = $billingDiscount + $shippingDiscount;
  137. // Exclude shipping discount
  138. // Discount is negative value
  139. $discount += $shippingAddress->getBaseShippingDiscountAmount();
  140. $discountItem = new Varien_Object(array(
  141. 'price' => $discount,
  142. 'name' => $this->__('Cart Discount'),
  143. 'description' => $this->__('A virtual item to reflect the discount total')
  144. ));
  145. Mage::dispatchEvent('google_checkout_discount_item_price', array(
  146. 'quote' => $this->getQuote(),
  147. 'discount_item' => $discountItem
  148. ));
  149. $discount = $discountItem->getPrice();
  150. if ($discount) {
  151. $xml .= <<<EOT
  152. <item>
  153. <merchant-item-id>_INTERNAL_DISCOUNT_</merchant-item-id>
  154. <item-name>{$discountItem->getName()}</item-name>
  155. <item-description>{$discountItem->getDescription()}</item-description>
  156. <unit-price currency="{$this->getCurrency()}">{$discount}</unit-price>
  157. <quantity>1</quantity>
  158. <item-weight unit="{$weightUnit}" value="0.00" />
  159. <tax-table-selector>none</tax-table-selector>
  160. {$this->_getDigitalContentXml($this->getQuote()->isVirtual())}
  161. </item>
  162. EOT;
  163. }
  164. $hiddenTax = $shippingAddress->getBaseHiddenTaxAmount() + $billingAddress->getBaseHiddenTaxAmount();
  165. if ($hiddenTax) {
  166. $xml .= <<<EOT
  167. <item>
  168. <merchant-item-id>_INTERNAL_TAX_</merchant-item-id>
  169. <item-name>{$this->__('Discount Tax')}</item-name>
  170. <item-description>{$this->__('A virtual item to reflect the tax total')}</item-description>
  171. <unit-price currency="{$this->getCurrency()}">{$hiddenTax}</unit-price>
  172. <quantity>1</quantity>
  173. <item-weight unit="{$weightUnit}" value="0.00" />
  174. <tax-table-selector>none</tax-table-selector>
  175. {$this->_getDigitalContentXml($this->getQuote()->isVirtual())}
  176. </item>
  177. EOT;
  178. }
  179. $xml .= <<<EOT
  180. </items>
  181. EOT;
  182. return $xml;
  183. }
  184. /**
  185. * Retrieve digital content XML
  186. *
  187. * @param boolean $isVirtual
  188. * @return string
  189. */
  190. protected function _getDigitalContentXml($isVirtual)
  191. {
  192. if (!$isVirtual) {
  193. return '';
  194. }
  195. $storeId = $this->getQuote()->getStoreId();
  196. $active = Mage::getStoreConfigFlag(Mage_GoogleCheckout_Helper_Data::XML_PATH_SHIPPING_VIRTUAL_ACTIVE, $storeId);
  197. if (!$active) {
  198. return '';
  199. }
  200. $schedule = Mage::getStoreConfig(Mage_GoogleCheckout_Helper_Data::XML_PATH_SHIPPING_VIRTUAL_SCHEDULE, $storeId);
  201. $method = Mage::getStoreConfig(Mage_GoogleCheckout_Helper_Data::XML_PATH_SHIPPING_VIRTUAL_METHOD, $storeId);
  202. $xml = "<display-disposition>{$schedule}</display-disposition>";
  203. if ($method == 'email') {
  204. $xml .= '<email-delivery>true</email-delivery>';
  205. } elseif ($method == 'key_url') {
  206. } elseif ($method == 'description_based') {
  207. }
  208. $xml = "<digital-content>{$xml}</digital-content>";
  209. return $xml;
  210. }
  211. /**
  212. * Convert quote item to private item XML
  213. *
  214. * @param Mage_Sales_Model_Quote_Item $item
  215. * @return string
  216. */
  217. protected function _getMerchantPrivateItemDataXml($item)
  218. {
  219. $xml = <<<EOT
  220. <merchant-private-item-data>
  221. <quote-item-id>{$item->getId()}</quote-item-id>
  222. </merchant-private-item-data>
  223. EOT;
  224. return $xml;
  225. }
  226. /**
  227. * Retrieve merchant private data XML
  228. *
  229. * @return string
  230. */
  231. protected function _getMerchantPrivateDataXml()
  232. {
  233. $xml = <<<EOT
  234. <merchant-private-data>
  235. <quote-id><![CDATA[{$this->getQuote()->getId()}]]></quote-id>
  236. <store-id><![CDATA[{$this->getQuote()->getStoreId()}]]></store-id>
  237. </merchant-private-data>
  238. EOT;
  239. return $xml;
  240. }
  241. /**
  242. * Retrieve quote expiration XML
  243. *
  244. * @return string
  245. */
  246. protected function _getCartExpirationXml()
  247. {
  248. $xml = <<<EOT
  249. EOT;
  250. return $xml;
  251. }
  252. /**
  253. * Retrieve merchant checkout flow support XML
  254. *
  255. * @return string
  256. */
  257. protected function _getMerchantCheckoutFlowSupportXml()
  258. {
  259. $xml = <<<EOT
  260. <merchant-checkout-flow-support>
  261. <edit-cart-url><![CDATA[{$this->_getEditCartUrl()}]]></edit-cart-url>
  262. <continue-shopping-url><![CDATA[{$this->_getContinueShoppingUrl()}]]></continue-shopping-url>
  263. {$this->_getRequestBuyerPhoneNumberXml()}
  264. {$this->_getMerchantCalculationsXml()}
  265. {$this->_getShippingMethodsXml()}
  266. {$this->_getAllTaxTablesXml()}
  267. {$this->_getParameterizedUrlsXml()}
  268. {$this->_getPlatformIdXml()}
  269. {$this->_getAnalyticsDataXml()}
  270. </merchant-checkout-flow-support>
  271. EOT;
  272. return $xml;
  273. }
  274. /**
  275. * Retrieve request buyer phone number XML
  276. *
  277. * @return string
  278. */
  279. protected function _getRequestBuyerPhoneNumberXml()
  280. {
  281. $requestPhone = Mage::getStoreConfig(
  282. Mage_GoogleCheckout_Helper_Data::XML_PATH_REQUEST_PHONE,
  283. $this->getQuote()->getStoreId()
  284. );
  285. $requestPhone = $requestPhone ? 'true' : 'false';
  286. $xml = <<<EOT
  287. <request-buyer-phone-number>{$requestPhone}</request-buyer-phone-number>
  288. EOT;
  289. return $xml;
  290. }
  291. /**
  292. * Retrieve merchant calculations XML
  293. *
  294. * @return string
  295. */
  296. protected function _getMerchantCalculationsXml()
  297. {
  298. $xml = <<<EOT
  299. <merchant-calculations>
  300. <merchant-calculations-url><![CDATA[{$this->_getCalculationsUrl()}]]></merchant-calculations-url>
  301. </merchant-calculations>
  302. EOT;
  303. return $xml;
  304. }
  305. /**
  306. * Retrieve free shipping rate XML
  307. *
  308. * @return string
  309. */
  310. protected function _getVirtualOrderShippingXml()
  311. {
  312. $title = Mage::helper('googlecheckout')->__('Free Shipping');
  313. $xml = <<<EOT
  314. <shipping-methods>
  315. <flat-rate-shipping name="{$title}">
  316. <shipping-restrictions><allowed-areas><world-area /></allowed-areas></shipping-restrictions>
  317. <price currency="{$this->getCurrency()}">0</price>
  318. </flat-rate-shipping>
  319. </shipping-methods>
  320. EOT;
  321. return $xml;
  322. }
  323. /**
  324. * Retrieve shipping methods XML
  325. *
  326. * @return string
  327. */
  328. protected function _getShippingMethodsXml()
  329. {
  330. if ($this->_isOrderVirtual()) {
  331. return $this->_getVirtualOrderShippingXml();
  332. }
  333. $xml = <<<EOT
  334. <shipping-methods>
  335. {$this->_getCarrierCalculatedShippingXml()}
  336. {$this->_getFlatRateShippingXml()}
  337. {$this->_getMerchantCalculatedShippingXml()}
  338. {$this->_getPickupXml()}
  339. </shipping-methods>
  340. EOT;
  341. return $xml;
  342. }
  343. /**
  344. * Generate XML of calculated shipping carriers rates
  345. *
  346. * @return string
  347. */
  348. protected function _getCarrierCalculatedShippingXml()
  349. {
  350. /*
  351. * Prevent sending more then one shipping option to Google
  352. */
  353. if ($this->_shippingCalculated) {
  354. return '';
  355. }
  356. $storeId = $this->getQuote()->getStoreId();
  357. $active = Mage::getStoreConfigFlag(Mage_GoogleCheckout_Helper_Data::XML_PATH_SHIPPING_CARRIER_ACTIVE, $storeId);
  358. $methods = Mage::getStoreConfig(Mage_GoogleCheckout_Helper_Data::XML_PATH_SHIPPING_CARRIER_METHODS, $storeId);
  359. if (!$active || !$methods) {
  360. return '';
  361. }
  362. $country = Mage::getStoreConfig(Mage_Shipping_Model_Config::XML_PATH_ORIGIN_COUNTRY_ID, $storeId);
  363. $region = Mage::getStoreConfig(Mage_Shipping_Model_Config::XML_PATH_ORIGIN_REGION_ID, $storeId);
  364. $postcode = Mage::getStoreConfig(Mage_Shipping_Model_Config::XML_PATH_ORIGIN_POSTCODE, $storeId);
  365. $city = Mage::getStoreConfig(Mage_Shipping_Model_Config::XML_PATH_ORIGIN_CITY, $storeId);
  366. $defPrice = (float)Mage::getStoreConfig(
  367. Mage_GoogleCheckout_Helper_Data::XML_PATH_SHIPPING_CARRIER_DEFAULT_PRICE,
  368. $storeId
  369. );
  370. $width = Mage::getStoreConfig(
  371. Mage_GoogleCheckout_Helper_Data::XML_PATH_SHIPPING_CARRIER_DEFAULT_WIDTH,
  372. $storeId
  373. );
  374. $height = Mage::getStoreConfig(
  375. Mage_GoogleCheckout_Helper_Data::XML_PATH_SHIPPING_CARRIER_DEFAULT_HEIGHT,
  376. $storeId
  377. );
  378. $length = Mage::getStoreConfig(
  379. Mage_GoogleCheckout_Helper_Data::XML_PATH_SHIPPING_CARRIER_DEFAULT_LENGTH,
  380. $storeId
  381. );
  382. $sizeUnit = self::ITEM_SIZE_UNIT;
  383. $addressCategory = Mage::getStoreConfig(
  384. Mage_GoogleCheckout_Helper_Data::XML_PATH_SHIPPING_CARRIER_ADDRESS_CATEGORY,
  385. $storeId
  386. );
  387. $defPrice = (float) Mage::helper('tax')->getShippingPrice($defPrice, false, false);
  388. $this->getQuote()->getShippingAddress()
  389. ->setCountryId($country)
  390. ->setCity($city)
  391. ->setPostcode($postcode)
  392. ->setRegionId($region)
  393. ->setCollectShippingRates(true);
  394. $address = $this->getQuote()->getShippingAddress();
  395. $address->collectShippingRates();
  396. $shipments = $address->getGroupedAllShippingRates();
  397. $shippingMethodsList = array();
  398. foreach (explode(',', $methods) as $method) {
  399. list($company, $type) = explode('/', $method);
  400. $shippingMethodsList[$method] = array('company' => $company, 'type' => $type);
  401. }
  402. $freeMethodsList = array();
  403. foreach ($this->_getGoogleCarriersMap() as $mageCode => $map) {
  404. if (!isset($shipments[$mageCode])) {
  405. continue;
  406. }
  407. $freeMethod = Mage::getStoreConfig('carriers/' . $mageCode . '/free_method', $storeId);
  408. foreach ($shipments[$mageCode] as $rate) {
  409. $mageRateCode = $rate->getMethod();
  410. if ($mageRateCode != $freeMethod) {
  411. continue;
  412. }
  413. $googleRateCode = isset($map['methods'][$mageRateCode]) ? $map['methods'][$mageRateCode] : false;
  414. if (false == $googleRateCode || $rate->getPrice() != 0) {
  415. continue;
  416. }
  417. $methodName = $map['googleCarrierCompany'] . '/'. $googleRateCode;
  418. if (empty($shippingMethodsList[$methodName])) {
  419. continue;
  420. }
  421. $freeMethodsList[$methodName] = array(
  422. 'company' => $map['googleCarrierCompany'],
  423. 'type' => $googleRateCode
  424. );
  425. unset($shippingMethodsList[$methodName]);
  426. }
  427. }
  428. $xml = '';
  429. $sendShipMethods = (bool)count($shippingMethodsList) > 0;
  430. if ($sendShipMethods) {
  431. $xml .= <<<EOT
  432. <carrier-calculated-shipping>
  433. <shipping-packages>
  434. <shipping-package>
  435. <ship-from id="Origin">
  436. <city>{$city}</city>
  437. <region>{$region}</region>
  438. <postal-code>{$postcode}</postal-code>
  439. <country-code>{$country}</country-code>
  440. </ship-from>
  441. <width unit="{$sizeUnit}" value="{$width}"/>
  442. <height unit="{$sizeUnit}" value="{$height}"/>
  443. <length unit="{$sizeUnit}" value="{$length}"/>
  444. <delivery-address-category>{$addressCategory}</delivery-address-category>
  445. </shipping-package>
  446. </shipping-packages>
  447. EOT;
  448. $xml .= '<carrier-calculated-shipping-options>';
  449. foreach ($shippingMethodsList as $method) {
  450. $xml .= <<<EOT
  451. <carrier-calculated-shipping-option>
  452. <shipping-company>{$method['company']}</shipping-company>
  453. <shipping-type>{$method['type']}</shipping-type>
  454. <price currency="{$this->getCurrency()}">{$defPrice}</price>
  455. </carrier-calculated-shipping-option>
  456. EOT;
  457. }
  458. $xml .= '</carrier-calculated-shipping-options>';
  459. $xml .= '</carrier-calculated-shipping>';
  460. }
  461. foreach ($freeMethodsList as $method) {
  462. $xml .= <<<EOT
  463. <flat-rate-shipping name="{$method['company']} {$method['type']}">
  464. <price currency="{$this->getCurrency()}">0.00</price></flat-rate-shipping>
  465. EOT;
  466. }
  467. $this->_shippingCalculated = true;
  468. return $xml;
  469. }
  470. /**
  471. * Generate flat rate shipping XML
  472. *
  473. * @return string
  474. */
  475. protected function _getFlatRateShippingXml()
  476. {
  477. /*
  478. * Prevent sending more then one shipping option to Google
  479. */
  480. if ($this->_shippingCalculated) {
  481. return '';
  482. }
  483. $storeId = $this->getQuote()->getStoreId();
  484. if (!Mage::getStoreConfigFlag(Mage_GoogleCheckout_Helper_Data::XML_PATH_SHIPPING_FLATRATE_ACTIVE, $storeId)) {
  485. return '';
  486. }
  487. // If is set Tax Class for Shipping - create ability to manage shipping rates in MerchantCalculationCallback
  488. $nodeName = 'merchant-calculated-shipping';
  489. if (!$this->_getTaxClassForShipping($this->getQuote())) {
  490. $nodeName = 'flat-rate-shipping';
  491. }
  492. $xml = '';
  493. for ($i = 1; $i <= 3; $i++) {
  494. $title = Mage::getStoreConfig('google/checkout_shipping_flatrate/title_' . $i, $storeId);
  495. $price = (float)Mage::getStoreConfig('google/checkout_shipping_flatrate/price_' . $i, $storeId);
  496. $price = number_format($price, 2, '.', '');
  497. $price = (float)Mage::helper('tax')->getShippingPrice($price, false, false);
  498. $allowSpecific = Mage::getStoreConfigFlag(
  499. 'google/checkout_shipping_flatrate/sallowspecific_' . $i,
  500. $storeId
  501. );
  502. $specificCountries = Mage::getStoreConfig(
  503. 'google/checkout_shipping_flatrate/specificcountry_' . $i,
  504. $storeId
  505. );
  506. $allowedAreasXml = $this->_getAllowedCountries($allowSpecific, $specificCountries);
  507. if (empty($title) || $price <= 0) {
  508. continue;
  509. }
  510. $xml .= <<<EOT
  511. <{$nodeName} name="{$title}">
  512. <shipping-restrictions>
  513. <allowed-areas>
  514. {$allowedAreasXml}
  515. </allowed-areas>
  516. </shipping-restrictions>
  517. <price currency="{$this->getCurrency()}">{$price}</price>
  518. </{$nodeName}>
  519. EOT;
  520. }
  521. $this->_shippingCalculated = true;
  522. return $xml;
  523. }
  524. /**
  525. * Generate shipping allowed countries XML
  526. *
  527. * @param boolean $allowSpecific
  528. * @param string $specific
  529. * @return string
  530. */
  531. protected function _getAllowedCountries($allowSpecific, $specific)
  532. {
  533. $xml = '';
  534. if ($allowSpecific == 1) {
  535. if ($specific) {
  536. foreach (explode(',', $specific) as $country) {
  537. $xml .= "<postal-area><country-code>{$country}</country-code></postal-area>\n";
  538. }
  539. }
  540. }
  541. if ($xml) {
  542. return $xml;
  543. }
  544. return '<world-area />';
  545. }
  546. /**
  547. * Retrieve merchant calculated shipping carriers rates XML
  548. *
  549. * @return string
  550. */
  551. protected function _getMerchantCalculatedShippingXml()
  552. {
  553. /*
  554. * Prevent sending more then one shipping option to Google
  555. */
  556. if ($this->_shippingCalculated) {
  557. return '';
  558. }
  559. $storeId = $this->getQuote()->getStoreId();
  560. $active = Mage::getStoreConfigFlag(
  561. Mage_GoogleCheckout_Helper_Data::XML_PATH_SHIPPING_MERCHANT_ACTIVE,
  562. $storeId
  563. );
  564. $methods = Mage::getStoreConfig(
  565. Mage_GoogleCheckout_Helper_Data::XML_PATH_SHIPPING_MERCHANT_ALLOWED_METHODS,
  566. $storeId
  567. );
  568. if (!$active || !$methods) {
  569. return '';
  570. }
  571. $xml = '';
  572. $methods = unserialize($methods);
  573. $taxHelper = Mage::helper('tax');
  574. $shippingModel = Mage::getModel('shipping/shipping');
  575. foreach ($methods['method'] as $i => $method) {
  576. if (!$i || !$method) {
  577. continue;
  578. }
  579. list($carrierCode, $methodCode) = explode('/', $method);
  580. if ($carrierCode) {
  581. $carrier = $shippingModel->getCarrierByCode($carrierCode);
  582. if ($carrier) {
  583. $allowedMethods = $carrier->getAllowedMethods();
  584. if (isset($allowedMethods[$methodCode])) {
  585. $method = Mage::getStoreConfig('carriers/' . $carrierCode . '/title', $storeId);
  586. $method .= ' - '.$allowedMethods[$methodCode];
  587. }
  588. $defaultPrice = (float) $methods['price'][$i];
  589. $defaultPrice = $taxHelper->getShippingPrice($defaultPrice, false, false);
  590. $allowedAreasXml = $this->_getAllowedCountries(
  591. $carrier->getConfigData('sallowspecific'),
  592. $carrier->getConfigData('specificcountry')
  593. );
  594. $xml .= <<<EOT
  595. <merchant-calculated-shipping name="{$method}">
  596. <address-filters>
  597. <allowed-areas>
  598. {$allowedAreasXml}
  599. </allowed-areas>
  600. </address-filters>
  601. <price currency="{$this->getCurrency()}">{$defaultPrice}</price>
  602. </merchant-calculated-shipping>
  603. EOT;
  604. }
  605. }
  606. }
  607. $this->_shippingCalculated = true;
  608. return $xml;
  609. }
  610. /**
  611. * Retrieve pickup XML
  612. *
  613. * @return string
  614. */
  615. protected function _getPickupXml()
  616. {
  617. $storeId = $this->getQuote()->getStoreId();
  618. if (!Mage::getStoreConfig(Mage_GoogleCheckout_Helper_Data::XML_PATH_SHIPPING_PICKUP_ACTIVE, $storeId)) {
  619. return '';
  620. }
  621. $title = Mage::getStoreConfig(Mage_GoogleCheckout_Helper_Data::XML_PATH_SHIPPING_PICKUP_TITLE, $storeId);
  622. $price = Mage::getStoreConfig(Mage_GoogleCheckout_Helper_Data::XML_PATH_SHIPPING_PICKUP_PRICE, $storeId);
  623. $price = (float) Mage::helper('tax')->getShippingPrice($price, false, false);
  624. $xml = <<<EOT
  625. <pickup name="{$title}">
  626. <price currency="{$this->getCurrency()}">{$price}</price>
  627. </pickup>
  628. EOT;
  629. return $xml;
  630. }
  631. /**
  632. * Retrieve specific tax table XML
  633. *
  634. * @param array|float $rules
  635. * @param string $type
  636. * @return string
  637. */
  638. protected function _getTaxTableXml($rules, $type)
  639. {
  640. $xml = '';
  641. if (is_array($rules)) {
  642. foreach ($rules as $group => $taxRates) {
  643. if ($type != 'default') {
  644. $nameAttribute = "name=\"{$group}\"";
  645. $standaloneAttribute = "standalone=\"true\"";
  646. $rulesTag = "{$type}-tax-rules";
  647. $shippingTaxed = false;
  648. } else {
  649. $nameAttribute = '';
  650. $standaloneAttribute = '';
  651. $rulesTag = 'tax-rules';
  652. $shippingTaxed = true;
  653. }
  654. $xml .= <<<EOT
  655. <{$type}-tax-table {$nameAttribute} {$standaloneAttribute}>
  656. <{$rulesTag}>
  657. EOT;
  658. if (is_array($taxRates)) {
  659. foreach ($taxRates as $rate) {
  660. $xml .= <<<EOT
  661. <{$type}-tax-rule>
  662. <tax-area>
  663. EOT;
  664. if ($rate['country'] === Mage_Usa_Model_Shipping_Carrier_Abstract::USA_COUNTRY_ID) {
  665. if (!empty($rate['postcode']) && $rate['postcode']!=='*') {
  666. $xml .= <<<EOT
  667. <us-zip-area>
  668. <zip-pattern>{$rate['postcode']}</zip-pattern>
  669. </us-zip-area>
  670. EOT;
  671. } else if (!empty($rate['state'])) {
  672. $xml .= <<<EOT
  673. <us-state-area>
  674. <state>{$rate['state']}</state>
  675. </us-state-area>
  676. EOT;
  677. } else {
  678. $xml .= <<<EOT
  679. <us-zip-area>
  680. <zip-pattern>*</zip-pattern>
  681. </us-zip-area>
  682. EOT;
  683. }
  684. } else {
  685. if (!empty($rate['country'])) {
  686. $xml .= <<<EOT
  687. <postal-area>
  688. <country-code>{$rate['country']}</country-code>
  689. EOT;
  690. if (!empty($rate['postcode']) && $rate['postcode']!=='*') {
  691. $xml .= <<<EOT
  692. <postal-code-pattern>{$rate['postcode']}</postal-code-pattern>
  693. EOT;
  694. }
  695. $xml .= <<<EOT
  696. </postal-area>
  697. EOT;
  698. }
  699. }
  700. $xml .= <<<EOT
  701. </tax-area>
  702. <rate>{$rate['value']}</rate>
  703. EOT;
  704. if ($shippingTaxed) {
  705. $xml .= '<shipping-taxed>true</shipping-taxed>';
  706. }
  707. $xml .= "</{$type}-tax-rule>";
  708. }
  709. } else {
  710. $taxRate = $taxRates/100;
  711. $xml .= <<<EOT
  712. <{$type}-tax-rule>
  713. <tax-area>
  714. <world-area/>
  715. </tax-area>
  716. <rate>{$taxRate}</rate>
  717. EOT;
  718. if ($shippingTaxed) {
  719. $xml .= '<shipping-taxed>true</shipping-taxed>';
  720. }
  721. $xml .= "</{$type}-tax-rule>";
  722. }
  723. $xml .= <<<EOT
  724. </$rulesTag>
  725. </{$type}-tax-table>
  726. EOT;
  727. }
  728. } else {
  729. if (is_numeric($rules)) {
  730. $taxRate = $rules / 100;
  731. $xml .= <<<EOT
  732. <{$type}-tax-table>
  733. <tax-rules>
  734. <{$type}-tax-rule>
  735. <tax-area>
  736. <world-area/>
  737. </tax-area>
  738. <rate>{$taxRate}</rate>
  739. <shipping-taxed>true</shipping-taxed>
  740. </{$type}-tax-rule>
  741. </tax-rules>
  742. </{$type}-tax-table>
  743. EOT;
  744. }
  745. }
  746. return $xml;
  747. }
  748. /**
  749. * Generate all tax tables XML
  750. *
  751. * @return string
  752. */
  753. protected function _getAllTaxTablesXml()
  754. {
  755. $isDefaultTaxTablesDisabled = Mage::getStoreConfigFlag(
  756. Mage_GoogleCheckout_Helper_Data::XML_PATH_DISABLE_DEFAULT_TAX_TABLES,
  757. $this->getQuote()->getStoreId()
  758. );
  759. if ($isDefaultTaxTablesDisabled) {
  760. return '<tax-tables merchant-calculated="true" />';
  761. }
  762. $xml = <<<EOT
  763. <tax-tables merchant-calculated="true">
  764. {$this->_getTaxTableXml($this->_getShippingTaxRules(), 'default')}
  765. <!-- default-tax-table>
  766. <tax-rules>
  767. <default-tax-rule>
  768. </default-tax-rule>
  769. </tax-rules>
  770. </default-tax-table -->
  771. <alternate-tax-tables>
  772. <alternate-tax-table name="none" standalone="true">
  773. <alternate-tax-rules>
  774. <alternate-tax-rule>
  775. <tax-area>
  776. <world-area/>
  777. </tax-area>
  778. <rate>0</rate>
  779. </alternate-tax-rule>
  780. </alternate-tax-rules>
  781. </alternate-tax-table>
  782. {$this->_getTaxTableXml($this->_getTaxRules(), 'alternate')}
  783. </alternate-tax-tables>
  784. </tax-tables>
  785. EOT;
  786. return $xml;
  787. }
  788. /**
  789. * Retrieve customer tax class id
  790. *
  791. * @return int
  792. */
  793. protected function _getCustomerTaxClass()
  794. {
  795. $customerGroup = $this->getQuote()->getCustomerGroupId();
  796. if (!$customerGroup) {
  797. $customerGroup = Mage::getStoreConfig(
  798. Mage_Customer_Model_Group::XML_PATH_DEFAULT_ID,
  799. $this->getQuote()->getStoreId()
  800. );
  801. }
  802. return Mage::getModel('customer/group')->load($customerGroup)->getTaxClassId();
  803. }
  804. /**
  805. * Retrieve shipping tax rules
  806. *
  807. * @return array
  808. */
  809. protected function _getShippingTaxRules()
  810. {
  811. $customerTaxClass = $this->_getCustomerTaxClass();
  812. $shippingTaxClass = Mage::getStoreConfig(
  813. Mage_Tax_Model_Config::CONFIG_XML_PATH_SHIPPING_TAX_CLASS,
  814. $this->getQuote()->getStoreId()
  815. );
  816. $taxCalculationModel = Mage::getSingleton('tax/calculation');
  817. if ($shippingTaxClass) {
  818. if (Mage::helper('tax')->getTaxBasedOn() == 'origin') {
  819. $request = $taxCalculationModel->getRateRequest();
  820. $request
  821. ->setCustomerClassId($customerTaxClass)
  822. ->setProductClassId($shippingTaxClass);
  823. return $taxCalculationModel->getRate($request);
  824. }
  825. $customerRules = $taxCalculationModel->getRatesByCustomerAndProductTaxClasses(
  826. $customerTaxClass,
  827. $shippingTaxClass
  828. );
  829. $rules = array();
  830. foreach ($customerRules as $rule) {
  831. $rules[$rule['product_class']][] = $rule;
  832. }
  833. return $rules;
  834. }
  835. return array();
  836. }
  837. /**
  838. * Retrieve yax rules
  839. *
  840. * @return array
  841. */
  842. protected function _getTaxRules()
  843. {
  844. $customerTaxClass = $this->_getCustomerTaxClass();
  845. $taxCalculationModel = Mage::getSingleton('tax/calculation');
  846. if (Mage::helper('tax')->getTaxBasedOn() == 'origin') {
  847. $request = $taxCalculationModel->getRateRequest()->setCustomerClassId($customerTaxClass);
  848. return $taxCalculationModel->getRatesForAllProductTaxClasses($request);
  849. }
  850. $customerRules = $taxCalculationModel->getRatesByCustomerTaxClass($customerTaxClass);
  851. $rules = array();
  852. foreach ($customerRules as $rule) {
  853. $rules[$rule['product_class']][] = $rule;
  854. }
  855. return $rules;
  856. }
  857. /**
  858. * Getter for request initial auth details flag XML
  859. *
  860. * @return string
  861. */
  862. protected function _getRequestInitialAuthDetailsXml()
  863. {
  864. $xml = <<<EOT
  865. <request-initial-auth-details>true</request-initial-auth-details>
  866. EOT;
  867. return $xml;
  868. }
  869. /**
  870. * Getter for parametrized url XML
  871. *
  872. * @return string
  873. */
  874. protected function _getParameterizedUrlsXml()
  875. {
  876. return '';
  877. $xml = <<<EOT
  878. <parameterized-urls>
  879. <parameterized-url url="{$this->_getParameterizedUrl()}" />
  880. </parameterized-urls>
  881. EOT;
  882. return $xml;
  883. }
  884. /**
  885. * Getter for platform Id XML
  886. *
  887. * @return string
  888. */
  889. protected function _getPlatformIdXml()
  890. {
  891. $xml = <<<EOT
  892. <platform-id>473325629220583</platform-id>
  893. EOT;
  894. return $xml;
  895. }
  896. /**
  897. * Retrieve analytics data XML
  898. *
  899. * @return string
  900. */
  901. protected function _getAnalyticsDataXml()
  902. {
  903. if (!($analytics = $this->getApi()->getAnalyticsData())) {
  904. return '';
  905. }
  906. $xml = <<<EOT
  907. <analytics-data><![CDATA[{$analytics}]]></analytics-data>
  908. EOT;
  909. return $xml;
  910. }
  911. /**
  912. * Getter for cart edit url
  913. *
  914. * @return string
  915. */
  916. protected function _getEditCartUrl()
  917. {
  918. return Mage::getUrl('googlecheckout/redirect/cart');
  919. }
  920. /**
  921. * Getter for continue shopping url
  922. *
  923. * @return string
  924. */
  925. protected function _getContinueShoppingUrl()
  926. {
  927. return Mage::getUrl('googlecheckout/redirect/continue');
  928. }
  929. /**
  930. * Getter for notifications url
  931. *
  932. * @return string
  933. */
  934. protected function _getNotificationsUrl()
  935. {
  936. return $this->_getCallbackUrl();
  937. }
  938. /**
  939. * Getter for calculations url
  940. *
  941. * @return string
  942. */
  943. protected function _getCalculationsUrl()
  944. {
  945. return $this->_getCallbackUrl();
  946. }
  947. /**
  948. * Getter for parametrized url
  949. *
  950. * @return string
  951. */
  952. protected function _getParameterizedUrl()
  953. {
  954. return Mage::getUrl('googlecheckout/api/beacon');
  955. }
  956. /**
  957. * Define if current quote is virtual
  958. *
  959. * @return bool
  960. */
  961. protected function _isOrderVirtual()
  962. {
  963. foreach ($this->getQuote()->getAllItems() as $item) {
  964. if (!$item->getIsVirtual()) {
  965. return false;
  966. }
  967. }
  968. return true;
  969. }
  970. /**
  971. * Retrieve native carriers to Google carriers map
  972. *
  973. * @return array
  974. */
  975. protected function _getGoogleCarriersMap() {
  976. return array(
  977. 'ups' => array(
  978. 'googleCarrierCompany' => 'UPS',
  979. 'methods' => array(
  980. 'GND' => Mage::helper('usa')->__('Ground'),
  981. '1DA' => Mage::helper('usa')->__('Next Day Air'),
  982. '1DM' => Mage::helper('usa')->__('Next Day Air Early AM'),
  983. '1DP' => Mage::helper('usa')->__('Next Day Air Saver'),
  984. '2DA' => Mage::helper('usa')->__('2nd Day Air'),
  985. '2DM' => Mage::helper('usa')->__('2nd Day Air AM'),
  986. '3DS' => Mage::helper('usa')->__('3 Day Select'),
  987. '03' => Mage::helper('usa')->__('Ground'),
  988. '01' => Mage::helper('usa')->__('Next Day Air'),
  989. '14' => Mage::helper('usa')->__('Next Day Air Early AM'),
  990. '13' => Mage::helper('usa')->__('Next Day Air Saver'),
  991. '02' => Mage::helper('usa')->__('2nd Day Air'),
  992. '59' => Mage::helper('usa')->__('2nd Day Air AM'),
  993. '12' => Mage::helper('usa')->__('3 Day Select')
  994. )
  995. ),
  996. 'usps' => array(
  997. 'googleCarrierCompany' => 'USPS',
  998. 'methods' => array(
  999. 'Express Mail' => Mage::helper('usa')->__('Express Mail'),
  1000. 'Priority Mail' => Mage::helper('usa')->__('Priority Mail'),
  1001. 'Parcel Post' => Mage::helper('usa')->__('Parcel Post'),
  1002. 'Media Mail' => Mage::helper('usa')->__('Media Mail')
  1003. )
  1004. ),
  1005. 'fedex' => array(
  1006. 'googleCarrierCompany' => 'FedEx',
  1007. 'methods' => array(
  1008. 'FEDEXGROUND' => Mage::helper('usa')->__('Ground'),
  1009. 'GROUNDHOMEDELIVERY' => Mage::helper('usa')->__('Home Delivery'),
  1010. 'FEDEXEXPRESSSAVER' => Mage::helper('usa')->__('Express Saver'),
  1011. 'FIRSTOVERNIGHT' => Mage::helper('usa')->__('First Overnight'),
  1012. 'PRIORITYOVERNIGHT' => Mage::helper('usa')->__('Priority Overnight'),
  1013. 'STANDARDOVERNIGHT' => Mage::helper('usa')->__('Standard Overnight'),
  1014. 'FEDEX2DAY' => Mage::helper('usa')->__('2Day')
  1015. )
  1016. )
  1017. );
  1018. }
  1019. }