I have configured a Magento 1.9 community store and all orders for which payment is made through Paypal or other payment methods (like cash on delivery), are showing up in backend.
However, when I checkout selecting Paypal as the gateway, cancel my order on the Paypal page and return to the website - my order is not showing in the admin. Isn't it supposed to show up as a cancelled order.
Since this was a store migrated from Shopify, we had to manually create about a 100 orders and change their dates in the database manually. Can this be a reason for this unexpected behaviour?
Edit 1: No order info is displayed in the grid even if the paypal window is closed instead of clicking in cancel as many answers are suggesting.
This is obvious because when you (as a customer) cancel an order in PayPal payment page it automatically destroys (unset) the order and the order quote before redirecting to shop - Not to be confused with the famous: Cancelled Order where as the name suggests is shown for the actual orders which have been actually done and then cancelled.
Depending on the PayPal method you are using this can be treated differently.
In standard PayPal you can find it in this controller:
\magento\app\code\core\Mage\Paypal\controllers\StandardController.php
when you cancel the order, cancelAction(), it first cancels the order:
public function cancelAction()
{
$session = Mage::getSingleton('checkout/session');
$session->setQuoteId($session->getPaypalStandardQuoteId(true));
if ($session->getLastRealOrderId()) {
$order = Mage::getModel('sales/order')->loadByIncrementId($session->getLastRealOrderId());
if ($order->getId()) {
$order->cancel()->save();
}
Mage::helper('paypal/checkout')->restoreQuote();
}
$this->_redirect('checkout/cart');
}
and then redirectAction() unset the quote before redirecting back to the cart page:
public function redirectAction()
{
$session = Mage::getSingleton('checkout/session');
$session->setPaypalStandardQuoteId($session->getQuoteId());
$this->getResponse()->setBody($this->getLayout()->createBlock('paypal/standard_redirect')->toHtml());
$session->unsQuoteId();
$session->unsRedirectUrl();
}
On the other hand in PayPal Express, cancel operation is triggered in this controller:
\app\code\core\Mage\Paypal\Controller\Express\Abstract.php
public function cancelAction()
{
try {
$this->_initToken(false);
// TODO verify if this logic of order cancelation is deprecated
// if there is an order - cancel it
$orderId = $this->_getCheckoutSession()->getLastOrderId();
$order = ($orderId) ? Mage::getModel('sales/order')->load($orderId) : false;
if ($order && $order->getId() && $order->getQuoteId() == $this->_getCheckoutSession()->getQuoteId()) {
$order->cancel()->save();
$this->_getCheckoutSession()
->unsLastQuoteId()
->unsLastSuccessQuoteId()
->unsLastOrderId()
->unsLastRealOrderId()
->addSuccess($this->__('Express Checkout and Order have been canceled.'))
;
} else {
$this->_getCheckoutSession()->addSuccess($this->__('Express Checkout has been canceled.'));
}
} catch (Mage_Core_Exception $e) {
$this->_getCheckoutSession()->addError($e->getMessage());
} catch (Exception $e) {
$this->_getCheckoutSession()->addError($this->__('Unable to cancel Express Checkout.'));
Mage::logException($e);
}
$this->_redirect('checkout/cart');
}
where it unset everything in the same place.
So in your case if you need to keep the quote (which I suppose is what you have been exploiting in your custom module) you have to change this behavior of PayPal module.
Please remember if you are going to do this do not modify the original core files, instead extend these classes in your custom module and apply your changes there.
When you cancel the order from Paypal page without completing the payment, it will redirect you back to your cart page. The order will not get placed.
If you close the page after paypal redirection, without completing the payment(note that you do not have to press cancel here) the order will get placed with pending payment status.
To verify whether paypal is working correctly or not, try to complete the payment process via paypal. If you are using it for testing purposes you can use the sandbox mode so that you won't get charged for your order.
Hope this helps!!
Related
I'm using Magento API to create orders. My code fails when I want to add payment method to the cart :
$paymentMethod = array(
“method” => “paypal_standard”
);
$resultPaymentMethod = $proxy->call(
$sessionId,
“cart_payment.method”,
array(
$shoppingCartId,
$paymentMethod
)
);
I'm getting following error: Payment method is not allowed.
In admin section in System->Configuration->PayPal I have set Website Payments Standard but I didn't enabled any option in System->Configuration->Payment Methods cause there is none available for PayPal.
When I call:
$proxy->call($session, 'cart_payment.list')
method I get an empty array as there isn't any available payment method set. Does someone knows how and where paypal payment setting is saved in Magento ?
If I set another Payment method like "checkmo" then the order is created fine. The thing is that I only need to allow Paypal standard payment.
So my question is: How can I set payment method to PayPal to the cart so my order will be successfully created?
Thanks.
I have also facing this problem and find reason for it.
$method->canUseInternal() used in payment method api. When we use paypal or other redirect able methods in payment methos api in that case $method->canUseInternal() it getting false value.
So for this type situation we need to create own custom coding.
api function refreance:
protected function _canUsePaymentMethod($method, $quote){
if (!($method->isGateway() || $method->canUseInternal())) {
return false; }
if (!$method->canUseForCountry($quote->getBillingAddress()->getCountry())) {
return false;
}
if (!$method->canUseForCurrency(Mage::app()->getStore($quote->getStoreId())->getBaseCurrencyCode())) {
return false;
}
To pay with Paypal you need your customer to be redirected to Paypal. Because of this fact, you may not be allowed to use this payment method using API. I recommend you to have look at isAvailable() of the payment method to customize this behaviour.
My Problem:
I want to use observer before checkout onepage page begins, in that, based on products in the cart, I want to disable shipping if it doesn't match certain conditions.
I am using [controller_action_predispatch_checkout_onepage_index] event observer, this basically call before checkout page starts loading...I am able to get all products and quote info but didn't found any method to disable shipping.
What I am looking for,
from the observer, is it possible to disable shipping by calling certain magento methods or any other solutions?
Overriding collectRates()
After getting few replies, I am trying to override collectRates() method using code given below
$method = Mage::getModel('shipping/rate_result_method');
$method->setCarrier('flatrate');
$method->setCarrierTitle($this->getConfigData('title'));
$method->setMethod('flatrate');
$method->setMethodTitle($this->getConfigData('name'));
if ($request->getFreeShipping() === true || $request->getPackageQty() == $this->getFreeBoxes()) {
$shippingPrice = '0.00';
}
$method->setPrice($shippingPrice);
$method->setCost($shippingPrice);
$result->append($method);
Although, I dont want to enable flatrate shipping method either. I just want to disable shipping, or optionally return with reply something like
Free shipping $0.00
User can select that to continue to next step. Please help me from here..
What should I use in $method->setCarrier('??????');
or what changes I do need to do in above code?
I think it might be better to either override or subclass the individual Carrier models.
All carriers implement a method "Mage_Shipping_Model_Carrier_Abstract::collectRates()" to return results.
It is possible to get information about the current quote to modify the returned rates/options from within this method.
That said, if there is a way to do it with an observer, it would probably be cleaner/easier.
Finally I have override shipping method, its a two step code but you can reduce it to one step if you wish. Here is my two step solution.
Before we start our shipping class needs to extend and implement
extends Mage_Shipping_Model_Carrier_Abstract
implements Mage_Shipping_Model_Carrier_Interface
Now, We create a protected method
protected function _createMethod($request, $method_code, $title, $price, $cost)
{
$method = Mage::getModel('shipping/rate_result_method');
$method->setCarrier('australiapost'); // in my case its australia post, it can be any other whatever you are using
$method->setCarrierTitle($this->getConfigData('title'));
$method->setMethod($method_code);
$method->setMethodTitle($title);
$method->setPrice($this->getFinalPriceWithHandlingFee($price));
$method->setCost($cost);
return $method;
}
Now just use code below to create new method with free shipping and bypass existing shipping calculator, this code will go inside collectRates(Mage_Shipping_Model_Rate_Request $request) method
// PROCESS WILL RETURN FREE SHIPPING
if ($request->getFreeShipping() === true || $request->getPackageQty() == $this->getFreeBoxes()) {
$shippingPrice = '0.00';
}
$shipping_method = 'Free Shipping';
$method = $this->_createMethod($request, $shipping_method, 'Shipping Disabled', '0.00', '0.00');
$result->append($method);
return $result;
By Doing this, you can get result like below in checkout and user can easily click continue to next step.
Shipping Disabled $0.00
I've been searching, trying, and failing alot here. What I want is to add a checkbox, on the Shipping page of Onepage checkout, the standard magento checkout.
I want to create a checkbox so that customers can check it if they want their products to be placed on their address without a signature.
I've been messing around with some old "Accept Terms" checkboxes, but with no luck.
I'm hoping that somebody might have had to make the same kind of customization.
What you can do is save the preference in the checkout/session via an observer. First, add the checkbox to the shipping section and give it the property of name=shipping[no_signature]. Then, create a new module and hook into the event controller_action_postdispatch_checkout_onepage_saveShipping and then use this code:
public function controller_action_postdispatch_checkout_onepage_saveShipping($observer)
{
$params = (Mage::app()->getRequest()->getParams()) ? Mage::app()->getRequest()->getParams() : array();
if (isset($params['shipping']['no_signature']) && $params['shipping']['no_signature']) {
Mage::getSingleton('checkout/session')->setNoSignature(true);
} else {
Mage::getSingleton('checkout/session')->setNoSignature(false);
}
return $this;
}
Then, when the order is about to be placed, hook into the event sales_order_place_before you can add a comment to the order like this:
public function sales_order_place_before($observer)
{
$order = $observer->getOrder();
if (Mage::getSingleton('checkout/session')->getNoSignature()) {
$order->setCustomerNote('No signature required.');
} else {
$order->setCustomerNote(null);
}
return $this;
}
When you go to Sales > Orders, you should see a comment on the order regarding if the customer requires a signature or not. This is under the assumption that no other module or custom code is injecting anything into the customer_note field on the order object.
Once a user has added a product to the Shopping Cart , I want to restrict that specific user from shopping further during the particular session.
If the user check out and visit again to the Website, he should be able to Shop again but the above rule must be considered.
Is this functionality available in Magento?Can anyone provide a solution for this?
Of course this is possible! Configure an observer for the controller_action_predispatch event, grab the quote object from the session - if it contains items, set the redirect in your observer method and redirect them to the cart. Example (not tested):
public function restrictToCheckout(Varien_Event_Observer $observer)
{
$items = Mage::getSingleton('checkout/session')->getQuote()->getItemsCount();
if ($items) {
$observer->getControllerAction()->getResponse()
->setRedirect(Mage::getUrl('checkout/cart'));
Mage::throwException('You have items in your cart and must checkout'));
}
}
There may be nuances, but this is the meat of it.
This is one of the most vital problems I have found since I started testing Magento for my web store. It's kind of a no-brainer that it's absolutely unnecessary and harmful to sales to empty cart before payment confirmation, which unfortunately, Magento does.
If the user selects PayPal (website standard) for payment method and for some reason clicks "Back to xxxx" (your business name at PayPal) on the PayPal payment page without paying, PayPal would redirect the user back to http://www.example.com/checkout/cart/, which now is an EMPTY cart.
I think it should be after payment confirmation / PayPal IPN that the cart be empty-ed, instead of any point before that.
Even if the user wants to continue again, he or she'd be annoyed from searching and adding all the products again and would very probably just leave.
Any idea how I can work around this?
This worked for me:
File: ~/app/code/core/Mage/Checkout/controllers/OnepageController.php
Replace this:
$this->getOnepage()->getQuote()->save();
/**
* when there is redirect to third party, we don't want to save order yet.
* we will save the order in return action.
*/
if (isset($redirectUrl)) {
$result['redirect'] = $redirectUrl;
}
$this->getResponse()->setBody(Mage::helper('core')->jsonEncode($result));
With this one:
/**
* when there is redirect to third party, we don't want to save order yet.
* we will save the order in return action.
*/
if (isset($redirectUrl)) {
$result['redirect'] = $redirectUrl;
$this->getOnepage()->getQuote()->setIsActive(1) ;
}
$this->getOnepage()->getQuote()->save();
$this->getResponse()->setBody(Mage::helper('core')->jsonEncode($result));
For Paypal I found the cancel action inside the app/code/core/Mage/Paypal/controllers/StandardController.php cancelAction
I changed the code like that for cancel action
public function cancelAction()
{
$session = Mage::getSingleton('checkout/session');
$cart = Mage::getSingleton('checkout/cart');
$session->setQuoteId($session->getPaypalStandardQuoteId(true));
if ($session->getLastRealOrderId()) {
$incrementId = $session->getLastRealOrderId();
if (empty($incrementId)) {
$session->addError($this->__('Your payment failed, Please try again later'));
$this->_redirect('checkout/cart');
return;
}
$order = Mage::getModel('sales/order')->loadByIncrementId($session->getLastRealOrderId());
$session->getQuote()->setIsActive(false)->save();
$session->clear();
try {
$order->setActionFlag(Mage_Sales_Model_Order::ACTION_FLAG_CANCEL, true);
$order->cancel()->save();
} catch (Mage_Core_Exception $e) {
Mage::logException($e);
}
$items = $order->getItemsCollection();
foreach ($items as $item) {
try {
$cart->addOrderItem($item);
} catch (Mage_Core_Exception $e) {
$session->addError($this->__($e->getMessage()));
Mage::logException($e);
continue;
}
}
$cart->save();
$session->addError($this->__('Your payment failed. Please try again later'));
}
$this->_redirect('checkout/cart');
}
It worked pretty good for me and there is no need to change any other place for that.
It marks the current order as Cancelled and restores the cart with using that order and redirects the user to cart again.
/app/code/core/Mage/Checkout/controllers/OnepageController.php this file is the actual controller file, but depends up on the payment method extensions it will change with Namespace/Modulename/Checkout/controllers/OnepageController.php
Find function saveOrderAction()
find these lines
$this->getOnepage()->getQuote()->save();
/**
* when there is redirect to third party, we don't want to save order yet.
* we will save the order in return action.
*/
if (isset($redirectUrl)) {
$result['redirect'] = $redirectUrl;
}
$this->getResponse()->setBody(Mage::helper('core')->jsonEncode($result));
comment this line //$this->getOnepage()->getQuote()->save();
and add below codes inside the if condition so the condition will look like ..
//$this->getOnepage()->getQuote()->save();
if (isset($redirectUrl)) {
$result['redirect'] = $redirectUrl;
$this->getOnepage()->getQuote()->setIsActive(1) ;
}
$this->getOnepage()->getQuote()->save();
$this->getResponse()->setBody(Mage::helper('core')->jsonEncode($result));
This is i have done with the third party Payment extension.
Since Magento version 1.6.0.0 (juli 2011) you can enable "Persistent Shopping Cart"
under
System > Configuration > Customers > Persistent Shopping Cart
This should solve this problem.
Use these settings to make it work
Enable Persistence = Yes
Persistence Lifetime (seconds) = 31536000
Enable "Remember Me" = Yes
"Remember Me" Default Value = Yes
Clear Persistence on Log Out = No
Persist Shopping Cart = Yes
Good luck :)
Your issue is with the way Mage_Checkout_OnepageController::saveOrderAction() behaves.
More specific: open app/code/core/Mage/Checkout/controllers/OnepageController.php
$this->getOnepage()->getQuote()->save();//this makes the cart empty (sets the quote as converted to order)
if (isset($redirectUrl)) {
$result['redirect'] = $redirectUrl;
}
$this->getResponse()->setBody(Mage::helper('core')->jsonEncode($result));
}
You can replace the last part:
$this->getOnepage()->getQuote()->save();//....
with:
if (isset($redirectUrl)) {
$result['redirect'] = $redirectUrl;
$this->getOnepage()->getQuote()->setIsActive(1) ;
}
$this->getOnepage()->getQuote()->save();
$this->getResponse()->setBody(Mage::helper('core')->jsonEncode($result));