Skip to content

Commit

Permalink
Refactor: prevent subscription renewals with gateway transaction IDs …
Browse files Browse the repository at this point in the history
…already used previously (#7449)
  • Loading branch information
glaubersilva authored Aug 15, 2024
1 parent 3e94d1b commit 5dc54d1
Show file tree
Hide file tree
Showing 3 changed files with 99 additions and 0 deletions.
8 changes: 8 additions & 0 deletions src/Donations/Repositories/DonationRepository.php
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,14 @@ public function getByGatewayTransactionId($gatewayTransactionId)
return $this->queryByGatewayTransactionId($gatewayTransactionId)->get();
}

/**
* @unreleased
*/
public function getTotalDonationCountByGatewayTransactionId($gatewayTransactionId): int
{
return $this->queryByGatewayTransactionId($gatewayTransactionId)->count();
}

/**
* @since 2.21.0
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
class SubscriptionRenewalDonationCreated
{
/**
* @unreleased Add log messages and a defensive approach to prevent duplicated renewals
* @since 3.6.0
*/
public function __invoke(
Expand All @@ -25,6 +26,48 @@ public function __invoke(
$subscription = give()->subscriptions->getByGatewaySubscriptionId($gatewaySubscriptionId);

if ( ! $subscription) {
PaymentGatewayLog::error(
sprintf('The renewal was not created for the gateway transaction ID %s because no subscription with the gateway subscription %s was found.',
$gatewayTransactionId, $gatewaySubscriptionId),
[
'Gateway Subscription ID' => $gatewaySubscriptionId,
'Gateway Transaction ID' => $gatewayTransactionId,
'Message' => $message,
]
);

return;
}

if ($subscription->initialDonation()->gatewayTransactionId === $gatewayTransactionId) {
PaymentGatewayLog::error(
sprintf('The renewal was not created for the gateway transaction ID %s because the initial donation of the subscription %s is already using the informed gateway transaction ID %s.',
$gatewayTransactionId, $subscription->id, $gatewaySubscriptionId),
[
'Gateway Subscription ID' => $gatewaySubscriptionId,
'Gateway Transaction ID' => $gatewayTransactionId,
'Message' => $message,
'Subscription' => $subscription->toArray(),
]
);

return;
}

$donation = give()->donations->getByGatewayTransactionId($gatewayTransactionId);

if ($donation) {
PaymentGatewayLog::error(
sprintf('The renewal was not created for the gateway transaction ID %s because the donation %s is already using the informed gateway transaction ID %s.',
$gatewayTransactionId, $donation->id, $gatewaySubscriptionId),
[
'Gateway Subscription ID' => $gatewaySubscriptionId,
'Gateway Transaction ID' => $gatewayTransactionId,
'Message' => $message,
'Donation' => $donation->toArray(),
]
);

return;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,4 +44,52 @@ public function testShouldCreateRenewalDonation()

$this->assertEquals($subscription->id, $renewalDonation->subscriptionId);
}

/**
* @unreleased
*
* @throws Exception
*/
public function testShouldNotCreateRenewalDonationWithFirstGatewayTransactionId()
{
$subscription = Subscription::factory()->createWithDonation();
$donation = $subscription->initialDonation();

$firstGatewayTransactionId = 'first-gateway-transaction-id';

$donation->status = DonationStatus::COMPLETE();
$donation->gatewayTransactionId = $firstGatewayTransactionId;
$donation->save();

give(SubscriptionRenewalDonationCreated::class)($subscription->gatewaySubscriptionId,
$firstGatewayTransactionId);

$totalDonations = give()->donations->getTotalDonationCountByGatewayTransactionId($firstGatewayTransactionId);

$this->assertEquals(1, $totalDonations);
}

/**
* @unreleased
*
* @throws Exception
*/
public function testShouldNotCreateRenewalDonationWithDuplicatedGatewayTransactionId()
{
$subscription = Subscription::factory()->createWithDonation();

$duplicatedGatewayTransactionId = 'duplicated-gateway-transaction-id';

// #1 Renewal Donation
give(SubscriptionRenewalDonationCreated::class)($subscription->gatewaySubscriptionId,
$duplicatedGatewayTransactionId);

// #2 Renewal Donation - This one should not be created
give(SubscriptionRenewalDonationCreated::class)($subscription->gatewaySubscriptionId,
$duplicatedGatewayTransactionId);

$totalDonations = give()->donations->getTotalDonationCountByGatewayTransactionId($duplicatedGatewayTransactionId);

$this->assertEquals(1, $totalDonations);
}
}

0 comments on commit 5dc54d1

Please sign in to comment.