Skip to content

Commit

Permalink
Redirect to a second checkout on subscriptions with donation
Browse files Browse the repository at this point in the history
  • Loading branch information
subiabre committed Dec 14, 2023
1 parent ed5e6c4 commit d804fc3
Show file tree
Hide file tree
Showing 4 changed files with 125 additions and 31 deletions.
6 changes: 6 additions & 0 deletions src/Goteo/Controller/InvestController.php
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
use Goteo\Payment\Payment;
use Goteo\Util\Monolog\Processor\WebProcessor;
use Omnipay\Common\Message\ResponseInterface;
use Omnipay\Stripe\Subscription\Message\DonationResponse;
use RuntimeException;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
Expand Down Expand Up @@ -523,6 +524,11 @@ public function completePaymentAction($project_id, $invest_id, Request $request)
if (!$response instanceof ResponseInterface) {
throw new RuntimeException('This response does not implements ResponseInterface.');
}

if ($response instanceof DonationResponse) {
return $this->dispatch(AppEvents::INVEST_INIT_REDIRECT, new FilterInvestRequestEvent($method, $response))->getHttpResponse();
}

if ($response->isSuccessful()) {
// Goto User data fill
Message::info(Text::get('invest-payment-success'));
Expand Down
3 changes: 2 additions & 1 deletion src/Omnipay/Stripe/Subscription/Gateway.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

use Omnipay\Common\AbstractGateway;
use Omnipay\Common\Http\ClientInterface;
use Omnipay\Common\Message\ResponseInterface;
use Omnipay\Stripe\Subscription\Message\SubscriptionRequest;
use Omnipay\Stripe\Subscription\Message\SubscriptionResponse;
use Symfony\Component\HttpFoundation\Request as HttpRequest;
Expand Down Expand Up @@ -31,7 +32,7 @@ public function purchase($options = array())
return new SubscriptionRequest($options);
}

