1

We have a problem with "sort order" of IPN requests from PayPal. PayPal sends two IPN requests to some of our orders (that were created at external POS). First is "pending" and second is "complete", but our server sometimes receives these requests in reverse order. So we are receiving something like:

[04/Sep/2018:07:13:55 +0000] <= time when server receives first IPN

...
payment_date=23:52:21 Sep 03, 2018 PDT <= payment time
payment_status=Completed
...

[04/Sep/2018:07:14:04 +0000] <= time when server receives second IPN

...
payment_date=23:52:13 Sep 03, 2018 PDT <= payment time
payment_status=Pending
...

Problem is that first IPN setup the order state to "Processing" and second IPN changes the order state back to "Pending Payment" - so admin does not know that order is paid. We are using standard Mage_PayPal (but maybe some 3rd party module rewrites them, I am not sure now).

I would like to ask you, Is there anyone who has meets this problem? Is the changing the order state to "Pedning Payment" a standard behaviour? Any idea how to solve it?

Very thank you.

1 Answer 1

0

We created a workaround by rewriting class Mage_Paypal_Model_Ipn. So that if the server receives "pending" IPN after "complete" IPN, then "pending" IPN will be only stored into the transaction collection, but order state will not be changed. Checking is done by compare "parent_txn_id". We done it by follows:

    /**
     * Process payment pending notification
     *
     * @throws Exception
     */
    public function _registerPaymentPending()
    {
        $transactionId = $this->getRequestData('txn_id');

        if ($this->_isAlreadyPaidByTransaction($transactionId)) {

            $this->_order->getPayment()
                ->setTransactionId($transactionId)
                ->setIsTransactionClosed(0)
                ->addTransaction(Mage_Sales_Model_Order_Payment_Transaction::TYPE_AUTH, $this->_order)
                ->save();

            return;
        }

        parent::_registerPaymentPending();
    }

    /**
     * Order is get from $this->_order.
     * Order is already paid by trasnaction when
     *  - is paid => all is invoiced (nothing is refunded)
     *  - is there only one transaction with txn_type=capture and parent_txn_id=$transactionId
     *
     * @param string $transactionId
     * @return bool
     */
    protected function _isAlreadyPaidByTransaction($transactionId)
    {
        if (!$transactionId || !$this->_order) {
            return false;
        }

        if ($this->_order->getBaseTotalDue() > 0) {
            // Order is not completely paid.
            return false;
        }

        $payments = $this->_order->getAllPayments();

        if (count($payments) !== 1) {
            // Hmm, too many payments, I don't know how to decide about "already paid"
            return false;
        }

        /** @var Mage_Sales_Model_Order_Payment $payment */
        $payment = reset($payments);

        /** @var Mage_Sales_Model_Order_Payment_Transaction $transaction */
        $transaction = $payment->lookupTransaction("", Mage_Sales_Model_Order_Payment_Transaction::TYPE_CAPTURE);

        return $transaction && ($transaction->getParentTxnId() === $transactionId);
    }

It is not the nicest solution but should help.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.