diff --git a/src/Goteo/Controller/InvestController.php b/src/Goteo/Controller/InvestController.php index 0d2d191586..cce2ba37db 100644 --- a/src/Goteo/Controller/InvestController.php +++ b/src/Goteo/Controller/InvestController.php @@ -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; @@ -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')); diff --git a/src/Omnipay/Stripe/Subscription/Gateway.php b/src/Omnipay/Stripe/Subscription/Gateway.php index fb7a491e47..9fa34ef2f8 100644 --- a/src/Omnipay/Stripe/Subscription/Gateway.php +++ b/src/Omnipay/Stripe/Subscription/Gateway.php @@ -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; @@ -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); diff --git a/src/Omnipay/Stripe/Subscription/Message/DonationResponse.php b/src/Omnipay/Stripe/Subscription/Message/DonationResponse.php new file mode 100644 index 0000000000..e964fb8d4b --- /dev/null +++ b/src/Omnipay/Stripe/Subscription/Message/DonationResponse.php @@ -0,0 +1,40 @@ +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; + } +} diff --git a/src/Omnipay/Stripe/Subscription/Message/SubscriptionRequest.php b/src/Omnipay/Stripe/Subscription/Message/SubscriptionRequest.php index a167a2e4d8..b0d3b5d64e 100644 --- a/src/Omnipay/Stripe/Subscription/Message/SubscriptionRequest.php +++ b/src/Omnipay/Stripe/Subscription/Message/SubscriptionRequest.php @@ -5,8 +5,10 @@ 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; @@ -14,6 +16,7 @@ class SubscriptionRequest extends AbstractRequest { private array $data; + private StripeClient $stripe; public function __construct(array $data) @@ -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); @@ -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 @@ -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, + ]; + } }