<?php
namespace App\Repository;
use App\Entity\Cluster;
use DateTime;
use App\Entity\User;
use App\Entity\Production;
use App\Entity\EtatProduction;
use App\Entity\PointOfSale;
use App\Service\HierarchyService;
use Doctrine\Persistence\ManagerRegistry;
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
use Doctrine\ORM\Tools\Pagination\Paginator;
use Doctrine\Common\Collections\Criteria;
use Doctrine\ORM\Query\Expr\Join;
use Doctrine\ORM\QueryBuilder;
/**
* @extends ServiceEntityRepository<Production>
*
* @method Production|null find($id, $lockMode = null, $lockVersion = null)
* @method Production|null findOneBy(array $criteria, array $orderBy = null)
* @method Production[] findAll()
* @method Production[] findBy(array $criteria, array $orderBy = null, $limit = null, $offset = null)
*/
class ProductionRepository extends ServiceEntityRepository
{
private $hierarchyService;
public function __construct(ManagerRegistry $registry, HierarchyService $hierarchyService)
{
parent::__construct($registry, Production::class);
$this->hierarchyService = $hierarchyService;
}
public function add(Production $entity, bool $flush = false): void
{
$this->getEntityManager()->persist($entity);
if ($flush) {
$this->getEntityManager()->flush();
}
}
public function remove(Production $entity, bool $flush = false): void
{
$this->getEntityManager()->remove($entity);
if ($flush) {
$this->getEntityManager()->flush();
}
}
public function findProductionsByStatusAndDateByIdOfSales($debut, $fin, $pointOfSale, $page, $limit, $category, $product, $etat)
{
if ($debut != null) {
$dateDebutFormat = $debut->format('Y-m-d');
}
if ($fin != null) {
$dateFinFormat = $fin->format('Y-m-d');
} elseif ($debut != null && $fin == null) {
$dateFinFormat = $debut->format('Y-m-d');
}
$stmt = $this->createQueryBuilder('p')
->where('p.pointOfSale = :pointOfSale')
->andWhere('DATE_FORMAT(p.dateCmdA, \'%Y-%m-%d\') >= :dateDebut')
->andWhere('DATE_FORMAT(p.dateCmdA, \'%Y-%m-%d\') <= :dateFin')
->setParameter('pointOfSale', $pointOfSale)
->setParameter('dateDebut', $dateDebutFormat)
->setParameter('dateFin', $dateFinFormat);
if ($category != null) {
$stmt->andWhere('p.category = :category')
->setParameter('category', $category);
}
if ($product != null) {
$stmt->andWhere('p.product = :product')
->setParameter('product', $product);
}
if ($etat != null) {
$stmt->andWhere('p.etat = :etat')
->setParameter('etat', $etat);
}
$stmt->setFirstResult(($page - 1) * $limit)
->setMaxResults($limit);
$query = $stmt->getQuery();
$paginator = new Paginator($query, $fetchJoinCollection = true);
return $paginator;
}
public function findProductionsByStatusAndDateByIdOfSaleV2($debut, $fin, $pointOfSale)
{
$criteria = Criteria::create()
->where(Criteria::expr()->eq('pointOfSale', $pointOfSale));
if ($debut !== null) {
$criteria->andWhere(Criteria::expr()->gte('dateCmdA', $debut));
}
if ($fin !== null) {
$criteria->andWhere(Criteria::expr()->lte('dateCmdA', $fin));
}
return $this->matching($criteria)->toArray();
}
public function findProductionsByStatusAndDateByIdOfSaleV2_test($debut, $fin, $pointOfSale)
{
$qb = $this->createQueryBuilder('p')
->where('p.pointOfSale = :pointOfSale')
->setParameter('pointOfSale', $pointOfSale);
if ($debut !== null) {
$qb->andWhere('p.dateCmdA >= :debut')
->setParameter('debut', $debut);
}
if ($fin !== null) {
$qb->andWhere('p.dateCmdA <= :fin')
->setParameter('fin', $fin);
}
// Assurez-vous qu'aucune limite n'est définie
$qb->setMaxResults(null)->setFirstResult(null);
return $qb->getQuery()->getResult();
}
// public function findProductionsByStatusAndDateByIdOfSaleV2($debut, $fin, $pointOfSale)
// {
// if ($debut != null) {
// $dateDebutFormat = $debut->format('Y-m-d');
// }
// if ($fin != null) {
// $dateFinFormat = $debut->format('Y-m-d');
// }
// $stmt = $this->createQueryBuilder('p')
// ->where('p.pointOfSale = :pointOfSale')
// ->andWhere('DATE_FORMAT(p.dateCmdA, \'%Y-%m-%d\') >= :dateDebut')
// ->andWhere('DATE_FORMAT(p.dateCmdA, \'%Y-%m-%d\') <= :dateFin')
// ->setParameter('pointOfSale', $pointOfSale)
// ->setParameter('dateDebut', $dateDebutFormat)
// ->setParameter('dateFin', $dateFinFormat);
// $query = $stmt->getQuery();
// return $query->getArrayResult();
// }
public function findProductionsByStatusAndSale($children, ?DateTime $debut, ?int $id, ?EtatProduction $etat)
{
$stmt = $this->createQueryBuilder('p')
->leftJoin('p.pointOfSale', 'f')
->leftJoin('p.declarative', 'd')
->leftJoin('d.seller', 's')
->where('s.id IN (:sellers)')
->setParameter('sellers', $children)
->andWhere('f.id IN (:point_of_sale)')
->setParameter('point_of_sale', $id);
if ($debut != null) {
$dateDebutFormat = $debut->format('Y-m-d 00:00:00:00');
$stmt->andWhere('p.dateVenteValidB >= :dateDebut')
->setParameter('dateDebut', $dateDebutFormat);
}
if ($etat != null) {
$stmt->andWhere('p.etat = :etat')
->setParameter('etat', $etat->getId())
;
}
return $stmt
->getQuery()
->getResult();
}
public function getProductionForTurnover(?string $year, ?string $month, User $user, ?int $etatId, ?int $operatorId)
{
$children = $this->hierarchyService->childrenArray($user);
$stmt = $this->createQueryBuilder('p')
->leftJoin('p.declarative', 'd')
->leftJoin('d.seller', 's')
->where('s.id IN (:sellers)')
->setParameter('sellers', $children);
if ($year) {
$stmt->andwhere('YEAR(p.createdAt) = :year');
$stmt->setParameter('year', $year);
}
if ($month) {
$stmt->andwhere('MONTH(p.createdAt) = :month');
$stmt->setParameter('month', $month);
}
if ($etatId) {
$stmt->andwhere('p.etat = :etatId');
$stmt->setParameter('etatId', $etatId);
}
if ($operatorId) {
$stmt->andwhere('p.operator = :operatorId');
$stmt->setParameter('operatorId', $operatorId);
}
return $stmt->getQuery()->getResult();
}
/**
* @return Production[] Returns an array of Production objects
*/
public function getProductionCoordinates($codeCluster, $codeInsee, ?DateTime $debut, ?DateTime $fin): array
{
if ($debut != null) {
$dateDebutFormat = $debut->format('Y-m-d');
}
if ($fin != null) {
$dateFinFormat = $fin->format('Y-m-d');
} elseif ($debut != null && $fin == null) {
$dateFinFormat = $debut->format('Y-m-d');
}
$qb = $this->createQueryBuilder('p')
->select(
'p.codeInsee AS code_insee',
'p.latitude as latitude',
'p.longitude as longitude',
)
->leftJoin('p.cluster', 'c')
->addSelect('c.codeCluster AS code_cluster')
->andWhere('c.codeCluster = :codeCluster')
->setParameter('codeCluster', $codeCluster);
if ($codeInsee) {
$qb->andWhere('p.codeInsee = :codeInsee')
->setParameter('codeInsee', $codeInsee);
}
if ($debut != null) {
$qb->andWhere('DATE_FORMAT(p.dateVenteValidB, \'%Y-%m-%d\') >= :dateDebut')
->setParameter('dateDebut', $dateDebutFormat)
->andWhere('DATE_FORMAT(p.dateVenteValidB, \'%Y-%m-%d\') <= :dateFin')
->setParameter('dateFin', $dateFinFormat)
;
}
return $qb->getQuery()->getResult();
}
/**
* @return Production[] Returns an array of Production objects
*/
public function getProductionDeclarativeCoordinates($children, ?DateTime $debut, ?DateTime $fin): array
{
if ($debut != null) {
$dateDebutFormat = $debut->format('Y-m-d');
}
if ($fin != null) {
$dateFinFormat = $fin->format('Y-m-d');
} elseif ($debut != null && $fin == null) {
$dateFinFormat = $debut->format('Y-m-d');
}
$qb = $this->createQueryBuilder('p')
->select(
'p.latitude as latitude',
'p.longitude as longitude',
)
->leftJoin('p.declarative', 'd', 'WITH', 'p.numCommande = d.numCommande')
->leftJoin('d.seller', 's')
->where('s.id IN (:sellers)')
->setParameter('sellers', $children);
if ($debut != null) {
$qb->andWhere('DATE_FORMAT(p.dateVenteValidB, \'%Y-%m-%d\') >= :dateDebut')
->setParameter('dateDebut', $dateDebutFormat)
->andWhere('DATE_FORMAT(p.dateVenteValidB, \'%Y-%m-%d\') <= :dateFin')
->setParameter('dateFin', $dateFinFormat)
;
}
return $qb->getQuery()->getResult();
}
/**
* @return Production[] Returns an array of Production objects
*/
public function findProductionsTotalsByStatusAndDateAndUserIdGroupByCategory(
$children,
$user,
PointOfSale $pointOfSale,
?DateTime $debut,
?DateTime $fin
): array {
$qb = $this->createQueryBuilder('p')
->select(
// Totaux globaux
'(SELECT SUM(CASE WHEN DATE_FORMAT(p1.dateCmdA, \'%Y-%m-%d\') >= :dateDebut AND DATE_FORMAT(p1.dateCmdA, \'%Y-%m-%d\') <= :dateFin THEN 1 ELSE 0 END)
FROM App\Entity\Production p1
WHERE p1.pointOfSale = :pointOfSale AND p1.seller IN (:sellers)) as totalLignes_BRUT',
'(SELECT SUM(CASE WHEN DATE_FORMAT(p2.dateVenteValidB, \'%Y-%m-%d\') >= :dateDebut AND DATE_FORMAT(p2.dateVenteValidB, \'%Y-%m-%d\') <= :dateFin THEN 1 ELSE 0 END)
FROM App\Entity\Production p2
WHERE p2.pointOfSale = :pointOfSale AND p2.seller IN (:sellers)) as totalLignes_VALID',
'(SELECT SUM(CASE WHEN DATE_FORMAT(p3.dateRacc, \'%Y-%m-%d\') >= :dateDebut AND DATE_FORMAT(p3.dateRacc, \'%Y-%m-%d\') <= :dateFin THEN 1 ELSE 0 END)
FROM App\Entity\Production p3
WHERE p3.pointOfSale = :pointOfSale AND p3.seller IN (:sellers)) as totalLignes_RACC',
// Data par catégorie et par seller
'c.name as categoryName',
's.id as id',
's.prenom as prenom',
'SUM(CASE WHEN DATE_FORMAT(p.dateCmdA, \'%Y-%m-%d\') >= :dateDebut AND DATE_FORMAT(p.dateCmdA, \'%Y-%m-%d\') <= :dateFin THEN 1 ELSE 0 END) as BRUT',
'SUM(CASE WHEN DATE_FORMAT(p.dateVenteValidB, \'%Y-%m-%d\') >= :dateDebut AND DATE_FORMAT(p.dateVenteValidB, \'%Y-%m-%d\') <= :dateFin THEN 1 ELSE 0 END) as VALID',
'SUM(CASE WHEN DATE_FORMAT(p.dateRacc, \'%Y-%m-%d\') >= :dateDebut AND DATE_FORMAT(p.dateRacc, \'%Y-%m-%d\') <= :dateFin THEN 1 ELSE 0 END) as RACC'
)
->leftJoin('p.product', 'pr')
->leftJoin('pr.category', 'c')
->leftJoin('p.seller', 's')
->where('p.pointOfSale = :pointOfSale')
->andWhere('p.seller IN (:sellers)')
->setParameter('sellers', $children)
->setParameter('pointOfSale', $pointOfSale)
->setParameter('dateDebut', $debut ? $debut->format('Y-m-d') : null)
->setParameter('dateFin', $fin ? $fin->format('Y-m-d') : null)
->groupBy('c.name, s.id, s.prenom');
if ($debut !== null) {
$qb->andWhere(
'(DATE_FORMAT(p.dateCmdA, \'%Y-%m-%d\') >= :dateDebut AND DATE_FORMAT(p.dateCmdA, \'%Y-%m-%d\') <= :dateFin)
OR (DATE_FORMAT(p.dateVenteValidB, \'%Y-%m-%d\') >= :dateDebut AND DATE_FORMAT(p.dateVenteValidB, \'%Y-%m-%d\') <= :dateFin)
OR (DATE_FORMAT(p.dateRacc, \'%Y-%m-%d\') >= :dateDebut AND DATE_FORMAT(p.dateRacc, \'%Y-%m-%d\') <= :dateFin)'
);
}
if ($fin !== null) {
$qb->andWhere(
'(DATE_FORMAT(p.dateCmdA, \'%Y-%m-%d\') <= :dateFin)
OR (DATE_FORMAT(p.dateVenteValidB, \'%Y-%m-%d\') <= :dateFin)
OR (DATE_FORMAT(p.dateRacc, \'%Y-%m-%d\') <= :dateFin)'
);
}
return $qb->getQuery()->getArrayResult();
}
public function findProductionsUserIdTreeFirstkpi(
$parents,
$pointOfSale,
$clusterId,
$codeCluster,
$codeInsee,
?DateTime $debut,
?DateTime $fin,
$category,
$optionSelect
): array {
$qb = $this->createQueryBuilder('p')
->select('COUNT(p.id) as totalVentes, po.code as cpv');
$qb->leftJoin('p.pointOfSale', 'po')
->where('p.pointOfSale = :pointOfSale')
->setParameter('pointOfSale', $pointOfSale)
;
// Optionals
$qb->leftJoin('p.cluster', 'c')
->addSelect('c.codeCluster as codeCluster, c.libelleCluster as nomCluster,c.id as idCluster');
$groupByFields = ['p.cluster'];
if ($clusterId !== null) {
$qb->andWhere('c.id = :cluster')
->setParameter('cluster', $clusterId)
->addSelect('p.codeInsee as codeInsee,p.ville as ville');
$groupByFields[] = 'p.codeInsee';
} else {
if ($codeCluster) {
$qb->andWhere('c.codeCluster = :codeCluster')
->setParameter('codeCluster', $codeCluster)
->addSelect('p.codeInsee as codeInsee,p.ville as ville');
$groupByFields[] = 'p.codeInsee';
}
}
if ($category !== null) {
$qb->andWhere('p.category = :category')
->leftJoin('p.category', 'cat')
->addSelect('cat.name as categoryName')
->setParameter('category', $category);
}
if ($codeInsee !== null) {
$qb
->addSelect('p.streetName as nomVoie')
->andWhere('p.codeInsee = :codeInsee')
->setParameter('codeInsee', $codeInsee);
$groupByFields[] = 'p.streetName';
}
switch ($optionSelect) {
case 'V':
$qb->andWhere('DATE_FORMAT(p.dateVenteValidB, \'%Y-%m-%d\') >= :debut');
$qb->andWhere('DATE_FORMAT(p.dateVenteValidB, \'%Y-%m-%d\') <= :fin');
break;
case 'R':
$qb->andWhere('DATE_FORMAT(p.dateRacc, \'%Y-%m-%d\') >= :debut');
$qb->andWhere('DATE_FORMAT(p.dateRacc, \'%Y-%m-%d\') <= :fin');
break;
case 'B':
$qb->andWhere('DATE_FORMAT(p.dateCmdA, \'%Y-%m-%d\') >= :debut');
$qb->andWhere('DATE_FORMAT(p.dateCmdA, \'%Y-%m-%d\') <= :fin');
break;
}
$qb->setParameter('debut', $debut->format('Y-m-d'))
->setParameter('fin', $fin->format('Y-m-d'));
if (is_array($parents) && count($parents) > 0) {
$qb->andWhere('p.seller IN (:parents)')
->leftJoin('p.seller', 's')
->addSelect('s.id as idSeller , s.prenom as prenomSeller')
->setParameter('parents', $parents);
$groupByFields[] = 's.id';
}
$qb->orderBy('totalVentes', 'DESC');
$qb->groupBy(
implode(', ', $groupByFields)
);
// var_dump($qb->getQuery()->getSQL());
return $qb->getQuery()->getArrayResult();
}
public function findProductionsByOption(
$pointOfSale,
$month,
$year,
$etat,
$option,
$children = []
): array {
$qb = $this->createQueryBuilder('p')
->select('
COUNT(p.id) as totalVentes,
po.code as cpv
')
->leftJoin('p.pointOfSale', 'po')
->where('p.pointOfSale = :pointOfSale')
->setParameter('pointOfSale', $pointOfSale)
->andWhere('YEAR(p.dateRacc) = :year')
->setParameter('year', $year)
->andWhere('p.etat = :etat')
->setParameter('etat', $etat);
// Si option est 'raccordement', filtrer sur le mois de raccordement
if ($option === 'raccordement') {
$qb->andWhere('MONTH(p.dateRacc) = :month')
->addSelect('MONTH(p.dateVenteValidB) as moisValidation')
->setParameter('month', $month);
$qb->groupBy('moisValidation'); // Regrouper par mois de raccordement
} else {
$qb->andWhere('MONTH(p.dateVenteValidB) = :month')
->addSelect('MONTH(p.dateRacc) as moisRacc')
->setParameter('month', $month);
$qb->groupBy('moisRacc');
}
if (count($children) > 0) {
$qb->andWhere('p.seller IN (:children)')
->leftJoin('p.seller', 's')
->addSelect('
s.id as idSeller,
s.prenom as prenomSeller
')
->setParameter('children', $children);
}
$qb->orderBy('totalVentes', 'DESC');
return $qb->getQuery()->getArrayResult();
}
public function findProductionsByStatusAndDate(
$children,
$dateDebutVenteValidB,
$dateFinVenteValidB,
$etat
) {
$qb = $this->createQueryBuilder('p');
if ($etat != null) {
$qb->andWhere('p.etat = :etat')
->setParameter('etat', $etat);
}
if ($children) {
$qb->andWhere('s.id IN (:children)')
->leftJoin('p.seller', 's')
->setParameter('children', $children);
}
if ($dateDebutVenteValidB) {
$qb->andWhere('DATE_FORMAT(p.dateVenteValidB, \'%Y-%m-%d\') >= :dateDebut')
->setParameter('dateDebut', $dateDebutVenteValidB->format('Y-m-d'));
}
if ($dateFinVenteValidB) {
$qb->andWhere('DATE_FORMAT(p.dateVenteValidB, \'%Y-%m-%d\') <= :dateFin')
->setParameter('dateFin', $dateFinVenteValidB->format('Y-m-d'));
}
return $qb->getQuery()->getResult();
}
public function findProductionsByStatusAndDateAndPointOfSale(
$children,
$pointOfSale,
$dateDebutVenteValidB,
$dateFinVenteValidB,
$etat
) {
$qb = $this->createQueryBuilder('p')
->leftJoin('p.pointOfSale', 'po')
->where('p.pointOfSale = :pointOfSale')
->setParameter('pointOfSale', $pointOfSale);
if ($etat != null) {
$qb->andWhere('p.etat = :etat')
->setParameter('etat', $etat);
}
if (count($children) > 0) {
$qb->andWhere('p.seller IN (:children)')
->leftJoin('p.seller', 's')
// ->addSelect('
// s.id as idSeller,
// s.prenom as prenomSeller
// ')
->setParameter('children', $children);
}
if ($dateDebutVenteValidB) {
$qb->andWhere('DATE_FORMAT(p.dateVenteValidB, \'%Y-%m-%d\') >= :dateDebut')
->setParameter('dateDebut', $dateDebutVenteValidB->format('Y-m-d'));
}
if ($dateFinVenteValidB) {
$qb->andWhere('DATE_FORMAT(p.dateVenteValidB, \'%Y-%m-%d\') <= :dateFin')
->setParameter('dateFin', $dateFinVenteValidB->format('Y-m-d'));
}
return $qb->getQuery()->getResult();
}
public function findProductionsByOptionGroup(
$pointOfSale,
$optionSelect,
$optionGroup,
$debut,
$fin,
$codeCluster,
$codeInsee,
$childs,
$organisationId,
$category
) {
$qb = $this->createQueryBuilder('p')
->select('COUNT(p.id) as totalVentes');
// Joindre et sélectionner cpv uniquement si pas d’organisation
if (!$organisationId) {
$qb->addSelect('po.code as cpv')
->leftJoin('p.pointOfSale', 'po');
}
if ($pointOfSale !== null) {
$qb->andWhere('p.pointOfSale = :pointOfSale')
->setParameter('pointOfSale', $pointOfSale);
}
// Filtre de dates
switch ($optionSelect) {
case 'V':
$qb->andWhere('DATE_FORMAT(p.dateVenteValidB, \'%Y-%m-%d\') >= :debut');
$qb->andWhere('DATE_FORMAT(p.dateVenteValidB, \'%Y-%m-%d\') <= :fin');
break;
case 'R':
$qb->andWhere('DATE_FORMAT(p.dateRacc, \'%Y-%m-%d\') >= :debut');
$qb->andWhere('DATE_FORMAT(p.dateRacc, \'%Y-%m-%d\') <= :fin');
break;
case 'B':
$qb->andWhere('DATE_FORMAT(p.dateCmdA, \'%Y-%m-%d\') >= :debut');
$qb->andWhere('DATE_FORMAT(p.dateCmdA, \'%Y-%m-%d\') <= :fin');
break;
}
$qb->setParameter('debut', $debut->format('Y-m-d'))
->setParameter('fin', $fin->format('Y-m-d'));
// Filtre cluster
if ($codeCluster) {
$qb->leftJoin('p.cluster', 'cluster')
->addSelect('cluster.codeCluster as clusterCode')
->andWhere('cluster.codeCluster = :codeCluster')
->setParameter('codeCluster', $codeCluster);
}
if ($codeInsee) {
$qb->addSelect('p.codeInsee')
->andWhere('p.codeInsee = :codeInsee')
->setParameter('codeInsee', $codeInsee);
}
if ($organisationId) {
$qb->andWhere('p.organisation = :organisationId')
->setParameter('organisationId', $organisationId);
}
if (is_array($childs) && count($childs) > 0) {
$qb->andWhere('p.seller IN (:childs)')
->leftJoin('p.seller', 's')
->setParameter('childs', $childs);
}
// Gestion du groupement
switch ($optionGroup) {
case 'Tech':
$qb->addSelect('p.tech as tech');
if (!$organisationId) {
$qb->groupBy('po.code, p.tech');
} else {
$qb->groupBy('p.tech');
}
break;
case 'Categorie':
$qb->addSelect('category.name as categoryName')
->leftJoin('p.category', 'category');
if (!$organisationId) {
$qb->groupBy('po.code, category.id');
} else {
$qb->groupBy('category.id');
}
break;
case 'Produit':
$qb->addSelect('product.name as productName, cat.name as categoryName')
->leftJoin('p.product', 'product')
->leftJoin('product.category', 'cat');
if (!$organisationId) {
$qb->groupBy('po.code, product.id');
} else {
$qb->groupBy('product.id');
}
if ($category) {
$category = array_filter(
array_map('intval', explode(',', $category)),
fn($id) => $id > 0
);
$qb->andWhere('p.category IN (:categories)')
->setParameter('categories', $category);
}
break;
case 'PreCommande':
$qb->addSelect('p.preCommande as preCommande');
if (!$organisationId) {
$qb->groupBy('po.code, p.preCommande');
} else {
$qb->groupBy('p.preCommande');
}
break;
default:
if (!$organisationId) {
$qb->groupBy('po.code');
}
break;
}
return $qb->getQuery()->getResult();
}
public function findProductionsByLblMotifInstance(
$pointOfSale,
$debut,
$fin,
$codeCluster,
$codeInsee,
$childs,
$organisationId
) {
$qb = $this->createQueryBuilder('p')
->select('
COUNT(p.id) as totalVentes,
po.code as cpv,
p.libelleMotifInstance as libelle_motif_instance
')
->leftJoin('p.pointOfSale', 'po');
if ($pointOfSale) {
$qb->where('p.pointOfSale = :pointOfSale')
->setParameter('pointOfSale', $pointOfSale);
}
//seuelemnt les KO
$qb->leftJoin('p.etat', 'e')
->andWhere('e.id = :idEtat')
->setParameter('idEtat', 2)
->andWhere('DATE_FORMAT(p.dateVenteValidB, \'%Y-%m-%d\') >= :debut')
->andWhere('DATE_FORMAT(p.dateVenteValidB, \'%Y-%m-%d\') <= :fin')
->setParameter('debut', $debut->format('Y-m-d'))
->setParameter('fin', $fin->format('Y-m-d'));
if ($codeCluster) {
$qb->leftJoin('p.cluster', 'c')
->addSelect('c.codeCluster')
->andWhere('c.codeCluster = :codeCluster')
->setParameter('codeCluster', $codeCluster)
;
}
if ($codeInsee) {
$qb->addSelect('p.codeInsee')
->andWhere('p.codeInsee = :codeInsee')
->setParameter('codeInsee', $codeInsee)
;
}
if ($organisationId) {
$qb->andWhere('p.organisation = :organisationId')
->setParameter('organisationId', $organisationId);
}
if (is_array($childs) && count($childs) > 0) {
$qb->andWhere('p.seller IN (:childs)')
->leftJoin('p.seller', 's')
->setParameter('childs', $childs);
}
$qb->groupBy('p.libelleMotifInstance, po.id');
return $qb->getQuery()->getResult();
}
public function findProductionsByStatus($children, $pointOfSale, $debut, $fin)
{
$qb = $this->createQueryBuilder('p')
->select('
COUNT(p.id) as totalVentes,
po.code as cpv,
e.nom as status
')
->leftJoin('p.pointOfSale', 'po')
->where('p.pointOfSale = :pointOfSale')
->setParameter('pointOfSale', $pointOfSale)
->leftJoin('p.etat', 'e');
$groupByFields = ['e.nom', 'e.id'];
if (count($children) > 0) {
$qb->andWhere('p.seller IN (:children)')
->leftJoin('p.seller', 's')
->addSelect('
s.id as idSeller,
s.prenom as prenomSeller
')
->setParameter('children', $children);
$groupByFields[] = 's.id';
}
$qb->andWhere('DATE_FORMAT(p.dateVenteValidB, \'%Y-%m-%d\') >= :debut')
->andWhere('DATE_FORMAT(p.dateVenteValidB, \'%Y-%m-%d\') <= :fin')
->setParameter('debut', $debut->format('Y-m-d'))
->setParameter('fin', $fin->format('Y-m-d'))
->orderBy('e.id')
->groupBy(
implode(', ', $groupByFields)
);
return $qb->getQuery()->getResult();
}
public function findProductionsByAnnulationTypes($pointOfSale, $debut, $fin, $codeCluster, $codeInsee, $childs, $organisationId)
{
$qb = $this->createQueryBuilder('p')
->select(
'SUM(CASE
WHEN p.motifInstance LIKE :reseauMotif1
OR p.motifInstance LIKE :reseauMotif2
OR p.motifInstance LIKE :reseauMotif3
OR p.motifInstance LIKE :reseauMotif4 THEN 1
ELSE 0
END) AS totalReseau',
'SUM(CASE
WHEN p.motifInstance LIKE :ventesMotif1
OR p.motifInstance LIKE :ventesMotif2 THEN 1
ELSE 0
END) AS totalVentes',
'po.code AS cpv'
)
->leftJoin('p.pointOfSale', 'po')
->leftJoin('p.etat', 'e')
->andWhere('e.id = :idEtat')
->andWhere('DATE_FORMAT(p.dateVenteValidB, \'%Y-%m-%d\') >= :debut')
->andWhere('DATE_FORMAT(p.dateVenteValidB, \'%Y-%m-%d\') <= :fin')
->setParameter('idEtat', 2)
->setParameter('debut', $debut->format('Y-m-d'))
->setParameter('fin', $fin->format('Y-m-d'))
->setParameter('reseauMotif1', 'T%')
->setParameter('reseauMotif2', 'R%')
->setParameter('reseauMotif3', 'O%')
->setParameter('reseauMotif4', 'E%')
->setParameter('ventesMotif1', 'S%')
->setParameter('ventesMotif2', 'A%');
// CORRECTION : utiliser andWhere, jamais where seul
if (!empty($pointOfSale)) {
$qb->andWhere('p.pointOfSale = :pointOfSale')
->setParameter('pointOfSale', $pointOfSale);
}
if (!empty($codeCluster)) {
$qb->leftJoin('p.cluster', 'c')
->addSelect('c.codeCluster')
->andWhere('c.codeCluster = :codeCluster')
->setParameter('codeCluster', $codeCluster);
}
if (!empty($codeInsee)) {
$qb->addSelect('p.codeInsee')
->andWhere('p.codeInsee = :codeInsee')
->setParameter('codeInsee', $codeInsee);
}
if ($organisationId) {
$qb->andWhere('p.organisation = :organisationId')
->setParameter('organisationId', $organisationId);
}
// if (!empty($children)) {
// $qb->leftJoin('p.seller', 's')
// ->addSelect('s.id as idSeller, s.prenom as prenomSeller')
// ->andWhere('p.seller IN (:children)')
// ->setParameter('children', $children)
// ->groupBy('s.id');
// }
if (is_array($childs) && count($childs) > 0) {
$qb->andWhere('p.seller IN (:childs)')
->leftJoin('p.seller', 's')
->setParameter('childs', $childs);
}
$qb->groupBy('po.id');
return $qb->getQuery()->getResult();
}
public function findProductionsByStatutIntervention($pointOfSale, $debut, $fin, $codeCluster, $codeInsee, $childs, $organisationId)
{
$qb = $this->createQueryBuilder('p')
->select(
'SUM(CASE WHEN p.statutIntervention = :statut1 THEN 1 ELSE 0 END) AS totalXapRDV',
'SUM(CASE WHEN p.statutIntervention = :statut2 THEN 1 ELSE 0 END) AS totalXavRDV',
'po.code AS cpv'
)
->leftJoin('p.pointOfSale', 'po')
->leftJoin('p.etat', 'e')
->andWhere('e.id = :idEtat')
->andWhere('DATE_FORMAT(p.dateVenteValidB, \'%Y-%m-%d\') >= :debut')
->andWhere('DATE_FORMAT(p.dateVenteValidB, \'%Y-%m-%d\') <= :fin')
->groupBy('po.id')
->setParameter('statut1', 'XapRDV')
->setParameter('statut2', 'XavRDV')
->setParameter('idEtat', 2)
->setParameter('debut', $debut->format('Y-m-d'))
->setParameter('fin', $fin->format('Y-m-d'));
if (!empty($pointOfSale)) {
$qb->andWhere('p.pointOfSale = :pointOfSale')
->setParameter('pointOfSale', $pointOfSale);
}
if (!empty($codeCluster)) {
$qb->leftJoin('p.cluster', 'c')
->addSelect('c.codeCluster')
->andWhere('c.codeCluster = :codeCluster')
->setParameter('codeCluster', $codeCluster);
}
if (!empty($codeInsee)) {
$qb->addSelect('p.codeInsee')
->andWhere('p.codeInsee = :codeInsee')
->setParameter('codeInsee', $codeInsee);
}
if (is_array($childs) && count($childs) > 0) {
$qb->andWhere('p.seller IN (:childs)')
->leftJoin('p.seller', 's')
->setParameter('childs', $childs);
}
if ($organisationId) {
$qb->andWhere('p.organisation = :organisationId')
->setParameter('organisationId', $organisationId);
}
return $qb->getQuery()->getResult();
}
public function findProductionsByCategoryFor12Months($pointOfSale, $mois, $year, $codeCluster, $codeInsee, $childs, $organisationId)
{
$mois = $this->generatePreviousMonths($year, $mois, 12);
$qb = $this->createQueryBuilder('p');
foreach ($mois as $cle => $moisData) {
$qb->addSelect(sprintf(
"SUM(CASE WHEN DATE_FORMAT(p.dateCmdA, '%%Y-%%m') = '%s' THEN 1 ELSE 0 END) AS total_date_cmd_a_%d",
$moisData['mois_annee'],
$cle
));
$qb->addSelect(sprintf(
"SUM(CASE WHEN DATE_FORMAT(p.dateVenteValidB, '%%Y-%%m') = '%s' THEN 1 ELSE 0 END) AS total_date_vente_valid_b_%d",
$moisData['mois_annee'],
$cle
));
$qb->addSelect(sprintf(
"SUM(CASE WHEN DATE_FORMAT(p.dateRacc, '%%Y-%%m') = '%s' THEN 1 ELSE 0 END) AS total_date_racc_%d",
$moisData['mois_annee'],
$cle
));
}
$qb
->leftJoin('App\Entity\CategoryProduct', 'cp', 'WITH', 'p.category = cp.id')
->leftJoin('App\Entity\PointOfSale', 'po', 'WITH', 'p.pointOfSale = po.id')
->addSelect('cp.name as categoryName, po.code as cpv');
if ($pointOfSale) {
$qb
->where('p.pointOfSale = :pointOfSale')
->setParameter('pointOfSale', $pointOfSale);
}
if ($codeCluster) {
$qb->leftJoin('p.cluster', 'c')
->addSelect('c.codeCluster')
->andWhere('c.codeCluster = :codeCluster')
->setParameter('codeCluster', $codeCluster)
;
}
if ($codeInsee) {
$qb->addSelect('p.codeInsee')
->andWhere('p.codeInsee = :codeInsee')
->setParameter('codeInsee', $codeInsee)
;
}
if ($organisationId) {
$qb->andWhere('p.organisation = :organisationId')
->setParameter('organisationId', $organisationId);
}
$qb
->groupBy('cp.name,po.id')
->orderBy('cp.name', 'ASC');
// Ajout des colonnes statiques pour les mois
foreach ($mois as $cle => $moisData) {
$qb->addSelect(sprintf("'%s' AS mois_annee_%d", $moisData['mois_annee'], $cle));
}
if (is_array($childs) && count($childs) > 0) {
$qb->andWhere('p.seller IN (:childs)')
->leftJoin('p.seller', 's')
->setParameter('childs', $childs);
}
return $qb->getQuery()->getResult();
}
public function getTotalVentesObjectifs($mois, $annee)
{
$qb = $this->createQueryBuilder('p')
// Filtre sur la date_vente_valid_b en fonction du mois et de l'année
->innerJoin('App\Entity\PointOfSale', 'po', Join::WITH, 'p.pointOfSale = po.id')
->innerJoin('App\Entity\NmdObjectifClusters', 'o', Join::WITH, 'po.code = o.cpv AND o.mois = :mois AND o.year = :annee')
->innerJoin('App\Entity\Cluster', 'c', Join::WITH, 'p.cluster = c.id AND c.codeCluster = o.codeCluster')
->innerJoin('App\Entity\EtatProduction', 'e', Join::WITH, 'p.etat = e.id')
// Sélectionner les champs
->addSelect('po.code AS cpv')
->addSelect('c.codeCluster AS codeCluster')
->addSelect('MAX(c.libelleCluster) AS libelleCluster')
->addSelect('e.nom AS etat')
->addSelect('COUNT(p.id) AS totalVente')
->addSelect('o.vv')
->addSelect('o.vr')
->addSelect('o.mois')
->addSelect('o.year')
// Conditions de filtrage par mois et année
->where('MONTH(p.dateVenteValidB) = :mois')
->andWhere('YEAR(p.dateVenteValidB) = :annee')
->setParameter('mois', $mois)
->setParameter('annee', $annee)
// Regroupement
->groupBy('po.code, c.codeCluster, e.id, o.mois, o.year')
// Ordre
->orderBy('po.code', 'ASC')
->addOrderBy('c.codeCluster', 'ASC')
// Exécuter la requête
->getQuery();
return $qb->getArrayResult();
}
private function createBaseQueryBuilder(
$pointOfSale,
$codeCluster,
$codeInsee,
$mois,
$annee,
$optionSelect,
$departement
): QueryBuilder {
$qb = $this->createQueryBuilder('p')
->leftJoin('p.pointOfSale', 'po')
->leftJoin('p.cluster', 'c');
// ✅ N’ajouter la condition que si un point de vente est défini
if ($pointOfSale !== null) {
$qb->where('p.pointOfSale = :pointOfSale')
->setParameter('pointOfSale', $pointOfSale);
} else {
// sinon on s'assure juste d'avoir une clause WHERE neutre
$qb->where('1 = 1');
}
if ($codeCluster) {
$qb->andWhere('c.codeCluster = :codeCluster')
->setParameter('codeCluster', $codeCluster);
}
if ($codeInsee) {
$qb->andWhere('p.codeInsee = :codeInsee')
->setParameter('codeInsee', $codeInsee);
}
switch ($optionSelect) {
case 'V':
$qb->andWhere('MONTH(p.dateVenteValidB) = :mois')
->andWhere('YEAR(p.dateVenteValidB) = :annee');
break;
case 'R':
$qb->andWhere('MONTH(p.dateRacc) = :mois')
->andWhere('YEAR(p.dateRacc) = :annee');
break;
case 'B':
$qb->andWhere('MONTH(p.dateCmdA) = :mois')
->andWhere('YEAR(p.dateCmdA) = :annee');
break;
}
if ($departement) {
$qb->andWhere('c.codeCluster LIKE :prefix')
->setParameter('prefix', $departement . '-%');
}
$qb->setParameter('mois', $mois)
->setParameter('annee', $annee);
return $qb;
}
private function createBaseQueryBuilderTest($pointOfSale, $codeCluster, $codeInsee, $mois, $annee, $optionSelect, $organisationId, $departement): QueryBuilder
{
$qb = $this->createQueryBuilder('p')
->leftJoin('p.cluster', 'c');
if ($organisationId) {
$qb->andWhere('p.organisation = :organisationId')
->setParameter('organisationId', $organisationId);
} else {
$qb->leftJoin('p.pointOfSale', 'po')
->where('p.pointOfSale = :pointOfSale')
->setParameter('pointOfSale', $pointOfSale);
}
if ($codeCluster) {
$qb
->andWhere('c.codeCluster = :codeCluster')
->setParameter('codeCluster', $codeCluster);
}
if ($codeInsee) {
$qb->andWhere('p.codeInsee = :codeInsee')
->setParameter('codeInsee', $codeInsee);
}
switch ($optionSelect) {
case 'V':
$qb->andWhere('MONTH(p.dateVenteValidB) = :mois')
->andWhere('YEAR(p.dateVenteValidB) = :annee');
break;
case 'R':
$qb->andWhere('MONTH(p.dateRacc) = :mois')
->andWhere('YEAR(p.dateRacc) = :annee');
break;
case 'B':
$qb->andWhere('MONTH(p.dateCmdA) = :mois')
->andWhere('YEAR(p.dateCmdA) = :annee');
break;
}
if ($departement) {
// Si le département est fourni, on cherche les clusters dont le code commence par "departement-"
$qb->andWhere('c.codeCluster LIKE :prefix')
->setParameter('prefix', $departement . '-%');
}
$qb->setParameter('mois', $mois)
->setParameter('annee', $annee);
return $qb;
}
private function createBaseQueryBuilder2($pointOfSale, $codeCluster, $codeInsee, $mois, $annee, $optionSelect, $departement): QueryBuilder
{
$qb = $this->createQueryBuilder('p')
->leftJoin('p.cluster', 'c')
->where('p.pointOfSale = :pointOfSale')
->setParameter('pointOfSale', $pointOfSale);
if ($codeCluster) {
$qb
->andWhere('c.codeCluster = :codeCluster')
->setParameter('codeCluster', $codeCluster);
}
if ($departement) {
// Si le département est fourni, on cherche les clusters dont le code commence par "departement-"
$qb->andWhere('c.codeCluster LIKE :prefix')
->setParameter('prefix', $departement . '-%');
}
if ($codeInsee) {
$qb->andWhere('p.codeInsee = :codeInsee')
->setParameter('codeInsee', $codeInsee);
}
$qb->andWhere('MONTH(p.dateCmdA) = :mois')
->andWhere('YEAR(p.dateCmdA) = :annee');
$qb->setParameter('mois', $mois)
->setParameter('annee', $annee);
return $qb;
}
public function getProductionsAnalyticsVentes($pointOfSale, $codeCluster, $codeInsee, $mois, $annee, $optionSelect, $etat, $category, $childs, $organisationId, $perid, $sellerId, $departement): array
{
$qb = $this->createBaseQueryBuilder($pointOfSale, $codeCluster, $codeInsee, $mois, $annee, $optionSelect, $departement)
->select('COUNT(p.id) as total_ventes');
if ($category != null) {
$category = array_filter(
array_map('intval', explode(',', $category)),
fn($id) => $id > 0
);
$qb->andWhere('p.category IN (:categories)')
->setParameter('categories', $category);
}
if ($organisationId) {
$qb->andWhere('p.organisation = :organisationId')
->setParameter('organisationId', $organisationId);
}
if ($perid) {
$qb->andWhere('p.loginVendeurInit = :perid ')
->setParameter('perid', $perid);
}
if ($sellerId) {
$qb->andWhere('p.seller = :sellerId')
->setParameter('sellerId', $sellerId);
}
/*Gestion de cas des produits fixe qui existent dans
le fichier mobile on doit le supprimer depuis mobile et on le prend dans fixe */
if ($etat == "Raccorde") {
$qb->andWhere('p.dateRacc IS NOT NULL')
->andWhere(
$qb->expr()->orX(
$qb->expr()->in('p.category', [1, 2, 3]),
$qb->expr()->in('p.product', [150, 262, 264, 266, 334, 335, 341, 344, 345, 379, 441, 442, 443, 444])
)
);
}
#MOBILE
else if ($etat == "Raccorde_mobile") {
$qb->andWhere('p.category IN (31,32,33,48)')
// ->andWhere('p.etat = 1')
->andWhere('p.dateRacc IS NOT NULL ')
->andWhere('p.product NOT IN (150,262,264,266,334,335,341,344,345,379,441,442,443,444) ')
;
}
if (is_array($childs) && count($childs) > 0) {
$qb->andWhere('p.seller IN (:childs)')
->leftJoin('p.seller', 's')
->setParameter('childs', $childs);
}
$qb->orderBy('total_ventes', 'DESC');
return $qb->getQuery()->getArrayResult();
}
public function getProductionsAnalyticsVentesForChurn($pointOfSale, $codeCluster, $codeInsee, $mois, $annee, $optionSelect, $etat, $category, $childs, $organisationId, $perid, $sellerId, $departement): array
{
$qb = $this->createBaseQueryBuilder($pointOfSale, $codeCluster, $codeInsee, $mois, $annee, $optionSelect, $departement)
->select('COUNT(p.id) as total_ventes');
if ($category != null) {
$category = array_filter(
array_map('intval', explode(',', $category)),
fn($id) => $id > 0
);
$qb->andWhere('p.category IN (:categories)')
->setParameter('categories', $category);
}
if ($organisationId) {
$qb->andWhere('p.organisation = :organisationId')
->setParameter('organisationId', $organisationId);
}
if ($perid) {
$qb->andWhere('p.loginVendeurInit = :perid ')
->setParameter('perid', $perid);
}
if ($sellerId) {
$qb->andWhere('p.seller = :sellerId')
->setParameter('sellerId', $sellerId);
}
/*Gestion de cas des produits fixe qui existent dans
le fichier mobile on doit le supprimer depuis mobile et on le prend dans fixe */
if ($etat == "Raccorde") {
$qb->andWhere('p.dateRacc IS NOT NULL')
->andWhere(
$qb->expr()->orX(
$qb->expr()->in('p.category', [1, 3]),
$qb->expr()->andX(
$qb->expr()->in('p.category', [31]),
$qb->expr()->in('p.product', [150, 262, 264, 266, 334, 335, 341, 344, 345, 379, 441, 442, 443, 444])
)
)
);
}
#MOBILE
else if ($etat == "Raccorde_mobile") {
$qb->andWhere('p.category IN (31,32,33,48)')
// ->andWhere('p.etat = 1')
->andWhere('p.dateRacc IS NOT NULL ')
->andWhere('p.product NOT IN (150,262,264,266,334,335,341,344,345,379,441,442,443,444) ')
;
}
if (is_array($childs) && count($childs) > 0) {
$qb->andWhere('p.seller IN (:childs)')
->leftJoin('p.seller', 's')
->setParameter('childs', $childs);
}
$qb->orderBy('total_ventes', 'DESC');
return $qb->getQuery()->getArrayResult();
}
public function getProductionsAnalyticsVentesForChurn5G($pointOfSale, $codeCluster, $codeInsee, $mois, $annee, $optionSelect, $etat, $category, $childs, $organisationId, $perid, $sellerId, $departement): array
{
$qb = $this->createBaseQueryBuilder($pointOfSale, $codeCluster, $codeInsee, $mois, $annee, $optionSelect, $departement)
->select('COUNT(p.id) as total_ventes');
if ($category != null) {
$category = array_filter(
array_map('intval', explode(',', $category)),
fn($id) => $id > 0
);
$qb->andWhere('p.category IN (:categories)')
->setParameter('categories', $category);
}
if ($organisationId) {
$qb->andWhere('p.organisation = :organisationId')
->setParameter('organisationId', $organisationId);
}
if ($perid) {
$qb->andWhere('p.loginVendeurInit = :perid ')
->setParameter('perid', $perid);
}
if ($sellerId) {
$qb->andWhere('p.seller = :sellerId')
->setParameter('sellerId', $sellerId);
}
/*Gestion de cas des produits fixe qui existent dans
le fichier mobile on doit le supprimer depuis mobile et on le prend dans fixe */
if ($etat == "Raccorde") {
$qb->andWhere('p.dateRacc IS NOT NULL')
->andWhere(
$qb->expr()->in('p.product', [150, 262, 264, 266, 334, 335, 341, 344, 345, 379, 441, 442, 443, 444])
);
}
#MOBILE
else if ($etat == "Raccorde_mobile") {
$qb->andWhere('p.category IN (31,32,33,48)')
// ->andWhere('p.etat = 1')
->andWhere('p.dateRacc IS NOT NULL ')
->andWhere('p.product NOT IN (150,262,264,266,334,335,341,344,345,379,441,442,443,444) ')
;
}
if (is_array($childs) && count($childs) > 0) {
$qb->andWhere('p.seller IN (:childs)')
->leftJoin('p.seller', 's')
->setParameter('childs', $childs);
}
$qb->orderBy('total_ventes', 'DESC');
return $qb->getQuery()->getArrayResult();
}
public function getProductionsAnalyticsVentesBox5G($pointOfSale, $codeCluster, $codeInsee, $mois, $annee, $optionSelect, $etat, $category, $childs, $organisationId, $perid, $sellerId, $departement): array
{
$qb = $this->createBaseQueryBuilder($pointOfSale, $codeCluster, $codeInsee, $mois, $annee, "B", $departement)
->select('COUNT(p.id) as total_ventes');
if ($organisationId) {
$qb->andWhere('p.organisation = :organisationId')
->setParameter('organisationId', $organisationId);
}
if ($perid) {
$qb->andWhere('p.loginVendeurInit = :perid ')
->setParameter('perid', $perid);
}
if ($sellerId) {
$qb->andWhere('p.seller = :sellerId')
->setParameter('sellerId', $sellerId);
}
$qb->andWhere('p.product IN (150,262,264,266,334,335,341,344,345,379,441,442,443,444)');
if (is_array($childs) && count($childs) > 0) {
$qb->andWhere('p.seller IN (:childs)')
->leftJoin('p.seller', 's')
->setParameter('childs', $childs);
}
$qb->orderBy('total_ventes', 'DESC');
return $qb->getQuery()->getArrayResult();
}
public function getProductionsAnalyticsVentesVlaConquete($pointOfSale, $codeCluster, $codeInsee, $mois, $annee, $optionSelect, $category, $childs, $organisationId, $perid, $sellerId, $departement): array
{
$qb = $this->createBaseQueryBuilder($pointOfSale, $codeCluster, $codeInsee, $mois, $annee, $optionSelect, $departement)
->select('COUNT(p.id) as total_ventes');
if ($category) {
$category = array_filter(
array_map('intval', explode(',', $category)),
fn($id) => $id > 0
);
$qb->andWhere('p.category IN (:categories)')
->setParameter('categories', $category);
}
if ($organisationId) {
$qb->andWhere('p.organisation = :organisationId')
->setParameter('organisationId', $organisationId);
}
if ($perid) {
$qb->andWhere('p.loginVendeurInit = :perid ')
->setParameter('perid', $perid);
}
if ($sellerId) {
$qb->andWhere('p.seller = :sellerId')
->setParameter('sellerId', $sellerId);
}
if (is_array($childs) && count($childs) > 0) {
$qb->andWhere('p.seller IN (:childs)')
->leftJoin('p.seller', 's')
->setParameter('childs', $childs);
}
$qb->orderBy('total_ventes', 'DESC');
return $qb->getQuery()->getArrayResult();
}
public function getProductionsAnalyticsVendeurs($pointOfSale, $codeCluster, $codeInsee, $mois, $annee, $optionSelect, $etatKO, $category, $childs, $organisationId, $perid, $sellerId, $departement): array
{
$qb = $this->createBaseQueryBuilderTest($pointOfSale, $codeCluster, $codeInsee, $mois, $annee, $optionSelect, $organisationId, $departement)
->select('COUNT(DISTINCT s.id) as nombre_vendeurs')
->leftJoin('p.seller', 's');
if ($category) {
$category = array_filter(
array_map('intval', explode(',', $category)),
fn($id) => $id > 0
);
$qb->andWhere('p.category IN (:categories)')
->setParameter('categories', $category);
}
if ($perid) {
$qb->andWhere('p.loginVendeurInit = :perid ')
->setParameter('perid', $perid);
}
if ($sellerId) {
$qb->andWhere('p.seller = :sellerId')
->setParameter('sellerId', $sellerId);
}
if (is_array($childs) && count($childs) > 0) {
$qb->andWhere('p.seller IN (:childs)')
->setParameter('childs', $childs);
}
return $qb->getQuery()->getArrayResult();
}
public function getProductionsAnalyticsETP($pointOfSale, $codeCluster, $codeInsee, $mois, $annee, $optionSelect, $etatKO, $category, $childs, $organisationId, $perid, $sellerId, $departement): array
{
$qb = $this->createBaseQueryBuilder($pointOfSale, $codeCluster, $codeInsee, $mois, $annee, $optionSelect, $departement)
->select('COUNT(p.id) / NULLIF(COUNT(DISTINCT s.id), 0) AS etp')
->leftJoin('p.seller', 's');
if ($category) {
$category = array_filter(
array_map('intval', explode(',', $category)),
fn($id) => $id > 0
);
$qb->andWhere('p.category IN (:categories)')
->setParameter('categories', $category);
}
if (is_array($childs) && count($childs) > 0) {
$qb->andWhere('p.seller IN (:childs)')
->setParameter('childs', $childs);
}
if ($organisationId) {
$qb->andWhere('p.organisation = :organisationId')
->setParameter('organisationId', $organisationId);
}
if ($perid) {
$qb->andWhere('p.loginVendeurInit = :perid ')
->setParameter('perid', $perid);
}
if ($sellerId) {
$qb->andWhere('p.seller = :sellerId')
->setParameter('sellerId', $sellerId);
}
return $qb->getQuery()->getArrayResult();
}
public function getProductionsAnalyticsKO($pointOfSale, $codeCluster, $codeInsee, $mois, $annee, $optionSelect, $etatKO, $category, $childs, $organisationId, $perid, $sellerId, $departement): array
{
$qb = $this->createBaseQueryBuilder($pointOfSale, $codeCluster, $codeInsee, $mois, $annee, $optionSelect, $departement)
->select('COUNT(p.id) AS total_ventes_ko')
->andWhere('p.etat = :etat')
->setParameter('etat', $etatKO);
if ($category) {
$category = array_filter(
array_map('intval', explode(',', $category)),
fn($id) => $id > 0
);
$qb->andWhere('p.category IN (:categories)')
->setParameter('categories', $category);
}
if (is_array($childs) && count($childs) > 0) {
$qb->andWhere('p.seller IN (:childs)')
->setParameter('childs', $childs);
}
if ($organisationId) {
$qb->andWhere('p.organisation = :organisationId')
->setParameter('organisationId', $organisationId);
}
if ($perid) {
$qb->andWhere('p.loginVendeurInit = :perid ')
->setParameter('perid', $perid);
}
if ($sellerId) {
$qb->andWhere('p.seller = :sellerId')
->setParameter('sellerId', $sellerId);
}
return $qb->getQuery()->getArrayResult();
}
public function getProductionsAnalyticsObjectifs(
$pointOfSale,
$codeCluster,
$mois,
$annee,
$optionSelect,
$etatKO,
$category,
$childs,
$organisationId,
$departement
): array {
$qb = $this->getEntityManager()->createQueryBuilder()
->select('SUM(o.vv) AS total_objectif')
->from('App\Entity\NmdObjectifClusters', 'o')
->where('o.cpv = :cpv')
->setParameter('cpv', $pointOfSale->getCode())
->andWhere('o.mois = :mois')
->andWhere('o.year = :annee')
->setParameter('mois', $mois)
->setParameter('annee', $annee);
if ($codeCluster) {
$qb
->andWhere('o.codeCluster = :codeCluster')
->setParameter('codeCluster', $codeCluster);
}
if ($departement) {
// Si le département est fourni, on cherche les clusters dont le code commence par "departement-"
$qb->andWhere('o.codeCluster LIKE :prefix')
->setParameter('prefix', $departement . '-%');
}
if (is_array($childs) && count($childs) > 0) {
$qb = $this->getEntityManager()->createQueryBuilder()
->select('SUM(o.objectivesVv) AS total_objectif')
->from('App\Entity\ObjectivesManagement', 'o')
->andWhere('MONTH(o.monthAt) = :mois')
->andWhere('YEAR(o.monthAt) = :annee')
->setParameter('mois', $mois)
->setParameter('annee', $annee);
$qb->andWhere('o.user IN (:childs)')
->leftJoin('o.user', 's')
->setParameter('childs', $childs);
}
return $qb->getQuery()->getArrayResult();
}
public function getProductionsAnalyticsProjection($pointOfSale, $codeCluster, $codeInsee, $mois, $annee, $optionSelect, $etatKO, $category, $childs, $organisationId, $perid, $sellerId, $departement): array
{
$qb = $this->createBaseQueryBuilder($pointOfSale, $codeCluster, $codeInsee, $mois, $annee, $optionSelect, $departement);
$dateField = '';
$dateFieldSql = '';
switch ($optionSelect) {
case 'V':
$dateField = 'p.dateVenteValidB';
$dateFieldSql = 'p.date_vente_valid_b';
break;
case 'R':
$dateField = 'p.dateRacc';
$dateFieldSql = 'p.date_racc';
break;
case 'B':
$dateField = 'p.dateCmdA';
$dateFieldSql = 'p.date_cmd_a';
break;
}
// 3. Calcul du nombre de ventes réalisées jusqu'à aujourd'hui
$qb->select('COUNT(p.id)')
->andWhere("$dateField <= :currentDate")
->setParameter('currentDate', new \DateTime());
if ($category) {
$category = array_filter(
array_map('intval', explode(',', $category)),
fn($id) => $id > 0
);
$qb->andWhere('p.category IN (:categories)')
->setParameter('categories', $category);
}
if (is_array($childs) && count($childs) > 0) {
$qb->andWhere('p.seller IN (:childs)')
->leftJoin('p.seller', 's')
->setParameter('childs', $childs);
}
if ($organisationId) {
$qb->andWhere('p.organisation = :organisationId')
->setParameter('organisationId', $organisationId);
}
if ($perid) {
$qb->andWhere('p.loginVendeurInit = :perid ')
->setParameter('perid', $perid);
}
if ($sellerId) {
$qb->andWhere('p.seller = :sellerId')
->setParameter('sellerId', $sellerId);
}
$ventesRealisees = $qb->getQuery()
->getSingleScalarResult();
// Récupérer la connexion DBAL
$conn = $this->getEntityManager()->getConnection();
// 4. Calcul du nombre de jours de travail effectués jusqu'à aujourd'hui
$sql = "
SELECT COUNT(DISTINCT DAY($dateFieldSql))
FROM production p
WHERE p.point_of_sale_id = :pointOfSale
AND MONTH($dateFieldSql) = :mois
AND YEAR($dateFieldSql) = :annee
AND DAYOFWEEK($dateFieldSql) >= 2 AND DAYOFWEEK($dateFieldSql) <= 6 -- Jours de travail (lundi à vendredi)
AND $dateFieldSql <= CURDATE() -- Jusqu'à aujourd'hui
";
$parameters = [];
if ($category) {
$categories = $category;
if (!empty($categories)) {
$placeholders = [];
foreach ($categories as $index => $catId) {
$placeholder = ":cat$index";
$placeholders[] = $placeholder;
$parameters[$placeholder] = $catId;
}
$sql .= " AND p.category_id IN (" . implode(',', $placeholders) . ")";
}
}
$stmt = $conn->prepare($sql);
// Bind des paramètres
foreach ($parameters as $placeholder => $value) {
$stmt->bindValue($placeholder, $value, \PDO::PARAM_INT);
}
$stmt->bindValue('pointOfSale', $pointOfSale->getId());
$stmt->bindValue('mois', $mois);
$stmt->bindValue('annee', $annee);
$joursTravailEffectues = $stmt->executeQuery()->fetchOne();
// 5. Calcul de la moyenne des ventes par jour
$ventesParJour = $ventesRealisees / (($joursTravailEffectues > 0) ? $joursTravailEffectues : 1);
// 6. Calcul du nombre de jours restants dans le mois
$dateFinMois = new \DateTime();
$dateFinMois->setDate($annee, $mois, 1)->modify('last day of this month'); // Dernier jour du mois
$currentDate = new \DateTime(); // Date actuelle
$joursRestants = 0;
// Si la date de fin du mois est après la date actuelle, on calcule les jours restants
if ($dateFinMois > $currentDate) {
$interval = $currentDate->diff($dateFinMois); // Différence entre la date actuelle et la fin du mois
for ($i = 0; $i <= $interval->days; $i++) {
$jourTemp = (clone $currentDate)->modify("+$i day");
// Vérifier si c'est un jour de semaine (lundi à vendredi)
if ($jourTemp->format('N') < 6) {
$joursRestants++;
}
}
}
// ✅ Ajouter 1 jour si aujourd’hui est le dernier jour du mois
if ($currentDate->format('t') == $currentDate->format('d')) {
$joursRestants++;
}
// 7. Calcul de la projection des ventes pour le reste du mois
#joursRestants +1 car on reçoit les ventes d'aujourd'hui le lendemain
$projectionVentes = ($ventesParJour * ($joursRestants)) + $ventesRealisees;
return [
'ventes_realisees' => $ventesRealisees,
'ventes_par_jour' => $ventesParJour,
'jours_travail_effectues' => $joursTravailEffectues,
'jours_restants' => $joursRestants,
'projection_ventes' => $projectionVentes,
];
}
public function getSalesStats($pointOfSale, $cluster, $annee, $optionSelect, $groupBy, $codeInsee, $byCategory, $childs, $organisationId)
{
$dateField = '';
switch ($optionSelect) {
case 'V':
$dateField = 'p.date_vente_valid_b';
break;
case 'R':
$dateField = 'p.date_racc';
break;
case 'B':
$dateField = 'p.date_cmd_a';
break;
}
$groupByField = '';
$selectField = '';
$range = [];
switch ($groupBy) {
case 'month':
$groupByField = 'MONTH(' . $dateField . ')';
$selectField = 'MONTH(' . $dateField . ') AS cle';
break;
case 'day':
$groupByField = 'DAY(' . $dateField . ')';
$selectField = 'DAY(' . $dateField . ') AS cle';
$range = range(1, 31);
break;
case 'week':
$groupByField = 'WEEK(' . $dateField . ', 1)';
$selectField = 'WEEK(' . $dateField . ', 1) AS cle';
break;
case 'hour':
$groupByField = 'HOUR(' . $dateField . ')';
$selectField = 'HOUR(' . $dateField . ') AS cle';
$range = range(0, 23);
break;
case 'dayOfWeek':
$groupByField = 'DAYOFWEEK(' . $dateField . ')';
$selectField = 'DAYOFWEEK(' . $dateField . ') AS cle';
$range = range(1, 7);
break;
}
// Base SQL
$sql = "SELECT $selectField, COUNT(p.id) AS total_ventes";
if ($byCategory == 1) {
$sql .= ", c.name AS category_name";
}
$sql .= " FROM production p";
if ($byCategory == 1) {
$sql .= " LEFT JOIN category_product c ON c.id = p.category_id";
}
$conditions = [];
$params = [];
if ($pointOfSale !== null) {
$conditions[] = "p.point_of_sale_id = :pointOfSale";
$params['pointOfSale'] = $pointOfSale->getId();
}
if ($annee) {
$conditions[] = "YEAR($dateField) = :annee";
$params['annee'] = $annee;
}
if ($cluster) {
$conditions[] = "p.cluster_id = :clusterId";
$params['clusterId'] = $cluster->getId();
}
if ($codeInsee) {
$conditions[] = "p.code_insee = :codeInsee";
$params['codeInsee'] = $codeInsee;
}
if ($organisationId) {
$conditions[] = 'p.organisation_id = :organisationId';
$params['organisationId'] = $organisationId;
}
if (is_array($childs) && count($childs) > 0) {
$placeholders = [];
foreach ($childs as $i => $child) {
$placeholder = ':child_' . $i;
$placeholders[] = $placeholder;
$params['child_' . $i] = $child;
}
$conditions[] = ' p.seller_id IN (' . implode(', ', $placeholders) . ')';
}
if (!empty($conditions)) {
$sql .= " WHERE " . implode(' AND ', $conditions);
}
// Group by
$sql .= " GROUP BY $groupByField";
if ($byCategory == 1) {
$sql .= ", p.category_id, c.name";
}
$sql .= " ORDER BY $groupByField ASC";
$conn = $this->getEntityManager()->getConnection();
$stmt = $conn->prepare($sql);
$result = $stmt->executeQuery($params)->fetchAllAssociative();
// Format des résultats
$formattedResult = [];
if ($byCategory == 1) {
foreach ($result as $row) {
$cat = $row['category_name'] ?? 'Inconnu';
$cle = $row['cle'];
if (!isset($formattedResult[$cat])) {
$formattedResult[$cat] = ($groupBy !== 'month') ? array_fill_keys($range, 0) : [];
}
$formattedResult[$cat][$cle] = (int) $row['total_ventes'];
}
} else {
if ($groupBy !== 'month') {
foreach ($range as $cle) {
$formattedResult[$cle] = 0;
}
}
foreach ($result as $row) {
$formattedResult[$row['cle']] = (int) $row['total_ventes'];
}
}
return (object) $formattedResult;
}
public function getMissingInseeCodes($annee, $mois, $idCluster, $codeCluster, $pointOfSale, $optionSelect)
{
$entityManager = $this->getEntityManager();
$subQuery = $entityManager->createQueryBuilder()
->select('DISTINCT(p.codeInsee)')
->from('App\Entity\Production', 'p')
->leftJoin('App\Entity\Cluster', 'c', 'WITH', 'c.id = p.cluster')
->where('p.pointOfSale = :pointOfSale')
->andWhere('c.id = :idCluster')
->setParameter('idCluster', $idCluster)
->setParameter('pointOfSale', $pointOfSale);
switch ($optionSelect) {
case 'V':
$subQuery->andWhere('MONTH(p.dateVenteValidB) = :mois')
->andWhere('YEAR(p.dateVenteValidB) = :annee');
break;
case 'R':
$subQuery->andWhere('MONTH(p.dateRacc) = :mois')
->andWhere('YEAR(p.dateRacc) = :annee');
break;
case 'B':
$subQuery->andWhere('MONTH(p.dateCmdA) = :mois')
->andWhere('YEAR(p.dateCmdA) = :annee');
break;
}
$subQuery->setParameter('mois', $mois)
->setParameter('annee', $annee);
$qb = $entityManager->createQueryBuilder();
$qb
->select('a.CODE_CLUSTER, a.COD_INSEE,a.VILL')
->from('App\Entity\NmdAdresse', 'a')
->where('a.CODE_CLUSTER = :codeCluster')
->andWhere($qb->expr()->notIn('a.COD_INSEE', $subQuery->getDQL()))
->groupBy('a.COD_INSEE')
->setParameter('codeCluster', $codeCluster)
->setParameter('idCluster', $idCluster)
->setParameter('pointOfSale', $pointOfSale)
->setParameter('mois', $mois)
->setParameter('annee', $annee);
return $qb->getQuery()->getResult();
}
public function getZeroSalesDays($pointOfSale, $cluster, $codeInsee, $optionSelect)
{
$dateField = '';
switch ($optionSelect) {
case 'V':
$dateField = 'p.date_vente_valid_b';
break;
case 'R':
$dateField = 'p.date_racc';
break;
case 'B':
$dateField = 'p.date_cmd_a';
break;
}
$sql = "SELECT
DATEDIFF(CURRENT_DATE(), MAX($dateField)) AS nombre_jours,
p.cluster_id AS clusterId,
p.code_insee AS codeInsee,
p.ville AS ville
FROM production p
LEFT JOIN category_product cp ON p.category_id = cp.id
WHERE p.point_of_sale_id = :idPointOfSale
AND p.cluster_id = :idCluster";
if (!empty($codeInsee)) {
$sql .= " AND p.code_insee = :codeInsee";
}
$sql .= " GROUP BY p.cluster_id, p.code_insee, p.ville
ORDER BY nombre_jours DESC";
$conn = $this->getEntityManager()->getConnection();
$stmt = $conn->prepare($sql);
$params = [
'idPointOfSale' => $pointOfSale->getId(),
'idCluster' => $cluster->getId()
];
if (!empty($codeInsee)) {
$params['codeInsee'] = $codeInsee;
}
$resultSet = $stmt->executeQuery($params);
return $resultSet->fetchAllAssociative();
}
public function findBySellerAndDate($user, $year, $month, $optionSelect, $cluster, $codeInsee)
{
$qb = $this->createQueryBuilder('p')
->andWhere('p.seller = :user')
->setParameter('user', $user);
if ($cluster) {
$qb->andWhere('p.cluster = :cluster')
->setParameter('cluster', $cluster);
}
if ($codeInsee) {
$qb->andWhere('p.codeInsee = :codeInsee')
->setParameter('codeInsee', $codeInsee);
}
switch ($optionSelect) {
case 'V':
$qb->andWhere('MONTH(p.dateVenteValidB) = :mois')
->andWhere('YEAR(p.dateVenteValidB) = :annee');
break;
case 'R':
$qb->andWhere('MONTH(p.dateRacc) = :mois')
->andWhere('YEAR(p.dateRacc) = :annee');
break;
case 'B':
$qb->andWhere('MONTH(p.dateCmdA) = :mois')
->andWhere('YEAR(p.dateCmdA) = :annee');
break;
}
$qb
->setParameter('mois', $month)
->setParameter('annee', $year);
return $qb->getQuery()
->getResult();
}
public function findBySellerAndDateCategoryStatus($user, $year, $month, $optionSelect, $cluster, $codeInsee)
{
$qb = $this->createQueryBuilder('p')
->leftJoin('p.category', 'c')
->leftJoin('p.etat', 'e')
->andWhere('p.seller = :user')
->setParameter('user', $user);
if ($cluster) {
$qb->andWhere('p.cluster = :cluster')
->setParameter('cluster', $cluster);
}
if ($codeInsee) {
$qb->andWhere('p.codeInsee = :codeInsee')
->setParameter('codeInsee', $codeInsee);
}
switch ($optionSelect) {
case 'V':
$qb->andWhere('MONTH(p.dateVenteValidB) = :mois')
->andWhere('YEAR(p.dateVenteValidB) = :annee');
break;
case 'R':
$qb->andWhere('MONTH(p.dateRacc) = :mois')
->andWhere('YEAR(p.dateRacc) = :annee');
break;
case 'B':
$qb->andWhere('MONTH(p.dateCmdA) = :mois')
->andWhere('YEAR(p.dateCmdA) = :annee');
break;
}
$qb
->setParameter('mois', $month)
->setParameter('annee', $year);
$qb->groupBy('c.id', 'e.id');
return $qb->getQuery()
->getResult();
}
public function getSalesByDay($pointOfSale, $cluster, $mois, $annee, $codeInsee, $optionSelect, $roleUser, $category, $childs)
{
$dateField = '';
switch ($optionSelect) {
case 'V':
$dateField = 'p.date_vente_valid_b';
break;
case 'R':
$dateField = 'p.date_racc';
break;
case 'B':
$dateField = 'p.date_cmd_a';
break;
}
$groupByField = 'DAY(' . $dateField . ')';
$selectField = 'DAY(' . $dateField . ') AS cle';
$range = $this->getDaysInMonth($mois, $annee);
$sql = "
SELECT
$selectField,
COUNT(p.id) AS total_ventes
FROM production p
";
$params = [];
$whereConditions = [];
if ($roleUser != "ROLE_ORGANISATION") {
$whereConditions[] = "p.point_of_sale_id = :pointOfSale";
$params['pointOfSale'] = $pointOfSale->getId();
}
if ($annee) {
$whereConditions[] = "YEAR($dateField) = :annee";
$params['annee'] = $annee;
}
if ($mois) {
$whereConditions[] = "MONTH($dateField) = :mois";
$params['mois'] = $mois;
}
if ($cluster) {
$whereConditions[] = "p.cluster_id = :clusterId";
$params['clusterId'] = $cluster->getId();
}
if ($category) {
// Si $category est une chaîne "1,2,3", transforme en tableau
if (is_string($category)) {
$category = array_filter(array_map('intval', explode(',', $category)));
}
if (count($category) === 1) {
$whereConditions[] = "p.category_id = :category0";
$params['category0'] = $category[0];
} elseif (count($category) > 1) {
$placeholders = [];
foreach ($category as $index => $catId) {
$placeholders[] = ":category$index";
$params["category$index"] = $catId;
}
$whereConditions[] = "p.category_id IN (" . implode(',', $placeholders) . ")";
}
}
if ($codeInsee) {
$whereConditions[] = "p.code_insee = :codeInsee";
$params['codeInsee'] = $codeInsee;
}
if (is_array($childs) && count($childs) > 0) {
$placeholders = [];
foreach ($childs as $i => $child) {
$placeholder = ':child_' . $i;
$placeholders[] = $placeholder;
$params['child_' . $i] = $child;
}
$whereConditions[] = ' p.seller_id IN (' . implode(', ', $placeholders) . ')';
}
if (!empty($whereConditions)) {
$sql .= " WHERE " . implode(' AND ', $whereConditions);
}
$sql .= "
GROUP BY $groupByField
ORDER BY $groupByField ASC
";
$conn = $this->getEntityManager()->getConnection();
$stmt = $conn->prepare($sql);
$result = $stmt->executeQuery($params)->fetchAllAssociative();
// Reformater les résultats sous forme { cle: total_ventes }
$formattedResult = [];
foreach ($range as $cle) {
$formattedResult[$cle] = 0;
}
foreach ($result as $row) {
$formattedResult[$row['cle']] = (int) $row['total_ventes'];
}
return (object) $formattedResult;
}
function getDaysInMonth($month, $year)
{
$daysInMonth = cal_days_in_month(CAL_GREGORIAN, $month, $year);
return range(1, $daysInMonth);
}
public function getProductionsDetailsForOneDay($pointOfSale, $date, $cluster, $codeInsee, $optionSelect, $anneeMois, $etatId, $roleUser, $childs, $organisationId)
{
$dateField = '';
switch ($optionSelect) {
case 'V':
$dateField = 'p.date_vente_valid_b';
break;
case 'R':
$dateField = 'p.date_racc';
break;
case 'B':
$dateField = 'p.date_cmd_a';
break;
}
$sql = "
SELECT
p.*, e.nom AS nom_etat, s.verbatim, s.note_satisfaction
FROM production p
LEFT JOIN satisfaction_client s ON s.production_id = p.id AND s.order_number = p.num_commande
LEFT JOIN etat_production e ON e.id = p.etat_id
";
$whereConditions = [];
$params = [];
if ($anneeMois) {
$whereConditions[] = "MONTH($dateField) = :mois";
$whereConditions[] = "YEAR($dateField) = :annee";
$params['mois'] = (int)explode('-', $anneeMois)[1];
$params['annee'] = (int)explode('-', $anneeMois)[0];
} elseif ($date) {
$whereConditions[] = "DATE($dateField) = :dateJour";
$params['dateJour'] = $date->format('Y-m-d');
}
if ($cluster) {
$whereConditions[] = "p.cluster_id = :clusterId";
$params['clusterId'] = $cluster->getId();
}
if ($etatId) {
$whereConditions[] = "p.etat_id = :etatId";
$params['etatId'] = $etatId;
}
if ($codeInsee) {
$whereConditions[] = "p.code_insee = :codeInsee";
$params['codeInsee'] = $codeInsee;
}
if ($organisationId) {
$whereConditions[] = 'p.organisation_id = :organisationId';
$params['organisationId'] = $organisationId;
} else {
$whereConditions[] = "p.point_of_sale_id = :pointOfSale";
$params['pointOfSale'] = $pointOfSale->getId();
}
if (is_array($childs) && count($childs) > 0) {
$placeholders = [];
foreach ($childs as $i => $child) {
$placeholder = ':child_' . $i;
$placeholders[] = $placeholder;
$params['child_' . $i] = $child;
}
$whereConditions[] = ' p.seller_id IN (' . implode(', ', $placeholders) . ')';
}
if (!empty($whereConditions)) {
$sql .= " WHERE " . implode(' AND ', $whereConditions);
}
$sql .= "
ORDER BY $dateField DESC
";
$conn = $this->getEntityManager()->getConnection();
$stmt = $conn->prepare($sql);
$result = $stmt->executeQuery($params)->fetchAllAssociative();
return $result;
}
public function getSalesForOneDayByHour($pointOfSale, $date, $cluster, $codeInsee, $user, $optionSelect, $roleUser)
{
$dateField = '';
switch ($optionSelect) {
case 'V':
$dateField = 'p.date_vente_valid_b';
break;
case 'R':
$dateField = 'p.date_racc';
break;
case 'B':
$dateField = 'p.date_cmd_a';
break;
}
$groupByField = 'HOUR(' . $dateField . ')';
$selectField = 'HOUR(' . $dateField . ') AS cle';
$range = range(0, 23);
$sql = "
SELECT
$selectField,
COUNT(p.id) AS total_ventes
FROM production p
";
$params = [];
$whereConditions = [];
if ($roleUser != "ROLE_ORGANISATION") {
$whereConditions[] = "p.point_of_sale_id = :pointOfSale";
$params['pointOfSale'] = $pointOfSale->getId();
}
if ($date) {
$whereConditions[] = "DATE($dateField) = :dateJour";
$params['dateJour'] = $date->format('Y-m-d');
}
if ($cluster) {
$whereConditions[] = "p.cluster_id = :clusterId";
$params['clusterId'] = $cluster->getId();
}
if ($codeInsee) {
$whereConditions[] = "p.code_insee = :codeInsee";
$params['codeInsee'] = $codeInsee;
}
if ($user) {
$whereConditions[] = "p.seller_id = :seller_id";
$params['seller_id'] = $user->getId();
}
if (!empty($whereConditions)) {
$sql .= " WHERE " . implode(' AND ', $whereConditions);
}
$sql .= "
GROUP BY $groupByField
ORDER BY $groupByField ASC
";
$conn = $this->getEntityManager()->getConnection();
$stmt = $conn->prepare($sql);
$result = $stmt->executeQuery($params)->fetchAllAssociative();
// Reformater les résultats sous forme { cle: total_ventes }
$formattedResult = [];
foreach ($range as $cle) {
$formattedResult[$cle] = 0;
}
foreach ($result as $row) {
$formattedResult[$row['cle']] = (int) $row['total_ventes'];
}
return (object) $formattedResult;
}
public function getTopAndFlopClusters($pointOfSale, $anneeMois, $optionSelect, $option, $childs, $organisationId)
{
$dateField = '';
switch ($optionSelect) {
case 'V':
$dateField = 'p.date_vente_valid_b';
break;
case 'R':
$dateField = 'p.date_racc';
break;
case 'B':
$dateField = 'p.date_cmd_a';
break;
}
$sql = "
SELECT
c.code_cluster,
c.libelle_cluster,
COUNT(p.id) AS total_ventes
FROM production p
LEFT JOIN cluster c ON c.id = p.cluster_id
";
$params = [];
$whereAdded = false;
if ($pointOfSale) {
$sql .= " WHERE p.point_of_sale_id = :pointOfSale ";
$params['pointOfSale'] = $pointOfSale->getId();
$whereAdded = true;
}
if ($anneeMois) {
$sql .= $whereAdded ? " AND " : " WHERE ";
$sql .= "MONTH($dateField) = :mois AND YEAR($dateField) = :annee ";
[$annee, $mois] = explode('-', $anneeMois);
$params['mois'] = (int)$mois;
$params['annee'] = (int)$annee;
$whereAdded = true;
}
if ($organisationId) {
$sql .= $whereAdded ? " AND " : " WHERE ";
$sql .= "p.organisation_id = :organisationId";
$params['organisationId'] = (int)$organisationId;
$whereAdded = true;
}
if (is_array($childs) && count($childs) > 0) {
$placeholders = [];
foreach ($childs as $i => $child) {
$placeholder = ':child_' . $i;
$placeholders[] = $placeholder;
$params['child_' . $i] = $child;
}
// Ajouter correctement WHERE ou AND selon le contexte
$sql .= $whereAdded ? " AND " : " WHERE ";
$sql .= 'p.seller_id IN (' . implode(', ', $placeholders) . ')';
$whereAdded = true;
}
$sql .= " GROUP BY p.cluster_id, p.point_of_sale_id ";
$sql .= ($option === "top")
? " ORDER BY total_ventes DESC "
: " ORDER BY total_ventes ASC ";
$sql .= " LIMIT 5";
$conn = $this->getEntityManager()->getConnection();
$stmt = $conn->prepare($sql);
$result = $stmt->executeQuery($params)->fetchAllAssociative();
return $result;
}
public function getProductionsRaccoValidRate($pointOfSale, $cluster, $mois, $annee, $codeInsee, $etat, $option, $childs, $organisationId): array
{
$qb = $this->createQueryBuilder('p')
->select('
COUNT(p.id) as total_ventes,
MONTH(p.dateVenteValidB) as mois_validation,
YEAR(p.dateVenteValidB) as annee_validation,
MONTH(p.dateRacc) as mois_racc,
YEAR(p.dateRacc) as annee_racc
')
->where('p.etat = :etat')
->setParameter('etat', $etat)
->leftJoin('p.pointOfSale', 'po');
if ($pointOfSale) {
$qb->andWhere('p.pointOfSale = :pointOfSale')
->setParameter('pointOfSale', $pointOfSale);
}
// Vérifier si un mois est fourni
if ($mois) {
// Récupérer les trois mois précédents avec année
$months = $this->generatePreviousMonths($annee, $mois, 3);
// Extraire les mois et années sous forme de tuples
$moisAnneeArray = array_map(function ($entry) {
return [
'mois' => (int)substr($entry['mois_annee'], 5, 2),
'annee' => (int)substr($entry['mois_annee'], 0, 4)
];
}, $months);
if ($option === "R") {
$qb->andWhere(
'(YEAR(p.dateRacc) = :year1 AND MONTH(p.dateRacc) = :month1)
OR (YEAR(p.dateRacc) = :year2 AND MONTH(p.dateRacc) = :month2)
OR (YEAR(p.dateRacc) = :year3 AND MONTH(p.dateRacc) = :month3)'
)
->setParameter('year1', $moisAnneeArray[0]['annee'])
->setParameter('month1', $moisAnneeArray[0]['mois'])
->setParameter('year2', $moisAnneeArray[1]['annee'])
->setParameter('month2', $moisAnneeArray[1]['mois'])
->setParameter('year3', $moisAnneeArray[2]['annee'])
->setParameter('month3', $moisAnneeArray[2]['mois']);
} elseif ($option === "V") {
$qb->andWhere(
'(YEAR(p.dateVenteValidB) = :year1 AND MONTH(p.dateVenteValidB) = :month1)
OR (YEAR(p.dateVenteValidB) = :year2 AND MONTH(p.dateVenteValidB) = :month2)
OR (YEAR(p.dateVenteValidB) = :year3 AND MONTH(p.dateVenteValidB) = :month3)'
)
->setParameter('year1', $moisAnneeArray[0]['annee'])
->setParameter('month1', $moisAnneeArray[0]['mois'])
->setParameter('year2', $moisAnneeArray[1]['annee'])
->setParameter('month2', $moisAnneeArray[1]['mois'])
->setParameter('year3', $moisAnneeArray[2]['annee'])
->setParameter('month3', $moisAnneeArray[2]['mois']);
}
} else {
// Si aucun mois n'est spécifié, appliquer uniquement le filtre sur l'année
if ($option === "R") {
$qb->andWhere('YEAR(p.dateRacc) = :year')
->setParameter('year', $annee);
} elseif ($option === "V") {
$qb->andWhere('YEAR(p.dateVenteValidB) = :year')
->setParameter('year', $annee);
}
}
// Filtrage supplémentaire
if ($cluster) {
$qb->andWhere('p.cluster = :cluster')
->setParameter('cluster', $cluster);
}
if ($codeInsee) {
$qb->andWhere('p.codeInsee = :codeInsee')
->setParameter('codeInsee', $codeInsee);
}
if (is_array($childs) && count($childs) > 0) {
$qb->andWhere('p.seller IN (:childs)')
->leftJoin('p.seller', 's')
->setParameter('childs', $childs);
}
if ($organisationId) {
$qb->andWhere('p.organisation = :organisationId')
->setParameter('organisationId', $organisationId);
}
$qb->groupBy('mois_validation', 'mois_racc', 'po.id')
->orderBy("DATE_FORMAT(p.dateRacc, '%Y%m')", "DESC") // Formater l'année et le mois en 'YYYYMM'
->addOrderBy("DATE_FORMAT(p.dateVenteValidB, '%Y%m')", "DESC");;
$results = $qb->getQuery()->getArrayResult();
// Formater les mois et trier en PHP
foreach ($results as &$result) {
$result['mois_racc'] = str_pad($result['mois_racc'], 2, '0', STR_PAD_LEFT);
$result['mois_validation'] = str_pad($result['mois_validation'], 2, '0', STR_PAD_LEFT);
}
// Trier les résultats par année et mois (formaté en 'YYYYMM')
usort($results, function ($a, $b) {
$aDate = $a['annee_racc'] . str_pad($a['mois_racc'], 2, '0', STR_PAD_LEFT);
$bDate = $b['annee_racc'] . str_pad($b['mois_racc'], 2, '0', STR_PAD_LEFT);
return strcmp($bDate, $aDate); // Tri décroissant
});
return $results;
}
function generatePreviousMonths($year, $month, $nbMonths)
{
// Crée une DateTime pour le mois et l'année donnés
$date = new \DateTime("$year-$month-01");
// Tableau pour stocker les mois
$months = [];
// Générer les NBRe de mois
for ($i = 0; $i < $nbMonths; $i++) {
// Ajouter le mois formaté au tableau
$months[] = ['mois_annee' => $date->format('Y-m')];
// Subir la date de 1 mois
$date->sub(new \DateInterval('P1M'));
}
// Retourner le tableau avec les mois du plus récent au plus ancien
return $months;
}
public function getTotalVentesObjectivesMangamentByUsers($mois, $annee)
{
$qb = $this->getEntityManager()->createQueryBuilder()
->from('App\Entity\ObjectivesManagement', 'o')
->leftJoin('App\Entity\Production', 'p', Join::WITH, 'p.seller = o.user')
->leftJoin('App\Entity\Cluster', 'c', Join::WITH, 'o.codeCluster = c.codeCluster')
->leftJoin('App\Entity\EtatProduction', 'e', Join::WITH, 'p.etat = e.id')
->leftJoin('App\Entity\User', 'u', Join::WITH, 'o.user = u.id')
// Sélectionner les champs
->addSelect('u.id AS user_id')
->addSelect('o.codeCluster AS codeCluster')
->addSelect('MAX(c.libelleCluster) AS libelleCluster')
->addSelect('e.nom AS etat')
->addSelect('COUNT(p.id) AS totalVente')
->addSelect('o.objectivesVv AS vv')
->addSelect('o.objectivesVr AS vr')
->where('MONTH(p.dateVenteValidB) = :mois')
->andWhere('YEAR(p.dateVenteValidB) = :annee')
->andWhere('YEAR(o.monthAt) = :annee')
->andWhere('MONTH(o.monthAt) = :mois')
->setParameter('mois', $mois)
->setParameter('annee', $annee)
// Regroupement
->groupBy('u.id, o.codeCluster, e.id')
// Ordre
->orderBy('u.id', 'ASC')
->addOrderBy('c.codeCluster', 'ASC')
// Exécuter la requête
->getQuery();
return $qb->getArrayResult();
}
public function searchProductions(?string $searchTerm, ?int $pointOfSaleId)
{
$qb = $this->getEntityManager()->createQueryBuilder();
$qb->select('p AS production', 'n.titulaireEmail AS nomClient')
->from('App\Entity\Production', 'p')
->leftJoin('App\Entity\NmdAppPanier', 'n', 'WITH', 'p.codePanier = n.numPanier')
->where(
$qb->expr()->orX(
$qb->expr()->like('LOWER(p.codePanier)', ':search'),
$qb->expr()->like('LOWER(p.numCommande)', ':search'),
$qb->expr()->like('LOWER(p.ville)', ':search'),
$qb->expr()->like('LOWER(p.streetName)', ':search'),
$qb->expr()->like('LOWER(p.codeInsee)', ':search'),
$qb->expr()->like('LOWER(p.codePostTitu)', ':search'),
$qb->expr()->like('LOWER(n.titulaireEmail)', ':search')
)
)
->andWhere('p.pointOfSale = :pointOfSaleId')
->setParameter('search', $searchTerm ? '%' . strtolower($searchTerm) . '%' : '%%')
->setParameter('pointOfSaleId', $pointOfSaleId);
return $qb->getQuery()->getResult();
}
public function filterDataTotal($option, $code, $place, $category, $pointOfSaleId, $dateDebut, $dateFin)
{
$qb = $this->getEntityManager()->createQueryBuilder();
$qb->select('po.code AS cpv, cat.name AS category_name, COUNT(p.id) AS total_ventes')
->from('App\Entity\Production', 'p')
->leftJoin('p.pointOfSale', 'po')
->leftJoin('p.category', 'cat')
->leftJoin('p.cluster', 'c');
$groupByFields = ['po.id', 'c.id', 'cat.id'];
// Initialiser un tableau pour stocker les champs déjà sélectionnés
$selectedFields = [];
$codeType = null;
// CODE ou PLACE
if ($code) {
// Vérification si $code est un codeCluster ou un codeInsee
if (strpos($code, '-') !== false) {
// Si c'est un codeCluster
if (!in_array('c.libelleCluster AS libelle_cluster', $selectedFields)) {
$qb->addSelect('c.libelleCluster AS libelle_cluster');
$selectedFields[] = 'c.libelleCluster AS libelle_cluster';
}
if (!in_array('p.codeInsee AS cod_insee', $selectedFields)) {
$qb->addSelect('p.codeInsee AS cod_insee');
$selectedFields[] = 'p.codeInsee AS cod_insee';
}
if (!in_array('p.ville AS ville', $selectedFields)) {
$qb->addSelect('p.ville AS ville');
$selectedFields[] = 'p.ville AS ville';
}
$qb->andWhere('c.codeCluster = :codeCluster')
->setParameter('codeCluster', $code);
// Groupement par COD_INSEE pour un codeCluster
$qb->groupBy('p.codeInsee');
$groupByFields[] = 'p.codeInsee';
$codeType = "codeCluster";
} else {
// Si c'est un codeInsee
$qb->andWhere('p.codeInsee = :codeInsee')
->setParameter('codeInsee', $code);
if (!in_array('p.codeInsee AS cod_insee', $selectedFields)) {
$qb->addSelect('p.codeInsee AS cod_insee');
$selectedFields[] = 'p.codeInsee AS cod_insee';
}
if (!in_array('p.ville AS ville', $selectedFields)) {
$qb->addSelect('p.ville AS ville');
$selectedFields[] = 'p.ville AS ville';
}
if (!in_array('p.streetName AS nom_voie', $selectedFields)) {
$qb->addSelect('p.streetName AS nom_voie');
$selectedFields[] = 'p.streetName AS nom_voie';
}
$groupByFields[] = 'p.streetName';
$codeType = "codeInsee";
}
}
if ($place) {
if (strpos(trim($place), 'v:') === 0) {
$qb->andWhere('LOWER(p.ville) = :ville')
->setParameter('ville', strtolower(substr($place, 2)));
if (!in_array('p.streetName AS nom_voie', $selectedFields)) {
$qb->addSelect('p.streetName AS nom_voie');
$selectedFields[] = 'p.streetName AS nom_voie';
}
if (!in_array('p.ville AS ville', $selectedFields)) {
$qb->addSelect('p.ville AS ville');
$selectedFields[] = 'p.ville AS ville';
}
$groupByFields[] = 'p.streetName';
$codeType = "codeInsee";
} elseif (strpos(trim($place), 'c:') === 0) {
if (!in_array('c.libelleCluster AS libelle_cluster', $selectedFields)) {
$qb->addSelect('c.libelleCluster AS libelle_cluster');
$selectedFields[] = 'c.libelleCluster AS libelle_cluster';
}
if (!in_array('p.codeInsee AS cod_insee', $selectedFields)) {
$qb->addSelect('p.codeInsee AS cod_insee');
$selectedFields[] = 'p.codeInsee AS cod_insee';
}
if (!in_array('p.ville AS ville', $selectedFields)) {
$qb->addSelect('p.ville AS ville');
$selectedFields[] = 'p.ville AS ville';
}
$qb->andWhere('LOWER(c.libelleCluster) = :libelleCluster')
->setParameter('libelleCluster', strtolower(substr($place, 2)));
// Groupement par COD_INSEE pour un codeCluster
$groupByFields[] = 'p.codeInsee';
$codeType = "codeCluster";
}
}
switch ($option) {
case 'V':
$qb->andWhere('DATE_FORMAT(p.dateVenteValidB, \'%Y-%m-%d\') >= :debut');
$qb->andWhere('DATE_FORMAT(p.dateVenteValidB, \'%Y-%m-%d\') <= :fin');
break;
case 'R':
$qb->andWhere('DATE_FORMAT(p.dateRacc, \'%Y-%m-%d\') >= :debut');
$qb->andWhere('DATE_FORMAT(p.dateRacc, \'%Y-%m-%d\') <= :fin');
break;
case 'B':
$qb->andWhere('DATE_FORMAT(p.dateCmdA, \'%Y-%m-%d\') >= :debut');
$qb->andWhere('DATE_FORMAT(p.dateCmdA, \'%Y-%m-%d\') <= :fin');
break;
}
$qb->setParameter('debut', $dateDebut)
->setParameter('fin', $dateFin);
if ($category) {
$qb->andWhere('LOWER(cat.name) = :category')
->setParameter('category', strtolower($category));
}
if ($pointOfSaleId) {
$qb->andWhere('p.pointOfSale = :pointOfSaleId')
->setParameter('pointOfSaleId', $pointOfSaleId);
}
$qb->groupBy(
implode(', ', $groupByFields)
);
// Trier par total_ventes
$qb->orderBy('total_ventes', 'DESC');
// Exécuter la requête et retourner les résultats
$results = $qb->getQuery()->getArrayResult();
// Ajouter codeType dans les résultats
foreach ($results as &$result) {
if ($codeType) {
$result['codeType'] = $codeType;
}
}
// Retourner les résultats
return $results;
}
public function filterDataDetails($option, $code, $place, $category, $pointOfSaleId, $dateDebut, $dateFin)
{
$qb = $this->getEntityManager()->createQueryBuilder();
$qb->select('p')
->from('App\Entity\Production', 'p')
->leftJoin('p.pointOfSale', 'po')
->leftJoin('p.category', 'cat')
->leftJoin('p.cluster', 'c')
;
$groupByFields = ['po.id', 'c.id', 'cat.id'];
//CODE ou PLACE
if ($code) {
// Vérification si $code est un codeCluster ou un codeInsee
if (strpos($code, '-') !== false) {
// Si c'est un codeCluster
$qb
->andWhere('c.codeCluster = :codeCluster')
->setParameter('codeCluster', $code);
// Groupement par COD_INSEE pour un codeCluster
$qb->groupBy('p.codeInsee');
$groupByFields[] = 'p.codeInsee';
$codeType = "codeCluster";
} else {
// Si c'est un codeInsee
$qb->andWhere('p.codeInsee = :codeInsee')
->setParameter('codeInsee', $code);
$groupByFields[] = 'p.streetName';
$codeType = "codeInsee";
}
}
if ($place) {
if (strpos($place, 'v:') === 0) {
$qb->andWhere('LOWER(p.ville) = :ville')
->setParameter('ville', strtolower(substr($place, 2)));
$groupByFields[] = 'p.streetName';
$codeType = "codeInsee";
} elseif (strpos($place, 'c:') === 0) {
$qb
->andWhere('LOWER(c.libelleCluster) = :libelleCluster')
->setParameter('libelleCluster', strtolower(substr($place, 2)));
// Groupement par COD_INSEE pour un codeCluster
$groupByFields[] = 'p.codeInsee';
$codeType = "codeCluster";
}
}
switch ($option) {
case 'V':
$qb->andWhere('DATE_FORMAT(p.dateVenteValidB, \'%Y-%m-%d\') >= :debut');
$qb->andWhere('DATE_FORMAT(p.dateVenteValidB, \'%Y-%m-%d\') <= :fin');
break;
case 'R':
$qb->andWhere('DATE_FORMAT(p.dateRacc, \'%Y-%m-%d\') >= :debut');
$qb->andWhere('DATE_FORMAT(p.dateRacc, \'%Y-%m-%d\') <= :fin');
break;
case 'B':
$qb->andWhere('DATE_FORMAT(p.dateCmdA, \'%Y-%m-%d\') >= :debut');
$qb->andWhere('DATE_FORMAT(p.dateCmdA, \'%Y-%m-%d\') <= :fin');
break;
}
$qb->setParameter('debut', $dateDebut)
->setParameter('fin', $dateFin);
if ($category) {
$qb->andWhere('LOWER(cat.name) = :category')
->setParameter('category', strtolower($category));
}
if ($pointOfSaleId) {
$qb->andWhere('p.pointOfSale = :pointOfSaleId')
->setParameter('pointOfSaleId', $pointOfSaleId);
}
$qb->groupBy(
implode(', ', $groupByFields)
);
// Exécuter la requête et retourner les résultats
$results = $qb->getQuery()->getArrayResult();
return $results;
}
public function getProductionsUsersCategoriesByMonth($pointOfSale): string
{
$sql = "
SELECT CONCAT('{',
GROUP_CONCAT(
'\"', mois, '\": {', days_data, '}'
SEPARATOR ','
),
'}') AS json_result
FROM (
SELECT mois,
GROUP_CONCAT(
'\"', jour, '\": {', seller_data, '}'
SEPARATOR ','
) AS days_data
FROM (
SELECT mois, jour,
GROUP_CONCAT(
'\"', seller_id, ' - ', seller_name, '\": {', category_data, '}'
SEPARATOR ','
) AS seller_data
FROM (
SELECT mois, jour, seller_id, seller_name,
GROUP_CONCAT(
'\"', category_name, '\": {', product_data, '}'
SEPARATOR ','
) AS category_data
FROM (
SELECT mois, jour, seller_id, seller_name, category_name,
GROUP_CONCAT(
'\"', product_name, '\": ', total_lignes
SEPARATOR ','
) AS product_data
FROM (
SELECT
DATE_FORMAT(d.date, '%Y-%m') AS mois,
DATE_FORMAT(d.date, '%Y-%m-%d') AS jour,
d.seller_id,
CONCAT(u.nom, ' ', u.prenom) AS seller_name,
c.name AS category_name,
p.name AS product_name,
COUNT(*) AS total_lignes
FROM declarative d
JOIN product p ON d.product_id = p.id
JOIN category_product c ON p.category_id = c.id
JOIN user u ON d.seller_id = u.id
WHERE u.point_of_sale_id = :pointOfSaleId
GROUP BY mois, jour, seller_id, seller_name, category_name, product_name
) AS products_grouped
GROUP BY mois, jour, seller_id, seller_name, category_name
) AS categories_grouped
GROUP BY mois, jour, seller_id, seller_name
) AS sellers_grouped
GROUP BY mois, jour
) AS days_grouped
GROUP BY mois
) AS final_json;
";
$conn = $this->getEntityManager()->getConnection();
$stmt = $conn->prepare($sql);
$stmt->bindValue('pointOfSaleId', $pointOfSale->getId());
$result = $stmt->executeQuery()->fetchOne();
return $result ?: '{}';
}
public function getProductionsByCpv($pointOfSaleId, $codeCluster, $codeInsee, $optionSelect, $debut, $fin, $category, $etatId, $organisationId)
{
$qb = $this->createQueryBuilder('p')
->leftJoin('p.pointOfSale', 'ps')
->leftJoin('p.cluster', 'c')
->select('
ps.id AS pointOfSaleId,
ps.code AS pointOfSaleCode,
ps.name AS pointOfSaleName,
c.codeCluster AS codeCluster,
c.libelleCluster AS libelleCluster,
p.codeInsee AS codeInsee,
p.ville AS ville,
COUNT(p.id) AS total_ventes
');
if ($category) {
$category = array_filter(
array_map('intval', explode(',', $category)),
fn($id) => $id > 0
);
$qb->andWhere('p.category IN (:categories)')
->setParameter('categories', $category);
}
if ($etatId !== null) {
$qb->andWhere('p.etat = :etatId')
->setParameter('etatId', $etatId);
}
if ($pointOfSaleId !== null) {
$qb->andWhere('p.pointOfSale = :pointOfSaleId')
->setParameter('pointOfSaleId', $pointOfSaleId);
}
if ($codeCluster !== null) {
$qb->andWhere('c.codeCluster = :codeCluster')
->setParameter('codeCluster', $codeCluster);
}
if ($codeInsee !== null) {
$qb->andWhere('p.codeInsee = :codeInsee')
->setParameter('codeInsee', $codeInsee);
}
if ($organisationId !== null) {
$qb
->andWhere('p.organisation = :organisationId')
->andWhere('ps.organisation = :organisationId')
->setParameter('organisationId', $organisationId);
}
$qb->groupBy('ps.id, c.codeCluster, p.codeInsee');
if ($optionSelect && $debut && $fin) {
switch ($optionSelect) {
case 'V':
$qb->andWhere('DATE_FORMAT(p.dateVenteValidB, \'%Y-%m-%d\') >= :debut');
$qb->andWhere('DATE_FORMAT(p.dateVenteValidB, \'%Y-%m-%d\') <= :fin');
break;
case 'R':
$qb->andWhere('DATE_FORMAT(p.dateRacc, \'%Y-%m-%d\') >= :debut');
$qb->andWhere('DATE_FORMAT(p.dateRacc, \'%Y-%m-%d\') <= :fin');
break;
case 'B':
$qb->andWhere('DATE_FORMAT(p.dateCmdA, \'%Y-%m-%d\') >= :debut');
$qb->andWhere('DATE_FORMAT(p.dateCmdA, \'%Y-%m-%d\') <= :fin');
break;
}
$qb->setParameter('debut', $debut->format('Y-m-d'))
->setParameter('fin', $fin->format('Y-m-d'));
}
$results = $qb->getQuery()->getArrayResult();
return $this->structureResults($results);
}
private function structureResults(array $rows): array
{
$final = [];
foreach ($rows as $row) {
$psId = $row['pointOfSaleId'];
$psCode = $row['pointOfSaleCode'];
$psName = $row['pointOfSaleName'];
$clusterCode = $row['codeCluster'];
$insee = $row['codeInsee'];
if (!isset($final[$psCode])) {
$final[$psCode] = [
'pointOfSaleId' => $psId,
'cpv' => $psCode,
'cpv_name' => $psName,
'total_ventes' => 0,
'clusters' => []
];
}
if (!isset($final[$psCode]['clusters'][$clusterCode])) {
$final[$psCode]['clusters'][$clusterCode] = [
'code_cluster' => $clusterCode,
'libelle_cluster' => $row['libelleCluster'],
'total_ventes' => 0,
'villes' => []
];
}
$final[$psCode]['total_ventes'] += (int) $row['total_ventes'];
$final[$psCode]['clusters'][$clusterCode]['total_ventes'] += (int)$row['total_ventes'];
$final[$psCode]['clusters'][$clusterCode]['villes'][] = [
'code_insee' => $insee,
'ville' => $row['ville'],
'total_ventes' => (int)$row['total_ventes']
];
}
// Convert associative arrays to indexed arrays for JSON-friendly output
return array_values(array_map(function ($ps) {
$ps['clusters'] = array_values($ps['clusters']);
return $ps;
}, $final));
}
public function getFixeDetails($pointOfSale, $cluster, $codeInsee, $optionSelect, $dateDebut, $dateFin, $childs, $organisationId)
{
$qb = $this->getEntityManager()->createQueryBuilder();
$qb->select('p')
->from('App\Entity\Production', 'p');
if ($pointOfSale !== null) {
$qb
->andWhere('p.pointOfSale = :pointOfSale')
->setParameter('pointOfSale', $pointOfSale);
}
switch ($optionSelect) {
case 'V':
$qb->andWhere('DATE_FORMAT(p.dateVenteValidB, \'%Y-%m-%d\') >= :debut');
$qb->andWhere('DATE_FORMAT(p.dateVenteValidB, \'%Y-%m-%d\') <= :fin');
break;
case 'R':
$qb->andWhere('DATE_FORMAT(p.dateRacc, \'%Y-%m-%d\') >= :debut');
$qb->andWhere('DATE_FORMAT(p.dateRacc, \'%Y-%m-%d\') <= :fin');
break;
case 'B':
$qb->andWhere('DATE_FORMAT(p.dateCmdA, \'%Y-%m-%d\') >= :debut');
$qb->andWhere('DATE_FORMAT(p.dateCmdA, \'%Y-%m-%d\') <= :fin');
break;
}
$qb->setParameter('debut', $dateDebut)
->setParameter('fin', $dateFin);
if ($cluster) {
$qb->andWhere('p.cluster = :cluster')
->setParameter('cluster', $cluster);
}
if ($codeInsee) {
$qb->andWhere('p.codeInsee = :codeInsee')
->setParameter('codeInsee', $codeInsee);
}
if ($organisationId) {
$qb->andWhere('p.organisation = :organisationId')
->setParameter('organisationId', $organisationId);
}
if (is_array($childs) && count($childs) > 0) {
$qb->andWhere('p.seller IN (:childs)')
->leftJoin('p.seller', 's')
->setParameter('childs', $childs);
}
// $qb->andWhere('p.mobileAutre IS NOT NULL OR p.mobileChainage IS NOT NULL');
$qb->andWhere('p.fixeChainage IS NOT NULL ');
$qb->andWhere('p.category IN (31,32,33)');
$qb->orderBy('p.mobileAutre', 'DESC');
$qb->orderBy('p.mobileChainage', 'ASC');
return $qb->getQuery()->getArrayResult();
}
public function getProductionsGroupedByDateAnnulation($pointOfSale, $cluster, $codeInsee, $optionSelect, $dateDebut, $dateFin)
{
$qb = $this->getEntityManager()->createQueryBuilder();
$qb->select('p')
->from('App\Entity\Production', 'p')
->where('p.pointOfSale = :pointOfSale')
->andWhere('p.dateResiliation IS NOT NULL') // on ne veut que les résiliées
->setParameter('pointOfSale', $pointOfSale);
switch ($optionSelect) {
case 'V':
$qb->andWhere('DATE_FORMAT(p.dateVenteValidB, \'%Y-%m-%d\') >= :debut');
$qb->andWhere('DATE_FORMAT(p.dateVenteValidB, \'%Y-%m-%d\') <= :fin');
break;
case 'R':
$qb->andWhere('DATE_FORMAT(p.dateRacc, \'%Y-%m-%d\') >= :debut');
$qb->andWhere('DATE_FORMAT(p.dateRacc, \'%Y-%m-%d\') <= :fin');
break;
case 'B':
$qb->andWhere('DATE_FORMAT(p.dateCmdA, \'%Y-%m-%d\') >= :debut');
$qb->andWhere('DATE_FORMAT(p.dateCmdA, \'%Y-%m-%d\') <= :fin');
break;
}
$qb->setParameter('debut', $dateDebut)
->setParameter('fin', $dateFin);
if ($cluster) {
$qb->andWhere('p.cluster = :cluster')
->setParameter('cluster', $cluster);
}
if ($codeInsee) {
$qb->andWhere('p.codeInsee = :codeInsee')
->setParameter('codeInsee', $codeInsee);
}
$productions = $qb->getQuery()->getArrayResult();
// Regroupement manuel par date d'annulation
$grouped = [];
foreach ($productions as $prod) {
$date = $prod['dateResiliation']->format('Y-m-d');
if (!isset($grouped[$date])) {
$grouped[$date] = [
'date_resiliation' => $date,
'total_lignes' => 0,
'details' => []
];
}
$grouped[$date]['total_lignes'] += 1;
$grouped[$date]['details'][] = $prod;
}
return array_values($grouped); // reset des clés numériques
}
public function getProductionsAnalyticsTitulaireVentes($pointOfSale, $codeCluster, $codeInsee, $mois, $annee, $optionSelect, $etatKO, $category, $option, $byWeek, $childs, $organisationId, $perid, $sellerId, $departement): array
{
$qb = $this->createBaseQueryBuilder2($pointOfSale, $codeCluster, $codeInsee, $mois, $annee, $optionSelect, $departement)
->select('COUNT(DISTINCT p.titulaireEmail) as nombre_titulaire_email');
if ($option == "chainage") {
$qb->andWhere('p.fixeChainage IS NOT NULL ');
$qb->andWhere('p.category IN (31,32,33)');
} else {
$qb->andWhere('p.fixeChainage IS NOT NULL OR p.fixeAutre IS NOT NULL');
$qb->andWhere('p.category IN (31,32,33)');
}
if (is_array($childs) && count($childs) > 0) {
$qb->andWhere('p.seller IN (:childs)')
->leftJoin('p.seller', 's')
->setParameter('childs', $childs);
}
if ($organisationId) {
$qb->andWhere('p.organisation = :organisationId')
->setParameter('organisationId', $organisationId);
}
if ($perid) {
$qb->andWhere('p.loginVendeurInit = :perid ')
->setParameter('perid', $perid);
}
if ($sellerId) {
$qb->andWhere('p.seller = :sellerId')
->setParameter('sellerId', $sellerId);
}
return $qb->getQuery()->getArrayResult();
}
public function get4PCByWeek(
$pointOfSale,
$codeCluster,
$codeInsee,
$mois,
$annee,
$optionSelect,
$etatKO,
$category,
$option,
$byWeek,
$childs,
$organisationId,
$perid,
$sellerId,
$departement
): array {
$conn = $this->getEntityManager()->getConnection();
$where = [];
$params = [];
// pointOfSale optionnel
if ($pointOfSale !== null) {
$where[] = 'p.point_of_sale_id = :pointOfSale';
$params['pointOfSale'] = is_object($pointOfSale) ? $pointOfSale->getId() : $pointOfSale;
}
// codeCluster optionnel
if ($codeCluster !== null) {
$where[] = 'c.code_cluster = :codeCluster';
$params['codeCluster'] = $codeCluster;
}
if ($departement) {
$where[] = 'c.code_cluster LIKE :departement';
$params["departement"] = $departement . '-%';
}
if ($codeInsee !== null) {
$where[] = 'p.code_insee = :codeInsee';
$params['codeInsee'] = $codeInsee;
}
if ($organisationId) {
$where[] = 'p.organisation_id = :organisationId';
$params['organisationId'] = $organisationId;
}
if ($perid) {
$where[] = 'p.login_vendeur_init = :perid';
$params['perid'] = $perid;
}
if ($sellerId) {
$where[] = 'p.seller_id = :sellerId';
$params['sellerId'] = $sellerId;
}
// mois optionnel
if ($mois !== null) {
$where[] = 'MONTH(p.date_cmd_a) = :mois';
$params['mois'] = $mois;
}
// annee optionnel
if ($annee !== null) {
$where[] = 'YEAR(p.date_cmd_a) = :annee';
$params['annee'] = $annee;
}
if (is_array($childs) && count($childs) > 0) {
$placeholders = [];
foreach ($childs as $i => $child) {
$placeholder = ':child_' . $i;
$placeholders[] = $placeholder;
$params['child_' . $i] = $child;
}
$where[] = ' p.seller_id IN (' . implode(', ', $placeholders) . ')';
}
// Si aucune condition ajoutée, on peut ne rien mettre dans WHERE ou ajouter "1=1"
if (empty($where)) {
$where[] = '1=1'; // condition toujours vraie pour éviter erreur SQL
}
$select = 'COUNT(DISTINCT p.titulaire_email) AS total';
$groupBy = '';
if ($option === 'chainage') {
$where[] = 'p.fixe_chainage IS NOT NULL';
if (!empty($category)) {
$categoryArray = array_filter(
array_map('intval', explode(',', $category)),
fn($id) => $id > 0
);
if (!empty($categoryArray)) {
$placeholders = [];
foreach ($categoryArray as $k => $catId) {
$key = 'cat' . $k;
$placeholders[] = ':' . $key;
$params[$key] = $catId;
}
$where[] = 'p.category_id IN (' . implode(',', $placeholders) . ')';
}
}
if ($byWeek == true) {
$select .= ', WEEK(p.date_cmd_a,3) AS semaine';
$groupBy = 'GROUP BY semaine';
}
}
$sql = "
SELECT $select
FROM production p
LEFT JOIN cluster c ON c.id = p.cluster_id
WHERE " . implode(' AND ', $where) . "
$groupBy
";
$stmt = $conn->prepare($sql);
$result = $stmt->executeQuery($params);
return $result->fetchAllAssociative();
}
public function get4PByWeek($pointOfSale, $codeCluster, $codeInsee, $mois, $annee, $optionSelect, $etat, $filtre, $childs, $organisationId, $perid, $sellerId, $departement): array
{
$conn = $this->getEntityManager()->getConnection();
$sql = '
SELECT
COUNT(DISTINCT result.titulaire_email) AS total,
WEEK(result.date_cmd_a, 3) AS semaine
FROM (
-- Partie 1 : Catégorie 32 avec emails en catégorie 1
SELECT p1.titulaire_email, p1.date_cmd_a
FROM production p1
LEFT JOIN cluster c1 ON p1.cluster_id = c1.id
WHERE p1.category_id = :cat1
AND p1.point_of_sale_id = :pointOfSale
AND MONTH(p1.date_cmd_a) = :mois
AND YEAR(p1.date_cmd_a) = :annee
AND p1.titulaire_email IN (
SELECT DISTINCT p_sub1.titulaire_email
FROM production p_sub1
WHERE p_sub1.category_id = 1
AND p_sub1.point_of_sale_id = :pointOfSale
AND MONTH(p_sub1.date_cmd_a) = :mois
AND YEAR(p_sub1.date_cmd_a) = :annee
)
';
$params = [
'pointOfSale' => $pointOfSale->getId(),
'mois' => $mois,
'annee' => $annee,
'cat1' => 32,
'cat2' => 31,
];
if ($codeCluster) {
$sql .= ' AND c1.code_cluster = :codeCluster';
$params['codeCluster'] = $codeCluster;
}
if ($departement) {
$sql .= " AND c1.code_cluster LIKE :departement";
$params["departement"] = $departement . '-%';
}
if ($codeInsee) {
$sql .= ' AND p1.code_insee = :codeInsee';
$params['codeInsee'] = $codeInsee;
}
if ($organisationId) {
$sql .= ' AND p1.organisation_id = :organisationId';
$params['organisationId'] = $organisationId;
}
if ($perid) {
$sql .= ' AND p1.login_vendeur_init = :perid';
$params['perid'] = $perid;
}
if ($sellerId) {
$sql .= ' AND p1.seller_id = :sellerId';
$params['sellerId'] = $sellerId;
}
// Gestion dynamique des placeholders pour p1.seller_id IN (...)
if (is_array($childs) && count($childs) > 0) {
$placeholdersP1 = [];
foreach ($childs as $i => $child) {
$key = 'child_p1_' . $i;
$placeholdersP1[] = ':' . $key;
$params[$key] = $child;
}
$sql .= ' AND p1.seller_id IN (' . implode(', ', $placeholdersP1) . ')';
}
$sql .= '
UNION
-- Partie 2 : Catégorie 31 avec emails en catégorie 1 ou 3
SELECT p2.titulaire_email, p2.date_cmd_a
FROM production p2
LEFT JOIN cluster c2 ON p2.cluster_id = c2.id
WHERE p2.category_id = :cat2
AND p2.point_of_sale_id = :pointOfSale
AND MONTH(p2.date_cmd_a) = :mois
AND YEAR(p2.date_cmd_a) = :annee
AND p2.titulaire_email IN (
SELECT DISTINCT p_sub2.titulaire_email
FROM production p_sub2
WHERE p_sub2.category_id IN (1, 3)
AND p_sub2.point_of_sale_id = :pointOfSale
AND MONTH(p_sub2.date_cmd_a) = :mois
AND YEAR(p_sub2.date_cmd_a) = :annee
)
';
if ($codeCluster) {
$sql .= ' AND c2.code_cluster = :codeCluster';
// Pas besoin de le rajouter à $params, déjà fait avant
}
if ($departement) {
$sql .= " AND c2.code_cluster LIKE :departement";
}
if ($codeInsee) {
$sql .= ' AND p2.code_insee = :codeInsee';
}
if ($organisationId) {
$sql .= ' AND p2.organisation_id = :organisationId';
}
if ($perid) {
$sql .= ' AND p2.login_vendeur_init = :perid';
}
if ($sellerId) {
$sql .= ' AND p2.seller_id = :sellerId';
}
// Gestion dynamique des placeholders pour p2.seller_id IN (...)
if (is_array($childs) && count($childs) > 0) {
$placeholdersP2 = [];
foreach ($childs as $i => $child) {
$key = 'child_p2_' . $i;
$placeholdersP2[] = ':' . $key;
$params[$key] = $child;
}
$sql .= ' AND p2.seller_id IN (' . implode(', ', $placeholdersP2) . ')';
}
$sql .= '
) AS result
GROUP BY WEEK(result.date_cmd_a, 3)
ORDER BY semaine
';
$stmt = $conn->prepare($sql);
$result = $stmt->executeQuery($params);
return $result->fetchAllAssociative();
}
public function getProductionsAnalyticsTotalVentesByDateResiliationInf30($pointOfSale, $codeCluster, $codeInsee, $mois, $annee, $optionSelect, $etat, $category, $childs, $organisationId, $perid, $sellerId, $departement): array
{
$conn = $this->getEntityManager()->getConnection();
$sql = '
SELECT COUNT(DISTINCT p.id) AS total_vente
FROM production p
LEFT JOIN point_of_sale po ON p.point_of_sale_id = po.id
LEFT JOIN cluster c ON p.cluster_id = c.id
WHERE p.point_of_sale_id = :pointOfSale
AND p.date_resiliation IS NOT NULL
AND p.date_racc IS NOT NULL
AND DATEDIFF(p.date_racc, p.date_resiliation) > -31
AND (p.category_id NOT IN (2, 31, 32, 33,48) OR p.product_id IN(150,262,264,266,334,335,341,344,345,379))
';
$params = [
'pointOfSale' => $pointOfSale->getId(),
'mois' => $mois,
'annee' => $annee,
];
if ($codeCluster) {
$sql .= ' AND c.code_cluster = :codeCluster';
$params['codeCluster'] = $codeCluster;
}
if ($departement) {
$sql .= " AND c.code_cluster LIKE :departement";
$params["departement"] = $departement . '-%';
}
if ($codeInsee) {
$sql .= ' AND p.code_insee = :codeInsee';
$params['codeInsee'] = $codeInsee;
}
if ($organisationId) {
$sql .= ' AND p.organisation_id = :organisationId';
$params['organisationId'] = $organisationId;
}
if ($perid) {
$sql .= ' AND p.login_vendeur_init = :perid';
$params['perid'] = $perid;
}
if ($sellerId) {
$sql .= ' AND p.seller_id = :sellerId';
$params['sellerId'] = $sellerId;
}
if (is_array($childs) && count($childs) > 0) {
$placeholders = [];
foreach ($childs as $i => $child) {
$placeholder = ':child_' . $i;
$placeholders[] = $placeholder;
$params['child_' . $i] = $child;
}
$sql .= ' AND p.seller_id IN (' . implode(', ', $placeholders) . ')';
}
switch ($optionSelect) {
case 'V':
$sql .= ' AND MONTH(p.date_vente_valid_b) = :mois AND YEAR(p.date_vente_valid_b) = :annee';
break;
case 'R':
$sql .= ' AND MONTH(p.date_racc) = :mois AND YEAR(p.date_racc) = :annee';
break;
case 'B':
$sql .= ' AND MONTH(p.date_cmd_a) = :mois AND YEAR(p.date_cmd_a) = :annee';
break;
}
$stmt = $conn->prepare($sql);
$result = $stmt->executeQuery($params);
return $result->fetchAssociative();
}
public function getProductionsAnalyticsTotalVentesByDateResiliationInf30ForChurn($pointOfSale, $codeCluster, $codeInsee, $mois, $annee, $optionSelect, $etat, $category, $childs, $organisationId, $perid, $sellerId, $departement): array
{
$conn = $this->getEntityManager()->getConnection();
$sql = '
SELECT COUNT(DISTINCT p.id) AS total_vente
FROM production p
LEFT JOIN point_of_sale po ON p.point_of_sale_id = po.id
LEFT JOIN cluster c ON p.cluster_id = c.id
WHERE p.point_of_sale_id = :pointOfSale
AND p.date_resiliation IS NOT NULL
AND p.date_racc IS NOT NULL
AND DATEDIFF(p.date_racc, p.date_resiliation) > -31
AND
(
p.category_id IN(1,3)
OR
(
p.category_id IN(31) AND p.product_id IN(150, 262, 264, 266, 334, 335, 341, 344, 345, 379,441,442,443,444)
) )
';
$params = [
'pointOfSale' => $pointOfSale->getId(),
'mois' => $mois,
'annee' => $annee,
];
if ($codeCluster) {
$sql .= ' AND c.code_cluster = :codeCluster';
$params['codeCluster'] = $codeCluster;
}
if ($departement) {
$sql .= " AND c.code_cluster LIKE :departement";
$params["departement"] = $departement . '-%';
}
if ($codeInsee) {
$sql .= ' AND p.code_insee = :codeInsee';
$params['codeInsee'] = $codeInsee;
}
if ($organisationId) {
$sql .= ' AND p.organisation_id = :organisationId';
$params['organisationId'] = $organisationId;
}
if ($perid) {
$sql .= ' AND p.login_vendeur_init = :perid';
$params['perid'] = $perid;
}
if ($sellerId) {
$sql .= ' AND p.seller_id = :sellerId';
$params['sellerId'] = $sellerId;
}
if (is_array($childs) && count($childs) > 0) {
$placeholders = [];
foreach ($childs as $i => $child) {
$placeholder = ':child_' . $i;
$placeholders[] = $placeholder;
$params['child_' . $i] = $child;
}
$sql .= ' AND p.seller_id IN (' . implode(', ', $placeholders) . ')';
}
switch ($optionSelect) {
case 'V':
$sql .= ' AND MONTH(p.date_vente_valid_b) = :mois AND YEAR(p.date_vente_valid_b) = :annee';
break;
case 'R':
$sql .= ' AND MONTH(p.date_racc) = :mois AND YEAR(p.date_racc) = :annee';
break;
case 'B':
$sql .= ' AND MONTH(p.date_cmd_a) = :mois AND YEAR(p.date_cmd_a) = :annee';
break;
}
$stmt = $conn->prepare($sql);
$result = $stmt->executeQuery($params);
return $result->fetchAssociative();
}
public function getProductionsAnalyticsTotalVentesByDateResiliationInf30ForChurn5G($pointOfSale, $codeCluster, $codeInsee, $mois, $annee, $optionSelect, $etat, $category, $childs, $organisationId, $perid, $sellerId, $departement): array
{
$conn = $this->getEntityManager()->getConnection();
$sql = '
SELECT COUNT(DISTINCT p.id) AS total_vente
FROM production p
LEFT JOIN point_of_sale po ON p.point_of_sale_id = po.id
LEFT JOIN cluster c ON p.cluster_id = c.id
WHERE p.point_of_sale_id = :pointOfSale
AND p.date_resiliation IS NOT NULL
AND p.date_racc IS NOT NULL
AND DATEDIFF(p.date_racc, p.date_resiliation) > -31
AND
p.product_id IN(150, 262, 264, 266, 334, 335, 341, 344, 345, 379,441,442,443,444)
';
$params = [
'pointOfSale' => $pointOfSale->getId(),
'mois' => $mois,
'annee' => $annee,
];
if ($codeCluster) {
$sql .= ' AND c.code_cluster = :codeCluster';
$params['codeCluster'] = $codeCluster;
}
if ($departement) {
$sql .= " AND c.code_cluster LIKE :departement";
$params["departement"] = $departement . '-%';
}
if ($codeInsee) {
$sql .= ' AND p.code_insee = :codeInsee';
$params['codeInsee'] = $codeInsee;
}
if ($organisationId) {
$sql .= ' AND p.organisation_id = :organisationId';
$params['organisationId'] = $organisationId;
}
if ($perid) {
$sql .= ' AND p.login_vendeur_init = :perid';
$params['perid'] = $perid;
}
if ($sellerId) {
$sql .= ' AND p.seller_id = :sellerId';
$params['sellerId'] = $sellerId;
}
if (is_array($childs) && count($childs) > 0) {
$placeholders = [];
foreach ($childs as $i => $child) {
$placeholder = ':child_' . $i;
$placeholders[] = $placeholder;
$params['child_' . $i] = $child;
}
$sql .= ' AND p.seller_id IN (' . implode(', ', $placeholders) . ')';
}
switch ($optionSelect) {
case 'V':
$sql .= ' AND MONTH(p.date_vente_valid_b) = :mois AND YEAR(p.date_vente_valid_b) = :annee';
break;
case 'R':
$sql .= ' AND MONTH(p.date_racc) = :mois AND YEAR(p.date_racc) = :annee';
break;
case 'B':
$sql .= ' AND MONTH(p.date_cmd_a) = :mois AND YEAR(p.date_cmd_a) = :annee';
break;
}
$stmt = $conn->prepare($sql);
$result = $stmt->executeQuery($params);
return $result->fetchAssociative();
}
public function getProductionsAnalyticsTotalVentesByDateResiliationInf30Mobile($pointOfSale, $codeCluster, $codeInsee, $mois, $annee, $optionSelect, $etat, $category, $childs, $organisationId, $perid, $sellerId, $departement): array
{
$conn = $this->getEntityManager()->getConnection();
$sql = '
SELECT COUNT(DISTINCT p.id) AS total_vente
FROM production p
LEFT JOIN point_of_sale po ON p.point_of_sale_id = po.id
LEFT JOIN cluster c ON p.cluster_id = c.id
WHERE p.point_of_sale_id = :pointOfSale
AND p.date_resiliation IS NOT NULL
AND p.date_racc IS NOT NULL
AND DATEDIFF(p.date_racc , p.date_resiliation) > -31
AND p.category_id IN(31,32,33,48)
';
$params = [
'pointOfSale' => $pointOfSale->getId(),
'mois' => $mois,
'annee' => $annee
];
if ($etat === "Raccorde_mobile") {
$sql .= ' AND p.product_id NOT IN (150, 262, 264, 266, 334, 335, 341, 344, 345, 379,441,442,443,444)';
}
if ($codeCluster) {
$sql .= ' AND c.code_cluster = :codeCluster';
$params['codeCluster'] = $codeCluster;
}
if ($departement) {
$sql .= " AND c.code_cluster LIKE :departement";
$params["departement"] = $departement . '-%';
}
if ($codeInsee) {
$sql .= ' AND p.code_insee = :codeInsee';
$params['codeInsee'] = $codeInsee;
}
if ($organisationId) {
$sql .= ' AND p.organisation_id = :organisationId';
$params['organisationId'] = $organisationId;
}
if ($perid) {
$sql .= ' AND p.login_vendeur_init = :perid';
$params['perid'] = $perid;
}
if ($sellerId) {
$sql .= ' AND p.seller_id = :sellerId';
$params['sellerId'] = $sellerId;
}
if (is_array($childs) && count($childs) > 0) {
$placeholders = [];
foreach ($childs as $i => $child) {
$placeholder = ':child_' . $i;
$placeholders[] = $placeholder;
$params['child_' . $i] = $child;
}
$sql .= ' AND p.seller_id IN (' . implode(', ', $placeholders) . ')';
}
// if ($category) {
// $sql .= " AND p.category_id = :category";
// $params['category'] = $category;
// }
// // Ajout du filtre date selon $optionSelect
switch ($optionSelect) {
case 'V': // Vente
$sql .= ' AND MONTH(p.date_vente_valid_b) = :mois AND YEAR(p.date_vente_valid_b) = :annee';
break;
case 'R': // Raccordement
$sql .= ' AND MONTH(p.date_racc) = :mois AND YEAR(p.date_racc) = :annee';
break;
case 'B': // Commande
$sql .= ' AND MONTH(p.date_cmd_a) = :mois AND YEAR(p.date_cmd_a) = :annee';
break;
}
$stmt = $conn->prepare($sql);
$result = $stmt->executeQuery($params);
return $result->fetchAssociative();
}
public function getProductionsAnalyticsTotalMobile($pointOfSale, $codeCluster, $mois, $annee, $optionSelect, $filtre): array
{
$conn = $this->getEntityManager()->getConnection();
$sql = '
SELECT COUNT(DISTINCT p.id) AS total_vente
FROM production p
LEFT JOIN point_of_sale po ON p.point_of_sale_id = po.id
LEFT JOIN cluster c ON p.cluster_id = c.id
WHERE p.point_of_sale_id = :pointOfSale
AND p.category_id IN (SELECT DISTINCT(id) FROM category_product WHERE parent_category_id =4)
';
$params = [
'pointOfSale' => $pointOfSale->getId(),
'mois' => $mois,
'annee' => $annee,
];
if ($codeCluster) {
$sql .= ' AND c.code_cluster = :codeCluster';
$params['codeCluster'] = $codeCluster;
}
if ($filtre == "oui") {
$sql .= "
AND (
p.fixe_chainage IS NOT NULL
OR p.fixe_autre IS NOT NULL
)
";
}
$sql .= ' AND MONTH(p.date_cmd_a) = :mois AND YEAR(p.date_cmd_a) = :annee';
$stmt = $conn->prepare($sql);
$result = $stmt->executeQuery($params);
return $result->fetchAssociative();
}
public function getProductionsAnalyticsTotalMobileV2($pointOfSale, $codeCluster, $codeInsee, $mois, $annee, $optionSelect, $etat, $filtre, $childs, $organisationId, $perid, $sellerId, $departement): array
{
$conn = $this->getEntityManager()->getConnection();
$sql = '
SELECT COUNT(DISTINCT p.titulaire_email) AS total_vente
FROM production p
LEFT JOIN point_of_sale po ON p.point_of_sale_id = po.id
LEFT JOIN cluster c ON p.cluster_id = c.id
WHERE p.point_of_sale_id = :pointOfSale
AND p.category_id IN (SELECT DISTINCT(id) FROM category_product WHERE parent_category_id =4)
AND (
p.fixe_chainage IS NOT NULL
OR p.fixe_autre IS NOT NULL
)
';
$params = [
'pointOfSale' => $pointOfSale->getId(),
'mois' => $mois,
'annee' => $annee
];
if (is_array($childs) && count($childs) > 0) {
$placeholders = [];
foreach ($childs as $i => $child) {
$placeholder = ':child_' . $i;
$placeholders[] = $placeholder;
$params['child_' . $i] = $child;
}
$sql .= ' AND p.seller_id IN (' . implode(', ', $placeholders) . ')';
}
if ($codeCluster) {
$sql .= ' AND c.code_cluster = :codeCluster';
$params['codeCluster'] = $codeCluster;
}
if ($departement) {
$sql .= " AND c.code_cluster LIKE :departement";
$params["departement"] = $departement . '-%';
}
if ($codeInsee) {
$sql .= ' AND p.code_insee = :codeInsee';
$params['codeInsee'] = $codeInsee;
}
if ($organisationId) {
$sql .= ' AND p.organisation_id = :organisationId';
$params['organisationId'] = $organisationId;
}
if ($perid) {
$sql .= ' AND p.login_vendeur_init = :perid';
$params['perid'] = $perid;
}
if ($sellerId) {
$sql .= ' AND p.seller_id = :sellerId';
$params['sellerId'] = $sellerId;
}
// // Ajout du filtre date selon $optionSelect
switch ($optionSelect) {
case 'V': // Vente
$sql .= ' AND MONTH(p.date_vente_valid_b) = :mois AND YEAR(p.date_vente_valid_b) = :annee';
break;
case 'R': // Raccordement
$sql .= ' AND MONTH(p.date_racc) = :mois AND YEAR(p.date_racc) = :annee';
break;
case 'B': // Commande
$sql .= ' AND MONTH(p.date_cmd_a) = :mois AND YEAR(p.date_cmd_a) = :annee';
break;
}
$stmt = $conn->prepare($sql);
$result = $stmt->executeQuery($params);
return $result->fetchAssociative();
}
public function getProductionsAnalyticsTotalMobileChainage($pointOfSale, $codeCluster, $codeInsee, $mois, $annee, $optionSelect, $etat, $filtre, $childs, $organisationId, $perid, $sellerId, $departement): array
{
$conn = $this->getEntityManager()->getConnection();
$sql = '
SELECT COUNT(DISTINCT p.titulaire_email) AS total_vente
FROM production p
LEFT JOIN point_of_sale po ON p.point_of_sale_id = po.id
LEFT JOIN cluster c ON p.cluster_id = c.id
WHERE p.point_of_sale_id = :pointOfSale
AND p.category_id IN (SELECT DISTINCT(id) FROM category_product WHERE parent_category_id =4)
AND (
p.fixe_chainage IS NOT NULL
)
';
$params = [
'pointOfSale' => $pointOfSale->getId(),
'mois' => $mois,
'annee' => $annee
];
if ($codeCluster) {
$sql .= ' AND c.code_cluster = :codeCluster';
$params['codeCluster'] = $codeCluster;
}
if ($departement) {
$sql .= " AND c.code_cluster LIKE :departement";
$params["departement"] = $departement . '-%';
}
if ($codeInsee) {
$sql .= ' AND p.code_insee = :codeInsee';
$params['codeInsee'] = $codeInsee;
}
if ($organisationId) {
$sql .= ' AND p.organisation_id = :organisationId';
$params['organisationId'] = $organisationId;
}
if ($perid) {
$sql .= ' AND p.login_vendeur_init = :perid';
$params['perid'] = $perid;
}
if ($sellerId) {
$sql .= ' AND p.seller_id = :sellerId';
$params['sellerId'] = $sellerId;
}
if (is_array($childs) && count($childs) > 0) {
$placeholders = [];
foreach ($childs as $i => $child) {
$placeholder = ':child_' . $i;
$placeholders[] = $placeholder;
$params['child_' . $i] = $child;
}
$sql .= ' AND p.seller_id IN (' . implode(', ', $placeholders) . ')';
}
// // Ajout du filtre date selon $optionSelect
switch ($optionSelect) {
case 'V': // Vente
$sql .= ' AND MONTH(p.date_vente_valid_b) = :mois AND YEAR(p.date_vente_valid_b) = :annee';
break;
case 'R': // Raccordement
$sql .= ' AND MONTH(p.date_racc) = :mois AND YEAR(p.date_racc) = :annee';
break;
case 'B': // Commande
$sql .= ' AND MONTH(p.date_cmd_a) = :mois AND YEAR(p.date_cmd_a) = :annee';
break;
}
$stmt = $conn->prepare($sql);
$result = $stmt->executeQuery($params);
return $result->fetchAssociative();
}
public function getProductionsAnalyticsTotalClientsHosting($pointOfSale, $codeCluster, $codeInsee, $mois, $annee, $optionSelect, $filtre, $childs, $organisationId, $perid, $sellerId, $departement): array
{
$conn = $this->getEntityManager()->getConnection();
$sql = '
SELECT COUNT(DISTINCT p.titulaire_email) AS total_vente
FROM production p
LEFT JOIN point_of_sale po ON p.point_of_sale_id = po.id
LEFT JOIN cluster c ON p.cluster_id = c.id
WHERE p.point_of_sale_id = :pointOfSale
AND p.category_id NOT IN (2)
AND MONTH(p.date_cmd_a) = :mois
AND YEAR(p.date_cmd_a) = :annee
';
$params = [
'pointOfSale' => $pointOfSale->getId(),
'mois' => $mois,
'annee' => $annee,
];
if ($codeCluster) {
$sql .= ' AND c.code_cluster = :codeCluster';
$params['codeCluster'] = $codeCluster;
}
if ($departement) {
$sql .= " AND c.code_cluster LIKE :departement";
$params["departement"] = $departement . '-%';
}
if ($codeInsee) {
$sql .= ' AND p.code_insee = :codeInsee';
$params['codeInsee'] = $codeInsee;
}
if ($organisationId) {
$sql .= ' AND p.organisation_id = :organisationId';
$params['organisationId'] = $organisationId;
}
if ($perid) {
$sql .= ' AND p.login_vendeur_init = :perid';
$params['perid'] = $perid;
}
if ($sellerId) {
$sql .= ' AND p.seller_id = :sellerId';
$params['sellerId'] = $sellerId;
}
if (is_array($childs) && count($childs) > 0) {
$placeholders = [];
foreach ($childs as $i => $child) {
$placeholder = ':child_' . $i;
$placeholders[] = $placeholder;
$params['child_' . $i] = $child;
}
$sql .= ' AND p.seller_id IN (' . implode(', ', $placeholders) . ')';
}
$stmt = $conn->prepare($sql);
$result = $stmt->executeQuery($params);
return $result->fetchAssociative();
}
public function getProductionsReselies($pointOfSale, $codeCluster, $mois, $annee, $optionSelect, $page)
{
$conn = $this->getEntityManager()->getConnection();
$limit = 30;
$offset = ($page - 1) * $limit;
$sql = '
SELECT *
FROM production p
LEFT JOIN point_of_sale po ON p.point_of_sale_id = po.id
LEFT JOIN cluster c ON p.cluster_id = c.id
WHERE
p.date_resiliation IS NOT NULL
AND p.date_racc IS NOT NULL
AND DATEDIFF(p.date_racc, p.date_resiliation) > -31
AND p.category_id NOT IN (2, 31, 32, 33)
';
$params = [];
if ($pointOfSale && $pointOfSale->getId()) {
$sql .= " AND p.point_of_sale_id = :pointOfSale";
$params["pointOfSale"] = $pointOfSale->getId();
}
if ($codeCluster) {
$sql .= ' AND c.code_cluster = :codeCluster';
$params['codeCluster'] = $codeCluster;
}
switch ($optionSelect) {
case 'V':
$sql .= ' AND MONTH(p.date_vente_valid_b) = :mois AND YEAR(p.date_vente_valid_b) = :annee';
$params['mois'] = $mois;
$params['annee'] = $annee;
break;
case 'R':
$sql .= ' AND MONTH(p.date_racc) = :mois AND YEAR(p.date_racc) = :annee';
$params['mois'] = $mois;
$params['annee'] = $annee;
break;
case 'B':
$sql .= ' AND MONTH(p.date_cmd_a) = :mois AND YEAR(p.date_cmd_a) = :annee';
$params['mois'] = $mois;
$params['annee'] = $annee;
break;
}
// $sql .= ' LIMIT :limit OFFSET :offset';
$stmt = $conn->prepare($sql);
if (isset($params['pointOfSale'])) {
$stmt->bindValue('pointOfSale', $params['pointOfSale'], \PDO::PARAM_INT);
}
if (isset($params['codeCluster'])) {
$stmt->bindValue('codeCluster', $params['codeCluster']);
}
if (isset($params['mois'])) {
$stmt->bindValue('mois', $params['mois'], \PDO::PARAM_INT);
}
if (isset($params['annee'])) {
$stmt->bindValue('annee', $params['annee'], \PDO::PARAM_INT);
}
// $stmt->bindValue('limit', $limit, \PDO::PARAM_INT);
// $stmt->bindValue('offset', $offset, \PDO::PARAM_INT);
$result = $stmt->executeQuery();
return $result->fetchAllAssociative();
}
public function getProductionsReseliesMobile($pointOfSale, $codeCluster, $mois, $annee, $optionSelect, $page)
{
$conn = $this->getEntityManager()->getConnection();
$limit = 30;
$offset = ($page - 1) * $limit;
$sql = '
SELECT *
FROM production p
LEFT JOIN point_of_sale po ON p.point_of_sale_id = po.id
LEFT JOIN cluster c ON p.cluster_id = c.id
WHERE
p.date_resiliation IS NOT NULL
AND p.date_racc IS NOT NULL
AND DATEDIFF(p.date_racc, p.date_resiliation) > -31
AND p.category_id IN (31, 32, 33)
';
$params = [];
if ($pointOfSale && $pointOfSale->getId()) {
$sql .= ' AND p.point_of_sale_id = :pointOfSale';
$params['pointOfSale'] = $pointOfSale->getId();
}
if ($codeCluster) {
$sql .= ' AND c.code_cluster = :codeCluster';
$params['codeCluster'] = $codeCluster;
}
switch ($optionSelect) {
case 'V':
$sql .= ' AND MONTH(p.date_vente_valid_b) = :mois AND YEAR(p.date_vente_valid_b) = :annee';
$params['mois'] = $mois;
$params['annee'] = $annee;
break;
case 'R':
$sql .= ' AND MONTH(p.date_racc) = :mois AND YEAR(p.date_racc) = :annee';
$params['mois'] = $mois;
$params['annee'] = $annee;
break;
case 'B':
$sql .= ' AND MONTH(p.date_cmd_a) = :mois AND YEAR(p.date_cmd_a) = :annee';
$params['mois'] = $mois;
$params['annee'] = $annee;
break;
}
// $sql .= ' LIMIT :limit OFFSET :offset';
$stmt = $conn->prepare($sql);
if (isset($params['pointOfSale'])) {
$stmt->bindValue('pointOfSale', $params['pointOfSale'], \PDO::PARAM_INT);
}
if (isset($params['codeCluster'])) {
$stmt->bindValue('codeCluster', $params['codeCluster']);
}
if (isset($params['mois'])) {
$stmt->bindValue('mois', $params['mois'], \PDO::PARAM_INT);
}
if (isset($params['annee'])) {
$stmt->bindValue('annee', $params['annee'], \PDO::PARAM_INT);
}
// $stmt->bindValue('limit', $limit, \PDO::PARAM_INT);
// $stmt->bindValue('offset', $offset, \PDO::PARAM_INT);
$result = $stmt->executeQuery();
return $result->fetchAllAssociative();
}
public function getMobileDetails($pointOfSale, $cluster, $codeInsee, $optionSelect, $dateDebut, $dateFin, $childs, $organisationId)
{
$qb = $this->getEntityManager()->createQueryBuilder();
$qb->select('p')
->from('App\Entity\Production', 'p');
if ($pointOfSale !== null) {
$qb->andWhere('p.pointOfSale = :pointOfSale')
->setParameter('pointOfSale', $pointOfSale);
}
switch ($optionSelect) {
case 'V':
$qb->andWhere('DATE_FORMAT(p.dateVenteValidB, \'%Y-%m-%d\') >= :debut');
$qb->andWhere('DATE_FORMAT(p.dateVenteValidB, \'%Y-%m-%d\') <= :fin');
break;
case 'R':
$qb->andWhere('DATE_FORMAT(p.dateRacc, \'%Y-%m-%d\') >= :debut');
$qb->andWhere('DATE_FORMAT(p.dateRacc, \'%Y-%m-%d\') <= :fin');
break;
case 'B':
$qb->andWhere('DATE_FORMAT(p.dateCmdA, \'%Y-%m-%d\') >= :debut');
$qb->andWhere('DATE_FORMAT(p.dateCmdA, \'%Y-%m-%d\') <= :fin');
break;
}
$qb->setParameter('debut', $dateDebut)
->setParameter('fin', $dateFin);
if ($cluster) {
$qb->andWhere('p.cluster = :cluster')
->setParameter('cluster', $cluster);
}
if ($codeInsee) {
$qb->andWhere('p.codeInsee = :codeInsee')
->setParameter('codeInsee', $codeInsee);
}
if ($organisationId) {
$qb->andWhere('p.organisation = :organisationId')
->setParameter('organisationId', $organisationId);
}
if (is_array($childs) && count($childs) > 0) {
$qb->andWhere('p.seller IN (:childs)')
->leftJoin('p.seller', 's')
->setParameter('childs', $childs);
}
$qb->andWhere('p.fixeAutre IS NOT NULL OR p.fixeChainage IS NOT NULL');
$qb->join('p.category', 'c')
->andWhere('c.parentCategory = :parentCategory')
->setParameter('parentCategory', 4);
return $qb->getQuery()->getArrayResult();
}
public function getProductionsAnalyticsTotalByIdentityCtrl($pointOfSale, $codeCluster, $codeInsee, $mois, $annee, $optionSelect, $filtre, $childs, $organisationId, $perid, $sellerId, $departement)
{
$conn = $this->getEntityManager()->getConnection();
$sql = '
SELECT COUNT(p.id) AS total_vente, p.identity_ctrl
FROM production p
LEFT JOIN point_of_sale po ON p.point_of_sale_id = po.id
LEFT JOIN cluster c ON p.cluster_id = c.id
WHERE p.point_of_sale_id = :pointOfSale
AND p.identity_ctrl IS NOT NULL
';
$params = [
'pointOfSale' => $pointOfSale->getId(),
'mois' => $mois,
'annee' => $annee
];
if (is_array($childs) && count($childs) > 0) {
$placeholders = [];
foreach ($childs as $i => $child) {
$placeholder = ':child_' . $i;
$placeholders[] = $placeholder;
$params['child_' . $i] = $child;
}
$sql .= ' AND p.seller_id IN (' . implode(', ', $placeholders) . ')';
}
if ($codeCluster) {
$sql .= ' AND c.code_cluster = :codeCluster';
$params['codeCluster'] = $codeCluster;
}
if ($departement) {
$sql .= " AND c.code_cluster LIKE :departement";
$params["departement"] = $departement . '-%';
}
if ($codeInsee) {
$sql .= ' AND p.code_insee = :codeInsee';
$params['codeInsee'] = $codeInsee;
}
if ($organisationId) {
$sql .= ' AND p.organisation_id = :organisationId';
$params['organisationId'] = $organisationId;
}
if ($perid) {
$sql .= ' AND p.login_vendeur_init = :perid';
$params['perid'] = $perid;
}
if ($sellerId) {
$sql .= ' AND p.seller_id = :sellerId';
$params['sellerId'] = $sellerId;
}
switch ($optionSelect) {
case 'V':
$sql .= ' AND MONTH(p.date_vente_valid_b) = :mois AND YEAR(p.date_vente_valid_b) = :annee';
$params['mois'] = $mois;
$params['annee'] = $annee;
break;
case 'R':
$sql .= ' AND MONTH(p.date_racc) = :mois AND YEAR(p.date_racc) = :annee';
$params['mois'] = $mois;
$params['annee'] = $annee;
break;
case 'B':
$sql .= ' AND MONTH(p.date_cmd_a) = :mois AND YEAR(p.date_cmd_a) = :annee';
$params['mois'] = $mois;
$params['annee'] = $annee;
break;
}
$sql .= ' GROUP BY p.identity_ctrl ';
$stmt = $conn->prepare($sql);
$result = $stmt->executeQuery($params);
return $result->fetchAllAssociative();
}
public function getProductionsDetailsByIdentityCtrl($pointOfSale, $codeCluster, $codeInsee, $mois, $annee, $optionSelect, $identityCtrl, $page)
{
$limit = 30;
$offset = ($page - 1) * $limit;
$conn = $this->getEntityManager()->getConnection();
$sql = '
SELECT *
FROM production p
LEFT JOIN point_of_sale po ON p.point_of_sale_id = po.id
LEFT JOIN cluster c ON p.cluster_id = c.id
WHERE p.point_of_sale_id = :pointOfSale
';
$params = [
'pointOfSale' => $pointOfSale->getId(),
'mois' => $mois,
'annee' => $annee,
];
if ($identityCtrl) {
$sql .= ' AND p.identity_ctrl = :identityCtrl';
$params['identityCtrl'] = $identityCtrl;
}
if ($codeCluster) {
$sql .= ' AND c.code_cluster = :codeCluster';
$params['codeCluster'] = $codeCluster;
}
if ($codeInsee) {
$sql .= ' AND p.code_insee = :codeInsee';
$params['codeInsee'] = $codeInsee;
}
switch ($optionSelect) {
case 'V':
$sql .= ' AND MONTH(p.date_vente_valid_b) = :mois AND YEAR(p.date_vente_valid_b) = :annee';
break;
case 'R':
$sql .= ' AND MONTH(p.date_racc) = :mois AND YEAR(p.date_racc) = :annee';
break;
case 'B':
$sql .= ' AND MONTH(p.date_cmd_a) = :mois AND YEAR(p.date_cmd_a) = :annee';
break;
}
$sql .= ' ORDER BY p.id DESC ';
// // Ajouter les paramètres de pagination
// $params['limit'] = $limit;
// $params['offset'] = $offset;
// Préparer la requête
$stmt = $conn->prepare($sql);
// Liaison explicite des paramètres LIMIT/OFFSET pour éviter les erreurs PDO
$stmt->bindValue('pointOfSale', $params['pointOfSale']);
if ($identityCtrl) {
$stmt->bindValue('identityCtrl', $params['identityCtrl']);
}
if (isset($params['codeCluster'])) {
$stmt->bindValue('codeCluster', $params['codeCluster']);
}
if (isset($params['codeInsee'])) {
$stmt->bindValue('codeInsee', $params['codeInsee']);
}
$stmt->bindValue('mois', $params['mois']);
$stmt->bindValue('annee', $params['annee']);
// $stmt->bindValue('limit', $params['limit'], \PDO::PARAM_INT);
// $stmt->bindValue('offset', $params['offset'], \PDO::PARAM_INT);
$result = $stmt->executeQuery();
return $result->fetchAllAssociative();
}
public function getProductionsAnalyticsTotalClientsUnique($pointOfSale, $codeCluster, $codeInsee, $mois, $annee, $optionSelect, $etatKO, $category, $option, $childs, $organisationId, $perid, $sellerId, $departement): array
{
$qb = $this->createBaseQueryBuilder2($pointOfSale, $codeCluster, $codeInsee, $mois, $annee, $optionSelect, $departement)
->select('COUNT(DISTINCT p.titulaireEmail) as total_client_unique');
if (is_array($childs) && count($childs) > 0) {
$qb->andWhere('p.seller IN (:childs)')
->leftJoin('p.seller', 's')
->setParameter('childs', $childs);
}
if ($organisationId) {
$qb->andWhere('p.organisation = :organisationId')
->setParameter('organisationId', $organisationId);
}
if ($perid) {
$qb->andWhere('p.loginVendeurInit = :perid ')
->setParameter('perid', $perid);
}
if ($sellerId) {
$qb->andWhere('p.seller = :sellerId')
->setParameter('sellerId', $sellerId);
}
return $qb->getQuery()->getArrayResult();
}
public function getProductionsAnalyticsTotal4P($pointOfSale, $codeCluster, $codeInsee, $mois, $annee, $optionSelect, $etat, $filtre, $childs, $organisationId, $perid, $sellerId, $departement): array
{
$conn = $this->getEntityManager()->getConnection();
$params = [
'pointOfSale' => $pointOfSale->getId(),
'mois' => $mois,
'annee' => $annee,
'cat1' => 32,
'cat2' => 31
];
$sql = '
SELECT COUNT(DISTINCT result.titulaire_email) AS total_vente
FROM (
SELECT p1.titulaire_email
FROM production p1
LEFT JOIN cluster c1 ON c1.id=p1.cluster_id
WHERE p1.category_id = :cat1
AND p1.point_of_sale_id = :pointOfSale
AND MONTH(p1.date_cmd_a) = :mois
AND YEAR(p1.date_cmd_a) = :annee
AND p1.titulaire_email IN (
SELECT DISTINCT p_sub1.titulaire_email
FROM production p_sub1
WHERE p_sub1.category_id = 1
AND p_sub1.point_of_sale_id = :pointOfSale
AND MONTH(p_sub1.date_cmd_a) = :mois
AND YEAR(p_sub1.date_cmd_a) = :annee
)
';
if ($organisationId) {
$sql .= ' AND p1.organisation_id = :organisationId';
$params['organisationId'] = $organisationId;
}
if ($codeCluster) {
$sql .= " AND c1.code_cluster = :codeCluster";
$params["codeCluster"] = $codeCluster;
}
if ($departement) {
$sql .= " AND c1.code_cluster LIKE :departement";
$params["departement"] = $departement . '-%';
}
if ($codeInsee) {
$sql .= " AND p1.code_insee = :codeInsee";
$params["codeInsee"] = $codeInsee;
}
if ($perid) {
$sql .= " AND p1.login_vendeur_init = :perid";
$params["perid"] = $perid;
}
if ($sellerId) {
$sql .= ' AND p1.seller_id = :sellerId';
$params['sellerId'] = $sellerId;
}
if (is_array($childs) && count($childs) > 0) {
$placeholders = [];
foreach ($childs as $i => $child) {
$placeholder = ':child_' . $i;
$placeholders[] = $placeholder;
$params['child_' . $i] = $child;
}
$sql .= ' AND p1.seller_id IN (' . implode(', ', $placeholders) . ')';
}
$sql .= '
UNION
SELECT p2.titulaire_email
FROM production p2
LEFT JOIN cluster c2 ON c2.id=p2.cluster_id
WHERE p2.category_id = :cat2
AND p2.point_of_sale_id = :pointOfSale
AND MONTH(p2.date_cmd_a) = :mois
AND YEAR(p2.date_cmd_a) = :annee
AND p2.titulaire_email IN (
SELECT DISTINCT p_sub2.titulaire_email
FROM production p_sub2
WHERE p_sub2.category_id IN (1, 3)
AND p_sub2.point_of_sale_id = :pointOfSale
AND MONTH(p_sub2.date_cmd_a) = :mois
AND YEAR(p_sub2.date_cmd_a) = :annee
)
';
if ($organisationId) {
$sql .= ' AND p2.organisation_id = :organisationId';
}
if ($codeCluster) {
$sql .= " AND c2.code_cluster = :codeCluster";
}
if ($departement) {
$sql .= " AND c2.code_cluster LIKE :departement";
}
if ($perid) {
$sql .= ' AND p2.login_vendeur_init = :perid';
}
if ($sellerId) {
$sql .= ' AND p2.seller_id = :sellerId';
}
if ($codeInsee) {
$sql .= ' AND p2.code_insee = :codeInsee';
}
if (is_array($childs) && count($childs) > 0) {
$placeholders = [];
foreach ($childs as $i => $child) {
$placeholder = ':child_' . $i;
$placeholders[] = $placeholder;
}
$sql .= ' AND p2.seller_id IN (' . implode(', ', $placeholders) . ')';
}
$sql .= ') AS result';
$stmt = $conn->prepare($sql);
$result = $stmt->executeQuery($params);
return $result->fetchAssociative();
}
public function getDetails4P($pointOfSale, $codeCluster, $codeInsee, $mois, $annee, $childs, $organisationId, $perid, $sellerId): array
{
$conn = $this->getEntityManager()->getConnection();
$params = [
'pointOfSale' => $pointOfSale->getId(),
'mois' => $mois,
'annee' => $annee,
'cat1' => 32,
'cat2' => 31,
];
$sql = '
SELECT result.*
FROM (
SELECT p1.*
FROM production p1
LEFT JOIN cluster c1 ON p1.cluster_id = c1.id
WHERE p1.category_id = :cat1
AND p1.point_of_sale_id = :pointOfSale
AND MONTH(p1.date_cmd_a) = :mois
AND YEAR(p1.date_cmd_a) = :annee
AND p1.titulaire_email IN (
SELECT p_sub1.titulaire_email
FROM production p_sub1
WHERE p_sub1.category_id = 1
AND p_sub1.point_of_sale_id = :pointOfSale
AND MONTH(p_sub1.date_cmd_a) = :mois
AND YEAR(p_sub1.date_cmd_a) = :annee
)
';
if ($organisationId) {
$sql .= ' AND p1.organisation_id = :organisationId';
$params['organisationId'] = $organisationId;
}
if ($codeCluster) {
$sql .= ' AND c1.code_cluster = :codeCluster';
$params['codeCluster'] = $codeCluster;
}
if ($perid) {
$sql .= ' AND p1.login_vendeur_init = :perid';
$params['perid'] = $perid;
}
if ($sellerId) {
$sql .= ' AND p1.seller_id = :sellerId';
$params['sellerId'] = $sellerId;
}
if ($codeInsee) {
$sql .= ' AND p1.code_insee = :codeInsee';
$params['codeInsee'] = $codeInsee;
}
if (is_array($childs) && count($childs) > 0) {
$placeholders = [];
foreach ($childs as $i => $child) {
$placeholder = ':child_' . $i;
$placeholders[] = $placeholder;
$params[$placeholder] = $child;
}
$sql .= ' AND p1.seller_id IN (' . implode(', ', $placeholders) . ')';
}
$sql .= '
UNION
SELECT p2.*
FROM production p2
LEFT JOIN cluster c2 ON p2.cluster_id = c2.id
WHERE p2.category_id = :cat2
AND p2.point_of_sale_id = :pointOfSale
AND MONTH(p2.date_cmd_a) = :mois
AND YEAR(p2.date_cmd_a) = :annee
AND p2.titulaire_email IN (
SELECT p_sub2.titulaire_email
FROM production p_sub2
WHERE p_sub2.category_id IN (1, 3)
AND p_sub2.point_of_sale_id = :pointOfSale
AND MONTH(p_sub2.date_cmd_a) = :mois
AND YEAR(p_sub2.date_cmd_a) = :annee
)
';
if ($organisationId) {
$sql .= ' AND p2.organisation_id = :organisationId';
}
if ($codeCluster) {
$sql .= ' AND c2.code_cluster = :codeCluster';
}
if ($perid) {
$sql .= ' AND p2.login_vendeur_init = :perid';
}
if ($sellerId) {
$sql .= ' AND p2.seller_id = :sellerId';
}
if ($codeInsee) {
$sql .= ' AND p2.code_insee = :codeInsee';
}
if (is_array($childs) && count($childs) > 0) {
$placeholders = [];
foreach ($childs as $i => $child) {
$placeholder = ':child_' . $i;
$placeholders[] = $placeholder;
$params[$placeholder] = $child;
}
$sql .= ' AND p2.seller_id IN (' . implode(', ', $placeholders) . ')';
}
$sql .= ') AS result';
$stmt = $conn->prepare($sql);
$result = $stmt->executeQuery($params);
// retourne tous les enregistrements (sinon tu n'auras qu’un seul résultat)
return $result->fetchAllAssociative();
}
public function findDistinctTech(): array
{
return $this->createQueryBuilder('p')
->select('DISTINCT p.tech')
->where('p.tech IS NOT NULL')
->getQuery()
->getResult();
}
public function filterProductions(
$periode = null,
$pointOfSaleId = null,
$categoryId = null,
$technologie = null,
$clusterId = null,
$optionSelect = 'B'
) {
$conn = $this->getEntityManager()->getConnection();
// Choix de la colonne de date en fonction de $optionSelect
switch ($optionSelect) {
case 'V':
$dateField = 'date_vente_valid_b';
break;
case 'R':
$dateField = 'date_racc';
break;
case 'B':
default:
$dateField = 'date_cmd_a';
break;
}
// Base SQL
$sql = "SELECT COUNT(p.id) AS total_vente";
// Ajout des regroupements par période
switch ($periode) {
case 'jour':
$sql .= ", DATE(p.$dateField) AS jour";
$groupBy = "GROUP BY jour";
break;
case 'semaine':
$sql .= ", YEAR(p.$dateField) AS annee, WEEK(p.$dateField, 1) AS semaine";
$groupBy = "GROUP BY annee, semaine";
break;
case 'mois':
$sql .= ", YEAR(p.$dateField) AS annee, MONTH(p.$dateField) AS mois";
$groupBy = "GROUP BY annee, mois";
break;
case 'annee':
$sql .= ", YEAR(p.$dateField) AS annee";
$groupBy = "GROUP BY annee";
break;
default:
$groupBy = "";
}
// Suite de la requête
$sql .= " FROM production p WHERE 1=1";
$params = [];
if ($pointOfSaleId) {
$sql .= " AND p.point_of_sale_id = :pointOfSaleId";
$params['pointOfSaleId'] = $pointOfSaleId;
}
if ($clusterId) {
$sql .= " AND p.cluster_id = :clusterId";
$params['clusterId'] = $clusterId;
}
if ($categoryId) {
$sql .= " AND p.category_id = :categoryId";
$params['categoryId'] = $categoryId;
}
if ($technologie) {
$sql .= " AND p.tech LIKE :technologie";
$params['technologie'] = '%' . $technologie . '%';
}
if ($groupBy) {
$sql .= " " . $groupBy;
}
$stmt = $conn->prepare($sql);
$resultSet = $stmt->executeQuery($params);
return $resultSet->fetchAllAssociative();
}
public function getProductionsAnalyticsTotalVenteByOption(
$pointOfSale,
?string $codeCluster,
$codeInsee,
int $mois,
int $annee,
array $childs,
?int $organisationId,
?string $optionCalcul,
?string $perid,
$sellerId,
$departement
): array {
$conn = $this->getEntityManager()->getConnection();
$sql = '
SELECT COUNT(DISTINCT p.id) AS total_vente
FROM production p
LEFT JOIN point_of_sale po ON p.point_of_sale_id = po.id
LEFT JOIN cluster c ON c.id =p.cluster_id
';
$sql .= '
WHERE p.point_of_sale_id = :pointOfSale
AND p.category_id IN (1,3)
AND MONTH(p.date_cmd_a) = :mois
AND YEAR(p.date_cmd_a) = :annee
';
$params = [
'pointOfSale' => $pointOfSale->getId(),
'mois' => $mois,
'annee' => $annee,
];
if ($organisationId) {
$sql .= ' AND p.organisation_id = :organisationId';
$params['organisationId'] = $organisationId;
}
if (!empty($childs)) {
$placeholders = [];
foreach ($childs as $i => $child) {
$placeholder = ':child_' . $i;
$placeholders[] = $placeholder;
$params['child_' . $i] = $child;
}
$sql .= ' AND p.seller_id IN (' . implode(', ', $placeholders) . ')';
}
if ($codeInsee) {
$sql .= ' AND p.code_insee = :codeInsee';
$params['codeInsee'] = $codeInsee;
}
if ($codeCluster) {
$sql .= ' AND c.code_cluster = :codeCluster';
$params['codeCluster'] = $codeCluster;
}
if ($departement) {
$sql .= " AND c.code_cluster LIKE :departement";
$params["departement"] = $departement . '-%';
}
if ($perid) {
$sql .= ' AND p.login_vendeur_init = :perid';
$params['perid'] = $perid;
}
if ($sellerId) {
$sql .= ' AND p.seller_id = :sellerId';
$params['sellerId'] = $sellerId;
}
if ($optionCalcul) {
switch ($optionCalcul) {
case 'RIO':
$sql .= ' AND p.portabilite = :opt';
$params['opt'] = 'OUI';
break;
case 'PTO_SAISIE':
$sql .= ' AND p.prise_saisie_commande = :opt';
$params['opt'] = 'OUI';
break;
case 'PTO_NON_SAISIE':
$sql .= ' AND p.prise_saisie_commande = :opt AND p.prise_existante_commande = :opt2';
$params['opt'] = 'NON';
$params['opt2'] = 'OUI';
break;
case 'PTO_EXISTANTE':
$sql .= ' AND p.prise_existante_commande = :opt';
$params['opt'] = 'OUI';
break;
case 'PTO_NON_EXISTANTE':
$sql .= ' AND p.prise_existante_commande = :opt';
$params['opt'] = 'NON';
break;
}
}
$stmt = $conn->prepare($sql);
$result = $stmt->executeQuery($params);
return $result->fetchAssociative();
}
/*******DASHBOARD *******/
public function getTotalVentesByPeriod(
$pointOfSale,
$codeCluster,
$departement,
$codeInsee,
int $annee,
string $optionSelect,
$etat,
$category,
$childs,
$organisationId,
$perid,
string $periode = 'month' // 'day', 'week', 'month'
): array {
$conn = $this->getEntityManager()->getConnection();
// Choisir la colonne date selon optionSelect
switch ($optionSelect) {
case 'R':
$dateCol = 'p.date_racc';
break;
case 'B':
$dateCol = 'p.date_cmd_a';
break;
case 'V':
default:
$dateCol = 'p.date_vente_valid_b';
}
// Déterminer la colonne de regroupement selon la période
switch ($periode) {
case 'day':
$groupCol = "DATE($dateCol)";
$selectCol = "DATE($dateCol) AS periode";
$currentMonth = (int)date('m');
$previousMonth = $currentMonth === 1 ? 12 : $currentMonth - 1;
$monthCondition = " AND MONTH($dateCol) IN (:currentMonth, :previousMonth)";
break;
case 'week':
$groupCol = "WEEK($dateCol, 1)";
$selectCol = "WEEK($dateCol, 1) AS periode";
$monthCondition = "";
break;
case 'month':
default:
$groupCol = "MONTH($dateCol)";
$selectCol = "MONTH($dateCol) AS periode";
$monthCondition = "";
}
// --- Construction SQL ---
$sql = "
SELECT
$selectCol,
COUNT(p.id) AS total_ventes
";
// Si organisationId existe, on ajoute po.code et po.name
if ($organisationId) {
$sql .= ",
po.code AS code_point,
po.name AS nom_point
";
}
$sql .= "
FROM production p
LEFT JOIN point_of_sale po ON p.point_of_sale_id = po.id
LEFT JOIN cluster c ON p.cluster_id = c.id
WHERE YEAR($dateCol) = :annee
";
$params = ['annee' => $annee];
if ($organisationId) {
$sql .= " AND p.organisation_id = :organisationId";
$params['organisationId'] = $organisationId;
} else {
$sql .= " AND p.point_of_sale_id = :pointOfSale";
$params['pointOfSale'] = $pointOfSale->getId();
}
if ($codeCluster) {
$sql .= " AND c.code_cluster = :codeCluster";
$params['codeCluster'] = $codeCluster;
}
if ($departement) {
$sql .= " AND c.code_cluster LIKE :prefix";
$params['prefix'] = $departement . '-%';
}
if ($codeInsee) {
$sql .= " AND p.code_insee = :codeInsee";
$params['codeInsee'] = $codeInsee;
}
if ($perid) {
$sql .= " AND p.login_vendeur_init = :perid";
$params['perid'] = $perid;
}
if ($etat === "Raccorde") {
$sql .= " AND p.date_racc IS NOT NULL AND (p.category_id IN (1,3) OR p.product_id IN (150, 262, 264, 266, 334, 335, 341, 344, 345, 379))";
} elseif ($etat === "Raccorde_mobile") {
$sql .= " AND p.category_id IN (31,32,33) AND p.date_racc IS NOT NULL AND p.product_id NOT IN (150,262,264,266,334,335,341,344,345,379)";
}
if ($category) {
$categoryArray = [];
if (is_string($category)) {
$categoryArray = array_filter(array_map('intval', explode(',', $category)), fn($id) => $id > 0);
} elseif (is_array($category) || $category instanceof \Traversable) {
foreach ($category as $cat) {
$categoryArray[] = is_object($cat) && method_exists($cat, 'getId') ? $cat->getId() : (int)$cat;
}
$categoryArray = array_filter($categoryArray, fn($id) => $id > 0);
}
if (!empty($categoryArray)) {
$sql .= " AND p.category_id IN (" . implode(',', $categoryArray) . ")";
}
}
if (is_array($childs) && count($childs) > 0) {
$sql .= " AND p.seller_id IN (" . implode(',', $childs) . ")";
}
if ($periode === 'day') {
$sql .= $monthCondition;
$params['currentMonth'] = $currentMonth;
$params['previousMonth'] = $previousMonth;
}
// GROUP BY dynamique
if ($organisationId) {
$sql .= " GROUP BY po.id, $groupCol
ORDER BY po.id, $groupCol ASC";
} else {
$sql .= " GROUP BY $groupCol
ORDER BY $groupCol ASC";
}
// --- Exécution ---
$stmt = $conn->executeQuery($sql, $params);
$results = $stmt->fetchAllAssociative();
// --- Réorganisation du résultat ---
$data = [];
foreach ($results as $row) {
if ($organisationId) {
$codePoint = $row['code_point'];
$periode = $row['periode'];
$total = (int)$row['total_ventes'];
if (!isset($data[$codePoint])) {
$data[$codePoint] = [];
}
// On alimente la période avec le total
$data[$codePoint][$periode] = $total;
} else {
$data[$row['periode']] = (int)$row['total_ventes'];
}
}
return $data;
}
public function getTotalObjectifsByMonth(
$pointOfSale,
$codeCluster,
$annee,
$optionSelect,
$etatKO,
$category,
$childs,
$organisationId,
$departement
): array {
$em = $this->getEntityManager();
// --- 1️⃣ Construction de la requête ---
if (is_array($childs) && count($childs) > 0) {
$qb = $em->createQueryBuilder()
->select('MONTH(o.monthAt) AS mois, SUM(o.objectivesVv) AS total_objectif')
->from('App\Entity\ObjectivesManagement', 'o')
->where('YEAR(o.monthAt) = :annee ')
->setParameter('annee', $annee)
->andWhere('o.user IN (:childs)')
->setParameter('childs', $childs)
->groupBy('mois')
->orderBy('mois', 'ASC');
} else {
$qb = $em->createQueryBuilder()
->select('o.mois AS mois, SUM(o.vv) AS total_objectif')
->from('App\Entity\NmdObjectifClusters', 'o')
->leftJoin('App\Entity\PointOfSale', 'po', 'WITH', 'o.cpv = po.code')
->where('o.year = :annee ')
->andWhere('o.mois != \'\'')
->setParameter('annee', $annee);
if ($codeCluster) {
$qb->andWhere('o.codeCluster = :codeCluster')
->setParameter('codeCluster', $codeCluster);
}
if ($departement) {
$qb->andWhere('o.codeCluster LIKE :prefix')
->setParameter('prefix', $departement . '-%');
}
if ($organisationId) {
$qb->addSelect('o.cpv')
->addGroupBy('o.cpv')
->addGroupBy('o.mois')
->addOrderBy('o.cpv', 'ASC')
->addOrderBy('o.mois', 'ASC');
} else {
if ($pointOfSale !== null) {
$qb->andWhere('o.cpv = :cpv')
->setParameter('cpv', $pointOfSale->getCode());
}
$qb->addGroupBy('o.mois')
->addOrderBy('o.mois', 'ASC');
}
}
// --- 2️⃣ Exécution de la requête ---
$results = $qb->getQuery()->getArrayResult();
// --- 3️⃣ Formatage du résultat ---
$formatted = ['parMois' => []];
if ($organisationId) {
// Structure : parMois[cpv][mois] = total
foreach ($results as $row) {
$mois = isset($row['mois']) ? (int) $row['mois'] : 0;
$total = isset($row['total_objectif']) ? (float) $row['total_objectif'] : 0.0;
$cpv = isset($row['cpv']) && $row['cpv'] !== null ? $row['cpv'] : 'UNKNOWN';
if (!isset($formatted['parMois'][$cpv])) {
$formatted['parMois'][$cpv] = [];
}
$formatted['parMois'][$cpv][$mois] = (int) $total;
}
// Tri des mois pour chaque CPV
foreach ($formatted['parMois'] as &$data) {
ksort($data);
}
unset($data);
} else {
// Structure : parMois[mois] = total
foreach ($results as $row) {
$mois = isset($row['mois']) ? (int) $row['mois'] : 0;
$total = isset($row['total_objectif']) ? (float) $row['total_objectif'] : 0.0;
$formatted['parMois'][$mois] = (int) $total;
}
ksort($formatted['parMois']); // Tri des mois
}
return $formatted;
}
public function getTotalVentesBOX5G(
$pointOfSale,
$codeCluster,
$departement,
$codeInsee,
int $annee,
string $optionSelect,
$etat,
$category,
$childs,
$organisationId,
$perid,
string $periode = 'month' // 'day', 'week', 'month'
): array {
$conn = $this->getEntityManager()->getConnection();
// Choisir la colonne date selon optionSelect
switch ($optionSelect) {
case 'R':
$dateCol = 'p.date_racc';
break;
case 'B':
$dateCol = 'p.date_cmd_a';
break;
case 'V':
default:
$dateCol = 'p.date_vente_valid_b';
}
// Déterminer la colonne de regroupement selon la période
switch ($periode) {
case 'day':
$groupCol = "DATE($dateCol)";
$selectCol = "DATE($dateCol) AS periode";
$currentMonth = (int)date('m');
$previousMonth = $currentMonth === 1 ? 12 : $currentMonth - 1;
$monthCondition = " AND MONTH($dateCol) IN (:currentMonth, :previousMonth)";
break;
case 'week':
$groupCol = "WEEK($dateCol, 1)";
$selectCol = "WEEK($dateCol, 1) AS periode";
$monthCondition = "";
break;
case 'month':
default:
$groupCol = "MONTH($dateCol)";
$selectCol = "MONTH($dateCol) AS periode";
$monthCondition = "";
}
// --- Construction SQL ---
$sql = "
SELECT
$selectCol,
COUNT(p.id) AS total_ventes
";
// Si organisationId existe, on ajoute po.code et po.name
if ($organisationId) {
$sql .= ",
po.code AS code_point,
po.name AS nom_point
";
}
$sql .= "
FROM production p
LEFT JOIN point_of_sale po ON p.point_of_sale_id = po.id
LEFT JOIN cluster c ON p.cluster_id = c.id
WHERE YEAR($dateCol) = :annee
";
$params = ['annee' => $annee];
if ($organisationId) {
$sql .= " AND p.organisation_id = :organisationId";
$params['organisationId'] = $organisationId;
} else {
$sql .= " AND p.point_of_sale_id = :pointOfSale";
$params['pointOfSale'] = $pointOfSale->getId();
}
if ($codeCluster) {
$sql .= " AND c.code_cluster = :codeCluster";
$params['codeCluster'] = $codeCluster;
}
if ($departement) {
$sql .= " AND c.code_cluster LIKE :prefix";
$params['prefix'] = $departement . '-%';
}
if ($codeInsee) {
$sql .= " AND p.code_insee = :codeInsee";
$params['codeInsee'] = $codeInsee;
}
if ($perid) {
$sql .= " AND p.login_vendeur_init = :perid";
$params['perid'] = $perid;
}
$sql .= " AND p.product_id IN (150, 262, 264, 266, 334, 335, 341, 344, 345, 379)";
if (is_array($childs) && count($childs) > 0) {
$sql .= " AND p.seller_id IN (" . implode(',', $childs) . ")";
}
if ($periode === 'day') {
$sql .= $monthCondition;
$params['currentMonth'] = $currentMonth;
$params['previousMonth'] = $previousMonth;
}
// GROUP BY dynamique
if ($organisationId) {
$sql .= " GROUP BY po.id, $groupCol
ORDER BY po.id, $groupCol ASC";
} else {
$sql .= " GROUP BY $groupCol
ORDER BY $groupCol ASC";
}
// --- Exécution ---
$stmt = $conn->executeQuery($sql, $params);
$results = $stmt->fetchAllAssociative();
// --- Réorganisation du résultat ---
$data = [];
foreach ($results as $row) {
if ($organisationId) {
$codePoint = $row['code_point'];
$periode = $row['periode'];
$total = (int)$row['total_ventes'];
if (!isset($data[$codePoint])) {
$data[$codePoint] = [];
}
// On alimente la période avec le total
$data[$codePoint][$periode] = $total;
} else {
$data[$row['periode']] = (int)$row['total_ventes'];
}
}
return $data;
}
public function getNbVendeursByMonthWeekDay(
$pointOfSale,
$codeCluster,
$departement,
$codeInsee,
int $annee,
string $optionSelect,
$etat,
$category,
$childs,
$organisationId,
$perid,
string $groupBy // 'mois', 'semaine' ou 'jour'
): array {
$conn = $this->getEntityManager()->getConnection();
// Choix de la colonne date
switch ($optionSelect) {
case 'R':
$dateCol = 'p.date_racc';
break;
case 'B':
$dateCol = 'p.date_cmd_a';
break;
case 'V':
default:
$dateCol = 'p.date_vente_valid_b';
}
// Déterminer les colonnes SQL pour le regroupement
switch ($groupBy) {
case 'mois':
$selectGroup = "MONTH($dateCol) AS periode";
$groupSQL = "MONTH($dateCol)";
break;
case 'semaine':
$selectGroup = "WEEK($dateCol, 1) AS periode";
$groupSQL = "WEEK($dateCol, 1)";
break;
case 'jour':
default:
$selectGroup = "$dateCol AS periode";
$groupSQL = "$dateCol";
}
$now = new \DateTime();
$moisActuel = (int)$now->format('n');
$moisPrecedent = (int)((clone $now)->modify('-1 month')->format('n'));
// --- Début du SQL ---
$sql = "
SELECT
$selectGroup,
COUNT(DISTINCT p.seller_id) AS nombre_vendeurs
";
// Si organisationId existe, on ajoute les infos du point de vente
if ($organisationId) {
$sql .= ",
po.code AS code_point,
po.name AS nom_point
";
}
$sql .= "
FROM production p
LEFT JOIN point_of_sale po ON p.point_of_sale_id = po.id
LEFT JOIN cluster c ON p.cluster_id = c.id
WHERE YEAR($dateCol) = :annee
";
$params = ['annee' => $annee];
// Filtrer par mois courant et précédent si on groupe par jour
if ($groupBy === 'jour') {
$sql .= " AND MONTH($dateCol) IN (:moisPrecedent, :moisActuel)";
$params['moisPrecedent'] = $moisPrecedent;
$params['moisActuel'] = $moisActuel;
}
// Conditions d'organisation / point de vente
if ($organisationId) {
$sql .= " AND p.organisation_id = :organisationId";
$params['organisationId'] = $organisationId;
} else {
$sql .= " AND p.point_of_sale_id = :pointOfSale";
$params['pointOfSale'] = $pointOfSale->getId();
}
// Autres filtres
if ($codeCluster) {
$sql .= " AND c.code_cluster = :codeCluster";
$params['codeCluster'] = $codeCluster;
}
if ($departement) {
$sql .= " AND c.code_cluster LIKE :prefix";
$params['prefix'] = $departement . '-%';
}
if ($codeInsee) {
$sql .= " AND p.code_insee = :codeInsee";
$params['codeInsee'] = $codeInsee;
}
if ($perid) {
$sql .= " AND p.login_vendeur_init = :perid";
$params['perid'] = $perid;
}
if ($etat === "Raccorde") {
$sql .= " AND p.etat_id = 1";
}
if ($etat === "Raccorde_mobile") {
$sql .= " AND p.category_id IN (31,32,33) AND p.date_racc IS NOT NULL";
}
if ($category) {
$categoryArray = [];
if (is_string($category)) {
$categoryArray = array_filter(array_map('intval', explode(',', $category)), fn($id) => $id > 0);
}
if (!empty($categoryArray)) {
$sql .= " AND p.category_id IN (" . implode(',', $categoryArray) . ")";
}
}
if (is_array($childs) && count($childs) > 0) {
$sql .= " AND p.seller_id IN (" . implode(',', $childs) . ")";
}
// GROUP BY dynamique
if ($organisationId) {
$sql .= " GROUP BY po.id, $groupSQL
ORDER BY po.id, $groupSQL ASC";
} else {
$sql .= " GROUP BY $groupSQL
ORDER BY $groupSQL ASC";
}
// --- Exécution ---
$stmt = $conn->executeQuery($sql, $params);
$results = $stmt->fetchAllAssociative();
// --- Réorganisation du résultat ---
$data = [];
foreach ($results as $row) {
if ($organisationId) {
$codePoint = $row['code_point'];
$periode = $row['periode'];
$nbVendeurs = (int)$row['nombre_vendeurs'];
if (!isset($data[$codePoint])) {
$data[$codePoint] = [];
}
$data[$codePoint][$periode] = $nbVendeurs;
} else {
$data[$row['periode']] = (int)$row['nombre_vendeurs'];
}
}
return $data;
}
public function getEtpByMonthWeekDay(
$pointOfSale,
$codeCluster,
$departement,
$codeInsee,
int $annee,
string $optionSelect,
$etat,
$category,
$childs,
$organisationId,
$perid
): array {
$conn = $this->getEntityManager()->getConnection();
// Choix de la colonne date
switch ($optionSelect) {
case 'R':
$dateCol = 'p.date_racc';
break;
case 'B':
$dateCol = 'p.date_cmd_a';
break;
case 'V':
default:
$dateCol = 'p.date_vente_valid_b';
}
$now = new \DateTime();
$moisActuel = (int)$now->format('n');
$moisPrecedent = (int)((clone $now)->modify('-1 month')->format('n'));
// --- Début du SQL ---
$sql = "
SELECT
$dateCol AS dateStat,
MONTH($dateCol) AS mois,
WEEK($dateCol, 1) AS semaine,
COUNT(p.id) / NULLIF(COUNT(DISTINCT p.seller_id), 0) AS etp
";
// Si organisationId existe → on ajoute les infos du point de vente
if ($organisationId) {
$sql .= ",
po.code AS code_point,
po.name AS nom_point
";
}
$sql .= "
FROM production p
LEFT JOIN point_of_sale po ON p.point_of_sale_id = po.id
LEFT JOIN cluster c ON p.cluster_id = c.id
WHERE YEAR($dateCol) = :annee
";
$params = ['annee' => $annee];
if ($organisationId) {
$sql .= " AND p.organisation_id = :organisationId";
$params['organisationId'] = $organisationId;
} else {
$sql .= " AND p.point_of_sale_id = :pointOfSale";
$params['pointOfSale'] = $pointOfSale->getId();
}
if ($codeCluster) {
$sql .= " AND c.code_cluster = :codeCluster";
$params['codeCluster'] = $codeCluster;
}
if ($departement) {
$sql .= " AND c.code_cluster LIKE :prefix";
$params['prefix'] = $departement . '-%';
}
if ($codeInsee) {
$sql .= " AND p.code_insee = :codeInsee";
$params['codeInsee'] = $codeInsee;
}
if ($perid) {
$sql .= " AND p.login_vendeur_init = :perid";
$params['perid'] = $perid;
}
if ($etat === "Raccorde") {
$sql .= " AND p.etat_id = 1";
}
if ($etat === "Raccorde_mobile") {
$sql .= " AND p.category_id IN (31,32,33) AND p.date_racc IS NOT NULL";
}
if ($category) {
$categoryArray = is_string($category)
? array_filter(array_map('intval', explode(',', $category)), fn($id) => $id > 0)
: [];
if (!empty($categoryArray)) {
$sql .= " AND p.category_id IN (" . implode(',', $categoryArray) . ")";
}
}
if (is_array($childs) && count($childs) > 0) {
$sql .= " AND p.seller_id IN (" . implode(',', $childs) . ")";
}
// GROUP BY dynamique
if ($organisationId) {
$sql .= " GROUP BY po.id, $dateCol ORDER BY po.id, $dateCol ASC";
} else {
$sql .= " GROUP BY $dateCol ORDER BY $dateCol ASC";
}
// --- Exécution ---
$stmt = $conn->executeQuery($sql, $params);
$results = $stmt->fetchAllAssociative();
// --- Réorganisation du résultat ---
$data = [];
foreach ($results as $row) {
$mois = (int)$row['mois'];
$semaine = (int)$row['semaine'];
$jour = $row['dateStat'];
$etp = (float)$row['etp'];
if ($organisationId) {
$codePoint = $row['code_point'];
if (!isset($data[$codePoint])) {
$data[$codePoint] = [
'parMois' => [],
'parSemaine' => [],
'parJour' => [],
];
}
$data[$codePoint]['parMois'][$mois] = ($data[$codePoint]['parMois'][$mois] ?? 0) + $etp;
$data[$codePoint]['parSemaine'][$semaine] = ($data[$codePoint]['parSemaine'][$semaine] ?? 0) + $etp;
if ($mois === $moisActuel || $mois === $moisPrecedent) {
$data[$codePoint]['parJour'][$jour] = $etp;
}
} else {
$data['parMois'][$mois] = ($data['parMois'][$mois] ?? 0) + $etp;
$data['parSemaine'][$semaine] = ($data['parSemaine'][$semaine] ?? 0) + $etp;
if ($mois === $moisActuel || $mois === $moisPrecedent) {
$data['parJour'][$jour] = $etp;
}
}
}
// --- Arrondir les valeurs ---
if ($organisationId) {
foreach ($data as $codePoint => &$valeurs) {
foreach (['parMois', 'parSemaine'] as $type) {
foreach ($valeurs[$type] as $period => $value) {
$valeurs[$type][$period] = round($value, 2);
}
}
}
} else {
foreach (['parMois', 'parSemaine'] as $type) {
foreach ($data[$type] as $period => $value) {
$data[$type][$period] = round($value, 2);
}
}
}
return $data;
}
public function getVentesKOByMonthWeekDay(
$pointOfSale,
$codeCluster,
$departement,
$codeInsee,
int $annee,
string $optionSelect,
$etatKO,
$category,
$childs,
$organisationId,
$perid
): array {
$conn = $this->getEntityManager()->getConnection();
// Déterminer la colonne date
switch ($optionSelect) {
case 'R':
$dateCol = 'p.date_racc';
break;
case 'B':
$dateCol = 'p.date_cmd_a';
break;
case 'V':
default:
$dateCol = 'p.date_vente_valid_b';
}
$now = new \DateTime();
$moisActuel = (int)$now->format('n');
$moisPrecedent = (int)((clone $now)->modify('-1 month')->format('n'));
// --- Début du SQL ---
$sql = "
SELECT
DATE($dateCol) AS dateStat,
MONTH($dateCol) AS mois,
WEEK($dateCol, 1) AS semaine,
COUNT(p.id) AS total_ventes_ko
";
// Si organisationId → on ajoute code_point et nom_point
if ($organisationId) {
$sql .= ",
po.code AS code_point,
po.name AS nom_point
";
}
$sql .= "
FROM production p
LEFT JOIN point_of_sale po ON p.point_of_sale_id = po.id
LEFT JOIN cluster c ON p.cluster_id = c.id
WHERE YEAR($dateCol) = :annee
AND p.etat_id = :etatKO
";
$params = [
'annee' => $annee,
'etatKO' => $etatKO->getId(),
];
// Conditions organisation / point de vente
if ($organisationId) {
$sql .= " AND p.organisation_id = :organisationId";
$params['organisationId'] = $organisationId;
} else {
$sql .= " AND p.point_of_sale_id = :pointOfSale";
$params['pointOfSale'] = $pointOfSale->getId();
}
if ($codeCluster) {
$sql .= " AND c.code_cluster = :codeCluster";
$params['codeCluster'] = $codeCluster;
}
if ($departement) {
$sql .= " AND c.code_cluster LIKE :prefix";
$params['prefix'] = $departement . '-%';
}
if ($codeInsee) {
$sql .= " AND p.code_insee = :codeInsee";
$params['codeInsee'] = $codeInsee;
}
if ($perid) {
$sql .= " AND p.login_vendeur_init = :perid";
$params['perid'] = $perid;
}
if ($category) {
$categoryArray = is_string($category)
? array_filter(array_map('intval', explode(',', $category)), fn($id) => $id > 0)
: [];
if (!empty($categoryArray)) {
$sql .= " AND p.category_id IN (" . implode(',', $categoryArray) . ")";
}
}
if (is_array($childs) && count($childs) > 0) {
$sql .= " AND p.seller_id IN (" . implode(',', $childs) . ")";
}
// GROUP BY dynamique
if ($organisationId) {
$sql .= " GROUP BY po.id, $dateCol ORDER BY po.id, $dateCol ASC";
} else {
$sql .= " GROUP BY $dateCol ORDER BY $dateCol ASC";
}
// --- Exécution ---
$stmt = $conn->executeQuery($sql, $params);
$results = $stmt->fetchAllAssociative();
// --- Réorganisation du résultat ---
$data = [];
foreach ($results as $row) {
$mois = (int)$row['mois'];
$semaine = (int)$row['semaine'];
$jour = $row['dateStat'];
$total = (int)$row['total_ventes_ko'];
if ($organisationId) {
$codePoint = $row['code_point'];
// Initialiser les sous-tableaux
if (!isset($data['parMois'][$codePoint])) {
$data['parMois'][$codePoint] = [];
}
if (!isset($data['parSemaine'][$codePoint])) {
$data['parSemaine'][$codePoint] = [];
}
if (!isset($data['parJour'][$codePoint])) {
$data['parJour'][$codePoint] = [];
}
// Agrégations
$data['parMois'][$codePoint][$mois] = ($data['parMois'][$codePoint][$mois] ?? 0) + $total;
$data['parSemaine'][$codePoint][$semaine] = ($data['parSemaine'][$codePoint][$semaine] ?? 0) + $total;
// Par jour → mois courant et précédent uniquement
if ($mois === $moisActuel || $mois === $moisPrecedent) {
$data['parJour'][$codePoint][$jour] = $total;
}
} else {
// Cas sans organisation : structure simple
$data['parMois'][$mois] = ($data['parMois'][$mois] ?? 0) + $total;
$data['parSemaine'][$semaine] = ($data['parSemaine'][$semaine] ?? 0) + $total;
if ($mois === $moisActuel || $mois === $moisPrecedent) {
$data['parJour'][$jour] = $total;
}
}
}
return $data;
}
public function getVentesKOByPeriod(
$pointOfSale,
$codeCluster,
$departement,
$codeInsee,
int $annee,
string $optionSelect,
$etatKO,
$category,
$childs,
$organisationId,
$perid,
string $periode = 'month'
): array {
$conn = $this->getEntityManager()->getConnection();
// Sélection de la date
switch ($optionSelect) {
case 'R':
$dateCol = 'p.date_racc';
break;
case 'B':
$dateCol = 'p.date_cmd_a';
break;
case 'V':
default:
$dateCol = 'p.date_vente_valid_b';
break;
}
switch ($periode) {
case 'week':
$selectGroup = "WEEK($dateCol, 1) AS periode";
break;
case 'day':
$selectGroup = "DATE($dateCol) AS periode";
break;
default:
$selectGroup = "MONTH($dateCol) AS periode";
break;
}
$sql = "
SELECT
$selectGroup,
COUNT(p.id) AS total_ventes_ko
";
if ($organisationId) {
$sql .= ", po.code AS code_point, po.name AS nom_point";
}
$sql .= "
FROM production p
LEFT JOIN point_of_sale po ON p.point_of_sale_id = po.id
LEFT JOIN cluster c ON p.cluster_id = c.id
WHERE YEAR($dateCol) = :annee
AND p.etat_id = :etatKO
";
$params = ['annee' => $annee, 'etatKO' => $etatKO->getId()];
if ($organisationId) {
$sql .= " AND p.organisation_id = :organisationId";
$params['organisationId'] = $organisationId;
} else {
$sql .= " AND p.point_of_sale_id = :pointOfSale";
$params['pointOfSale'] = $pointOfSale->getId();
}
if ($codeCluster) {
$sql .= " AND c.code_cluster = :codeCluster";
$params['codeCluster'] = $codeCluster;
}
if ($departement) {
$sql .= " AND c.code_cluster LIKE :prefix";
$params['prefix'] = $departement . '-%';
}
if ($codeInsee) {
$sql .= " AND p.code_insee = :codeInsee";
$params['codeInsee'] = $codeInsee;
}
if ($perid) {
$sql .= " AND p.login_vendeur_init = :perid";
$params['perid'] = $perid;
}
if ($category) {
$categoryArray = is_string($category)
? array_filter(array_map('intval', explode(',', $category)), fn($id) => $id > 0)
: [];
if (!empty($categoryArray)) {
$sql .= " AND p.category_id IN (" . implode(',', $categoryArray) . ")";
}
}
if (is_array($childs) && count($childs) > 0) {
$sql .= " AND p.seller_id IN (" . implode(',', $childs) . ")";
}
if ($organisationId) {
$sql .= " GROUP BY po.id, periode ORDER BY po.id, periode ASC";
} else {
$sql .= " GROUP BY periode ORDER BY periode ASC";
}
$stmt = $conn->executeQuery($sql, $params);
$results = $stmt->fetchAllAssociative();
$data = [];
foreach ($results as $row) {
$periodeKey = $row['periode'];
$total = (int)$row['total_ventes_ko'];
if ($organisationId) {
$codePoint = $row['code_point'];
if (!isset($data[$codePoint])) {
$data[$codePoint] = [];
}
$data[$codePoint][$periodeKey] = $total;
} else {
$data[$periodeKey] = $total;
}
}
return $data;
}
public function getEtpByPeriod(
$pointOfSale,
$codeCluster,
$departement,
$codeInsee,
int $annee,
string $optionSelect,
$etat,
$category,
$childs,
$organisationId,
$perid,
string $periode = 'month' // 'day' | 'week' | 'month'
): array {
$conn = $this->getEntityManager()->getConnection();
// Choix de la colonne date
switch ($optionSelect) {
case 'R':
$dateCol = 'p.date_racc';
break;
case 'B':
$dateCol = 'p.date_cmd_a';
break;
case 'V':
default:
$dateCol = 'p.date_vente_valid_b';
}
// Début SQL
$selectGroup = '';
switch ($periode) {
case 'week':
$selectGroup = "WEEK($dateCol, 1) AS periode";
break;
case 'day':
$selectGroup = "DATE($dateCol) AS periode";
break;
case 'month':
default:
$selectGroup = "MONTH($dateCol) AS periode";
break;
}
$sql = "
SELECT
$selectGroup,
COUNT(p.id) / NULLIF(COUNT(DISTINCT p.seller_id), 0) AS etp
";
if ($organisationId) {
$sql .= ",
po.code AS code_point,
po.name AS nom_point
";
}
$sql .= "
FROM production p
LEFT JOIN point_of_sale po ON p.point_of_sale_id = po.id
LEFT JOIN cluster c ON p.cluster_id = c.id
WHERE YEAR($dateCol) = :annee
";
$params = ['annee' => $annee];
// Conditions dynamiques
if ($organisationId) {
$sql .= " AND p.organisation_id = :organisationId";
$params['organisationId'] = $organisationId;
} else {
$sql .= " AND p.point_of_sale_id = :pointOfSale";
$params['pointOfSale'] = $pointOfSale->getId();
}
if ($codeCluster) {
$sql .= " AND c.code_cluster = :codeCluster";
$params['codeCluster'] = $codeCluster;
}
if ($departement) {
$sql .= " AND c.code_cluster LIKE :prefix";
$params['prefix'] = $departement . '-%';
}
if ($codeInsee) {
$sql .= " AND p.code_insee = :codeInsee";
$params['codeInsee'] = $codeInsee;
}
if ($perid) {
$sql .= " AND p.login_vendeur_init = :perid";
$params['perid'] = $perid;
}
if ($etat === "Raccorde") {
$sql .= " AND p.etat_id = 1";
} elseif ($etat === "Raccorde_mobile") {
$sql .= " AND p.category_id IN (31,32,33) AND p.date_racc IS NOT NULL";
}
if ($category) {
$categoryArray = is_string($category)
? array_filter(array_map('intval', explode(',', $category)), fn($id) => $id > 0)
: [];
if (!empty($categoryArray)) {
$sql .= " AND p.category_id IN (" . implode(',', $categoryArray) . ")";
}
}
if (is_array($childs) && count($childs) > 0) {
$sql .= " AND p.seller_id IN (" . implode(',', $childs) . ")";
}
// Group by selon la période
if ($organisationId) {
$sql .= " GROUP BY po.id, periode ORDER BY po.id, periode ASC";
} else {
$sql .= " GROUP BY periode ORDER BY periode ASC";
}
// Exécution
$stmt = $conn->executeQuery($sql, $params);
$results = $stmt->fetchAllAssociative();
// Résultat final
$data = [];
foreach ($results as $row) {
$periodeKey = $row['periode'];
$etp = (float)$row['etp'];
if ($organisationId) {
$codePoint = $row['code_point'];
if (!isset($data[$codePoint])) {
$data[$codePoint] = [];
}
$data[$codePoint][$periodeKey] = round($etp, 2);
} else {
$data[$periodeKey] = round($etp, 2);
}
}
return $data;
}
public function get4PByPeriod(
$pointOfSale,
$codeCluster,
$departement,
$codeInsee,
int $annee,
$optionSelect,
$etat,
$filtre,
$childs,
?int $organisationId,
$perid,
string $periode = 'month' // week | month | day
): array {
$conn = $this->getEntityManager()->getConnection();
$now = new \DateTime();
$moisActuel = (int)$now->format('n');
$moisPrecedent = (int)((clone $now)->modify('-1 month')->format('n'));
// Déterminer la période et alias
switch (strtolower($periode)) {
case 'day':
$groupField = 'DATE(result.date_cmd_a)';
$alias = 'jour';
break;
case 'month':
$groupField = 'MONTH(result.date_cmd_a)';
$alias = 'mois';
break;
case 'week':
default:
$groupField = 'WEEK(result.date_cmd_a, 3)';
$alias = 'semaine';
break;
}
$params = [
'annee' => $annee,
'cat1' => 32,
'cat2' => 31,
'moisPrecedent' => $moisPrecedent,
'moisActuel' => $moisActuel
];
// Filtrage selon organisation ou point de vente
$pointOrOrg = $organisationId ? 'organisation_id = :organisationId' : 'point_of_sale_id = :pointOfSale';
if ($organisationId) {
$params['organisationId'] = $organisationId;
} else {
$params['pointOfSale'] = is_object($pointOfSale) ? $pointOfSale->getId() : $pointOfSale;
}
// Sélection et groupement conditionnel par point de vente
$selectPosFields = '';
$groupByPos = '';
$joinPos = '';
if ($organisationId) {
$selectPosFields = ', result.point_of_sale_id, pos.code AS point_of_sale_code';
$groupByPos = ', result.point_of_sale_id, pos.code';
$joinPos = 'LEFT JOIN point_of_sale pos ON pos.id = result.point_of_sale_id';
}
// Sous-requête UNION combinée
$sql = "
SELECT COUNT(DISTINCT result.titulaire_email) AS total,
$groupField AS $alias
$selectPosFields
FROM (
SELECT p1.titulaire_email, p1.date_cmd_a, p1.point_of_sale_id
FROM production p1
LEFT JOIN cluster c1 ON p1.cluster_id = c1.id
WHERE p1.category_id = :cat1
AND YEAR(p1.date_cmd_a) = :annee
AND $pointOrOrg
";
if (strtolower($periode) === 'day') {
$sql .= " AND MONTH(p1.date_cmd_a) IN (:moisPrecedent, :moisActuel)";
}
$sql .= " AND p1.titulaire_email IN (
SELECT DISTINCT p_sub1.titulaire_email
FROM production p_sub1
WHERE p_sub1.category_id = 1
AND YEAR(p_sub1.date_cmd_a) = :annee
AND $pointOrOrg
)";
if ($codeCluster) {
$sql .= " AND c1.code_cluster = :codeCluster";
$params["codeCluster"] = $codeCluster;
}
if ($departement) {
$sql .= " AND c1.code_cluster LIKE :prefix";
$params['prefix'] = $departement . '-%';
}
if ($codeInsee) {
$sql .= " AND p1.code_insee = :codeInsee";
$params["codeInsee"] = $codeInsee;
}
if ($perid) {
$sql .= " AND p1.login_vendeur_init = :perid";
$params["perid"] = $perid;
}
if (!empty($childs)) {
$placeholders = [];
foreach ($childs as $i => $child) {
$key = 'child_' . $i;
$placeholders[] = ':' . $key;
$params[$key] = $child;
}
$sql .= " AND p1.seller_id IN (" . implode(',', $placeholders) . ")";
}
// UNION partie 2
$sql .= "
UNION
SELECT p2.titulaire_email, p2.date_cmd_a, p2.point_of_sale_id
FROM production p2
LEFT JOIN cluster c2 ON p2.cluster_id = c2.id
WHERE p2.category_id = :cat2
AND YEAR(p2.date_cmd_a) = :annee
AND $pointOrOrg
";
if (strtolower($periode) === 'day') {
$sql .= " AND MONTH(p2.date_cmd_a) IN (:moisPrecedent, :moisActuel)";
}
$sql .= " AND p2.titulaire_email IN (
SELECT DISTINCT p_sub2.titulaire_email
FROM production p_sub2
WHERE p_sub2.category_id IN (1,3)
AND YEAR(p_sub2.date_cmd_a) = :annee
AND $pointOrOrg
)";
if ($codeCluster) $sql .= " AND c2.code_cluster = :codeCluster";
if ($departement) {
$sql .= " AND c2.code_cluster LIKE :prefix";
}
if ($codeInsee) $sql .= " AND p2.code_insee = :codeInsee";
if ($perid) $sql .= " AND p2.login_vendeur_init = :perid";
if (!empty($childs)) {
$placeholders = [];
foreach ($childs as $i => $child) {
$key = 'child2_' . $i;
$placeholders[] = ':' . $key;
$params[$key] = $child;
}
$sql .= " AND p2.seller_id IN (" . implode(',', $placeholders) . ")";
}
$sql .= ") AS result
$joinPos
GROUP BY $groupField $groupByPos
ORDER BY $alias
";
$stmt = $conn->prepare($sql);
$rawResult = $stmt->executeQuery($params)->fetchAllAssociative();
// Mapping final : [période => code_point => total]
$formatted = [];
foreach ($rawResult as $item) {
switch (strtolower($periode)) {
case 'day':
$key = substr($item['jour'], 0, 10);
break;
case 'week':
$key = (int)$item['semaine'];
break;
case 'month':
default:
$key = (int)$item['mois'];
break;
}
if ($organisationId) {
$posCode = $item['point_of_sale_code'] ?? 'UNKNOWN';
$formatted[$posCode][$key] = (int)$item['total'];
} else {
$formatted[$key] = (int)$item['total'];
}
}
return $formatted;
}
public function get4PCByPeriod(
$pointOfSale,
$codeCluster,
$departement,
$codeInsee,
$annee,
$optionSelect,
$etatKO,
$category,
$option,
$childs,
$organisationId,
$perid,
string $periode = 'month' // day | week | month
): array {
$conn = $this->getEntityManager()->getConnection();
$where = [];
$params = [];
// --- Filtre organisation ou point de vente ---
if ($organisationId) {
$where[] = 'p.organisation_id = :organisationId';
$params['organisationId'] = $organisationId;
} elseif ($pointOfSale !== null) {
$where[] = 'p.point_of_sale_id = :pointOfSale';
$params['pointOfSale'] = is_object($pointOfSale) ? $pointOfSale->getId() : $pointOfSale;
}
if ($codeCluster !== null) {
$where[] = 'c.code_cluster = :codeCluster';
$params['codeCluster'] = $codeCluster;
}
if ($departement) {
$where[] = " c.code_cluster LIKE :prefix";
$params['prefix'] = $departement . '-%';
}
if ($codeInsee) {
$where[] = 'p.code_insee = :codeInsee';
$params['codeInsee'] = $codeInsee;
}
if ($perid) {
$where[] = 'p.login_vendeur_init = :perid';
$params['perid'] = $perid;
}
if ($annee !== null) {
$where[] = 'YEAR(p.date_cmd_a) = :annee';
$params['annee'] = $annee;
}
if (is_array($childs) && count($childs) > 0) {
$placeholders = [];
foreach ($childs as $i => $child) {
$placeholder = ':child_' . $i;
$placeholders[] = $placeholder;
$params['child_' . $i] = $child;
}
$where[] = 'p.seller_id IN (' . implode(', ', $placeholders) . ')';
}
if (empty($where)) {
$where[] = '1=1';
}
// --- Sélection selon la période ---
$select = 'COUNT(DISTINCT p.titulaire_email) AS total';
$groupBy = '';
$alias = '';
switch (strtolower($periode)) {
case 'month':
$select .= ', MONTH(p.date_cmd_a) AS mois';
$groupBy = 'MONTH(p.date_cmd_a)';
$alias = 'mois';
break;
case 'day':
$select .= ', p.date_cmd_a AS dateJour, MONTH(p.date_cmd_a) AS mois';
$groupBy = 'p.date_cmd_a';
$alias = 'dateJour';
break;
case 'week':
default:
$select .= ', WEEK(p.date_cmd_a, 3) AS semaine';
$groupBy = 'WEEK(p.date_cmd_a, 3)';
$alias = 'semaine';
break;
}
// --- Option spécifique chainage ---
if ($option === 'chainage') {
$where[] = 'p.fixe_chainage IS NOT NULL';
if (!empty($category)) {
$categoryArray = array_filter(
array_map('intval', explode(',', $category)),
fn($id) => $id > 0
);
if (!empty($categoryArray)) {
$placeholders = [];
foreach ($categoryArray as $k => $catId) {
$key = 'cat' . $k;
$placeholders[] = ':' . $key;
$params[$key] = $catId;
}
$where[] = 'p.category_id IN (' . implode(',', $placeholders) . ')';
}
}
}
// --- Construction du SQL ---
$sql = "
SELECT $select
";
if ($organisationId) {
$sql .= ",
po.code AS code_point,
po.name AS nom_point
";
}
$sql .= "
FROM production p
LEFT JOIN point_of_sale po ON po.id = p.point_of_sale_id
LEFT JOIN cluster c ON c.id = p.cluster_id
WHERE " . implode(' AND ', $where) . "
";
// --- Groupement ---
if ($organisationId) {
$sql .= " GROUP BY po.id, $groupBy ORDER BY po.id, $groupBy";
} else {
$sql .= " GROUP BY $groupBy ORDER BY $groupBy";
}
$stmt = $conn->prepare($sql);
$results = $stmt->executeQuery($params)->fetchAllAssociative();
// --- Limiter aux 2 derniers mois si 'day' ---
if (strtolower($periode) === 'day') {
$currentMonth = (int)date('m');
$previousMonth = $currentMonth === 1 ? 12 : $currentMonth - 1;
$results = array_filter($results, function ($row) use ($currentMonth, $previousMonth) {
return ((int)$row['mois'] === $currentMonth || (int)$row['mois'] === $previousMonth);
});
}
// --- Réorganisation du résultat ---
$mappedResults = [];
foreach ($results as $row) {
$total = (int)$row['total'];
if ($organisationId) {
$codePoint = $row['code_point'] ?? 'N/A';
if (!isset($mappedResults[$codePoint])) {
$mappedResults[$codePoint] = [];
}
switch (strtolower($periode)) {
case 'day':
$mappedResults[$codePoint][$row['dateJour']] = $total;
break;
case 'week':
$mappedResults[$codePoint][$row['semaine']] = $total;
break;
case 'month':
default:
$mappedResults[$codePoint][$row['mois']] = $total;
break;
}
} else {
switch (strtolower($periode)) {
case 'day':
$mappedResults[$row['dateJour']] = $total;
break;
case 'week':
$mappedResults[$row['semaine']] = $total;
break;
case 'month':
default:
$mappedResults[$row['mois']] = $total;
break;
}
}
}
return $mappedResults;
}
public function getJ30ByPeriod(
$pointOfSale,
$codeCluster,
$departement,
$codeInsee,
$annee,
$optionSelect,
$etat,
$category,
$childs,
$organisationId,
$perid,
string $periode = 'month' // day | week | month
): array {
$conn = $this->getEntityManager()->getConnection();
$where = [];
$params = [];
// --- Filtres de base ---
if ($organisationId) {
$where[] = 'p.organisation_id = :organisationId';
$params['organisationId'] = $organisationId;
} elseif ($pointOfSale !== null) {
$where[] = 'p.point_of_sale_id = :pointOfSale';
$params['pointOfSale'] = is_object($pointOfSale) ? $pointOfSale->getId() : $pointOfSale;
}
if ($codeCluster) {
$where[] = 'c.code_cluster = :codeCluster';
$params['codeCluster'] = $codeCluster;
}
if ($departement) {
$where[] = " c.code_cluster LIKE :prefix";
$params['prefix'] = $departement . '-%';
}
if ($codeInsee) {
$where[] = 'p.code_insee = :codeInsee';
$params['codeInsee'] = $codeInsee;
}
if ($perid) {
$where[] = 'p.login_vendeur_init = :perid';
$params['perid'] = $perid;
}
if (is_array($childs) && count($childs) > 0) {
$placeholders = [];
foreach ($childs as $i => $child) {
$placeholder = ':child_' . $i;
$placeholders[] = $placeholder;
$params['child_' . $i] = $child;
}
$where[] = 'p.seller_id IN (' . implode(', ', $placeholders) . ')';
}
// --- Conditions fixes ---
$where[] = 'p.date_resiliation IS NOT NULL';
$where[] = 'p.date_racc IS NOT NULL';
$where[] = 'DATEDIFF(p.date_racc, p.date_resiliation) > -31';
if ($etat === "Raccorde") {
$where[] = '(p.category_id IN (1,3) OR p.product_id IN (150, 262, 264, 266, 334, 335, 341, 344, 345, 379))';
} else {
$where[] = 'p.category_id NOT IN (2, 31, 32, 33)';
}
// --- Champ de date selon optionSelect ---
switch ($optionSelect) {
case 'V':
$dateField = 'p.date_vente_valid_b';
break;
case 'R':
$dateField = 'p.date_racc';
break;
case 'B':
default:
$dateField = 'p.date_cmd_a';
break;
}
// --- SELECT selon la période ---
switch (strtolower($periode)) {
case 'day':
$selectField = "DATE($dateField) AS dateJour, MONTH($dateField) AS mois";
$alias = 'dateJour';
$groupBy = 'dateJour';
break;
case 'week':
$selectField = "WEEK($dateField,3) AS semaine";
$alias = 'semaine';
$groupBy = 'semaine';
break;
case 'month':
default:
$selectField = "MONTH($dateField) AS mois";
$alias = 'mois';
$groupBy = 'mois';
break;
}
// --- Construction du SQL ---
$sql = "
SELECT COUNT(DISTINCT p.id) AS total_vente, $selectField
";
if ($organisationId) {
$sql .= ",
po.code AS code_point,
po.name AS nom_point
";
}
$sql .= "
FROM production p
LEFT JOIN point_of_sale po ON p.point_of_sale_id = po.id
LEFT JOIN cluster c ON p.cluster_id = c.id
WHERE " . implode(' AND ', $where) . "
AND YEAR($dateField) = :annee
";
if ($organisationId) {
$sql .= " GROUP BY po.id, $groupBy ORDER BY po.id, $groupBy";
} else {
$sql .= " GROUP BY $groupBy ORDER BY $groupBy";
}
$params['annee'] = $annee;
$stmt = $conn->prepare($sql);
$results = $stmt->executeQuery($params)->fetchAllAssociative();
// --- Limiter par jour aux deux derniers mois ---
if (strtolower($periode) === 'day') {
$currentMonth = (int)date('m');
$previousMonth = $currentMonth === 1 ? 12 : $currentMonth - 1;
$results = array_values(array_filter($results, function ($row) use ($currentMonth, $previousMonth) {
return ((int)$row['mois'] === $currentMonth || (int)$row['mois'] === $previousMonth);
}));
}
// --- Réorganisation du résultat ---
$mappedResults = [];
foreach ($results as $row) {
$total = (int)$row['total_vente'];
if ($organisationId) {
$codePoint = $row['code_point'] ?? 'N/A';
if (!isset($mappedResults[$codePoint])) {
$mappedResults[$codePoint] = [];
}
switch (strtolower($periode)) {
case 'day':
$mappedResults[$codePoint][$row['dateJour']] = $total;
break;
case 'week':
$mappedResults[$codePoint][$row['semaine']] = $total;
break;
case 'month':
default:
$mappedResults[$codePoint][$row['mois']] = $total;
break;
}
} else {
switch (strtolower($periode)) {
case 'day':
$mappedResults[$row['dateJour']] = $total;
break;
case 'week':
$mappedResults[$row['semaine']] = $total;
break;
case 'month':
default:
$mappedResults[$row['mois']] = $total;
break;
}
}
}
return $mappedResults;
}
public function getJ30MobileByPeriod(
$pointOfSale,
$codeCluster,
$departement,
$codeInsee,
$annee,
$optionSelect,
$etat,
$category,
$childs,
$organisationId,
$perid,
string $periode = 'month' // day | week | month
): array {
$conn = $this->getEntityManager()->getConnection();
$where = [];
$params = [];
// --- Filtre organisation ou point de vente ---
if ($organisationId) {
$where[] = 'p.organisation_id = :organisationId';
$params['organisationId'] = $organisationId;
} elseif ($pointOfSale !== null) {
$where[] = 'p.point_of_sale_id = :pointOfSale';
$params['pointOfSale'] = is_object($pointOfSale) ? $pointOfSale->getId() : $pointOfSale;
}
if ($codeCluster) {
$where[] = 'c.code_cluster = :codeCluster';
$params['codeCluster'] = $codeCluster;
}
if ($departement) {
$where[] = " c.code_cluster LIKE :prefix";
$params['prefix'] = $departement . '-%';
}
if ($codeInsee) {
$where[] = 'p.code_insee = :codeInsee';
$params['codeInsee'] = $codeInsee;
}
if ($perid) {
$where[] = 'p.login_vendeur_init = :perid';
$params['perid'] = $perid;
}
if (is_array($childs) && count($childs) > 0) {
$placeholders = [];
foreach ($childs as $i => $child) {
$placeholder = ':child_' . $i;
$placeholders[] = $placeholder;
$params['child_' . $i] = $child;
}
$where[] = 'p.seller_id IN (' . implode(', ', $placeholders) . ')';
}
// --- Conditions fixes ---
$where[] = 'p.date_resiliation IS NOT NULL';
$where[] = 'p.date_racc IS NOT NULL';
$where[] = 'DATEDIFF(p.date_racc, p.date_resiliation) > -31';
$where[] = 'p.category_id IN (31, 32, 33)';
if ($etat === "Raccorde_mobile") {
$where[] = 'p.product_id NOT IN (150,262,264,266,334,335,341,344,345,379)';
}
// --- Champ de date selon optionSelect ---
switch ($optionSelect) {
case 'V':
$dateField = 'p.date_vente_valid_b';
break;
case 'R':
$dateField = 'p.date_racc';
break;
case 'B':
default:
$dateField = 'p.date_cmd_a';
break;
}
// --- Sélection et groupement selon la période ---
switch (strtolower($periode)) {
case 'day':
$selectField = "DATE($dateField) AS dateJour, MONTH($dateField) AS mois";
$alias = 'dateJour';
$groupBy = 'dateJour';
break;
case 'week':
$selectField = "WEEK($dateField,3) AS semaine";
$alias = 'semaine';
$groupBy = 'semaine';
break;
case 'month':
default:
$selectField = "MONTH($dateField) AS mois";
$alias = 'mois';
$groupBy = 'mois';
break;
}
// --- Construction du SQL ---
$sql = "
SELECT COUNT(DISTINCT p.id) AS total_vente, $selectField
";
if ($organisationId) {
$sql .= ",
po.code AS code_point,
po.name AS nom_point
";
}
$sql .= "
FROM production p
LEFT JOIN point_of_sale po ON p.point_of_sale_id = po.id
LEFT JOIN cluster c ON p.cluster_id = c.id
WHERE " . implode(' AND ', $where) . "
AND YEAR($dateField) = :annee
";
if ($organisationId) {
$sql .= " GROUP BY po.id, $groupBy ORDER BY po.id, $groupBy";
} else {
$sql .= " GROUP BY $groupBy ORDER BY $groupBy";
}
$params['annee'] = $annee;
$stmt = $conn->prepare($sql);
$results = $stmt->executeQuery($params)->fetchAllAssociative();
// --- Limiter les jours aux deux derniers mois ---
if (strtolower($periode) === 'day') {
$currentMonth = (int)date('m');
$previousMonth = $currentMonth === 1 ? 12 : $currentMonth - 1;
$results = array_values(array_filter($results, function ($row) use ($currentMonth, $previousMonth) {
return ((int)$row['mois'] === $currentMonth || (int)$row['mois'] === $previousMonth);
}));
}
// --- Réorganisation des résultats ---
$mappedResults = [];
foreach ($results as $row) {
$total = (int)$row['total_vente'];
if ($organisationId) {
$codePoint = $row['code_point'] ?? 'N/A';
if (!isset($mappedResults[$codePoint])) {
$mappedResults[$codePoint] = [];
}
switch (strtolower($periode)) {
case 'day':
$mappedResults[$codePoint][$row['dateJour']] = $total;
break;
case 'week':
$mappedResults[$codePoint][$row['semaine']] = $total;
break;
case 'month':
default:
$mappedResults[$codePoint][$row['mois']] = $total;
break;
}
} else {
switch (strtolower($periode)) {
case 'day':
$mappedResults[$row['dateJour']] = $total;
break;
case 'week':
$mappedResults[$row['semaine']] = $total;
break;
case 'month':
default:
$mappedResults[$row['mois']] = $total;
break;
}
}
}
return $mappedResults;
}
public function getMrzByPeriod(
$pointOfSale,
$codeCluster,
$departement,
$codeInsee,
$annee,
$optionSelect,
$filtre,
$childs,
$organisationId,
$perid,
string $periode = 'month' // day | week | month
): array {
$conn = $this->getEntityManager()->getConnection();
$where = [];
$params = [];
// --- Filtre organisation ou point de vente ---
if ($organisationId) {
$where[] = 'p.organisation_id = :organisationId';
$params['organisationId'] = $organisationId;
} elseif ($pointOfSale !== null) {
$where[] = 'p.point_of_sale_id = :pointOfSale';
$params['pointOfSale'] = is_object($pointOfSale) ? $pointOfSale->getId() : $pointOfSale;
}
if ($codeCluster) {
$where[] = 'c.code_cluster = :codeCluster';
$params['codeCluster'] = $codeCluster;
}
if ($departement) {
$where[] = "c.code_cluster LIKE :prefix";
$params['prefix'] = $departement . '-%';
}
if ($codeInsee) {
$where[] = 'p.code_insee = :codeInsee';
$params['codeInsee'] = $codeInsee;
}
if (is_array($childs) && count($childs) > 0) {
$placeholders = [];
foreach ($childs as $i => $child) {
$placeholder = ':child_' . $i;
$placeholders[] = $placeholder;
$params['child_' . $i] = $child;
}
$where[] = 'p.seller_id IN (' . implode(', ', $placeholders) . ')';
}
if ($perid) {
$where[] = 'p.login_vendeur_init = :perid';
$params['perid'] = $perid;
}
$where[] = 'p.identity_ctrl IS NOT NULL';
// --- Choix du champ de date ---
switch ($optionSelect) {
case 'V':
$dateField = 'p.date_vente_valid_b';
break;
case 'R':
$dateField = 'p.date_racc';
break;
case 'B':
default:
$dateField = 'p.date_cmd_a';
break;
}
// --- Définition du SELECT selon la période ---
switch (strtolower($periode)) {
case 'day':
$selectField = "DATE($dateField)";
$alias = 'jour';
$startDate = (new \DateTime('first day of last month'))->format('Y-m-d');
$endDate = (new \DateTime('last day of this month'))->format('Y-m-d');
$where[] = "$dateField BETWEEN :startDate AND :endDate";
$params['startDate'] = $startDate;
$params['endDate'] = $endDate;
break;
case 'week':
$selectField = "WEEK($dateField, 3)";
$alias = 'semaine';
$where[] = "YEAR($dateField) = :annee";
$params['annee'] = $annee;
break;
case 'month':
default:
$selectField = "MONTH($dateField)";
$alias = 'mois';
$where[] = "YEAR($dateField) = :annee";
$params['annee'] = $annee;
break;
}
// --- Construction du SQL ---
$sql = "
SELECT
COUNT(p.id) AS total_vente,
p.identity_ctrl,
$selectField AS $alias
";
if ($organisationId) {
$sql .= ",
po.code AS code_point,
po.name AS nom_point
";
}
$sql .= "
FROM production p
LEFT JOIN point_of_sale po ON p.point_of_sale_id = po.id
LEFT JOIN cluster c ON p.cluster_id = c.id
WHERE " . implode(' AND ', $where) . "
";
if ($organisationId) {
$sql .= " GROUP BY po.id, p.identity_ctrl, $selectField ORDER BY po.id, $selectField";
} else {
$sql .= " GROUP BY p.identity_ctrl, $selectField ORDER BY $selectField";
}
// --- Exécution ---
$stmt = $conn->prepare($sql);
$rows = $stmt->executeQuery($params)->fetchAllAssociative();
// --- Structuration du résultat ---
$structuredResult = [];
foreach ($rows as $row) {
$periodValue = $row[$alias];
$entry = [
'identity_ctrl' => $row['identity_ctrl'],
'total_vente' => (int)$row['total_vente']
];
if ($organisationId) {
$codePoint = $row['code_point'] ?? 'N/A';
if (!isset($structuredResult[$codePoint])) {
$structuredResult[$codePoint] = [];
}
if (!isset($structuredResult[$codePoint][$periodValue])) {
$structuredResult[$codePoint][$periodValue] = [];
}
$structuredResult[$codePoint][$periodValue][] = $entry;
} else {
if (!isset($structuredResult[$periodValue])) {
$structuredResult[$periodValue] = [];
}
$structuredResult[$periodValue][] = $entry;
}
}
return $structuredResult;
}
public function getClientsHorsMigByPeriod(
$pointOfSale,
$codeCluster,
$departement,
$codeInsee,
$annee,
$optionSelect,
$filtre,
$childs,
$organisationId,
$perid,
string $periode = 'month' // day | week | month
): array {
$conn = $this->getEntityManager()->getConnection();
$where = [];
$params = [];
// Filtre organisation ou pointOfSale
if ($organisationId) {
$where[] = 'p.organisation_id = :organisationId';
$params['organisationId'] = $organisationId;
} elseif ($pointOfSale !== null) {
$where[] = 'p.point_of_sale_id = :pointOfSale';
$params['pointOfSale'] = is_object($pointOfSale) ? $pointOfSale->getId() : $pointOfSale;
}
if ($codeCluster) {
$where[] = 'c.code_cluster = :codeCluster';
$params['codeCluster'] = $codeCluster;
}
if ($departement) {
$where[] = " c.code_cluster LIKE :prefix";
$params['prefix'] = $departement . '-%';
}
if ($codeInsee) {
$where[] = 'p.code_insee = :codeInsee';
$params['codeInsee'] = $codeInsee;
}
// child sellers
if (is_array($childs) && count($childs) > 0) {
$placeholders = [];
foreach ($childs as $i => $child) {
$placeholder = ':child_' . $i;
$placeholders[] = $placeholder;
$params['child_' . $i] = $child;
}
$where[] = 'p.seller_id IN (' . implode(', ', $placeholders) . ')';
}
// Conditions fixes
$where[] = 'p.category_id NOT IN (2)';
// Champ de date
$dateField = 'p.date_cmd_a';
// Sélection et groupement selon la période
switch (strtolower($periode)) {
case 'day':
$selectField = "DATE($dateField)";
$alias = 'jour';
$startDate = (new \DateTime('first day of last month'))->format('Y-m-d');
$endDate = (new \DateTime('last day of this month'))->format('Y-m-d');
$where[] = "$dateField BETWEEN :startDate AND :endDate";
$params['startDate'] = $startDate;
$params['endDate'] = $endDate;
break;
case 'week':
$selectField = "WEEK($dateField,3)";
$alias = 'semaine';
$where[] = "YEAR($dateField) = :annee";
$params['annee'] = $annee;
break;
case 'month':
default:
$selectField = "MONTH($dateField)";
$alias = 'mois';
$where[] = "YEAR($dateField) = :annee";
$params['annee'] = $annee;
break;
}
$sql = "
SELECT
COUNT(DISTINCT p.titulaire_email) AS total_vente,
$selectField AS $alias
";
if ($organisationId) {
$sql .= ",
po.code AS code_point,
po.name AS nom_point
";
}
$sql .= "
FROM production p
LEFT JOIN point_of_sale po ON p.point_of_sale_id = po.id
LEFT JOIN cluster c ON p.cluster_id = c.id
WHERE " . implode(' AND ', $where);
// GROUP BY selon présence organisationId
if ($organisationId) {
$sql .= " GROUP BY po.id, $selectField ORDER BY po.id, $selectField";
} else {
$sql .= " GROUP BY $selectField ORDER BY $selectField";
}
$stmt = $conn->prepare($sql);
$results = $stmt->executeQuery($params)->fetchAllAssociative();
// --- Structuration du résultat ---
$structuredResult = [];
foreach ($results as $row) {
$periodValue = $row[$alias];
$total = (int)$row['total_vente'];
if ($organisationId) {
$codePoint = $row['code_point'] ?? 'N/A';
if (!isset($structuredResult[$codePoint])) {
$structuredResult[$codePoint] = [];
}
$structuredResult[$codePoint][$periodValue] = $total;
} else {
$structuredResult[$periodValue] = $total;
}
}
return $structuredResult;
}
public function getProductionsAnalyticsTotalVenteByOptionByPeriod(
$pointOfSale,
?string $codeCluster,
$codeInsee,
int $annee,
array $childs,
?int $organisationId,
?string $optionCalcul,
?string $perid,
string $periode = 'month' // day | week | month
): array {
$conn = $this->getEntityManager()->getConnection();
$dateField = 'p.date_cmd_a'; // par défaut
switch ($periode) {
case 'day':
$groupField = "DATE($dateField)"; // date complète
$alias = 'parJour';
break;
case 'week':
$groupField = "WEEK($dateField,3)";
$alias = 'parSemaine';
break;
case 'month':
default:
$groupField = "MONTH($dateField)";
$alias = 'parMois';
break;
}
$sql = "
SELECT COUNT(DISTINCT p.id) AS total_vente, $groupField AS $alias
FROM production p
LEFT JOIN point_of_sale po ON p.point_of_sale_id = po.id
WHERE p.category_id IN (1,3)
AND YEAR($dateField) = :annee
";
$params = ['annee' => $annee];
// Limiter aux jours du mois courant et précédent si parJour
if ($periode === 'day') {
$sql .= " AND $dateField >= DATE_FORMAT(CURRENT_DATE - INTERVAL 1 MONTH, '%Y-%m-01')
AND $dateField <= LAST_DAY(CURRENT_DATE)";
}
if ($organisationId) {
$sql .= " AND p.organisation_id = :organisationId";
$params['organisationId'] = $organisationId;
} elseif ($pointOfSale !== null) {
$sql .= " AND p.point_of_sale_id = :pointOfSale";
$params['pointOfSale'] = is_object($pointOfSale) ? $pointOfSale->getId() : $pointOfSale;
}
if (!empty($childs)) {
$placeholders = [];
foreach ($childs as $i => $child) {
$key = ':child_' . $i;
$placeholders[] = $key;
$params['child_' . $i] = $child;
}
$sql .= " AND p.seller_id IN (" . implode(',', $placeholders) . ")";
}
if ($optionCalcul) {
switch ($optionCalcul) {
case 'RIO':
$sql .= " AND p.portabilite = 'OUI'";
break;
case 'PTO_SAISIE':
$sql .= " AND p.prise_saisie_commande = 'OUI'";
break;
case 'PTO_NON_SAISIE':
$sql .= " AND p.prise_saisie_commande = 'NON' AND p.prise_existante_commande = 'OUI'";
break;
case 'PTO_EXISTANTE':
$sql .= " AND p.prise_existante_commande = 'OUI'";
break;
case 'PTO_NON_EXISTANTE':
$sql .= " AND p.prise_existante_commande = 'NON'";
break;
}
if ($perid) {
$sql .= " AND p.login_vendeur_init = :perid";
$params['perid'] = $perid;
}
if ($codeCluster) {
$sql .= " AND c.code_cluster = :codeCluster";
$params['codeCluster'] = $codeCluster;
}
if ($codeInsee) {
$sql .= " AND p.code_insee = :codeInsee";
$params['codeInsee'] = $codeInsee;
}
}
$sql .= " GROUP BY $groupField ORDER BY $alias";
$stmt = $conn->prepare($sql);
return $stmt->executeQuery($params)->fetchAllAssociative();
}
public function getProductionsAnalyticsTotalVenteByOptionByPeriod2(
$pointOfSale,
?string $codeCluster,
$departement,
$codeInsee,
int $annee,
array $childs,
?int $organisationId,
?string $optionCalcul,
?string $perid,
string $periode = 'month' // day | week | month
): array {
$conn = $this->getEntityManager()->getConnection();
$dateField = 'p.date_cmd_a'; // par défaut
switch ($periode) {
case 'day':
$groupField = "DATE($dateField)";
$alias = 'parJour';
break;
case 'week':
$groupField = "WEEK($dateField,3)";
$alias = 'parSemaine';
break;
case 'month':
default:
$groupField = "MONTH($dateField)";
$alias = 'parMois';
break;
}
$sql = "SELECT COUNT(DISTINCT p.id) AS total_vente, $groupField AS $alias";
if ($organisationId) {
$sql .= ", po.code AS code_point, po.name AS nom_point";
}
$sql .= " FROM production p
LEFT JOIN point_of_sale po ON p.point_of_sale_id = po.id
LEFT JOIN cluster c ON p.cluster_id = c.id
WHERE p.category_id IN (1,3)
AND YEAR($dateField) = :annee";
$params = ['annee' => $annee];
if ($periode === 'day') {
$sql .= " AND $dateField >= DATE_FORMAT(CURRENT_DATE - INTERVAL 1 MONTH, '%Y-%m-01')
AND $dateField <= LAST_DAY(CURRENT_DATE)";
}
if ($organisationId) {
$sql .= " AND p.organisation_id = :organisationId";
$params['organisationId'] = $organisationId;
} elseif ($pointOfSale !== null) {
$sql .= " AND p.point_of_sale_id = :pointOfSale";
$params['pointOfSale'] = is_object($pointOfSale) ? $pointOfSale->getId() : $pointOfSale;
}
if (!empty($childs)) {
$placeholders = [];
foreach ($childs as $i => $child) {
$key = ':child_' . $i;
$placeholders[] = $key;
$params['child_' . $i] = $child;
}
$sql .= " AND p.seller_id IN (" . implode(',', $placeholders) . ")";
}
if ($optionCalcul) {
switch ($optionCalcul) {
case 'RIO':
$sql .= " AND p.portabilite = 'OUI'";
break;
case 'PTO_SAISIE':
$sql .= " AND p.prise_saisie_commande = 'OUI'";
break;
case 'PTO_NON_SAISIE':
$sql .= " AND p.prise_saisie_commande = 'NON' AND p.prise_existante_commande = 'OUI'";
break;
case 'PTO_EXISTANTE':
$sql .= " AND p.prise_existante_commande = 'OUI'";
break;
case 'PTO_NON_EXISTANTE':
$sql .= " AND p.prise_existante_commande = 'NON'";
break;
}
if ($perid) {
$sql .= " AND p.login_vendeur_init = :perid";
$params['perid'] = $perid;
}
if ($codeCluster) {
$sql .= " AND c.code_cluster = :codeCluster";
$params['codeCluster'] = $codeCluster;
}
if ($departement) {
$sql .= " AND c.code_cluster LIKE :prefix";
$params['prefix'] = $departement . '-%';
}
if ($codeInsee) {
$sql .= " AND p.code_insee = :codeInsee";
$params['codeInsee'] = $codeInsee;
}
}
// GROUP BY selon organisationId
if ($organisationId) {
$sql .= " GROUP BY po.id, $groupField ORDER BY po.id, $groupField";
} else {
$sql .= " GROUP BY $groupField ORDER BY $groupField";
}
$stmt = $conn->prepare($sql);
$results = $stmt->executeQuery($params)->fetchAllAssociative();
// Structuration
$structuredResult = [];
foreach ($results as $row) {
$periodValue = $row[$alias];
$total = (int)$row['total_vente'];
if ($organisationId) {
$codePoint = $row['code_point'] ?? 'N/A';
if (!isset($structuredResult[$codePoint])) {
$structuredResult[$codePoint] = [];
}
$structuredResult[$codePoint][$periodValue] = $total;
} else {
$structuredResult[$periodValue] = $total;
}
}
return $structuredResult;
}
public function getVentesVlaConqueteByPeriod(
$pointOfSale,
?string $codeCluster,
$codeInsee,
int $annee,
string $optionSelect,
?string $category,
array $childs = [],
?int $organisationId = null,
?string $perid = null,
string $periode = 'week' // day | week | month
): array {
$conn = $this->getEntityManager()->getConnection();
// Choix du champ date
switch ($optionSelect) {
case 'V':
$dateField = 'date_vente_valid_b';
break;
case 'R':
$dateField = 'date_racc';
break;
case 'B':
default:
$dateField = 'date_cmd_a';
break;
}
// Choix de la fonction de groupement
switch (strtolower($periode)) {
case 'day':
$groupField = "DATE(p.$dateField)"; // date complète
$alias = 'parJour';
break;
case 'month':
$groupField = "MONTH(p.$dateField)";
$alias = 'parMois';
break;
case 'week':
default:
$groupField = "WEEK(p.$dateField, 3)";
$alias = 'parSemaine';
break;
}
$sql = "
SELECT COUNT(p.id) AS total_ventes, $groupField AS $alias
FROM production p
LEFT JOIN cluster c ON p.cluster_id = c.id
WHERE YEAR(p.$dateField) = :annee
";
$params = ['annee' => $annee];
// Limiter aux jours du mois courant et précédent si parJour
if (strtolower($periode) === 'day') {
$sql .= " AND p.$dateField >= DATE_FORMAT(CURRENT_DATE - INTERVAL 1 MONTH, '%Y-%m-01')
AND p.$dateField <= LAST_DAY(CURRENT_DATE)";
}
// pointOfSale / organisation
if ($organisationId) {
$sql .= " AND p.organisation_id = :organisationId";
$params['organisationId'] = $organisationId;
} elseif ($pointOfSale !== null) {
$sql .= " AND p.point_of_sale_id = :pointOfSale";
$params['pointOfSale'] = is_object($pointOfSale) ? $pointOfSale->getId() : $pointOfSale;
}
// cluster
if ($codeCluster) {
$sql .= " AND c.code_cluster = :codeCluster";
$params['codeCluster'] = $codeCluster;
}
if ($codeInsee) {
$sql .= " AND p.code_insee = :codeInsee";
$params['codeInsee'] = $codeInsee;
}
// category
if ($category) {
$categoryArray = array_filter(array_map('intval', explode(',', $category)), fn($id) => $id > 0);
if (!empty($categoryArray)) {
$placeholders = [];
foreach ($categoryArray as $k => $catId) {
$key = 'cat' . $k;
$placeholders[] = ':' . $key;
$params[$key] = $catId;
}
$sql .= " AND p.category_id IN (" . implode(',', $placeholders) . ")";
}
}
// perid
if ($perid) {
$sql .= " AND p.login_vendeur_init = :perid";
$params['perid'] = $perid;
}
// childs
if (!empty($childs)) {
$placeholders = [];
foreach ($childs as $i => $child) {
$key = 'child_' . $i;
$placeholders[] = ':' . $key;
$params[$key] = $child;
}
$sql .= " AND p.seller_id IN (" . implode(',', $placeholders) . ")";
}
$sql .= " GROUP BY $groupField ORDER BY $alias";
$stmt = $conn->prepare($sql);
return $stmt->executeQuery($params)->fetchAllAssociative();
}
public function getVentesVlaConqueteByPeriod2(
$pointOfSale,
?string $codeCluster,
$departement,
$codeInsee,
int $annee,
string $optionSelect,
?string $category,
array $childs = [],
?int $organisationId = null,
?string $perid = null,
string $periode = 'week' // day | week | month
): array {
$conn = $this->getEntityManager()->getConnection();
// Choix du champ date
switch ($optionSelect) {
case 'V':
$dateField = 'date_vente_valid_b';
break;
case 'R':
$dateField = 'date_racc';
break;
case 'B':
default:
$dateField = 'date_cmd_a';
break;
}
// Choix de la fonction de groupement
switch (strtolower($periode)) {
case 'day':
$groupField = "DATE(p.$dateField)";
$alias = 'parJour';
break;
case 'month':
$groupField = "MONTH(p.$dateField)";
$alias = 'parMois';
break;
case 'week':
default:
$groupField = "WEEK(p.$dateField, 3)";
$alias = 'parSemaine';
break;
}
$sql = "SELECT COUNT(p.id) AS total_ventes, $groupField AS $alias";
if ($organisationId) {
$sql .= ", po.code AS code_point, po.name AS nom_point";
}
$sql .= " FROM production p
LEFT JOIN point_of_sale po ON p.point_of_sale_id = po.id
LEFT JOIN cluster c ON p.cluster_id = c.id
WHERE YEAR(p.$dateField) = :annee";
$params = ['annee' => $annee];
if (strtolower($periode) === 'day') {
$sql .= " AND p.$dateField >= DATE_FORMAT(CURRENT_DATE - INTERVAL 1 MONTH, '%Y-%m-01')
AND p.$dateField <= LAST_DAY(CURRENT_DATE)";
}
if ($organisationId) {
$sql .= " AND p.organisation_id = :organisationId";
$params['organisationId'] = $organisationId;
} elseif ($pointOfSale !== null) {
$sql .= " AND p.point_of_sale_id = :pointOfSale";
$params['pointOfSale'] = is_object($pointOfSale) ? $pointOfSale->getId() : $pointOfSale;
}
if ($codeCluster) {
$sql .= " AND c.code_cluster = :codeCluster";
$params['codeCluster'] = $codeCluster;
}
if ($departement) {
$sql .= " AND c.code_cluster LIKE :prefix";
$params['prefix'] = $departement . '-%';
}
if ($codeInsee) {
$sql .= " AND p.code_insee = :codeInsee";
$params['codeInsee'] = $codeInsee;
}
if ($category) {
$categoryArray = array_filter(array_map('intval', explode(',', $category)), fn($id) => $id > 0);
if (!empty($categoryArray)) {
$placeholders = [];
foreach ($categoryArray as $k => $catId) {
$key = 'cat' . $k;
$placeholders[] = ':' . $key;
$params[$key] = $catId;
}
$sql .= " AND p.category_id IN (" . implode(',', $placeholders) . ")";
}
}
if ($perid) {
$sql .= " AND p.login_vendeur_init = :perid";
$params['perid'] = $perid;
}
if (!empty($childs)) {
$placeholders = [];
foreach ($childs as $i => $child) {
$key = 'child_' . $i;
$placeholders[] = ':' . $key;
$params[$key] = $child;
}
$sql .= " AND p.seller_id IN (" . implode(',', $placeholders) . ")";
}
// GROUP BY selon organisationId
if ($organisationId) {
$sql .= " GROUP BY po.id, $groupField ORDER BY po.id, $groupField";
} else {
$sql .= " GROUP BY $groupField ORDER BY $groupField";
}
$stmt = $conn->prepare($sql);
$results = $stmt->executeQuery($params)->fetchAllAssociative();
// Structuration du résultat
$structuredResult = [];
foreach ($results as $row) {
$periodValue = $row[$alias];
$total = (int)$row['total_ventes'];
if ($organisationId) {
$codePoint = $row['code_point'] ?? 'N/A';
if (!isset($structuredResult[$codePoint])) {
$structuredResult[$codePoint] = [];
}
$structuredResult[$codePoint][$periodValue] = $total;
} else {
$structuredResult[$periodValue] = $total;
}
}
return $structuredResult;
}
public function getProjectionByPeriod(
$pointOfSale,
$codeCluster,
$departement,
$codeInsee,
$annee,
$optionSelect,
$category,
$childs,
$organisationId,
$perid,
string $periode = 'month' // day | week | month
): array {
$conn = $this->getEntityManager()->getConnection();
// Champ de date selon l'option
switch ($optionSelect) {
case 'V':
$dateField = 'p.date_vente_valid_b';
break;
case 'R':
$dateField = 'p.date_racc';
break;
case 'B':
default:
$dateField = 'p.date_cmd_a';
break;
}
$where = [];
$params = [];
// Filtres principaux
if ($organisationId) {
$where[] = 'p.organisation_id = :organisationId';
$params['organisationId'] = $organisationId;
} elseif ($pointOfSale !== null) {
$where[] = 'p.point_of_sale_id = :pointOfSale';
$params['pointOfSale'] = is_object($pointOfSale) ? $pointOfSale->getId() : $pointOfSale;
}
if ($codeCluster) {
$where[] = 'c.code_cluster = :codeCluster';
$params['codeCluster'] = $codeCluster;
}
if ($departement) {
$where[] = " c.code_cluster LIKE :prefix";
$params['prefix'] = $departement . '-%';
}
if ($codeInsee) {
$where[] = 'p.code_insee = :codeInsee';
$params['codeInsee'] = $codeInsee;
}
if ($perid) {
$where[] = 'p.login_vendeur_init = :perid';
$params['perid'] = $perid;
}
// Filtre catégories
if ($category) {
$categoryArray = array_filter(array_map('intval', explode(',', $category)), fn($id) => $id > 0);
if (!empty($categoryArray)) {
$placeholders = [];
foreach ($categoryArray as $i => $catId) {
$key = 'cat' . $i;
$placeholders[] = ':' . $key;
$params[$key] = $catId;
}
$where[] = 'p.category_id IN (' . implode(',', $placeholders) . ')';
}
}
// Filtre vendeurs enfants
if (is_array($childs) && count($childs) > 0) {
$placeholders = [];
foreach ($childs as $i => $child) {
$key = 'child_' . $i;
$placeholders[] = ':' . $key;
$params[$key] = $child;
}
$where[] = 'p.seller_id IN (' . implode(',', $placeholders) . ')';
}
// Select et group selon la période
switch (strtolower($periode)) {
case 'day':
$selectField = "DATE($dateField)";
$alias = 'jour';
$currentMonth = (int)date('n');
$previousMonth = (int)((new \DateTime('first day of last month'))->format('n'));
$where[] = "MONTH($dateField) IN (:currentMonth, :previousMonth)";
$params['currentMonth'] = $currentMonth;
$params['previousMonth'] = $previousMonth;
break;
case 'week':
$selectField = "WEEK($dateField, 3)";
$alias = 'semaine';
$where[] = "YEAR($dateField) = :annee";
$params['annee'] = $annee;
break;
case 'month':
default:
$selectField = "MONTH($dateField)";
$alias = 'mois';
$where[] = "YEAR($dateField) = :annee";
$params['annee'] = $annee;
break;
}
// Gestion point de vente
$selectPosFields = '';
$groupByExtra = '';
$joinPos = '';
if ($organisationId) {
$selectPosFields = ', pos.code AS point_of_sale_code, pos.name AS point_of_sale_name';
$groupByExtra = ', p.point_of_sale_id, pos.code, pos.name';
$joinPos = 'LEFT JOIN point_of_sale pos ON pos.id = p.point_of_sale_id';
}
// Requête principale optimisée
$sql = "
SELECT
$selectField AS $alias,
COUNT(DISTINCT p.id) AS ventes_realisees,
COUNT(DISTINCT CASE WHEN DAYOFWEEK($dateField) BETWEEN 2 AND 6 THEN DATE($dateField) END) AS jours_travail_effectues
$selectPosFields
FROM production p
LEFT JOIN cluster c ON c.id = p.cluster_id
$joinPos
WHERE " . implode(' AND ', $where) . "
AND DATE($dateField) <= CURDATE()
GROUP BY $alias $groupByExtra
ORDER BY $alias
";
$results = $conn->prepare($sql)->executeQuery($params)->fetchAllAssociative();
$final = [];
foreach ($results as &$row) {
$joursEffectues = (int)$row['jours_travail_effectues'];
$ventesParJour = $row['ventes_realisees'] / max($joursEffectues, 1);
// -------------------------
// Jours restants - version exacte que tu as donnée
// -------------------------
$joursRestants = 0;
if ($periode === 'month') {
$mois = $row[$alias];
$dateFinMois = new \DateTime();
$dateFinMois->setDate($annee, $mois, 1)->modify('last day of this month');
$currentDate = new \DateTime();
if ($dateFinMois > $currentDate) {
$interval = $currentDate->diff($dateFinMois);
for ($i = 0; $i <= $interval->days; $i++) {
$jourTemp = (clone $currentDate)->modify("+$i day");
if ($jourTemp->format('N') < 6) $joursRestants++;
}
}
// Ajouter 1 jour si aujourd'hui est le dernier jour du mois
if ($currentDate->format('t') == $currentDate->format('d')) {
$joursRestants++;
}
} elseif ($periode === 'week') {
$currentWeek = (int)date('W');
$joursRestants = max(0, 5 * max(0, $row[$alias] - $currentWeek));
}
$row['ventes_par_jour'] = $ventesParJour;
$row['jours_restants'] = $joursRestants;
$row['projection_ventes'] = ($ventesParJour * $joursRestants) + $row['ventes_realisees'];
if ($organisationId) {
$posCode = $row['point_of_sale_code'];
$final[$posCode][$row[$alias]] = round($row['projection_ventes'], 2);
} else {
$final[$row[$alias]] = round($row['projection_ventes'], 2);
}
}
return $final;
}
public function getVentesByPrisesNeuves($pointOfSaleId, $codeCluster = null, $codeInsee = null)
{
$conn = $this->getEntityManager()->getConnection();
$params = ['pointOfSaleId' => $pointOfSaleId];
// === Sous-requête PRISES (pn) ===
$wherePn = ['ps.id = :pointOfSaleId'];
if ($codeInsee !== null) {
$wherePn[] = 'pn.cod_insee = :codeInsee';
$params['codeInsee'] = $codeInsee;
}
if ($codeCluster !== null) {
$wherePn[] = 'pn.code_cluster = :codeCluster';
$params['codeCluster'] = $codeCluster;
}
$wherePnClause = implode(' AND ', $wherePn);
// === Sous-requête VENTES (pr + cluster) ===
$wherePr = ['pr.point_of_sale_id = :pointOfSaleId'];
if ($codeInsee !== null) {
$wherePr[] = 'pr.code_insee = :codeInsee';
}
if ($codeCluster !== null) {
$wherePr[] = 'c.code_cluster = :codeCluster';
}
$wherePrClause = implode(' AND ', $wherePr);
$sql = "
SELECT
p.annee,
p.mois_num,
p.mois,
SUM(p.nb_prises) AS nb_prises_recues,
COALESCE(SUM(v.nb_ventes), 0) AS nb_ventes_sur_prises_meme_mois
FROM (
SELECT
YEAR(pn.date_import_data) AS annee,
MONTH(pn.date_import_data) AS mois_num,
DATE_FORMAT(pn.date_import_data,'%Y-%m') AS mois,
pn.cod_hexc AS code_hexc,
COUNT(*) AS nb_prises
FROM nmd_adresses_incomming AS pn
JOIN point_of_sale AS ps ON ps.code = pn.cpv
WHERE $wherePnClause
GROUP BY annee, mois_num, mois, code_hexc
) AS p
LEFT JOIN (
SELECT
YEAR(pr.date_cmd_a) AS annee,
MONTH(pr.date_cmd_a) AS mois_num,
DATE_FORMAT(pr.date_cmd_a,'%Y-%m') AS mois,
pr.code_hexc AS code_hexc,
COUNT(DISTINCT pr.id) AS nb_ventes
FROM production AS pr
JOIN cluster AS c ON c.id = pr.cluster_id
WHERE $wherePrClause
GROUP BY annee, mois_num, mois, code_hexc
) AS v
ON v.mois = p.mois
AND v.code_hexc = p.code_hexc
GROUP BY p.annee, p.mois_num, p.mois
ORDER BY p.annee, p.mois_num;
";
// Préparation + exécution
$stmt = $conn->prepare($sql);
$result = $stmt->executeQuery($params);
$ventes = $result->fetchAllAssociative();
// Transformation hiérarchique
$ventesHierarchique = [];
foreach ($ventes as $ligne) {
$annee = $ligne['annee'];
$mois = $ligne['mois'];
if (!isset($ventesHierarchique[$annee])) {
$ventesHierarchique[$annee] = [];
}
$ventesHierarchique[$annee][$mois] = [
'nb_prises_recues' => $ligne['nb_prises_recues'],
'nb_ventes_sur_prises_meme_mois' => $ligne['nb_ventes_sur_prises_meme_mois'],
];
}
return $ventesHierarchique;
}
public function findVentesByTechByPeriod(
$pointOfSale,
$optionSelect,
$annee,
$periode, // "jour", "semaine" ou "mois"
$codeCluster,
$codeInsee,
$childs,
$organisationId
) {
$qb = $this->createQueryBuilder('p')
// Dénominateur : ventes selon optionSelect (B ou V)
->select('COUNT(p.id) as totalVentes, po.code as cpv, p.tech ')
// Numérateur : ventes avec date_racc
->addSelect('SUM(CASE WHEN p.dateRacc IS NOT NULL THEN 1 ELSE 0 END) as ventesRacc')
->leftJoin('p.pointOfSale', 'po');
if ($pointOfSale !== null) {
$qb->andWhere('p.pointOfSale = :pointOfSale')
->setParameter('pointOfSale', $pointOfSale);
}
// Champ de date pour filtrer l’année et la période
switch (strtoupper($optionSelect)) {
case 'V':
$dateField = 'p.dateVenteValidB';
break;
case 'B':
$dateField = 'p.dateCmdA';
break;
default:
$dateField = 'p.dateVenteValidB';
}
$qb->andWhere("YEAR($dateField) = :annee")
->setParameter('annee', $annee);
// Sélection dynamique selon la période
switch (strtolower($periode)) {
case 'jour':
$qb->addSelect("DATE_FORMAT($dateField, '%Y-%m-%d') as periode");
break;
case 'semaine':
$qb->addSelect("WEEK($dateField, 1) as periode");
break;
case 'mois':
default:
$qb->addSelect("DATE_FORMAT($dateField, '%Y-%m') as periode");
break;
}
// Filtres cluster, codeInsee, organisation, seller
if ($codeCluster) {
$qb->leftJoin('p.cluster', 'cluster')
->addSelect('cluster.codeCluster as clusterCode')
->andWhere('cluster.codeCluster = :codeCluster')
->setParameter('codeCluster', $codeCluster);
}
if ($codeInsee) {
$qb->addSelect('p.codeInsee')
->andWhere('p.codeInsee = :codeInsee')
->setParameter('codeInsee', $codeInsee);
}
if ($organisationId) {
$qb->andWhere('p.organisation = :organisationId')
->setParameter('organisationId', $organisationId);
}
if (is_array($childs) && count($childs) > 0) {
$qb->andWhere('p.seller IN (:childs)')
->leftJoin('p.seller', 's')
->setParameter('childs', $childs);
}
$qb->groupBy('po.code, p.tech, periode');
// Exécution de la requête
$results = $qb->getQuery()->getArrayResult();
// Calcul du taux_racc côté PHP
foreach ($results as &$row) {
$row['taux_racc'] = $row['totalVentes'] > 0
? ($row['ventesRacc'] / $row['totalVentes']) * 100
: 0;
}
return $results;
}
public function findVentesByProductByPeriod(
$pointOfSale,
$optionSelect,
$annee,
$periode, // "jour", "semaine" ou "mois"
$codeCluster,
$codeInsee,
$childs,
$organisationId
) {
// Sélection du champ date
switch (strtoupper($optionSelect)) {
case 'V':
$dateField = 'pr.date_vente_valid_b';
break;
case 'R':
$dateField = 'pr.date_racc';
break;
case 'B':
$dateField = 'pr.date_cmd_a';
break;
default:
$dateField = 'pr.date_vente_valid_b';
}
// Format de la période
switch (strtolower($periode)) {
case 'jour':
$periodeFormat = "DATE_FORMAT($dateField, '%Y-%m-%d')";
break;
case 'semaine':
$periodeFormat = "WEEK($dateField, 1)";
break;
case 'mois':
default:
$periodeFormat = "DATE_FORMAT($dateField, '%Y-%m')";
}
$conn = $this->getEntityManager()->getConnection();
// Filtres et paramètres
$whereFilters = ["YEAR($dateField) = :annee"];
$params = ['annee' => $annee];
$joinCluster = "";
if ($pointOfSale) {
$whereFilters[] = "pr.point_of_sale_id = :pointOfSale";
$params['pointOfSale'] = $pointOfSale->getId();
}
if ($organisationId) {
$whereFilters[] = "pr.organisation_id = :organisationId";
$params['organisationId'] = $organisationId;
}
if ($codeCluster) {
$joinCluster = "LEFT JOIN cluster clu ON clu.id = pr.cluster_id";
$whereFilters[] = "clu.code_cluster = :codeCluster";
$params['codeCluster'] = $codeCluster;
}
if ($codeInsee) {
$whereFilters[] = "pr.code_insee = :codeInsee";
$params['codeInsee'] = $codeInsee;
}
if (is_array($childs) && count($childs) > 0) {
$whereFilters[] = "pr.seller_id IN (:childs)";
$params['childs'] = $childs;
}
$whereSql = implode(" AND ", $whereFilters);
// 🧠 Fenêtre analytique partitionnée par cpv (point de vente)
// Cela garantit que le total = 100% par cpv (et par période si applicable)
$sql = "
SELECT
$periodeFormat AS periode,
pos.code AS cpv,
pr.product_id,
p.name AS product_name,
cat.intern_name AS category_name,
COUNT(*) AS total_ventes,
ROUND(
COUNT(*) * 100.0 /
SUM(COUNT(*)) OVER (PARTITION BY pos.code, $periodeFormat),
2
) AS pourcentage
FROM production pr
LEFT JOIN product p ON p.id = pr.product_id
LEFT JOIN category_product cat ON cat.id = p.category_id
LEFT JOIN point_of_sale pos ON pos.id = pr.point_of_sale_id
$joinCluster
WHERE $whereSql
GROUP BY periode, pos.code, pr.product_id, p.name, cat.intern_name
ORDER BY periode, pos.code, pr.product_id
";
$stmt = $conn->prepare($sql);
$result = $stmt->executeQuery($params);
return $result->fetchAllAssociative();
}
public function getVentesPrisesCohorte(
$pointOfSaleId = null,
$annee = null,
$mois = null,
$semaine = null,
$codeCluster = null,
$departement = null
) {
$conn = $this->getEntityManager()->getConnection();
$bindings = [];
$wherePrises = [];
$whereVentes = [];
// Point of sale (optionnel)
if ($pointOfSaleId) {
$wherePrises[] = "ps.id = :pointOfSaleId";
$whereVentes[] = "pr.point_of_sale_id = :pointOfSaleId";
$bindings['pointOfSaleId'] = $pointOfSaleId;
}
// Filtres dynamiques
if ($annee) {
$wherePrises[] = "YEAR(pn.date_import_data) = :annee";
// $whereVentes[] = "YEAR(pr.date_cmd_a) = :annee";
$bindings['annee'] = $annee;
}
if ($mois) {
$wherePrises[] = "DATE_FORMAT(pn.date_import_data, '%Y-%m') = :mois";
// $whereVentes[] = "DATE_FORMAT(pr.date_cmd_a, '%Y-%m') = :mois";
$bindings['mois'] = $mois;
}
if ($semaine) {
$wherePrises[] = "WEEK(pn.date_import_data, 3) = :semaine";
// $whereVentes[] = "WEEK(pr.date_cmd_a, 3) = :semaine";
$bindings['semaine'] = $semaine;
}
if ($codeCluster) {
$wherePrises[] = "pn.code_cluster = :codeCluster";
$whereVentes[] = "c.code_cluster = :codeCluster";
$bindings['codeCluster'] = $codeCluster;
}
if ($departement) {
$wherePrises[] = "pn.code_cluster LIKE :departement";
// $whereVentes[] = "c.code_cluster LIKE :departement";
$bindings['departement'] = $departement . '-%';
}
// Construction des WHERE
$wherePrisesSql = count($wherePrises) > 0 ? 'WHERE ' . implode(' AND ', $wherePrises) : '';
$whereVentesSql = count($whereVentes) > 0 ? 'WHERE ' . implode(' AND ', $whereVentes) : '';
// --- SQL ---
$sql = " WITH p AS (
SELECT
YEAR(pn.date_import_data) AS annee,
MONTH(pn.date_import_data) AS mois_num,
DATE_FORMAT(pn.date_import_data,'%Y-%m') AS mois_livraison,
pn.cod_hexc AS code_hexc,
pn.cpv AS cpv,
pn.lbl_cpv AS cpv_name,
pn.code_cluster AS code_cluster,
SUM(pn.nb_logt) AS nb_prises
FROM nmd_adresses_incomming AS pn
JOIN point_of_sale AS ps
ON ps.code = pn.cpv -- filtre POS côté prises, dans ON pour éviter d'éliminer des lignes
$wherePrisesSql -- filtre année côté prises
GROUP BY
annee, mois_num, mois_livraison,
code_hexc, cpv, code_cluster
),
v AS (
SELECT
YEAR(pr.date_cmd_a) AS annee,
MONTH(pr.date_cmd_a) AS mois_num,
DATE_FORMAT(pr.date_cmd_a,'%Y-%m') AS mois_vente,
pr.code_hexc AS code_hexc,
c.code_cluster AS code_cluster,
COUNT(DISTINCT pr.id) AS nb_ventes
FROM production AS pr
LEFT JOIN cluster c ON pr.cluster_id = c.id
$whereVentesSql -- filtre POS côté ventes
GROUP BY
annee, mois_num, mois_vente,
code_hexc, code_cluster
)
SELECT
p.annee,
p.cpv,
p.cpv_name,
p.mois_livraison,
v.mois_vente,
p.code_cluster,
SUM(p.nb_prises) AS nb_prises_recues,
COALESCE(SUM(v.nb_ventes), 0) AS nb_ventes_cohorte
FROM p
LEFT JOIN v
ON v.code_hexc = p.code_hexc
GROUP BY
p.annee, p.cpv, p.mois_livraison, v.mois_vente, p.code_cluster
ORDER BY
p.annee, p.cpv, p.mois_num, p.code_cluster;
";
$stmt = $conn->prepare($sql);
$rows = $stmt->executeQuery($bindings)->fetchAllAssociative();
return $rows;
}
public function getProductionsAnalyticsObjectifsOptimized(
$pointOfSale,
$codeCluster,
$mois,
$annee,
$optionSelect,
$etatKO,
$category,
$childs,
$organisationId,
$departement
): array {
// Cas où on a des enfants (hiérarchie utilisateurs)
if (is_array($childs) && count($childs) > 0) {
$qb = $this->getEntityManager()->createQueryBuilder()
->select('
SUM(o.objectivesVv) AS total_objectif,
IDENTITY(o.user) AS userId
')
->from('App\Entity\ObjectivesManagement', 'o')
->andWhere('MONTH(o.monthAt) = :mois')
->andWhere('YEAR(o.monthAt) = :annee')
->setParameter('mois', $mois)
->setParameter('annee', $annee)
->andWhere('o.user IN (:childs)')
->leftJoin('o.user', 's')
->setParameter('childs', $childs)
->groupBy('o.user');
return $qb->getQuery()->getArrayResult();
}
// Cas standard (objectif par cluster ou par CPV)
$qb = $this->getEntityManager()->createQueryBuilder()
->select('
SUM(o.vv) AS total_objectif,
o.codeCluster,
SUBSTRING(o.codeCluster, 1, 2) AS departement
')
->from('App\Entity\NmdObjectifClusters', 'o')
->andWhere('o.mois = :mois')
->andWhere('o.year = :annee')
->setParameter('mois', $mois)
->setParameter('annee', $annee);
// Filtre principal : si point de vente, filtrer par CPV
if ($pointOfSale) {
$qb->andWhere('o.cpv = :cpv')
->setParameter('cpv', $pointOfSale->getCode());
}
// Filtre par codeCluster si fourni
if ($codeCluster) {
$qb->andWhere('o.codeCluster = :codeCluster')
->setParameter('codeCluster', $codeCluster);
}
// Filtre par département
if ($departement) {
$qb->andWhere('o.codeCluster LIKE :prefix')
->setParameter('prefix', $departement . '-%');
}
$qb->groupBy('o.codeCluster');
return $qb->getQuery()->getArrayResult();
}
public function getProductionsAnalyticsVentesOptimized(
$pointOfSale,
$codeCluster,
$codeInsee,
$mois,
$annee,
$optionSelect,
$category,
$etat,
$childs,
$organisationId,
$perid,
$sellerId,
$departement
): array {
$boxProducts = [150, 262, 264, 266, 334, 335, 341, 344, 345, 379];
// 🔹 Base commune
$qb = $this->createBaseQueryBuilder(
$pointOfSale,
$codeCluster,
$codeInsee,
$mois,
$annee,
$optionSelect,
$departement
);
$qb->select("
po.code AS cpv,
po.name AS nomCpv,
c.codeCluster AS codeCluster,
c.libelleCluster AS libelleCluster,
SUBSTRING(c.codeCluster, 1, 2) AS departement,
COUNT(p.id) AS total_ventes,
SUM(CASE WHEN p.dateRacc IS NOT NULL
AND (p.category IN (1,3) OR p.product IN (:boxProducts))
THEN 1 ELSE 0 END) AS total_ventes_raccordes_fixe,
SUM(CASE WHEN p.category IN (31,32,33)
AND p.dateRacc IS NOT NULL
AND p.product NOT IN (:boxProducts)
THEN 1 ELSE 0 END) AS total_ventes_raccorde_mobile,
SUM(CASE WHEN p.product IN (:boxProducts) THEN 1 ELSE 0 END) AS total_ventes_box_5G,
SUM(CASE WHEN p.category IN (1,3)
THEN 1 ELSE 0 END) AS total_ventes_conq_vla,
SUM(CASE WHEN p.etat = :etat THEN 1 ELSE 0 END) AS total_ventes_ko
");
// 🔹 Groupement par défaut sur le point de vente
$qb->groupBy('c.codeCluster')
->orderBy('po.code', 'ASC');
$qb->setParameter('boxProducts', $boxProducts);
// ------------------------------------------
// 🔸 Filtres dynamiques additionnels
// ------------------------------------------
if ($organisationId) {
$qb->andWhere('p.organisation = :organisationId')
->setParameter('organisationId', $organisationId);
}
if ($perid) {
$qb->andWhere('p.loginVendeurInit = :perid')
->setParameter('perid', $perid);
}
if ($sellerId) {
$qb->andWhere('p.seller = :sellerId')
->setParameter('sellerId', $sellerId);
}
if (is_array($childs) && count($childs) > 0) {
$qb->andWhere('p.seller IN (:childs)')
->setParameter('childs', $childs);
}
if ($category) {
$categoryIds = array_filter(
array_map('intval', explode(',', $category)),
fn($id) => $id > 0
);
$qb->andWhere('p.category IN (:categories)')
->setParameter('categories', $categoryIds);
}
if ($etat) {
$qb->setParameter('etat', $etat);
}
// ✅ Exécution
return $qb->getQuery()->getArrayResult();
}
public function getProductionsAnalyticsVentesOptimized2(
$pointOfSale,
$codeCluster,
$codeInsee,
$mois,
$annee,
$optionSelect,
$category,
$etat,
$childs,
$organisationId,
$perid,
$sellerId,
$departement
): array {
$boxProducts = [150, 262, 264, 266, 334, 335, 341, 344, 345, 379];
// 🔹 Base commune
$qb = $this->createBaseQueryBuilder(
$pointOfSale,
$codeCluster,
$codeInsee,
$mois,
$annee,
$optionSelect,
$departement
);
$qb->select("
po.code AS cpv,
po.name AS nomCpv,
c.codeCluster AS codeCluster,
c.libelleCluster AS libelleCluster,
SUBSTRING(c.codeCluster, 1, 2) AS departement,
COUNT(p.id) AS total_ventes,
SUM(CASE WHEN p.dateRacc IS NOT NULL
AND (p.category IN (1,3) OR p.product IN (:boxProducts))
THEN 1 ELSE 0 END) AS total_ventes_raccordes_fixe,
SUM(CASE WHEN p.category IN (1,3)
THEN 1 ELSE 0 END) AS total_ventes_conq_vla,
SUM(CASE WHEN p.etat = :etat THEN 1 ELSE 0 END) AS total_ventes_ko
");
// 🔹 Groupement par défaut sur le point de vente
$qb->groupBy('c.codeCluster')
->orderBy('po.code', 'ASC');
$qb->setParameter('boxProducts', $boxProducts);
// ------------------------------------------
// 🔸 Filtres dynamiques additionnels
// ------------------------------------------
if ($organisationId) {
$qb->andWhere('p.organisation = :organisationId')
->setParameter('organisationId', $organisationId);
}
if ($perid) {
$qb->andWhere('p.loginVendeurInit = :perid')
->setParameter('perid', $perid);
}
if ($sellerId) {
$qb->andWhere('p.seller = :sellerId')
->setParameter('sellerId', $sellerId);
}
if (is_array($childs) && count($childs) > 0) {
$qb->andWhere('p.seller IN (:childs)')
->setParameter('childs', $childs);
}
if ($category) {
$categoryIds = array_filter(
array_map('intval', explode(',', $category)),
fn($id) => $id > 0
);
$qb->andWhere('p.category IN (:categories)')
->setParameter('categories', $categoryIds);
}
if ($etat) {
$qb->setParameter('etat', $etat);
}
// ✅ Exécution
return $qb->getQuery()->getArrayResult();
}
public function getProductionsAnalyticsVentesMobileOptimized(
$pointOfSale,
$codeCluster,
$codeInsee,
$mois,
$annee,
$optionSelect,
$childs,
$organisationId,
$perid,
$sellerId,
$departement
): array {
$boxProducts = [150, 262, 264, 266, 334, 335, 341, 344, 345, 379];
// 🔹 Base commune
$qb = $this->createBaseQueryBuilder(
$pointOfSale,
$codeCluster,
$codeInsee,
$mois,
$annee,
$optionSelect,
$departement
);
$qb->select("
SUBSTRING(p.titulaireZipCode, 1, 2) AS departement,
SUM(CASE WHEN p.category IN (31,32,33)
AND p.dateRacc IS NOT NULL
AND p.product NOT IN (:boxProducts)
THEN 1 ELSE 0 END) AS total_ventes_raccorde_mobile,
SUM(CASE WHEN p.product IN (:boxProducts) THEN 1 ELSE 0 END) AS total_ventes_box_5G
");
// 🔹 Groupement par défaut sur le point de vente
$qb->groupBy('departement')
->orderBy('po.code', 'ASC');
$qb->setParameter('boxProducts', $boxProducts);
// ------------------------------------------
// 🔸 Filtres dynamiques additionnels
// ------------------------------------------
if ($organisationId) {
$qb->andWhere('p.organisation = :organisationId')
->setParameter('organisationId', $organisationId);
}
if ($perid) {
$qb->andWhere('p.loginVendeurInit = :perid')
->setParameter('perid', $perid);
}
if ($sellerId) {
$qb->andWhere('p.seller = :sellerId')
->setParameter('sellerId', $sellerId);
}
if (is_array($childs) && count($childs) > 0) {
$qb->andWhere('p.seller IN (:childs)')
->setParameter('childs', $childs);
}
// ✅ Exécution
return $qb->getQuery()->getArrayResult();
}
public function getTotalVenteCnqVla(
$pointOfSale,
$codeCluster,
$codeInsee,
$mois,
$annee,
$optionSelect,
$childs,
$organisationId,
$perid,
$sellerId,
$departement
): array {
// 🔹 Base commune
$qb = $this->createBaseQueryBuilder(
$pointOfSale,
$codeCluster,
$codeInsee,
$mois,
$annee,
$optionSelect,
$departement
);
$qb->select("
c.codeCluster AS codeCluster,
SUBSTRING(c.codeCluster, 1, 2) AS departement,
COUNT(p.id) AS total_ventes,
SUM(CASE WHEN p.category IN (1,3)
THEN 1 ELSE 0 END) AS total_ventes_conq_vla
");
// 🔹 Groupement par défaut sur le point de vente
$qb->groupBy('c.codeCluster')
->orderBy('po.code', 'ASC');
// ------------------------------------------
// 🔸 Filtres dynamiques additionnels
// ------------------------------------------
if ($organisationId) {
$qb->andWhere('p.organisation = :organisationId')
->setParameter('organisationId', $organisationId);
}
if ($perid) {
$qb->andWhere('p.loginVendeurInit = :perid')
->setParameter('perid', $perid);
}
if ($sellerId) {
$qb->andWhere('p.seller = :sellerId')
->setParameter('sellerId', $sellerId);
}
if (is_array($childs) && count($childs) > 0) {
$qb->andWhere('p.seller IN (:childs)')
->setParameter('childs', $childs);
}
// ✅ Exécution
return $qb->getQuery()->getArrayResult();
}
public function getMrzList($pointOfSale, $codeCluster, $codeInsee, $mois, $annee, $optionSelect, $childs, $organisationId, $perid, $sellerId, $departement)
{
$conn = $this->getEntityManager()->getConnection();
$sql = '
SELECT COUNT(p.id) AS total_ventes,
p.identity_ctrl,
c.code_cluster AS codeCluster
FROM production p
LEFT JOIN point_of_sale po ON p.point_of_sale_id = po.id
LEFT JOIN cluster c ON p.cluster_id = c.id
WHERE p.identity_ctrl IS NOT NULL
';
$params = [
'mois' => $mois,
'annee' => $annee
];
// ✅ Ajout condition dynamique sur pointOfSale
if ($pointOfSale) {
$sql .= ' AND p.point_of_sale_id = :pointOfSale';
$params['pointOfSale'] = $pointOfSale->getId();
}
// ✅ Condition sur les enfants
if (is_array($childs) && count($childs) > 0) {
$placeholders = [];
foreach ($childs as $i => $child) {
$placeholder = ':child_' . $i;
$placeholders[] = $placeholder;
$params['child_' . $i] = $child;
}
$sql .= ' AND p.seller_id IN (' . implode(', ', $placeholders) . ')';
}
// ✅ Autres conditions
if ($codeCluster) {
$sql .= ' AND c.code_cluster = :codeCluster';
$params['codeCluster'] = $codeCluster;
}
if ($departement) {
$sql .= ' AND c.code_cluster LIKE :departement';
$params['departement'] = $departement . '-%';
}
if ($codeInsee) {
$sql .= ' AND p.code_insee = :codeInsee';
$params['codeInsee'] = $codeInsee;
}
if ($organisationId) {
$sql .= ' AND p.organisation_id = :organisationId';
$params['organisationId'] = $organisationId;
}
if ($perid) {
$sql .= ' AND p.login_vendeur_init = :perid';
$params['perid'] = $perid;
}
if ($sellerId) {
$sql .= ' AND p.seller_id = :sellerId';
$params['sellerId'] = $sellerId;
}
// ✅ Condition sur le mois / année selon optionSelect
switch ($optionSelect) {
case 'V':
$sql .= ' AND MONTH(p.date_vente_valid_b) = :mois AND YEAR(p.date_vente_valid_b) = :annee';
break;
case 'R':
$sql .= ' AND MONTH(p.date_racc) = :mois AND YEAR(p.date_racc) = :annee';
break;
case 'B':
$sql .= ' AND MONTH(p.date_cmd_a) = :mois AND YEAR(p.date_cmd_a) = :annee';
break;
}
$sql .= ' GROUP BY p.identity_ctrl, p.point_of_sale_id, c.code_cluster ';
$stmt = $conn->prepare($sql);
$result = $stmt->executeQuery($params);
return $result->fetchAllAssociative();
}
public function get4P(
$pointOfSale,
$codeCluster,
$codeInsee,
$mois,
$annee,
$childs,
$organisationId,
$perid,
$sellerId,
$departement
): array {
$conn = $this->getEntityManager()->getConnection();
// 🔹 Base des paramètres
$params = [
'mois' => $mois,
'annee' => $annee,
'cat32' => 32,
'cat31' => 31
];
if ($pointOfSale) {
$params['pointOfSale'] = $pointOfSale->getId();
}
// ------------------------------------------
// 🧱 SQL Construction (partie principale)
// ------------------------------------------
$sql = '
SELECT
SUBSTRING(result.titulaire_zip_code, 1, 2) AS departement,
COUNT(DISTINCT result.titulaire_email) AS total_vente
FROM (
-- Partie 1 : Catégorie 32 avec emails en catégorie 1
SELECT
p1.titulaire_email,
p1.titulaire_zip_code
FROM production p1
WHERE p1.category_id = :cat32
AND MONTH(p1.date_cmd_a) = :mois
AND YEAR(p1.date_cmd_a) = :annee
AND p1.titulaire_email IN (
SELECT DISTINCT p_sub1.titulaire_email
FROM production p_sub1
WHERE p_sub1.category_id = 1
AND MONTH(p_sub1.date_cmd_a) = :mois
AND YEAR(p_sub1.date_cmd_a) = :annee
';
// Ajout des filtres dynamiques pour la sous-requête p_sub1
if ($pointOfSale) {
$sql .= ' AND p_sub1.point_of_sale_id = :pointOfSale';
}
$sql .= ')';
// 🔹 Filtres optionnels pour p1
if ($pointOfSale) {
$sql .= ' AND p1.point_of_sale_id = :pointOfSale';
}
if ($organisationId) {
$sql .= ' AND p1.organisation_id = :organisationId';
$params['organisationId'] = $organisationId;
}
if ($codeCluster) {
$sql .= ' AND p1.cluster_id IN (SELECT id FROM cluster WHERE code_cluster = :codeCluster)';
$params['codeCluster'] = $codeCluster;
}
if ($departement) {
// On filtre sur le code postal du titulaire, pas sur le cluster
$sql .= ' AND SUBSTRING(p1.titulaire_zip_code, 1, 2) = :departement';
$params['departement'] = $departement;
}
if ($codeInsee) {
$sql .= ' AND p1.code_insee = :codeInsee';
$params['codeInsee'] = $codeInsee;
}
if ($perid) {
$sql .= ' AND p1.login_vendeur_init = :perid';
$params['perid'] = $perid;
}
if ($sellerId) {
$sql .= ' AND p1.seller_id = :sellerId';
$params['sellerId'] = $sellerId;
}
if (is_array($childs) && count($childs) > 0) {
$placeholders = [];
foreach ($childs as $i => $child) {
$placeholder = ':child_' . $i;
$placeholders[] = $placeholder;
$params['child_' . $i] = $child;
}
$sql .= ' AND p1.seller_id IN (' . implode(', ', $placeholders) . ')';
}
// ------------------------------------------
// 🧩 UNION : catégorie 31
// ------------------------------------------
$sql .= '
UNION
SELECT
p2.titulaire_email,
p2.titulaire_zip_code
FROM production p2
WHERE p2.category_id = :cat31
AND MONTH(p2.date_cmd_a) = :mois
AND YEAR(p2.date_cmd_a) = :annee
AND p2.titulaire_email IN (
SELECT DISTINCT p_sub2.titulaire_email
FROM production p_sub2
WHERE p_sub2.category_id IN (1, 3)
AND MONTH(p_sub2.date_cmd_a) = :mois
AND YEAR(p_sub2.date_cmd_a) = :annee
';
// Filtres dynamiques pour sous-requête p_sub2
if ($pointOfSale) {
$sql .= ' AND p_sub2.point_of_sale_id = :pointOfSale';
}
$sql .= ')';
// 🔹 Filtres optionnels pour p2
if ($pointOfSale) {
$sql .= ' AND p2.point_of_sale_id = :pointOfSale';
}
if ($organisationId) {
$sql .= ' AND p2.organisation_id = :organisationId';
}
if ($codeCluster) {
$sql .= ' AND p2.cluster_id IN (SELECT id FROM cluster WHERE code_cluster = :codeCluster)';
}
if ($departement) {
$sql .= ' AND SUBSTRING(p2.titulaire_zip_code, 1, 2) = :departement';
}
if ($codeInsee) {
$sql .= ' AND p2.code_insee = :codeInsee';
}
if ($perid) {
$sql .= ' AND p2.login_vendeur_init = :perid';
}
if ($sellerId) {
$sql .= ' AND p2.seller_id = :sellerId';
}
if (is_array($childs) && count($childs) > 0) {
$placeholders = [];
foreach ($childs as $i => $child) {
$placeholder = ':child_' . $i;
$placeholders[] = $placeholder;
}
$sql .= ' AND p2.seller_id IN (' . implode(', ', $placeholders) . ')';
}
// ------------------------------------------
// 🔚 Fermeture du bloc + agrégation
// ------------------------------------------
$sql .= '
) AS result
GROUP BY SUBSTRING(result.titulaire_zip_code, 1, 2)
ORDER BY departement
';
// ------------------------------------------
// ▶️ Exécution
// ------------------------------------------
$stmt = $conn->prepare($sql);
$result = $stmt->executeQuery($params);
return $result->fetchAllAssociative();
}
public function get4PC(
$pointOfSale,
$codeCluster,
$codeInsee,
$mois,
$annee,
$childs,
$organisationId,
$perid,
$sellerId,
$departement
): array {
$qb = $this->createQueryBuilder('p')
->leftJoin('p.cluster', 'c')
->select('COUNT(DISTINCT p.titulaireEmail) AS nombre_titulaire_email')
->addSelect('SUBSTRING(p.titulaireZipCode, 1, 2) AS departement')
->groupBy('departement');
// 🔹 Filtres temporels
$qb->andWhere('MONTH(p.dateCmdA) = :mois')
->andWhere('YEAR(p.dateCmdA) = :annee')
->setParameter('mois', $mois)
->setParameter('annee', $annee);
// 🔹 Point de vente (optionnel)
if ($pointOfSale) {
$qb->andWhere('p.pointOfSale = :pointOfSale')
->setParameter('pointOfSale', $pointOfSale);
}
// 🔹 Cluster
if ($codeCluster) {
$qb->andWhere('c.codeCluster = :codeCluster')
->setParameter('codeCluster', $codeCluster);
}
// 🔹 INSEE
if ($codeInsee) {
$qb->andWhere('p.codeInsee = :codeInsee')
->setParameter('codeInsee', $codeInsee);
}
// 🔹 Département
if ($departement) {
$qb->andWhere('c.codeCluster LIKE :prefix')
->setParameter('prefix', $departement . '-%');
}
// 🔹 Logique chainage
$qb->andWhere('p.fixeChainage IS NOT NULL')
->andWhere('p.category IN (31,32,33)');
// 🔹 Filtres vendeurs
if (is_array($childs) && count($childs) > 0) {
$qb->andWhere('p.seller IN (:childs)')
->setParameter('childs', $childs);
}
if ($organisationId) {
$qb->andWhere('p.organisation = :organisationId')
->setParameter('organisationId', $organisationId);
}
if ($perid) {
$qb->andWhere('p.loginVendeurInit = :perid')
->setParameter('perid', $perid);
}
if ($sellerId) {
$qb->andWhere('p.seller = :sellerId')
->setParameter('sellerId', $sellerId);
}
return $qb->getQuery()->getArrayResult();
}
public function getJ30(
$pointOfSale,
$codeCluster,
$codeInsee,
$mois,
$annee,
$childs,
$organisationId,
$perid,
$sellerId,
$departement
): array {
$conn = $this->getEntityManager()->getConnection();
$sql = "
SELECT
c.code_cluster AS codeCluster,
-- 🟩 Total global (fixe + mobile)
COUNT(DISTINCT CASE
WHEN p.date_resiliation IS NOT NULL
AND p.date_racc IS NOT NULL
AND DATEDIFF(p.date_racc, p.date_resiliation) > -31
AND MONTH(p.date_vente_valid_b) = :mois
AND YEAR(p.date_vente_valid_b) = :annee
AND (p.category_id NOT IN (2, 31, 32, 33) OR p.product_id IN(150,262,264,266,334,335,341,344,345,379))
THEN p.id END) AS total_vente,
-- 🟦 Total raccordé fixe
COUNT(DISTINCT CASE
WHEN (p.category_id NOT IN (31,32,33)
OR p.product_id IN (150,262,264,266,334,335,341,344,345,379))
AND p.date_resiliation IS NOT NULL
AND p.date_racc IS NOT NULL
AND DATEDIFF(p.date_racc, p.date_resiliation) > -31
AND MONTH(p.date_cmd_a) = :mois
AND YEAR(p.date_cmd_a) = :annee
THEN p.id END) AS total_vente_fixe_raccorde
FROM production p
LEFT JOIN cluster c ON p.cluster_id = c.id
LEFT JOIN point_of_sale po ON p.point_of_sale_id = po.id
WHERE 1 = 1
";
$params = [
'mois' => $mois,
'annee' => $annee,
];
// ✅ Point de vente optionnel
if ($pointOfSale) {
$sql .= " AND p.point_of_sale_id = :pointOfSale";
$params['pointOfSale'] = $pointOfSale->getId();
}
if ($codeCluster) {
$sql .= " AND c.code_cluster = :codeCluster";
$params['codeCluster'] = $codeCluster;
}
if ($departement) {
$sql .= " AND c.code_cluster LIKE :departement";
$params['departement'] = $departement . '-%';
}
if ($codeInsee) {
$sql .= " AND p.code_insee = :codeInsee";
$params['codeInsee'] = $codeInsee;
}
if ($organisationId) {
$sql .= " AND p.organisation_id = :organisationId";
$params['organisationId'] = $organisationId;
}
if ($perid) {
$sql .= " AND p.login_vendeur_init = :perid";
$params['perid'] = $perid;
}
if ($sellerId) {
$sql .= " AND p.seller_id = :sellerId";
$params['sellerId'] = $sellerId;
}
if (is_array($childs) && count($childs) > 0) {
$placeholders = [];
foreach ($childs as $i => $child) {
$placeholder = ':child_' . $i;
$placeholders[] = $placeholder;
$params['child_' . $i] = $child;
}
$sql .= ' AND p.seller_id IN (' . implode(', ', $placeholders) . ')';
}
// ✅ Groupement
$sql .= ' GROUP BY c.code_cluster';
$stmt = $conn->prepare($sql);
$result = $stmt->executeQuery($params);
return $result->fetchAllAssociative();
}
public function getJ30Mobile(
$pointOfSale,
$codeCluster,
$codeInsee,
$mois,
$annee,
$childs,
$organisationId,
$perid,
$sellerId,
$departement
): array {
$conn = $this->getEntityManager()->getConnection();
$sql = "
SELECT
SUBSTRING(p.titulaire_zip_code,1,2) AS departement,
-- 🟧 Total mobile
COUNT(DISTINCT CASE
WHEN p.category_id IN (31,32,33)
AND p.date_resiliation IS NOT NULL
AND p.date_racc IS NOT NULL
AND DATEDIFF(p.date_racc, p.date_resiliation) > -31
AND MONTH(p.date_cmd_a) = :mois
AND YEAR(p.date_cmd_a) = :annee
THEN p.id END) AS total_vente_mobile,
-- 🟥 Total raccordé mobile
COUNT(DISTINCT CASE
WHEN p.category_id IN (31,32,33)
AND p.date_resiliation IS NOT NULL
AND p.date_racc IS NOT NULL
AND DATEDIFF(p.date_racc, p.date_resiliation) > -31
AND p.product_id NOT IN (150,262,264,266,334,335,341,344,345,379)
AND MONTH(p.date_cmd_a) = :mois
AND YEAR(p.date_cmd_a) = :annee
THEN p.id END) AS total_vente_mobile_raccorde
FROM production p
LEFT JOIN cluster c ON p.cluster_id = c.id
LEFT JOIN point_of_sale po ON p.point_of_sale_id = po.id
WHERE 1 = 1
";
$params = [
'mois' => $mois,
'annee' => $annee,
];
// ✅ Point de vente optionnel
if ($pointOfSale) {
$sql .= " AND p.point_of_sale_id = :pointOfSale";
$params['pointOfSale'] = $pointOfSale->getId();
}
if ($codeCluster) {
$sql .= " AND c.code_cluster = :codeCluster";
$params['codeCluster'] = $codeCluster;
}
if ($departement) {
$sql .= " AND c.code_cluster LIKE :departement";
$params['departement'] = $departement . '-%';
}
if ($codeInsee) {
$sql .= " AND p.code_insee = :codeInsee";
$params['codeInsee'] = $codeInsee;
}
if ($organisationId) {
$sql .= " AND p.organisation_id = :organisationId";
$params['organisationId'] = $organisationId;
}
if ($perid) {
$sql .= " AND p.login_vendeur_init = :perid";
$params['perid'] = $perid;
}
if ($sellerId) {
$sql .= " AND p.seller_id = :sellerId";
$params['sellerId'] = $sellerId;
}
if (is_array($childs) && count($childs) > 0) {
$placeholders = [];
foreach ($childs as $i => $child) {
$placeholder = ':child_' . $i;
$placeholders[] = $placeholder;
$params['child_' . $i] = $child;
}
$sql .= ' AND p.seller_id IN (' . implode(', ', $placeholders) . ')';
}
// ✅ Groupement
$sql .= ' GROUP BY departement';
$stmt = $conn->prepare($sql);
$result = $stmt->executeQuery($params);
return $result->fetchAllAssociative();
}
public function getPto(
$pointOfSale,
?string $codeCluster,
$codeInsee,
int $mois,
int $annee,
array $childs,
?int $organisationId,
?string $perid,
$sellerId,
$departement
): array {
$conn = $this->getEntityManager()->getConnection();
$sql = "
SELECT
c.code_cluster AS codeCluster,
-- RIO
COUNT(DISTINCT CASE WHEN p.portabilite = 'OUI' THEN p.id END) AS total_rio,
-- PTO_SAISIE
COUNT(DISTINCT CASE WHEN p.prise_saisie_commande = 'OUI' THEN p.id END) AS total_pto_saisie,
-- PTO_NON_SAISIE
COUNT(DISTINCT CASE WHEN p.prise_saisie_commande = 'NON' AND p.prise_existante_commande = 'OUI' THEN p.id END) AS total_pto_non_saisie,
-- PTO_EXISTANTE
COUNT(DISTINCT CASE WHEN p.prise_existante_commande = 'OUI' THEN p.id END) AS total_pto_existante,
-- PTO_NON_EXISTANTE
COUNT(DISTINCT CASE WHEN p.prise_existante_commande = 'NON' THEN p.id END) AS total_pto_non_existante
FROM production p
LEFT JOIN cluster c ON c.id = p.cluster_id
LEFT JOIN point_of_sale po ON po.id = p.point_of_sale_id
WHERE p.category_id IN (1,3)
AND MONTH(p.date_cmd_a) = :mois
AND YEAR(p.date_cmd_a) = :annee
";
$params = [
'mois' => $mois,
'annee' => $annee,
];
// 🔹 Point de vente optionnel
if ($pointOfSale) {
$sql .= " AND p.point_of_sale_id = :pointOfSale";
$params['pointOfSale'] = $pointOfSale->getId();
}
if ($organisationId) {
$sql .= " AND p.organisation_id = :organisationId";
$params['organisationId'] = $organisationId;
}
if (!empty($childs)) {
$placeholders = [];
foreach ($childs as $i => $child) {
$placeholder = ':child_' . $i;
$placeholders[] = $placeholder;
$params['child_' . $i] = $child;
}
$sql .= ' AND p.seller_id IN (' . implode(', ', $placeholders) . ')';
}
if ($codeInsee) {
$sql .= " AND p.code_insee = :codeInsee";
$params['codeInsee'] = $codeInsee;
}
if ($codeCluster) {
$sql .= " AND c.code_cluster = :codeCluster";
$params['codeCluster'] = $codeCluster;
}
if ($departement) {
$sql .= " AND c.code_cluster LIKE :departement";
$params['departement'] = $departement . '-%';
}
if ($perid) {
$sql .= " AND p.login_vendeur_init = :perid";
$params['perid'] = $perid;
}
if ($sellerId) {
$sql .= " AND p.seller_id = :sellerId";
$params['sellerId'] = $sellerId;
}
// 🔹 Group by cluster
$sql .= " GROUP BY c.code_cluster";
$stmt = $conn->prepare($sql);
$result = $stmt->executeQuery($params);
return $result->fetchAllAssociative();
}
public function getProjection(
$pointOfSale,
$codeCluster,
$codeInsee,
$mois,
$annee,
$optionSelect,
$etatKO,
$category,
$childs,
$organisationId,
$perid,
$sellerId,
$departement
): array {
$qb = $this->createBaseQueryBuilder($pointOfSale, $codeCluster, $codeInsee, $mois, $annee, $optionSelect, $departement);
$dateField = '';
$dateFieldSql = '';
switch ($optionSelect) {
case 'V':
$dateField = 'p.dateVenteValidB';
$dateFieldSql = 'p.date_vente_valid_b';
break;
case 'R':
$dateField = 'p.dateRacc';
$dateFieldSql = 'p.date_racc';
break;
case 'B':
$dateField = 'p.dateCmdA';
$dateFieldSql = 'p.date_cmd_a';
break;
}
// Sélectionner codeCluster et count des ventes
$qb->select('c.codeCluster AS codeCluster, COUNT(p.id) AS ventes_realisees')
->andWhere("$dateField <= :currentDate")
->setParameter('currentDate', new \DateTime());
if ($category) {
$categories = array_filter(array_map('intval', explode(',', $category)), fn($id) => $id > 0);
if ($categories) {
$qb->andWhere('p.category IN (:categories)')
->setParameter('categories', $categories);
}
}
if ($childs) {
$qb->andWhere('p.seller IN (:childs)')
->leftJoin('p.seller', 's')
->setParameter('childs', $childs);
}
if ($organisationId) $qb->andWhere('p.organisation = :organisationId')->setParameter('organisationId', $organisationId);
if ($perid) $qb->andWhere('p.loginVendeurInit = :perid')->setParameter('perid', $perid);
if ($sellerId) $qb->andWhere('p.seller = :sellerId')->setParameter('sellerId', $sellerId);
// Grouper par codeCluster
$qb->groupBy('c.codeCluster');
$ventesRealiseesData = $qb->getQuery()->getResult();
// Connexion DBAL pour calcul des jours de travail par cluster
$conn = $this->getEntityManager()->getConnection();
$parameters = ['mois' => $mois, 'annee' => $annee];
$sql = "
SELECT c.code_cluster,
COUNT(DISTINCT DAY($dateFieldSql)) AS jours_travail
FROM production p
LEFT JOIN cluster c ON p.cluster_id = c.id
WHERE
MONTH($dateFieldSql) = :mois
AND YEAR($dateFieldSql) = :annee
AND DAYOFWEEK($dateFieldSql) BETWEEN 2 AND 6
AND $dateFieldSql <= CURDATE()
";
if ($pointOfSale) {
$sql .= ' AND p.point_of_sale_id = :pointOfSale';
$parameters["pointOfSale"] = $pointOfSale->getId();
}
if ($category) {
$placeholders = [];
foreach ($categories as $i => $catId) {
$ph = ":cat$i";
$placeholders[] = $ph;
$parameters[$ph] = $catId;
}
$sql .= " AND p.category_id IN (" . implode(',', $placeholders) . ")";
}
$sql .= " GROUP BY c.code_cluster";
$stmt = $conn->prepare($sql);
foreach ($parameters as $key => $value) $stmt->bindValue($key, $value, \PDO::PARAM_INT);
$joursTravailData = $stmt->executeQuery()->fetchAllAssociative();
// Fusionner résultats pour calcul de projection par cluster
$projectionData = [];
foreach ($ventesRealiseesData as $row) {
$codeCluster = $row['codeCluster'];
$ventesRealisees = (int)$row['ventes_realisees'];
$joursTravailEffectues = 1; // fallback
foreach ($joursTravailData as $j) {
if ($j['code_cluster'] === $codeCluster) {
$joursTravailEffectues = (int)$j['jours_travail'];
break;
}
}
$ventesParJour = $ventesRealisees / max($joursTravailEffectues, 1);
$dateFinMois = new \DateTime();
$dateFinMois->setDate($annee, $mois, 1)->modify('last day of this month');
$currentDate = new \DateTime();
$joursRestants = 0;
if ($dateFinMois > $currentDate) {
$interval = $currentDate->diff($dateFinMois);
for ($i = 0; $i <= $interval->days; $i++) {
$jourTemp = (clone $currentDate)->modify("+$i day");
if ($jourTemp->format('N') < 6) $joursRestants++;
}
}
if ($currentDate->format('t') == $currentDate->format('d')) $joursRestants++;
$projectionVentes = ($ventesParJour * $joursRestants) + $ventesRealisees;
$projectionData[$codeCluster] = [
'ventes_realisees' => $ventesRealisees,
'ventes_par_jour' => $ventesParJour,
'jours_travail_effectues' => $joursTravailEffectues,
'jours_restants' => $joursRestants,
'projection_ventes' => $projectionVentes,
];
}
return $projectionData;
}
public function getVentesParPrisesFttb($cpv = null, $annee = null, $mois = null, $semaine = null, $codeCluster = null, $codeInsee = null)
{
$conn = $this->getEntityManager()->getConnection();
// Sous-requête dynamique
$sub = "
SELECT a.cod_hexc
FROM nmd_arret_fttb a
WHERE 1 = 1
";
$params = [];
if ($cpv !== null) {
$sub .= " AND a.cpv = :cpv";
$params['cpv'] = $cpv;
}
if ($annee !== null) {
$sub .= " AND YEAR(a.date_arret_fttb) = :annee";
$params['annee'] = $annee;
}
if ($mois !== null) {
$sub .= " AND MONTH(a.date_arret_fttb) = :mois";
$params['mois'] = $mois;
}
if ($semaine !== null) {
$sub .= " AND WEEK(a.date_arret_fttb, 1) = :semaine";
$params['semaine'] = $semaine;
}
if ($codeCluster !== null) {
$sub .= " AND a.code_cluster = :codeCluster";
$params['codeCluster'] = $codeCluster;
}
if ($codeInsee !== null) {
$sub .= " AND a.cod_insee = :codeInsee";
$params['codeInsee'] = $codeInsee;
}
// Requête principale
$sql = "
SELECT COUNT(*) AS total
FROM production p
WHERE p.code_hexc IN ($sub)
";
$stmt = $conn->executeQuery($sql, $params);
return $stmt->fetchOne();
}
public function getVentesParPrisesCuivre($cpv = null, $annee = null, $mois = null, $semaine = null, $codeCluster = null, $codeInsee = null)
{
$conn = $this->getEntityManager()->getConnection();
// Sous-requête dynamique
$sub = "
SELECT a.cod_hexc
FROM nmd_arret_cuivre a
WHERE 1 = 1
";
$params = [];
if ($cpv !== null) {
$sub .= " AND a.cpv = :cpv";
$params['cpv'] = $cpv;
}
if ($annee !== null) {
$sub .= " AND YEAR(a.arret_cu) = :annee";
$params['annee'] = $annee;
}
if ($mois !== null) {
$sub .= " AND MONTH(a.arret_cu) = :mois";
$params['mois'] = $mois;
}
if ($semaine !== null) {
$sub .= " AND WEEK(a.arret_cu, 1) = :semaine";
$params['semaine'] = $semaine;
}
if ($codeCluster !== null) {
$sub .= " AND a.code_cluster = :codeCluster";
$params['codeCluster'] = $codeCluster;
}
if ($codeInsee !== null) {
$sub .= " AND a.cod_insee = :codeInsee";
$params['codeInsee'] = $codeInsee;
}
// Requête principale
$sql = "
SELECT COUNT(*) AS total
FROM production p
WHERE p.code_hexc IN ($sub)
";
$stmt = $conn->executeQuery($sql, $params);
return $stmt->fetchOne();
}
}