You can hook into the payment process with your custom extensions.
Here's a list of all hooks available to extensions.
onAuthorized
called when a payment was successfully authorized. You'll get theServiceResponse
as parameter.onAwaitingAuthorized
called when authorization was completed, but is waiting for an asynchronous notification from the gateway. You'll get theServiceResponse
as parameter.onCaptured
called when a payment was successfully captured. You'll get theServiceResponse
as parameter.onAwaitingCaptured
called when a purchase completes, but is waiting for an asynchronous notification from the gateway. You'll get theServiceResponse
as parameter.onRefunded
called when a payment was successfully refunded. You'll get theServiceResponse
as parameter.onVoid
called when a payment was successfully voided/cancelled via Omnipay. You'll get theServiceResponse
as parameter.onCancelled
called then a payment was cancelled by the user (eg. user cancelled offsite payment). This is not an action that goes through Omnipay, so there's no parameter here.updateCMSFields
standard SilverStripe hook to update CMS fields.
updateServiceResponse
every service response that is being generated from the different services will be passed through this callback. You'll get theServiceResponse
as parameter.updatePartialPayment
whenever a partial payment is being generated "from" the main payment, this extension will be called. You'll get the new partialPayment
as the first and the "original/parent"Payment
as a second parameter.
Since the service-responses are crucial to a proper application-flow, you should be extremely careful when modifying a response! The most common use-case for a modification of the service-response is probably to return a proper response to a notification coming from your payment provider.
Let's say you have two (fictional) payment providers, 'EasyPayProvider' and 'CoolPayProvider'. Both return success-status via an asynchronous notification.
The 'EasyPayProvider' API states, that you should return a HTTP Response with Status 200
, and a message body of SUCCESS
when payment notification was handled successfully.
The 'CoolPayProvider' API states, that you should return an HTTP Response with Status 200
, a message body of OK
and a response header: X-CoolPay-Success: 1
Here's how you can achieve that with an Extension:
use SilverStripe\Omnipay\Service\ServiceResponse;
class NotifyResponseExtension extends Extension
{
public function updateServiceResponse(ServiceResponse $serviceResponse)
{
if ($serviceResponse->isNotification()) {
if ($serviceResponse->getPayment()->Gateway == 'EasyPayProvider') {
$serviceResponse->setHttpResponse(new SS_HTTPResponse('SUCCESS', 200));
} else if ($serviceResponse->getPayment()->Gateway == 'CoolPayProvider') {
$httpResponse = new SS_HTTPResponse('OK', 200);
$httpResponse->addHeader('X-CoolPay-Success', '1');
$serviceResponse->setHttpResponse($httpResponse);
}
}
}
}
And then add the extension as usual:
SilverStripe\Omnipay\Service\PaymentService:
extensions:
- NotifyResponseExtension
Partial payments (eg. partial refunds and partial captures) generate new Payment instances.
These new payments will inherit the Gateway
, TransactionReference
, SuccessUrl
and FailureUrl
of the initial payment.
You'll get the newly created Payment instance as parameter in the updatePartialPayment
hook (right before it will be written to DB).
The original Payment (eg. the "parent" payment) is passed as the second parameter to the extension hook.
If you added custom properties to your Payment (eg. via Extension) it is your duty as developer to copy these to the newly created Payment, if necessary!
Please do not tinker with the default fields of the Payment class, as further processing of the Payments depend on these values to be correct!
onBeforeAuthorize
called just before theauthorize
call is being made to the gateway. Passes the Gateway-Data (an array) as parameter, which allows you to modify the gateway data prior to being sent.onAfterAuthorize
called just after the Omnipayauthorize
call. Will pass the Omnipay request object as parameter.onAfterSendAuthorize
called aftersend
has been called on the Omnipay request object. You'll get the request as first, and the omnipay response as second parameter.onBeforeCompleteAuthorize
called just before thecompleteAuthorize
call is being made to the gateway. Passes the Gateway-Data (an array) as parameter, which allows you to modify the gateway data prior to being sent.onAfterCompleteAuthorize
called just after the OmnipaycompleteAuthorize
call. Will pass the Omnipay request object as parameter.
onBeforeCapture
called just before thecapture
call is being made to the gateway. Passes the Gateway-Data (an array) as parameter, which allows you to modify the gateway data prior to being sent.onAfterCapture
called just after the Omnipaycapture
call. Will pass the Omnipay request object as parameter.onAfterSendCapture
called aftersend
has been called on the Omnipay request object. You'll get the request as first, and the omnipay response as second parameter.
onBeforePurchase
called just before thepurchase
call is being made to the gateway. Passes the Gateway-Data (an array) as parameter, which allows you to modify the gateway data prior to being sent.onAfterPurchase
called just after the Omnipaypurchase
call. Will pass the Omnipay request object as parameter.onAfterSendPurchase
called aftersend
has been called on the Omnipay request object. You'll get the request as first, and the omnipay response as second parameter.onBeforeCompletePurchase
called just before thecompletePurchase
call is being made to the gateway. Passes the Gateway-Data (an array) as parameter, which allows you to modify the gateway data prior to being sent.onAfterCompletePurchase
called just after the OmnipaycompletePurchase
call. Will pass the Omnipay request object as parameter.
onBeforeRefund
called just before therefund
call is being made to the gateway. Passes the Gateway-Data (an array) as parameter, which allows you to modify the gateway data prior to being sent.onAfterRefund
called just after the Omnipayrefund
call. Will pass the Omnipay request object as parameter.onAfterSendRefund
called aftersend
has been called on the Omnipay request object. You'll get the request as first, and the omnipay response as second parameter.
onBeforeVoid
called just before thevoid
call is being made to the gateway. Passes the Gateway-Data (an array) as parameter, which allows you to modify the gateway data prior to being sent.onAfterVoid
called just after the Omnipayvoid
call. Will pass the Omnipay request object as parameter.onAfterSendVoid
called aftersend
has been called on the Omnipay request object. You'll get the request as first, and the omnipay response as second parameter.
You can use extension hooks to override what services are being created for what intent.
If somebody does the following:
$factory = ServiceFactory::create();
$service = $factory->getService($payment, ServiceFactory::INTENT_PAYMENT);
The constant ServiceFactory::INTENT_PAYMENT
just translates to a string "payment"
, which invokes the following
hook on any ServiceFactory extension: createPaymentService
. The hook will get the Payment
object as parameter and
should return a PaymentService
instance (eg. a subclass).
Example code that might be in your extension:
// This is just an example and already implemented in the default Factory, do not create an actual extension to do this.
public function createPaymentService(Payment $payment)
{
if (GatewayInfo::shouldUseAuthorize($payment->Gateway)) {
return AuthorizeService::create($payment);
} else {
return PurchaseService::create($payment);
}
}
Please be aware that you can't implement the same create-method in multiple extensions. If the factory encounters several Extensions with the same method, it will raise an exception.