8

I'm trying to use JMSPaymentCoreBundle with JMSPaymentPaypalBundle and I can't find a clear example anywhere on how to do it.

I've done all steps specified in the documentation and I'm not able to get it working. Can anybody help me please?

Danny Beckett
  • 20,529
  • 24
  • 107
  • 134
Xavi
  • 205
  • 6
  • 12

2 Answers2

19

Payum bundle supports jms payments via the bridge. The links describes how to get started.

Usage of the bundle gives you several advantages:

  • Secured capture action.
  • Have credit card form, can ask user for credit card
  • Ability to easy setup IPN. Notify action is also secured.
  • Built-in support of all omnipay gateways (25 +), jms plugins (+ 10) and payum native libs.
  • Payum paypal lib supports recurring payment and digital goods out of the box.
  • Storages integrated into payment process so you do not have worry about data that might be lost.
  • Domain friendly. Indeed Payum provide some models but it does not restrict you to use them.
  • It already supports PSR-0 logger. In dev it logs executed payum actions, to easy debug (Visit symfony profile logs tab).
  • It is possible setup several payments (one paypal account for EU and one for US for example)
  • Extremely customizable. Add your custom payum actions, or extensions, or storages.
  • There is a symfony sandbox (code|web) to help you to start.

P.S. It is not the full list of features.

Maksim Kotlyar
  • 3,821
  • 27
  • 31
8

The default way to create a payment instruction is through the jms_choose_payment_method form:

$form = $this->getFormFactory()->create('jms_choose_payment_method', null, array(
        'amount'   => 12.99,
        'currency' => 'EUR',
        'default_method' => 'payment_paypal', // Optional
        'predefined_data' => array(
            'paypal_express_checkout' => array(
                'return_url' => $this->get('router')->generate('payment_complete', array(
                    'number' => $order->getOrderNumber(),
                ), true),
                'cancel_url' => $this->get('router')->generate('payment_cancel', array(
                    'number' => $order->getOrderNumber(),
                ), true)
            ),
        ),
    ));

You can also create a payment instruction manually:

        use JMS\Payment\CoreBundle\Entity\ExtendedData;
        use JMS\Payment\CoreBundle\Entity\Payment;
        use JMS\Payment\CoreBundle\PluginController\Result;
        use JMS\Payment\CoreBundle\Plugin\Exception\ActionRequiredException;
        use JMS\Payment\CoreBundle\Plugin\Exception\Action\VisitUrl;
        use JMS\Payment\CoreBundle\Entity\PaymentInstruction;


        $extendedData = new ExtendedData();
        $extendedData->set('return_url', $this->get('router')->generate('payment_complete', array(
                'number' => $order->getOrderNumber(),
            ), true));

        $extendedData->set('cancel_url', $this->get('router')->generate('payment_cancel', array(
                'number' => $order->getOrderNumber(),
            ), true));

        $instruction = new PaymentInstruction((float)$order->getCharge() > 0 ? $order->getCharge() : $order->getAmount(), 'EUR', 'paypal_express_checkout', $extendedData);
        $this->get('payment.plugin_controller')->createPaymentInstruction($instruction);

        $order->setPaymentInstruction($instruction);
        $em = $this->get('doctrine.orm.entity_manager');
        $em->persist($order);
        $em->flush();

My payment_complete route looks like:

public function completeAction(Booking $order)
{
    $instruction = $order->getPaymentInstruction();
    if (($instruction->getAmount() - $instruction->getDepositedAmount()) > 0) {
        if (null === $pendingTransaction = $instruction->getPendingTransaction()) {
            $payment = $this->get('payment.plugin_controller')->createPayment($instruction->getId(), $instruction->getAmount() - $instruction->getDepositedAmount());
        } else {
            $payment = $pendingTransaction->getPayment();
        }

        $result = $this->get('payment.plugin_controller')->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());
        }
    }

    $order->setTransactionAmount((float)$order->getAmount());
    $creditPurchased = (float)$order->getCharge() > (float)$order->getAmount() ? (float)$order->getCharge() - (float)$order->getAmount() : 0;
    $em->persist($order);
    $em->flush();

I've got it running going through http://jmsyst.com/bundles/JMSPaymentCoreBundle/master/usage

hacfi
  • 756
  • 3
  • 7
  • I need just a form where you can say the amount you want to pay and a "pay now" button.. :D I think i'm not understanding what's exactly the data flow for all this payment bundle. Why a payment instruction is NOT the same as an order?? is this correct? 1- Render a form with an input to write the amount (creating and flushing an order). 2- Render (inside the previous form) the payment_details route too with the "choose payment method" form, submitting the post data and the orderNumber. 3- Update the Order entity and flush everything else. – Xavi Mar 04 '13 at 13:37