Jump to content
  • Checkout
  • Login
  • Get in touch

osCommerce

The e-commerce.

Enable PayPal Express Checkout, quick question


pedgette

Recommended Posts

I have uploaded all of the new files to the correct directories and have done the manual file edits using this guide, http://svn.oscommerce.com/fisheye/changelo...ommerce?cs=1699

 

I went into admin>modules>payment and enabled the module and inserted by sandbox info. I then went to my site and test it, the paypal image shows up fine but when I click on it I'm redirected to login.php. I copied the URL that the button links to and it is: mysite.com/ext/modules/payment/paypal/express.php

 

I'm not sure where I went wrong, any insight would be great. Thanks.

Link to comment
Share on other sites

Ok, I guess I thought this worked a little differently and no longer required a user to have an account to make a purchase. But after I was redirected to the login page I used one of my testing login names and finished a payment through the sandbox server, is this exactly how it's suppose to work? Thanks for your time.

Link to comment
Share on other sites

Hi Paul..

 

Yes, that is correct behaviour of the module. It is not the preferred manner for the Express Checkout payment method however many more codebase changes would be required to properly support a purchase without a customer account.

 

The codebase changes going in 2.2 RC1/RC2/Final are minimal changes to ease the upgrade procedure for existing store owners. Although we are focusing the bigger changes for the 3.0 release, a 2.3 release will also be made where such features will be available on based on the 2.2 core. (The 3.0 release has a new core that is not compatible to 2.2)

:heart:, osCommerce

Link to comment
Share on other sites

Thanks very much for bringing the paypal express checkout to life!

 

I have a question: If I run the order with the new paypal express checkout there is no billing adress

afterwards and the following error-code inside the checkout_confirmation.php:

 

htmlspecialchars() expects parameter 1 to be string, array given....

 

Does anybody have an idea why that happens? It´s just if I use the new paypal payment.

 

Kind regards from Germany

 

Guido

Link to comment
Share on other sites

  • 2 weeks later...

Hi

 

I installed this contribution, and am receiving this error on shopping_cart.php

 

Fatal error: Call to undefined method: payment->checkout_initialization_method()

 

I have checked my code changes, and am missing something.

 

Appreciate your help with identifying it.

 

thanks

 

Sam

Link to comment
Share on other sites

Please ignore my previous message _ i found the error I had made while incorporating the changes in /includes/classes/payment.php

thanks

 

Hi Sameer,

I have the same problem but can't trace what I have done wrong.... what was the error you made and sorted? Any pointers useful.

Link to comment
Share on other sites

  • 2 weeks later...

This function needs to be added to

 

/includes/classes/payment.php

 

 
function checkout_initialization_method() {
$initialize_array = array();



if (is_array($this->modules)) {

reset($this->modules);

while (list(, $value) = each($this->modules)) {

$class = substr($value, 0, strrpos($value, '.'));

if ($GLOBALS[$class]->enabled && method_exists($GLOBALS[$class], 'checkout_initialization_method')) {

$initialize_array[] = $GLOBALS[$class]->checkout_initialization_method();

}

}

}



return $initialize_array;

}

Link to comment
Share on other sites

  • 3 weeks later...

I have installed the contribution by making all the code changes to add PayPal express but get the error below in admin.

 

Fatal error: Cannot redeclare class paypal_express in /modules/payment/paypal_express.php on line 13

 

I have double checked that all the code is correct. The only file I think might be incorrect is the classes/order.php??

 

Can anyone tell me where I have gone wrong?

 

 

      $customer_address_query = tep_db_query("select c.customers_firstname, c.customers_lastname, c.customers_telephone, c.customers_email_address, ab.entry_company, ab.entry_street_address, ab.entry_suburb, ab.entry_postcode, ab.entry_city, ab.entry_zone_id, z.zone_name, co.countries_id, co.countries_name, co.countries_iso_code_2, co.countries_iso_code_3, co.address_format_id, ab.entry_state from " . TABLE_CUSTOMERS . " c, " . TABLE_ADDRESS_BOOK . " ab left join " . TABLE_ZONES . " z on (ab.entry_zone_id = z.zone_id) left join " . TABLE_COUNTRIES . " co on (ab.entry_country_id = co.countries_id) where c.customers_id = '" . (int)$customer_id . "' and ab.customers_id = '" . (int)$customer_id . "' and c.customers_default_address_id = ab.address_book_id");

     $customer_address = tep_db_fetch_array($customer_address_query);

