|
<?php |
|
|
|
namespace App\Http\Controllers; |
|
|
|
use Illuminate\Http\Request; |
|
use App\Http\Controllers\Controller; |
|
|
|
use Cache; |
|
use Omnipay; |
|
use Omnipay\Common\CreditCard; |
|
use Omnipay\Common\Exception\InvalidResponseException; |
|
use Omnipay\SagePay\Message\ServerCompleteAuthorizeResponse; |
|
|
|
class PaymentController extends Controller |
|
{ |
|
private function getTransactionId(Order $order) { |
|
// Make some shit up here. |
|
return $transactionId; |
|
} |
|
|
|
// This happens when the user submits the order. |
|
public function checkout(Request $request) |
|
{ |
|
// Get the transaction ID for the order |
|
$transactionId = $this->getTransactionId($order); |
|
|
|
// Actual credit card data entered on remote payment page. |
|
$card = new CreditCard( |
|
[ |
|
'firstName' => $order->name_first, |
|
'lastName' => $order->name_last, |
|
|
|
'billingAddress1' => $order->address->street_1, |
|
'billingAddress2' => $order->address->street_2, |
|
'billingCity' => $order->address->city, |
|
'billingState' => $order->address->county, |
|
'billingPostcode' => $order->address->postcode, |
|
'billingCountry' => $order->address->country, |
|
|
|
'shippingAddress1' => $order->address->street_1, |
|
'shippingAddress2' => $order->address->street_2, |
|
'shippingCity' => $order->address->city, |
|
'shippingState' => $order->address->county, |
|
'shippingPostcode' => $order->address->postcode, |
|
'shippingCountry' => $order->address->country, |
|
] |
|
); |
|
|
|
// May be able to add line items here. |
|
// https://github.com/thephpleague/omnipay/pull/154 |
|
|
|
// Create transaction with remote API. |
|
$response = Omnipay::purchase( |
|
[ |
|
'amount' => number_format($amount, 2, '.', ''), |
|
'transactionId' => $transactionId, |
|
'card' => $card, |
|
'currency' => 'GBP', |
|
'description' => 'Description', |
|
'notifyUrl' => route('api.payment.process', [$order]), |
|
] |
|
)->send(); |
|
|
|
// Store the transaction status in the cache. |
|
// Probably not a good idea, should really go into the database proper |
|
$transaction = Cache::forever( |
|
$transactionId, [ |
|
'finalStatus' => 'PENDING', |
|
'status' => method_exists($response, 'getStatus') ? $response->getStatus() : $response->getCode(), |
|
'message' => 'Awaiting notify', |
|
'transactionReference' => $response->getTransactionReference(), |
|
] |
|
); |
|
|
|
if ($response->isRedirect()) { |
|
// Redirect the user to a payment page. |
|
$response->redirect(); |
|
} else { |
|
// SOMETHING FUCKED UP. |
|
} |
|
} |
|
|
|
// Sagepay will post to this upon payment successful/failed. |
|
public function process(Request $request) |
|
{ |
|
// Get the transaction ID for the order. |
|
$transactionId = $this->getTransactionId($order); |
|
|
|
// Retrieve the transaction from the database. |
|
$transaction = Cache::get($transactionId); |
|
|
|
// I've forgotten what this does. |
|
if (empty($transaction) || $transaction['finalStatus'] != 'PENDING') { |
|
// vendorTxCode missing or invalid - aborting |
|
$transactionReference = null; |
|
} else { |
|
$transactionReference = $transaction['transactionReference']; |
|
} |
|
|
|
// Get the "complete purchase" message. |
|
$requestMessage = OmniPay::completePurchase( |
|
[ |
|
'amount' => '0.01', |
|
'transactionId' => $transactionId, |
|
'transactionReference' => $transactionReference, |
|
] |
|
); |
|
|
|
// Do a "send" - this will validate everything. |
|
// This is mental. |
|
try { |
|
$responseMessage = $requestMessage->send(); |
|
} catch (\Exception $e) { |
|
|
|
// InvalidResponseException will not catch a null transactionReference. |
|
// You may want to catch them separately and return different error messages. |
|
// This is a nasty hack, manually creating a message in the |
|
// event of an exception caused by a security failure. |
|
|
|
$requestMessage = OmniPay::completePurchase([]); |
|
$responseMessage = new ServerCompleteAuthorizeResponse($requestMessage, []); |
|
$responseMessage->invalid(route('order.failed', [$order]), $e->getMessage()); |
|
} |
|
|
|
// Handle the actions based on successful (or not) authorisation |
|
// of the transaction. |
|
if ($responseMessage->isSuccessful()) { |
|
$finalStatus = 'APPROVED'; |
|
|
|
// Do some magic. |
|
$order->completed(); |
|
} else { |
|
$finalStatus = 'REJECTED'; |
|
|
|
// This is tragic. |
|
$order->failed(); |
|
} |
|
|
|
// Store the result. |
|
Cache::forever( |
|
$transactionId, [ |
|
'finalStatus' => $finalStatus, |
|
'status' => $responseMessage->getStatus(), |
|
'message' => $responseMessage->getMessage(), |
|
'notifyData' => $responseMessage->getData(), |
|
] |
|
); |
|
|
|
// Return to SagePay with route end user will be redirected to. |
|
$responseMessage->confirm(route('order.thanks', [$order])); |
|
} |
|
} |