<?php namespace App\Controller; use App\Entity\Adherent; use App\Entity\Cotisation; use App\Entity\GlobalParameter; use App\Entity\HelloAsso; use App\Entity\Prestataire; use App\Entity\User; use App\Enum\HelloassoStateEnum; use App\Utils\HelloassoUtils; use App\Utils\OperationUtils; use Doctrine\ORM\EntityManagerInterface; use Psr\Log\LoggerInterface; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; use Symfony\Component\EventDispatcher\EventDispatcherInterface; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\Routing\Annotation\Route; use Symfony\Component\Security\Core\Security; use Symfony\Component\Translation\TranslatorInterface; use Symfony\Contracts\HttpClient\HttpClientInterface; class HelloAssoCallbackController extends AbstractController { protected $em; protected $logger; protected $security; protected $translator; protected $eventDispatcher; protected $operationUtils; protected $client; protected $helloassoUtils; public function __construct( Security $security, EntityManagerInterface $em, TranslatorInterface $translator, EventDispatcherInterface $eventDispatcher, LoggerInterface $logger, OperationUtils $operationUtils, HttpClientInterface $client, HelloassoUtils $helloassoUtils ) { $this->security = $security; $this->logger = $logger; $this->em = $em; $this->translator = $translator; $this->eventDispatcher = $eventDispatcher; $this->operationUtils = $operationUtils; $this->client = $client; $this->helloassoUtils = $helloassoUtils; } /** * @Route("/helloasso/callback", methods="POST", name="hello_asso_callback") */ public function callback(Request $request): Response { // Make sure that the client is providing something that we can consume $consumes = ['application/json', 'text/json']; if (!static::isContentTypeAllowed($request, $consumes)) { // We can't consume the content that the client is sending us return new Response('', 415); } $arrayResult = json_decode($request->getContent(), true); $flux = null; // eventType : Order / Payment / Form if ('Order' == $arrayResult['eventType']) { $data = $arrayResult['data']; foreach ($data['items'] as $items) { $itemId = $items['id']; // state : "Waiting", "Processed", "Registered", "Deleted", "Refunded", "Unknown", "Canceled", "Contested" $itemState = $items['state']; $payments = isset($data['payments']) ? $data['payments'] : null; $statePayment = 'NONE'; $paymentReceiptUrl = ''; if (null != $payments) { $statePayment = isset($payments[0]['state']) ? $payments[0]['state'] : 'NONE'; $paymentReceiptUrl = isset($payments[0]['paymentReceiptUrl']) ? $payments[0]['paymentReceiptUrl'] : ''; } // Create HelloAsso entity $helloasso = new HelloAsso(); $helloasso->setHistorical(false); $helloasso->setData($arrayResult); $helloasso->setHelloassoid((int) $itemId); $itemMontant = floatval($items['amount']) / 100; $helloasso->setAmount($itemMontant); $payer = $data['payer']; $payerCompany = isset($payer['company']) ? $payer['company'] : ''; $helloasso->setUserfirstname($payerCompany); $payerEmail = $payer['email']; $helloasso->setPayeremail($payerEmail); $payerFirstName = $payer['firstName']; $helloasso->setPayerfirstname($payerFirstName); $payerLastName = $payer['lastName']; $helloasso->setPayerlastname($payerLastName); // type : "Donation", "Payment", "Registration", "Membership", "MonthlyDonation", "MonthlyPayment", "OfflineDonation", "Contribution", "Bonus" $itemType = $items['type']; $helloasso->setType($itemType); $userFirstname = ''; $userLastname = ''; $userEmail = ''; $userAdress = ''; $userZipcode = ''; $userCity = ''; if ('Membership' == $itemType) { $customFields = isset($items['customFields']) ? $items['customFields'] : []; foreach ($customFields as $customField) { if ('Email' == $customField['name']) { $userEmail = $customField['answer']; $helloasso->setUseremail($userEmail); } elseif ('Adresse' == $customField['name']) { $userAdress = $customField['answer']; } elseif ('Code Postal' == $customField['name']) { $userZipcode = $customField['answer']; } elseif ('Ville' == $customField['name']) { $userCity = $customField['answer']; } } $user = $items['user']; $userFirstname = $user['firstName']; $helloasso->setUserfirstname($userFirstname); $userLastname = $user['lastName']; $helloasso->setUserlastname($userLastname); } $helloasso->setState($itemState); $helloasso->setStatePayment($statePayment); $helloasso->setPaymentReceiptUrl($paymentReceiptUrl); // priceCategory : "Fixed", "Pwyw", "Free" (Free, Fixed or Pay what you want) // $itemState = $items['priceCategory']; $helloasso->setOperationState(HelloassoStateEnum::HELLOASSO_STATE_START); try { if (!empty($payerCompany)) { $prestataire = $this->findPrestataireWithData($payerCompany, $userFirstname, $userLastname, $userEmail, $payer, $userAdress, $userZipcode, $userCity); } if (empty($prestataire)) { $adherent = $this->findAdherentWithData($userFirstname, $userLastname, $userEmail, $payer, $userAdress, $userZipcode, $userCity); if (empty($adherent)) { $prestataire = $this->findPrestataireWithData($payerCompany, $userFirstname, $userLastname, $userEmail, $payer, $userAdress, $userZipcode, $userCity); if (empty($prestataire)) { $helloasso->setOperationState(HelloassoStateEnum::HELLOASSO_STATE_ERROR_NOT_FOUND); $helloasso->setErrors('Adherent or Prestataire not found !'); } else { $helloasso->setPrestataire($prestataire); } } else { $helloasso->setAdherent($adherent); } } else { $helloasso->setPrestataire($prestataire); } } catch (\Exception $e) { $helloasso->setErrors($e->getMessage()); $response = new Response('Erreur : ' . $e->getMessage(), 500); } $this->em->persist($helloasso); $this->em->flush(); try { // Si le paiement est autorisé et qu'on a trouvé le prestataire ou l'adhérent, on crée le flux et on execute les opérations if ('Processed' == $itemState && ('Authorized' == $statePayment || 'Processed' == $statePayment) && null != $helloasso->getPrestataire() || null != $helloasso->getAdherent()) { if ('Membership' == $itemType) { // COTISATION $flux = $this->helloassoUtils->addCotisation($helloasso); $helloasso->setFlux($flux); } elseif ('Payment' == $itemType) { // ACHAT EMLC $flux = $this->helloassoUtils->addAchatEmlc($helloasso); $helloasso->setFlux($flux); } elseif ('Donation' == $itemType) { // DON $don = $this->helloassoUtils->addDonation($helloasso); if (null != $flux) { // ASSOCIATE DON WITH OTHER FLUX $flux->setDon($don); $this->em->persist($flux); } $helloasso->setFlux($don); } $helloasso->setOperationState(HelloassoStateEnum::HELLOASSO_STATE_OK); } else { $helloasso->setOperationState(HelloassoStateEnum::HELLOASSO_STATE_OK); } $this->em->persist($helloasso); $this->em->flush(); } catch (\Exception $e) { $helloasso->setErrors($e->getMessage()); $helloasso->setOperationState(HelloassoStateEnum::HELLOASSO_STATE_ERROR_FLUX); $this->em->persist($helloasso); $this->em->flush(); $response = new Response('Erreur : ' . $e->getMessage(), 500); } } } $response = new Response('OK', 200); return $response; } private function findPrestataireWithData(string $raison, ?string $userFirstname, ?string $userLastname, ?string $userEmail, array $payer, ?string $userAdress, ?string $userZipcode, ?string $userCity): ?Prestataire { //@ TODO $presta = null; if (!empty($raison)) { $presta = $this->em->getRepository(Prestataire::class)->findBy(['raison' => $raison]); if (!empty($presta) && 1 == count($presta)) { return $presta[0]; } } if (!empty($userEmail)) { $user = $this->em->getRepository(User::class)->findBy(['email' => $userEmail]); if (!empty($user)) { $prestas = $this->em->getRepository(Prestataire::class)->findByData(['user' => $user]); if (!empty($presta) && 1 == count($presta)) { return $presta[0]; } else { foreach ($prestas as $presta) { if ($presta->getResponsable() == $userFirstname || $presta->getResponsable() == $userLastname || $presta->getResponsable() == $userFirstname . ' ' . $userLastname || $presta->getResponsable() == $userLastname . ' ' . $userFirstname) { return $presta; } } } } } return $presta; } private function findAdherentWithData(string $userFirstname, string $userLastname, ?string $userEmail, array $payer, ?string $userAdress, ?string $userZipcode, ?string $userCity): ?Adherent { $adh = null; if (!empty($userEmail)) { $adh = $this->em->getRepository(Adherent::class)->findByData(['email' => $userEmail]); } if (empty($adh)) { $adh = $this->em->getRepository(Adherent::class)->findByData(['firstname' => $userFirstname, 'lastname' => $userLastname]); } if (empty($adh) && !empty($payer['email'])) { $adh = $this->em->getRepository(Adherent::class)->findByEmail($payer['email']); } return $adh; } private function sendMail($name, $from, $to, $message) { if (empty($to)) { $to = $this->em->getRepository(GlobalParameter::class)->val(GlobalParameter::MLC_CONTACT_EMAIL); } $subject = $this->em->getRepository(GlobalParameter::class)->val(GlobalParameter::MLC_NAME_SMALL) . " : HelloAsso : Reception d'un paiement"; $mail = (new \Swift_Message($subject)) ->setFrom($from) ->setTo($this->em->getRepository(GlobalParameter::class)->val(GlobalParameter::MLC_CONTACT_EMAIL)) ->setBody( $this->templating->render( '@kohinos/email/contact.html.twig', [ 'subject' => $subject, 'from' => $from, 'name' => $name, 'message' => $message, ] ), 'text/html' ); $this->mailer->send($mail); } /** * Checks whether Content-Type request header presented in supported formats. * * @param Request $request request instance * @param array $consumes array of supported content types * * @return bool returns true if Content-Type supported otherwise false */ public static function isContentTypeAllowed(Request $request, array $consumes = []) { if (!empty($consumes) && '*/*' !== $consumes[0]) { $currentFormat = $request->getContentType(); foreach ($consumes as $mimeType) { // canonize mime type if (is_string($mimeType) && false !== $pos = strpos($mimeType, ';')) { $mimeType = trim(substr($mimeType, 0, $pos)); } if (!$format = $request->getFormat($mimeType)) { // add custom format to request $format = $mimeType; $request->setFormat($format, $format); $currentFormat = $request->getContentType(); } if ($format === $currentFormat) { return true; } } return false; } return true; } }