<?php
namespace App\Controller;
use App\Repository\InterventionRepository;
use App\Traits\Autowired\Vendor\LoggerTrait;
use App\Traits\Autowired\Vendor\SeoPageTrait;
use App\Traits\Autowired\Vendor\TranslatorTrait;
use Stripe\Exception\CardException;
use Symfony\Component\HttpFoundation\Session\SessionInterface;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpFoundation\Session\Session;
use Symfony\Component\HttpKernel\Exception\HttpException;
use App\Entity\Commande;
use App\Entity\Intervention;
use App\Entity\Setting;
use App\Form\Type\CommandeType;
use App\Form\Type\Step2Type;
use App\Form\Type\Step3Type;
use App\Form\Type\VisioStep1Type;
use App\Traits\ClientManagerTrait;
use App\Traits\CommandeManagerTrait;
use App\Traits\DistanceManagerTrait;
use App\Traits\DoctorManagerTrait;
use App\Traits\InterventionManagerTrait;
use App\Traits\LeMedecinServiceTrait;
use App\Traits\NotificationManagerTrait;
use App\Traits\PriceServiceTrait;
use App\Traits\StripeServiceTrait;
use App\Entity\Docteur;
use App\Manager\UserManager;
use App\Services\CommandeService;
use App\Services\TeleconsultationService;
use App\Traits\HubspotServiceTrait;
use App\Traits\UserManagerTrait;
use Symfony\Component\Form\FormInterface;
use Symfony\Component\HttpFoundation\RedirectResponse;
class CommandeController extends AbstractController
{
use LoggerTrait;
private TeleconsultationService $teleconsultationService;
private CommandeService $commandeService;
public function __construct(
TeleconsultationService $teleconsultationService,
CommandeService $commandeService
) {
$this->teleconsultationService = $teleconsultationService;
$this->commandeService = $commandeService;
}
use DistanceManagerTrait;
use StripeServiceTrait;
use DoctorManagerTrait;
use ClientManagerTrait;
use PriceServiceTrait;
use CommandeManagerTrait;
use InterventionManagerTrait;
use NotificationManagerTrait;
use LeMedecinServiceTrait;
use SeoPageTrait;
use TranslatorTrait;
use UserManagerTrait;
use HubspotServiceTrait;
/**
* Handle form submission for the Step3Type form.
*
* @param Request $request The request object
* @param Commande $commande The Commande entity
*
* @return RedirectResponse The redirect response
*/
private function handleFormSubmission(FormInterface $form, Commande $commande): RedirectResponse
{
}
#[Route('/fr/commande/mode', options: ['sitemap' => true])]
public function domicile(Request $request)
{
$titre = "Urgence Docteurs : Choisissez Téléconsultation, Visio ou Consultation à Domicile";
$description = "En téléconsultation, en visio ou à domicile, Urgence Docteurs vous offre des solutions médicales flexibles et adaptées à vos besoins médicaux en SOS.";
$this->seoPage
->setTitle($titre)
->addMeta('name', 'description', $description)
->addMeta('property', 'og:title', $titre)
->addMeta('property', 'og:description', $description)
->addMeta('property', 'og:url', $this->generateUrl('app_commande_domicile'))
->addMeta('property', 'twitter:title', $titre)
->addMeta('property', 'twitter:description', $description);
$this->resetSession();
$em = $this->getDoctrine()->getManager();
// Formulaire de commande
$commande = new Commande;
$formCommande = $this->createForm(CommandeType::class, $commande, []);
$formCommande->handleRequest($request);
if ($formCommande->isSubmitted() && $formCommande->isValid()) {
$commande->setType(Intervention::TYPE_DOMICILE);
$client = $this->clientManager->createByCommand($commande);
$commande->setClient($client);
$customer = $this->stripeService->createCustomer($commande->getEmail());
$commande->setStripeCustomer($customer->id);
try {
$contactId = $this->hubspotService->createContact($commande);
$commande->setHubspotContactId($contactId);
$dealId = $this->hubspotService->createTransactionStep1($commande);
$commande->setHubspotDealId($dealId);
}
catch (\Exception $exception){
$this->logger->error('Hubspot err:: ' . $exception->getMessage(), [
'exception' => $exception,
]);
}
$em->persist($commande);
$em->flush();
$this->get('session')->set('commande', $commande->getId());
return $this->redirectToRoute('app_commande_step2');
}
return $this->render(
'Commande/domicile.html.twig',
[
'form' => $formCommande->createView(),
'mode' => 'domicile'
]
);
}
#[Route('/fr/commande/mode/visio', options: ['sitemap' => true])]
public function visio(Request $request)
{
$titre = 'Téléconsultation Médicale en Visio - Urgence Docteurs Disponibles 24/7';
$description = 'Avec Urgence Docteurs, accédez à une téléconsultation en visio sécurisée, 24/7. Obtenez des conseils médicaux et des prescriptions rapidement.';
$this->seoPage
->setTitle($titre)
->addMeta('name', 'description', $description)
->addMeta('property', 'og:title', $titre)
->addMeta('property', 'og:description', $description)
->addMeta('property', 'og:url', $this->generateUrl('app_commande_visio', []))
->addMeta('property', 'twitter:title', $titre)
->addMeta('property', 'twitter:description', $description);
$em = $this->getDoctrine()->getManager();
// Formulaire de commande
$commande = new Commande;
$formCommande = $this->createForm(VisioStep1Type::class, $commande, []);
$formCommande->handleRequest($request);
if ($formCommande->isSubmitted() && $formCommande->isValid()) {
$commande->setType(Intervention::TYPE_VISIO);
$client = $this->clientManager->createByCommand($commande);
$commande->setClient($client);
$customer = $this->stripeService->createCustomer($commande->getEmail());
$commande->setStripeCustomer($customer->id);
try {
$contactId = $this->hubspotService->createContact($commande);
$commande->setHubspotContactId($contactId);
$dealId = $this->hubspotService->createTransactionStep1($commande);
$commande->setHubspotDealId($dealId);
}
catch(\Exception $exception){
$this->logger->error('Hubspot err:: ' . $exception->getMessage(), [
'exception' => $exception,
]);
}
$em->persist($commande);
$em->flush();
$this->get('session')->set('commande', $commande->getId());
return $this->redirectToRoute('app_commande_step2');
}
return $this->render(
'Commande/visio.html.twig',
[
'form' => $formCommande->createView(),
'mode' => 'visio'
]
);
}
#[Route('/fr/commande/step2')]
public function step2Action(Request $request)
{
$titre = "Sélectionnez Votre spécialité et vos symptômes";
$description = "Urgence Docteurs vous propose de choisir parmi un large choix de spécialités et de symptômes afin de vous prendre en charge dans les meilleurs conditions.";
$this->seoPage
->setTitle($titre)
->addMeta('name', 'description', $description)
->addMeta('property', 'og:title', $titre)
->addMeta('property', 'og:description', $description)
->addMeta('property', 'og:url', $this->generateUrl('app_commande_step2', array(), true))
->addMeta('property', 'twitter:title', $titre)
->addMeta('property', 'twitter:description', $description);
$em = $this->getDoctrine()->getManager();
$commandeId = $this->get('session')->get('commande');
/** @var Commande $commande */
$commande = $this->commandeManager->findOneBy(['id' => $commandeId]);
if (!$commande) {
return $this->redirectToRoute('app_cms_prendrerdv');
}
$form = $this->createForm(Step2Type::class, null, ['type' => 'domicile']);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$specialite = $form->get('specialite')->getData();
$symptome = $form->get('symptome')->getData();
$commande->setSpecialite($specialite);
$commande->setSymptome($symptome);
$em->persist($commande);
$em->flush();
return $this->redirectToRoute('app_commande_step3');
}
return $this->render(
'Commande/step2.html.twig',
[
'form' => $form->createView(),
'mode' => 'visio'
]
);
}
#[Route('/fr/commande/step3')]
public function step3Action(Request $request): Response
{
$titre = "Confirmez votre rendez-vous";
$description = "Un médecin en SOS vous prend en charge d’ici quelques minutes afin de vous émettre une ordonnance et un arrêt maladie.";
$this->seoPage
->setTitle($titre)
->addMeta('name', 'description', $description)
->addMeta('property', 'og:title', $titre)
->addMeta('property', 'og:description', $description)
->addMeta('property', 'og:url', $this->generateUrl('app_commande_step2', array(), true))
->addMeta('property', 'twitter:title', $titre)
->addMeta('property', 'twitter:description', $description);
$commande = $this->commandeService->commandeBySession();
if (!$commande) {
return $this->redirectToRoute('app_cms_prendrerdv');
}
$form = $this->createForm(Step3Type::class, null);
$form->handleRequest($request);
$paymentIntentRequest = null;
if ($form->isSubmitted() && $form->isValid()) {
$this->commandeService->changeCommandeConverted($commande);
$cardToken = $form->get('cardToken')->getData();
try {
$paymentIntentRequest = $request->request->get('paymentIntent');
$result = $this->teleconsultationService->modificationCommande($commande, $cardToken, $paymentIntentRequest);
$price_special = $this->priceService->getPrice($commande->getType(), $commande->getSpecialite());
try {
$this->hubspotService->updateTransaction($commande,$price_special);
}
catch (\Exception $exception){
$this->logger->error('Hubspot err:: ' . $exception->getMessage(), [
'exception' => $exception,
]);
}
if (!empty($result)) {
if ($result['redirectToRoute']) {
return $this->redirectToRoute(
$result['route'],
$result['payload']
);
} else {
return $this->redirect($result['route'], 302);
}
}
return $this->redirectToRoute('app_commande_intervention');
}
catch (CardException $exception){
[$price, $priceSpecial, $intent,$paymentIntent, $isWeekend] = $this->commandeService->dataCommand($commande);
return $this->render('Commande/step3.html.twig', [
'weekend' => $isWeekend,
'err' => strpos($exception->getMessage(), "Your card has insufficient funds") !== false ? "Paiement refusé. Fonds insuffisants." : "Paiement refusé. Veuillez changer votre moyen de paiement",
'specialiste' => $commande->getSpecialite()->getId() === 1,
'form' => $form->createView(),
'mode' => $commande->getType(),
'price' => $price,
'price_special' => $priceSpecial,
'paymentIntent' => $paymentIntent,
'intent' => $intent
]);
}
}
[$price, $priceSpecial, $intent,$paymentIntent, $isWeekend] = $this->commandeService->dataCommand($commande);
return $this->render('Commande/step3.html.twig', [
'weekend' => $isWeekend,
'specialiste' => $commande->getSpecialite()->getId() === 1,
'form' => $form->createView(),
'mode' => $commande->getType(),
'price' => $price,
'paymentIntent' => $paymentIntent,
'price_special' => $priceSpecial,
'intent' => $intent
]);
}
#[Route('/fr/commande/medecin-pas-trouve')]
public function doctorNotFound()
{
return $this->render(
'Commande/doctorNotFound.html.twig',
[]
);
}
/**
* Etape 3 ( téléconsultation) : Simple page de confirmatiton
* Route : commande/validation
* @return Response
*/
public function validationAction()
{
$titre = $this->translator->trans('seo.commande.validation.titre');
$description = $this->translator->trans('seo.commande.validation.description');
$this->seoPage
->setTitle($titre)
->addMeta('name', 'description', $description)
->addMeta('property', 'og:title', $titre)
->addMeta('property', 'og:description', $description)
->addMeta('property', 'og:url', $this->generateUrl('commande_validation', array(), true))
->addMeta('property', 'twitter:title', $titre)
->addMeta('property', 'twitter:description', $description);
return $this->render('UrgenceDocteursUserBundle:Public:commande_validation.html.twig');
}
/**
* @param $reason
* @return Response
*/
public function echecAction($reason)
{
$titre = $this->translator->trans('seo.commande.echec.titre');
$description = $this->translator->trans('seo.commande.echec.description');
$this->seoPage
->setTitle($titre)
->addMeta('name', 'description', $description)
->addMeta('property', 'og:title', $titre)
->addMeta('property', 'og:description', $description)
->addMeta('property', 'og:url', $this->generateUrl('commande_echec', array('reason' => $reason), true))
->addMeta('property', 'twitter:title', $titre)
->addMeta('property', 'twitter:description', $description);
$this->get('session')->remove('intervention');
$noDocteurs = false;
return $this->render(
'UrgenceDocteursUserBundle:Public:commande_echec.html.twig',
[
'reason' => $reason,
'noDocteurs' => $noDocteurs
]
);
}
/**
*
* Route : commande/intervention
* Page after ask for teleconsultation or consultation
* @return Response
*/
#[Route('/fr/commande/intervention')]
public function intervention()
{
/// START SEO..
$titre = $this->translator->trans('Demande d\'intervention en cours');
$description = $this->translator->trans('seo.commande_intervention.description');
$this->seoPage
->setTitle($titre)
->addMeta('name', 'description', $description)
->addMeta('property', 'og:title', $titre)
->addMeta('property', 'og:description', $description)
->addMeta('property', 'og:url', $this->generateUrl('app_commande_intervention', array(), true))
->addMeta('property', 'twitter:title', $titre)
->addMeta('property', 'twitter:description', $description);
/// END SEO
/** @var Session $session */
$session = $this->get('session');
$session->remove('iframe');
$interventionSession = $session->get('intervention');
$interventionRepo = $this->getDoctrine()->getRepository(Intervention::class);
/** @var Intervention $intervention */
$intervention = $interventionRepo->findOneBy(['numeroReference' => $interventionSession]);
// protect null infos
if (!$intervention) {
$session->clear();
return $this->redirectToRoute('app_cms_prendrerdv');
}
$modeCommande = $intervention->getModeIntervention();
$latitude = null;
$longitude = null;
return $this->render(
'Commande/intervention.html.twig',
[
'intervention' => $intervention,
'latitude' => $latitude,
'longitude' => $longitude,
'modeCommande' => $modeCommande,
'error' => false
]
);
}
/**
* Ajax call from page doctor search
* @return Response
*/
#[Route('/fr/commande/intervention/reference')]
public function interventionReference(SessionInterface $session, InterventionRepository $interventionRepository)
{
/** @var Intervention $intervention */
$intervention = $session->get('intervention');
if (!$intervention) throw new HttpException(500, 'Error Ref');
$intervention = $interventionRepository
->findOneBy(['numeroReference' => $intervention]);
if (!$intervention) {
throw new HttpException(500, 'Error intervention');
}
$image = null;
$docteur = $intervention->getDocteur();
$user = $this->userManager->getUserByDocteur($docteur);
$info = [
'etat' => $intervention->getEtat(),
'firstname' => ($intervention->getDocteur()) ? $user->getFirstname() : null,
'lastname' => ($intervention->getDocteur()) ? $user->getLastname() : null,
'phone' => ($intervention->getDocteur()) ? $user->getPhone() : null,
'latitude' => ($intervention->getDocteur()) ? $intervention->getDocteur()->getLatitude() : null,
'longitude' => ($intervention->getDocteur()) ? $intervention->getDocteur()->getLongitude() : null,
'urlVisio' => ($intervention->getDocteur()) ? $intervention->getDocteur()->getUrlClientVisio() : null,
'image' => $image
];
return new JsonResponse($info);
}
#[Route('/fr/commande/intervention/cancel')]
public function interventionCancel()
{
$intervention = $this->get('session')->get('intervention');
if (!$intervention) throw new HttpException(500, 'Error Ref');
$intervention = $this->getDoctrine()
->getManager()
->getRepository('UrgenceDocteursPublicBundle:Intervention')
->findBy(array('numeroReference' => $intervention));
$intervention = $intervention[0];
if (!$intervention) throw new HttpException(500, 'Error intervention');
$etat = $intervention->getEtat();
if ($etat == 'initConsultation' || $etat == 'endConsultation') throw new HttpException(403, 'intervention.enCours');
$intervention->setEtat('annule');
$this->getDoctrine()->getManager()->persist($intervention);
$this->getDoctrine()->getManager()->flush();
$this->launchCancel($intervention);
return new Response(json_encode(array('int' => $intervention->getId())));
}
/**
* @param $data
* @throws \Exception
*/
private function launchCancel($data)
{
$onesignal = $this->get('onesignal.docteur');
$infos = array(
'adresse' => $data->getAdresse(),
'codePostal' => $data->getCodePostal(),
'complement' => $data->getComplement(),
'symptomes' => $data->getSymptomes(),
'typeIntervention' => $data->getTypeIntervention(),
'numeroReference' => $data->getNumeroReference(),
'client' => $data->getClient(),
'specialite' => $data->getSpecialite()
);
$headings = array('en' => 'Urgence Docteurs Pro');
$contents = array('en' => 'Consultation en urgence annulée');
$dataNotif = array('type' => 'docteur.interventionCancel', 'infos' => $infos);
$include_player_ids = array();
$included_segments = array();
$excluded_segments = array();
$url = '';
$docteur = $data->getDocteur();
$user = $this->userManager->getUserByDocteur($docteur);
// Retrieve Docteur =>
$include_player_ids[] = $user->getId();
$notification = array(
'headings' => $headings,
'contents' => $contents,
'data' => $dataNotif,
'include_player_ids' => $include_player_ids,
'included_segments' => $included_segments,
'excluded_segments' => $excluded_segments,
// 'url' => $url,
// 'send_after' => '2016-12-27 22:30:00 GMT+0800',
'ios_badgeType' => 'Increase',
'ios_badgeCount' => 1
);
$response = $onesignal->sendMessage($notification);
$return = json_encode($response);
// Email Part
$email = $data->getClient()->getUser()->getEmail();
if (empty($email)) throw new HttpException(500, 'Email Empty');
// Set the price => montant
$prix = $data->getPrix();
$montant = 0;
$now = new \DateTime();
$dateIntervention = $data->getHorodateCreation();
$dateIntervention->modify("+10 minutes");
if ($now > $dateIntervention) $montant = round($prix / 2, 2);
// Send Email to the current User
$subjectPatient = $this->translator->trans('mail.intervention.cancel.patient');
$subjectDocteur = $this->translator->trans('mail.intervention.cancel.docteur');
$emailClient = null;
if ($data->getTypeIntervention() == 'web') {
if ($data->getCommande()) $emailClient = $data->getCommande()->getEmail();
else $emailClient = null;
} else $emailClient = $data->getClient()->getUser()->getEmail();
$mail = array(
'image' => $this->getParameter('mail.image'),
'url' => $this->getParameter('mail.url'),
'site' => $this->getParameter('mail.site'),
'author' => $this->getParameter('mail.author'),
'copyright' => $this->getParameter('mail.copyright')
);
// Envoi d'email => Patient
$message = (new \Swift_Message())
->setSubject($subjectPatient)
->setFrom($this->getParameter('admin_email'), $this->getParameter('site'))
->setTo($emailClient)
->setBody($this->renderView(
'UrgenceDocteursUserBundle:Template:mail/Annulation_urgence_patient.html.twig',
array(
'sujet' => $subjectPatient,
'montant' => $montant,
'mail' => $mail
)
), 'text/html');
if ($this->getParameter('environment') == 'prod' && $emailClient) $this->get('mailer')->send($message);
// Envoi d'email => Docteur
$message = (new \Swift_Message())
->setSubject($subjectDocteur)
->setFrom($this->getParameter('admin_email'), $this->getParameter('site'))
->setTo($data->getDocteur()->getUser()->getEmail())
->setBody($this->renderView(
'UrgenceDocteursUserBundle:Template:mail/Annulation_urgence_docteur.html.twig',
array(
'sujet' => $subjectDocteur,
'infos' => $infos,
'montant' => $montant,
'mail' => $mail
)
), 'text/html');
if ($this->getParameter('environment') == 'prod') $this->get('mailer')->send($message);
// Charge Stripe
if ($montant > 0) {
$card = $data->getCarteBancaire();
$client = $data->getClient();
$email = $client->getUser()->getEmail();
$stripeKey = ($this->getParameter('environment') == 'prod') ? $this->getParameter('stripe_live_key') : $this->getParameter('stripe_test_key');
\Stripe\Stripe::setApiKey($stripeKey);
try {
$charge = \Stripe\Charge::create(array(
'customer' => $card->getCustomerToken(),
'amount' => $montant * 100,
'currency' => 'eur',
'description' => 'Annulation -> Customer for ' . $email,
'metadata' => array('order_id' => $data->getNumeroReference())
));
} catch (\Stripe\Exception\CardException $e) {
// Since it's a decline, \Stripe\Error\Card will be caught
$body = $e->getJsonBody();
$err = $body['error'];
throw new HttpException(500, 'Error Card');
} catch (\Stripe\Exception\RateLimitException $e) {
// Too many requests made to the API too quickly
throw new HttpException(500, 'too_many_request_too_quickly');
} catch (\Stripe\Exception\InvalidRequestException $e) {
// Invalid parameters were supplied to Stripe's API
throw new HttpException(500, 'invalid_parameter');
} catch (\Stripe\Exception\AuthenticationException $e) {
// Authentication with Stripe's API failed
// (maybe you changed API keys recently)
throw new HttpException(500, 'authentification_failed');
} catch (\Stripe\Exception\ApiConnectionException $e) {
// Network communication with Stripe failed
throw new HttpException(500, 'network_communication_failed');
} catch (\Stripe\Exception\ApiErrorException $e) {
// Display a very generic error to the user, and maybe send
// yourself an email
throw new HttpException(500, 'Global error');
} catch (\Exception $e) {
// Something else happened, completely unrelated to Stripe
throw new HttpException(500, 'Other error');
}
}
}
// Private utils function
private function resetSession()
{
//TO remove
$this->get('session')->remove('typeDay');
$this->get('session')->remove('typeHeure');
$this->get('session')->remove('infoCommande'); // Last Commande
$this->get('session')->remove('modeCommande'); // visio|physique
$this->get('session')->remove('typeCommande'); // now|later
$this->get('session')->remove('horaireCommande'); // horaire Info
$this->get('session')->remove('codeCommande'); // Code de sécurité
// end
$this->get('session')->remove('commande');
$this->get('session')->remove('intervention');
$this->get('session')->remove('iframe');
}
private function chargeVisio($intervention, $lastCommande, $montant)
{
$carte = $intervention->getCarteBancaire()->getLastDigit();
$client = $intervention->getClient();
$email = $lastCommande->getEmail();
$card = $intervention->getCarteBancaire();
$chargeToken = $intervention->getChargeToken();
$stripeKey = ($this->getParameter('environment') == 'prod') ? $this->getParameter('stripe_live_key') : $this->getParameter('stripe_test_key');
\Stripe\Stripe::setApiKey($stripeKey);
try {
$charge = \Stripe\Charge::create(array(
'customer' => $card->getCustomerToken(),
'amount' => $montant * 100,
'currency' => 'eur',
'description' => 'Recu -> Customer for ' . $email,
'metadata' => array('order_id' => $intervention->getNumeroReference())
));
return $charge;
} catch (CardException $e) {
// Since it's a decline, \Stripe\Error\Card will be caught
$body = $e->getJsonBody();
$err = $body['error'];
return array('reason' => 'card_declined');
} catch (RateLimitException $e) {
return array('reason' => 'too_many_request_too_quickly');
} catch (InvalidRequestException $e) {
return array('reason' => 'invalid_cb_parameter');
} catch (AuthenticationException $e) {
return array('reason' => 'authentification_failed');
} catch (ApiConnectionException $e) {
return array('reason' => 'network_communication_failed');
} catch (\Exception $e) {
return array('reason' => 'global_error');
}
}
}