Jump to content
Sign in to follow this  
devosc

[Contribution]Paypal IPN - Devosc

Recommended Posts

he he done the 1146 error, must have put this

 

//begin PayPal_Shopping_Cart_IPN

require_once(DIR_FS_CATALOG_MODULES . 'payment/paypal/database_tables.php');

//end PayPal_Shopping_Cart_IPN

 

in the wrong database_tables.php. Thought it looked a little weird at the time, should have been added to admin/includes/database_tables.php

 

Now what else can I find wrong....hmmmm :ph34r:

Share this post


Link to post
Share on other sites

Hi there,

 

Don (and Kim), when testing via the IPN test panel the 'Transaction ID' must be unique, what I normally do is when checking out as a customer and stopping at the PayPal screen, I then go back into the admin->customers->orders section and identify that order_id for that transaction, then in the IPN Test Panel in the 'Transaction ID' field I amend (overwrite) the first few zeros with that order_id number, this way each transaction is unique, e,g 'PAYPAL12300000000' (the transaction id must be 17 characters long).

 

Also remember if testing with the 'Cart Test' on then you must enter that correct amount into the 'MC Gross' otherwise the transaction will not, intentionally, go through. The email debug info should identify when it fails.

 

Don, I'll have to maybe get back to you on the currencies, I've never really messed around with the paypal currencies and or osCs (too much), and i'm pretty confident that things work as per the default osCommerce PayPal module. A temporary workaround (if it helps at all) would be to go into modules/payment/paypal.php and change the defaulting currency from 'USD' to 'CAD' or whatever your definition is for CAD, remeber this code must also be recognizable by PayPal or they themselves will revert back to USD (this maybe the case).

 

I've recently made a local update to the contrib to include osC->Admin selection of which paypal domain to use, e.g either sandbox.paypal.com or the regular (live) paypal.com domain.

Also included is the additional invoice synchronization functionality enabling a payment to be resumed if it was abandoned prior to the customer fullfilling payment, per Bob's discussion.

Also per Bob, I've included a more generic help pop info page (in PayPal style) for info about making credit card payments via PayPal.

 

Just need to test things again prior to uploading, however at present I still feel the best method is to list all these changes as per install docs, I appreciate that this may not be to everyones liking, but as long as time and care is taken I think it is more personally rewarding, and also allows one to become accquainted with what changes have been made (in my experience no-one ever uses a stock version of osC as a live site). I haven't used windows for a while now but my favorite editor was TextPad, but I cannot recall if it will resolve the hidden character issue.


"Any fool can know. The point is to understand." -- Albert Einstein

Share this post


Link to post
Share on other sites

Hi Donavan,

 

Ok, thanks, not sure what happened during the previous versions but the 'currency_code' field seemed to have got dropped.

 

In catalog/includes/modules/payment/paypal.php find

      tep_draw_hidden_field('business', MODULE_PAYMENT_PAYPAL_BUSINESS_ID);

and place below this line

$paypal_fields .= tep_draw_hidden_field('currency_code', $my_currency);

 

I just tested it, and PayPal recognized the currency ('CAD') of the transaction, so things should be ok, thanks for pointing this out.


"Any fool can know. The point is to understand." -- Albert Einstein

Share this post


Link to post
Share on other sites
I've recently made a local update to the contrib to include osC->Admin selection of which paypal domain to use, e.g either sandbox.paypal.com or the regular (live) paypal.com domain.

 

hmm hello again Greg, could you please tell me more about the different PP domains and whats the difference etc, i havent understood that...And again thanx for beeing so patiance with helping me as a noob out with installing of PP IPN !! :)

Share this post


Link to post
Share on other sites

Hi there, glad to hear you got things going. The sandbox.paypal.com domain is for developers (as such), it is merely a PayPal testing environment. (Currently?) This is does not have anything to do with the IPN Test Panel.

 

The 'paypal.com' domain is the one used for live transactions, and is/will be the default domain.


"Any fool can know. The point is to understand." -- Albert Einstein

Share this post