public function completePurchase($options = array()): SubscriptionResponse
public function completePurchase($options = array()): ResponseInterface
{
$request = new SubscriptionRequest($options);

Expand Down
40 changes: 40 additions & 0 deletions src/Omnipay/Stripe/Subscription/Message/DonationResponse.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
<?php

namespace Omnipay\Stripe\Subscription\Message;

use Goteo\Application\Config;
use Omnipay\Common\Message\AbstractResponse;
use Omnipay\Common\Message\RedirectResponseInterface;
use Omnipay\Common\Message\RequestInterface;
use Stripe\Checkout\Session as StripeSession;
use Stripe\StripeClient;

class DonationResponse extends AbstractResponse implements RedirectResponseInterface
{
private StripeClient $stripe;

private StripeSession $checkout;

public function __construct(RequestInterface $request, string $checkoutSessionId)
{
parent::__construct($request, $checkoutSessionId);

$this->stripe = new StripeClient(Config::get('payments.stripe.secretKey'));
$this->checkout = $this->stripe->checkout->sessions->retrieve($checkoutSessionId);
}

public function isSuccessful()
{
return $this->checkout->status === StripeSession::STATUS_COMPLETE;
}

public function isRedirect()
{
return true;
}

public function getRedirectUrl()
{
return $this->checkout->url;
}
}
107 changes: 77 additions & 30 deletions src/Omnipay/Stripe/Subscription/Message/SubscriptionRequest.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,18 @@
use Goteo\Application\Config;
use Goteo\Library\Text;
use Goteo\Model\Invest;
use Goteo\Model\Project;
use Goteo\Model\User;
use Omnipay\Common\Message\AbstractRequest;
use Stripe\Checkout\Session as CheckoutSession;
use Stripe\Customer;
use Stripe\Product;
use Stripe\StripeClient;

class SubscriptionRequest extends AbstractRequest
{
private array $data;

private StripeClient $stripe;

public function __construct(array $data)
Expand All @@ -34,40 +37,35 @@ public function sendData($data)
{
$user = $data['user'];
$invest = $data['invest'];

$project = $invest->getProject();

$price = $this->stripe->prices->create([
'unit_amount' => ($invest->amount + $invest->donate_amount) * 100,
'currency' => 'eur',
'recurring' => ['interval' => 'month'],
'product' => $this->getStripeProduct($invest)->id
]);
$customer = $this->getStripeCustomer($user)->id;
$metadata = $this->getMetadata($project, $invest, $user);

$successUrl = sprintf('%s?session_id={CHECKOUT_SESSION_ID}', $this->getRedirectUrl(
'invest',
$project->id,
$invest->id,
'complete'
));

$session = $this->stripe->checkout->sessions->create([
'customer' => $this->getStripeCustomer($data['user'])->id,
'success_url' => sprintf('%s?session_id={CHECKOUT_SESSION_ID}', $this->getRedirectUrl(
'invest',
$project->id,
$invest->id,
'complete'
)),
'cancel_url' => $this->getRedirectUrl(
'project',
$project->id
),
'mode' => 'subscription',
'customer' => $customer,
'success_url' => $successUrl,
'cancel_url' => $this->getRedirectUrl('project', $project->id),
'mode' => CheckoutSession::MODE_SUBSCRIPTION,
'line_items' => [
[
'price' => $price->id,
'price' => $this->stripe->prices->create([
'unit_amount' => $invest->amount * 100,
'currency' => 'eur',
'recurring' => ['interval' => 'month'],
'product' => $this->getStripeProduct($invest)->id
])->id,
'quantity' => 1
]
],
'metadata' => [
'project' => $project->id,
'reward' => $this->getInvestReward($invest, ''),
'user' => $user->id,
]
'metadata' => $metadata
]);

return new SubscriptionResponse($this, $session->id);
Expand All @@ -78,13 +76,51 @@ public function completePurchase(array $options = [])
// Dirty sanitization because something is double concatenating the ?session_id query param
$sessionId = explode('?', $_REQUEST['session_id'])[0];
$session = $this->stripe->checkout->sessions->retrieve($sessionId);
$metadata = $session->metadata->toArray();

$this->stripe->subscriptions->update(
$session->subscription, [
'metadata' => $session->metadata->toArray()
]);
if ($session->subscription) {
$this->stripe->subscriptions->update(
$session->subscription,
[
'metadata' => $metadata
]
);

if ($metadata['donate_amount'] < 1) {
return new SubscriptionResponse($this, $session->id);
}

$checkout = $this->stripe->checkout->sessions->create([
'customer' => $this->getStripeCustomer(User::get($metadata['user']))->id,
'success_url' => sprintf('%s?session_id={CHECKOUT_SESSION_ID}', $this->getRedirectUrl(
'invest',
$metadata['project'],
$metadata['invest'],
'complete'
)),
'cancel_url' => $this->getRedirectUrl('project', $metadata['project']->id),
'mode' => CheckoutSession::MODE_PAYMENT,
'line_items' => [
[
'price' => $this->stripe->prices->create([
'unit_amount' => $metadata['donate_amount'] * 100,
'currency' => 'eur',
'product_data' => [
'name' => Text::get('donate-meta-description')
]
])->id,
'quantity' => 1
]
],
'metadata' => $metadata
]);

return new DonationResponse($this, $checkout->id);
}

return new SubscriptionResponse($this, $session->id);
if ($session->payment_intent) {
return new SubscriptionResponse($this, $session->id);
}
}

private function getRedirectUrl(...$args): string
Expand Down Expand Up @@ -157,4 +193,15 @@ private function getStripeProduct(Invest $invest): Product
]);
}
}

private function getMetadata(Project $project, Invest $invest, User $user): array
{
return [
'donate_amount' => $invest->donate_amount,
'project' => $project->id,
'invest' => $invest->id,
'reward' => $this->getInvestReward($invest, ''),
'user' => $user->id,
];
}
}

0 comments on commit d804fc3

Please sign in to comment.