Example #1
0
 /**
  * Attempt to make a payment.
  * 
  * @param  array $data returnUrl/cancelUrl + customer creditcard and billing/shipping details.
  * 	Some keys (e.g. "amount") are overwritten with data from the associated {@link $payment}.
  *  If this array is constructed from user data (e.g. a form submission), please take care
  *  to whitelist accepted fields, in order to ensure sensitive gateway parameters like "freeShipping" can't be set.
  *  If using {@link Form->getData()}, only fields which exist in the form are returned,
  *  effectively whitelisting against arbitrary user input.
  * @return ResponseInterface omnipay's response class, specific to the chosen gateway.
  */
 public function purchase($data = array())
 {
     if ($this->payment->Status !== "Created") {
         return null;
         //could be handled better? send payment response?
     }
     if (!$this->payment->isInDB()) {
         $this->payment->write();
     }
     //update success/fail urls
     $this->update($data);
     //set the client IP address, if not already set
     if (!isset($data['clientIp'])) {
         $data['clientIp'] = Controller::curr()->getRequest()->getIP();
     }
     $gatewaydata = array_merge($data, array('card' => $this->getCreditCard($data), 'amount' => (double) $this->payment->MoneyAmount, 'currency' => $this->payment->MoneyCurrency, 'returnUrl' => $this->getEndpointURL("complete", $this->payment->Identifier), 'cancelUrl' => $this->getEndpointURL("cancel", $this->payment->Identifier), 'notifyUrl' => $this->getEndpointURL("notify", $this->payment->Identifier)));
     if (!isset($gatewaydata['transactionId'])) {
         $gatewaydata['transactionId'] = $this->payment->Identifier;
     }
     $request = $this->oGateway()->purchase($gatewaydata);
     $message = $this->createMessage('PurchaseRequest', $request);
     $message->SuccessURL = $this->returnurl;
     $message->FailureURL = $this->cancelurl;
     $message->write();
     $gatewayresponse = $this->createGatewayResponse();
     try {
         $response = $this->response = $request->send();
         $gatewayresponse->setOmnipayResponse($response);
         //update payment model
         if ($this->manualpurchasestatus == "Authorized" && GatewayInfo::is_manual($this->payment->Gateway)) {
             //initiate 'authorized' manual payment
             $this->createMessage('AuthorizedResponse', $response);
             $this->payment->Status = 'Authorized';
             $this->payment->write();
             $gatewayresponse->setMessage("Manual payment authorised");
         } elseif ($response->isSuccessful()) {
             //successful payment
             $this->createMessage('PurchasedResponse', $response);
             $this->payment->Status = 'Captured';
             $gatewayresponse->setMessage("Payment successful");
             $this->payment->write();
             $this->payment->extend('onCaptured', $gatewayresponse);
         } elseif ($response->isRedirect()) {
             // redirect to off-site payment gateway
             $this->createMessage('PurchaseRedirectResponse', $response);
             $this->payment->Status = 'Authorized';
             $this->payment->write();
             $gatewayresponse->setMessage("Redirecting to gateway");
         } else {
             //handle error
             $this->createMessage('PurchaseError', $response);
             $gatewayresponse->setMessage("Error (" . $response->getCode() . "): " . $response->getMessage());
         }
     } catch (Omnipay\Common\Exception\OmnipayException $e) {
         $this->createMessage('PurchaseError', $e);
         $gatewayresponse->setMessage($e->getMessage());
     }
     $gatewayresponse->setRedirectURL($this->getRedirectURL());
     return $gatewayresponse;
 }
 /**
  * Make payment for a place order, where payment had previously failed.
  *
  * @param array $data
  * @param Form  $form
  *
  * @return boolean
  */
 public function dopayment($data, $form)
 {
     if (self::config()->allow_paying && $this->order && $this->order->canPay()) {
         // Save payment data from form and process payment
         $data = $form->getData();
         $gateway = !empty($data['PaymentMethod']) ? $data['PaymentMethod'] : null;
         if (!GatewayInfo::is_manual($gateway)) {
             $processor = OrderProcessor::create($this->order);
             $data['cancelUrl'] = $processor->getReturnUrl();
             $response = $processor->makePayment($gateway, $data);
             if ($response) {
                 if ($response->isRedirect() || $response->isSuccessful()) {
                     return $response->redirect();
                 }
                 $form->sessionMessage($response->getMessage(), 'bad');
             } else {
                 $form->sessionMessage($processor->getError(), 'bad');
             }
         } else {
             $form->sessionMessage(_t('OrderActionsForm.MANUAL_NOT_ALLOWED', "Manual payment not allowed"), 'bad');
         }
         return $this->controller->redirectBack();
     }
     $form->sessionMessage(_t('OrderForm.COULDNOTPROCESSPAYMENT', 'Payment could not be processed.'), 'bad');
     $this->controller->redirectBack();
 }
 public function paymentmethod()
 {
     $gateways = GatewayInfo::get_supported_gateways();
     if (count($gateways) == 1) {
         return $this->owner->redirect($this->NextStepLink());
     }
     return array('OrderForm' => $this->PaymentMethodForm());
 }
 public function testSupportedGateways()
 {
     $expected = array('PayPal_Express' => 'PayPal Express', 'PaymentExpress_PxPay' => 'PaymentExpress PxPay', 'Manual' => 'Manual', 'Dummy' => 'Dummy');
     $gateways = GatewayInfo::get_supported_gateways();
     $this->assertArrayHasKey('PayPal_Express', $gateways);
     $this->assertArrayHasKey('PaymentExpress_PxPay', $gateways);
     $this->assertArrayHasKey('Manual', $gateways);
     $this->assertArrayHasKey('Dummy', $gateways);
 }
 /**
  * Attempt to make a payment.
  * 
  * @param  array $data returnUrl/cancelUrl + customer creditcard and billing/shipping details.
  * 	Some keys (e.g. "amount") are overwritten with data from the associated {@link $payment}.
  *  If this array is constructed from user data (e.g. a form submission), please take care
  *  to whitelist accepted fields, in order to ensure sensitive gateway parameters like "freeShipping" can't be set.
  *  If using {@link Form->getData()}, only fields which exist in the form are returned,
  *  effectively whitelisting against arbitrary user input.
  * @return ResponseInterface omnipay's response class, specific to the chosen gateway.
  */
 public function purchase($data = array())
 {
     if ($this->payment->Status !== "Created") {
         return null;
         //could be handled better? send payment response?
     }
     if (!$this->payment->isInDB()) {
         $this->payment->write();
     }
     $message = $this->createMessage('PurchaseRequest');
     $message->SuccessURL = isset($data['returnUrl']) ? $data['returnUrl'] : $this->returnurl;
     $message->FailureURL = isset($data['cancelUrl']) ? $data['cancelUrl'] : $this->cancelurl;
     $message->write();
     $request = $this->oGateway()->purchase(array_merge($data, array('card' => $this->getCreditCard($data), 'amount' => (double) $this->payment->MoneyAmount, 'currency' => $this->payment->MoneyCurrency, 'transactionId' => $message->Identifier, 'clientIp' => isset($data['clientIp']) ? $data['clientIp'] : null, 'returnUrl' => PaymentGatewayController::get_return_url($message, 'complete'), 'notifyUrl' => PaymentGatewayController::get_return_url($message, 'notify'), 'cancelUrl' => PaymentGatewayController::get_return_url($message, 'cancel'))));
     $this->logToFile($request->getParameters(), "PurchaseRequest_post");
     $gatewayresponse = $this->createGatewayResponse();
     try {
         $response = $this->response = $request->send();
         $gatewayresponse->setOmnipayResponse($response);
         //update payment model
         if (GatewayInfo::is_manual($this->payment->Gateway)) {
             //initiate manual payment
             $this->createMessage('AuthorizedResponse', $response);
             $this->payment->Status = 'Authorized';
             $this->payment->write();
             $gatewayresponse->setMessage("Manual payment authorised");
         } elseif ($response->isSuccessful()) {
             //successful payment
             $this->createMessage('PurchasedResponse', $response);
             $this->payment->Status = 'Captured';
             $gatewayresponse->setMessage("Payment successful");
             $this->payment->write();
             $this->payment->extend('onCaptured', $gatewayresponse);
         } elseif ($response->isRedirect()) {
             // redirect to off-site payment gateway
             $this->createMessage('PurchaseRedirectResponse', $response);
             $this->payment->Status = 'Authorized';
             $this->payment->write();
             $gatewayresponse->setMessage("Redirecting to gateway");
         } else {
             //handle error
             $this->createMessage('PurchaseError', $response);
             $this->payment->Status = 'Void';
             $this->payment->write();
             $gatewayresponse->setMessage("Error (" . $response->getCode() . "): " . $response->getMessage());
         }
     } catch (Omnipay\Common\Exception\OmnipayException $e) {
         $this->createMessage('PurchaseError', $e);
         $this->payment->Status = 'Void';
         $this->payment->write();
         $gatewayresponse->setMessage($e->getMessage());
     }
     $gatewayresponse->setRedirectURL($this->getRedirectURL());
     return $gatewayresponse;
 }
 public function checkoutSubmit($data, $form)
 {
     // form validation has passed by this point, so we can save data
     $this->config->setData($form->getData());
     $order = $this->config->getOrder();
     $gateway = Checkout::get($order)->getSelectedPaymentMethod(false);
     if (GatewayInfo::is_offsite($gateway) || GatewayInfo::is_manual($gateway) || $this->config->getComponentByType('OnsitePaymentCheckoutComponent')) {
         return $this->submitpayment($data, $form);
     }
     return $this->controller->redirect($this->controller->Link('payment'));
 }
 public function getCMSFields()
 {
     $fields = parent::getCMSFields();
     $gateways = GatewayInfo::get_supported_gateways();
     $amountfields = $this->Fields()->map("ID", "Title");
     $fields->addFieldsToTab("Root.Payment", array(DropdownField::create("PaymentAmountFieldID", "Payment Amount Field", $amountfields)->setDescription("This must return a value like 20.00 (no dollar sign)"), new DropdownField("PaymentGateway", "Payment Gateway", $gateways), new TextField("PaymentCurrency", "Payment Currency"), new CheckboxField("PaymentFields_Card", "Show Card Fields"), new CheckboxField("PaymentFields_Billing", "Show Billing Fields"), new CheckboxField("PaymentFields_Shipping", "Show Shipping Fields"), new CheckboxField("PaymentFields_Company", "Show Company Fields"), new CheckboxField("PaymentFields_Email", "Show Email Fields")));
     // text to show on error
     $onErrorFieldSet = new CompositeField($label = new LabelField('OnErrorMessageLabel', _t('UserDefinedForm.ONERRORLABEL', 'Show on error')), $editor = new HtmlEditorField("OnErrorMessage", "", _t('UserDefinedForm.ONERRORMESSAGE', $this->OnErrorMessage)));
     $onErrorFieldSet->addExtraClass('field');
     $fields->insertAfter($onErrorFieldSet, "OnCompleteMessage");
     return $fields;
 }
 public function validateData(Order $order, array $data)
 {
     $result = new ValidationResult();
     if (!isset($data['PaymentMethod'])) {
         $result->error("Payment method not provided", "PaymentMethod");
         throw new ValidationException($result);
     }
     $methods = GatewayInfo::get_supported_gateways();
     if (!isset($methods[$data['PaymentMethod']])) {
         $result->error("Gateway not supported", "PaymentMethod");
         throw new ValidationException($result);
     }
 }
 public function validateData(Order $order, array $data)
 {
     $result = ValidationResult::create();
     if (!isset($data['PaymentMethod'])) {
         $result->error(_t('PaymentCheckoutComponent.NO_PAYMENT_METHOD', "Payment method not provided"), "PaymentMethod");
         throw new ValidationException($result);
     }
     $methods = GatewayInfo::get_supported_gateways();
     if (!isset($methods[$data['PaymentMethod']])) {
         $result->error(_t('PaymentCheckoutComponent.UNSUPPORTED_GATEWAY', "Gateway not supported"), "PaymentMethod");
         throw new ValidationException($result);
     }
 }
 public function getPaymentMethods()
 {
     return GatewayInfo::get_supported_gateways();
 }
 /**
  * Create a new payment for an order
  */
 public function createPayment($gateway)
 {
     if (!GatewayInfo::is_supported($gateway)) {
         $this->error(_t("PaymentProcessor.INVALID_GATEWAY", "`{gateway}` isn't a valid payment gateway.", 'gateway is the name of the payment gateway', array('gateway' => $gateway)));
         return false;
     }
     if (!$this->order->canPay(Member::currentUser())) {
         $this->error(_t("PaymentProcessor.CANTPAY", "Order can't be paid for."));
         return false;
     }
     $payment = Payment::create()->init($gateway, $this->order->TotalOutstanding(), ShopConfig::get_base_currency());
     $this->order->Payments()->add($payment);
     return $payment;
 }
 public function __construct(Order $order)
 {
     parent::__construct($order);
     $this->addComponent(CustomerDetailsCheckoutComponent::create());
     $this->addComponent(ShippingAddressCheckoutComponent::create());
     $this->addComponent(BillingAddressCheckoutComponent::create());
     if (Checkout::member_creation_enabled() && !Member::currentUserID()) {
         $this->addComponent(MembershipCheckoutComponent::create());
     }
     if (count(GatewayInfo::get_supported_gateways()) > 1) {
         $this->addComponent(PaymentCheckoutComponent::create());
     }
     $this->addComponent(NotesCheckoutComponent::create());
     $this->addComponent(TermsCheckoutComponent::create());
 }
 public function getPaymentMethodFields()
 {
     //TODO: only get one field if there is no option
     return OptionsetField::create('PaymentMethod', _t('CheckoutField.PAYMENT_TYPE', "Payment Type"), GatewayInfo::get_supported_gateways(), array_keys(GatewayInfo::get_supported_gateways()));
 }
 public function testIsOffsite()
 {
     $this->assertFalse(GatewayInfo::is_offsite('\\GatewayInfoTest_OnsiteGateway'));
     $this->assertTrue(GatewayInfo::is_offsite('\\GatewayInfoTest_OffsiteGateway'));
 }
