I'm currently testing Express Checkout using the PayPal sandbox but when transactions undergo a payment review, PayPal sends an IPN with the same txn_id
as the subsequent IPN.
See below IPN chain:
payment_status=Pending
txn_id=6M061502SS003073U
pending_reason=paymentreview
payment_status=Pending
txn_id=6M061502SS003073U
pending_reason=authorization
payment_status=Pending
txn_id=5U160197RA036471T
pending_reason=paymentreview
payment_status=Completed
txn_id=5U160197RA036471T
This causes non-paymentreview IPN's to fail validation because the validate()
function in PayPalPaymentIPNController.inc checks whether the txn_id
has already been processed before.
The end result is that the payment never completes in the Drupal site because the completion IPN is never processed. Payments just remain stuck with a status of "Being reviewed for risk".
Comment | File | Size | Author |
---|---|---|---|
#10 | 2550693-10-paypal_payment_ipn-per-psiid.patch | 11.93 KB | torotil |
|
Comments
Comment #2
morbiD CreditAttribution: morbiD commentedAs far as I can see, there is no single identifier in an IPN that can be reliably used to test if the IPN has been processed already.
txn_id
can be shared by multiple IPN's and so, apparently, canipn_track_id
(ignoring the fact that it's documented as being for internal use only). I can't find any other suitable parameters either.It seems the only reliable way would be to track some combination of parameters such as
txn_id
,payment_status
andpending_reason
, which I guess would require modifications to the database schema.Comment #3
morbiD CreditAttribution: morbiD commentedI would tentatively say that this patch seems to solve the problem for me,
but I can't verify that the modified tests work since I seem to be having issues withEdit: looks like they do!drupal_http_request()
on my server.However, the problem this patch presents is that once the new columns are added to the database table, the existing table rows will be useless for validation and due to #2555297: IPN's always have pid's of 0 in database I don't think there's even a way to trace the old rows to specific payments and update the payment statuses in the rows accordingly.
Comment #4
morbiD CreditAttribution: morbiD commentedPrevious patch didn't contain documentation for the hook_update_N() implementation so here's an updated version.
Comment #5
torotil CreditAttribution: torotil at more onion commentedIMHO each paypal_payment_ipn should be linked to a payment_status_item [that should be created in the IPN request]. Then the whole issue is moot. Having the pending reason in there is nice anyway.
Comment #6
morbiD CreditAttribution: morbiD commented@torotil: I haven't done any work on this for nearly 18 months so I'm not that familiar with it any more, but I think you're right.
In fact, a couple of months after I wrote the patch in #3, I actually ended up linking paypal_payment_ipn and paypal_status_item together for #2569467: Record and display refund amounts, so your suggestion makes even more sense.
If I get a chance I'll try and update this issue with a new patch at some point.
Comment #7
torotil CreditAttribution: torotil at more onion commentedHere is my first attempt on implementing this. It changes paypal_payment_ipn to have the psiid as primary key. This makes it possible to have multiple IPNs per payment. For the sake of simplicity I've ignored #2569467: Record and display refund amounts for the while.
Comment #8
torotil CreditAttribution: torotil at more onion commentedAfter some more testing:
paypal_payment_pps_return()
Comment #9
morbiD CreditAttribution: morbiD commentedNot sure there's any point in keeping the
pending_reason
column in paypal_payment_ipn.If the IPN's status is "Pending" then
payment_status_item.status
will be derived fromPayPalPaymentIPNController::pendingStatusMap()
rather thanPayPalPaymentIPNController::statusMap()
, which means the paypal_payment_ipn'spending_reason
can always be inferred from the linked payment_status_item if I'm not mistaken.Comment #10
torotil CreditAttribution: torotil at more onion commentedYes, I agree. The information is redundant (except for 'authorization' and 'order' which point to the same status).
Here is an updated patch without that column. I've also added an additional update that deletes all the items with pid=0 from the table as they are pretty useless anyway. Without removing them we'd have duplicate entries for the new psiid primary key.
Comment #12
torotil CreditAttribution: torotil at more onion commented