We will set up JMSPaymentCoreBundle in order to manage different types of payment. We will install the paypal bundle, but you can make your own plugin to manage credit cards.
/* Bundle configuration with Symfony 2.1 */
"sensio/framework-extra-bundle": "2.1.x-dev", "jms/security-extra-bundle": "1.2.*", "jms/di-extra-bundle": "1.1.*", "jms/payment-paypal-bundle": "*", "jms/payment-core-bundle": "dev-master", //appKernel new Sensio\Bundle\FrameworkExtraBundle\SensioFrameworkExtraBundle() , new JMS\DiExtraBundle\JMSDiExtraBundle($this), new JMS\SecurityExtraBundle\JMSSecurityExtraBundle(), new JMS\Payment\CoreBundle\JMSPaymentCoreBundle(), new JMS\Payment\PaypalBundle\JMSPaymentPaypalBundle(), //Here it is for the config.yml file: sensio_framework_extra: view: annotations: false jms_payment_core: secret: 0123 jms_payment_paypal: username: yourmail@domain.com password: 13554848 signature: LbGakzdnaokndand debug: true jms_di_extra: locations: all_bundles: false bundles: [HereYourAppBundle] directories: ["%kernel.root_dir%/../src"] automatic_controller_injections: properties: request: "@request" router: "@router" method_calls: setRouter: ["@router"]
Install the bundles via
php composer.phar update
and don’t forget to update the database
php app/console doctrine:schema:update --force
First of all, you have to register on https://developer.paypal.com/
You can see the whole paypal documentation here ( Paypal Doc )
When you are logged in, you can see your API Credentials by clicking in Api and Payement Credentials on the left menu. You have to set your name,password and signature in your config.yml
jms_payment_paypal: username: yourmail@domain.com password: 13554848 signature: LbGakzdnaokndand debug: true
Then go to « tests accounts ». You can create a new one by selecting « preconfigured ». Now fill the fields and choose « buyer », put some money on your bank account and the most important: copy past the generated password. Now create your account( it takes a long time with me… ) You can see your new fake buyer account and the associated email address.
This is the account you have to use when you are redirected to sandbox.paypal.com from your website.
Now, the order class, twig and the controller.
On the JMSPaymentCoreBundle, you can see an order class. You should use it or use your own and adding a paymentInstruction attribute, getters and setters.
JMSPaymentCoreBundle Class , and don’t forget the use instructions..
Your Order Class use JMS\Payment\CoreBundle\Entity\PaymentInstruction; /** * @ORM\OneToOne(targetEntity="JMS\Payment\CoreBundle\Entity\PaymentInstruction") */ private $paymentInstruction;
I modified a little bit the examples to fit my wish.
It’s important to understand this class, because, when you get an error, you just have a » Transaction was not successful » message..
class PaiementController extends Controller { /** @DI\Inject */ private $request; /** @DI\Inject */ private $router; /** @DI\Inject("doctrine.orm.entity_manager") */ private $em; /** @DI\Inject("payment.plugin_controller") */ private $ppc; /** * @Route("/{id}", name="paiement") * @Template() */ public function paymentAction($id=0) // this is a personnal ID i pass to the controler to identify the previous shopping cart { $form = $this->getFormFactory()->create('jms_choose_payment_method', null, array( 'amount' => $order->getPrice(), 'currency' => 'EUR', 'default_method' => 'payment_paypal', // Optional 'predefined_data' => array() )); if ('POST' === $this->request->getMethod()) { $form->bindRequest($this->request); $order = new Order(); $this->em->persist( $order); $this->em->flush( $order); $form = $this->getFormFactory()->create('jms_choose_payment_method', null, array( 'amount' => $order->getPrice(), 'currency' => 'EUR', 'default_method' => 'payment_paypal', // Optional 'predefined_data' => array( 'paypal_express_checkout' => array( 'return_url' => $this->router->generate('payment_complete', array( 'id' =>$order->getId() ), true), 'cancel_url' => $this->router->generate('payment_cancel', array( 'id' => $order->getId() ), true) ), ), )); $form->bindRequest($this->request); // Once the Form is validate, you update the order with payment instruction if ($form->isValid()) { $instruction = $form->getData(); $this->ppc->createPaymentInstruction($instruction); $order->setPaymentInstruction($instruction); $this->em->persist($order); $this->em->flush($order); // now, let's redirect to payment_complete with the order id return new RedirectResponse($this->router->generate('payment_complete', array('id' => $order->getId() ))); } } return $this->render('YourBundle:Paiement:paymentChooseTemplate.html.twig',array('form' => $form->createView() , 'id' => $id)); }
/** * @Route("/complete/{id}", name = "payment_complete") */ public function completeAction($id=0) // id of the order { if ( $id != 0 ){ $order = $this->getDoctrine()->getRepository("YourBundle:order")->find($id);} $instruction = $order->getPaymentInstruction(); if (null === $pendingTransaction = $instruction->getPendingTransaction()) { $payment = $this->ppc->createPayment($instruction->getId(), $instruction->getAmount() - $instruction->getDepositedAmount()); } else { $payment = $pendingTransaction->getPayment(); } $result = $this->ppc->approveAndDeposit($payment->getId(), $payment->getTargetAmount()); if (Result::STATUS_PENDING === $result->getStatus()) { $ex = $result->getPluginException(); if ($ex instanceof ActionRequiredException) { $action = $ex->getAction(); if ($action instanceof VisitUrl) { return new RedirectResponse($action->getUrl()); } throw $ex; } } else if (Result::STATUS_SUCCESS !== $result->getStatus()) { throw new \RuntimeException('Transaction was not successful: '.$result->getReasonCode()); } // if successfull, i render my order validation template return $this->render('YourBundle:Paiement:validation.html.twig',array('order'=>$order )); } /** @DI\LookupMethod("form.factory") */ protected function getFormFactory() { } /** * @Route("/cancel", name = "payment_cancel") */ public function CancelAction( ) { $this->get('session')->getFlashBag()->add('info', 'Transaction annulée.'); return $this->redirect($this->generateUrl('yourTemplate')); } }
If the payment succeded, you can see useful informations about it in Payments table. You can see the deposited amount, the state of the payment etc..
A really basic twig for paymentChooseTemplate; It just chow A Paypal radio Button:
{% extends "::layout.html.twig" %} {% block body %} <div class="container"> <form action="{{ path('paiement' , {'id': id } ) }}" method="post"> {{ form_widget(form) }} <input type="submit" /> </form> {% endblock %}
Thanks for the article. Unfortunately there is not much iformación regarding this « bundle » and has been fortunate that you shared your knowledge.
greetings
Bonjour,
Merci pour votre article. Il serait possible de fournir un exemple pour le téléchargement?
Excusez mon français …
Merci
Bonjour à tous,
J’ai bien implémenté le bundle mais il y’a un problème que je n’arrive pas à résoudre.
Comment est-il possible de customizé le form pour qu’il ne ressemble pas à une choice list en anglais mais un simple boutton paypal paiement par exemple.
Mercie à vous
Hi! I’m getting « The requested package jms/payment-paypal-bundle could not be found in any version, there may be a typo in the package name. » and i have copy-pasted the code. I don’t know what i’m doing wrong… any help please???
ok, my fault, sorry.
salut
merci pour ce tutoriel, mais je suis bloquer au point où il faut modifier l’order class et le paiement controlller , les ources du bundle que j’ai trouvé sont ici https://github.com/schmittjoh/JMSPaymentCoreBundle
mais je trouve pos les controlleur….
Bonjour,
Je suis novice sur Symfony2 et je travaille sur Mac OS X 10.9. Actuelle, je travaille sur un site commerce et j’ai donc besoin de ce bundle. Je bloque dès le début de ce tuto, quand je mets les 5 premiers lignes dans composer.json, voici l’erreur que j’ai:
Problem 1
– Installation request for jms/payment-core-bundle dev-master -> satisfiable by jms/payment-core-bundle[dev-master].
– jms/payment-core-bundle dev-master requires ext-mcrypt * -> the requested PHP extension mcrypt is missing from your system.
Problem 2
– jms/payment-core-bundle 1.0.x-dev requires ext-mcrypt * -> the requested PHP extension mcrypt is missing from your system.
– jms/payment-core-bundle 1.0.0 requires ext-mcrypt * -> the requested PHP extension mcrypt is missing from your system.
– jms/payment-paypal-bundle 1.0.0 requires jms/payment-core-bundle ~1.0 -> satisfiable by jms/payment-core-bundle[1.0.0, 1.0.x-dev].
– Installation request for jms/payment-paypal-bundle * -> satisfiable by jms/payment-paypal-bundle[1.0.0].
J’ai vérifié mon php.ini et j’ai bien cette ligne : extension=mcrypt.so.
Quand je vais dans phpInfo sur mamp, j’ai bien « mcrypt support: enabled » et « mcrypt_filter support: enabled ».
Quelqu’un aurai une idée pour résoudre ce problème?
As-tu fais un restart de ton serveur apache ?
Si tu es sur Windows il faut passer par le logiciel tierce (wamp, easyphp)
Si tu es sur Linux ou Mac tu peux executer la commande suivant :
apachectl restart
Bonjour !
Je suis à la recherche d’un Bundle qui me permettrait de gérer des paiements de services sur un site web réalisé sous SF2 via Paypal. Votre solution est-t-elle toujours compatible avec Paypal aujourd’hui ?
Cette solution est toujours active pour l’un de nos site oui.
Attention le bundle a du évoluer mais le principe est la.
Super pour les explications mais totalement nouveau… je ne vois pas quand je dois appeler paymentAction. J’ai tenté de comprendre la nouvelle doc mais … je cale un peu. http://jmsyst.com/bundles/JMSPaymentCoreBundle/master/usage
Dois-je faire un formulaire avec mes produits et sauvegarder en DB la ‘commande’ puis rediriger vers paymentAction ? Si oui à quoi ça sert de persister à nouveau la commande ?
Merci !!!
Bonsoir,
Je voudrais pouvoir valider le paiement des produits sur mon site e-commerce avec paypal. Mon controller Validation simule un faux paiement. Maintenant je voudrais pouvoir réaliser un vrai paiement avec paypal pour cela j’ai suivi les instructions dans votre tutoriel. j’ai remplacé mon controller validation par completeAction. Mais cette erreur:
Error: Call to a member function getPendingTransaction() on null
if (null === $pendingTransaction = $instruction->getPendingTransaction()) {
Sur le lien suivant il y a mon controller validation et le controller completeAction.
http://pastebin.com/VXqFskSj
Merci