Jump to content
cinolas

Change the selected payment module while loading checkout_confirmation.php when the total is $0

Recommended Posts

I'm looking for a way to change the selected payment module while loading checkout_confirmation.php

The problem I'm having is with the Gift Voucher contrib (https://apps.oscommerce.com/KMILS&gift-vouchers-secure-v1-0) still requiring a valid payment method, even when the total is fully covered by the Gift Voucher balance (order total = $0). I added the Free Product Checkout payment module (https://apps.oscommerce.com/Get&xy0S8&JuIEu) to take care of that. However, that payment module only shows up when the order total = $0, and the order total is not yet $0 at this point since the Gift Voucher balance doesn't get applied until checkout_confirmation.php loads.

So my thinking is that if I could change the selected payment method to Free Product Checkout while loading checkout_confirmation.php (if the order total at that point is = $0) then it would take care of it all.

Unfortunately, I don't know enough php to do this. I've learned quite a bit while customizing my osC install, but not quite enough to know where to start with this. Unless there's something else I can compare to / copy / get inspired by?

Anyway, if anyone has any insights on how I might be able to change the selected payment method if the order total = $0 while loading checkout_confirmation.php, that would grreeeeeeeaaaat.

Cheers!

Share this post


Link to post
Share on other sites

Alternatively, I figure I could do without the Free Product Checkout payment module if I could just tweak the checkout_process to allow orders with a total of $0, and prevent the payment module from being invoked. I don't mind changes to the core of osC, my install is already very customized.

So don't laugh, I'm trying here... Looking at checkout_process.php around line 87 it goes:

$payment_modules->update_status();

  if ( ($payment_modules->selected_module != $payment) || ( is_array($payment_modules->modules) && (sizeof($payment_modules->modules) > 1) && !is_object($$payment) ) || (is_object($$payment) && ($$payment->enabled == false)) ) {
    tep_redirect(tep_href_link(FILENAME_CHECKOUT_PAYMENT, 'error_message=' . urlencode(ERROR_NO_PAYMENT_MODULE_SELECTED), 'SSL'));
  }

  require(DIR_WS_CLASSES . 'order_total.php');
  $order_total_modules = new order_total;

  $order_totals = $order_total_modules->process();

// load the before_process function from the payment modules
  $payment_modules->before_process();

I'm thinking that's where the logic to refuse total = $0 orders is. What if I was to modify it to something like this (but, you know, with proper syntax and such):

if ($order->info['total'] > 0) {
            $payment_modules->update_status();
    }
  

  if ( ($payment_modules->selected_module != $payment) || ( is_array($payment_modules->modules) && (sizeof($payment_modules->modules) > 1) && !is_object($$payment) ) || (is_object($$payment) && ($$payment->enabled == false)) ) {
    if ($order->info['total'] > 0) {
       tep_redirect(tep_href_link(FILENAME_CHECKOUT_PAYMENT, 'error_message=' . urlencode(ERROR_NO_PAYMENT_MODULE_SELECTED), 'SSL'));
    }
  }

  require(DIR_WS_CLASSES . 'order_total.php');
  $order_total_modules = new order_total;

  $order_totals = $order_total_modules->process();

// load the before_process function from the payment modules
   if ($order->info['total'] > 0) {
      $payment_modules->before_process();
   }

First suppressing the error redirect, and then adding IFs everywhere to prevent the payment part from being invoked when the order total is $0?

I'm not sure if ($order->info['total'] > 0) is valid syntax here... I'm not sure how to get the new order total after the Gift Voucher balance has been applied.

Share this post


Link to post
Share on other sites

Why not just modify Free Product Checkout to compare the order total to the gift voucher balance instead of to 0? 


Always back up before making changes.

Share this post


Link to post
Share on other sites

@ecartz Brilliant! Though, the Gift Voucher balance get's applied on checkout_payment.php (that's where the checkbox to use the balance is), so it hasn't been applied yet and is therefore $0, so that unfortunately wouldn't work.

It gets applied, and the order total becomes $0, between the payment and confirmation page. Which is why I was looking for a way to change the payment method at that point.

It almost seems silly that osC would prevent orders with $0 totals. I don't get what it's meant to protect against. It should just confirm the order without bugging the payment modules.

Any other awesomely simple ideas?

Cheers!

Share this post


Link to post
Share on other sites

Compare it to the gift voucher balance available, not the amount applied.  If the balance is sufficient, you can show the payment module.  You may have to do more work if the user selects that module without applying the balance.  Because presumably you want to deduct the amount from the balance before processing the order.  But the question on the payment page is how someone is paying.  And the answer in that situation would be with the voucher balance. 


