diff --git a/readme.txt b/readme.txt
index 9bfe193..72ea818 100644
--- a/readme.txt
+++ b/readme.txt
@@ -13,8 +13,6 @@ module.
 Ogone backend:
 -Global transaction parameters tab:
   -Default ECI value : 7 - e-commerce with SSL encryption
--Global security parameters tab:
-  -Global security parameters: Main parameters only.
 -Data and origin verification  tab:
   -SHA-IN Pass phrase: must be the same as "SHA-1 Signature pre"*
   -IP address...: Whell, you guess..
@@ -23,9 +21,11 @@ Ogone backend:
   -I want to receive transaction feedback parameters...: TRUE
   -I want Ogone to display a short text to the customer...: TRUE
   -Timing of the request: Always online...
+  -Post payment URL: absolute path to /cart/uc_ogone_update_status
   -Request method: GET
   -SHA-OUT Pass phrase: "SHA-1 Signature post"*
-  -Timing of the request: No request
+  -Timing of the request: for all offline status changes
+  -URL: absolute path to /cart/uc_ogone_update_status
   -Transaction e-mails tab:
     -To customer not necessary, because Ubercart takes care of that by default
 
@@ -38,8 +38,11 @@ Ogone backend:
   FEATURES
 
 - Payment method choice after redirection to Ogone
+- Handles (offline) status changes
+- Select payment methods to show on the ogone page
+- Bypasses Ogone when total order amount is zero or below (free orders)
 - Based on 'basic' integration handbook with some tweaks from the 'advanced' integration
-- All settings adjustable in admin form
+- All settings adjustable in admin form (see payment methods in your store configuration)
 
 
 INFORMATION
@@ -56,10 +59,13 @@ TIPS
 -You could change the 'submit order' button text to something more meaningful like 'Go to Payment Screen'.
 -It's tricky to test from localhost. You have to open up port 80 to that machine, and configure the right URL to it under 4.1.
 
+PROBLEMS
+-If you get an error like 'Unknown order/1/s' its most likely the SHA-keys don't match. See also Drupal logs. Otherwise the encoding might be wrong, try changing the encoding in the 'Global security parameters' tab.
+
 THANKS
 Thanks to the helpful Ubercart team and forum users for tips and answers.
 
 DEVELOPMENT
 This module is developed, maintained and distributed bij Qrios. We can be contracted for Drupal/Ubercart projects or (payment) module building. Mail us: info {at} qrios {dot} nl.
 