Link to post
Share on other sites
Don, I'll have to maybe get back to you on the currencies, I've never really messed around with the paypal currencies and or osCs (too much), and i'm pretty confident that things work as per the default osCommerce PayPal module. A temporary workaround (if it helps at all) would be to go into modules/payment/paypal.php and change the defaulting currency from 'USD' to 'CAD' or whatever your definition is for CAD, remeber this code must also be recognizable by PayPal or they themselves will revert back to USD (this maybe the case).

Hi,

 

thanks for the quick response! Although I didn't see the solution above right away... I went to your code fix first, then figured out that I'd changed the currency code to CDN from CAD... then to further complicate things, my logged in osC session would show the prices as 0 when I'd made the change. I spent a long time trying to figure out where in the database they were storing CDN instead of it's ID, looking at code, etc., only to find out that it was just a session variable for the selected currency, once I reselected Canadian $ everything went back to normal. ARRAGH!

 

:) So yes, PayPal is respecting the currency type now, thank you. Something else I've discovered is that the PayPal amounts need some tweaking.

 

Of no real concern is that osC reports a product total of 22.97 and PayPal says it's 22.96 (yes, I was using the Itemized over Aggregate, as it looks more professional). No biggy, however PayPal is being told of a Shipping and Handling charge that does not include the tax on shipping (you probably don't use this?). I'm sure it's a small code change in paypal.php which I will look at in a little bit, just a heads up and I thank you for your help!

 

 

...Dono

Share this post


Link to post
Share on other sites
Of no real concern is that osC reports a product total of 22.97 and PayPal says it's 22.96 (yes, I was using the Itemized over Aggregate, as it looks more professional).

<rant>I really dislike the rather limited time you are allowed to edit your posts on the forum here, less than 5 minutes it seems, assuming we are allowed to actually edit them, lol</rant>

 

To expand my above message after some more research:

 

The 1 cent difference is due to the primary currency being Canadian and doing a checkout in USD... osC is (presumably) keeping extra decimal places and coming up with a 2 qty item total of $2.91. PayPal is feed the per item price with two decimal places (presumably) with a qty of 2 and thus comes up with 2.90. :P

 

If this really bothered someone that the invoice totals didn't match the purchase price exactly (perhaps extremely large quantities, lol), they can just use the aggregate method, which is passed the exact amounts as osC sees them.

 

Cheers,

...Dono

Share this post


Link to post
Share on other sites

Thanks for the response Greg. I seemed to have completely lost my train of thought while looking at the code. Anyway I was wondering if anyone has come up with a way yet to drop orders that fail on the ipn (ie declines credit card) and then return the items to the users shoppibg cart. Well if not I'll be working on it in the morning. If all goes well I should be able to post the results on the contribs by afternoon.

Edited by jwbonow

Share this post


Link to post
Share on other sites

Hi Joe,

I'll look out for it.

I was trying to make a quick update, with some of the recent discussions and also to more easily facilitate usage of PayPal's sandbox.

However I've now moved onto to changing the way each IPN is associated to its corresponding order, previously the paypal.custom var was set with that IPN's orders_id, but this can allow someone to spoof payment for a different order even if the cart totals are the same amounts, so now a unique (md5 digest timestamp) transaction signature is going to be created per order and will be set as the paypal.custom var in replace of the orders_id.

A little overhaul has also been done so that the structure of the contrib can be more easily identified. Just currently trying to find time to test and document.

Regards,


"Any fool can know. The point is to understand." -- Albert Einstein

Share this post


Link to post
Share on other sites

hello i just added the PayPal_Shopping_Cart_IPN_v2.4 module to our shop and everything seemed to be okay, so thats one part covered i gues :)

 

My question is this:

 

I saw when trying out a testpayment as suggested in the contribution that at the point when leaving the shop and going over into the paypall site a page which i didn't really like

 

 

Here is a screenshot i made

ipn.jpg

 

 

 

Can this be changed into something else perhaps, like something i would like to appear as text or images perhaps?

 

Thanks

Edited by PVK

Share this post


Link to post
Share on other sites

seems like the contribution's new catalog/includes/languages/english/modules/payment/paypal.php languge file wasn't copied over or you need to copy it's contents accordingly for any other language.


"Any fool can know. The point is to understand." -- Albert Einstein