Always back up before making changes.

Share this post


Link to post
Share on other sites

That would be even better than the current Gift Voucher contribution process. As it is now, the checkbox to apply the Gift Voucher balance always shows up under the Payment Methods.

If I could make it so that the Free payment module only shows up when there's enough in the Gift Voucher balance to pay for the order fully (comparing to the available balance as you suggest), and at the same time HIDE the Apply Gift Voucher Balance checkbox. And then somehow make it so that this hidden checkbox gets checked when the Free payment method is used. And for times where the available balance is't enough to cover the entire total, the check box would show up but not the Free payment method (since they have to choose a method for remainder).

Technically, I have no idea how to access the customer's available Gift Voucher balance from /includes/modules/payment/free.php I'll also need to access it from checkout_payment.php to hide the checkbox.

Javascript should be able to check the hidden box on submit, or would there be a better method?

Thanks for all the help @ecartz!

Share this post


Link to post
Share on other sites

Copy-pasta artist at work.

I scooped this bit from the Gift Voucher account content module and added it to the Free shipping module like:

// enable the module if the order total is equal or less than the Gift Certificate balance
		include_once(DIR_FS_CATALOG . 'includes/languages/' . $_SESSION['language'] . '/gift_vouchers.php');
        if (tep_session_is_registered('customer_id')) {
            $gv_query = tep_db_query("select amount from coupon_gv_customer where customer_id = '" . tep_db_input($_SESSION['customer_id']) . "'");
            $gv_result = tep_db_fetch_array($gv_query);
        }													      
  
          if ($order->info['total'] > $gv_result['amount']) {
            $this->enabled = false;
          }  
    }

and it seems to work!

I'm only posting it in case it can help someone looking for something similar in the future.

Share this post


Link to post
Share on other sites

And that first include is not needed. Derp:

// enable the module if the order total is equal or less than the Gift Certificate balance
	if (tep_session_is_registered('customer_id')) {
		$gv_query = tep_db_query("select amount from coupon_gv_customer where customer_id = '" . tep_db_input($_SESSION['customer_id']) . "'");
		$gv_result = tep_db_fetch_array($gv_query);
	}													      
  
	if ($order->info['total'] > $gv_result['amount']) {
		$this->enabled = false;
	} 

 

Share this post


Link to post
Share on other sites

And the same technique worked to hide the Apply Gift Voucher checkbox, for when there's enough to pay for it all, and the Free payment module is showing. I changed the __construct() function of /includes/modules/order_total/ot_gv.php to this:

function __construct() {
      global $order, $currencies;	
      $this->code = 'ot_gv';
      $this->title = MODULE_ORDER_TOTAL_GV_TITLE;
      $this->header = MODULE_ORDER_TOTAL_GV_HEADER;
      $this->description = MODULE_ORDER_TOTAL_GV_DESCRIPTION;
      $this->enabled = MODULE_ORDER_TOTAL_GV_STATUS;
      $this->sort_order = MODULE_ORDER_TOTAL_GV_SORT_ORDER;
      $this->include_shipping = MODULE_ORDER_TOTAL_GV_INC_SHIPPING;
      $this->include_tax = MODULE_ORDER_TOTAL_GV_INC_TAX;
      $this->calculate_tax = MODULE_ORDER_TOTAL_GV_CALC_TAX;
      $this->credit_tax = MODULE_ORDER_TOTAL_GV_CREDIT_TAX;
      $this->tax_class  = MODULE_ORDER_TOTAL_GV_TAX_CLASS;
      $this->show_redeem_box = MODULE_ORDER_TOTAL_GV_REDEEM_BOX;
      $this->credit_class = true;
      // NIC added test to see if there's enough Gift Certificate balance to cover the entire order. If so, hide the Gift Certificate checkbox, if not hide the Free payment module and show the checkbox
      if (tep_session_is_registered('customer_id')) {
          $gv_query = tep_db_query("select amount from coupon_gv_customer where customer_id = '" . tep_db_input($_SESSION['customer_id']) . "'");
          $gv_result = tep_db_fetch_array($gv_query);
      }
      If ($order->info['total'] > $gv_result['amount']) {
            $this->user_prompt = MODULE_ORDER_TOTAL_GV_USER_PROMPT;
            $this->checkbox = $this->user_prompt . ' (' . $currencies->format($gv_result['amount']) . ') <input type="checkbox" onClick="submitFunction()" name="' . 'c' . $this->code . '">';
      } else {
            $this->user_prompt = '';
            $this->checkbox = $this->user_prompt . '<input type="hidden" value="0" name="' . 'c' . $this->code . '">';
      }
      $this->output = array();
    }

 NOW, the only thing left to achieve is toggling the value of the hidden checkbox when the users selects/deselects the Free payment method...

