Php – Magento – How to stop invoicing orders on failed payment transactions

magentoPHPzend-framework

I am using custom payment module and upon receiving failed transaction response from my custom payment gateway I would like to

  • save the order with "pending_payment" state/status and not send any order email.

  • I do not want to create any invoice /process it or send any invoice email.

  • Also I would like to redirect my customers to a failure page or maybe checkout/cart page but with a message at the top saying their payment details was erroneous, and please try again.

Once I receive a 'Failed' response from my payment gateway I am able to save the order to pending_payment status and stopping it form sending a new order email but I'm not able to stop it from invoicing n hence stop d invoice email from being sent out.

I'm calling an Observer on sales_order_place_after event in my custom payment module which invoices the orders and sends the invoice email on successful transactions.

Now I dont know if that file needs editing too(app/code/local/Mage/Paymentmodule/Model/Observer.php) or just my app/code/local/Mage/Paymentmodule/Model/PaymentMethod.php is enough for this.

PaymentMethod.php

      public function capture(Varien_Object $payment, $amount) 
      {
        $error = false;
    // check for payment
   if($amount > 0)
   {
    $payment->setAmount($amount);
    $order = $payment->getOrder();
    if($payment->getTxnNumber() == "")
    {
        $transaction = $this->_build($payment, self::TRANSACTION_PREAUTH);
            $authResponse = $this->_send($transaction);
        if($authResponse->getResponseCode() > 0 && $authResponse->getResponseCode() <= self::ERROR_CODE_LIMIT)
        {
            $payment->setCcApproval($authResponse->getReceiptId())
             ->setLastTransId($authResponse->getReceiptId())
             ->setCcTransId($authResponse->getTxnNumber())    ->setCcCidStatus($this->getCvdDescription($authResponse->getCvdResultCode()));    

        }
        else if($authResponse->getResponseCode() > self::ERROR_CODE_LIMIT && $authResponse->getResponseCode() < self::ERROR_CODE_UPPER_LIMIT)
        {
           $order->setState(Mage_Sales_Model_Order::STATE_PENDING_PAYMENT, 'pending_payment', '', false)->save();
           $order->setCanSendNewEmailFlag(false);
           $order->setCanInvoiceFlag(false);
        }
        else
        {
           $order->setState(Mage_Sales_Model_Order::STATE_PENDING_PAYMENT, 'pending_payment', '', false)->save();
           $order->setCanSendNewEmailFlag(false);
           $order->setCanInvoiceFlag(false);
        }
    }
    $check = $this->checkCvdResponse($authResponse->getCvdResultCode());
    if($check == true)
    {
        $order->setState(Mage_Sales_Model_Order::STATE_PENDING_PAYMENT, 'pending_payment', '', false)->save();
        $order->setCanSendNewEmailFlag(false);
        $order->setCanInvoiceFlag(false);
    }
    else
    {
        $transaction_completion = $this->_build($payment, self::TRANSACTION_COMPLETION);
        $response = $this->_send($transaction_completion);  
        if($response->getResponseCode() > 0 && $response->getResponseCode() <= self::ERROR_CODE_LIMIT) 
        {
            $payment->setStatus(self::STATUS_SUCCESS);
            $payment->setCcApproval($response->getReceiptId())
             ->setLastTransId($response->getReferenceNum())
             ->setCcTransId($response->getTxnNumber())
             ->setCcAvsStatus($this->getAvsDescription($authResponse->getAvsResultCode()))
             ->setCcCidStatus($this->getCvdDescription($authResponse->getCvdResultCode())); 
        }    
        else if($response->getResponseCode() > self::ERROR_CODE_LIMIT && $response->getResponseCode() < self::ERROR_CODE_UPPER_LIMIT) 
        {
            $order->setState(Mage_Sales_Model_Order::STATE_PENDING_PAYMENT, 'pending_payment', '', false)->save();
            $order->setCanSendNewEmailFlag(false);
            $order->setCanInvoiceFlag(false);
        } 
        else 
        {
           $order->setState(Mage_Sales_Model_Order::STATE_PENDING_PAYMENT, 'pending_payment', '', false)                                       ->save();
           $order->setCanSendNewEmailFlag(false);
           $order->setCanInvoiceFlag(false);
        }
    }
} 
else
{
    $error = Mage::helper('paygate')->__('Invalid amount for authorization.');
}
if ($error !== false)
Mage::throwException($error);
    return $this;
 }

