Skip to content

Instantly share code, notes, and snippets.

@danvbe
Last active September 26, 2017 07:14
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save danvbe/79c7f557f37a473dedea to your computer and use it in GitHub Desktop.
Save danvbe/79c7f557f37a473dedea to your computer and use it in GitHub Desktop.
Sonata PayPal issue fix
<?xml version="1.0" ?>
<!-- Application\Sonata\PaymentBundle\Resources\config\payment.xml -->
<!-- TODO: Remember to load it in you app/config/config.yml -->
<container xmlns="http://symfony.com/schema/dic/services"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd">
<parameters>
<parameter key="sonata.payment.method.paypal.class">Application\Sonata\PaymentBundle\Component\Paypal</parameter>
</parameters>
</container>
<?php
/**
* Created by PhpStorm.
* User: danvbe
* Date: 7/25/14
* Time: 2:49 PM
*/
namespace Application\Sonata\PaymentBundle\Component;
use Sonata\Component\Payment\Paypal as BasePaypal;
use Sonata\Component\Order\OrderInterface;
use Sonata\Component\Payment\TransactionInterface;
class Paypal extends BasePaypal{
/**
* {@inheritdoc}
*/
public function sendbank(OrderInterface $order)
{
$params = array(
'order' => $order->getReference(),
'bank' => $this->getCode(),
'check' => $this->generateUrlCheck($order),
);
$fields = array(
// paypal specific
'cmd' => '_xclick',
'charset' => 'utf-8',
'business' => $this->getOption('account'),
'cert_id' => $this->getOption('cert_id'),
'no_shipping' => '1', // client cannot add shipping address
'lc' => 'EN', // user interface language
'no_note' => '1', // no comment on paypal
// invoice information
'invoice' => $order->getReference(),
//FIRST CHANGE IS HERE
'amount' => round($order->getTotalInc(),2),
//SECOND CHANGE IS HERE
'currency_code' => $order->getCurrency()->getLabel(),
'item_name' => 'Order ' . $order->getReference(),
'bn' => 'Sonata/1.0', // Assign Build Notation for PayPal Support
// user information, for prepopulated form (paypal side)
'first_name' => $order->getBillingName(),
'last_name' => '',
'address1' => $order->getBillingAddress1(),
'address2' => $order->getBillingAddress2(),
'city' => $order->getBillingCity(),
'zip' => $order->getBillingPostcode(),
'country' => $order->getBillingCountryCode(),
// Callback information
'custom' => $this->generateUrlCheck($order),
'notify_url' => $this->router->generate($this->getOption('url_callback'), $params, true),
// user link
'cancel_return' => $this->router->generate($this->getOption('url_return_ko'), $params, true),
'return' => $this->router->generate($this->getOption('url_return_ok'), $params, true),
);
if ($this->getOption('debug', false)) {
$html = '<html><body>' . "\n";
} else {
$html = '<html><body onload="document.getElementById(\'submit_button\').disabled = \'disabled\'; document.getElementById(\'formPaiement\').submit();">' . "\n";
}
$method = $this->getOption('method', 'encrypt');
$html .= sprintf('<form action="%s" method="%s" id="formPaiement" >' . "\n", $this->getOption('url_action'), 'POST');
$html .= '<input type="hidden" name="cmd" value="_s-xclick">' . "\n";
$html .= sprintf('<input type="hidden" name="encrypted" value="%s" />', call_user_func(array($this, $method), $fields));
$html .= '<p>' . $this->translator->trans('process_to_paiement_bank_page', array(), 'PaymentBundle') . '</p>';
$html .= '<input type="submit" id="submit_button" value="' . $this->translator->trans('process_to_paiement_btn', array(), 'PaymentBundle') . '" />';
$html .= '</form>';
$html .= '</body></html>';
if ($this->getOption('debug', false)) {
echo "<!-- Encrypted Array : \n" . print_r($fields, 1) . "-->";
}
$response = new \Symfony\Component\HttpFoundation\Response($html, 200, array(
'Content-Type' => 'text/html'
));
$response->setPrivate(true);
return $response;
}
/**
* {@inheritdoc}
*/
public function sendConfirmationReceipt(TransactionInterface $transaction)
{
if (!$transaction->isValid()) {
return new \Symfony\Component\HttpFoundation\Response('');
}
$params = $transaction->getParameters();
$params['cmd'] = '_notify-validate';
//$this->getLogger()->
/*
// retrieve the client
$client = $this
->getWebConnectorProvider()
->getNamedClient($this->getOption('web_connector_name', 'default'));
$client->request('POST', $this->getOption('url_action'), $params);
*/
//I HAVE USED CURL HERE TO MAKE IT WORK !
$ch = curl_init();
curl_setopt($ch,CURLOPT_URL, $this->getOption('url_action'));
curl_setopt($ch,CURLOPT_POST, true);
curl_setopt($ch,CURLOPT_POSTFIELDS, $params);
$result = curl_exec($ch);
//if ($client->getResponse()->getContent() == 'VERIFIED') {
if ($result == 'VERIFIED') {
$transaction->setState(TransactionInterface::STATE_OK);
$transaction->setStatusCode(TransactionInterface::STATUS_VALIDATED);
$transaction->getOrder()->setValidatedAt(new \DateTime);
$transaction->getOrder()->setStatus(OrderInterface::STATUS_VALIDATED);
$transaction->getOrder()->setPaymentStatus(TransactionInterface::STATUS_VALIDATED);
} else {
$transaction->setState(TransactionInterface::STATE_KO);
$transaction->setStatusCode(TransactionInterface::STATUS_ERROR_VALIDATION);
// TODO error in status -> setting payment status to an order status value
$transaction->getOrder()->setPaymentStatus(OrderInterface::STATUS_ERROR);
if ($this->getLogger()) {
$this->getLogger()->emergency('[Paypal::sendAccuseReception] Paypal failed to check the postback');
}
}
return new \Symfony\Component\HttpFoundation\Response('');
}
}
@piotr-galas
Copy link