Share this post


Link to post
Share on other sites

Actually onSubmit would be better... the checkout_payment.php page runs the check_form() js onSubmit. That script is written by the javascript_validation() function from /includes/classes/payment.php:

function javascript_validation() {
      $js = '';
      if (is_array($this->modules)) {
        $js = '<script><!-- ' . "\n" .
              'function check_form() {' . "\n" .
              '  var error = 0;' . "\n" .
              '  var error_message = "' . JS_ERROR . '";' . "\n" .
              '  var payment_value = null;' . "\n" .
              '  if (document.checkout_payment.payment.length) {' . "\n" .
              '    for (var i=0; i<document.checkout_payment.payment.length; i++) {' . "\n" .
              '      if (document.checkout_payment.payment[i].checked) {' . "\n" .
              '        payment_value = document.checkout_payment.payment[i].value;' . "\n" .
              '      }' . "\n" .
              '    }' . "\n" .
              '  } else if (document.checkout_payment.payment.checked) {' . "\n" .
              '    payment_value = document.checkout_payment.payment.value;' . "\n" .
              '  } else if (document.checkout_payment.payment.value) {' . "\n" .
              '    payment_value = document.checkout_payment.payment.value;' . "\n" .
              '  }' . "\n\n";

        reset($this->modules);
        while (list(, $value) = each($this->modules)) {
          $class = substr($value, 0, strrpos($value, '.'));
          if ($GLOBALS[$class]->enabled) {
            $js .= $GLOBALS[$class]->javascript_validation();
          }
        }

        //$js .= "\n" . '  if (payment_value == null) {' . "\n" .
        //       '    error_message = error_message + "' . JS_ERROR_NO_PAYMENT_MODULE_SELECTED . '";' . "\n" .
        //       '    error = 1;' . "\n" .
        //       '  }' . "\n\n" .
        //       '  if (error == 1) {' . "\n" .
        //       '    alert(error_message);' . "\n" .
        //       '    return false;' . "\n" .
        //       '  } else {' . "\n" .
        //       '    return true;' . "\n" .
        //       '  }' . "\n" .
        //       '}' . "\n" .
        //       '//--></script>' . "\n";
		// Begin Gift Vouchers Secure

        $js .= "\n" . '  if (payment_value == null && submitter != 1) {' . "\n" . 
               '    error_message = error_message + "' . JS_ERROR_NO_PAYMENT_MODULE_SELECTED . '";' . "\n" .
               '    error = 1;' . "\n" .
               '  }' . "\n\n" .
               '  if (error == 1 && submitter != 1) {' . "\n" . 
               '    alert(error_message);' . "\n" .
               '    return false;' . "\n" .
               '  } else {' . "\n" .
               '    return true;' . "\n" .
               '  }' . "\n" .
               '}' . "\n" .
               '//--></script>' . "\n";
        // End Gift Vouchers Secure
      }
      return $js;
    }

I need to change this function so it looks at which payment method is selected (or which payment module value is submitted?) and sets the value of my hidden input to 1 if the payment module is 'free'.

Unfortunately my JS skills are even worse than my php... any tips?

Note that this js references submitter, which is a variable set by script when someone clicks the checkbox I have just hidden. The checkbox is not always hidden, so I need to keep this functionality working, but also make it so that it doesn't rely on submitter for when the checkbox is indeed hidden.... argh! haha

Edited by cinolas

Share this post


Link to post
Share on other sites

Ok, so it wasn't that difficult after all.

I added an ID to the hidden checkbox. In the __construct() function of /includes/modules/order_total/ot_gv.php to this:

