2

I am trying to implement a custom recurring payment module for Magento 1.9.

I follow a tutorial from ModulesGarden Blog combined with Paypal Express.

I was able to create a new payment method that is showing in checkout only for recurring products. If I create only a fake request for testing like in the tutorial, everything it is working well, the orders are created, the profile it is created, I can cancel or suspend the profile from My Account.

The problem is that I don't know how to redirect on the gateway page after order is placed. Until now I tried to add in my payment model the method getOrderPlaceRedirectUrl() which is called in saveOrder() method, but this doesn't work because the method looks like this:

public function saveOrder()
{
    $this->validate();
    $isNewCustomer = false;
    switch ($this->getCheckoutMethod()) {
        case self::METHOD_GUEST:
            $this->_prepareGuestQuote();
            break;
        case self::METHOD_REGISTER:
            $this->_prepareNewCustomerQuote();
            $isNewCustomer = true;
            break;
        default:
            $this->_prepareCustomerQuote();
            break;
    }

    $service = Mage::getModel('sales/service_quote', $this->getQuote());
    $service->submitAll();

    if ($isNewCustomer) {
        try {
            $this->_involveNewCustomer();
        } catch (Exception $e) {
            Mage::logException($e);
        }
    }

    $this->_checkoutSession->setLastQuoteId($this->getQuote()->getId())
        ->setLastSuccessQuoteId($this->getQuote()->getId())
        ->clearHelperData();

    $order = $service->getOrder();
    if ($order) {
        Mage::dispatchEvent('checkout_type_onepage_save_order_after',
            array('order'=>$order, 'quote'=>$this->getQuote()));

        /**
         * a flag to set that there will be redirect to third party after confirmation
         * eg: paypal standard ipn
         */
        $redirectUrl = $this->getQuote()->getPayment()->getOrderPlaceRedirectUrl();
        /**
         * we only want to send to customer about new order when there is no redirect to third party
         */
        if (!$redirectUrl && $order->getCanSendNewEmailFlag()) {
            try {
                $order->queueNewOrderEmail();
            } catch (Exception $e) {
                Mage::logException($e);
            }
        }

        // add order information to the session
        $this->_checkoutSession->setLastOrderId($order->getId())
            ->setRedirectUrl($redirectUrl)
            ->setLastRealOrderId($order->getIncrementId());

        // as well a billing agreement can be created
        $agreement = $order->getPayment()->getBillingAgreement();
        if ($agreement) {
            $this->_checkoutSession->setLastBillingAgreementId($agreement->getId());
        }
    }

    // add recurring profiles information to the session
    $profiles = $service->getRecurringPaymentProfiles();
    if ($profiles) {
        $ids = array();
        foreach ($profiles as $profile) {
            $ids[] = $profile->getId();
        }
        $this->_checkoutSession->setLastRecurringProfileIds($ids);
        // TODO: send recurring profile emails
    }

    Mage::dispatchEvent(
        'checkout_submit_all_after',
        array('order' => $order, 'quote' => $this->getQuote(), 'recurring_profiles' => $profiles)
    );

    return $this;
}

The method is called only if there is an order, but there it isn't because when we use recurring profiles the order is created later, so only the code inside the if ($profiles) {} runs and there is no redirectUrl.

Then I tried to use the method getCheckoutRedirectUrl() like it's used in PayPal Express. Now I am redirected to payment gateway but the problem is that this method is called in savePaymentAction() and that means that I am redirected before the order review step.

Is there a possible to redirect to payment gateway only after the order is placed, somewhere in submitRecurringProfile() method? I don't want to remove the review order step because the customers need to accept the terms and conditions.

Thank you!

2 Answers 2

1

I encountered the exact same issue and I approached it in a different manner.

I created an observer for the checkout_submit_all_after event and inside the the observer I check if any recurring profiles have been added to the event data. If so, then I force a redirect to my action.

Here is the observer method code

