Page 1 of 8

[vQmod] Apply coupon during checkout (1.5.x and 2.x)

Posted: Wed Aug 10, 2011 5:22 am
by JNeuhoff
This little vQmod file provides the coupon text box during the checkout process, in the Step 5: Payment Method. It is instantly applied to the order, and listed as one of the totals in the next checkout step. For Opencart 1.5.1.1 only.

Update by Qphoria: I've added a version that works with ALL VERSIONS of OpenCart 1.5.x and 2.x now and attached it here.

Re: [vQmod] Apply coupon during checkout

Posted: Wed Aug 10, 2011 5:32 am
by uksitebuilder
Nice one and much needed.

Can this be expanded for Gift Vouchers and Rewards Points ?

Re: [vQmod] Apply coupon during checkout

Posted: Wed Aug 10, 2011 6:38 am
by Maansy
Thanks. It's indeed needed.
Have you successfully used it with paypal.
In my end paypal didnt seem to minus the coupon amount from the total amount.
Just wondering if you guys are facing the same thing.

Re: [vQmod] Apply coupon during checkout

Posted: Wed Aug 10, 2011 4:08 pm
by JNeuhoff
Maansy wrote:Thanks. It's indeed needed.
Have you successfully used it with paypal.
In my end paypal didnt seem to minus the coupon amount from the total amount.
Just wondering if you guys are facing the same thing.
Did the coupon show up on the Step 6: Confirm ?
If so, then it might be an issue with Paypal.

I just tested it with Paypal Standard, and it works fine. The Paypal module puts all of the shipping, taxes, and discounts into one line.

Re: [vQmod] Apply coupon during checkout

Posted: Wed Aug 10, 2011 7:17 pm
by Maansy
JNeuhoff wrote:
Maansy wrote:Thanks. It's indeed needed.
Have you successfully used it with paypal.
In my end paypal didnt seem to minus the coupon amount from the total amount.
Just wondering if you guys are facing the same thing.
Did the coupon show up on the Step 6: Confirm ?
If so, then it might be an issue with Paypal.

I just tested it with Paypal Standard, and it works fine. The Paypal module puts all of the shipping, taxes, and discounts into one line.
it shows in step 6, but when it took me to paypal page there was no coupon value at all.

Re: [vQmod] Apply coupon during checkout

Posted: Wed Aug 10, 2011 8:34 pm
by JNeuhoff
it shows in step 6, but when it took me to paypal page there was no coupon value at all.
I am unable to reproduce your error. Any URL of your website where I can see this error?

Re: [vQmod] Apply coupon during checkout

Posted: Wed Aug 10, 2011 9:47 pm
by Qphoria
This is a known paypal issue with discounts in 1.5.x

Re: [vQmod] Apply coupon during checkout

Posted: Wed Aug 10, 2011 10:01 pm
by uksitebuilder
Strange, I just tried it on my 1.5.0.5 and the correct amount minus the discount was sent to paypal

Will check if i somehow fixed it and forgot about it (has been known)

Re: [vQmod] Apply coupon during checkout

Posted: Wed Aug 10, 2011 10:18 pm
by uksitebuilder
OK, the only thing I can think of it being is in catalog/controll/payment/pp_standard.php

lines 80-88 of original 1.5.0.5 download:

Code: Select all

									
			$this->data['products'][] = array(
				'name'     => $this->language->get('text_total'),
				'model'    => '',
				'price'    => $this->currency->format($order_info['total'] - $this->cart->getSubTotal(), $currency, false, false),
				'quantity' => 1,
				'option'   => array(),
				'weight'   => 0
			);			
In my file I have:

Code: Select all

			
			$this->data['discount_amount_cart'] = 0;
			
			$total = $this->currency->format($order_info['total'] - $this->cart->getSubTotal(), $currency, false, false);

			if ($total > 0) {
				$this->data['products'][] = array(
					'name'     => $this->language->get('text_total'),
					'model'    => '',
					'price'    => $total,
					'quantity' => 1,
					'option'   => array(),
					'weight'   => 0
				);	
			} else {
				$this->data['discount_amount_cart'] -= $this->currency->format($total, $currency, FALSE, FALSE);
			}
I can only assume I fixed this from the SVN

Re: [vQmod] Apply coupon during checkout

