Friday

Bypass Magento Payment and Shipping

Magento has always been flying forward with code optimization and adding new features. Recently I’ve been tasked with upgrading one of our websites from 1.2 to 1.3.2
Seems like alot has changed since that time, no core changes are now required, you can overwrite code functionality with your own controllers, and etc.. Awesome! So lets move forward.

How would you disable shipping and payment steps for you Magento installation and apply changes in such manner that you wont have to worry about this when doing the next Magento upgrade?
Below is a step by step tutorial “copy paste” pretty much.

Now I don’t expect this that this solution will always work with next version of Magento, but unless they deprecate some existing functionality I’m sure you wont need to change anything.
NOTE: When doing copy paste make sure you wont end up with weird characters, such as single and double quotes.

STEP 1

First step would be to get a Magento extension called “LKC_ModularRouters” (ext. key: “magento-community/LKC_ModularRouters” to be used in MagentoConnect from admin tool)
After installation you can proceed to step 2, if you are using Magento v.1.3 if you are on a newer version you would need to make some tweaks to that module, since it has not been updated for the newer versions yet.
See how to do it…

STEP 2

Next, you would want to do is to create a project folder under /app/code/local
Lets say we name it “XYZ”

STEP 3

First, lets create a Bock that will overwrite existing Magento core block for onepage checkout /app/code/local/XYZ/Checkout/Block/Onepage.php

  1. class XYZ_Checkout_Block_Onepage extends Mage_Checkout_Block_Onepage {
  2. public function getSteps() {
  3. $steps = array();
  4. if (!$this->isCustomerLoggedIn()) {
  5. $steps['login'] = $this->getCheckout()->getStepData('login');
  6. }
  7. $stepCodes = array('billing', 'shipping', 'review');
  8. foreach ($stepCodes as $step) {
  9. $steps[$step] = $this->getCheckout()->getStepData($step);
  10. }
  11. return $steps;
  12. }
  13. }

Basically, this class will extend the core class. If you compare getSteps() function to the core file its pretty much identical, we just removed payment and shipping option steps.

STEP 4

Now this is the most intense part, We would have to tweak the default controllers for that page and make sure we assign a shipping method automatically and automatically select free shipping.

Create the following file /app/code/local/XYZ/Checkout/Controller/Onepage.php

  1. require_once 'Mage/Checkout/controllers/OnepageController.php';
  2. class XYZ_Checkout_Controller_Onepage extends Mage_Checkout_OnepageController
  3. {
  4. /**
  5. * Checkout page
  6. */
  7. public function indexAction()
  8. {
  9. if (!Mage::helper('checkout')->canOnepageCheckout()) {
  10. Mage::getSingleton('checkout/session')->addError($this->__('Sorry, Onepage Checkout is disabled.'));
  11. $this->_redirect('checkout/cart');
  12. return;
  13. }
  14. $quote = $this->getOnepage()->getQuote();
  15. if (!$quote->hasItems() || $quote->getHasError()) {
  16. $this->_redirect('checkout/cart');
  17. return;
  18. }
  19. if (!$quote->validateMinimumAmount()) {
  20. $error = Mage::getStoreConfig('sales/minimum_order/error_message');
  21. Mage::getSingleton('checkout/session')->addError($error);
  22. $this->_redirect('checkout/cart');
  23. return;
  24. }
  25. Mage::getSingleton('checkout/session')->setCartWasUpdated(false);
  26. Mage::getSingleton('customer/session')->setBeforeAuthUrl($this->getRequest()->getRequestUri());
  27. $this->getOnepage()->initCheckout();
  28. $this->loadLayout();
  29. $this->_initLayoutMessages('customer/session');
  30. $this->getLayout()->getBlock('head')->setTitle($this->__('Request a Quote'));
  31. $this->renderLayout();
  32. }
  33. public function saveBillingAction()
  34. {
  35. $this->_expireAjax();
  36. if ($this->getRequest()->isPost()) {
  37. $data = $this->getRequest()->getPost('billing', array());
  38. $customerAddressId = $this->getRequest()->getPost('billing_address_id', false);
  39. $result = $this->getOnepage()->saveBilling($data, $customerAddressId);
  40. if (!isset($result['error'])) {
  41. if ($this->getOnepage()->getQuote()->isVirtual()) {
  42. $this->loadLayout('checkout_onepage_review');
  43. $result['goto_section'] = 'review';
  44. $result['update_section'] = array(
  45. 'name' => 'review',
  46. 'html' => $this->getLayout()->getBlock('root')->toHtml()
  47. );
  48. }
  49. elseif (isset($data['use_for_shipping']) && $data['use_for_shipping'] == 1) {
  50. $this->saveShippingMethodAction();
  51. $this->loadLayout('checkout_onepage_review');
  52. $result['goto_section'] = 'review';
  53. $result['update_section'] = array(
  54. 'name' => 'review',
  55. 'html' => $this->_getReviewHtml()
  56. );
  57. $result['allow_sections'] = array('shipping','review');
  58. $result['duplicateBillingInfo'] = 'true';
  59. }
  60. else {
  61. $result['goto_section'] = 'shipping';
  62. }
  63. }
  64. $this->getResponse()->setBody(Zend_Json::encode($result));
  65. }
  66. }
  67. public function saveShippingAction()
  68. {
  69. $this->_expireAjax();
  70. if ($this->getRequest()->isPost()) {
  71. $data = $this->getRequest()->getPost('shipping', array());
  72. $customerAddressId = $this->getRequest()->getPost('shipping_address_id', false);
  73. $result = $this->getOnepage()->saveShipping($data, $customerAddressId);
  74. if (!isset($result['error'])) {
  75. $this->saveShippingMethodAction();
  76. $this->loadLayout('checkout_onepage_review');
  77. $result['goto_section'] = 'review';
  78. $result['update_section'] = array(
  79. 'name' => 'review',
  80. 'html' => $this->_getReviewHtml()
  81. );
  82. }
  83. $this->getResponse()->setBody(Zend_Json::encode($result));
  84. }
  85. }
  86. public function saveShippingMethodAction()
  87. {
  88. $this->_expireAjax();
  89. if ($this->getRequest()->isPost()) {
  90. $this->savePaymentAction();
  91. $data = $this->getRequest()->getPost('shipping_method', 'freeshipping_freeshipping');
  92. $result = $this->getOnepage()->saveShippingMethod($data);
  93. $this->getResponse()->setBody(Zend_Json::encode($result));
  94. }
  95. }
  96. public function savePaymentAction()
  97. {
  98. $this->_expireAjax();
  99. if ($this->getRequest()->isPost()) {
  100. $data = $this->getRequest()->getPost('payment', array('method'=>'checkmo'));
  101. try {
  102. $result = $this->getOnepage()->savePayment($data);
  103. }
  104. catch (Mage_Payment_Exception $e) {
  105. if ($e->getFields()) {
  106. $result['fields'] = $e->getFields();
  107. }
  108. $result['error'] = $e->getMessage();
  109. }
  110. catch (Exception $e) {
  111. $result['error'] = $e->getMessage();
  112. }
  113. $redirectUrl = $this->getOnePage()->getQuote()->getPayment()->getCheckoutRedirectUrl();
  114. if ($redirectUrl) {
  115. $result['redirect'] = $redirectUrl;
  116. }
  117. $this->getResponse()->setBody(Zend_Json::encode($result));
  118. }
  119. }
  120. }