if (is_array($sendto) && !empty($sendto)) { 
        $shipping_address = array('entry_firstname' => $sendto['firstname'], 
                                  'entry_lastname' => $sendto['lastname'], 
                                  'entry_company' => $sendto['company'], 
                                  'entry_street_address' => $sendto['street_address'], 
                                  'entry_suburb' => $sendto['suburb'], 
                                  'entry_postcode' => $sendto['postcode'], 
                                  'entry_city' => $sendto['city'], 
                                  'entry_zone_id' => $sendto['zone_id'], 
                                  'zone_name' => $sendto['zone_name'], 
                                  'entry_country_id' => $sendto['country_id'], 
                                  'countries_id' => $sendto['country_id'], 
                                  'countries_name' => $sendto['country_name'], 
                                  'countries_iso_code_2' => $sendto['country_iso_code_2'], 
                                  'countries_iso_code_3' => $sendto['country_iso_code_3'], 
                                  'address_format_id' => $sendto['address_format_id'], 
                                  'entry_state' => $sendto['zone_name']); 
      } else { 


     $shipping_address_query = tep_db_query("select ab.entry_firstname, ab.entry_lastname, ab.entry_company, ab.entry_street_address, ab.entry_suburb, ab.entry_postcode, ab.entry_city, ab.entry_zone_id, z.zone_name, ab.entry_country_id, c.countries_id, c.countries_name, c.countries_iso_code_2, c.countries_iso_code_3, c.address_format_id, ab.entry_state from " . TABLE_ADDRESS_BOOK . " ab left join " . TABLE_ZONES . " z on (ab.entry_zone_id = z.zone_id) left join " . TABLE_COUNTRIES . " c on (ab.entry_country_id = c.countries_id) where ab.customers_id = '" . (int)$customer_id . "' and ab.address_book_id = '" . (int)$sendto . "'");

     $shipping_address = tep_db_fetch_array($shipping_address_query);

     }


if (is_array($billto) && !empty($billto)) { 
        $billing_address = array('entry_firstname' => $billto['firstname'], 
                                 'entry_lastname' => $billto['lastname'], 
                                 'entry_company' => $billto['company'], 
                                 'entry_street_address' => $billto['street_address'], 
                                 'entry_suburb' => $billto['suburb'], 
                                 'entry_postcode' => $billto['postcode'], 
                                 'entry_city' => $billto['city'], 
                                 'entry_zone_id' => $billto['zone_id'], 
                                 'zone_name' => $billto['zone_name'], 
                                 'entry_country_id' => $billto['country_id'], 
                                 'countries_id' => $billto['country_id'], 
                                 'countries_name' => $billto['country_name'], 
                                 'countries_iso_code_2' => $billto['country_iso_code_2'], 
                                 'countries_iso_code_3' => $billto['country_iso_code_3'], 
                                 'address_format_id' => $billto['address_format_id'], 
                                 'entry_state' => $billto['zone_name']); 
      } else { 
          $billing_address_query = tep_db_query("select ab.entry_firstname, ab.entry_lastname, ab.entry_company, ab.entry_street_address, ab.entry_suburb, ab.entry_postcode, ab.entry_city, ab.entry_zone_id, z.zone_name, ab.entry_country_id, c.countries_id, c.countries_name, c.countries_iso_code_2, c.countries_iso_code_3, c.address_format_id, ab.entry_state from " . TABLE_ADDRESS_BOOK . " ab left join " . TABLE_ZONES . " z on (ab.entry_zone_id = z.zone_id) left join " . TABLE_COUNTRIES . " c on (ab.entry_country_id = c.countries_id) where ab.customers_id = '" . (int)$customer_id . "' and ab.address_book_id = '" . (int)$billto . "'"); 
          $billing_address = tep_db_fetch_array($billing_address_query); 
      } 

$tax_address_query = tep_db_query("select ab.entry_country_id, ab.entry_zone_id from " . TABLE_ADDRESS_BOOK . " ab left join " . TABLE_ZONES . " z on (ab.entry_zone_id = z.zone_id) where ab.customers_id = '" . (int)$customer_id . "' and ab.address_book_id = '" . (int)($this->content_type == 'virtual' ? $billto : $sendto) . "'"); 
      $tax_address = tep_db_fetch_array($tax_address_query); 

      if ($this->content_type == 'virtual') { 
        $tax_address = array('entry_country_id' => $billing_address['entry_country_id'], 
                             'entry_zone_id' => $billing_address['entry_zone_id']); 
      } else { 
        $tax_address = array('entry_country_id' => $shipping_address['entry_country_id'], 
                             'entry_zone_id' => $shipping_address['entry_zone_id']); 
      }

Link to comment
Share on other sites

I have installed the contribution by making all the code changes to add PayPal express but get the error below in admin.

 

Fatal error: Cannot redeclare class paypal_express in /modules/payment/paypal_express.php on line 13

 

I have double checked that all the code is correct. The only file I think might be incorrect is the classes/order.php??

 