Share this post


Link to post
Share on other sites

Ok heres a fix I'm toying with on the checkout_success.php page to remove failed paypal orders and keep the information in the shopping cart to be adjusted by the customer along with a link back to the payment page so they could provide another form of payment if desired.

 

Word of caution, I am using the BTS template system so you will see $content='SOMETHING' where SOMETHING is the content to be displayed. This is not tested yet, I will be doing that today at some point.

 

Also as you may notice I am not including any directions on what to change, those who are familiar with this page may be able to provide feedback (Greg ;) ). Once I have it tested I'll write up a howto and post it in the contribs section. Since I have not done that before maybee a sugestion of where to post it could be made also.

 

Anyway heres the code I have come up with (and the tep_remove_order function was pulled from the admin functions to facilitate deleting the order).

 

// Removed this section of code

// BOF: jwb - PayPal_Shopping_Cart_IPN Contribution

//begin PayPal_Shopping_Cart_IPN

/*

else if ((isset($HTTP_GET_VARS['action']) && $HTTP_GET_VARS['action'] == 'success')) {

$cart->reset(true);

// unregister session variables used during checkout

tep_session_unregister('sendto');

tep_session_unregister('billto');

tep_session_unregister('shipping');

tep_session_unregister('payment');

tep_session_unregister('comments');

tep_session_unregister('paypal_order_id');

}

*/

//end PayPal_Shopping_Cart_IPN

// EOF: jwb

 

// And Replaced with

// BOF: jwb - Added this to account for failed order payment

$payment_status_array = tep_db_fetch_array("SELECT payment_status FROM paypal pp INNER JOIN orders o ON o.paypal_ipn_id = pp.paypal_ipn_id WHERE o.orders_id = '" . $last_order . "'");

$payment_status = $payment_status_array['payment_status'];

 

if($payment_status != 'Failed' && $payment_status == 'Denied') {

$cart->reset(true);

// unregister session variables used during checkout

tep_session_unregister('sendto');

tep_session_unregister('billto');

tep_session_unregister('shipping');

tep_session_unregister('payment');

tep_session_unregister('comments');

tep_session_unregister('paypal_order_id');

}

 

if($payment_status == 'Completed' || !tep_not_null($payment_status)) {

require(DIR_WS_LANGUAGES . $language . '/' . FILENAME_CHECKOUT_SUCCESS);

$content = CONTENT_CHECKOUT_SUCCESS;

}

else if($payment_status == 'Failed') {

// Remove the order that was just created and request customer to go back to payment section and provide new payment

// Or adjust the order total and proceede to checkout again.

tep_remove_order($last_order);

require(DIR_WS_LANGUAGES . $language . '/' . FILENAME_CHECKOUT_FAILED);

$content = CONTENT_CHECKOUT_SUCCESS;

}

else if($payment_status == 'Denied') {

// Remove the order that was just created and request customer to go back to payment section and provide new payment

// Or adjust the order total and proceede to checkout again.

tep_remove_order($last_order);

require(DIR_WS_LANGUAGES . $language . '/' . FILENAME_CHECKOUT_DENIED);

$content = CONTENT_CHECKOUT_SUCCESS;

}

else if($payment_status == 'Pending') {

// The created order will stay in place here and not be removed....... this will result in some

// manual maintinance of the orders section within admin in the case of a failed order. (At the moment.)

// However if settings are correct on the paypal site then pending SHOULD NOT be an issue.

require(DIR_WS_LANGUAGES . $language . '/' . FILENAME_CHECKOUT_PENDING);

$content = CONTENT_CHECKOUT_SUCCESS;

}

else {

// Something incredibly odd happened here and the customer should contact customer service in

// order to determine the status of the order. This realy should not happen but needs to be

// here to trap any such odity.

require(DIR_WS_LANGUAGES . $language . '/' . FILENAME_CHECKOUT_INCOMPLETE);

$content = CONTENT_CHECKOUT_SUCCESS;

}

// EOF: jwb

Edited by jwbonow

Share this post


Link to post
Share on other sites

Sorry for the second post coming so fast. It occured to me that what i just posted realy should be incorporated into catalog/includes/modules/payment/paypal/ipn.php somewhere after the lines that look like this:

 

 

 