-www.qrios.nl
\ No newline at end of file
+www.qrios.nl
diff --git a/uc_ogone_payment.install b/uc_ogone_payment.install
index 6bc9e68..44ffca0 100644
--- a/uc_ogone_payment.install
+++ b/uc_ogone_payment.install
@@ -16,6 +16,7 @@ function uc_ogone_payment_schema() {
       'pay_id' => array(
         'description' => 'The Pay ID from Ogone.',
         'type' => 'int',
+        'length' => 10,
         'not null' => TRUE,
         'unsigned' => TRUE,
       ),
@@ -93,3 +94,4 @@ function uc_ogone_payment_uninstall() {
   variable_del('ogone_sha1_signature_pre');
   variable_del('ogone_sha1_signature_post');
 }
+
diff --git a/uc_ogone_payment.module b/uc_ogone_payment.module
index 7bdcb19..6055d12 100644
--- a/uc_ogone_payment.module
+++ b/uc_ogone_payment.module
@@ -11,8 +11,6 @@
  *
  */
 
-
-
 /**
  * Implementation of hook_payment_method().
  */
@@ -43,14 +41,18 @@ function uc_ogone_payment_menu() {
       'access arguments' => array('access content'),
       'type' => MENU_CALLBACK,
     );
-
+    $items['cart/ogone_ok'] = array(
+      'title' => 'Ogone Payment OK',
+      'page callback' => 'uc_ogone_ok',
+      'access arguments' => array('access content'),
+      'type' => MENU_CALLBACK,
+    );
     $items['cart/ogone_return_ok'] = array(
       'title' => 'Ogone Payment return status',
-      'page callback' => 'uc_ogone_return_ok',
+      'page callback' => 'uc_ogone_update_status',
       'access arguments' => array('access content'),
       'type' => MENU_CALLBACK,
     );
-
     $items['cart/checkout/ogone_cancel'] = array(
       'title' => 'Ogone Payment cancel',
       'page callback' => 'uc_ogone_return_cancel',
@@ -67,10 +69,10 @@ function uc_ogone_payment_menu() {
 
     // Can be used optionally to let Ogone return the payment status
     // automatically/unmanaged.
-    $items['cart/ogone_return_ok_callback'] = array(
+    $items['cart/uc_ogone_update_status'] = array(
       'title' => 'Ogone Payment return status',
-      'callback' => 'uc_ogone_return_ok',
-      'callback arguments' => array(TRUE),
+      'page callback' => 'uc_ogone_update_status',
+      'page arguments' => array(TRUE),
       'access arguments' => array('access content'),
       'type' => MENU_CALLBACK,
     );
@@ -119,17 +121,21 @@ function uc_ogone_payment_order($op, &$arg1, $arg2) {
  * Callback from hook payment_method
  */
 function uc_payment_method_ogone($op, $arg1) {
+  
   switch($op) {
     case 'order-view':
     case 'customer-view':
-      $payment = db_fetch_object(db_query_range("SELECT pay_id, description FROM {uc_payment_ogone} WHERE order_id = %d", $arg1->order_id, 0, 1));
-      if (empty($payment->pay_id)) {
-        $payment->pay_id = t('Unknown');
+      //$payment = db_fetch_object(db_query_range("SELECT pay_id, description FROM {uc_payment_ogone} WHERE order_id = %d", $arg1->order_id, 0, 1));
+      $payment = db_fetch_object(db_query_range("SELECT pay_id, description, payment_method FROM {uc_payment_ogone} WHERE order_id = %d", $arg1->order_id, 0, 1));
+      if (!empty($payment->pay_id)) {
+        $output = t('Pay ID: @pay_id', array('@pay_id' => $payment->pay_id));
       }
-      if (empty($payment->description)) {
-        $payment->description = t('Unknown');
+      if (!empty($payment->payment_method)) {
+        if (!empty($payment->pay_id)) $output .='<br />';
+        $output .= t('Type: @paymentmethod', array('@paymentmethod' => $payment->payment_method));
       }
-      return t('Pay ID: @pay_id', array('@pay_id' => $payment->pay_id)) . '<br />' . t('Type: @description', array('@description' => $payment->description));
+      return $output;
+    //return t('Pay ID: @pay_id', array('@pay_id' => $payment->pay_id)) . '<br />' . t('Type: @description', array('@description' => $payment->description));
 
     case 'order-details':
       $details = drupal_get_form('uc_ogone_payment_method_form', $arg1);
@@ -145,7 +151,8 @@ function uc_payment_method_ogone($op, $arg1) {
     case 'order-load':
       $result = db_query("SELECT description FROM {uc_payment_ogone} WHERE "
                         ."order_id = %d", $arg1->order_id);
-      if ($row = db_fetch_object($result)) {
+      $row = db_fetch_object($result);
+      if ($row) {
         $arg1->payment_details['description'] = $row->description;
       }
       break;
@@ -196,6 +203,12 @@ function uc_ogone_payment_settings_form() {
     '#default_value' => variable_get('ogone_catalog_url', 'catalog'),
     '#description' => t('The relative path to your catalog page. For instance if your catalog page is www.yourdomain.com/catalog enter catalog'),
   );
+  $form['ogone_mark_order_as_paid'] = array(
+    '#type' => 'checkbox',
+    '#title' => t('Mark order as paid after succesfull payment'),
+    '#default_value' => variable_get('ogone_mark_order_as_paid)', 1),
+    '#description' => t('If checked the order state will be set to `payment received` after succesfull payment.'),
+  );
   $form['ogone_pspid_id'] = array(
     '#type' => 'textfield',
     '#title' => t('pspid'),
@@ -210,9 +223,24 @@ function uc_ogone_payment_settings_form() {
   );
   $form['ogone_language'] = array(
     '#type' => 'textfield',
-    '#title' => t('Language'),
+    '#title' => t('Default language'),
+    '#type' => 'select',
+    '#multiple' => FALSE,
+    '#options' => _uc_ogone_payment_language_codes(),
     '#default_value' => variable_get('ogone_language', 'en_US'),
-    '#description' => t('Use "en_US" notation for language. See Ogone documentation for details.'),
+    '#description' => t('The default value is used if the language can not be determined. Use "en_US" notation for language. See Ogone documentation for details.'),
+  );
+  $form['ogone_payment_methods_supported'] = array(
+    '#type' => 'textfield',
+    '#title' => t('Payment methods'),
+    '#default_value' => variable_get('ogone_payment_methods_supported', 'Bank transfer NL;iDEAL'),
+    '#description' => t('Fill in codes for supported methodes separated by ";" for instance "Direct Debits NL;iDEAL".'),
+  );
+  $form['ogone_payment_methods_list_type'] = array(
+    '#type' => 'textfield',
+    '#title' => t('Payment methods layout'),
+    '#default_value' => variable_get('ogone_payment_methods_list_type', '0'),
+    '#description' => t('0: Hor. grouped logos with the group name on the left, 1: Hor. grouped logos with no group names, 2: Vert. list of logos with specific payment method.'),
   );
   //Layout
   $form['ogone_layout_title'] = array(
@@ -268,16 +296,6 @@ function uc_ogone_payment_settings_form() {
     '#title' => t('Fonttype'),
     '#default_value' => variable_get('ogone_layout_fonttype', ''),
   );
-  $form['ogone_hashing_method'] = array(
-    '#type' => 'radios',
-    '#title' => t('Hashing method'),
-    '#options' => array(
-      'main_parameters' => t('Main parameters only.'),
-      'each_parameter' => t('Each parameter followed by the pass phrase.'),
-    ),
-    '#default_value' => variable_get('ogone_hashing_method', 'each_parameter'),
-    '#description' => t('In Ogone, “Tehcnical information” on the left side, then “Global security parameters” tab.'),
-  );
   $form['ogone_sha1_signature_pre'] = array(
     '#type' => 'textfield',
     '#title' => t('SHA-1 Signature pre'),
@@ -294,9 +312,60 @@ function uc_ogone_payment_settings_form() {
   return $form;
 }
 
+/**
+ * Dynamicaly set the language variable for the call to Ogone.
+ *
+ * @param string $lang The languagecode of the language used in drupal that should be used on the Ogone page.
+ */
+function _uc_ogone_payment_language($lang = NULL) {
+  // If no language code is given, get the language code from global.
+  if (!isset($lang)) {
+    global $language;
+    $lang = $language->language;
+  }
+  $code = _uc_ogone_payment_language_codes();
+  // If no language is mapped, use the default value.
+  if (!($lang = $code[$lang])) {
+    $lang = filter_xss(variable_get('ogone_language', 'en_US'));
+  }
+  return $lang;
+}
 
-function uc_ogone_call(&$arg1, $arg2) {
+/**
+ * Get a list of all defined language codes.
+ */
+function _uc_ogone_payment_language_codes() {
+  // Map the drupal language codes with the supported Ogone codes.
+  // Available Ogone languages: https://secure.ogone.com/ncol/param_cookbook.asp?CSRFSP=%2Fncol%2Fprod%2Fdownload_docs.asp&CSRFKEY=3EF8158F6FCF6791556E614075A2E52040DA20DC&CSRFTS=20111222125809
+  //Drupal languages: http://api.drupal.org/api/drupal/includes--locale.inc/function/_locale_get_predefined_list/6    
+  
+  return array(
+    'ar' => 'ar_AR',// Arabic
+    'cs' => 'cs_CZ',// Czech
+    'da' => 'dk_DK',// Danish
+    'de' => 'de_DE',// German
+    'el' => 'el_GR',// Greek
+    'en' => 'en_US', //English
+    'es' => 'es_ES',// Spanish     
+    'fr' => 'fr_FR',// French
+    'hu' => 'hu_HU',// hungarian
+    'it' => 'it_IT',// Italian
+    'ja' => 'ja_JP',// Japanese    
+    'nl' => 'nl_NL',// Dutch
+    'no' => 'no_NO',// Norwegian
+    'pl' => 'pl_PL',// Polish
+    'pt-pt' => 'pt_PT',// Portugese (Portugal)
+    'pt-br' => 'pt_PT',// Portugese (Brazil)
+    'ru' => 'ru_RU',// Russian
+    'sv' => 'se_SE',// Swedish
+    'sk' => 'sk_SK',// Slovak
+    'tr' => 'tr_TR',// Turkish
+    'zh-hans' => 'zh_CN',// Simplified Chinese
+  );
+}
 
+function uc_ogone_call(&$arg1, $arg2) {
+  
   /*global $user; //Todo: find a way to detect user language
   if (!($user->language)) {
     $language = 'en_US';
@@ -327,10 +396,9 @@ function uc_ogone_call(&$arg1, $arg2) {
   $orderid = $arg1->order_id;
   $amount = round($arg1->order_total * 100);   //amount *100
 
-  $currency = filter_xss(variable_get('ogone_currency', TRUE));
-  $language = filter_xss(variable_get('ogone_language', 'en_US'));
+  $currency = filter_xss(variable_get('ogone_currency', 'USD'));
 
-  $layout_title = filter_xss(variable_get('ogone_layout_title', TRUE));
+  $layout_title = filter_xss(t(variable_get('ogone_layout_title', TRUE)));
   $layout_bgcolor = filter_xss(variable_get('ogone_layout_bgcolor', TRUE));
   $layout_txtcolor = filter_xss(variable_get('ogone_layout_txtcolor', TRUE));
   $layout_tblbgcolor = filter_xss(variable_get('ogone_layout_tblbgcolor', TRUE));
@@ -340,6 +408,9 @@ function uc_ogone_call(&$arg1, $arg2) {
   $layout_logo = filter_xss(variable_get('ogone_layout_logo', TRUE));
   $layout_fonttype = filter_xss(variable_get('ogone_layout_fonttype', TRUE));
 
+  $pm_list = filter_xss(variable_get('ogone_payment_methods_supported', 'Bank transfer NL;iDEAL'));
+  $pm_list_type = filter_xss(variable_get('ogone_payment_methods_list_type', '0'));
+  
   $order_description = variable_get('uc_store_name', 'Webshop').' order: '.$arg1->order_id;
   $customer_name = $arg1->delivery_first_name.' '.$arg1->delivery_last_name;
   $customer_name = substr($customer_name, 0, 35); //Make sure this is < 35 char, else Ogone freaks out
@@ -354,6 +425,7 @@ function uc_ogone_call(&$arg1, $arg2) {
   $ogone_button_text = t('Click here to go to payment page manualy');
 
   $sha_suffix = variable_get('ogone_sha1_signature_pre', TRUE);
+  $template_path =url('ogone_template_call', array('absolute' => TRUE));
 
   //Make SHA1 string for pre payment verification
   $arguments = array(
@@ -373,27 +445,23 @@ function uc_ogone_call(&$arg1, $arg2) {
     'EXCEPTIONURL' => url('cart/checkout', array('absolute' => TRUE)),
     'FONTTYPE' => $layout_fonttype,
     'HOMEURL' => url('', array('absolute' => TRUE)),
-    'LANGUAGE' => $language,
+    'LANGUAGE' => _uc_ogone_payment_language(),
     'LOGO' => $layout_logo,
     'ORDERID' => $orderid,
     'OWNERADDRESS' => $customer_address,
     'OWNERZIP' => $customer_zip,
     'PM' => '',
+  	'PMLIST' => $pm_list,
+  	'PMLISTTYPE' => $pm_list_type,
     'PSPID' => $pspid,
     'TBLBGCOLOR' => $layout_tblbgcolor,
     'TBLTXTCOLOR' => $layout_tbltxtcolor,
     'TITLE' => $layout_title,
-    'TP' => url('ogone_template_call', array('absolute' => TRUE)),
+    'TP' => $template_path,
     'TXTCOLOR' => $layout_tbltxtcolor
   );
 
-  $ogone_hashing_method = variable_get('ogone_hashing_method', 'each_parameter');
-  if ($ogone_hashing_method === 'each_parameter') {
-    $sha1_signature = '';
-  }
-  elseif ($ogone_hashing_method === 'main_parameters') {
-    $sha1_signature = $orderid . $amount . $currency . $pspid . $sha_suffix;
-  }
+  $sha1_signature = '';
 
   $_SESSION['ogone_form']='
   <div class="ogone_redirect_message_top">
@@ -407,15 +475,13 @@ function uc_ogone_call(&$arg1, $arg2) {
     $param_value = trim($param_value);
     $param_name = strtoupper($param_name);
     if (strlen($param_value) > 0) {
-      if ($ogone_hashing_method === 'each_parameter') {
-        $sha1_signature .= $param_name.'='.$param_value.$sha_suffix;
-      }
+      $sha1_signature .= $param_name.'='.$param_value.$sha_suffix;
       $_SESSION['ogone_form'] .= '<INPUT type="hidden" NAME="'.$param_name.'" VALUE="'.$param_value.'" />';
     }
   }
 
   $_SESSION['ogone_form'] .= '
-  <INPUT type="hidden" NAME="SHASign" value="'.sha1($sha1_signature).'">
+  <INPUT type="hidden" NAME="SHASign" value="'.sha1($sha1_signature).'" />
   <input type="submit" value="'.$ogone_button_text.'" id="submit2" name="submit2" />
   </form>
   <script language="JavaScript">
@@ -427,7 +493,13 @@ function uc_ogone_call(&$arg1, $arg2) {
   </div>
   </div>'
   ;
-  drupal_goto('cart/checkout/ogone_redirect');
+  if ($amount >0){
+    drupal_goto('cart/checkout/ogone_redirect');
+
+  } 
+  else{ //Free orders should bypass ogone validation
+    uc_ogone_free_order_confirmed($orderid,$amount);
+  }
 }
 
 function uc_ogone_template() {
@@ -442,6 +514,9 @@ function uc_ogone_template() {
 
 function uc_ogone_return_cancel() {
   drupal_set_message(t('Ogone returned a cancel for your payment. Your order is not completed. Please try again or contact us.'), 'ERROR');
+  if (trim($_GET['orderID'])){
+    uc_order_update_status(trim($_GET['orderID']), uc_order_state_default('canceled'));
+  }
   drupal_goto('cart/checkout');
 }
 
@@ -456,56 +531,152 @@ function uc_ogone_redirect_form() {
   }
 }
 
+function uc_ogone_ok() {
+    $_SESSION['do_complete'] = TRUE;
+	drupal_goto('cart/checkout/complete');
+}
+
 /**
  * This is called by Ogone itself NOT within the user session!
  */
-function uc_ogone_return_ok($auto = FALSE) {
-  $valid_stat = array(5, 9);
+function uc_ogone_update_status($auto = FALSE) {
+  /* Definition of Ogone status codes  
+   * Ogone Status codes: https://secure.ogone.com/ncol/param_cookbook.asp?CSRFSP=%2Fncol%2Fprod%2Fdownload_docs.asp&CSRFKEY=3EF8158F6FCF6791556E614075A2E52040DA20DC&CSRFTS=20111222125809
+   * Ubercart order status codes: http://www.ubercart.org/docs/api/uc_order_status_list
+   */
+  
+  
+  $ogone_status_codes = array(
+      '5'=>'payment_received', 
+      '6'=>'canceled',
+      '9'=>'payment_received',
+      '95'=>'payment_received', //manual added payment
+      '41'=>'payment_pending_customer',
+  );
+  
   $sha_suffix = variable_get('ogone_sha1_signature_post', TRUE);
-
   $arguments = array(
-    'AAVCHECK' => trim($_GET['AAVCheck']),
-    'ACCEPTANCE' => trim($_GET['ACCEPTANCE']),
-    'AMOUNT' => trim($_GET['amount']),
-    'BRAND' => trim($_GET['BRAND']),
-    'CARDNO' => trim($_GET['CARDNO']),
-    'CCCTY'=> trim($_GET['CCCTY']),
-    'CN' => trim($_GET['CN']),
-    'CURRENCY' => trim($_GET['currency']),
-    'CVCCHECK' => trim($_GET['CVCCheck']),
-    'ECI' => trim($_GET['ECI']),
-    'ED' => trim($_GET['ED']),
-    'IP' => trim($_GET['IP']),
-    'IPCTY' => trim($_GET['IPCTY']),
-    'NCERROR' => trim($_GET['NCERROR']),
-    'ORDERID' => trim($_GET['orderID']),
-    'PAYID' => trim($_GET['PAYID']),
-    'PM' => trim($_GET['PM']),
-    'STATUS' => trim($_GET['STATUS']),
-    'TRXDATE' => trim($_GET['TRXDATE']),
-    'VC' => trim($_GET['VC']),
+    'AAVCHECK' => $_GET['AAVCheck'],
+    'ACCEPTANCE' => $_GET['ACCEPTANCE'],
+    'AMOUNT' => $_GET['amount'],
+    'BRAND' => $_GET['BRAND'],
+    'CARDNO' => $_GET['CARDNO'],
+    'CCCTY'=> $_GET['CCCTY'],
+    'CN' => $_GET['CN'],
+    'CURRENCY' => $_GET['currency'],
+    'CVCCHECK' => $_GET['CVCCheck'],
+    'ECI' => $_GET['ECI'],
+    'ED' => $_GET['ED'],
+    'IP' => $_GET['IP'],
+    'IPCTY' => $_GET['IPCTY'],
+    'NCERROR' => $_GET['NCERROR'],
+    'ORDERID' => $_GET['orderID'],
+    'PAYID' => $_GET['PAYID'],
+    'PM' => $_GET['PM'],
+    'STATUS' => $_GET['STATUS'],
+    'TRXDATE' => $_GET['TRXDATE'],
+    'VC' => $_GET['VC'],
   );
 
   $sha1_return_key = strtoupper($_GET['SHASIGN']);
 
-  $ogone_hashing_method = variable_get('ogone_hashing_method', 'each_parameter');
-  if ($ogone_hashing_method === 'each_parameter') {
-    $sha1_key = '';
-    foreach ($arguments as $param_name => $param_value) {
-      $param_value = trim($param_value);
-      $param_name = strtoupper($param_name);
-      if (strlen($param_value) > 0) {
-        $sha1_key .= $param_name . '=' . $param_value.$sha_suffix;
-      }
+  $sha1_key = '';
+  foreach ($arguments as $param_name => $param_value) {
+   // $param_value = trim($param_value);
+    $param_name = strtoupper($param_name);
+    if (strlen($param_value) > 0) {
+      $sha1_key .= $param_name . '=' . $param_value.$sha_suffix;
     }
   }
-  elseif ($ogone_hashing_method === 'main_parameters') {
-    $sha1_key = $arguments['ORDERID'] . $arguments['CURRENCY'] . $arguments['AMOUNT'] . $arguments['PM'] . $arguments['ACCEPTANCE'] .  $arguments['STATUS'] . $arguments['CARDNO'] . $arguments['PAYID'] . $arguments['NCERROR'] . $arguments['BRAND'] . $sha_suffix;
-  }
 
   $sha1_key = strtoupper(sha1($sha1_key));
+  
+  $errormessage='';
+  $ubercart_status='unknown';
+  if (array_key_exists($arguments['STATUS'], $ogone_status_codes)){
+    $ubercart_status = $ogone_status_codes[$arguments['STATUS']];
+  }else{
+    $ubercart_status='error';
+    $errormessage.=' Invalid status:'.$arguments['STATUS'].'. Valid statusses:'.var_export($ogone_status_codes,true); 
+  }
+  
+  //invalid SHA keys
+  if ($sha1_key != $sha1_return_key){
+    $ubercart_status='error';
+    $errormessage.=' SHA keys don\'t match. Sha1_key='.$sha1_key.' and return sha key='.$sha1_return_key.' received params:'.print_r($_GET,true);  
+  }
+  
+  switch($ubercart_status){
+    case 'payment_received':
+          uc_ogone_action_save_payment($auto,$arguments,$ubercart_status);
+          break;
+    case 'unknown': //unknown state
+          break;
+    case 'error':   //validation error
+          uc_ogone_action_error($auto,$ubercart_status,$errormessage);
+          break;
+    default:  //valid state
+          uc_ogone_action_save_new_state($auto,$ubercart_status);
+          break;
+  }
+}
+//
+function uc_ogone_action_error($auto,$ubercart_status,$errormessage){ 
+  if (isset($_GET['orderID']) && !$auto){
+    //Dont set the order as canceled if this is a webservice call from Ogone
+   // uc_order_update_status(trim($_GET['orderID']), uc_order_state_default('canceled'));
+  }
+  $additional_info='Error occured during customer checkout';
+  if ($auto){
+    $additional_info='Error occured during automatic Ogone webservice call';
+  }
+  watchdog('uc_ogone_payment', 'Ogone returned an error for this payment (orderid:'.$_GET['orderID'].') '.$errormessage.' Ubercart statuscode:'.$ubercart_status.' '.$additional_info, NULL, WATCHDOG_ERROR);
+  if ($_GET['orderID']){
+    uc_order_comment_save($_GET['orderID'], 0, t('Error occured during Ogone communication:').$errormessage, 'admin');
+  }
+  if (!$auto) {
+      drupal_set_message(t('Ogone returned an error for your payment. Your order is not completed. Please try again or contact us.'), 'ERROR');
+      drupal_goto('cart/checkout');      
+  }
+}
+
+/**
+ * Returns the order state for the specified order
+ * @param type $orderid
+ * @return string orderstate
+ */
+function uc_ogone_get_order_state($orderid){
+  if(!$orderid) return NULL;
+  $result = db_query("SELECT order_status FROM {uc_orders} WHERE order_id = %d", $orderid);
+  $order = db_fetch_object($result);
+  if ($order==FALSE) return NULL;
+  return $order->order_status;
+}
 
-  if (($sha1_key == $sha1_return_key) && in_array($arguments['STATUS'], $valid_stat)) {
+/**
+ * Updates the order to a new state
+ * @param type $auto
+ * @param type $new_ubercart_status 
+ */
+function uc_ogone_action_save_new_state($auto, $new_ubercart_status){
+  $orderid=trim($_GET['orderID']);
+  if ($orderid){
+    if (uc_ogone_get_order_state($orderid) != $new_ubercart_status){
+      uc_order_update_status(trim($_GET['orderID']), $new_ubercart_status);
+    }
+  }  
+  if (!$auto) {
+      drupal_goto('cart/ogone_ok');
+  }
+}
+
+/**
+ * Succesful payment is made. Update status to payed and redirect to ok page.
+ * @param type $arguments 
+ */
+function uc_ogone_action_save_payment($auto,$arguments,$ubercart_state){
+    //Skip this function if this order is already set to paid
+    if (uc_ogone_get_order_state($arguments['ORDERID'])=='payment_received') return;
     // Record the successful payment.
     $payment = (object) array(
       'order_id' => $arguments['ORDERID'],
@@ -517,7 +688,7 @@ function uc_ogone_return_ok($auto = FALSE) {
     );
     // Duplicates happen, check if we have one.
     if (db_result(db_query_range("SELECT 1 FROM {uc_payment_ogone} WHERE pay_id = %d", $payment->pay_id, 0, 1))) {
-      watchdog('uc_ogone_payment', 'Duplicate Ogone Pay ID @pay_id recieved.', array('@pay_id' => $payment->pay_id));
+      watchdog('uc_ogone_payment', 'Duplicate Ogone Pay ID @pay_id received.', array('@pay_id' => $payment->pay_id));
       // TODO The drupal_goto('cart/checkout/complete') below will redo some
       // order operations, like sending invoices. However, the logic for
       // messages and redirects in uc_cart_checkout_complete() and
@@ -527,23 +698,50 @@ function uc_ogone_return_ok($auto = FALSE) {
     }
     else {
       drupal_write_record('uc_payment_ogone', $payment);
-      uc_order_update_status($payment->order_id, uc_order_state_default('payment_received'));
     }
+    if (variable_get('ogone_mark_order_as_paid)', 1)){
+      //uc_order_update_status($payment->order_id, uc_order_state_default('payment_received'));
+      uc_order_update_status($payment->order_id,'payment_received');
+    }
+	  $order = uc_order_load($payment->order_id);
+		uc_payment_enter($order->order_id, 'ogone_payment', $order->order_total, $order->uid, NULL, $comment);
 
     // This lets us know it's a legitimate access of the complete page.
     $_SESSION['cart_order'] = $payment->order_id;
-    $_SESSION['do_complete'] = TRUE;
 
     if (!$auto) {
-      drupal_goto('cart/checkout/complete');
+      drupal_goto('cart/ogone_ok');
     }
+}
+
+/**
+ * Handle free orders (balance is zero or below)
+ * @param type $orderid
+ * @param type $amount 
+ */
+function uc_ogone_free_order_confirmed($orderid,$amount){
+  if ($amount>0){
+    drupal_set_message(t('Order total is positive, payment required.'), 'ERROR');
+    drupal_goto('cart/checkout');    
   }
-  else {
-    // Payment was not successful.
-    watchdog('uc_ogone_payment', 'Ogone returned an error for this payment.', NULL, WATCHDOG_ERROR);
-    if (!$auto) {
-      drupal_set_message(t('Ogone returned an error for your payment. Your order is not completed. Please try again or contact us.'), 'ERROR');
-      drupal_goto('cart/checkout');
-    }
+  if (!$orderid){
+    drupal_set_message(t('Unknown order'), 'ERROR');
+    drupal_goto('cart/checkout');    
   }
+  $payment = (object) array(
+    'order_id' => $orderid,
+    'pay_id' => -1,
+    'description' => 'Back-office',
+    'payment_method' =>t('Free order'),
+    'order_status' => 9,
+    'sha1_test_succes' => 'OK',
+  );
+  drupal_write_record('uc_payment_ogone', $payment);
+  //uc_order_update_status($orderid, uc_order_state_default('payment_received'));
+  uc_order_update_status($orderid, 'payment_received');
+  $order = uc_order_load($orderid);
+  uc_payment_enter($order->order_id, 'ogone_payment', $order->order_total, 0, NULL,t('Checkout completed for a free order.'));
+  // This lets us know it's a legitimate access of the complete page.
+  $_SESSION['cart_order'] = $payment->order_id;
+  drupal_goto('cart/ogone_ok');
 }
