/** * Cancel any payments that have not completed. */ public function tidyPayments() { foreach ($this->Payments() as $payment) { if (!$payment->isComplete()) { $response = PurchaseService::create($payment)->cancelPurchase(); } } }
/** * Create a payment model, and provide link to redirect to external gateway, * or redirect to order link. * @return string - url for redirection after payment has been made */ public function makePayment($gateway, $gatewaydata = array()) { //create payment $payment = $this->createPayment($gateway); if (!$payment) { //errors have been stored. return false; } // Create a purchase service, and set the user-facing success URL for redirects $service = PurchaseService::create($payment)->setReturnUrl($this->getReturnUrl()); // Process payment, get the result back $response = $service->purchase($this->getGatewayData($gatewaydata)); if (GatewayInfo::is_manual($gateway)) { //don't complete the payment at this stage, if payment is manual $this->placeOrder(); } elseif ($response->isSuccessful()) { $this->completePayment(); } return $response; }
/** * 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() { $payment = $this->getPayment(); if (!$payment) { return $this->httpError(404, _t("Payment.NOTFOUND", "Payment could not be found.")); } //isolate the gateway request message containing success / failure urls $message = $payment->Messages()->filter("ClassName", array("PurchaseRequest", "AuthorizeRequest"))->first(); $service = PurchaseService::create($payment); //redirect if payment is already a success if ($payment->isComplete()) { return $this->redirect($this->getSuccessUrl($message)); } //do the payment update $response = null; switch ($this->request->param('Status')) { case "complete": $serviceResponse = $service->completePurchase(); if ($serviceResponse->isSuccessful()) { $response = $this->redirect($this->getSuccessUrl($message)); } else { $response = $this->redirect($this->getFailureUrl($message)); } break; case "notify": $serviceResponse = $service->completePurchase(); // Allow implementations where no redirect happens, // since gateway failsafe callbacks might expect a 2xx HTTP response $response = new SS_HTTPResponse('', 200); break; case "cancel": //TODO: store cancellation message / void payment $response = $this->redirect($this->getFailureUrl($message)); break; default: $response = $this->httpError(404, _t("Payment.INVALIDURL", "Invalid payment url.")); } return $response; }
public function testNonExistantGateway() { //exception when trying to run functions that require a gateway $payment = $this->payment; $service = PurchaseService::create($payment->init("PxPayGateway", 100, "NZD"))->setReturnUrl("complete"); $this->setExpectedException("RuntimeException"); try { $result = $service->purchase(); } catch (RuntimeException $e) { $this->markTestIncomplete(); $totalNZD = Payment::get()->filter('MoneyCurrency', "NZD")->sum(); $this->assertEquals(27.23, $totalNZD); $service->purchase(); $service->completePurchase(); //just to assert that exception is thrown throw $e; } }
/** * Process the form that is submitted through the site. Note that omnipay fields are NOT saved to the database. * This is intentional (so we don't save credit card details) but should be fixed in future, so we save all fields, * but only save the last 3 digits of the credit card (and not the CVV/exp date) * * @todo: save all fields to database except credit card fields * * @param array $data * @param Form $form * * @return Redirection */ public function process($data, $form) { Session::set("FormInfo.{$form->FormName()}.data", $data); Session::clear("FormInfo.{$form->FormName()}.errors"); foreach ($this->Fields() as $field) { $messages[$field->Name] = $field->getErrorMessage()->HTML(); $formField = $field->getFormField(); if ($field->Required && $field->CustomRules()->Count() == 0) { if (isset($data[$field->Name])) { $formField->setValue($data[$field->Name]); } if (!isset($data[$field->Name]) || !$data[$field->Name] || !$formField->validate($form->getValidator())) { $form->addErrorMessage($field->Name, $field->getErrorMessage(), 'bad'); } } } if (Session::get("FormInfo.{$form->FormName()}.errors")) { Controller::curr()->redirectBack(); return; } // if there are no errors, create the payment $submittedForm = Object::create('SubmittedPaymentForm'); $submittedForm->SubmittedByID = ($id = Member::currentUserID()) ? $id : 0; $submittedForm->ParentID = $this->ID; // if saving is not disabled save now to generate the ID if (!$this->DisableSaveSubmissions) { $submittedForm->write(); } $attachments = array(); $submittedFields = new ArrayList(); foreach ($this->Fields() as $field) { if (!$field->showInReports()) { continue; } $submittedField = $field->getSubmittedFormField(); $submittedField->ParentID = $submittedForm->ID; $submittedField->Name = $field->Name; $submittedField->Title = $field->getField('Title'); // save the value from the data if ($field->hasMethod('getValueFromData')) { $submittedField->Value = $field->getValueFromData($data); } else { if (isset($data[$field->Name])) { $submittedField->Value = $data[$field->Name]; } } if (!empty($data[$field->Name])) { if (in_array("EditableFileField", $field->getClassAncestry())) { if (isset($_FILES[$field->Name])) { $foldername = $field->getFormField()->getFolderName(); // create the file from post data $upload = new Upload(); $file = new File(); $file->ShowInSearch = 0; try { $upload->loadIntoFile($_FILES[$field->Name], $file, $foldername); } catch (ValidationException $e) { $validationResult = $e->getResult(); $form->addErrorMessage($field->Name, $validationResult->message(), 'bad'); Controller::curr()->redirectBack(); return; } // write file to form field $submittedField->UploadedFileID = $file->ID; // attach a file only if lower than 1MB if ($file->getAbsoluteSize() < 1024 * 1024 * 1) { $attachments[] = $file; } } } } $submittedField->extend('onPopulationFromField', $field); if (!$this->DisableSaveSubmissions) { $submittedField->write(); } $submittedFields->push($submittedField); } /** Do the payment **/ // move this up here for our redirect link $referrer = isset($data['Referrer']) ? '?referrer=' . urlencode($data['Referrer']) : ""; // set amount $currency = $this->data()->PaymentCurrency; $paymentfieldname = $this->PaymentAmountField()->Name; $amount = $data[$paymentfieldname]; $postdata = $data; // request payment $payment = Payment::create()->init($this->data()->PaymentGateway, $amount, $currency); $payment->write(); $response = PurchaseService::create($payment)->setReturnUrl($this->Link('finished') . $referrer)->setCancelUrl($this->Link('finished') . $referrer)->purchase($postdata); // save payment to order $submittedForm->PaymentID = $payment->ID; $submittedForm->write(); $emailData = array("Sender" => Member::currentUser(), "Fields" => $submittedFields); $this->extend('updateEmailData', $emailData, $attachments); $submittedForm->extend('updateAfterProcess'); Session::clear("FormInfo.{$form->FormName()}.errors"); Session::clear("FormInfo.{$form->FormName()}.data"); // set a session variable from the security ID to stop people accessing the finished method directly if (isset($data['SecurityID'])) { Session::set('FormProcessed', $data['SecurityID']); } else { // if the form has had tokens disabled we still need to set FormProcessed // to allow us to get through the finshed method if (!$this->Form()->getSecurityToken()->isEnabled()) { $randNum = rand(1, 1000); $randHash = md5($randNum); Session::set('FormProcessed', $randHash); Session::set('FormProcessedNum', $randNum); } } if (!$this->DisableSaveSubmissions) { Session::set('userformssubmission' . $this->ID, $submittedForm->ID); } return $response->redirect(); }
public function testRedirectUrl() { $service = PurchaseService::create(new Payment())->setReturnUrl("abc/123")->setCancelUrl("xyz/blah/2345235?andstuff=124124#hash"); $this->assertEquals("abc/123", $service->getReturnUrl()); $this->assertEquals("xyz/blah/2345235?andstuff=124124#hash", $service->getCancelUrl()); }
/** * Initiate the actual purchase, and do redirect to * gateway site, success url or cancel url. * @param Payment $payment * @param array $data */ protected function processPayment(Payment $payment, $data) { $response = PurchaseService::create($payment)->setReturnUrl($this->successurl)->setCancelUrl($this->cancelurl)->setManualPurchaseStatus("Captured")->purchase($data); return $response->redirect(); }