if ($ipn->key['payment_status'] == 'Completed' && $ipn->valid_payment() ) {

 

include DIR_WS_MODULES . 'payment/paypal/checkout_update.php';

}

 

 

using somethig like this:

 

else {

// altering tep_remove_last_order so that ipn information still exists? so we can inform the customer of what went wrong

// plus puting this in here makes it easier to test using Gregs test page

// a column would need to be added to the paypal table to hold the order number so when we get to the checkout success page

// we can determine the status of the payment for the order if it failed, seems odd could use a suggestion or 2 here

tep_remove_order($last_order);

tep_db_query("update paypal set orders_id = '" . . (int)$ipn->key['orders_id'] . ."' where paypal_ipn_id = '" . (int)$ipn->_paypal_ipn_id . "''");

}

Share this post


Link to post
Share on other sites

Hi Joe, I had just wrote some comments but must of forgotten to hit the 'Add Reply' button, anway I've just upload the latest version, hopefully we can use this base the discussion on.


"Any fool can know. The point is to understand." -- Albert Einstein

Share this post


Link to post
Share on other sites

Greg,

I know the feeling, having one of those days myself. Thanks for the update. BTW I have it working on ipn 2.3 at the moment so a port to the new stuff should not be too bad, but I'll see once I get it in place. Quick question, being of limited inteligence what do I need ot set on your test pagewhen I want to verify cart total? Is it settlement amount or MC Gross... of course I could figure it out by pluging stuff in till it works too... Thanks in advance.

Share this post


Link to post
Share on other sites

:), I've improved the instructions slightly. Yeah, mc_gross and mc_currency, also custom and trasaction ID.

 

If possible please attempt v2.5, I didn't have time to go through all the tests, but during development things looked ok, quickly uploaded for you to have a look etc.

 

From your previous posts it wasn't clear exactly what actual content you had in mind to provide the customer when they returned to checkout_success? eg the verbatim text/html.

 

Sorry, one of those days, could you explain the reasoning for wanting to immediately delete a failed payment?


"Any fool can know. The point is to understand." -- Albert Einstein

Share this post


Link to post
Share on other sites

Just downloaded 2.4 and 2.5 will upgrade to each successively.

 

The reason for removing the failed order is not to have it lying about in the orders table should the customer decide to leave. Maybee this should be done on logout but you cant always rely on someone to log out.... Maybee what I should do is delete the order if they hit the continue button on the checkout_success.php page. After looking at it I supose the order_id (paypal_order_id) could be kept and then used if the customer attempts repayment imidieately after being notified of failure.

 

The content to be returned to the customer would be notification of success, failure, denied, pending or WOW we just had somehting unusual happen please contact customer service to see if your order was placed properly.

 

Anyway hope this helps confuse you less with what I am trying to do. Should have 2.5 in and testing withing about an hour or so. Thanks for all the help Greg and for this wonderful contrib!

Edited by jwbonow

Share this post


Link to post
Share on other sites

Hi Joe,

 

I'd need to think more maybe, but somewhat in relation to my previous thoughts, is that currently as long an IPN has been received then the cart is reset, whereas a better extended approch would be to in catalog/includes/modules/payment/paypal/classes/paypal_order.class.php in the check_order_status function would be to there also detemine the paypal.payment_status and only reset the cart if that status is Completed or Pending.

 

Additionally a new 'order status' could be made for failed orders, so that when an IPN is received with a paypal.payment_status of for example 'declined' that order's order status could be set to the new 'failed order status', (quickly thinking) that corresponding orders_session_info could then be deleted, and if the customer did select another method of payment then that order will result in that payment methods order status (assuming they were succesfully in the other method).

 

A cron job could then be used to automatically delete all orders with a 'failed order status' after 4 days, this way the crom job is not specifically looking for orders with paypal.payment_status since the customer could of completed that order via another method.

 