Posted: Thu Aug 11, 2011 12:16 am
by Maansy
uksitebuilder wrote:OK, the only thing I can think of it being is in catalog/controll/payment/pp_standard.php

lines 80-88 of original 1.5.0.5 download:

Code: Select all

									
			$this->data['products'][] = array(
				'name'     => $this->language->get('text_total'),
				'model'    => '',
				'price'    => $this->currency->format($order_info['total'] - $this->cart->getSubTotal(), $currency, false, false),
				'quantity' => 1,
				'option'   => array(),
				'weight'   => 0
			);			
In my file I have:

Code: Select all

			
			$this->data['discount_amount_cart'] = 0;
			
			$total = $this->currency->format($order_info['total'] - $this->cart->getSubTotal(), $currency, false, false);

			if ($total > 0) {
				$this->data['products'][] = array(
					'name'     => $this->language->get('text_total'),
					'model'    => '',
					'price'    => $total,
					'quantity' => 1,
					'option'   => array(),
					'weight'   => 0
				);	
			} else {
				$this->data['discount_amount_cart'] -= $this->currency->format($total, $currency, FALSE, FALSE);
			}
I can only assume I fixed this from the SVN

this is the one i am using:

Code: Select all

<?php
class ControllerPaymentPPStandard extends Controller {
	protected function index() {
		$this->language->load('payment/pp_standard');
		
		$this->data['text_testmode'] = $this->language->get('text_testmode');		
    	
		$this->data['button_confirm'] = $this->language->get('button_confirm');

		$this->data['testmode'] = $this->config->get('pp_standard_test');
		
		if (!$this->config->get('pp_standard_test')) {
    		$this->data['action'] = 'https://www.paypal.com/cgi-bin/webscr';
  		} else {
			$this->data['action'] = 'https://www.sandbox.paypal.com/cgi-bin/webscr';
		}

		$this->load->model('checkout/order');

		$order_info = $this->model_checkout_order->getOrder($this->session->data['order_id']);

		if ($order_info) {
			$currencies = array(
				'AUD',
				'CAD',
				'EUR',
				'GBP',
				'JPY',
				'USD',
				'NZD',
				'CHF',
				'HKD',
				'SGD',
				'SEK',
				'DKK',
				'PLN',
				'NOK',
				'HUF',
				'CZK',
				'ILS',
				'MXN',
				'MYR',
				'BRL',
				'PHP',
				'TWD',
				'THB',
				'TRY'
			);
			
			if (in_array($order_info['currency_code'], $currencies)) {
				$currency = $order_info['currency_code'];
			} else {
				$currency = 'USD';
			}		
		
			$this->data['business'] = $this->config->get('pp_standard_email');
			$this->data['item_name'] = html_entity_decode($this->config->get('config_name'), ENT_QUOTES, 'UTF-8');				
			
			$this->data['products'] = array();
			
			foreach ($this->cart->getProducts() as $product) {
				$option_data = array();
	
				foreach ($product['option'] as $option) {
					$option_data[] = array(
						'name'  => $option['name'],
						'value' => $option['option_value']
					);
				}
				
				$this->data['products'][] = array(
					'name'     => $product['name'],
					'model'    => $product['model'],
					'price'    => $this->currency->format($product['price'], $currency, false, false),
					'quantity' => $product['quantity'],
					'option'   => $option_data,
					'weight'   => $product['weight']
				);
			}	
			
			$this->data['discount_amount_cart'] = 0;
			
			$total = $this->currency->format($order_info['total'] - $this->cart->getSubTotal(), $currency, false, false);

			if ($total > 0) {
				$this->data['products'][] = array(
					'name'     => $this->language->get('text_total'),
					'model'    => '',
					'price'    => $total,
					'quantity' => 1,
					'option'   => array(),
					'weight'   => 0
				);	
			} else {
				$this->data['discount_amount_cart'] -= $this->currency->format($total, $currency, FALSE, FALSE);
			}
			
			$this->data['currency_code'] = $currency;
			$this->data['first_name'] = html_entity_decode($order_info['payment_firstname'], ENT_QUOTES, 'UTF-8');	
			$this->data['last_name'] = html_entity_decode($order_info['payment_lastname'], ENT_QUOTES, 'UTF-8');	
			$this->data['address1'] = html_entity_decode($order_info['payment_address_1'], ENT_QUOTES, 'UTF-8');	
			$this->data['address2'] = html_entity_decode($order_info['payment_address_2'], ENT_QUOTES, 'UTF-8');	
			$this->data['city'] = html_entity_decode($order_info['payment_city'], ENT_QUOTES, 'UTF-8');	
			$this->data['zip'] = html_entity_decode($order_info['payment_postcode'], ENT_QUOTES, 'UTF-8');	
			$this->data['country'] = $order_info['payment_iso_code_2'];
			$this->data['notify_url'] = $this->url->link('payment/pp_standard/callback');
			$this->data['email'] = $order_info['email'];
			$this->data['invoice'] = $this->session->data['order_id'] . ' - ' . html_entity_decode($order_info['payment_firstname'], ENT_QUOTES, 'UTF-8') . ' ' . html_entity_decode($order_info['payment_lastname'], ENT_QUOTES, 'UTF-8');
			$this->data['lc'] = $this->session->data['language'];
			$this->data['return'] = $this->url->link('checkout/success');
			$this->data['notify_url'] = $this->url->link('payment/pp_standard/callback');
			$this->data['cancel_return'] = $this->url->link('checkout/checkout', '', 'SSL');
			
			if (!$this->config->get('pp_standard_transaction')) {
				$this->data['paymentaction'] = 'authorization';
			} else {
				$this->data['paymentaction'] = 'sale';
			}
			
			$this->load->library('encryption');
	
			$encryption = new Encryption($this->config->get('config_encryption'));
	
			$this->data['custom'] = $encryption->encrypt($this->session->data['order_id']);
		
			if (file_exists(DIR_TEMPLATE . $this->config->get('config_template') . '/template/payment/pp_standard.tpl')) {
				$this->template = $this->config->get('config_template') . '/template/payment/pp_standard.tpl';
			} else {
				$this->template = 'default/template/payment/pp_standard.tpl';
			}
	
			$this->render();
		}
	}
	
