/** * 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')); }
/** * 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())); }