Example #15
0
 /**
  * Form for collecting gateway data.
  */
 public function GatewayDataForm()
 {
     $payment = $this->getCurrentPayment();
     if (!$payment) {
         //redirect if there is no payment object available
         return $this->redirect($this->Link());
     }
     $factory = new GatewayFieldsFactory($payment->Gateway);
     $fields = $factory->getFields();
     //TODO: never let CC details be stored in session (e.g. validation)
     //TODO: force requirement of SSL on live sites
     $actions = new FieldList($cancelaction = new FormAction("cancel", _t("PaymentController.DIFFERENTMETHOD", "Choose Different Method")), $payaction = new FormAction("pay", _t("PaymentController.DIFFERENTMETHOD", "Make Payment")));
     $cancelaction->setAttribute("formnovalidate", "formnovalidate");
     $validator = new RequiredFields(GatewayInfo::required_fields($payment->Gateway));
     $form = new Form($this, "GatewayDataForm", $fields, $actions, $validator);
     $this->extend('updateGatewayDataForm', $form);
     //allow cancel action to run without validation
     if (!empty($_REQUEST['action_cancel'])) {
         $form->unsetValidator();
     }
     return $form;
 }
 public function getGatewayTitle()
 {
     return GatewayInfo::nice_title($this->Gateway);
 }
 public function getDetailsForDataGrid($separator = ' - ')
 {
     $details = [];
     if ($this->Note) {
         $details[] = $this->Note;
     }
     switch ($this->Status) {
         case 'Updated':
             $log = $this->ChangeLog;
             $separator = '<br/>';
             if (isset($log['OrderItem'])) {
                 if (is_array($log['OrderItem']) && isset($log['OrderItem']['Quantity']) && isset($log['Quantity'])) {
                     if (isset($log['OrderItem']['_brandnew'])) {
                         $details[] = sprintf('Added %s of %s', $log['Quantity'], isset($log['OrderItem']['Title']) ? $log['OrderItem']['Title'] : 'item', $log['Quantity']);
                     } elseif ($log['Quantity']) {
                         $details[] = sprintf('Set %s to %s', isset($log['OrderItem']['Title']) ? $log['OrderItem']['Title'] : 'item', $log['Quantity'], $log['Quantity']);
                     } else {
                         $details[] = sprintf('Removed %s', isset($log['OrderItem']['Title']) ? $log['OrderItem']['Title'] : 'item');
                     }
                 } elseif (is_object($log['OrderItem']) && $log['OrderItem'] instanceof OrderItem && isset($log['Quantity'])) {
                     if (isset($log['OrderItem']->_brandnew)) {
                         $details[] = sprintf('Added %s of %s', $log['Quantity'], $log['OrderItem']->Buyable()->Title);
                     } elseif ($log['Quantity']) {
                         $details[] = sprintf('Set %s to %s', $log['OrderItem']->Buyable()->Title, $log['Quantity']);
                     } else {
                         $details[] = sprintf('Removed %s', $log['OrderItem']->Buyable()->Title);
                     }
                 }
             }
             if (isset($log['ShippingAddress']) && $log['ShippingAddress']) {
                 $details[] = 'Ship to: ' . implode(', ', array_filter([$log['ShippingAddress']->Name, $log['ShippingAddress']->toString()]));
                 if (!$this->Order()->SeparateBillingAddress) {
                     $details[] = 'Bill to: ' . implode(', ', array_filter([$log['ShippingAddress']->Name, $log['ShippingAddress']->toString()]));
                 }
             }
             if (isset($log['BillingAddress']) && $log['BillingAddress']) {
                 $details[] = 'Bill to: ' . implode(', ', array_filter([$log['BillingAddress']->Name, $log['BillingAddress']->toString()]));
             }
             if (isset($log['Member'])) {
                 $details[] = 'Member: ' . $log['Member']->Name;
             }
             $allowed = ['IPAddress', 'Reference', 'SeparateBillingAddress', 'Notes', 'Referrer'];
             if (!$this->Order()->IsCart()) {
                 $allowed[] = 'Total';
             }
             $log = array_intersect_key($log, array_flip($allowed));
             if (!empty($log)) {
                 foreach ($log as $field => $trans) {
                     if (is_array($trans) && array_key_exists('before', $trans)) {
                         $details[] = $this->Order()->fieldLabel($field) . ' changed from ' . ($trans['before'] ?: '<em class="orderStatusLog-detail--none">none</em>') . ' to ' . $trans['after'];
                     } elseif (is_string($trans)) {
                         $details[] = $this->Order()->fieldLabel($field) . ': ' . $trans;
                     }
                 }
             }
             break;
         case 'Processing':
             if (($component = $this->Order()->has_many('Payments')) && count($component) && ($lastPayment = $this->Order()->Payments()->filter(['Created:LessThan' => $this->Created])->first())) {
                 $details[] = 'Via ' . GatewayInfo::nice_title($lastPayment->Gateway);
                 $details[] = 'Charging ' . GatewayInfo::nice_title($lastPayment->obj('Money')->Nice());
                 if ($gatewayMessage = GatewayMessage::get()->filter(['PaymentID' => $lastPayment->ID, 'Reference:not' => ''])->first()) {
                     if ($gatewayMessage->Reference) {
                         $details[] = 'Reference: ' . $gatewayMessage->Reference;
                     }
                 }
             }
             break;
         case 'Paid':
             if (($component = $this->Order()->has_many('Payments')) && count($component) && ($lastPayment = $this->Order()->Payments()->filter(['Status' => 'Captured', 'Created:LessThan' => $this->Created])->first())) {
                 $details[] = 'Via ' . GatewayInfo::nice_title($lastPayment->Gateway);
                 $details[] = 'Charged ' . GatewayInfo::nice_title($lastPayment->obj('Money')->Nice());
                 if ($gatewayMessage = GatewayMessage::get()->filter(['PaymentID' => $lastPayment->ID, 'Reference:not' => ''])->first()) {
                     if ($gatewayMessage->Reference) {
                         $details[] = 'Reference: ' . $gatewayMessage->Reference;
                     }
                 }
             }
             break;
     }
     $details = [count($details) ? $separator . implode($separator, $details) : ''];
     if ($this->Sent) {
         $details[] = 'Notified customer on: ' . $this->Sent;
     }
     if ($this->Author()->exists()) {
         $details[] = 'Author: ' . $this->Author()->Name;
     }
     return implode('<br/>', $details);
 }
 public function getRequiredFields(Order $order)
 {
     return GatewayInfo::required_fields(Checkout::get($order)->getSelectedPaymentMethod());
 }
 protected function cullForGateway(&$fields, $defaults = array())
 {
     $selected = array_merge($defaults, GatewayInfo::required_fields($this->gateway));
     foreach ($fields as $name => $field) {
         if (!in_array($name, $selected)) {
             unset($fields[$name]);
         }
     }
 }
 public function getPaymentMethodFields()
 {
     //TODO: only get one field if there is no option
     return new OptionsetField('PaymentMethod', _t("Checkout", "Payment Type"), GatewayInfo::get_supported_gateways(), array_keys(GatewayInfo::get_supported_gateways()));
 }