	public function callback() {
		$this->load->library('encryption');
	
		$encryption = new Encryption($this->config->get('config_encryption'));
		
		if (isset($this->request->post['custom'])) {
			$order_id = $encryption->decrypt($this->request->post['custom']);
		} else {
			$order_id = 0;
		}		
		
		$this->load->model('checkout/order');
				
		$order_info = $this->model_checkout_order->getOrder($order_id);
		
		if ($order_info) {
			$request = 'cmd=_notify-validate';
		
			foreach ($this->request->post as $key => $value) {
				$request .= '&' . $key . '=' . urlencode(html_entity_decode($value, ENT_QUOTES, 'UTF-8'));
			}
			
			if (!$this->config->get('pp_standard_test')) {
				$curl = curl_init('https://www.paypal.com/cgi-bin/webscr');
			} else {
				$curl = curl_init('https://www.sandbox.paypal.com/cgi-bin/webscr');
			}

			curl_setopt($curl, CURLOPT_POST, true);
			curl_setopt($curl, CURLOPT_POSTFIELDS, $request);
			curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
			curl_setopt($curl, CURLOPT_HEADER, false);
			curl_setopt($curl, CURLOPT_TIMEOUT, 30);
			curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false);
					
			$response = curl_exec($curl);
			
			if (!$response) {
				$this->log->write('PP_STANDARD :: CURL failed ' . curl_error($curl) . '(' . curl_errno($curl) . ')');
			}
					
			if ($this->config->get('pp_standard_debug')) {
				$this->log->write('PP_STANDARD :: IPN REQUEST: ' . $request);
				$this->log->write('PP_STANDARD :: IPN RESPONSE: ' . $response);
			}
						
			if ((strcmp($response, 'VERIFIED') == 0 || strcmp($response, 'UNVERIFIED') == 0) && isset($this->request->post['payment_status'])) {
				$order_status_id = $this->config->get('config_order_status_id');
				
				switch($this->request->post['payment_status']) {
					case 'Canceled_Reversal':
						$order_status_id = $this->config->get('pp_standard_canceled_reversal_status_id');
						break;
					case 'Completed':
						if ((float)$this->request->post['mc_gross'] == $this->currency->format($order_info['total'], $order_info['currency_code'], $order_info['currency_value'], false)) {
							$order_status_id = $this->config->get('pp_standard_completed_status_id');
						}
						break;
					case 'Denied':
						$order_status_id = $this->config->get('pp_standard_denied_status_id');
						break;
					case 'Expired':
						$order_status_id = $this->config->get('pp_standard_expired_status_id');
						break;
					case 'Failed':
						$order_status_id = $this->config->get('pp_standard_failed_status_id');
						break;
					case 'Pending':
						$order_status_id = $this->config->get('pp_standard_pending_status_id');
						break;
					case 'Processed':
						$order_status_id = $this->config->get('pp_standard_processed_status_id');
						break;
					case 'Refunded':
						$order_status_id = $this->config->get('pp_standard_refunded_status_id');
						break;
					case 'Reversed':
						$order_status_id = $this->config->get('pp_standard_reversed_status_id');
						break;	 
					case 'Voided':
						$order_status_id = $this->config->get('pp_standard_voided_status_id');
						break;								
				}
				
				if (!$order_info['order_status_id']) {
					$this->model_checkout_order->confirm($order_id, $order_status_id);
				} else {
					$this->model_checkout_order->update($order_id, $order_status_id);
				}
			} else {
				$this->model_checkout_order->confirm($order_id, $this->config->get('config_order_status_id'));
			}
			
			curl_close($curl);
		}	
	}
}
?>

