Skip to content

Commit

Permalink
feature: add webhook notification logic
Browse files Browse the repository at this point in the history
  • Loading branch information
glaubersilva committed Aug 31, 2024
1 parent 8fdfbe6 commit 90c4420
Show file tree
Hide file tree
Showing 6 changed files with 138 additions and 25 deletions.
13 changes: 11 additions & 2 deletions src/OffSiteGateway/DataTransferObjects/OffSiteGatewayPayment.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,27 @@

namespace GiveAddon\OffSiteGateway\DataTransferObjects;

/**
* @unreleased
*/
class OffSiteGatewayPayment
{
/**
* @var string
*/
public $id;
public $merchantPaymentId;

/**
* @var string
*/
public $gatewayPaymentId;

public static function fromArray(array $data): OffSiteGatewayPayment
{
$self = new self();

$self->id = $data['id'] ?? '';
$self->gatewayPaymentId = $data['gatewayPaymentId'] ?? '';
$self->merchantPaymentId = $data['merchantPaymentId'] ?? '';

return $self;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,26 @@ class OffSiteGatewayWebhookNotification
*/
public $notificationType;

public static function fromArray(array $data): OffSiteGatewayWebhookNotification
/**
* @var string
*/
public $paymentStatus;

/**
* @var string
*/
public $merchantPaymentId;

/**
* @var string
*/
public $gatewayPaymentId;

public static function fromRequest(array $request): OffSiteGatewayWebhookNotification
{
$self = new self();

$self->notificationType = $data['notification_type'] ?? '';
$self->notificationType = $request['notification_type'] ?? '';

return $self;
}
Expand Down
6 changes: 5 additions & 1 deletion src/OffSiteGateway/Gateway/OffSiteCheckoutPageSimulation.php
Original file line number Diff line number Diff line change
Expand Up @@ -65,9 +65,13 @@ private function loadOffSiteGatewaySimulationMarkup()
</style>
<div class="container">
<h1>Off-site Checkout Page Simulation</h1>
<p>
Gateway Payment ID: <strong><?php
echo $_GET['gatewayPaymentId'] ?? ' -'; ?></strong>
</p>
<p>
Donation amount: <strong><?php
echo isset($_GET['amount']) ? $_GET['amount']['currency'] . ' ' . $_GET['amount']['value'] : ' 0'; ?></strong>
echo isset($_GET['amount']) ? $_GET['amount']['currency'] . ' ' . $_GET['amount']['value'] : ' -'; ?></strong>
</p>
<p>
Description: <strong><?php
Expand Down
63 changes: 43 additions & 20 deletions src/OffSiteGateway/Gateway/OffSiteGateway.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,12 @@
use Give\Framework\Http\Response\Types\RedirectResponse;
use Give\Framework\PaymentGateways\Commands\RedirectOffsite;
use Give\Framework\PaymentGateways\Exceptions\PaymentGatewayException;
use Give\Framework\PaymentGateways\Log\PaymentGatewayLog;
use Give\Framework\PaymentGateways\PaymentGateway;
use Give\Framework\Support\Facades\Scripts\ScriptAsset;
use GiveAddon\OffSiteGateway\DataTransferObjects\OffSiteGatewayPayment;
use GiveAddon\OffSiteGateway\DataTransferObjects\OffSiteGatewayWebhookNotification;
use GiveAddon\OffSiteGateway\Webhooks\OffSiteGatewaysWebhookNotificationHandler;

/**
* @unreleased
Expand Down Expand Up @@ -121,18 +124,6 @@ public function enqueueScript(int $formId)
public function createPayment(Donation $donation, $gatewayData): RedirectOffsite
{
try {
/**
* Get the parameters that will be sent to the gateway off-site checkout page, in this sample integration
* it will be sent to the "OffSiteCheckoutPageSimulation" where you can complete or cancel the donation.
*/
$paymentParameters = $this->getPaymentParameters($donation, $gatewayData);

/**
* This additional parameter is necessary to make the off-site checkout page simulation work;
* In real-world integrations, this parameter isn't necessary.
*/
$paymentParameters['off-site-gateway-simulation'] = true;

/**
* Some gateways can provide an API that allows creating a transaction before redirecting to the off-site
* checkout page, in these cases we can retrieve the gateway transaction ID and attach it to our donation
Expand All @@ -143,11 +134,23 @@ public function createPayment(Donation $donation, $gatewayData): RedirectOffsite
* when the "OffSiteGatewayWebhookRequestHandler" class receives a webhook notification sent from the
* "OffSiteCheckoutPageSimulation" even before the donor being redirected back to the site.
*/
$offSiteGatewayPayment = $this->createGiveAddonOffSiteGatewayPaymentApi($donation, $paymentParameters);
$donation->gatewayTransactionId = $offSiteGatewayPayment->id;
$offSiteGatewayPayment = $this->createGiveAddonOffSiteGatewayPaymentApi($donation);
$donation->gatewayTransactionId = $offSiteGatewayPayment->gatewayPaymentId;
$donation->status = DonationStatus::PENDING();
$donation->save();

/**
* Get the parameters that will be sent to the gateway off-site checkout page, in this sample integration
* it will be sent to the "OffSiteCheckoutPageSimulation" where you can complete or cancel the donation.
*/
$paymentParameters = $this->getPaymentParameters($donation, $gatewayData);

/**
* This additional parameter is necessary to make the off-site checkout page simulation work;
* In real-world integrations, this parameter isn't necessary.
*/
$paymentParameters['off-site-gateway-simulation'] = true;

/**
* Please note that we are using the "home_url()" method to redirect the donor to the "OffSiteCheckoutPageSimulation"
* class which is an internal page that simulates an external page, but in real-world integrations, the donor should
Expand Down Expand Up @@ -185,6 +188,7 @@ public function refundDonation(Donation $donation)
public function getPaymentParameters(Donation $donation, $gatewayData): array
{
return [
'gatewayPaymentId' => $donation->gatewayTransactionId,
'amount' => [
'value' => $donation->amount->formatToDecimal(),
'currency' => $donation->amount->getCurrency()->getCode(),
Expand All @@ -198,16 +202,17 @@ public function getPaymentParameters(Donation $donation, $gatewayData): array

/**
* @param Donation $donation
* @param array $paymentParameters
*
* @return OffSiteGatewayPayment
*/
protected function createGiveAddonOffSiteGatewayPaymentApi(
Donation $donation,
array $paymentParameters
): OffSiteGatewayPayment {
protected function createGiveAddonOffSiteGatewayPaymentApi(Donation $donation): OffSiteGatewayPayment
{
/**
* We are mocking an external API call return and converting it to an OffSite Gateway Payment object.
*/
return OffSiteGatewayPayment::fromArray([
'id' => 'payment-id',
'gatewayPaymentId' => 'off-site-sample-gateway-payment-id-' . rand(),
'merchantPaymentId' => $donation->id,
]);
}

Expand Down Expand Up @@ -247,6 +252,24 @@ protected function handleCanceledPaymentReturn(array $queryParams): RedirectResp
return new RedirectResponse(esc_url_raw($queryParams['givewp-return-url']));
}

/**
* @unreleased
*/
protected function webhookNotificationsListener()
{
try {
$webhookNotification = OffSiteGatewayWebhookNotification::fromRequest($_REQUEST);
give(OffSiteGatewaysWebhookNotificationHandler::class)($webhookNotification);
} catch (Exception $e) {
esc_html_e('Off-site gateway Webhook Notification failed.', 'ADDON_TEXTDOMAIN');
PaymentGatewayLog::error(
'Off-site gateway Webhook Notification failed. Error: ' . $e->getMessage()
);
}

exit();
}

/**
* @unreleased
*/
Expand Down
4 changes: 4 additions & 0 deletions src/OffSiteGateway/OffSiteGatewayServiceProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

use Exception;
use Give\Framework\PaymentGateways\PaymentGatewayRegister;
use Give\Framework\PaymentGateways\Webhooks\EventHandlers\DonationCompleted;
use Give\Helpers\Hooks;
use Give\ServiceProviders\ServiceProvider;
use GiveAddon\OffSiteGateway\Gateway\OffSiteCheckoutPageSimulation;
Expand Down Expand Up @@ -37,5 +38,8 @@ function (PaymentGatewayRegister $registrar) {
);

Hooks::addAction('init', OffSiteCheckoutPageSimulation::class);

// Add Async Event Handlers
Hooks::addAction('givewp_off-site_gateway_sample_event_donation_completed', DonationCompleted::class);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
<?php

namespace GiveAddon\OffSiteGateway\Webhooks;

use Give\Framework\Support\Facades\ActionScheduler\AsBackgroundJobs;
use GiveAddon\OffSiteGateway\DataTransferObjects\OffSiteGatewayWebhookNotification;

/**
* @unreleased
*/
class OffSiteGatewaysWebhookNotificationHandler
{
/**
* @unreleased
*/
public function __invoke(OffSiteGatewayWebhookNotification $webhookNotification)
{
/**
* Allow developers to handle the webhook notification.
*
* @unreleased
*
* @param OffSiteGatewayWebhookNotification $webhookNotification
*/
do_action("givewp_off-site_gateway_sample_webhook_notification_handler", $webhookNotification);

// We will handle recurring donations in a separate submodule sample that will enable Subscription on the Off-site gateway sample.
if ($this->isRecurringDonation($webhookNotification)) {
return;
}

switch (strtolower($webhookNotification->paymentStatus)) {
case 'complete':
AsBackgroundJobs::enqueueAsyncAction(
'givewp_off-site_gateway_sample_event_donation_completed',
[$webhookNotification->gatewayPaymentId],
'ADDON_TEXTDOMAIN'
);
break;
case 'failed':
// Handle failed transactions here...
break;
case 'cancelled':
// Handle cancelled transactions here...
break;
default:
break;
}
}

/**
* @unreleased
*/
private function isRecurringDonation(OffSiteGatewayWebhookNotification $webhookNotification): bool
{
return 'subscription' === $webhookNotification->notificationType;
}
}

0 comments on commit 90c4420

Please sign in to comment.