0
votes

I am using the PayPal IPN simulator here: https://developer.paypal.com/webapps/developer/applications/ipn_simulator

to send information to an application built with symfony2 and payum bundle (older version of symfony and bundle).

It is definitely getting to the application at the notify URL (so not a firewall issue) because a record is stored in the database with the payment name and the date. However there are no 'details' stored.

However, if I use a Rest Client to POST to a URL with data, as suggested here: https://developer.paypal.com/docs/classic/ipn/integration-guide/IPNIntro/#id08CKFJ00JYK

Then the record is stored with payment name and date and details!!

Is this an issue with the IPN simulator? I'm really not sure what is going on here, maybe I could try and log the request object somehow?

1
Hi! did you get to resolve this issue at all? I am struggling with IPN listener and I just don't get any request detail from Paypal at all in the object. It is just Payum\Core\Request\Notify with payment token entity init =(hsb1007
Hey, this was a long time ago so I can't completely remember what I did, but I remember fixing it somehow. I think it involved needing to change some of the settings on the Paypal side. I'll try see if I can find outtimhc22
@hsb1007 check my answertimhc22

1 Answers

0
votes

@hsb1007 I think this was what I used finally. But I'm pretty sure there was some settings on the paypal side which was the main issue. I just remember doing lots and lots of testing and waiting

<?php
namespace LabIT\CMSBundle\EventListener;

use Buzz\Client\ClientInterface;
use Exception;
use LabIT\CMSBundle\Entity\Payments\DetailsInterface;
use LabIT\CMSBundle\Helper\ApiHelper;
use LabIT\CMSBundle\Helper\PaymentHelper;
use LabIT\CMSBundle\Helper\SubscriptionHelper;
use LabIT\CMSBundle\Helper\UserHelper;
use Payum\Core\Action\PaymentAwareAction;
use Payum\Core\Exception\RequestNotSupportedException;
use Payum\Core\Request\Notify;
use Payum\Paypal\Ipn\Api;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
use Symfony\Component\HttpKernel\Log\LoggerInterface;

class PaymentListener extends PaymentAwareAction
{
/**
 * @var UserHelper
 */
protected $userHelper;
/**
 * @var PaymentHelper
 */
protected $paymentHelper;

/**
 * @var ApiHelper
 */
protected $apiHelper;

/**
 * @var SubscriptionHelper
 */
protected $subscriptionHelper;

/**
 * @var LoggerInterface
 */
protected $logger;
/**
 * @var
 */
protected $buzz;
/**
 * @var
 */
protected $sandbox;
/**
 * @var
 */
protected $paypalValidation;

/**
 * @param UserHelper $userHelper
 * @param PaymentHelper $paymentHelper
 * @param ApiHelper $apiHelper
 * @param SubscriptionHelper $subscriptionHelper
 * @param LoggerInterface $logger
 * @param ClientInterface $buzz
 * @param $sandbox
 * @param $paypalValidation
 */
public function __construct(
    UserHelper $userHelper,
    PaymentHelper $paymentHelper,
    ApiHelper $apiHelper,
    SubscriptionHelper $subscriptionHelper,
    LoggerInterface $logger,
    ClientInterface $buzz,
    $sandbox,
    $paypalValidation
) {
    $this->userHelper = $userHelper;
    $this->paymentHelper = $paymentHelper;
    $this->apiHelper = $apiHelper;
    $this->subscriptionHelper = $subscriptionHelper;
    $this->logger = $logger;
    $this->buzz = $buzz;
    $this->sandbox = $sandbox;
    $this->paypalValidation = $paypalValidation;
}

/**
 * {@inheritDoc}
 *
 * This is where all the IPNs from paypal get processed, acts in some ways like a controller
 *
 * @param Notify $request
 */
public function execute($request)
{
    $data = $_POST;

    // would be better to get this dynamically. It is the payment name defined in config,
    // but also forms part of the url set in the paypal notification backend
    $paymentName = 'post_a_job_with_paypal'; // todo maybe get this from the url

    $this->logger->notice('IPN received');
    // validate with paypal so it stops notifying (do this first because needs to be done within 30 seconds)
    if (true === $this->paypalValidation) {
        $this->validateWithPaypal($this->getPaypalArray());
    }

    $notificationDetails = $this->paymentHelper->createPaymentNotification($paymentName, $data);

    // todo other inspections of data? check email?

    $user = $this->paymentHelper->getNotificationUser($notificationDetails, $data);

    // these are only done for individual transactions //TODO STORE TRANSACTIONS IN TABLE?
    if (isset($data['txn_id'])) {
        $this->paymentHelper->getTransactionProcessed($data['txn_id']); // so don't process more than once //TODO ADD BACK IN AFTER ADDING TRANSACTION CLASS
        $this->subscriptionHelper->determineUserMembership($user, $notificationDetails); // automatically demote if payment fails
        $this->apiHelper->sendPaymentNotifications($user, $notificationDetails); // notify affiliates
        $this->paymentHelper->setTransactionProcessed($data['txn_id']); //set transaction to processed //TODO ADD BACK IN AFTER ADDING TRANSACTION CLASS
    }

    // handle recurring payment data (recurring payment info, but not recurring payment transaction
    if (isset($data['recurring_payment_id']) && !isset($data['txn_id'])) {
        $this->paymentHelper->setRecurringPaymentStatus($data);
        // cron job will determine user membership level because needs to check timestamp
    }
}
/**
 * {@inheritDoc}
 */
public function supports($request)
{
    return $request instanceof Notify;
}

/**
 * Send data back to paypal so paypal knows it was delivered successfully
 *
 * @param array $data
 *
 * @throws Exception
 */
protected function validateWithPaypal(array $data)
{
    $this->logger->notice('I am here');

    $options = array();
    $options['sandbox'] = $this->sandbox;
    $api = new Api($this->buzz, $options);

    // Verify the IPN via PayPal
    if (Api::NOTIFY_VERIFIED !== $api->notifyValidate($data)) {
        $this->logger->notice('paypal validation UNSUCCESSFUL');
        throw new Exception('Invalid IPN');
    }

    $this->logger->notice('paypal validation SUCCESSFUL');
    return;
}

/**
 * @return array
 */
protected function getPaypalArray()
{
    // Read POST data
    // reading posted data directly from $_POST causes serialization
    // issues with array data in POST. Reading raw POST data from input stream instead.
    $raw_post_data = file_get_contents('php://input');
    $raw_post_array = explode('&', $raw_post_data);
    $myPost = array();
    foreach ($raw_post_array as $keyval) {
        $keyval = explode ('=', $keyval);
        if (count($keyval) == 2)
            $myPost[$keyval[0]] = urldecode($keyval[1]);
    }
    return $myPost;
}