Re: [vQmod] Apply coupon during checkout

Posted: Thu Aug 11, 2011 12:17 am
by Maansy
Qphoria wrote:This is a known paypal issue with discounts in 1.5.x
has this been fixed in the svn at least?

Re: [vQmod] Apply coupon during checkout

Posted: Thu Aug 11, 2011 12:19 am
by uksitebuilder
Looks like we both have used SVN to fix it then.

Not tested Gift Vouchers yet though.

Re: [vQmod] Apply coupon during checkout

Posted: Thu Aug 11, 2011 12:26 am
by Maansy
uksitebuilder wrote:Looks like we both have used SVN to fix it then.

Not tested Gift Vouchers yet though.
its hasn't been fixed in my end. i posted the pp_stander.php that i am using to see if its identical to yours.

Re: [vQmod] Apply coupon during checkout

Posted: Thu Aug 11, 2011 1:09 am
by uksitebuilder
do you have these lines in catalog/view/theme/default/template/payment/pp_standard.tpl

around line: 23

Code: Select all

  <?php if ($discount_amount_cart) { ?>
  <input type="hidden" name="discount_amount_cart" value="<?php echo $discount_amount_cart; ?>" />
  <?php } ?>

Re: [vQmod] Apply coupon during checkout

Posted: Thu Aug 11, 2011 1:39 am
by Maansy
uksitebuilder wrote:do you have these lines in catalog/view/theme/default/template/payment/pp_standard.tpl

around line: 23

Code: Select all

  <?php if ($discount_amount_cart) { ?>
  <input type="hidden" name="discount_amount_cart" value="<?php echo $discount_amount_cart; ?>" />
  <?php } ?>
yes i do

Code: Select all

