/**
  * The main action for handling all requests.
  * It will redirect back to the application in all cases,
  * but will not update the Payment/Transaction models if they are not found,
  * or allowed to be updated.
  */
 public function index()
 {
     $response = null;
     $payment = $this->getPayment();
     if (!$payment) {
         $this->httpError(404, _t('Payment.NotFound', 'Payment could not be found.'));
     }
     $intent = null;
     switch ($payment->Status) {
         // We have to check for both states here, since the notification might come in before the gateway returns
         // if that's the case, the status of the payment will already be set to 'Authorized'
         case 'PendingAuthorization':
         case 'Authorized':
             $intent = ServiceFactory::INTENT_AUTHORIZE;
             break;
         case 'PendingCapture':
             $intent = ServiceFactory::INTENT_CAPTURE;
             break;
             // Both states have to be checked (see explanation with 'Authorized')
         // Both states have to be checked (see explanation with 'Authorized')
         case 'PendingPurchase':
         case 'Captured':
             $intent = ServiceFactory::INTENT_PURCHASE;
             break;
         case 'PendingRefund':
             $intent = ServiceFactory::INTENT_REFUND;
             break;
         case 'PendingVoid':
             $intent = ServiceFactory::INTENT_VOID;
             break;
         default:
             $this->httpError(403, _t('Payment.InvalidStatus', 'Invalid/unhandled payment status'));
     }
     $service = ServiceFactory::create()->getService($payment, $intent);
     //do the payment update
     switch ($this->request->param('Status')) {
         case "complete":
             $serviceResponse = $service->complete();
             $response = $serviceResponse->redirectOrRespond();
             break;
         case "notify":
             $serviceResponse = $service->complete(array(), true);
             $response = $serviceResponse->redirectOrRespond();
             break;
         case "cancel":
             $serviceResponse = $service->cancel();
             $response = $serviceResponse->redirectOrRespond();
             break;
         default:
             $this->httpError(404, _t('Payment.InvalidUrl', 'Invalid payment url.'));
     }
     return $response;
 }
 /**
  * Handle the actions and apply any changes to the GridField
  *
  * @param \GridField $gridField
  * @param string $actionName
  * @param mixed $arguments
  * @param array $data - form data
  * @return void
  * @throws \ValidationException when there was an error
  */
 public function handleAction(\GridField $gridField, $actionName, $arguments, $data)
 {
     if ($actionName == 'voidpayment') {
         $item = $gridField->getList()->byID($arguments['RecordID']);
         if (!$item instanceof \Payment) {
             return;
         }
         /** @var ServiceFactory $factory */
         $factory = ServiceFactory::create();
         $voidService = $factory->getService($item, ServiceFactory::INTENT_VOID);
         try {
             $serviceResponse = $voidService->initiate();
         } catch (Exception $ex) {
             throw new \ValidationException($ex->getMessage(), 0);
         }
         if ($serviceResponse->isError()) {
             throw new \ValidationException(_t('GridFieldVoidAction.VoidError', 'Unable to void payment. An error occurred.'), 0);
         }
     }
 }
 /**
  * Handle the actions and apply any changes to the GridField
  *
  * @param \GridField $gridField
  * @param string $actionName
  * @param mixed $arguments
  * @param array $data - form data
  * @return void
  * @throws \ValidationException when there was an error
  */
 public function handleAction(\GridField $gridField, $actionName, $arguments, $data)
 {
     if ($actionName == 'refundpayment') {
         $item = $gridField->getList()->byID($arguments['RecordID']);
         if (!$item instanceof \Payment) {
             return;
         }
         $serviceData = array_intersect_key($data, array('amount' => null));
         /** @var ServiceFactory $factory */
         $factory = ServiceFactory::create();
         $refundService = $factory->getService($item, ServiceFactory::INTENT_REFUND);
         try {
             $serviceResponse = $refundService->initiate($serviceData);
         } catch (Exception $ex) {
             throw new \ValidationException($ex->getMessage(), 0);
         }
         if ($serviceResponse->isError()) {
             throw new \ValidationException(_t('GridFieldRefundAction.RefundError', 'Unable to refund payment. An error occurred.'), 0);
         }
     }
 }
 /**
  * Create a payment model, and provide link to redirect to external gateway,
  * or redirect to order link.
  *
  * @param string $gateway the gateway to use
  * @param array $gatewaydata the data that should be passed to the gateway
  * @param string $successUrl (optional) return URL for successful payments.
  *  If left blank, the default return URL will be used @see getReturnUrl
  * @param string $cancelUrl (optional) return URL for cancelled/failed payments
  *
  * @return ServiceResponse|null
  */
 public function makePayment($gateway, $gatewaydata = array(), $successUrl = null, $cancelUrl = null)
 {
     //create payment
     $payment = $this->createPayment($gateway);
     if (!$payment) {
         //errors have been stored.
         return null;
     }
     $payment->setSuccessUrl($successUrl ? $successUrl : $this->getReturnUrl());
     // Explicitly set the cancel URL
     if ($cancelUrl) {
         $payment->setFailureUrl($cancelUrl);
     }
     // Create a payment service, by using the Service Factory. This will automatically choose an
     // AuthorizeService or PurchaseService, depending on Gateway configuration.
     // Set the user-facing success URL for redirects
     /** @var ServiceFactory $factory */
     $factory = ServiceFactory::create();
     $service = $factory->getService($payment, ServiceFactory::INTENT_PAYMENT);
     // Initiate payment, get the result back
     try {
         $serviceResponse = $service->initiate($this->getGatewayData($gatewaydata));
     } catch (SilverStripe\Omnipay\Exception\Exception $ex) {
         // error out when an exception occurs
         $this->error($ex->getMessage());
         return null;
     }
     // Check if the service response itself contains an error
     if ($serviceResponse->isError()) {
         if ($opResponse = $serviceResponse->getOmnipayResponse()) {
             $this->error($opResponse->getMessage());
         } else {
             $this->error('An unspecified payment error occurred. Please check the payment messages.');
         }
     }
     // For an OFFSITE payment, serviceResponse will now contain a redirect
     // For an ONSITE payment, ShopPayment::onCaptured will have been called, which will have called completePayment
     return $serviceResponse;
 }