Trying to customize the response to the customer upon their return is a bit tricky for two reasons I can forsee so far, IPNs are not always received prior to the customers return, this has some bearing on downloadable media which is expected to become available, there is another method where PayPal returns the customer with a digest transaction identifier but this should not be used to govern the status of an order, which makes things a little twisted since this identifier could be used to determine the status of the payment, but if it is successful then a race condition occurs between it and the actual IPN, so (quickly thinking) a test could be made to see whether the ipn has been received and if not use the passed trans_id to query PayPal, and only use this to determine whether the payment had failed or was declined, if so ask them to retry, if it was successful or pending I would not update the order until the IPN was received so it would be better to have to generic text requesting the customer to check their account history (assuming the ipn had not been recieved).

 

I need a break for awhile so will think about it.

 

In regard to upgrading from 2.3, would probably be ok to just go for 2.5.


"Any fool can know. The point is to understand." -- Albert Einstein

Share this post


Link to post
Share on other sites

Hi Greg,

Thanks for the help, again. Yes my intent on responses was to use the standard checkout_sucess text if the ipn returned completed. Upon denied or failed I would notify the customer of tis and provide a link back to the checkout_payment page (in which case the information was held in the shopping cart still) or allow the customer to change the contents of the shopping cart and then checkout again. In the case of pending received I suggest to the customer that the order is still pending verification of payment please check back. Anyway Ill get into 2.5 in a bit here, check my processes again then pass on the code which may or may not be of use to anyone at this point. :D

 

The cronjob idea would certainly be workable also, plus as I have sat and thought it may be best to leave the failed/denied orders in place for a bit so they might have an option to pay for them just by clicking on them/link in the account history page. Well back to upgrading and coding I'll post and letoyu all know how it works for me sometime tommorow it looks like. Thanks again.

 

By the way I didn't mean to make you think so hard Greg.

Edited by jwbonow

Share this post


Link to post
Share on other sites

Hi Joe,

 

I discovered a few things wrong with the v2.5 upload and have resolved them so will upload again in a few minutes with info on the fixing etc.... Its not often (recently) for me to have made such a bobo, but it has helped to identify some more food for thought.


"Any fool can know. The point is to understand." -- Albert Einstein

Share this post


Link to post
Share on other sites

I am a bit stuck here now.

 

I managed after lots of sweat to install the 2.4 version [i am not a programmer at all]

 

And now i read about the 2.5 version.

I tried to upgrade again, but i don't understand it anymore.

Am i supposed to undo all the stuff that i added from the 2.4 and then do the new 2.5 or do i need to add certain things from the 2.5 on top of the older one since some of the steps seem the same , while others are different.

 