<?php if ($testmode) { ?>
<div class="warning"><?php echo $text_testmode; ?></div>
<?php } ?>
<form action="<?php echo $action; ?>" method="post" id="payment">
  <input type="hidden" name="cmd" value="_cart" />
  <input type="hidden" name="upload" value="1" />
  <input type="hidden" name="business" value="<?php echo $business; ?>" />
  <?php $i = 1; ?>
  <?php foreach ($products as $product) { ?>
  <input type="hidden" name="item_name_<?php echo $i; ?>" value="<?php echo $product['name']; ?>" />
  <input type="hidden" name="item_number_<?php echo $i; ?>" value="<?php echo $product['model']; ?>" />
  <input type="hidden" name="amount_<?php echo $i; ?>" value="<?php echo $product['price']; ?>" />
  <input type="hidden" name="quantity_<?php echo $i; ?>" value="<?php echo $product['quantity']; ?>" />
  <input type="hidden" name="weight_<?php echo $i; ?>" value="<?php echo $product['weight']; ?>" />
  <?php $j = 0; ?>
  <?php foreach ($product['option'] as $option) { ?>
  <input type="hidden" name="on<?php echo $j; ?>_<?php echo $i; ?>" value="<?php echo $option['name']; ?>" />
  <input type="hidden" name="os<?php echo $j; ?>_<?php echo $i; ?>" value="<?php echo $option['value']; ?>" />
  <?php $j++; ?>
  <?php } ?>
  <?php $i++; ?>
  <?php } ?>
  <?php if ($discount_amount_cart) { ?>
  <input type="hidden" name="discount_amount_cart" value="<?php echo $discount_amount_cart; ?>" />
  <?php } ?>
  <input type="hidden" name="currency_code" value="<?php echo $currency_code; ?>" />
  <input type="hidden" name="first_name" value="<?php echo $first_name; ?>" />
  <input type="hidden" name="last_name" value="<?php echo $last_name; ?>" />
  <input type="hidden" name="address1" value="<?php echo $address1; ?>" />
  <input type="hidden" name="address2" value="<?php echo $address2; ?>" />
  <input type="hidden" name="city" value="<?php echo $city; ?>" />
  <input type="hidden" name="zip" value="<?php echo $zip; ?>" />
  <input type="hidden" name="country" value="<?php echo $country; ?>" />
  <input type="hidden" name="address_override" value="0" />
  <input type="hidden" name="email" value="<?php echo $email; ?>" />
  <input type="hidden" name="invoice" value="<?php echo $invoice; ?>" />
  <input type="hidden" name="lc" value="<?php echo $lc; ?>" />
  <input type="hidden" name="rm" value="2" />
  <input type="hidden" name="no_note" value="1" />
  <input type="hidden" name="charset" value="utf-8" />
  <input type="hidden" name="return" value="<?php echo $return; ?>" />
  <input type="hidden" name="notify_url" value="<?php echo $notify_url; ?>" />
  <input type="hidden" name="cancel_return" value="<?php echo $cancel_return; ?>" />
  <input type="hidden" name="paymentaction" value="<?php echo $paymentaction; ?>" />
  <input type="hidden" name="custom" value="<?php echo $custom; ?>" />
</form>
<div class="buttons">
  <div class="right"><a id="button-confirm" class="button" onclick="$('#payment').submit();"><span><?php echo $button_confirm; ?></span></a></div>
</div>

Re: [vQmod] Apply coupon during checkout

Posted: Thu Aug 11, 2011 2:34 am
by uksitebuilder
Do you have this:

Code: Select all

		$this->db->query("INSERT INTO `" . DB_PREFIX . "coupon_history` SET coupon_id = '" . (int)$coupon_id . "', order_id = '" . (int)$order_id . "', customer_id = '" . (int)$customer_id . "', amount = '" . (float)$amount . "', date_added = NOW()");
Near the bottom of: catalog/model/checkout/coupon.php

Just doing a file compare on 1.5.0.5 against my local copy which I svn'd the bugfixes and picking out any differences that may be related

Re: [vQmod] Apply coupon during checkout

Posted: Thu Aug 11, 2011 2:50 am
by Maansy
uksitebuilder wrote:Do you have this:

Code: Select all

		$this->db->query("INSERT INTO `" . DB_PREFIX . "coupon_history` SET coupon_id = '" . (int)$coupon_id . "', order_id = '" . (int)$order_id . "', customer_id = '" . (int)$customer_id . "', amount = '" . (float)$amount . "', date_added = NOW()");
Near the bottom of: catalog/model/checkout/coupon.php

Just doing a file compare on 1.5.0.5 against my local copy which I svn'd the bugfixes and picking out any differences that may be related
yes i do
this is the file i am using
catalog/model/checkout/coupon.php

Code: Select all

