Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature: add API for gateway webhook events #7664

Open
wants to merge 31 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 19 commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
a7b87c0
feature: add WebhookEvents api
glaubersilva Dec 27, 2024
3e43409
feature: add service provider
glaubersilva Jan 2, 2025
1d4ed35
feature: add subscription events
glaubersilva Jan 2, 2025
5bd3a0a
refactor: remove parameter
glaubersilva Jan 2, 2025
ac58b07
refactor: move setGateway logic to constructor
glaubersilva Jan 2, 2025
be0c8af
refactor: remove status parameters
glaubersilva Jan 2, 2025
b818166
refactor: move register logic to give_init hook
glaubersilva Jan 2, 2025
5a75b35
refactor: extract status logic to action classes
glaubersilva Jan 2, 2025
911936d
refactor: remove unused value object
glaubersilva Jan 2, 2025
13a759d
refactor: better naming
glaubersilva Jan 2, 2025
a3bd5c3
refactor: use sprintf
glaubersilva Jan 2, 2025
de63d93
tests: add tests for the new classes
glaubersilva Jan 3, 2025
c8100d6
refactor: deprecated subscription statuses
glaubersilva Jan 3, 2025
9005cc4
refactor: instantiate the webhook events object
glaubersilva Jan 3, 2025
b51c389
feature: add missing event handler classes for subscription statuses
glaubersilva Jan 3, 2025
1899c09
refactor: change parameter type
glaubersilva Jan 3, 2025
44856df
tests: add new tests for new event handler classes
glaubersilva Jan 3, 2025
160b685
Merge branch 'develop' into fun/gateway-webhook-events-api
glaubersilva Jan 10, 2025
d7e57e1
chore: update composer.lock
glaubersilva Jan 10, 2025
374e0bd
refactor: add new methods for each status and tweak unit tests
glaubersilva Jan 24, 2025
19f03ca
tests: move logic used only on tests and create new tests for the new…
glaubersilva Jan 24, 2025
9d619c0
tests: simplify logic
glaubersilva Jan 24, 2025
e006205
refactor: rename methods related to subscription donations
glaubersilva Jan 24, 2025
aac3de3
feature: add new methods and contract for webhook notifications
glaubersilva Jan 24, 2025
e894899
doc: update unreleased tag
glaubersilva Jan 24, 2025
aee1666
refactor: add $args parameter
glaubersilva Jan 24, 2025
a617c1a
tests: add WebhookTest class
glaubersilva Jan 24, 2025
c91ce8b
doc: tweak comment
glaubersilva Jan 24, 2025
fa2ffe0
refactor: add condition before register route
glaubersilva Jan 24, 2025
dfbf875
fix: wrong condition
glaubersilva Jan 24, 2025
e5d8dcb
refactor: tweak exception message
glaubersilva Jan 24, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
463 changes: 232 additions & 231 deletions composer.lock

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions give.php
Original file line number Diff line number Diff line change
Expand Up @@ -244,6 +244,7 @@ final class Give
Give\DonationSpam\ServiceProvider::class,
Give\Settings\ServiceProvider::class,
Give\FeatureFlags\OptionBasedFormEditor\ServiceProvider::class,
Give\Framework\PaymentGateways\ServiceProvider::class,
];

/**
Expand Down
21 changes: 21 additions & 0 deletions src/Framework/PaymentGateways/PaymentGateway.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
use Give\Framework\PaymentGateways\Routes\RouteSignature;
use Give\Framework\PaymentGateways\Traits\HandleHttpResponses;
use Give\Framework\PaymentGateways\Traits\HasRouteMethods;
use Give\Framework\PaymentGateways\Webhooks\WebhookEvents;
use Give\Framework\Support\ValueObjects\Money;
use Give\Log\Log;
use Give\Subscriptions\Models\Subscription;
Expand Down Expand Up @@ -43,6 +44,15 @@ abstract class PaymentGateway implements PaymentGatewayInterface,
public $subscriptionModule;

/**
* @unreleased
*
* @var WebhookEvents $webhookEvents
*/
public $webhookEvents;

/**
* @unreleased Add the webhookEvents property
*
* @since 2.20.0 Change first argument type to SubscriptionModule abstract class.
* @since 2.18.0
*
Expand All @@ -55,6 +65,17 @@ public function __construct(SubscriptionModule $subscriptionModule = null)
}

$this->subscriptionModule = $subscriptionModule;
$this->webhookEvents = new WebhookEvents($this::id());
}

/**
* @unreleased
*/
public static function webhookEvents(): WebhookEvents
{
$instance = new static();

return $instance->webhookEvents;
}

