src/Forms/PaymentForm.php
public function submitpayment($data, $form)
    {
        $data = $form->getData();

        $cancelUrl = $this->getFailureLink() ? $this->getFailureLink() : $this->controller->Link();

        $order = $this->config->getOrder();

        // final recalculation, before making payment
        $order->calculate();

        // handle cases where order total is 0. Note that the order will appear
        // as "paid", but without a Payment record attached.
        if ($order->GrandTotal() == 0 && Order::config()->allow_zero_order_total) {
            if (!$this->orderProcessor->placeOrder()) {
                $form->sessionMessage($this->orderProcessor->getError());
                return $this->controller->redirectBack();
            }
            return $this->controller->redirect($this->getSuccessLink());
        }

        // try to place order before payment, if configured
        if (Order::config()->place_before_payment) {
            if (!$this->orderProcessor->placeOrder()) {
                $form->sessionMessage($this->orderProcessor->getError());
                return $this->controller->redirectBack();
            }
            $cancelUrl = $this->orderProcessor->getReturnUrl();
        }

        // if we got here from checkoutSubmit and there's a namespaced Component that provides payment data,
        // we need to strip the inputs down to only the checkout component.
        $components = $this->config->getComponents();
        if ($components->first() instanceof CheckoutComponentNamespaced) {
            foreach ($components as $component) {
                if ($component->Proxy()->providesPaymentData()) {
                    $data = array_merge($data, $component->unnamespaceData($data));
                }
            }
        }

        $gateway = Checkout::get($order)->getSelectedPaymentMethod(false);
        $fieldFactory = new GatewayFieldsFactory($gateway);

        // This is where the payment is actually attempted
        $paymentResponse = $this->orderProcessor->makePayment(
            $gateway,
            $fieldFactory->normalizeFormData($data),
            $this->getSuccessLink(),
            $cancelUrl
        );

        $response = null;
        if ($this->controller->hasMethod('processPaymentResponse')) {
            $response = $this->controller->processPaymentResponse($paymentResponse, $form);
        } elseif ($paymentResponse && !$paymentResponse->isError()) {
            $response = $paymentResponse->redirectOrRespond();
        } else {
            $form->sessionMessage($this->orderProcessor->getError(), 'bad');
            $response = $this->controller->redirectBack();
        }

        return $response;
    }
public function submitpayment($data, $form)
    {
        $data = $form->getData();

        $cancelUrl = $this->getFailureLink() ? $this->getFailureLink() : $this->controller->Link();

        $order = $this->config->getOrder();

        // final recalculation, before making payment
        $order->calculate();

        // handle cases where order total is 0. Note that the order will appear
        // as "paid", but without a Payment record attached.
        if ($order->GrandTotal() == 0 && Order::config()->allow_zero_order_total) {
            if (!$this->orderProcessor->placeOrder()) {
                $form->sessionMessage($this->orderProcessor->getError());
                return $this->controller->redirectBack();
            }
            return $this->controller->redirect($this->getSuccessLink());
        }

        // try to place order before payment, if configured
        if (Order::config()->place_before_payment) {
            if (!$this->orderProcessor->placeOrder()) {
                $form->sessionMessage($this->orderProcessor->getError());
                return $this->controller->redirectBack();
            }
            $cancelUrl = $this->orderProcessor->getReturnUrl();
        }

        // if we got here from checkoutSubmit and there's a namespaced Component that provides payment data,
        // we need to strip the inputs down to only the checkout component.
        $components = $this->config->getComponents();
        if ($components->first() instanceof CheckoutComponentNamespaced) {
            foreach ($components as $component) {
                if ($component->Proxy()->providesPaymentData()) {
                    $data = array_merge($data, $component->unnamespaceData($data));
                }
            }
        }

        $gateway = Checkout::get($order)->getSelectedPaymentMethod(false);
        $fieldFactory = new GatewayFieldsFactory($gateway);

        // This is where the payment is actually attempted
        $paymentResponse = $this->orderProcessor->makePayment(
            $gateway,
            $fieldFactory->normalizeFormData($data),
            $this->getSuccessLink(),
            $cancelUrl
        );

        $response = null;
        if ($this->controller->hasMethod('processPaymentResponse')) {
            $response = $this->controller->processPaymentResponse($paymentResponse, $form);
        } elseif ($paymentResponse && !$paymentResponse->isError()) {
            $response = $paymentResponse->redirectOrRespond();
        } else {
            $form->sessionMessage($this->orderProcessor->getError(), 'bad');
            $response = $this->controller->redirectBack();
        }

        return $response;
    }
Behaviour can be overwritten by creating a processPaymentResponse method
on the controller owning this form. It takes a Symfony\Component\HttpFoundation\Response argument,
and expects an SS_HTTPResponse in return.