Page 1 of 1

[SOLVED] Pass product details to sage pay(basic)

Posted: Thu Apr 19, 2012 12:18 am
by crabwolf
Hi,

I'm currently working on a site where the client would like to have product details and customer details passed to the sage pay payment gateway. The existing sagepay module only sends order totals, rather than the the full order details the client requires.

Does anyone have any experience of this or any advice as I'm not 100% sure how to approach this!

Thanks in advance.

Re: Pass product details to sage pay

Posted: Fri Jun 29, 2012 12:20 am
by Kinetic
Hi Avvici,
thanks so much for getting back to me, I've tried so hard to try and understand this, I sort of understand the why just not the how.
Attached are the PDF's from Sage / SagePay for your reference. Some of these can only be downloaded once logged in.
I couldn't agree more about the blowing :D it's had me so confused.

I'm going to try some things out and will let you know.
I'm assuming you mean to edit the template file in catalogue/view/theme/(custom-theme)/template/payment/sagepay.tpl ?

Re: Pass product details to sage pay

Posted: Fri Jun 29, 2012 1:11 am
by Kinetic
still can't work out what to write in that file.
Obviously something in the format of:
<input type="hidden" name="parametername" value="<?php echo $billing_address; ?>" />
as you said but I'm lost.
I need to send the basket details and include the SKU in the description in square brackets [] as detailed in the sage 50 user guide on page 22. Also something about a colon delimited list. I'm thinking I need to call the info from my database somehow, I just don't know how, not even staring at my database gave me any insight.
I'm not experienced with PHP or much else as you can likely tell, but I'm very determined to learn.

If you can help me work out what I'm supposed to be typing I would be extremely grateful.

Thanks in advance, Kinetic

Re: Pass product details to sage pay

Posted: Fri Jun 29, 2012 5:43 am
by Avvici
That's "exactly" what you need. Finally some good api documentation. However I looked at the OC sagepay.php control file and it looks like they already have set you up with many parameters. The only one that is not there is the product information which can be easily sent with a string delimited by a ':'. just like the documentation sates. I can do that for you in a bit but I must leave for a while. All you would do is add it to this pile. I was incorrect in suggesting that you add it to the later. And an FYI, you are creating a string to send that ties all of the $data variables together that can be found here:

Code: Select all