Observer.php

   public function implementOrderStatus($event)
  {
    $order = $event->getEvent()->getOrder();    
    if ($this->_getPaymentMethod($order) == 'custompaymentmodule') 
    {
        if($order->getState() == 'pending_payment')
        {
          $order->setCanSendNewEmailFlag(false);
          $order->setCanInvoiceFlag(false);
        }
                 if ($order->canInvoice())

            $this->_processOrderStatus($order);
    }
    return $this;
}

Any ideas how can I just save it pending_payment state and stop it form invoicing and redirect to cart page with an appropriate message.

Any help on solving any of the bits would be highly appreciated. Thanks

Best Answer

I found a partial solution to my problem. On failed payment transactions, instead of setting the pending_payment state in my PaymentMethod.php, I'm setting the Payment status to Declined and setting CcTransId to NULL

Then using this condition in my Observer.php I'm saving that order with pending_payment status.

Here's d modified code

PaymentMethod.php

   if($payment->getTxnNumber() == "")
   {
      <!-- SOME CODE -->
      if($authResponse->getResponseCode() > 0 && $authResponse->getResponseCode() <= self::ERROR_CODE_LIMIT)
      {
        <!-- SUCCESSFUL TRANSACTION CODE   
      }
      else if($authResponse->getResponseCode() > self::ERROR_CODE_LIMIT && $authResponse->getResponseCode() < self::ERROR_CODE_UPPER_LIMIT)
      {
         $payment->setStatus(self::STATUS_DECLINED);
      }
      else
      {
         $payment->setStatus(self::STATUS_DECLINED);
      }
   }
   $check = $this->checkCvdResponse($authResponse->getCvdResultCode());
   if($check == true)
   {
       $payment->setStatus(self::STATUS_DECLINED);
       $payment->setCcTransId(NULL);  
   }
   else
   {
       $transaction_completion = $this->_build($payment, self::TRANSACTION_COMPLETION);
       $response = $this->_send($transaction_completion);  
       if($response->getResponseCode() > 0 && $response->getResponseCode() <= self::ERROR_CODE_LIMIT) 
       {
          <!-- SUCCESSFUL CAPTURE -->   
       }    
      else if($response->getResponseCode() > self::ERROR_CODE_LIMIT && $response->getResponseCode() < self::ERROR_CODE_UPPER_LIMIT) 
      {
         $payment->setStatus(self::STATUS_DECLINED);
         $payment->setCcTransId(NULL);  
      } 
      else 
      {
        $payment->setStatus(self::STATUS_DECLINED);
        $payment->setCcTransId(NULL);  
      }
}

Observer.php

    public function implementOrderStatus($event)
    {
      $order = $event->getEvent()->getOrder(); 
      if ($this->_getPaymentMethod($order) == 'custompaymentmodule') 
      {
     if($order->getPayment()->getCcTransId() == NULL)
     {
        $state = 'pending_payment';
    $status = 'pending_payment';
    $comment = 'Payment transaction failed due to incorrect AVS/CVD details.';
    $isNotified = false;
    $order->setState($state,$status,$comment,$isNotified)->save();
        $order->setCanSendNewEmailFlag(false);
         }
         else
         {
             <!-- SUCCESSFUL INVOICE CODE -->
         }
      }

The only thing I'm left now with is to redirect the user to Shopping Cart page with an erro message at the top.

However since I need to do all this in Observer file, I'm not able to call $this->_redirect() method. Tried Mage::app->getResponse->setRedirect(Mage::getUrl('checkout/cart')) but dint work.

Any ideas on how to accomplish this last bit. }

Related Topic