diff --git a/.env.copy b/.env.copy new file mode 100644 index 0000000..f334e40 --- /dev/null +++ b/.env.copy @@ -0,0 +1,4 @@ +# Please add this in your .env global +STRIPE_ENDPOINT=XXXX +STRIPE_SECRET=XXXX +STRIPE_PUBLIC=XXXX \ No newline at end of file diff --git a/README.md b/README.md index 2ac50f1..8725246 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,33 @@ -Merci d'avoir acheté le module Stripe ! +# Stripe Module +### English -Il vous suffit de glisser ces fichiers dans la racine de ClientX ! +![Stripe logo](https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcSQFZVtgqQoU3xMNDMfYzfbAyC2LZJt_MwtHmJANd1MqAC4jjDpBY0opV2uR9FPL2V0qkA&usqp=CAU "Stripe logo") -Ajoutez la ligne ->addModule(StripeModule::class) dans index.php +The entire CLIENTXCMS team thanks you for this purchase. We hope you like it. -Puis rendez-vous dans Bases de Données dans l'espace Administration de ClientX puis faites Migrate. +To install this module please refer to the documentation. -Le tour est joué et vous avez maintenant accès au module Stripe. +## Support & Documentation # + +For any questions regarding this module, you should contact the CLIENTXCMS service support: + +- https://clientxcms.com/client/support Technical support +- https://clientxcms.com/docs/en/stripe Official documentation +- https://clientxcms.com/discord Community discord + + +CLIENTXCMS, Customer manager, easy billing made for everyone. + + +### French +Toute l'équipe de CLIENTXCMS vous remercie pour cette achat. Nous espérons que celui la vous plaisent. + +Pour installer ce module veuillez vous référez à la documentation. + +# Support & Documentation # +Pour toutes questions par rapport à ce module, vous devez vous adressez au support du service de CLIENTXCMS : +- https://clientxcms.com/client/support Support technique +- https://clientxcms.com/docs/fr/stripe documentation Officiel +- https://clientxcms.com/discord Discord communautaire + +CLIENTXCMS, Customer manager, easy billing made for everyone. diff --git a/src/.env.copy b/src/.env.copy new file mode 100644 index 0000000..f334e40 --- /dev/null +++ b/src/.env.copy @@ -0,0 +1,4 @@ +# Please add this in your .env global +STRIPE_ENDPOINT=XXXX +STRIPE_SECRET=XXXX +STRIPE_PUBLIC=XXXX \ No newline at end of file diff --git a/src/Actions/StripeAdminAction.php b/src/Actions/StripeAdminAction.php index 3f93c2d..1933fad 100644 --- a/src/Actions/StripeAdminAction.php +++ b/src/Actions/StripeAdminAction.php @@ -1,25 +1,12 @@ renderer = $renderer; - $this->table = $table; - } - - public function __invoke() - { - return $this->render('@stripe_admin/index', ['items' => $this->table->findAll()]); - } -} \ No newline at end of file + protected $routePrefix = "stripe.admin"; + protected $moduleName = "Stripe"; + protected $paymenttype = "stripe"; +} diff --git a/src/Actions/StripeApiAction.php b/src/Actions/StripeApiAction.php index eade54b..c521a2e 100644 --- a/src/Actions/StripeApiAction.php +++ b/src/Actions/StripeApiAction.php @@ -1,52 +1,45 @@ stripe = $stripe; - $this->table = $table; - $this->invoiceTable = $invoiceTable; + $this->manager = $manager; + $this->transaction = $transaction; + $this->user = $user; } public function __invoke(ServerRequestInterface $request) { - $signature = $request->getServerParams()["HTTP_STRIPE_SIGNATURE"]; - $webhook = $this->stripe->getWebhook($signature); - if ($webhook->type === 'checkout.session'){ - $object = $webhook->data->object; - $id = $object->metadata->invoice; - if ($object->payment_status !== "paid"){ - $this->invoiceTable->updateStatus(0, $id); - } - $this->invoiceTable->update($id, [ - 'paymentId' => $object->id - ]); - $this->table->createTransaction($webhook); - var_dump($webhook); + $webhook = $this->manager->getWebhook($request->getServerParams()['HTTP_STRIPE_SIGNATURE']); + $object = $webhook->data->object; + if (empty($object->metadata) === false){ + + $response = $this->manager->confirm($request); + return $this->json(['success' => $response instanceof Transaction]); + } + $id = $object->metadata->transaction; + + $userId = $object->metadata->user; + + $user = $this->user->find($userId); + $transaction = $this->transaction->findTransaction($id); + if ($transaction != null && $transaction->getState() === $transaction::PENDING) { + $response = $this->manager->test($transaction, $request, $user); + return $this->json(['success' => $response instanceof Transaction]); } + return $this->json(['error' => true]); - die(); } -} \ No newline at end of file +} diff --git a/src/Api/Entity/StripeUser.php b/src/Api/Entity/StripeUser.php index 771f570..8ce0863 100644 --- a/src/Api/Entity/StripeUser.php +++ b/src/Api/Entity/StripeUser.php @@ -3,7 +3,8 @@ use App\Account\User; -class StripeUser extends User { +class StripeUser extends User +{ /** * @var string @@ -19,4 +20,4 @@ public function setStripeId($stripeId) { $this->stripeId = $stripeId; } -} \ No newline at end of file +} diff --git a/src/Api/Stripe.php b/src/Api/Stripe.php index 5a73906..6c1ca27 100644 --- a/src/Api/Stripe.php +++ b/src/Api/Stripe.php @@ -1,7 +1,9 @@ logger = $logger; $this->setPrivateKey($privateKey); @@ -86,26 +89,31 @@ public function getPaymentIntent(string $id): PaymentIntent return $this->stripe->paymentIntents->retrieve($id); } - public function createPaymentSession(StripeUser $user, $items, array $urls, int $invoice): Session + public function createPaymentSession(StripeUser $user, $items, array $urls, Transaction $transaction): Session { - $session = $this->stripe->checkout->sessions->create([ - //'customer_email' => $user->getEmail(), - 'cancel_url' => $urls[1], - 'success_url' => $urls[0], - 'mode' => 'payment', - 'payment_method_types' => [ - 'card', - ], - - 'metadata' => [ - 'invoice' => $invoice, - 'user' => $user->getId() - ], - 'customer' => $user->getStripeId(), - 'line_items' => $items, - ]); + try { - return $session; + $session = $this->stripe->checkout->sessions->create([ + //'customer_email' => $user->getEmail(), + 'cancel_url' => $urls['cancel'], + 'success_url' => $urls['return'], + 'mode' => 'payment', + 'payment_method_types' => [ + 'card', + ], + + 'metadata' => [ + 'transaction' => $transaction->getId(), + 'user' => $user->getId() + ], + 'customer' => $user->getStripeId(), + 'line_items' => $items, + ]); + + return $session; + } catch (Exception $e){ + dd($e->getMessage()); + } } public function getCheckoutSessionFromIntent(string $paymentIntent): Session @@ -135,12 +143,10 @@ public function getWebhook(string $signature) { $payload = @file_get_contents('php://input'); try { - $webhook = Webhook::constructEvent($payload, $signature, $this->endpointkey); - } catch(\UnexpectedValueException | SignatureVerificationException $e) { + $webhook = Webhook::constructEvent($payload, $signature, $this->endpointkey, 0); + } catch (\UnexpectedValueException | SignatureVerificationException $e) { $this->logger->error($e->getMessage()); throw new \Exception($e->getMessage()); - - } return $webhook; } @@ -150,8 +156,8 @@ private function setEndpointKey($endpointkey) { if ($endpointkey === null) { - $this->logger->error("La clée webhook stripe est nulle."); - throw new \Exception("Erreur interne."); + $this->logger->error("Endpoint key is null. Please add env STRIPE_ENDPOINT with your key"); + throw new \Exception("Internal error"); } $this->endpointkey = $endpointkey; } @@ -160,8 +166,8 @@ private function setPublicKey($publicKey) { if ($publicKey === null) { - $this->logger->error("La clée publique stripe est nulle."); - throw new \Exception("Erreur interne."); + $this->logger->error("public key is null. Please add env STRIPE_PUBLIC with your key."); + throw new \Exception("Internal error"); } $this->publicKey = $publicKey; } @@ -169,8 +175,8 @@ private function setPublicKey($publicKey) private function setPrivateKey($privateKey) { if ($privateKey === null) { - $this->logger->error("La clée privée stripe est nulle."); - throw new \Exception("Erreur interne."); + $this->logger->error("private key is null. Please add env STRIPE_PRIVATE with your key."); + throw new \Exception("Internal error"); } $this->privateKey = $privateKey; \Stripe\Stripe::setApiKey($privateKey); @@ -181,5 +187,4 @@ protected function setStripeVersion() { StripeStripe::setApiVersion(self::STRIPE_VERSION); } - -} \ No newline at end of file +} diff --git a/src/StripeModule.php b/src/StripeModule.php index 22e9d79..e153106 100644 --- a/src/StripeModule.php +++ b/src/StripeModule.php @@ -8,7 +8,8 @@ use ClientX\Router; use Psr\Container\ContainerInterface; -class StripeModule extends Module { +class StripeModule extends Module +{ const DEFINITIONS = __DIR__ . '/config.php'; const MIGRATIONS = __DIR__ . '/db/migrations'; @@ -16,10 +17,11 @@ class StripeModule extends Module { public function __construct(Router $router, RendererInterface $renderer, ContainerInterface $container) { $renderer->addPath("stripe_admin", __DIR__ . '/Views'); - $router->post('/api/stripe', StripeApiAction::class, 'stripe.webhook'); + $router->post('/stripe/api', StripeApiAction::class, 'stripe.webhook'); if ($container->has('admin.prefix')) { $prefix = $container->get('admin.prefix'); $router->get($prefix . "/stripe", StripeAdminAction::class, 'stripe.admin'); + $router->get($prefix . "/stripe", StripeAdminAction::class, 'stripe.admin.index'); } } -} \ No newline at end of file +} diff --git a/src/StripePaymentManager.php b/src/StripePaymentManager.php index 1d3b7f6..daf24c5 100644 --- a/src/StripePaymentManager.php +++ b/src/StripePaymentManager.php @@ -1,184 +1,149 @@ stripe = $stripe; - $this->session = $session; + private Stripe $stripe; + private UserTable $table; + private RendererInterface $renderer; + + public function __construct( + Router $router, + Auth $auth, + TransactionService $service, + Stripe $stripe, + UserTable $table, + RendererInterface $renderer + ) { + parent::__construct($router, $auth, $service); + $this->stripe = $stripe; + $this->table = $table; $this->renderer = $renderer; - $this->router = $router; - $this->user = $table->find($user->getId()); - $this->table = $table; } - public function process(ServerRequestInterface $request, $product = null, bool $isBasket = false, ?Basket $basket = null) + public function process(Transaction $transaction, Request $request, User $user) { - $this->request = $request; - $this->isBasket = $isBasket; - $this->basket = $basket; - if (!$isBasket) { - $this->product = $product; - } else { - $this->products = $product; + $user = $this->getUser(); + if ($user === null) { + return; } - $user = $this->createStripeUser($this->user); - $invoice = $request->getAttribute('invoice_id', null); - $this->session->set(self::SESSION_NAME, $invoice); - $session = $this->stripe->createPaymentSession($user, $this->makeItems(), $this->getRedirectUrls(), $invoice); - return $this->renderer->render("@stripe_admin/autoredirect", ['session' => $session, 'key' => $this->stripe->getPublicKey()]); + $items = collect($transaction->getItems())->map(function (TransactionItem $item) use ($transaction) { + return [ + [ + 'price_data' => + [ + 'currency' => $transaction->getCurrency(), + 'unit_amount' => $item->priceWithTax() * 100, + 'product_data' => ["name" => $item->getName()] + ], + 'quantity' => $item->getQuantity(), + ] + ]; + })->toArray(); + + $user = $this->createStripeUser($this->auth->getUser()); + $session = $this->stripe->createPaymentSession($user, $items, $this->getRedirectsLinks($request, $transaction), $transaction); + $params = ['session' => $session, 'key' => $this->stripe->getPublicKey()]; + return $this->renderer->render("@stripe_admin/autoredirect", $params); + } + + public function refund(array $items): bool + { + // TODO : Implemente + return false; } private function createStripeUser(StripeUser $stripeUser) { try { - $user = $this->table->findBy('stripe_id', $stripeUser->getStripeId()?? ""); - if ($user->getStripeId() === null || $user->getStripeId() === "") { - throw new \ClientX\Database\NoRecordException(); - } - } catch (NoRecordException $e){ - $stripeUser->setStripeId($this->stripe->createCustomer($stripeUser)->id); + /** @var StripeUser */ + $user = $this->table->findBy('stripe_id', $stripeUser->getStripeId()); + $stripeUser->setStripeId($user->getStripeId()); + } catch (NoRecordException $e) { + $this->stripe->createCustomer($stripeUser); $this->table->update($stripeUser->getId(), [ 'stripe_id' => $stripeUser->getStripeId() ]); } return $stripeUser; } - private function getUri(string $link) + public function execute(Transaction $transaction, Request $request, User $user) { - if (!$this->getRedirectsLinks()) { - throw $this->stripe->getLogger()->error('the redirects links is missing for generate uri'); - } - if (!isset($this->getRedirectsLinks()[$link])) { - throw $this->stripe->getLogger()->error(sprintf('The link array does not contain the key %s', $link)); - } - return $this->getRedirectsLinks()[$link] ?? null; - } - private function getRedirectUrls():array - { - return [$this->getUri('return'), $this->getUri('cancel')]; + } - private function getRedirectsLinks(?ServerRequestInterface $request = null):array - { - if ($this->links) { - return $this->links; - } - $request = $request ?? $this->request; - $domain = RequestHelper::getDomain($request); - $isRenewal = false; - if ($request) { - $isRenewal = strpos($request->getUri()->getPath(), 'services') ==! false; + public function test(Transaction $transaction, Request $request, User $user){ + $params = $request->getServerParams(); + $signature = $params["HTTP_STRIPE_SIGNATURE"]; + $webhook = $this->stripe->getWebhook($signature); + if ($webhook->type === 'checkout.session.completed') { + $object = $webhook->data->object; + $id = $object->id; + $transaction->setTransactionId($id); + $this->service->updateTransactionId($transaction); + + if ($object->payment_status !== "paid") { + $transaction->setState($transaction::REFUSED); + $transaction->setReason("Stripe error"); + $this->service->changeState($transaction); + $this->service->setReason($transaction); + } else { + + if ($this->service->isOrder($transaction)) { + $this->service->confirmOrder($transaction, $user->getId()); + } + $transaction->setState($transaction::COMPLETED); + $this->service->changeState($transaction); + return $transaction; + } + } else if ($webhook->type === 'payment_intent.succeeded') { + + $object = $webhook->data->object; + $id = $webhook->id; + $transaction->setTransactionId($id); + $this->service->updateTransactionId($transaction); + return $transaction; + } - $id = $request->getAttribute('id'); - $type = $request->getParsedBody()['type']; - $prefix = ($this->isBasket) ? 'basket' : 'shop'; - $prefix = ($isRenewal) ? 'shop.services.renew' : $prefix; - $cancel = $domain . $this->router->generateURI("$prefix.cancel", compact('type', 'id')); - $return = $domain . $this->router->generateURI("$prefix.return", compact('type', 'id')); - $this->links = compact('return', 'cancel'); - return compact('return', 'cancel'); } - public function execute(ServerRequestInterface $request, $product = null, bool $isBasket = false, ?Basket $basket = null) + public function confirm(Request $request) { - //$this->createStripeUser($this->user); - if ($this->session->get(self::SESSION_NAME) == null){ - throw new \Exception('the invoice id is missing'); + $params = $request->getServerParams(); + $signature = $params["HTTP_STRIPE_SIGNATURE"]; + $webhook = $this->stripe->getWebhook($signature); + if ($webhook->type === 'payment_intent.succeeded') { + $transaction = $this->service->getLastTransaction(); + + $object = $webhook->data->object; + $id = $object->id; + $transaction->setTransactionId($id); + $this->service->updateTransactionId($transaction); } - $invoiceId = $this->session->get(self::SESSION_NAME); - return ['id' => $invoiceId, 'payment_id' => null]; - } - - private function makeItems():array{ - $items = []; - if ($this->isBasket) { - foreach ($this->products as $row) { - $product = $row->getProduct(); - $amount = $product->getPrice(); - $name = $product->getName(); - $quantity = $row->getQuantity(); - } - } else { - $product = $this->product; - $amount = $product->getPrice(); - $name = $product->getName(); - $quantity = 1; - } - - $items[] = ['price_data' => - [ - 'currency' => $this->currency, - 'unit_amount' => $amount * 100, - 'product_data' => ["name" => $name] - ], - 'quantity' => $quantity, - ]; - return $items; + + public function getWebhook(string $signature) + { + return $this->stripe->getWebhook($signature); } - -} \ No newline at end of file +} diff --git a/src/StripePaymentType.php b/src/StripePaymentType.php index 7b7b7c1..2301032 100644 --- a/src/StripePaymentType.php +++ b/src/StripePaymentType.php @@ -3,7 +3,8 @@ use ClientX\Payment\PaymentTypeInterface; -class StripePaymentType implements PaymentTypeInterface { +class StripePaymentType implements PaymentTypeInterface +{ public function getName(): string { @@ -12,7 +13,7 @@ public function getName(): string public function getTitle(): ?string { - return "Stripe (Carte bleu)"; + return "Stripe (Blue Cart)"; } public function getManager(): string @@ -34,4 +35,4 @@ public function canPayWith(): bool { return true; } -} \ No newline at end of file +} diff --git a/src/config.php b/src/config.php index 6a32789..d14cf08 100644 --- a/src/config.php +++ b/src/config.php @@ -5,21 +5,17 @@ use App\Stripe\StripePaymentType; use App\Stripe\StripeSettings; -use function ClientX\setting; use function DI\add; use function DI\autowire; use function DI\get; return [ - 'auth.entity' => StripeUser::class, + 'auth.entity' => StripeUser::class, 'payments.type' => add(get(StripePaymentType::class)), - 'stripe.key' => setting("stripe_key"), - 'stripe.secret' => setting("stripe_secret"), - 'stripe.endsecret' => setting('stripe_endsecret'), 'admin.settings'=> add(get(StripeSettings::class)), - 'csrf.except' => add('stripe.webhook'), + 'csrf.except' => add(['stripe.webhook']), Stripe::class => autowire() - ->constructorParameter('endpointkey', get('stripe.endsecret')) - ->constructorParameter('privateKey', get('stripe.secret')) - ->constructorParameter('publicKey', get('stripe.key')) -]; \ No newline at end of file + ->constructorParameter('endpointkey', $_ENV['STRIPE_ENDPOINT'] ?? null) + ->constructorParameter('privateKey', $_ENV['STRIPE_SECRET'] ?? null) + ->constructorParameter('publicKey', $_ENV['STRIPE_PUBLIC'] ?? null) +]; diff --git a/src/db/migrations/20201212111041_add_stripe_id_to_user.php b/src/db/migrations/20201212111041_add_stripe_id_to_user.php index 27695d4..e343050 100644 --- a/src/db/migrations/20201212111041_add_stripe_id_to_user.php +++ b/src/db/migrations/20201212111041_add_stripe_id_to_user.php @@ -7,8 +7,7 @@ class AddStripeIdToUser extends AbstractMigration public function change() { $table = $this->table("users"); - if (!$table->hasColumn('stripe_id')){ - + if (!$table->hasColumn('stripe_id')) { $table->addColumn("stripe_id", "string", ['null' => true]); $table->addIndex("stripe_id", ['unique' => true]); }