Thank you so much. It work for me.

@helloma
Copy link

helloma commented Dec 13, 2014

Thank's a lot man

@lubo13
Copy link

lubo13 commented Sep 26, 2017

Hey, I think there is another way:

  1. Override Paypal Method
 parameters:
         sonata.payment.method.paypal.class: Application\Sonata\PaymentBundle\Paypal\Services\Paypal
  1. Create Listener on PaymentEvents::PRE_CALLBACK

use Sonata\Component\Payment\PaymentSelectorInterface;
use Buzz\Browser;

class PaymentSubscriber implements EventSubscriberInterface {

    /**
     *
     * @var BasePaypal 
     */
    private $browser;

    /**
     *
     * @var PaymentSelectorInterface 
     */
    private $selector;

    public function __construct(PaymentSelectorInterface $selector, Browser $browser) {
        $this->selector = $selector;
        $this->browser = $browser;
    }

    public static function getSubscribedEvents() {
        return array(
            PaymentEvents::PRE_CALLBACK => 'preCallback'
        );
    }

    /**
     * Set Browser in paypal payment method
     * 
     * @param PaymentEvent $event
     */
    public function preCallback(PaymentEvent $event) {
        if ($event->getTransaction()->getPaymentCode() == 'paypal') {
            $paypalMethod = $this->selector->getPayment($event->getTransaction()->getPaymentCode());
            $paypalMethod->setWebConnectorProvider($this->browser);
        }
    }

}
  1. Register subscriber
application.payment.listeners.payment_subscriber:
	class: Application\Sonata\PaymentBundle\Listeners\PaymentSubscriber
	arguments: ["@sonata.payment.selector.simple", "@sonata.payment.browser.curl"]
	tags:
		- { name: kernel.event_subscriber }
  1. In Paypal method
public function sendConfirmationReceipt(TransactionInterface $transaction) {
        if (!$transaction->isValid()) {
            return new Response('ko', 404, array(
                'Content-Type' => 'text/plain',
            ));
        }

        $params = $transaction->getParameters();
        $params['cmd'] = '_notify-validate';

        $browser = $this->getWebConnectorProvider()->submit($this->getOption('url_action'), $params);
        if ($browser->getContent() == 'VERIFIED') {
            $transaction->setState(TransactionInterface::STATE_OK);
            $transaction->setStatusCode(TransactionInterface::STATUS_VALIDATED);

            $transaction->getOrder()->setValidatedAt(new \DateTime());
            $transaction->getOrder()->setStatus(OrderInterface::STATUS_VALIDATED);
            $transaction->getOrder()->setPaymentStatus(TransactionInterface::STATUS_VALIDATED);
        } else {
            $transaction->setState(TransactionInterface::STATE_KO);
            $transaction->setStatusCode(TransactionInterface::STATUS_ERROR_VALIDATION);

            // TODO error in status -> setting payment status to an order status value
            $transaction->getOrder()->setPaymentStatus(OrderInterface::STATUS_ERROR);

            if ($this->getLogger()) {
                $this->getLogger()->emergency('[Paypal::sendAccuseReception] Paypal failed to check the postback');
            }
        }
        return new Response('ok', 200, array(
            'Content-Type' => 'text/plain',
        ));
    }

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment