<?php namespace App\Entity; use App\Entity\EntityTrait\EnablableEntityTrait; use App\Enum\MoyenEnum; use Doctrine\ORM\Event\LifecycleEventArgs; use Doctrine\ORM\Mapping as ORM; use Gedmo\Timestampable\Traits\TimestampableEntity; use Symfony\Component\Validator\Constraints as Assert; use Symfony\Component\Validator\Context\ExecutionContextInterface; use ApiPlatform\Core\Annotation\ApiResource; use Symfony\Component\Serializer\Annotation\Groups; /** * FLUX = TRANSFERT ou TRANSACTION ou COTISATIONS ou RECONVERSIONS * @ORM\Entity(repositoryClass="App\Repository\FluxRepository") * @ORM\HasLifecycleCallbacks() * @ORM\InheritanceType("SINGLE_TABLE") * @ORM\DiscriminatorColumn(name="discr", type="string") * @ORM\DiscriminatorMap({"cotisation" = "Cotisation", "cotisation_adherent" = "CotisationAdherent", "cotisation_prestataire" = "CotisationPrestataire", "tro_adh_pre" = "TransactionAdherentPrestataire", "tro_adh_adh" = "TransactionAdherentAdherent", "tro_pre_adh" = "TransactionPrestataireAdherent", "tro_pre_pre" = "TransactionPrestatairePrestataire", "tre_cpt_grp" = "TransfertComptoirGroupe", "tre_grp_cpt" = "TransfertGroupeComptoir", "tre_pre_cpt" = "TransfertPrestataireComptoir", "tre_pre_sie" = "TransfertPrestataireSiege", "tre_sie_grp" = "TransfertSiegeGroupe", "tre_grp_sie" = "TransfertGroupeSiege", "vte_cpt_pre" = "VenteComptoirPrestataire", "vte_cpt_adh" = "VenteComptoirAdherent", "ret_cpt_pre" = "RetraitComptoirPrestataire", "ret_cpt_adh" = "RetraitComptoirAdherent", "com_rec_pre" = "CommissionPrestataireMLC", "achat_monnaie" = "AchatMonnaie", "achat_monnaie_prestataire" = "AchatMonnaiePrestataire", "achat_monnaie_adherent" = "AchatMonnaieAdherent"}) */ abstract class Flux { use TimestampableEntity; const TYPE_COTISATION = 'cotisation'; const TYPE_TRANSFERT = 'transfert'; const TYPE_TRANSACTION = 'transaction'; const TYPE_VENTE = 'vente'; const TYPE_RETRAIT = 'retrait'; const TYPE_COMMISSION = 'commission'; const TYPE_ACHAT = 'achat'; /** * @var int * * @ORM\Id * @ORM\Column(type="integer") * @ORM\GeneratedValue(strategy="AUTO") * @Groups({"read"}) */ protected $id; /** * @ORM\ManyToOne(targetEntity="User", inversedBy="flux") * @ORM\JoinColumn(name="user_id", referencedColumnName="id", nullable=true) * @Groups({"read", "write"}) */ protected $operateur; /** * Role en cours de l'utilisateur * @var string * * @ORM\Column(name="role", type="string", length=200) * @Assert\NotBlank * @Groups({"read", "write"}) */ protected $role; /** * Type de transfert / transaction : exemple : Prestataire à Adhérent * @var string * * @ORM\Column(name="type", type="string", length=200) * @Assert\NotBlank * @Groups({"read", "write"}) */ protected $type; /** * Type de flux : transfert / transaction * @var string * * @ORM\Column(name="parenttype", type="string", length=20) * @Assert\NotBlank * @Groups({"read", "write"}) */ protected $parenttype; /** * @var float * * @ORM\Column(name="montant", type="decimal", precision=7, scale=2) * @Assert\NotBlank * @Assert\Type("numeric") * @Assert\GreaterThan( * value = 0 * ) * @Groups({"read", "write"}) */ protected $montant; /** * @var string * * @ORM\Column(name="moyen", type="string", length=100) * @Assert\NotBlank * @Groups({"read", "write"}) */ private $moyen; /** * @var null|string * * @ORM\Column(name="reference", type="string", length=255, nullable=true) * @Assert\NotBlank * @Groups({"read", "write"}) */ protected $reference; /** * Hash => permet de vérifier l'intégrité des données * @var text * * @ORM\Column(name="hash", type="text") */ protected $hash; /** * @var float * * @ORM\Column(name="tauxreconversion", type="decimal", precision=7, scale=2, nullable=true) * @Groups({"read", "write"}) */ protected $tauxreconversion; protected $expediteur = null; protected $destinataire = null; protected $cotisationInfos = null; abstract public function getParenttype(); /** * Effectuer l'opération (transfert, transaction, vente, retrait...) * @return array Tableau des entité(s) à persister (siege, comptoir, groupe, presta, adherent...) */ abstract public function operate($em); /** * Obtenir la liste des utilisateurs à notifier * @return array Tableau d'utilisateurs */ abstract public function getUsersToNotify(); public function __construct() { $this->parenttype = $this->getParenttype(); $this->type = $this->getType(); } public function getId(): ?int { return $this->id; } /** * @param $parenttype * @return $this */ public function setParenttype($parenttype) { $this->parenttype = $parenttype; return $this; } /** * @param User $destinataire * @return $this */ public function setOperateur(?User $operateur) { $this->operateur = $operateur; return $this; } /** * @return User operateur */ public function getOperateur(): ?User { return $this->operateur; } /** * @param $destinataire * @return $this */ public function setDestinataire($destinataire) { $this->destinataire = $destinataire; return $this; } /** * @return destinataire */ public function getDestinataire() { return $this->destinataire; } /** * @param $expediteur * @return $this */ public function setExpediteur($expediteur) { $this->expediteur = $expediteur; return $this; } /** * @return expediteur */ public function getExpediteur() { return $this->expediteur; } /** * @return string */ public function getType(): string { return $this->type; } /** * @param string $type * @return Transaction */ public function setType(string $type) { $this->type = $type; return $this; } /** * @return string */ public function getRole(): ?string { return $this->role; } /** * @param string $role * @return Transaction */ public function setRole(?string $role) { $this->role = $role; return $this; } /** * @return float */ public function getMontant(): ?float { return $this->montant; } /** * @param float $montant * @return Transaction */ public function setMontant(float $montant) { $this->montant = $montant; return $this; } /** * @return string */ public function getReference(): ?string { return $this->reference; } /** * @param string $reference * @return Transaction */ public function setReference(string $reference) { $this->reference = $reference; return $this; } /** * Get hash * @return text */ public function getHash() { return $this->hash; } /** * Set hash * @return $this */ public function setHash($hash) { $this->hash = $hash; return $this; } /** * @return string */ public function getMoyen(): ?string { return $this->moyen; } public function setMoyen($moyen) { if (!in_array($moyen, MoyenEnum::getAvailableTypes())) { throw new \InvalidArgumentException("Moyen de paiement invalide !"); } $this->moyen = $moyen; return $this; } /** * Get tauxreconversion * @return */ public function getTauxreconversion(): ?float { return $this->tauxreconversion; } /** * Set tauxreconversion * @return $this */ public function setTauxreconversion(?float $tauxreconversion): self { $this->tauxreconversion = $tauxreconversion; return $this; } public function getMontantareconvertir() { return ($this->getMontant() - ($this->getMontant()*($this->getTauxreconversion()/100))); } public function isVente() { return false; } public function getVerify() { if ($this->getHash() == null) { return 'Vide'; } return (password_verify($this->getAllInfosUncrypted(), $this->getHash()) === true)?'Oui':'Non'; } /** * @ORM\PrePersist * @param LifecycleEventArgs $event */ public function prePersist(LifecycleEventArgs $event) { $flux = $event->getEntity(); $flux->setHash('tmp'); } /** * @ORM\PostPersist * @param LifecycleEventArgs $event */ public function postPersist(LifecycleEventArgs $event) { $flux = $event->getEntity(); if (empty($flux->getExpediteur())) { throw new \Exception("[FLUX] Opération impossible ! Pas d'expéditeur !"); } if ($flux->getMontant() <= 0) { throw new \Exception("[FLUX] Opération impossible ! Montant inférieur ou égal à zéro !"); } if ($flux->getExpediteur() == $flux->getDestinataire()) { throw new \Exception("[FLUX] Opération impossible ! Expéditeur et Destinataire ne peuvent pas être les mêmes !"); } // @TODO : generation du hash du flux trop gourmand en ressource ! // $hash = password_hash($flux->getAllInfosUncrypted(), PASSWORD_BCRYPT, ['cost' => 12]); // $flux->setHash($hash); // $event->getEntityManager()->persist($flux); // $event->getEntityManager()->flush(); } /** * @Assert\Callback * @param ExecutionContextInterface $context [description] * @return [type] [description] */ public function validateConstraint(ExecutionContextInterface $context) { if ($this->getMoyen() == MoyenEnum::MOYEN_MLC && $this->getParenttype() == self::TYPE_COTISATION && $this->getExpediteur()->getEcompte() < $this->getMontant() ) { $context->addViolation('Montant supérieur au solde de monnaie éléctronique.'); } } public function getAllInfosUncrypted(): string { return $_ENV['APP_SECRET'].$this->id.$this->operateur->getId().$this->role.$this->type.$this->montant.$this->moyen.$this->reference.$this->destinataire->getId().$this->expediteur->getId(); } public function getOperateurAndRole(): string { return $this->operateur->__toString() . ' (' . $this->role . ')'; } public function __toString(): string { if (empty($this->getDestinataire()) || empty($this->getExpediteur()) || empty($this->getMontant())) { return "[FLUX] Visualisation impossible ! Destinataire / Expéditeur et/ou montant manquant(s) !"; } return ($this->getCreatedAt()?$this->getCreatedAt()->format('d/m/Y H:i').' | ':'').ucwords($this->getParenttype()).' : '.$this->getDestinataire().' => '.$this->getExpediteur().' ; '.$this->getMontant().'€'; } }