This tutorial explains how to cancel pending payments Magento 1 automatically.

Filter Pending Payments Magento
private function cancelPendingPayments() {
$fromDate = date('Y-m-d H:i:s', strtotime('-2 hour'));
$toDate = date('Y-m-d H:i:s', strtotime(now()));
$orderCollection = Mage::getResourceModel('sales/order_collection');
$orderCollection->addFieldToFilter('status', 'pending_payment')
->addFieldToFilter('updated_at', array( 'from' => $fromDate, 'to' => $toDate, 'date' => true ))
->getSelect()
->order('entity_id')
->limit(20);
if( count( $orderCollection ) < 1 ) {
return;
}
foreach( $orderCollection as $order ) {
$difference = $this->getDifference($order);
if( ( $difference >= 30 ) && ( $difference < 45 ) ) {
$emailVariables = $this->pendingPaymentsVariables( $order );
$this->prepareEmail( Mage::getStoreConfig('clearbasket_settings/email_template/pending_payment_notify'),
$emailVariables, $emailVariables['orderdetails']['customername'], $emailVariables['orderdetails']['customeremail'] );
$history = $order->addStatusHistoryComment('Notification email sent - Cron Jobs',false);
$history->setIsCustomerNotified(false);
$order->save();
}
if( $difference > 60 ) {
if(!$order->canCancel()) {
Mage::log('Order cannot be canceled anymore.',null,"order.log");
}
else {
$order->cancel();
}
$order->setData('state', "canceled");
$order->setStatus("canceled");
$order->setData('state', Mage_Sales_Model_Order::STATE_CANCELED);
$order->setActionFlag(Mage_Sales_Model_Order::ACTION_FLAG_CANCEL, true);
Mage::log('Order cancel after : '.$difference, null, "order.log");
$history = $order->addStatusHistoryComment('Order marked as cancelled due to pending payment - Cron Jobs.', false);
$history->setIsCustomerNotified(false);
$order->save();
}
}
}
Notification Email Before Cancelling
private function prepareEmail( $templateId, $emailVariables, $receipentName, $receipentEmail ) {
try {
Mage::log('Email sent : '.$receipentName, null,"order.log");
$storeId = Mage::app()->getStore()->getId();
$senderName = Mage::getStoreConfig('clearbasket_settings/email_details/send_email_name');
$senderEmail = Mage::getStoreConfig('clearbasket_settings/email_details/send_email');
$sender = array( 'name' =>$senderName,'email'=> $senderEmail );
$translate = Mage::getSingleton('core/translate');
Mage::getModel('core/email_template')->sendTransactional($templateId, $sender, $receipentEmail, $receipentName, $emailVariables, $storeId);
$translate->setTranslateInline(true);
}
catch ( Exception $ex ) {
Mage::log('Cron job emails not working : '.$templateId, null, "order.log");
}
}
Extract Email Variables from Order
private function pendingPaymentsVariables( $order ) {
$variables['orderdetails'] = array(
'customername' => $order->getCustomerFirstname().' '.$order->getCustomerLastname(),
'customeremail'=> $order->getCustomerEmail(),
'orderid' => $order->getEntityId(),
'currency_symbol' => $this->getCurrencySymbol(),
'order' => $order);
return $variables;
}
Calculate Pending Hours
private function getDifference( $obj ) {
$createdAt = strtotime($obj->getCreatedAt());
$currentDate = strtotime(date("Y-m-d H:i:s"));
$difference = $currentDate - $createdAt;
return ($difference/60);
}