<?php
class ModelCheckoutCoupon extends Model {
	public function getCoupon($code) {
		$status = true;
		
		$coupon_query = $this->db->query("SELECT * FROM " . DB_PREFIX . "coupon WHERE code = '" . $this->db->escape($code) . "' AND ((date_start = '0000-00-00' OR date_start < NOW()) AND (date_end = '0000-00-00' OR date_end > NOW())) AND status = '1'");
			
		if ($coupon_query->num_rows) {
			if ($coupon_query->row['total'] >= $this->cart->getSubTotal()) {
				$status = false;
			}
		
			$coupon_history_query = $this->db->query("SELECT COUNT(*) AS total FROM `" . DB_PREFIX . "coupon_history` ch WHERE ch.coupon_id = '" . (int)$coupon_query->row['coupon_id'] . "'");

			if ($coupon_query->row['uses_total'] > 0 && ($coupon_history_query->row['total'] >= $coupon_query->row['uses_total'])) {
				$status = false;
			}
			
			if ($coupon_query->row['logged'] && !$this->customer->getId()) {
				$status = false;
			}
			
			if ($this->customer->getId()) {
				$coupon_history_query = $this->db->query("SELECT COUNT(*) AS total FROM `" . DB_PREFIX . "coupon_history` ch WHERE ch.coupon_id = '" . (int)$coupon_query->row['coupon_id'] . "' AND ch.customer_id = '" . (int)$this->customer->getId() . "'");
				
				if ($coupon_query->row['uses_customer'] > 0 && ($coupon_history_query->row['total'] >= $coupon_query->row['uses_customer'])) {
					$status = false;
				}
			}
				
			$coupon_product_data = array();
				
			$coupon_product_query = $this->db->query("SELECT * FROM " . DB_PREFIX . "coupon_product WHERE coupon_id = '" . (int)$coupon_query->row['coupon_id'] . "'");

			foreach ($coupon_product_query->rows as $result) {
				$coupon_product_data[] = $result['product_id'];
			}
				
			if ($coupon_product_data) {
				$coupon_product = false;
					
				foreach ($this->cart->getProducts() as $product) {
					if (in_array($product['product_id'], $coupon_product_data)) {
						$coupon_product = true;
							
						break;
					}
				}
					
				if (!$coupon_product) {
					$status = false;
				}
			}
		} else {
			$status = false;
		}
		
		if ($status) {
			return array(
				'coupon_id'     => $coupon_query->row['coupon_id'],
				'code'          => $coupon_query->row['code'],
				'name'          => $coupon_query->row['name'],
				'type'          => $coupon_query->row['type'],
				'discount'      => $coupon_query->row['discount'],
				'shipping'      => $coupon_query->row['shipping'],
				'total'         => $coupon_query->row['total'],
				'product'       => $coupon_product_data,
				'date_start'    => $coupon_query->row['date_start'],
				'date_end'      => $coupon_query->row['date_end'],
				'uses_total'    => $coupon_query->row['uses_total'],
				'uses_customer' => $coupon_query->row['uses_customer'],
				'status'        => $coupon_query->row['status'],
				'date_added'    => $coupon_query->row['date_added']
			);
		}
	}
	
	public function redeem($coupon_id, $order_id, $customer_id, $amount) {
		$this->db->query("INSERT INTO `" . DB_PREFIX . "coupon_history` SET coupon_id = '" . (int)$coupon_id . "', order_id = '" . (int)$order_id . "', customer_id = '" . (int)$customer_id . "', amount = '" . (float)$amount . "', date_added = NOW()");
	}
}
?>

Re: [vQmod] Apply coupon during checkout

Posted: Thu Aug 11, 2011 3:00 am
by uksitebuilder
OK, I can't find any other files differences that relate now.

When you get to checkout confirm, before it fires you off to PayPal, that page will have all the hidden paypal form fields in it.

can you view source and find the hidden input field item_2 and amount_2

On mine,
item_2 = "Shipping, Handling, Discounts & Taxes"
amount_2 = (shipping + taxes - discounts)

Re: [vQmod] Apply coupon during checkout

Posted: Thu Aug 11, 2011 3:17 am
by uksitebuilder
Just in case it helps

here are my 3 files (attached)

feel free to drop on top of yours to see if it works. it has helped another user on a different thread with same problem.

Re: [vQmod] Apply coupon during checkout

Posted: Thu Aug 11, 2011 3:22 am
by Maansy
uksitebuilder wrote:OK, I can't find any other files differences that relate now.

When you get to checkout confirm, before it fires you off to PayPal, that page will have all the hidden paypal form fields in it.

can you view source and find the hidden input field item_2 and amount_2

On mine,
item_2 = "Shipping, Handling, Discounts & Taxes"
amount_2 = (shipping + taxes - discounts)
at step 6 (just before paypal page)
i view the page source with FF but i cant seem to find item_2 and amount_2