diff --git a/doc/dev-setup.md b/doc/dev-setup.md index 70aaaeba0..90e58b843 100644 --- a/doc/dev-setup.md +++ b/doc/dev-setup.md @@ -208,14 +208,14 @@ Ensuite pour le paiement, il faut utiliser ces informations [de carte](https://w #### Callbacks de paiement -Après le paiement, paybox effectue un retour sur le serveur et c'est suite à ce retour que l'on effectue des actions -comme l'ajout de la cotisation. +Afin de simuler un appel Paybox, il y a une commande disponible (en environnement de `dev` uniquement). -Afin d'en simplifier l'appel, il existe une commande dédiée qui s'appelle comme cela, où l'argument en exemple -correspond à l'URL de la page de retour sur le site après paiement. +Cette commande utilise une série de questions pour guider son utilisation. +Il faut cependant récupérer le cmd qui est indiqué dans la fenêtre de Paybox. +Ce paramètre est de la forme : `C2026-170120261126-0-1-ADMIN-84B` ou `F202601-1701-JDOE-11f8d` ``` -bin/console dev:callback-paybox-cotisation "https://localhost:9206/association/paybox-redirect?total=3000&cmd=C2020-150120201239-0-770-GALLO-E4F&autorisation=XXXXXX&transaction=588033888&status=00000" +bin/console dev:paybox-callback-simulator ``` ### GitHub diff --git a/sources/AppBundle/Command/DevCallBackPayboxCotisationCommand.php b/sources/AppBundle/Command/DevCallBackPayboxCotisationCommand.php deleted file mode 100644 index 1d48dbfc9..000000000 --- a/sources/AppBundle/Command/DevCallBackPayboxCotisationCommand.php +++ /dev/null @@ -1,55 +0,0 @@ -setName('dev:callback-paybox-cotisation') - ->addArgument('url_paiement_effectue', InputArgument::REQUIRED) - ->setHelp($help); - } - - protected function execute(InputInterface $input, OutputInterface $output): int - { - $parsedUrl = parse_url((string) $input->getArgument('url_paiement_effectue')); - - $query = $parsedUrl['query']; - - parse_str($query, $params); - - $callBackParameters = [ - 'total' => $params['total'], - 'cmd' => $params['cmd'], - 'autorisation' => $params['autorisation'], - 'transaction' => $params['transaction'], - 'status' => $params['status'], - ]; - - $url = 'https://apachephp:80/association/paybox-callback?' . http_build_query($callBackParameters); - - $curl = curl_init($url); - curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false); - curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, 0); - curl_exec($curl); - - $output->writeln("Appel au callback de paiement de cotisation effectué"); - - return Command::SUCCESS; - } -} diff --git a/sources/AppBundle/Command/PayboxCallbackSimulatorCommand.php b/sources/AppBundle/Command/PayboxCallbackSimulatorCommand.php new file mode 100644 index 000000000..a541402f5 --- /dev/null +++ b/sources/AppBundle/Command/PayboxCallbackSimulatorCommand.php @@ -0,0 +1,168 @@ +title("Commande pour la simulation d'appel de Paybox"); + $style->info("Cette commande permet de simuler des appels de callback depuis Paybox.\nLaissez-vous guider par les questions.\n"); + + $question = new ChoiceQuestion('Quel type de paiement souhaitez-vous simuler ?', [ + 'Cotisation', + 'Inscription', + ], 'Cotisation'); + $payementType = $helper->ask($input, $output, $question); + + if ($payementType === 'Cotisation') { + $example = 'C2026-170120261126-0-1-ADMIN-84B'; + $regexp = '"^C\d{4}"'; + } else { + $example = 'F202601-1701-JDOE-11f8d'; + $regexp = '"^F\d{4}"'; + } + $question = new Question(sprintf('Pour quel identifiant de paiement (cmd) ? (par exemple: %s)', $example)); + $cmd = $helper->ask($input, $output, $question); + $question->setValidator(function ($cmd) use ($regexp): void { + if (!preg_match($regexp, $cmd)) { + throw new \RuntimeException( + sprintf('Le format du CMD n\'est pas valide. Il doit être de la forme : %s', $regexp), + ); + } + }); + + $question = new ChoiceQuestion('Quel statut de paiement ?', [ + 'Validé', + 'Déjà effectué', + 'Annulé', + 'Refusé', + ], 'Validé'); + $status = $helper->ask($input, $output, $question); + + if ($payementType === 'Cotisation') { + $url = $this->callCotisation($cmd, $status); + } else { + $url = $this->callInvoice($cmd, $status); + } + + $style->title('Résumé'); + $style->text([ + "Vous êtes sur le point de simuler un appel Paybox :", + "Type de paiement: $payementType", + "Statut du paiement: $status", + "CMD: $cmd", + "URL: $url", + "", + ]); + + $question = new ConfirmationQuestion('Êtes-vous sûr de vouloir faire cet appel Paybox (oui/non)?',false, '/^(y|o)/i'); + if ($helper->ask($input, $output, $question)) { + $this->callCallback($url); + $style->success('Appel Paybox effectué'); + return Command::SUCCESS; + } + $style->warning('Appel Paybox annulé'); + + return Command::SUCCESS; + } + + private function callCotisation(string $cmd, string $status): string + { + $account = $this->cotisations->getAccountFromCmd($cmd); + $cotisation = $this->cotisations->obtenirDerniere(MemberType::from($account['type']), $account['id']); + if (!$cotisation) { + throw new \RuntimeException( + sprintf('Cotisation non trouvée avec ce CMD: %s', $cmd), + ); + } + $url = $this->urlGenerator->generate('membership_payment'); + + return $this->buildUrl($url, (float) $cotisation['montant'], $cmd, $status); + } + + private function callInvoice(string $cmd, string $status): string + { + $invoice = $this->invoiceRepository->getByReference($cmd); + if (!$invoice instanceof Invoice) { + throw new \RuntimeException( + sprintf('Facture non trouvée avec ce CMD: "%s"', $cmd), + ); + } + $event = $this->eventRepository->get($invoice->getForumId()); + if (!$event instanceof Event) { + throw new \RuntimeException( + sprintf('Inscription non trouvé avec ce CMD: "%s"', $cmd), + ); + } + + $url = $this->urlGenerator->generate('ticket_paybox_callback', ['eventSlug' => $event->getPath()]); + + return $this->buildUrl($url, $invoice->getAmount(), $cmd, $status); + } + + private function buildUrl(string $baseUrl, float $amount, string $cmd, string $state): string + { + $status = match ($state) { + 'Déjà effectué' => PayboxResponse::STATUS_DUPLICATE, + 'Annulé' => '00117', + 'Refusé' => '001XX', + default => PayboxResponse::STATUS_SUCCESS, + }; + + $callBackParameters = [ + 'total' => $amount * 100, + 'cmd' => $cmd, + 'autorisation' => 'fake_' . bin2hex(random_bytes(5)), + 'transaction' => random_int(400000, 600000), + 'status' => $status, + ]; + + return 'https://apachephp:80' . $baseUrl . '?' . http_build_query($callBackParameters); + } + + private function callCallback(string $url): string + { + $curl = curl_init($url); + curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false); + curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, 0); + curl_exec($curl); + + return $url; + } +}