"A successful Billing Agreement has already been created for this token."

316 Views Asked by At

I'm trying to set up recurring payments with Payum Bundle in Symfony. There needs to be the possibility for multiple recurring payments in one order and judging by the Paypal Sandbox dashboard, since the PROFILE_START_DATE is DATE_ATOM the initial payments go through, even if there are multiple items but when I look in Phpmyadmin, only one entry for RecurringPaymentDetails will have "ACK": "Success" and the rest will fail with A successful Billing Agreement has already been created for this token.

I have an OrderController which handles the logic, it sets the values of an entity that extends ArrayObject

/**
 * @Route("/accounts/order/paypal/completed", name="order_paypal_completed")
 */
public function orderPaypalCompletedAction(Request $request)
{
    $token = $this->get('payum')->getHttpRequestVerifier()->verify($request);

    $identity = $token->getDetails();
    $payment = $this->get('payum')->getStorage($identity->getClass())->find($identity);

    $gateway = $this->get('payum')->getGateway($token->getGatewayName());
    $gateway->execute($status = new GetHumanStatus($token));

    $order = $payment->getOrder();

    if ($status->isCaptured() || $status->isAuthorized()) {
        $order->setStatus(Order::STATUS_COMPLETED);

        $agreement = $status->getModel();
        $storage = $this->get('payum')->getStorage(RecurringPaymentDetails::class);
        $payments = [];
        foreach ($order->getItems() as $item) {
          $payment = $storage->create();
          $payment['TOKEN'] = $agreement['TOKEN'];
          $payment['DESC'] = $agreement['L_BILLINGAGREEMENTDESCRIPTION0'];
          $payment['EMAIL'] = $agreement['EMAIL'];
          $payment['AMT'] = $item->getPrice();
          $payment['CURRENCYCODE'] = $order->getCurrency();
          $payment['BILLINGFREQUENCY'] = $item->getDuration();
          $payment['PROFILESTARTDATE'] = date(DATE_ATOM);
          $payment['BILLINGPERIOD'] = Api::BILLINGPERIOD_DAY;

          $payments[] = $payment;
        }
        $this->addFlash('success', $this->get('translator')->trans('Payment has been successful.'));
    }

    if ($status->isPending()) {
        $this->addFlash('danger', $this->get('translator')->trans('Payment has been canceled.'));
    }

    if ($status->isFailed() || $status->isCanceled()) {
        $order->setStatus(Order::STATUS_CANCELED);
        $this->addFlash('danger', $this->get('translator')->trans('Payment has been canceled.'));
    }
    foreach ($payments as $payment) {
      $gateway->execute(new CreateRecurringPaymentProfile($payment));
      $gateway->execute(new Sync($payment));
      $recurringPaymentStatus = new GetHumanStatus($payment);
      $gateway->execute($recurringPaymentStatus);
    }

    try {
        $em = $this->getDoctrine()->getManager();
        $em->persist($order);
        $em->flush();
    } catch (\Exception $e) {
        $this->addFlash('danger', $this->get('translator')->trans('An error occurred when saving object.'));
    }
    return $this->redirectToRoute('homepage');
}

With this, I feel like, if there can only be one token returned from paypal, I'd have to redirect them back to Paypal for each item which is nonsense. Is there a way I can duplicate the token for each item or what do you suggest?

1

There are 1 best solutions below

0
xeon826 On

Looking around, I find this so apparently I have to redirect them to Paypal for each subscription. A bit arduous but it's the only way apparently.

Edit: I spoke to soon, that issue pertains to different types of billing agreements in the same checkout, mine is for multiple billing agreements with the same conditions.