Can anyone tell me where I have gone wrong?

      $customer_address_query = tep_db_query("select c.customers_firstname, c.customers_lastname, c.customers_telephone, c.customers_email_address, ab.entry_company, ab.entry_street_address, ab.entry_suburb, ab.entry_postcode, ab.entry_city, ab.entry_zone_id, z.zone_name, co.countries_id, co.countries_name, co.countries_iso_code_2, co.countries_iso_code_3, co.address_format_id, ab.entry_state from " . TABLE_CUSTOMERS . " c, " . TABLE_ADDRESS_BOOK . " ab left join " . TABLE_ZONES . " z on (ab.entry_zone_id = z.zone_id) left join " . TABLE_COUNTRIES . " co on (ab.entry_country_id = co.countries_id) where c.customers_id = '" . (int)$customer_id . "' and ab.customers_id = '" . (int)$customer_id . "' and c.customers_default_address_id = ab.address_book_id");

     $customer_address = tep_db_fetch_array($customer_address_query);

if (is_array($sendto) && !empty($sendto)) { 
        $shipping_address = array('entry_firstname' => $sendto['firstname'], 
                                  'entry_lastname' => $sendto['lastname'], 
                                  'entry_company' => $sendto['company'], 
                                  'entry_street_address' => $sendto['street_address'], 
                                  'entry_suburb' => $sendto['suburb'], 
                                  'entry_postcode' => $sendto['postcode'], 
                                  'entry_city' => $sendto['city'], 
                                  'entry_zone_id' => $sendto['zone_id'], 
                                  'zone_name' => $sendto['zone_name'], 
                                  'entry_country_id' => $sendto['country_id'], 
                                  'countries_id' => $sendto['country_id'], 
                                  'countries_name' => $sendto['country_name'], 
                                  'countries_iso_code_2' => $sendto['country_iso_code_2'], 
                                  'countries_iso_code_3' => $sendto['country_iso_code_3'], 
                                  'address_format_id' => $sendto['address_format_id'], 
                                  'entry_state' => $sendto['zone_name']); 
      } else { 
     $shipping_address_query = tep_db_query("select ab.entry_firstname, ab.entry_lastname, ab.entry_company, ab.entry_street_address, ab.entry_suburb, ab.entry_postcode, ab.entry_city, ab.entry_zone_id, z.zone_name, ab.entry_country_id, c.countries_id, c.countries_name, c.countries_iso_code_2, c.countries_iso_code_3, c.address_format_id, ab.entry_state from " . TABLE_ADDRESS_BOOK . " ab left join " . TABLE_ZONES . " z on (ab.entry_zone_id = z.zone_id) left join " . TABLE_COUNTRIES . " c on (ab.entry_country_id = c.countries_id) where ab.customers_id = '" . (int)$customer_id . "' and ab.address_book_id = '" . (int)$sendto . "'");

     $shipping_address = tep_db_fetch_array($shipping_address_query);

     }
if (is_array($billto) && !empty($billto)) { 
        $billing_address = array('entry_firstname' => $billto['firstname'], 
                                 'entry_lastname' => $billto['lastname'], 
                                 'entry_company' => $billto['company'], 
                                 'entry_street_address' => $billto['street_address'], 
                                 'entry_suburb' => $billto['suburb'], 
                                 'entry_postcode' => $billto['postcode'], 
                                 'entry_city' => $billto['city'], 
                                 'entry_zone_id' => $billto['zone_id'], 
                                 'zone_name' => $billto['zone_name'], 
                                 'entry_country_id' => $billto['country_id'], 
                                 'countries_id' => $billto['country_id'], 
                                 'countries_name' => $billto['country_name'], 
                                 'countries_iso_code_2' => $billto['country_iso_code_2'], 
                                 'countries_iso_code_3' => $billto['country_iso_code_3'], 
                                 'address_format_id' => $billto['address_format_id'], 
                                 'entry_state' => $billto['zone_name']); 
      } else { 
          $billing_address_query = tep_db_query("select ab.entry_firstname, ab.entry_lastname, ab.entry_company, ab.entry_street_address, ab.entry_suburb, ab.entry_postcode, ab.entry_city, ab.entry_zone_id, z.zone_name, ab.entry_country_id, c.countries_id, c.countries_name, c.countries_iso_code_2, c.countries_iso_code_3, c.address_format_id, ab.entry_state from " . TABLE_ADDRESS_BOOK . " ab left join " . TABLE_ZONES . " z on (ab.entry_zone_id = z.zone_id) left join " . TABLE_COUNTRIES . " c on (ab.entry_country_id = c.countries_id) where ab.customers_id = '" . (int)$customer_id . "' and ab.address_book_id = '" . (int)$billto . "'"); 
          $billing_address = tep_db_fetch_array($billing_address_query); 
      } 

$tax_address_query = tep_db_query("select ab.entry_country_id, ab.entry_zone_id from " . TABLE_ADDRESS_BOOK . " ab left join " . TABLE_ZONES . " z on (ab.entry_zone_id = z.zone_id) where ab.customers_id = '" . (int)$customer_id . "' and ab.address_book_id = '" . (int)($this->content_type == 'virtual' ? $billto : $sendto) . "'"); 
      $tax_address = tep_db_fetch_array($tax_address_query); 

      if ($this->content_type == 'virtual') { 
        $tax_address = array('entry_country_id' => $billing_address['entry_country_id'], 
                             'entry_zone_id' => $billing_address['entry_zone_id']); 
      } else { 
        $tax_address = array('entry_country_id' => $shipping_address['entry_country_id'], 
                             'entry_zone_id' => $shipping_address['entry_zone_id']); 
      }

 