/**
Expand Down
99 changes: 99 additions & 0 deletions src/Framework/PaymentGateways/ServiceProvider.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
<?php

namespace Give\Framework\PaymentGateways;

use Give\Donations\ValueObjects\DonationStatus;
use Give\Framework\PaymentGateways\Webhooks\EventHandlers\Actions\GetEventHandlerClassByDonationStatus;
use Give\Framework\PaymentGateways\Webhooks\EventHandlers\Actions\GetEventHandlerClassBySubscriptionStatus;
use Give\Framework\PaymentGateways\Webhooks\EventHandlers\SubscriptionFirstDonationCompleted;
use Give\Framework\PaymentGateways\Webhooks\EventHandlers\SubscriptionRenewalDonationCreated;
use Give\Helpers\Hooks;
use Give\ServiceProviders\ServiceProvider as ServiceProviderInterface;
use Give\Subscriptions\ValueObjects\SubscriptionStatus;

/**
* @unreleased
*/
class ServiceProvider implements ServiceProviderInterface
{
/**
* @unreleased
*/
public function register()
{
// TODO: Implement register() method.
}

/**
* @unreleased
*/
public function boot()
{
$this->registerWebhookEventHandlers();
}

private function registerWebhookEventHandlers()
{
add_action('give_init', function () {
$registeredPaymentGatewayIds = give()->gateways->getPaymentGateways();
foreach ($registeredPaymentGatewayIds as $gatewayId) {
$this->addDonationStatusEventHandlers($gatewayId);
$this->addSubscriptionStatusEventHandlers($gatewayId);
$this->addSubscriptionFirstDonationEventHandler($gatewayId);
$this->addSubscriptionRenewalDonationEventHandler($gatewayId);
}
}, 999);
}

/**
* @unreleased
*/
private function addDonationStatusEventHandlers(string $gatewayId)
{
foreach (DonationStatus::values() as $status) {
if ($eventHandlerClass = (new GetEventHandlerClassByDonationStatus())($status)) {
Hooks::addAction(
sprintf('givewp_%s_webhook_event_donation_status_%s', $gatewayId, $status->getValue()),
$eventHandlerClass
);
}
}
}

/**
* @unreleased
*/
private function addSubscriptionStatusEventHandlers(string $gatewayId)
{
foreach (SubscriptionStatus::values() as $status) {
if ($eventHandlerClass = (new GetEventHandlerClassBySubscriptionStatus())($status)) {
Hooks::addAction(
sprintf('givewp_%s_webhook_event_subscription_status_%s', $gatewayId, $status->getValue()),
$eventHandlerClass
);
}
}
}

/**
* @unreleased
*/
private function addSubscriptionFirstDonationEventHandler(string $gatewayId)
{
Hooks::addAction(
sprintf('givewp_%s_webhook_event_subscription_first_donation', $gatewayId),
SubscriptionFirstDonationCompleted::class
);
}

/**
* @unreleased
*/
private function addSubscriptionRenewalDonationEventHandler(string $gatewayId)
{
Hooks::addAction(
sprintf('givewp_%s_webhook_event_subscription_renewal_donation', $gatewayId),
SubscriptionRenewalDonationCreated::class
);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
<?php

namespace Give\Framework\PaymentGateways\Webhooks\EventHandlers\Actions;

use Give\Donations\ValueObjects\DonationStatus;
use Give\Framework\PaymentGateways\Webhooks\EventHandlers\DonationAbandoned;
use Give\Framework\PaymentGateways\Webhooks\EventHandlers\DonationCancelled;
use Give\Framework\PaymentGateways\Webhooks\EventHandlers\DonationCompleted;
use Give\Framework\PaymentGateways\Webhooks\EventHandlers\DonationFailed;
use Give\Framework\PaymentGateways\Webhooks\EventHandlers\DonationPending;
use Give\Framework\PaymentGateways\Webhooks\EventHandlers\DonationPreapproval;
use Give\Framework\PaymentGateways\Webhooks\EventHandlers\DonationProcessing;
use Give\Framework\PaymentGateways\Webhooks\EventHandlers\DonationRefunded;
use Give\Framework\PaymentGateways\Webhooks\EventHandlers\DonationRevoked;

/**
* @unreleased
*/
class GetEventHandlerClassByDonationStatus
{
/**
* @unreleased
*/
public function __invoke(DonationStatus $status): string
{
switch ($status) {
case $status->isAbandoned():
return DonationAbandoned::class;
case $status->isCancelled():
return DonationCancelled::class;
case $status->isComplete():
return DonationCompleted::class;
case $status->isFailed():
return DonationFailed::class;
case $status->isPending():
return DonationPending::class;
case $status->isPreapproval():
return DonationPreapproval::class;
case $status->isProcessing():
return DonationProcessing::class;
case $status->isRefunded():
return DonationRefunded::class;
case $status->isRevoked():
return DonationRevoked::class;
default:
return '';
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
<?php

namespace Give\Framework\PaymentGateways\Webhooks\EventHandlers\Actions;

use Give\Framework\PaymentGateways\Webhooks\EventHandlers\SubscriptionActive;
use Give\Framework\PaymentGateways\Webhooks\EventHandlers\SubscriptionCancelled;
use Give\Framework\PaymentGateways\Webhooks\EventHandlers\SubscriptionCompleted;
use Give\Framework\PaymentGateways\Webhooks\EventHandlers\SubscriptionExpired;
use Give\Framework\PaymentGateways\Webhooks\EventHandlers\SubscriptionFailing;
use Give\Framework\PaymentGateways\Webhooks\EventHandlers\SubscriptionPaused;
use Give\Framework\PaymentGateways\Webhooks\EventHandlers\SubscriptionPending;
use Give\Framework\PaymentGateways\Webhooks\EventHandlers\SubscriptionSuspended;
use Give\Subscriptions\ValueObjects\SubscriptionStatus;

/**
* @unreleased
*/
class GetEventHandlerClassBySubscriptionStatus
{
/**
* @unreleased
*/
public function __invoke(SubscriptionStatus $status): string
{
switch ($status) {
case $status->isActive():
return SubscriptionActive::class;
case $status->isCancelled():
return SubscriptionCancelled::class;
case $status->isCompleted():
return SubscriptionCompleted::class;
case $status->isExpired():
return SubscriptionExpired::class;
case $status->isFailing():
return SubscriptionFailing::class;
case $status->isPaused():
return SubscriptionPaused::class;
case $status->isPending():
return SubscriptionPending::class;
case $status->isSuspended():
return SubscriptionSuspended::class;
default:
return '';
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ public function __invoke(


/**
* @unreleased Add support for PAUSED and PENDING statuses
* @since 3.6.0
*/
protected function getMessageFromStatus(SubscriptionStatus $status): string
Expand All @@ -63,6 +64,12 @@ protected function getMessageFromStatus(SubscriptionStatus $status): string
case ($status->isFailing()):
$message = __('Subscription Failing.', 'give');
break;
case ($status->isPaused()):
$message = __('Subscription Paused.', 'give');
break;
case ($status->isPending()):
$message = __('Subscription Pending.', 'give');
break;
case ($status->isSuspended()):
$message = __('Subscription Suspended.', 'give');
break;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
<?php

namespace Give\Framework\PaymentGateways\Webhooks\EventHandlers;

use Exception;
use Give\Framework\PaymentGateways\Webhooks\EventHandlers\Actions\UpdateSubscriptionStatus;
use Give\Subscriptions\ValueObjects\SubscriptionStatus;

/**
* @unreleased
*/
class SubscriptionPaused
{
/**
* @unreleased
*
* @throws Exception
*/
public function __invoke(string $gatewaySubscriptionId, string $message = '')
{
$subscription = give()->subscriptions->getByGatewaySubscriptionId($gatewaySubscriptionId);

if ( ! $subscription || $subscription->status->isPaused()) {
return;
}

(new UpdateSubscriptionStatus())($subscription, SubscriptionStatus::PAUSED(), $message);
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
<?php

namespace Give\Framework\PaymentGateways\Webhooks\EventHandlers;

use Exception;
use Give\Framework\PaymentGateways\Webhooks\EventHandlers\Actions\UpdateSubscriptionStatus;
use Give\Subscriptions\ValueObjects\SubscriptionStatus;

/**
* @unreleased
*/
class SubscriptionPending
{
/**
* @unreleased
*
* @throws Exception
*/
public function __invoke(string $gatewaySubscriptionId, string $message = '')
{
$subscription = give()->subscriptions->getByGatewaySubscriptionId($gatewaySubscriptionId);

if ( ! $subscription || $subscription->status->isPending()) {
return;
}

(new UpdateSubscriptionStatus())($subscription, SubscriptionStatus::PENDING(), $message);
}
}
Loading
Loading