function __construct() {
      global $order, $currencies;	
      $this->code = 'ot_gv';
      $this->title = MODULE_ORDER_TOTAL_GV_TITLE;
      $this->header = MODULE_ORDER_TOTAL_GV_HEADER;
      $this->description = MODULE_ORDER_TOTAL_GV_DESCRIPTION;
      $this->enabled = MODULE_ORDER_TOTAL_GV_STATUS;
      $this->sort_order = MODULE_ORDER_TOTAL_GV_SORT_ORDER;
      $this->include_shipping = MODULE_ORDER_TOTAL_GV_INC_SHIPPING;
      $this->include_tax = MODULE_ORDER_TOTAL_GV_INC_TAX;
      $this->calculate_tax = MODULE_ORDER_TOTAL_GV_CALC_TAX;
      $this->credit_tax = MODULE_ORDER_TOTAL_GV_CREDIT_TAX;
      $this->tax_class  = MODULE_ORDER_TOTAL_GV_TAX_CLASS;
      $this->show_redeem_box = MODULE_ORDER_TOTAL_GV_REDEEM_BOX;
      $this->credit_class = true;
      // Added test to see if there's enough Gift Certificate balance to cover the entire order. If so, hide the Gift Certificate checkbox, if not hide the Free payment module and show the checkbox
      if (tep_session_is_registered('customer_id')) {
          $gv_query = tep_db_query("select amount from coupon_gv_customer where customer_id = '" . tep_db_input($_SESSION['customer_id']) . "'");
          $gv_result = tep_db_fetch_array($gv_query);
      }
      If ($order->info['total'] > $gv_result['amount']) {
            $this->user_prompt = MODULE_ORDER_TOTAL_GV_USER_PROMPT;
            $this->checkbox = $this->user_prompt . ' (' . $currencies->format($gv_result['amount']) . ') <input type="checkbox" onClick="submitFunction()" id="GiftCertBox" name="' . 'c' . $this->code . '">';
      } else {
            $this->user_prompt = '';
            $this->checkbox = $this->user_prompt . '<input type="hidden" value="0" id="GiftCertBox "name="' . 'c' . $this->code . '">';
      }
      $this->output = array();
    }

Then I modified the javascript_validation() function of /includes/classes/payment.php, line 76:

function javascript_validation() {
      $js = '';
      if (is_array($this->modules)) {
        $js = '<script><!-- ' . "\n" .
              'function check_form() {' . "\n" .
              '  var error = 0;' . "\n" .
              '  var error_message = "' . JS_ERROR . '";' . "\n" .
              '  var payment_value = null;' . "\n" .
              '  var gc_box = document.getElementById("GiftCertBox");' . "\n" .
              '  if (document.checkout_payment.payment.length) {' . "\n" .
              '    for (var i=0; i<document.checkout_payment.payment.length; i++) {' . "\n" .
              '      if (document.checkout_payment.payment[i].checked) {' . "\n" .
              '        payment_value = document.checkout_payment.payment[i].value;' . "\n" .
              '      }' . "\n" .
              '    }' . "\n" .
              '  } else if (document.checkout_payment.payment.checked) {' . "\n" .
              '    payment_value = document.checkout_payment.payment.value;' . "\n" .
              '  } else if (document.checkout_payment.payment.value) {' . "\n" .
              '    payment_value = document.checkout_payment.payment.value;' . "\n" .
              '  }' . "\n\n";

        reset($this->modules);
        while (list(, $value) = each($this->modules)) {
          $class = substr($value, 0, strrpos($value, '.'));
          if ($GLOBALS[$class]->enabled) {
            $js .= $GLOBALS[$class]->javascript_validation();
          }
        }

        //$js .= "\n" . '  if (payment_value == null) {' . "\n" .
        //       '    error_message = error_message + "' . JS_ERROR_NO_PAYMENT_MODULE_SELECTED . '";' . "\n" .
        //       '    error = 1;' . "\n" .
        //       '  }' . "\n\n" .
        //       '  if (error == 1) {' . "\n" .
        //       '    alert(error_message);' . "\n" .
        //       '    return false;' . "\n" .
        //       '  } else {' . "\n" .
        //       '    return true;' . "\n" .
        //       '  }' . "\n" .
        //       '}' . "\n" .
        //       '//--></script>' . "\n";
		// Begin Gift Vouchers Secure

        $js .= "\n" . '  if (payment_value == null && submitter != 1) {' . "\n" . 
               '    error_message = error_message + "' . JS_ERROR_NO_PAYMENT_MODULE_SELECTED . '";' . "\n" .
               '    error = 1;' . "\n" .
               '  }' . "\n\n" .
			   '  if (payment_value == "free") {' . "\n" .
			   '      	gc_box.value = 1;' . "\n" .
			   '   }' . "\n\n" .
               '  if (error == 1 && submitter != 1) {' . "\n" . 
               '    alert(error_message);' . "\n" .
               '    return false;' . "\n" .
               '  } else {' . "\n" .
               '    return true;' . "\n" .
               '  }' . "\n" .
               '}' . "\n" .
               '//--></script>' . "\n";
        // End Gift Vouchers Secure

Basically just adding:

var gc_box = document.getElementById("GiftCertBox");

At the top, and at the bottom before the return:

if (payment_value == "free") {
   gc_box.value = 1;
}

And that properly changes the value of the hidden checkbox, and does what I need it to!

Unfortunately, osC stil won't let me checkout with an order total = $0 but that's another story.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

×