How silly do I feel?! The wrong file had been put in the language folder.

Link to comment
Share on other sites

Hi Guys, I too am in the process of trying to Integrate Paypal Express as my only method of payment into my partners shop online. I have successfully installed osCommerce latest edition and see that it has icons for Paypal but i have no idea what code needs changed so the buttons show up in the places you'd expect them to be, checkout etc and payments successfully made with the transaction amount obviously going into my partners paypal business account. I looked at the link posted in the First message written in this post but wasn't really sure what i was to do as it just showed you code but didn't say what needed to be done, any help on this would be much appreciated.

Link to comment
Share on other sites

htmlspecialchars() expects parameter 1 to be string, array given

 

What worked for us was to look at /catalog/includes/classes/order.php

 

We had an old version of the file and we missing this code from the file. An eay way to fins what you are missing is download the newest verson of OSC and do a Diff of the files

 

Hope this helpes

 

 

      if (is_array($sendto) && !empty($sendto)) {
       $shipping_address = array('entry_firstname' => $sendto['firstname'],
                                 'entry_lastname' => $sendto['lastname'],
                                 'entry_company' => $sendto['company'],
                                 'entry_street_address' => $sendto['street_address'],
                                 'entry_suburb' => $sendto['suburb'],
                                 'entry_postcode' => $sendto['postcode'],
                                 'entry_city' => $sendto['city'],
                                 'entry_zone_id' => $sendto['zone_id'],
                                 'zone_name' => $sendto['zone_name'],
                                 'entry_country_id' => $sendto['country_id'],
                                 'countries_id' => $sendto['country_id'],
                                 'countries_name' => $sendto['country_name'],
                                 'countries_iso_code_2' => $sendto['country_iso_code_2'],
                                 'countries_iso_code_3' => $sendto['country_iso_code_3'],
                                 'address_format_id' => $sendto['address_format_id'],
                                 'entry_state' => $sendto['zone_name']);
     } elseif (is_numeric($sendto)) {
       $shipping_address_query = tep_db_query("select ab.entry_firstname, ab.entry_lastname, ab.entry_company, ab.entry_street_address, ab.entry_suburb, ab.entry_postcode, ab.entry_city, ab.entry_zone_id, z.zone_name, ab.entry_country_id, c.countries_id, c.countries_name, c.countries_iso_code_2, c.countries_iso_code_3, c.address_format_id, ab.entry_state from " . TABLE_ADDRESS_BOOK . " ab left join " . TABLE_ZONES . " z on (ab.entry_zone_id = z.zone_id) left join " . TABLE_COUNTRIES . " c on (ab.entry_country_id = c.countries_id) where ab.customers_id = '" . (int)$customer_id . "' and ab.address_book_id = '" . (int)$sendto . "'");
       $shipping_address = tep_db_fetch_array($shipping_address_query);
     } else {
       $shipping_address = array('entry_firstname' => null,
                                 'entry_lastname' => null,
                                 'entry_company' => null,
                                 'entry_street_address' => null,
                                 'entry_suburb' => null,
                                 'entry_postcode' => null,
                                 'entry_city' => null,
                                 'entry_zone_id' => null,
                                 'zone_name' => null,
                                 'entry_country_id' => null,
                                 'countries_id' => null,
                                 'countries_name' => null,
                                 'countries_iso_code_2' => null,
                                 'countries_iso_code_3' => null,
                                 'address_format_id' => 0,
                                 'entry_state' => null);
     }

     if (is_array($billto) && !empty($billto)) {
       $billing_address = array('entry_firstname' => $billto['firstname'],
                                'entry_lastname' => $billto['lastname'],
                                'entry_company' => $billto['company'],
                                'entry_street_address' => $billto['street_address'],
                                'entry_suburb' => $billto['suburb'],
                                'entry_postcode' => $billto['postcode'],
                                'entry_city' => $billto['city'],
                                'entry_zone_id' => $billto['zone_id'],
                                'zone_name' => $billto['zone_name'],
                                'entry_country_id' => $billto['country_id'],
                                'countries_id' => $billto['country_id'],
                                'countries_name' => $billto['country_name'],
                                'countries_iso_code_2' => $billto['country_iso_code_2'],
                                'countries_iso_code_3' => $billto['country_iso_code_3'],
                                'address_format_id' => $billto['address_format_id'],
                                'entry_state' => $billto['zone_name']);
     } else {
       $billing_address_query = tep_db_query("select ab.entry_firstname, ab.entry_lastname, ab.entry_company, ab.entry_street_address, ab.entry_suburb, ab.entry_postcode, ab.entry_city, ab.entry_zone_id, z.zone_name, ab.entry_country_id, c.countries_id, c.countries_name, c.countries_iso_code_2, c.countries_iso_code_3, c.address_format_id, ab.entry_state from " . TABLE_ADDRESS_BOOK . " ab left join " . TABLE_ZONES . " z on (ab.entry_zone_id = z.zone_id) left join " . TABLE_COUNTRIES . " c on (ab.entry_country_id = c.countries_id) where ab.customers_id = '" . (int)$customer_id . "' and ab.address_book_id = '" . (int)$billto . "'");
       $billing_address = tep_db_fetch_array($billing_address_query);
     }

     if ($this->content_type == 'virtual') {
       $tax_address = array('entry_country_id' => $billing_address['entry_country_id'],
                            'entry_zone_id' => $billing_address['entry_zone_id']);
     } else {
       $tax_address = array('entry_country_id' => $shipping_address['entry_country_id'],
                            'entry_zone_id' => $shipping_address['entry_zone_id']);
     }

