<?php
namespace App\DataPersister;
use App\Utils\Utils;
use App\Utils\Constantes;
use ApiPlatform\Core\DataPersister\ContextAwareDataPersisterInterface;
use Psr\Log\LoggerInterface;
use Doctrine\Persistence\ManagerRegistry;
use Doctrine\Persistence\ObjectManager as DoctrineObjectManager;
use Doctrine\ORM\Mapping\ClassMetadataInfo;
use ApiPlatform\Core\Util\ClassInfoTrait;
use App\Entity\Entite;
use App\Entity\Service;
use App\Entity\Partenaire;
use App\Entity\Rechargement;
use App\Entity\Commission;
use App\Entity\Compte;
use App\Entity\CommissionFixe;
use App\Entity\AirTime;
use App\Entity\Transfert;
use App\Entity\Encaissement;
use App\Entity\ServicePartenaire;
use App\Entity\Transaction;
use App\Entity\Wallet;
use App\Entity\Client;
use App\Entity\FraisFixe;
use App\Utils\ApiRequest;
use App\Utils\JWTEncoder;
use Symfony\Component\HttpFoundation\RequestStack;
use Symfony\Component\HttpFoundation\Request;
use ApiPlatform\Core\DataPersister\DataPersisterInterface;
final class RechargementDataPersister implements DataPersisterInterface
{
use ClassInfoTrait;
private $logger;
private $managerRegistry;
private $request;
private $apiRequest;
private $jwtFactory;
private $isAirTime;
private $apiKey;
private $trxType;
private $isDigicashPartner;
private $codeOperateur;
private $uid;
private $auteur;
private $frais;
public function __construct(LoggerInterface $logger, ManagerRegistry $managerRegistry, ApiRequest $apiRequest, RequestStack $requestStack)
{
$this->logger = $logger;
$this->managerRegistry = $managerRegistry;
$this->apiRequest = $apiRequest;
$this->request = Request::createFromGlobals();
$this->requestStack = $requestStack;
$this->jwtFactory = JWTEncoder::getInstance();
$this->trxType = "envoi";
$this->isDigicashPartner = false;
}
public function supports($data, array $context = []): bool
{
return $data instanceof Recharge;
}
public function persist($data)
{
try{
if (!$manager = $this->getManager($data)) {
return $data;
}
var_dump("ici");die;
$request = $this->requestStack->getCurrentRequest();
$dateAction = Utils::getCurrentDateTime();
$this->apiKey = $request->headers->get(Constantes::AUTH_TOKEN);
$data->setMessage("Sauvegardée avec succes");
$this->isDigicashPartner = $data->getServicePartenaire()->getNom() == "DIGICASH";
$dataToken = $this->jwtFactory->decode($this->apiKey);
$this->uid = $dataToken["id"];
$this->auteur = $dataToken["nom"];
$trxId = $this->uid.Utils::generateNumTransacService();
$codeEntite = $dataToken["codeClient"];
$estCaissier = in_array(Constantes::ROLE_CAISSIER, $dataToken["roles"]);
$walletUser = in_array(Constantes::ROLE_USER_WALLET, $dataToken["roles"]);
if(!$estCaissier && !$walletUser){
throw new \Exception("Opération non autorisée");
}
$data->setUid($this->uid);
$data->setAuteur($this->auteur);
$keyValues = [Constantes::ID => 0,
Constantes::USERNAME => "BGROBOT",
Constantes::ROLES => ["BG_ROBOT"],
];
$serverApiKey = $this->jwtFactory->encode($keyValues);
$uri = $_ENV['PARTNER_SERVICE_URL'];
$trx = new Transaction();
$montantTTC = intval($data->getMontant());
$trxId = $this->uid.Utils::generateNumTransacService();
$trx->setNumTransaction($trxId);
$trx->setStatus(true);
$trx->setPending(true);
$trx->setUid($this->uid);
if ($estCaissier) {
$this->saveCaissierTrx($data, $trx);
} elseif($walletUser){
$this->saveWalletUserTrx($data, $trx);
}
if($isDigicashPartner){
$clRepoRepository = $this->managerRegistry->getRepository(Client::class);
$benef = $clRepoRepository->findOneBy(["telephone" => $data->getTelephone()]);
if(!$benef){
throw new \Exception("Bénéficiaire introuvable");
}
$compteRepoRepository = $this->managerRegistry->getRepository(Compte::class);
$compteBenefId = $compteRepoRepository->getWalletEntity($benef->getId());
if(empty($compteBenefId)){
throw new \Exception("Compte wallet bénéficiaire introuvable");
}
$compteBenef = $compteRepoRepository->find($compteBenefId);
$trxBenf = new Transaction();
$montantNet = intval($data->getMontant());
$trxBenf->setNumTransaction($trxId);
$trxBenf->setStatus(true);
$trxBenf->setPending(false);
$trxBenf->setMontant($montantNet);
$trxBenf->setCommentaires("credit");
$trxBenf->setService($serviceP);
$trxBenf->setUid($benef->getUserId());
$soldeCompteBnef = $compteBenef->getSolde();
$soldeBenef = intval($benef->getSolde());
$soldeApresBnef = $soldeBenef + $montantNet;
$soldeApresCmptBnef = $soldeCompteBnef + $montantNet;
$benef->setSolde($soldeApresBnef);
$compteBenef->setSolde($soldeApresCmptBnef);
$trxBenf->setSoldeCompteAvant($soldeBenef);
$trxBenf->setSoldeCompteApres($soldeApresBnef);
$trxBenf->setClient($benef);
$benef->setDateModification($dateAction);
$compteBenef->setDateModification($dateAction);
$trxBenf->setDateCreation($dateAction);
$trxBenf->setDateModification($dateAction);
$manager->persist($benef);
$manager->persist($compteBenef);
$manager->persist($trxBenf);
}
$data->setStatus(true);
$data->setCodeEntite($codeEntite);
$data->setMontantTTC($montantTTC);
if(!$this->isDigicashPartner){
if($this->isAirTime || $this->isWallet) {
// var_dump($data->getServicePartenaire()->getNom());die;
$uri .= $this->isAirTime ? "/api/intouch/airtime" : "/api/intouch/" . strtolower($data->getServicePartenaire()->getTag());
$dataService = [
"operateur" => $data->getServicePartenaire()->getNom(),
"pays" => $data->getServicePartenaire()->getPays(),
"recipient_phone_number" => $data->getTelephone(),
"amount" => $data->getMontant(),
"transaction_id" => $trxId
];
$postRequest = $this->apiRequest->postData($dataService, $uri, $serverApiKey);
$createSuccess = $postRequest[0] == 200;
$retour = $postRequest[1];
if(!$createSuccess || !isset($retour['status']) || $retour['status'] == "FAILED") {
$ex = "Service indisponible, veuillez réssayer plus tard";
throw new \Exception($ex);
} else {
$trx->setPending(true);
}
}
} else {
$trx->setPending(false);
}
$object = get_class($data);
$message = "new ".$object."created ";
if($data->getId()){
$message = $object." ".$data->getId()." updated";
$data->setDateModification($dateAction);
}else{
$data->setDateCreation($dateAction);
$data->setDateModification($dateAction);
}
$this->logger->info($message);
if (!$manager = $this->getManager($data)) {
return $data;
}
$trx->setDateCreation($dateAction);
$trx->setDateModification($dateAction);
//if (!$manager->contains($data) || $this->isDeferredExplicit($manager, $data)) {
if($commEntity) {
$manager->persist($commEntity);
}
$manager->persist($trx);
$manager->persist($data);
//}
$manager->flush();
$manager->refresh($data);
return $data;
}catch(Exception $ex){
$data->setId(0);
// $data->setMessage("Une erreur est survenue lors de la sauvegarde");
$data->setMessage($ex->getMessage());
$this->logger->error( $ex->getMessage());
return $data;
}
}
public function remove($data)
{
try{
if (!$manager = $this->getManager($data)) {
return;
}
$manager->remove($data);
$manager->flush();
$object = get_class($data);
$message = $object." ".$data->getId()."delete ";
$this->logger->info( $message );
}catch(\Exception $ex){
$object = get_class($data);
$message = $object." ".$data->getId()."delete ";
$this->logger->info( $ex->getMessage() );
}
}
/**
* Gets the Doctrine object manager associated with given data.
*
* @return DoctrineObjectManager|null
*/
private function getManager($data)
{
return \is_object($data) ? $this->managerRegistry->getManagerForClass($this->getObjectClass($data)) : null;
}
private function getRepository($data)
{
return $this->managerRegistry->getRepository($data);
}
/**
* Checks if doctrine does not manage data automatically.
*
* @return bool
*/
private function isDeferredExplicit(DoctrineObjectManager $manager, $data)
{
$classMetadata = $manager->getClassMetadata($this->getObjectClass($data));
if ($classMetadata instanceof ClassMetadataInfo && method_exists($classMetadata, 'isChangeTrackingDeferredExplicit')) {
return $classMetadata->isChangeTrackingDeferredExplicit();
}
return false;
}
private function getCommission($montantNet) {
$adminResponse = $this->apiRequest->getFraisService($this->codeOperateur, $montantNet, $this->apiKey);
if(empty($adminResponse)) {
$ex = "Commission non définie pour ce service";
throw new \Exception($ex);
}
$adminCodeOper = $adminResponse["codeOperateur"];
$checkSoldeOper = $adminResponse["checkSolde"];
$partageCommission = $adminResponse["frais"];
$frais = 0;
$gain = [];
if(!empty($partageCommission["montant"])) {
$gain = Utils::calculCommission($partageCommission, $this->trxType);
$commissionEnvoi = new Commission();
$commissionEnvoi->setCodeEntite($codeEntite);
$commissionEnvoi->setCodeAgence($codeAgence);
$commissionEnvoi->setCodeCaisse($codeCaisse);
$commissionEnvoi->setMontant($montantNet);
$frais = $partageCommission["montant"];
$commissionEnvoi->setFrais($partageCommission["montant"]);
$commissionEnvoi->setNetCaisse($gain["caisse"]["netCaisse"]);
$commissionEnvoi->setTvaCaisse($gain["caisse"]["tvaCaisse"]);
$commissionEnvoi->setNetEntite($gain["entite"]["netEntite"]);
$commissionEnvoi->setTvaEntite($gain["entite"]["tvaEntite"]);
$commissionEnvoi->setStatus(true);
$commissionEnvoi->setTvaOperateur($gain["operateur"]["tvaOperateur"]);
$commissionEnvoi->setNetOperateur($gain["operateur"]["netOperateur"]);
$commissionEnvoi->setTvaPlateforme($gain["plateforme"]["tvaPlateforme"]);
$commissionEnvoi->setNetPlateforme($gain["plateforme"]["netPlateforme"]);
$commissionEnvoi->setDateCreation($dateAction);
$commissionEnvoi->setDateModification($dateAction);
}
$montantTTC = $montantNet + $frais;
return ["ttc" => $montantTTC, "frais" => $frais, "net" => $montantNet, "commissions" => $gain, "commissionEntity" => $commissionEnvoi ? $commissionEnvoi : null];
}
private function saveCaissierTrx(&$data, &$trx){
if($data->getCompte()){
throw new \Exception("L'opération sur compte client n'est pas autorisée");
}
if(!$data->getCodeService()){
throw new \Exception("Le code service est obligatoire");
}
$this->codeOperateur = $data->getCodeService();
$partnerServiceRepository = $this->managerRegistry->getRepository(ServicePartenaire::class);
$servicePartenaire = $partnerServiceRepository->findOneBy(["codePlateforme" => $this->codeOperateur]);
if(!$servicePartenaire){
throw new \Exception("Service introuvable");
}
$data->setServicePartenaire($servicePartenaire);
$trx->setMontant($montantTTC);
$trx->setCommentaires("debit");
$trx->setService($servicePartenaire);
$codeCaisse = $dataToken["codeCaisse"];
$this->apiRequest->verifierPlafondCaisse($codeCaisse, $montantTTC);
$service = Constantes::WALLET_CODE_SERVICE;
$commentaire = $this->isAirTime ? "Airtime": $this->isEnc ? "Encaissement" : "Wallet";
$operation = "RETRAIT";
$frais = 0;
$mtCommission = 0;
$total = intval($data->getMontant()) + $frais;
$this->trxType = "envoi";
$detailsComm = $this->getCommission($data->getMontant());
$total = $detailsComm["ttc"];
$this->frais = $detailsComm["frais"];
$data->setFrais($frais);
$gain = $detailsComm["commissions"];
$commEntity = $detailsComm["commissionEntity"];
$commEntity->setServicePartenaire($servicePartenaire);
$retour_paiement_reseau = $this->apiRequest->saveNetworkTransaction ( $codeCaisse, $total, $operation, $commentaire, $this->codeOperateur, $frais, $mtCommission, $gain, $trxId, $this->apiKey);
$trx->setSoldeCompteAvant(intval($retour_paiement_reseau[Constantes::SOLDE_CAISSE_AVANT]));
$trx->setSoldeCompteApres(intval($retour_paiement_reseau[Constantes::SOLDE_CAISSE_APRES]));
$trx->setCodeCaisse($dataToken["codeCaisse"]);
return $trx;
}
private function saveWalletUserTrx(&$data) {
$clRepoRepository = $this->managerRegistry->getRepository(Client::class);
$cl = $clRepoRepository->findOneBy(["userId" => $this->uid]);
$apiKey = $request->headers->get(Constantes::AUTH_TOKEN);
if( !$data->getPin() ) {
throw new \Exception("Le code Pin est obligatoire pour valider l'opération");
}
if( !$this->apiRequest->pinVerify($data->getPin(), $apiKey) ) {
throw new \Exception("Code Pin incorrect");
}
$compteClient = $data->getCompte();
$soldeCompte = $compteClient->getSolde();
$soldeClient = intval($cl->getSolde());
if($soldeCompte < $montantTTC){
throw new \Exception("Solde insuffisant");
}
$soldeApres = $soldeClient - $montantTTC;
$soldeApresCmpt = $soldeCompte - $montantTTC;
$cl->setSolde($soldeApres);
$data->setSolde($soldeApres);
$compteClient->setSolde($soldeApresCmpt);
$trx->setSoldeCompteAvant($soldeClient);
$trx->setSoldeCompteApres($soldeApres);
$trx->setClient($cl);
$cl->setDateCreation($dateAction);
$compteClient->setDateModification($dateAction);
$manager->persist($cl);
$manager->persist($compteClient);
}
}