<?php
namespace App\Manager\Progress;
use App\Entity\Adherent\Annuaire\MagasinContact;
use App\Entity\Adherent\Annuaire\MagasinContactQualifier;
use App\Entity\Adherent\Magasin;
use App\Entity\ContactThemeCanal;
use App\Manager\DatasProgress;
use App\Manager\WsProgressManager;
use App\Repository\Adherent\Annuaire\MagasinContactQualifierRepository;
use App\Repository\ContactThemeCanalRepository;
use App\Service\PhoneNumberService;
use DateTime;
use DateTimeImmutable;
use Doctrine\ORM\EntityManagerInterface;
use Doctrine\ORM\UnitOfWork;
use Doctrine\DBAL\Exception;
use libphonenumber\PhoneNumberUtil;
use Psr\Log\LoggerInterface;
use Symfony\Component\Console\Helper\ProgressBar;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\HttpFoundation\Session\SessionInterface;
use Throwable;
class ModerationAnnuaireManager
{
private DateTime $today;
const TABLES = ['mails' => 'mail', 'telephones' => 'tel'];
const K_ENTITE_TYPE = ['MAGASIN', 'GERANT'];
private PhoneNumberUtil $phoneNumberUtil;
public function __construct(
private readonly WsProgressManager $wsProgressManager,
private readonly SessionInterface $session,
private readonly DatasProgress $datasProgress,
private readonly LoggerInterface $progressLogger,
private readonly MagasinContactQualifierRepository $magasinContactQualifierRepository,
private readonly ContactThemeCanalRepository $contactThemeCanalRepository,
private readonly PhoneNumberService $phoneNumberService,
private readonly EntityManagerInterface $entityManager
)
{
$this->today = (new DateTime('now'));
$this->phoneNumberUtil = PhoneNumberUtil::getInstance();
}
/**
* @param Magasin $magasin L'objet Magasin représentant le magasin.
* @param String $typeData Table a appeler
* @param String $category MAGASIN pour magasin ou GERANT pour individu si l'on veut recevoir les infos du mag ou de l'indiv principal
* @param String $libAmt * ou qualifiant du contact (mobile_pro par exemple)
* @return bool|array
* @throws Exception
*/
public function getDatasProgress(Magasin $magasin, string $typeData, string $category, string $libAmt = "*"): bool|array
{
//Changement de la centrale en fonction du code adhérent.
$this->wsProgressManager->selectTenant($magasin->getKAdherent());
if (array_key_exists($typeData, self::TABLES)) {
if (in_array($category, self::K_ENTITE_TYPE)) {
if ($category === "GERANT") {
// si le type est INDIVIDU on va chercher l'identifiant du gérant car ce sont les contacts du gérant que nous allons chercher
$proprietaire = $this->datasProgress->getProprietaire($magasin->getKMag());
if ($proprietaire) {
return $this->callProgressAndFormatted($proprietaire['K_INDIV'], $libAmt, self::TABLES[$typeData], $category);
} else {
throw new Exception('Le propriétaire est introuvable.');
}
} elseif ($category === "MAGASIN") {
return $this->callProgressAndFormatted($magasin->getKMag(), $libAmt, self::TABLES[$typeData], $category);
}
} else {
throw new Exception('Le type ' . $category . ' ne correspond à aucun type possible.');
}
} else {
throw new Exception('La table ' . self::TABLES[$typeData] . ' ne correspond à aucune table possible.');
}
}
public function callProgressAndFormatted(string $IdEntityType, string $libAmt = '*', string $table, string $category): array
{
ini_set('memory_limit', '-1');
$finalData = [];
$datas = [
"ACTION" => "GET",
"K_ENTITE_ID" => $IdEntityType, // Le code magasin ou le code individu en fonction du K_ENTITE_TYPE
"K_ENTITE_TYPE" => ($category === "GERANT") ? "I" : (($category === "MAGASIN") ? "M" : null), // I pour INDIVIDU et M pour MAGASIN
"LIB_AMT" => $libAmt // Par défaut * mais peux être le qualifiant du contact (mobile_pro par exemple)
];
$ch = curl_init($this->wsProgressManager->getUrl() . "web/" . $table);
curl_setopt($ch, CURLOPT_HTTPHEADER, ['Content-Type:application/json']);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($datas));
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, false);
curl_setopt($ch, CURLOPT_COOKIE, $this->session->get('wsProgress_Token'));
$response = json_decode(curl_exec($ch), true);
$returnHeader = curl_getinfo($ch);
if ($returnHeader['http_code'] == 302 && preg_match('/auth\/login.jsp/', $returnHeader['redirect_url'])) {
$this->progressLogger->info('http_code 302 aucun session => reconnexion', ['Connecté avec l\'adhérent' => $this->wsProgressManager->getCurrentUser()]);
$this->wsProgressManager->auth();
curl_setopt($ch, CURLOPT_COOKIE, $this->session->get('wsProgress_Token'));
$response = json_decode(curl_exec($ch), true);
}
curl_close($ch);
if (!is_null($response) && $response['dsResAmt'] && array_key_exists('ttAmt', $response['dsResAmt'])) {
// récupération de tous les types de contact possible (voir la bdd)
$magContactQualifier = $this->entityManager->getRepository(MagasinContactQualifier::class)->findAll();
foreach ($response['dsResAmt']['ttAmt'] as $contact) {
if (!is_null($contact[strtoupper($table)]) && preg_replace('/\s+/', '', strtolower($contact[strtoupper($table)])) !== "enattente") {
$ID_ANNUAIRE = (int)$contact['ID_ANNUAIRE']; // Récupère l'id unique du contact
$canaux = (!empty($contact['CHPSUP'])) ? explode(';', trim($contact['CHPSUP'])) : [];
$qualifiant = null;
foreach ($magContactQualifier as $possibleQualifier) {
if (strtolower($possibleQualifier->getProgressIdentifier()) === strtolower($contact['LIB_AMT']) &&
strtolower($possibleQualifier->getCategory()) === strtolower($category)
) {
$qualifiant = $possibleQualifier;
}
}
if (!is_null($qualifiant)) {// si c'est un qualifiant que l'on prend en compte, on le traite
// on stocke les contacts dans un tableau ayant pour clé l'identifiant unique du contact dans progress
$finalData[$ID_ANNUAIRE] = [
'created_at' => (!empty($contact['D_MAJ'])) ? DateTimeImmutable::createFromFormat('Y-m-d H:i:s', $contact['D_CREE'] . ' ' . gmdate('H:i:s', $contact['H_CREE'])) : DateTimeImmutable::createFromFormat('Y-m-d', '1970-01-01'),
'updated_at' => (!empty($contact['D_MAJ'])) ? DateTimeImmutable::createFromFormat('Y-m-d H:i:s', $contact['D_MAJ'] . ' ' . gmdate('H:i:s', $contact['H_MAJ'])) : DateTimeImmutable::createFromFormat('Y-m-d', '1970-01-01'),
'value' => $contact[strtoupper($table)],
'canaux' => $canaux, // canaux de communication
'qualifiant' => $qualifiant,
'ID_ANNUAIRE' => $ID_ANNUAIRE,
'K_PROGRESS' => $contact["K_" . strtoupper($table)],
'lib_amt' => $contact['LIB_AMT'],
'principal' => $contact['L_PRINCIPAL']
];
}
}
}
}
return $finalData;
}
/**
* @throws Exception
* Crée ou met à jour un contact dans progress
*/
public function addOrUpdateContactInProgress(MagasinContact $magContact): MagasinContact
{
try {
$magasin = $magContact->getMagasin();
$table = (in_array(strtolower($magContact->getQualifier()->getType()), array_values(self::TABLES))) ? strtolower($magContact->getQualifier()->getType()) : false;
$canaux = array_map(function ($canal) {
return $canal->getProgressIdentifier();
}, $magContact->getCanaux()->toArray());
switch ($magContact->getQualifier()->getCategory()) {
case 'MAGASIN':
$kEntityType = "M";
$kEntityId = $magasin->getKMag();
break;
case 'GERANT':
$kEntityType = "I";
$proprietaire = $this->datasProgress->getProprietaire($magasin->getKMag());
$kEntityId = $proprietaire['K_INDIV'];
break;
}
$dataToSend = [
"ACTION" => "SET",
"K_ENTITE_TYPE" => $kEntityType,
"K_ENTITE_ID" => $kEntityId,
"K_PAYS" => $magContact->getMagasin()->getKPays(),
strtoupper($magContact->getQualifier()->getType()) => ($magContact->getQualifier()->getType() == 'TEL') ? $this->phoneNumberService->getNumberWithoutIndic($magContact->getValue()) : $magContact->getValue(), // "TEL" => "0606060606" || "MAIL" => "test@groupeall.fr"
"EAQUALI" => implode(',', $canaux),
"LIB_AMT" => $magContact->getQualifier()->getProgressIdentifier(),
"ID_ANNUAIRE" => $magContact->getIdAnnuaireProgress() !== null ? (int)$magContact->getIdAnnuaireProgress() : -1
];
ini_set('memory_limit', '-1');
$ch = curl_init($this->wsProgressManager->getUrl() . "web/" . $table);
curl_setopt($ch, CURLOPT_HTTPHEADER, ['Content-Type:application/json']);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($dataToSend));
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, false);
curl_setopt($ch, CURLOPT_COOKIE, $this->session->get('wsProgress_Token'));
$response = json_decode(curl_exec($ch), true);
$returnHeader = curl_getinfo($ch);
if ($returnHeader['http_code'] == 302 && preg_match('/auth\/login.jsp/', $returnHeader['redirect_url'])) {
$this->progressLogger->info('http_code 302 aucun session => reconnexion', ['Connecté avec l\'adhérent' => $this->wsProgressManager->getCurrentUser()]);
$this->wsProgressManager->auth();
curl_setopt($ch, CURLOPT_COOKIE, $this->session->get('wsProgress_Token'));
$response = json_decode(curl_exec($ch), true);
}
curl_close($ch);
if ($response && array_key_exists('dsResAmt', $response) && array_key_exists('ttAmt', $response['dsResAmt']) && count($response['dsResAmt']['ttAmt']) > 0) {
$magContact->setIdAnnuaireProgress((int)$response['dsResAmt']['ttAmt'][0]["ID_ANNUAIRE"]);
$magContact->setKProgress($response['dsResAmt']['ttAmt'][0]["K_" . strtoupper($table)]);
$magContact->setPrincipal($response['dsResAmt']['ttAmt'][0]["L_PRINCIPAL"]);
$this->entityManager->persist($magContact);
$this->entityManager->flush();
}
return $magContact;
} catch (Throwable $exception) {
throw new Exception($exception->getMessage());
}
}
/**
* @throws Exception
* Supprime un contact dans progress
*/
public function removeContactInProgress(MagasinContact $magContact): void
{
try {
$magasin = $magContact->getMagasin();
$table = strtolower($magContact->getQualifier()->getType());
if (in_array($table, self::TABLES)) {
switch ($magContact->getQualifier()->getCategory()) {
case 'MAGASIN':
$kEntityType = "M";
$kEntityId = $magContact->getMagasin()->getKMag();
break;
case 'GERANT':
$kEntityType = "I";
$proprietaire = $this->datasProgress->getProprietaire($magasin->getKMag());
$kEntityId = $proprietaire['K_INDIV'];
break;
}
$dataToSend = [
"ACTION" => "DEL",
"K_ENTITE_ID" => $kEntityId,
"K_ENTITE_TYPE" => $kEntityType,
// strtoupper($magContact->getQualifier()->getType()) => ($magContact->getQualifier()->getType() == 'TEL') ? $this->phoneNumberService->getNumberWithoutIndic($magContact->getValue()) : $magContact->getValue(), // "TEL" => "0606060606" || "MAIL" => "test@groupeall.fr"
"ID_ANNUAIRE" => (int)$magContact->getIdAnnuaireProgress(),
"LIB_AMT" => $magContact->getQualifier()->getProgressIdentifier()
];
$ch = curl_init($this->wsProgressManager->getUrl() . "web/" . $table);
curl_setopt($ch, CURLOPT_HTTPHEADER, ['Content-Type:application/json']);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($dataToSend));
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, false);
curl_setopt($ch, CURLOPT_COOKIE, $this->session->get('wsProgress_Token'));
$response = json_decode(curl_exec($ch), true);
$returnHeader = curl_getinfo($ch);
if ($returnHeader['http_code'] == 302 && preg_match('/auth\/login.jsp/', $returnHeader['redirect_url'])) {
$this->progressLogger->info('http_code 302 aucun session => reconnexion', ['Connecté avec l\'adhérent' => $this->wsProgressManager->getCurrentUser()]);
$this->wsProgressManager->auth();
curl_setopt($ch, CURLOPT_COOKIE, $this->session->get('wsProgress_Token'));
$response = json_decode(curl_exec($ch), true);
}
curl_close($ch);
} else {
throw new Exception('La table ' . $table . ' ne correspond à aucune table possible.');
}
} catch (Throwable $exception) {
throw new Exception($exception->getMessage());
}
}
/**
* @param bool $progressBarActive
* @param OutputInterface|null $cmdOutput
* @return string
* Cette fonction récupère toutes les données de progress et met à jour ceux de l'espace adhérent en conséquence
* Elle met a jour TOUS les adhérents
*/
public function majDataProgressEadh(OutputInterface $cmdOutput = null): string
{
$exceptions = [];
$canaux = $this->entityManager->getRepository(ContactThemeCanal::class)->createQueryBuilder('c', 'c.progressIdentifier')->getQuery()->getResult();
$magasins = $this->entityManager->getRepository(Magasin::class)->createQueryBuilder('m')
->where('m.deleted IS NULL')->orWhere('m.deleted != 1')
// ->setMaxResults(25) //pour les tests
->getQuery()->getResult();
$progressBar = new ProgressBar($cmdOutput);
$progressBar->setFormat('verbose');
$progressBar->start();
$progressBar->setMaxSteps(count($magasins));
$gap = 10;
$i = 0;
foreach ($magasins as $magasin) {
try {
$cmdOutput->writeln(["_____________________________", "<info>{$magasin->getKAdherent()}</info>"], OutputInterface::OUTPUT_PLAIN);
$magasinState = $this->entityManager->getUnitOfWork()->getEntityState($magasin);
if ($magasinState === UnitOfWork::STATE_DETACHED) {
// Recharger l'entité depuis la base pour éviter le problème des entités détachées
$magasin = $this->entityManager->getRepository(Magasin::class)->find($magasin->getKAdherent());
}
$cmdOutput->writeln(["_____________________________", "<info>Comparaison et mise à jour des contacts</info>"], OutputInterface::OUTPUT_PLAIN);
[$contactsBdd, $exceptions] = $this->updateAdhContactsByProgress($magasin, $canaux, $exceptions);
$i++;
if ($i === $gap) {
$cmdOutput->writeln(["__________________________________", "<info>FLUSH...</info>"], OutputInterface::OUTPUT_PLAIN);
$i = 0;
$this->entityManager->flush();
$progressBar->advance($gap);
}
} catch (Throwable $e) {
$cmdOutput->writeln([
"<error>{$e->getMessage()}</error>",
"<error>{$e->getFile()}</error>",
"<error>{$e->getLine()}</error>",
"Adhérent : " . $magasin->getKAdherent()
], OutputInterface::OUTPUT_NORMAL);
}
}
$this->entityManager->flush();
$progressBar->finish();
$cmdOutput->writeln([
"______________",
"<info>Mise à jour des CONTACTS réussie</info>",
"______________"
], OutputInterface::OUTPUT_PLAIN);
return 'ok';
}
/**
* @param Magasin $magasin
* @param array $canaux // Tableau des canaux de communication possible
* @param array $exceptions // Tableau qui récupère les erreurs ou exceptions rencontrées
* @return array
*/
public function updateAdhContactsByProgress(Magasin $magasin, array $canaux, array $exceptions): array
{
// Contacts de l'adhérent
$contactsBdd = $this->entityManager->getRepository(MagasinContact::class)->findBy(['magasin' => $magasin->getKAdherent()]);
// Nettoyage des valeurs (reformatage)
foreach ($contactsBdd as $contactBdd) {
if ($contactBdd->getQualifier()->getType() === "TEL") {
$cleanedNumber = $this->phoneNumberService->validateAndFormatPhoneNumber($contactBdd->getValue(), strtoupper($magasin->getKPays()));
if ($cleanedNumber === null) {
$this->entityManager->remove($contactBdd);
} else {
$cleanedNumber = preg_replace('/\s+/', '', strtolower($cleanedNumber));
$contactBdd->setValue($cleanedNumber);
$this->entityManager->persist($contactBdd);
}
} else {
$cleanedNumber = preg_replace('/\s+/', '', strtolower($contactBdd->getValue()));
$contactBdd->setValue(strtolower($cleanedNumber));
}
}
// Suppression des doublons après reformatage des valeurs - il y a une contrainte d'unicité avec magasin, qualifiant et value
// Attention on réaffecte tous les canaux du contact doublon qui va être supprimé
foreach ($contactsBdd as $key => $currentContact) {
foreach ($contactsBdd as $secondKey => $secondContact) {
if ($key !== $secondKey && $currentContact->getValue() === $secondContact->getValue() && $currentContact->getQualifier() === $secondContact->getQualifier()) {
$currentContact->setName($secondContact->getName());
foreach ($secondContact->getCanaux() as $canal) {
$currentContact->addCanaux($canal);
}
$this->entityManager->remove($secondContact);
unset($contactsBdd[$key]);
}
}
}
try {
//Telephones magasin
[$contactsBdd, $exceptions] = $this->updateContactsByTypeByProgress($magasin, $contactsBdd, $canaux, 'telephones', 'MAGASIN', $exceptions);
} catch (Throwable $e) {
$exceptions[] = [
'magasin' => $magasin->getKAdherent(),
'exception' => $e->getMessage()
];
}
try {
//Mails magasin
[$contactsBdd, $exceptions] = $this->updateContactsByTypeByProgress($magasin, $contactsBdd, $canaux, 'mails', 'MAGASIN', $exceptions);
} catch (Throwable $e) {
$exceptions[] = [
'magasin' => $magasin->getKAdherent(),
'exception' => $e->getMessage()
];
}
try {
//Telephones Individu principal
[$contactsBdd, $exceptions] = $this->updateContactsByTypeByProgress($magasin, $contactsBdd, $canaux, 'telephones', 'GERANT', $exceptions);
} catch (Throwable $e) {
$exceptions[] = [
'magasin' => $magasin->getKAdherent(),
'exception' => $e->getMessage()
];
}
try {
//Mails individus principal
[$contactsBdd, $exceptions] = $this->updateContactsByTypeByProgress($magasin, $contactsBdd, $canaux, 'mails', 'GERANT', $exceptions);
} catch (Throwable $e) {
$exceptions[] = [
'magasin' => $magasin->getKAdherent(),
'exception' => $e->getMessage()
];
}
return [$contactsBdd, $exceptions];
}
/**
*
* @throws Exception
*/
public function updateContactsByTypeByProgress(Magasin $mag, array $contactsBdd, array $canaux, string $typeData, string $category, array $exceptions): array
{
$progressContacts = $this->getDatasProgress($mag, $typeData, $category);
foreach ($progressContacts as $ProgressContact) {
// Je reformate et corrige les data pour qu'elles soit clean
if ($ProgressContact['qualifiant']->getType() === "TEL") {
// tels
$valueProgressFormatted = $this->phoneNumberService->validateAndFormatPhoneNumber(preg_replace('/\s+/', '', strtolower($ProgressContact['value'])), strtoupper($mag->getKPays()));
} else {
// mails
$valueProgressFormatted = preg_replace('/\s+/', '', strtolower($ProgressContact['value']));
}
if (!is_null($valueProgressFormatted)) {
$existingContact = false;
// vérifie si il existe déjà en base, si il existe on compare les dates de maj et le met a jour si nécessaire
foreach ($contactsBdd as $contactBdd) {
if ($contactBdd->getQualifier() === $ProgressContact['qualifiant']) {
if ($ProgressContact['qualifiant']->isMultiple()) {
if ($valueProgressFormatted === preg_replace('/\s+/', '', strtolower($contactBdd->getValue()))) {
$contactBdd->setIdAnnuaireProgress((int)$ProgressContact['ID_ANNUAIRE']);
$contactBdd->setKProgress($ProgressContact['K_PROGRESS']);
$contactBdd->setPrincipal($ProgressContact['principal']);
$existingContact = $contactBdd;
}
} else {
$contactBdd->seIdAnnuaireProgress((int)$ProgressContact['ID_ANNUAIRE']);
$contactBdd->setKProgress($ProgressContact['K_PROGRESS']);
$contactBdd->setPrincipal($ProgressContact['principal']);
$existingContact = $contactBdd;
if ($ProgressContact['updated_at'] > $existingContact->getUpdatedAt()) {
$existingContact->setValue($valueProgressFormatted);
}
}
}
}
if (!$existingContact) {
$existingContact = new MagasinContact();
$existingContact->setMagasin($mag);
$existingContact->setQualifier($ProgressContact['qualifiant']);
$existingContact->setValue($valueProgressFormatted);
$existingContact->setIdAnnuaireProgress((int)$ProgressContact['ID_ANNUAIRE']);
$existingContact->setKProgress($ProgressContact['K_PROGRESS']);
$existingContact->setPrincipal($ProgressContact['principal']);
$contactsBdd[] = $existingContact;
}
// Assignation des canaux de com si il y en a
foreach ($ProgressContact['canaux'] as $canal) {
if (array_key_exists($canal, $canaux)) {
$existingContact->addCanaux($canaux[$canal]);
}
}
$existingContact->setExistInProgress(true);
$this->entityManager->persist($existingContact);
}
}
return [$contactsBdd, $exceptions];
}
}