----------------------------

Long Island, New York

Link to comment
Share on other sites

Hi Paul..

 

Yes, that is correct behaviour of the module. It is not the preferred manner for the Express Checkout payment method however many more codebase changes would be required to properly support a purchase without a customer account.

 

The codebase changes going in 2.2 RC1/RC2/Final are minimal changes to ease the upgrade procedure for existing store owners. Although we are focusing the bigger changes for the 3.0 release, a 2.3 release will also be made where such features will be available on based on the 2.2 core. (The 3.0 release has a new core that is not compatible to 2.2)

 

 

 

Hi Harald and hi everybody!

 

 

I have installed the Paypal Express Checkout, and I've got the PayPal module from before. The problem is that I can't see any difference between them two. The only difference when i made few transactions with Paypal Express Checkout is thet after the paypal website brings you back to your order confirmation page, also meantime you can go and put more items in your basket you can browse other pages and at the end when you go to checkout and select again the radio button for Paypal Express Checkout will place the order straight away.

 

 

Ok, but where is the problem?

 

 

When you are buying with or without account (I've got the two options) you can select the desired shipping address which can be different than your paypal address. So after purchase you will receive the Instant Payment notification from paypal and you will see the pending (by default) order status in your admin panel. BUT, in your mail box the email from paypal will show you the registered address of the buyer - the address in his PayPal account, not the address entered by him in the delivery information meantime in your admin panel you will see the address entered by the buyer which is very confusing????

 

PayPal email will say Delivery Information: ABC.... Admin Panel will show: Shipping Address: XYZ.....

 

 

two completely different things?

 

 

 

I don't think buyers will go to their paypal account and change addresses, they will automatically click continue.

 

 

 

There can be two options: Either this is a big problem that need to be sorted, or I am missing something???

 

 

 

Please guys I need your help?

 

 

 

Many thanks!

Link to comment
Share on other sites

  • 1 year later...

Hi,

I installed the module but I have a problem when I return from the paypal page to checkout_confirmation, essentially in session I haven't the same data of payment and shipping selected before being directed to paypal.

Any suggestions?

Sorry for my bad english

Link to comment
Share on other sites

  • 4 months later...

Thanks very much for bringing the paypal express checkout to life!

 

I have a question: If I run the order with the new paypal express checkout there is no billing adress

afterwards and the following error-code inside the checkout_confirmation.php:

 

Does anybody have an idea why that happens? It´s just if I use the new paypal payment.

 

I'm having this same problem. So far, I have narrowed down the problem to the fact that when PayPal returns to the site at checkout_confirmation.php, $billto has the billing address (from PayPal) but the $order array is empty. This leads me to believe that somewhere there's supposed to be an exchange of info and it's not happening. I suspect that $order is theoretically supposed to have the store's default address in it. This would explain the comments above regarding the different addresses of PayPal returning versus what the OSC store says is the "billing" or "shipping" address.

 

I have not focused on the shipping address yet (produces same htmlspecialchars message) until I isolate the billing addr problem. I would bet they are related. I can see this error is produced because the $order array is emtpy and there is no trap for this condition (when the $order var is null) before calling the htmlspecialchars function.

 

I am contemplating adding code to force the store to use PayPal's shipping and billing addresses for the order, but I have not looked into that yet. Obviously that raises issues if either address is or is not already in the database. Anyone have any suggestions on where I ought to look for the problem that is causing the $order array to get lost? At least that would get it working and I'll then just have the conundrum raised above over whether to ignore the PayPal address entry or not.

 

I hope that all make sense. It's a somewhat complex issue considering the priority of which address to use if they are different. First I would just like suggestions on how to get back to square one and get $order working.

 

If no one replies, I'll see what I can sort out and post my findings.

 

David

Link to comment
Share on other sites

Ok... after many hours of tinkering I found a solution and fixed a few bugs. Perhaps this info will benefit someone else as well. It has taken me hours to figure out what the problem was.

 

Short answer: there’s a variable that is used in 3 different ways – either as an array, a Boolean (true/false), or as an integer. The fact that the same variable is global and used in three possible ways is IMHO a poor idea, but it’s how some critical back-end components work for the shopping cart and checkout so I had to find a way to work around it without breaking anything. The fix is short and simple to implement.

 

What I found is in my case the problem is that the order delivery and billing information are not populated during the PayPal Express Checkout process. Shipping (Delivery) info is gleaned from PayPal’s servers, but the OSC routines that grab this data are not invoked during the process. This causes all kinds of problems. First, no shipping cost is calculated. Second, you end up with these error messages on the checkout_confirmation.php page. Since the user has to be logged in to get the PayPal Express Checkout icon, it seems logical that OSC should know this info, but it is not getting passed into the right variables to make everything run smoothly ($order->delivery array is empty when it gets to checkout_confirmation.php). To fix this we need to establish the shipping/delivery address before the code gets to checkout_confirmation.php. It must be setup prior to the shipping calculation (unless you want to give all of your PayPal Express customers free shipping).

 

IMHO, the PayPal shipping address should trump what the OSC store has on file anyway. [Though this brings up the question of whether your store should automatically check to see if the PayPal address is on file with the OSC store or not and add it if it's not in the customer's address book, I am not going to delve into that right now.]

 

Another critical issue is that the shipping info is not being processed (at least not for my store), meaning if I only fixed the delivery address then the customer's order would go through but they would not be charged anything for shipping!

 

The code fix below will force the PayPal returned shipping (delivery) address as what is displayed in your store. If your customer changes this, they will have to go through the complete (normal) checkout process. This also takes care of another bug regarding mis-matched variable array keys (names).

 

In checkout_confirmation.php, locate this code (beginning around line 136):

 

<!-- body_text //-->
   <td width="100%" valign="top"><table border="0" width="100%" cellspacing="0" cellpadding="0">
     <tr>
       <td><table border="0" width="100%" cellspacing="0" cellpadding="0">
         <tr>
           <td class="pageHeading"><?php echo HEADING_TITLE; ?></td>
           <td class="pageHeading" align="right"><?php echo tep_image(DIR_WS_IMAGES . 'table_background_confirmation.gif', HEADING_TITLE, HEADING_IMAGE_WIDTH, HEADING_IMAGE_HEIGHT); ?></td>
         </tr>
       </table></td>
     </tr>
     <tr>
       <td><?php echo tep_draw_separator('pixel_trans.gif', '100%', '10'); ?></td>
     </tr>
     <tr>
       <td><table border="0" width="100%" cellspacing="1" cellpadding="2" class="infoBox">
         <tr class="infoBoxContents">
<?php
 if ($sendto != false) {

 

INSERT the following afterwards:

 

// BOF fix PayPal Express delivery addr display error
  		$order->delivery = $billto;
  		$order->delivery['format_id'] = $order->delivery['address_format_id']; // make names compatible
// EOF fix PayPal Express delivery addr display error

 

This will force the PayPal returned shipping address into the delivery address confirmation.

 

-------------

 

Now, for some bug fixes:

 

1. Code was returning “MODULE_PAYMENT_PAYPAL_EXPRESS_TEXT_TITLE” as payment method. To fix, open /ext/modules/payment/paypal/express.php and find this code starting around line 29:

 

 if ($cart->count_contents() < 1) {
   tep_redirect(tep_href_link(FILENAME_SHOPPING_CART));
 }

 require('includes/modules/payment/paypal_express.php');

 $paypal_express = new paypal_express();

 

REPLACE WITH:

 

 if ($cart->count_contents() < 1) {
   tep_redirect(tep_href_link(FILENAME_SHOPPING_CART));
 }

 require(DIR_WS_LANGUAGES . $language . '/modules/payment/paypal_express.php');
 require('includes/modules/payment/paypal_express.php');

 $paypal_express = new paypal_express(); 

 

2. $sendto is used as both an array and a variable. The code that tries to use $sendto as a variable sometimes fails when it’s being used only as an array (and the $sendto variable itself - not the array part - has no value assigned). $sendto is supposed to contain the shipping/delivery address returned by PayPal. The normal shipping methods use $sendto as a variable to store the desired shipping address, retrieved from the customer’s address book.

 

There are a few possible ways to resolve the problem for PayPal Express. What should be done IMHO is to use the PayPal returned shipping address, since that is the only address the customer can change and it’s also where PayPal expects you to ship the order.

 

So to solve the problem, a code fix is needed for the section trying to determine the customer's delivery (shipping) address. Essentially, it is necessary to modify the reading $sendto to first check and see if $sendto is an array. If it is, then it should contain the shipping address info. If it is not an array then it should contain the number of the default shipping address within the customer’s address book.

 

Modify /ext/modules/payment/paypal/express.php and insert code just before the redirect to checkout_confirmation.php when the cart does not contain a virtual product.

 

The code change required is:

 

Open /ext/modules/payment/paypal/express.php and find this code around line 202:

 

         if (!tep_session_is_registered('payment')) tep_session_register('payment');
         $payment = $paypal_express->code;

         if (!tep_session_is_registered('ppe_token')) tep_session_register('ppe_token');
         $ppe_token = $response_array['TOKEN'];

         if (!tep_session_is_registered('ppe_payerid')) tep_session_register('ppe_payerid');
         $ppe_payerid = $response_array['PAYERID'];

         tep_redirect(tep_href_link(FILENAME_CHECKOUT_CONFIRMATION, '', 'SSL'));

 

CHANGE TO:

 

         if (!tep_session_is_registered('payment')) tep_session_register('payment');
         $payment = $paypal_express->code;

         if (!tep_session_is_registered('ppe_token')) tep_session_register('ppe_token');
         $ppe_token = $response_array['TOKEN'];

         if (!tep_session_is_registered('ppe_payerid')) tep_session_register('ppe_payerid');
         $ppe_payerid = $response_array['PAYERID'];

// added by Richard Cranium to trap bad address error condition
         if (!is_array($sendto)) $sendto = $customer_default_address_id; // set customer default address if we do not have delivery addr from PayPal

         tep_redirect(tep_href_link(FILENAME_CHECKOUT_CONFIRMATION, '', 'SSL'));

 

The other possible state of $sendto is binary (true/false). If set to ‘false’, that is because the cart contains a virtual (downloadable) product. In that scenario it is not desirable to calc any shipping charge, so $sendto will rightfully not contain an array of delivery information. It may still be possible with the code changes I am outlining here to still have the delivery address fall through if the only product ordered is downloadable. I don't have a good test store atm with any downloadable content, so I have not explored this possibility atm. However, this could easily be solved by adding a check for $sendto == false in /ext/modules/payment/paypal/express.php and forcing the use of the customer's default address as the delivery address. See bug fix #3 below for a brief explanation and pointing out the code section that would need to be modified to do this.

 

 

3. Order delivery details blank

 

For me, the /ext/modules/payment/paypal/express.php code was not assigning a delivery address. The delivery address is stored in $order->delivery (which is an array), but the data does not get transferred to checkout_confirmation, even though all the other array parts are carried over. Why?

 

The problem is that $order does not transfer over to checkout_confirmation intact. Because there is no order_id number yet, the order referencing checks in various files grab the cart contents and attempt to pull the customer’s shipping/delivery address from $sendto as a variable (and not an array). If the code has not assigned a numeric value to $sendto, the result is the htmlspecialchars() error in the delivery address field when checkout_confirmation.php attempts to display an address via a pointer that does not exist. If $sendto is equal to an integer value, the integer is a pointer to the customer's default address on file with the OSC store.

 

If $sendto is being used as an array only (you can use a variable as both at the same time), any query of the integer value of $sendto will be invalid (looking at $sendto by itself would return the value “array”), resulting in an error or null by the (int) operation. This can create a state where it’s impossible for checkout_confirmation.php to retrieve a shipping address. Plus we don’t want it to pull an address from the database anyway, we want it to use what PayPal sent. To fix this problem, checkout_confirmation (or the cart function) needs to grab the delivery address from the PayPal data.

 

One method is to compare the PayPal address information with the customer’s addresses on file (in their address book) and create a new shipping address for the customer if a match is not found. Then store the pointer for this address as an integer in $sendto and the standard functions involved will take care of the rest. Another (and easier) option is to modify /includes/classes/order.php so the cart function will pull the delivery address data if $sendto is an array and not being used as a variable (which also enables this method to be used for other payment solutions).

 

A final possible state of $sendto is a boolean value (true/false). If set to ‘false’, that is because the cart contains a virtual (downloadable) product. In that scenario it is not desirable to calc any shipping charge, so $sendto will rightfully not contain an array of delivery information. It may be possible with the code changes I am outlining for the delivery address fall through if the only product ordered is downloadable. I don't have a good test store atm with any downloadable content, so I have not explored this possibility. However, this could easily be solved by adding a check for $sendto == false in /ext/modules/payment/paypal/express.php and forcing the use of the customer's default address as the delivery address (and change $sendto to an integer).

 

To re-cap, there are 4 possible states of $sendto:

a. array only

b. integer only

c. array and integer

d. true/false value only

 

 

Find the following:

 

   function cart() {
     global $HTTP_POST_VARS, $customer_id, $sendto, $billto, $cart, $languages_id, $currency, $currencies, $shipping, $payment, $comments, $customer_default_address_id;

     $this->content_type = $cart->get_content_type();

     $customer_address_query = tep_db_query("select c.customers_firstname, c.customers_lastname, c.customers_telephone, c.customers_email_address, ab.entry_company, ab.entry_street_address, ab.entry_suburb, ab.entry_postcode, ab.entry_city, ab.entry_zone_id, z.zone_name, co.countries_id, co.countries_name, co.countries_iso_code_2, co.countries_iso_code_3, co.address_format_id, ab.entry_state from " . TABLE_CUSTOMERS . " c, " . TABLE_ADDRESS_BOOK . " ab left join " . TABLE_ZONES . " z on (ab.entry_zone_id = z.zone_id) left join " . TABLE_COUNTRIES . " co on (ab.entry_country_id = co.countries_id) where c.customers_id = '" . (int)$customer_id . "' and ab.customers_id = '" . (int)$customer_id . "' and c.customers_default_address_id = ab.address_book_id");
     $customer_address = tep_db_fetch_array($customer_address_query);

 

Immediately after the code above you should see this:

 

     	$shipping_address_query = tep_db_query("select ab.entry_firstname, ab.entry_lastname, ab.entry_company, ab.entry_street_address, ab.entry_suburb, ab.entry_postcode, ab.entry_city, ab.entry_zone_id, z.zone_name, ab.entry_country_id, c.countries_id, c.countries_name, c.countries_iso_code_2, c.countries_iso_code_3, c.address_format_id, ab.entry_state from " . TABLE_ADDRESS_BOOK . " ab left join " . TABLE_ZONES . " z on (ab.entry_zone_id = z.zone_id) left join " . TABLE_COUNTRIES . " c on (ab.entry_country_id = c.countries_id) where ab.customers_id = '" . (int)$customer_id . "' and ab.address_book_id = '" . (int)$sendto . "'");
     	$shipping_address = tep_db_fetch_array($shipping_address_query);

 

REPLACE those 2 lines with this:

// BOF htmlspecialchars bug fix for PayPal Express by Richard Cranium
  if (is_numeric($sendto)) { // grab address book ref if we have one
     	$shipping_address_query = tep_db_query("select ab.entry_firstname, ab.entry_lastname, ab.entry_company, ab.entry_street_address, ab.entry_suburb, ab.entry_postcode, ab.entry_city, ab.entry_zone_id, z.zone_name, ab.entry_country_id, c.countries_id, c.countries_name, c.countries_iso_code_2, c.countries_iso_code_3, c.address_format_id, ab.entry_state from " . TABLE_ADDRESS_BOOK . " ab left join " . TABLE_ZONES . " z on (ab.entry_zone_id = z.zone_id) left join " . TABLE_COUNTRIES . " c on (ab.entry_country_id = c.countries_id) where ab.customers_id = '" . (int)$customer_id . "' and ab.address_book_id = '" . (int)$sendto . "'");
     	$shipping_address = tep_db_fetch_array($shipping_address_query);
  } elseif (is_array($sendto)) { // or if an array then get the delivery info from the array
// setup $shipping_address array with the delivery address info
// instead of using customer address book
   	$shipping_address = array('entry_firstname' => $sendto['firstname'],
							  'entry_lastname' => $sendto['lastname'],
							  'entry_company' => $sendto['company'],
							  'entry_street_address' => $sendto['street_address'],
							  'entry_suburb' => $sendto['suburb'],
							  'entry_city' => $sendto['city'],
							  'entry_postcode' => $sendto['postcode'],
							  'entry_state' => '',
							  'zone_name' => $sendto['zone_name'],
							  'entry_zone_id' => $sendto['zone_id'],
							  'countries_id' => $sendto['country_id'],
							  'countries_name' => $sendto['countries_name'],
							  'countries_iso_code_2' => $sendto['country_iso_code_2'],
							  'countries_iso_code_3' => $sendto['country_iso_code_3'],
							  'entry_country_id' => $sendto['country_id'],
							  'address_format_id' => $sendto['address_format_id']);
  }
// EOF htmlspecialchars bug fix for PayPal Express by Richard Cranium

The solution above will use a customer’s address book entry if called for (when $sendto is numeric). Otherwise the shipping address will be grabbed from $sendto (when it is an array containing the shipping info). Although I don’t think it’s necessary, another check could be added to see if $sendto == false and the whole routine could be trapped at the end to make sure nothing falls through the cracks. But if $sendto == false then you should never get to this code anyway. The only possible conditions for $sendto are holding an integer, a boolean (true/false), or an array.

Link to comment
Share on other sites

  • 2 months later...

Hi Paul..

 

Yes, that is correct behaviour of the module. It is not the preferred manner for the Express Checkout payment method however many more codebase changes would be required to properly support a purchase without a customer account.

 

The codebase changes going in 2.2 RC1/RC2/Final are minimal changes to ease the upgrade procedure for existing store owners. Although we are focusing the bigger changes for the 3.0 release, a 2.3 release will also be made where such features will be available on based on the 2.2 core. (The 3.0 release has a new core that is not compatible to 2.2)

 

Harald,

 

You mentioned in your post that some minimal changes would be required to enable a user to purchase without an account. I have managed to install the Paypal Express Checkout but when clicking on the checkout button, the user would then be taken to the website login page rather than the paypals website.

 

What changes would i need to make to get this corrected? Currently I have the RC2a version.

 

Thanks in advance.

Link to comment
Share on other sites

  • 3 months later...

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Unfortunately, your content contains terms that we do not allow. Please edit your content to remove the highlighted words below.
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...