Please help , since i started editing but halfway i got completely stuck :(

 

Isn't there a file which explains how to work when upgrading from 2.4 [hope so, cause i can see a raincloud coming up]

 

Thanks

Share this post


Link to post
Share on other sites

Hi Greg,

 

thanks for the new aupdate. Works so far (as I can say)

 

One thing that is not clear to me. The Cart Test On/Off. If I have it set to on and purchase something and return I see in the Admin/PayPal the status completed.

 

But not in the order (not automatically set to the defined status)

 

But if I simply set the cart Test to off everything works fine and also within the order the status is set correct.

 

Am I thinking wrong when I assume it should set in both cases the status automatically?

 

Pls help

Kai

Share this post


Link to post
Share on other sites

I just upgraded from 2.4 to 2.5 today and when I am finishing the order and arrive at the checkout_process.php page, I get this error:

 

1054 - Unknown column 'firstname' in 'field list'

 

insert into orders_session_info (sendto, billto, firstname, lastname, language, currency, content_type, txn_signature, orders_id) values ('5', '5', 'Eric', 'Poulos', 'english', 'USD', 'physical', 'a830e29e6a735d9731cfe11ea6a75df2', '11')

 

[TEP STOP]

 

but the order still goes through. Please help. I also replaced the files with the 2.5a files and added the include(DIR_FS_CATALOG_MODULES . 'payment/paypal/admin/orders.inc.php'); line around line 173 in admin/orders.php even though my files are heavily modified.

 

 

Thanks,

Eric

Share this post


Link to post
Share on other sites

Hi Eric,

 

I had the same and discovered that the tables had changed.

 

Because I had not really critical open data in my tabled I decided to just run the sql file - now it works fine.

Share this post


Link to post
Share on other sites

There is now a v2.5a with the corrections I discovered that were neccessary (I didn't go as far as testing synchronization).

 

PVK (and others), per FAQ-comments about upgrading from 2.4:

  • Uninstall the PayPal Payment Module in the admin section
     
     
  • Alter the table: orders_session_info table with the folowing:
     
    ALTER TABLE `orders_session_info` ADD `txn_signature` VARCHAR( 32 ) NOT NULL ;
     
     
  • Delete the directory catalog/includes/modules/payment/paypal, copy over all of the files found included with this contribution version(v2.5)
     
     
  • Now go directly to Step 2 and also follow through steps 3 and 4, all the edits in step 3 must be performed, the account_history_info edits are for those using invoice synchronization.

 

You need go through all the edits since things have changed slightly (hopefully for the better) and just replace your existings bits with the what is there.

 

One extra note, you now no longer need to include anything in admin/includes/database_tables.php so this can be removed.

 

The way the contrib is structed is so that any core contrib files can be easily replaced since they are all located (where and when possible) in the catalog/includes/modules/payment/paypal/ directory, so this directory can be deleted and replaced with the new one. But the edits per install docs must be done.

 

I've also commented on how to fix upgrading from v2.5 to v2.5a, really it is just a matter of copying and pasting but there is one dit required in admin/orders.php - see the contrib section for clearer details.

 

saletco

Yeah I just noticed that myself it is because the IPN get stored regardless of whether the cart total is correct or not, but the order itself is not updated eg, no products substracted and the customer is not notified. The reason the ipn status is updated is because this happens as soon as the ipn is inserted.

 

To prevent any invalid cart total ipns from being stored a change that could in catalog/ipn.php is

    //Check that txn_id has not been previously processed

    if ($ipn->unique_txn_id()) {

      $ipn->insert_ipn_txn();

      tep_db_query("update " . TABLE_ORDERS . " set paypal_ipn_id = '" . (int)$ipn->id() . "' where orders_id = '" . (int)$orders_id . "'");

      tep_db_query("delete from " . TABLE_CUSTOMERS_BASKET . " where customers_id = '" . (int)$order->customer['id'] . "'");

      tep_db_query("delete from " . TABLE_CUSTOMERS_BASKET_ATTRIBUTES . " where customers_id = '" . (int)$order->customer['id'] . "'");

      if ($ipn->key['payment_status'] == 'Completed' && $ipn->valid_payment($txn_signature) ) {

        include(DIR_WS_MODULES . 'payment/paypal/catalog/checkout_update.inc.php');

      }

To:

    //Check that txn_id has not been previously processed

    if ($ipn->unique_txn_id() && $ipn->valid_payment($txn_signature)) {

      $ipn->insert_ipn_txn();

      tep_db_query("update " . TABLE_ORDERS . " set paypal_ipn_id = '" . (int)$ipn->id() . "' where orders_id = '" . (int)$orders_id . "'");

      tep_db_query("delete from " . TABLE_CUSTOMERS_BASKET . " where customers_id = '" . (int)$order->customer['id'] . "'");

      tep_db_query("delete from " . TABLE_CUSTOMERS_BASKET_ATTRIBUTES . " where customers_id = '" . (int)$order->customer['id'] . "'");

      if ($ipn->key['payment_status'] == 'Completed' ) {

        include(DIR_WS_MODULES . 'payment/paypal/catalog/checkout_update.inc.php');

      }

BUT this will mean that the order will still exist in the customers cart.

However with the new IPN/order association method (md5 digest) and that the currency/total check no longer seems to cause any problems (?), I think the above might suffice?

 

Cocaberry

Perform the following via phpMyAdmin

ALTER TABLE `orders_session_info` ADD `firstname` VARCHAR( 32 ) NOT NULL ;

ALTER TABLE `orders_session_info` ADD `lastname` VARCHAR( 32 ) NOT NULL ;

 

Have to go now been 2 days on this so need to go, did I mention I do this for pleasure, please (all) use the donation button, keeps things motivated.


"Any fool can know. The point is to understand." -- Albert Einstein

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
Sign in to follow this  

×