public function checkoutSubmitAllFunction(Varien_Event_Observer $observer){
Mage::log(__FUNCTION__, Zend_Log::DEBUG, $this->logFileName);

if(0 < sizeof($observer->getEvent()->getData()['recurring_profiles'])){
  $recurringProfileId = $observer->getEvent()->getData()['recurring_profiles'][0]['profile_id'];

  if($recurringProfileId){
    /* Construct the redirect URL. */
    $redirectUrl = Mage::getUrl('module/controller/action', ['_query' => ['profileId' => $recurringProfileId]]);
    /* Set the redirect URL. */
    Mage::getSingleton('checkout/session')->setRedirectUrl($redirectUrl);
  }
}
return $this;
}

Hope this helps. :)

1
  • yes, this sound like a good approach too, maybe this will help someone because I already made like I write in the answer..
    – Ciprian
    Commented Dec 10, 2019 at 14:03
0

So after days of research and debugging I just found out a simple solution.

First, because we cannot change core files, I just copy the Onepage.php from core:

app/code/core/Mage/Checkout/Model/Type/Onepage.php

to:

app/code/local/Mage/Checkout/Model/Type/Onepage.php

and I made some changes in saveOrder() method. Now this method looks like this:

public function saveOrder()
{
    $this->validate();
    $isNewCustomer = false;
    switch ($this->getCheckoutMethod()) {
        case self::METHOD_GUEST:
            $this->_prepareGuestQuote();
            break;
        case self::METHOD_REGISTER:
            $this->_prepareNewCustomerQuote();
            $isNewCustomer = true;
            break;
        default:
            $this->_prepareCustomerQuote();
            break;
    }

    $service = Mage::getModel('sales/service_quote', $this->getQuote());
    $service->submitAll();

    if ($isNewCustomer) {
        try {
            $this->_involveNewCustomer();
        } catch (Exception $e) {
            Mage::logException($e);
        }
    }

    $this->_checkoutSession->setLastQuoteId($this->getQuote()->getId())
        ->setLastSuccessQuoteId($this->getQuote()->getId())
        ->clearHelperData();

    $order = $service->getOrder();
    /**
     * a flag to set that there will be redirect to third party after confirmation
     * eg: paypal standard ipn
     */
    $redirectUrl = $this->getQuote()->getPayment()->getOrderPlaceRedirectUrl();

    if ($order) {
        Mage::dispatchEvent('checkout_type_onepage_save_order_after',
            array('order'=>$order, 'quote'=>$this->getQuote()));

        /**
         * we only want to send to customer about new order when there is no redirect to third party
         */
        if (!$redirectUrl && $order->getCanSendNewEmailFlag()) {
            try {
                $order->queueNewOrderEmail();
            } catch (Exception $e) {
                Mage::logException($e);
            }
        }

        // add order information to the session
        $this->_checkoutSession->setLastOrderId($order->getId())
            ->setRedirectUrl($redirectUrl)
            ->setLastRealOrderId($order->getIncrementId());

        // as well a billing agreement can be created
        $agreement = $order->getPayment()->getBillingAgreement();
        if ($agreement) {
            $this->_checkoutSession->setLastBillingAgreementId($agreement->getId());
        }
    }

    // add recurring profiles information to the session
    $profiles = $service->getRecurringPaymentProfiles();
    if ($profiles) {
        $this->_checkoutSession->setRedirectUrl($redirectUrl);

        $ids = array();
        foreach ($profiles as $profile) {
            $ids[] = $profile->getId();
        }

        $this->_checkoutSession->setLastRecurringProfileIds($ids);
        // TODO: send recurring profile emails
    }

    Mage::dispatchEvent(
        'checkout_submit_all_after',
        array('order' => $order, 'quote' => $this->getQuote(), 'recurring_profiles' => $profiles)
    );

    return $this;
}

The differences are that I defined $redirectUrl even if there is no order and I set it to the $checkoutSession in both cases if exists order or recurring profile. You can compare the saveOrder() methods from my question and my answer to see de differences.

After that you have to create the getOrderPlaceRedirectUrl() method in your payment model and everything should work perfect.

Hope this helps other devs!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.