$data = array();
		
		$data['VendorTxCode'] = $this->session->data['order_id'];
		$data['ReferrerID'] = 'E511AF91-E4A0-42DE-80B0-09C981A3FB61';
		$data['Amount'] = $this->currency->format($order_info['total'], $order_info['currency_code'], $order_info['currency_value'], false);
		$data['Currency'] = $order_info['currency_code'];
		$data['Description'] = sprintf($this->language->get('text_description'), date($this->language->get('date_format_short')), $this->session->data['order_id']);
		$data['SuccessURL'] = str_replace('&', '&', $this->url->link('payment/sagepay/success', 'order_id=' . $this->session->data['order_id']));
		$data['FailureURL'] = str_replace('&', '&', $this->url->link('checkout/checkout', '', 'SSL'));
		
		$data['CustomerName'] = html_entity_decode($order_info['payment_firstname'] . ' ' . $order_info['payment_lastname'], ENT_QUOTES, 'UTF-8');
		$data['SendEMail'] = '1';
		$data['CustomerEMail'] = $order_info['email'];
		$data['VendorEMail'] = $this->config->get('config_email');  
		
		$data['BillingFirstnames'] = $order_info['payment_firstname'];
        $data['BillingSurname'] = $order_info['payment_lastname'];
        $data['BillingAddress1'] = $order_info['payment_address_1'];
		
		if ($order_info['payment_address_2']) {
        	$data['BillingAddress2'] = $order_info['payment_address_2'];
		}
		
		$data['BillingCity'] = $order_info['payment_city'];
       	$data['BillingPostCode'] = $order_info['payment_postcode'];	
        $data['BillingCountry'] = $order_info['payment_iso_code_2'];
		
		if ($order_info['payment_iso_code_2'] == 'US') {
			$data['BillingState'] = $order_info['payment_zone_code'];
		}
		
		$data['BillingPhone'] = $order_info['telephone'];
		
		if ($this->cart->hasShipping()) {
			$data['DeliveryFirstnames'] = $order_info['shipping_firstname'];
        	$data['DeliverySurname'] = $order_info['shipping_lastname'];
        	$data['DeliveryAddress1'] = $order_info['shipping_address_1'];
		
			if ($order_info['shipping_address_2']) {
        		$data['DeliveryAddress2'] = $order_info['shipping_address_2'];
			}
		
        	$data['DeliveryCity'] = $order_info['shipping_city'];
        	$data['DeliveryPostCode'] = $order_info['shipping_postcode'];
        	$data['DeliveryCountry'] = $order_info['shipping_iso_code_2'];
		
			if ($order_info['shipping_iso_code_2'] == 'US') {
				$data['DeliveryState'] = $order_info['shipping_zone_code'];
			}
		
			$data['DeliveryPhone'] = $order_info['telephone'];
		} else {
			$data['DeliveryFirstnames'] = $order_info['payment_firstname'];
        	$data['DeliverySurname'] = $order_info['payment_lastname'];
        	$data['DeliveryAddress1'] = $order_info['payment_address_1'];
		
			if ($order_info['payment_address_2']) {
        		$data['DeliveryAddress2'] = $order_info['payment_address_2'];
			}
		
        	$data['DeliveryCity'] = $order_info['payment_city'];
        	$data['DeliveryPostCode'] = $order_info['payment_postcode'];
        	$data['DeliveryCountry'] = $order_info['payment_iso_code_2'];
		
			if ($order_info['payment_iso_code_2'] == 'US') {
				$data['DeliveryState'] = $order_info['payment_zone_code'];
			}
		
			$data['DeliveryPhone'] = $order_info['telephone'];			
		}
		
		$data['AllowGiftAid'] = '0';
		
		if (!$this->config->get('sagepay_transaction')) {
			$data['ApplyAVSCV2'] = '0';
		}
		
 		$data['Apply3DSecure'] = '0';
		
		$this->data['transaction'] = $this->config->get('sagepay_transaction');
		$this->data['vendor'] = $vendor;
		
		$crypt_data = array();
   
		foreach($data as $key => $value){
   			$crypt_data[] = $key . '=' . $value;
		}

		$this->data['crypt'] = base64_encode($this->simpleXor(utf8_decode(implode('&', $crypt_data)), $password));
The html form reflects it like this:

Code: Select all

 <input type="hidden" name="Crypt" value="<?php echo $crypt; ?>" />
I shall help when I return

Re: Pass product details to sage pay(basic)

Posted: Fri Jun 29, 2012 11:10 pm
by Kinetic
Thanks again for your help.
My server has been down all day so I've not been able to test anything, but I think I may be starting to get it (probably not ??? )

Am I to enter:

Code: Select all

$data['Basket'] = Number of lines of detail in the basket field:[sku]Item 1 Description:Quantity of item 1:Unit cost item 1 without tax:Tax applied to item 1:Cost of Item 1 including tax:Total cost of item 1 (Quantity x cost including tax):
somewhere into that file, catalogue/controller/payment/sagepay.php ?

Thanks for your help and I'll await your reply.