STEP 5

Now that the code is in place we need to rewrite the core calls to custom classes we’ve created. To do so you create the file /app/code/local/XYZ/Checkout/etc/config.xml

  1. xml version="1.0"?>
  2. <config>
  3. <modules>
  4. <XYZ_Checkout>
  5. <version>0.1.0version>
  6. XYZ_Checkout>
  7. modules>
  8. <global>
  9. <controllers>
  10. <Mage_Checkout>
  11. <rewrite>
  12. <onepage>XYZ_Checkout_Controller_Onepageonepage>
  13. rewrite>
  14. Mage_Checkout>
  15. controllers>
  16. <blocks>
  17. <checkout>
  18. <rewrite>
  19. <onepage>XYZ_Checkout_Block_Onepageonepage>
  20. rewrite>
  21. checkout>
  22. blocks>
  23. global>
  24. config>

STEP 6

Now we would have to add a new XML config file for you XYZ module. This config file will tell Magento about your module and here you will enable all the code you wrote. /app/etc/modules/XYZ_All.xml

  1. xml version="1.0"?>
  2. <config>
  3. <modules>
  4. <XYZ_Checkout>
  5. <active>trueactive>
  6. <codePool>localcodePool>
  7. <<b style="color: white; background-color: rgb(136, 0, 0);">dependsb>>
  8. <Mage_Core />
  9. <Mage_Checkout />
  10. <LKC_ModularRouters />
  11. <b style="color: white; background-color: rgb(136, 0, 0);">dependsb>>
  12. XYZ_Checkout>
  13. modules>
  14. config>

STEP 7

Now that the tough part is done, we will just need to do some little tweaks to the AJAX JS file and tweak Magento configuration in the admin tool.
Now locate and open /skin/frontend/default/YOURSKIN/js/opcheckout.js where YOURSKIN is the skin you are using for your site. In most cases its ‘default’ but if you are using a separate skin that you might have created then it will be in a folder you’ve created.

Approximately on the line 721 you should find “var Review = Class.create();” which defines the Review class. Now if you skip to ’save’ function for that class you will find this line of code “var params = Form.serialize(payment.form);” We will have to tweak this because we are skipping payment. This variable wont be defined if we place the order. So I have changed that line to :

  1. //var params = Form.serialize(payment.form);
  2. var params = "color: black; background-color: rgb(255, 153, 153);">payment%5Bmethod%5D=checkmo";
  3. if (this.agreementsForm) {
  4. params += '&'+Form.serialize(this.agreementsForm);
  5. }
  6. params.save = true;

As you see we commented out the serialize call and hardcoding the parameter to reflect the free payment method

STEP 8

Now the last part: tweaking Magento configuration

  1. Go to the admin tool and go to System->Configuration->Shipping Methods and make sure “Free Shipping” is Enabled.
  2. Go to the admin tool and go to System->Configuration->Payment Methods and make sure “Check / Money order” payment option is Enabled.
  3. IMPORTANT! – When copying XML data make sure you don’t have any white-spaces before the first tag, which should be

That is it! Your comments and suggestions are welcome!

courtsy:Blog of Igor Krasnykh

1 comment:

Unknown said...

Wow! You can steal informations from other people's blogs...

Django URLs

In Django, the urls.py file is where you define the URL patterns for your web application. There are several ways to write the urls.py fil...