The only thing I need to send other than the basics is the SKU which needs to show at the start of the description in []'s. Another concern I have is that I'm using Qphoria's Options Boost module which allows for unique SKU's for each option. For products with options I need to make sure it sends the ob_sku (that's what it is in my database) and not the default sku.

If what I'm asking is too much please let me know.

Re: Pass product details to sage pay(basic)

Posted: Sat Jun 30, 2012 7:31 am
by Avvici
The only think you need to do is pass your products in a string separated by a colon like the documentation suggests. You would simply do this by getting your product data in a forloop and just forming a string every iteration. Just use the cart session already there. Sagepay requires you specify the total quantity of items first then specify each item with it's name, price, and quantity. Perhaps something like this:

Code: Select all

 $count_total_products = 0;
		  //get total product quantities
		   foreach ($this->cart->getProducts() as $product) {
			
			$count_total_products +=  $product['quantity'];
					
			}	
			$productsting = '';
			//sagepay requires colon delimiter. The last 3 fields are left empty with ':' If you want to use those fields then you will need to run another forloop to fetch the totals for combined product quantities. Below is just for name, quantity, and base price.
			foreach ($this->cart->getProducts() as $product) {
			
			$productsting .= $product['name'].':'.$product['quantity'].':'. $this->currency->format($product['price'], $order_info['currency_code'], false, false).':'.':'.':';
					
			}
			//this is the string you will send in the end.
			$main_string_to_send =	$count_total_products.':'.$productsting;
			//send here
			$data['Basket'] = $main_string_to_send;

Re: Pass product details to sage pay(basic)

Posted: Tue Jul 03, 2012 3:28 am
by Kinetic
Further to that, I think I worked out what was causing the error. I was trying to buy a product with options and one without, so once I removed the one with options the error goes away and the sagepay screen loads as usual.
However.... still with no basket contents, just the same as before.
The option thing may be due to me using Options Boost, maybe I should contact Qphoria regarding that.
Let me know what you think I should try next.

Thanks

Re: Pass product details to sage pay(basic)

Posted: Wed Jul 04, 2012 12:02 am
by Avvici
You aren't passing option data, just product data. If you want me to help you get the string properly formated I can but you have to skype me at Involution Media.

Re: Pass product details to sage pay(basic)

Posted: Wed Jul 04, 2012 12:26 am
by Kinetic
Avvici,
thanks for offering to help. I could be at this for days trying to work it out.
Give me 10-15 mins and I'll skype you.

Kenny Kinetic :joker:

Re: Pass product details to sage pay(basic)

Posted: Wed Jul 04, 2012 4:52 am
by Avvici
Solved: (BELOW CODE IS ONLY FOR 3 OF THE 6 POSSIBLE STRING VARIABLE FIELDS ACCORDING TO DOCUMENTATION.)
If you want item tax, line total, and item total then you will have to wait for my vQmod. I will upload the vQmod a little later. This just collects the Quantity, Name, and Item Price

Code: Select all

$count_total_products = 0;
        //get total rows to be sent in string
         foreach ($this->cart->getProducts() as $product) {
         
         $count_total_products++;
               
         }   
         $productstring = '';
         //sagepay requires colon delimiter. The last 3 fields are left empty with ':' If you want to use those fields then you will need to run another forloop to fetch the totals for combined product quantities. Below is just for name, quantity, and base price.
         foreach ($this->cart->getProducts() as $product) {
         //gather SKU for each product.  ugh.....
		 $sku = $this->model_checkout_order->getSku($product['product_id']);
         $productstring .= '['.$sku.']'.$product['name'].':'.$product['quantity'].':'. $this->currency->format($product['price'], $order_info['currency_code'], false, false).':'.'---'.':'.'---'.':'.'---'.':';
               
         }
         //this is the string you will send in the end.
         $main_string_to_send =   $count_total_products.':'.substr_replace($productstring ,"",-1);
         //send here
         $data['Basket'] = $main_string_to_send;
And the function to get the SKU: place in model/checkout/order.php

Code: Select all

public function getSku($product_id) {
		$query = $this->db->query("SELECT sku AS code FROM " . DB_PREFIX . "product WHERE product_id = '" . (int)$product_id . "'");

		return $query->row['code'];
	}	
That code tags the SKU to the beginning of the product name. If you don't want the SKU then use this version:

Code: Select all

$count_total_products = 0;
        //get total rows to be sent in string
         foreach ($this->cart->getProducts() as $product) {
         
         $count_total_products++;
               
         }   
         $productstring = '';
         //sagepay requires colon delimiter. The last 3 fields are left empty with ':' If you want to use those fields then you will need to run another forloop to fetch the totals for combined product quantities. Below is just for name, quantity, and base price.
         foreach ($this->cart->getProducts() as $product) {
         //gather SKU for each product.  ugh.....
		// $sku = $this->model_checkout_order->getSku($product['product_id']);
         $productstring .= $product['name'].':'.$product['quantity'].':'. $this->currency->format($product['price'], $order_info['currency_code'], false, false).':'.'---'.':'.'---'.':'.'---'.':';
               
         }
         //this is the string you will send in the end.
         $main_string_to_send =   $count_total_products.':'.substr_replace($productstring ,"",-1);
         //send here
         $data['Basket'] = $main_string_to_send;

Re: [SOLVED] Pass product details to sage pay(basic)

Posted: Wed Jul 04, 2012 1:38 pm
by Avvici
For those using OPTIONS BOOST that want to pass the option SKU, this checks for existing option SKU and if none, uses the regular SKU:

Code: Select all

$count_total_products = 0;
        //get total rows to be sent in string
         foreach ($this->cart->getProducts() as $product) {
         
         $count_total_products++;
               
         }   
         $productstring = '';
		
         //sagepay requires colon delimiter. The last 3 fields are left empty with ':' If you want to use those fields then you will need to run another forloop to fetch the totals for combined product quantities. Below is just for name, quantity, and base price.
		
         foreach ($this->cart->getProducts() as $product) {
         //gather Option SKU for each product.  If no option sku, use normal skuugh.....		 
			
					$sku = $this->model_checkout_order->getOptionSku($product['product_id']);
					if($sku){
					foreach ($sku as $value){
			       $skucode = $value['ob_sku'];
					}
					}else{
						$skucode = $this->model_checkout_order->getSku($product['product_id']);;
					}
					
					$baseprice = $this->currency->format($product['price'], $order_info['currency_code'], false, false);
					
					
				
				$line_total = $this->currency->format($product['price']  * $product['quantity'], $order_info['currency_code'], $order_info['currency_value']);
				
				
			
		 	//set up Basket String
         $productstring .= '['.$skucode.']'.$product['name'].':'.$product['quantity'].':'.$baseprice.':'.'---'.':'.$line_total.':'.$line_total.':';
               
         }
         //this is the string you will send in the end.
         $main_string_to_send =   $count_total_products.':'.substr_replace($productstring ,"",-1);

         //send here
         $data['Basket'] = $main_string_to_send;
And your model functions:

Code: Select all

public function getSku($product_id) {
		$query = $this->db->query("SELECT sku AS code FROM " . DB_PREFIX . "product WHERE product_id = '" . (int)$product_id . "'");

		return $query->row['code'];
	}
	public function getOptionSku($product_value_id) {
		$query = $this->db->query("SELECT ob_sku FROM " . DB_PREFIX . "product_option_value WHERE product_id = '" . (int)$product_value_id."'");

		return $query->rows;
	}		

Re: [SOLVED] Pass product details to sage pay(basic)

Posted: Tue Feb 26, 2013 6:48 pm
by Caradiaz
Thank you for posting this solution. Quick question - please excuse my ignorance... - where exactly does the code need to be placed in the tlp file? Just before </form> or else?

Many thanks for your help.

Re: [SOLVED] Pass product details to sage pay(basic)

Posted: Wed Feb 27, 2013 6:46 pm
by Caradiaz
I'd be really grateful if someone could please advice about the placement of the above code for get the shopping cart on to SagePay confirmation. I'm not developer and would be grateful for assistance with this.

Many thanks.

Re: [SOLVED] Pass product details to sage pay(basic)

Posted: Tue Oct 29, 2013 9:54 am
by toptenweb
Was there a vqmod version of these changes ever put together? Or even just some details of the model/view/controller files to update?

Re: [SOLVED] Pass product details to sage pay(basic)

Posted: Tue Oct 29, 2013 10:10 am
by toptenweb