src/Repository/ProduitDeclinationValueRepository.php line 204

Open in your IDE?
  1. <?php
  2. namespace App\Repository;
  3. use App\Entity\ProduitDeclinationValue;
  4. use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
  5. use Doctrine\Persistence\ManagerRegistry;
  6. use App\Entity\ValueDeclination;
  7. /**
  8.  * @method ProduitDeclinationValue|null find($id, $lockMode = null, $lockVersion = null)
  9.  * @method ProduitDeclinationValue|null findOneBy(array $criteria, array $orderBy = null)
  10.  * @method ProduitDeclinationValue[]    findAll()
  11.  * @method ProduitDeclinationValue[]    findBy(array $criteria, array $orderBy = null, $limit = null, $offset = null)
  12.  */
  13. class ProduitDeclinationValueRepository extends ServiceEntityRepository
  14. {
  15.     public function __construct(ManagerRegistry $registry)
  16.     {
  17.         parent::__construct($registryProduitDeclinationValue::class);
  18.     }
  19.     
  20. public function findProduitGroup(
  21.         $page,
  22.         $limit,
  23.         int $idProduit,
  24.         ?string $reference,
  25.         array $declinations = [],   // [declinationId => valueId|valueId[]]
  26.         bool $withDeleted false
  27.     ) {
  28.         $qb $this->createQueryBuilder('p')
  29.             ->leftJoin('p.produit''pp')
  30.             ->andWhere('pp.id = :produit')->setParameter('produit'$idProduit);
  31.         if ($reference) {
  32.             $qb->andWhere('UPPER(p.reference) LIKE :reference')
  33.             ->setParameter('reference''%'.mb_strtoupper($reference).'%');
  34.         }
  35.         // AND entre chaque declination
  36.         $i 0;
  37.         foreach ($declinations as $declId => $val) {
  38.             if ($val === null || $val === '' || $val === [] ) { continue; }
  39.             $i++;
  40.             $alias 'gdv'.$i;
  41.             $paramDecl 'd'.$i;
  42.             $paramVal  'v'.$i;
  43.             $vals is_array($val) ? array_values(array_unique($val)) : [ (int)$val ];
  44.             // innerJoin = critĂšre obligatoire
  45.             $qb->innerJoin('p.groupDeclinationValues'$alias'WITH',
  46.                 $alias.'.declination = :'.$paramDecl.' AND '.$alias.'.value IN (:'.$paramVal.')'
  47.             )
  48.             ->setParameter($paramDecl, (int)$declId)
  49.             ->setParameter($paramVal$vals);
  50.         }
  51.         if (!$withDeleted) {
  52.             $qb->andWhere('pp.deletedAt IS NULL');
  53.         }
  54.         $qb->orderBy('p.reference''ASC');
  55.         if ($page !== false) {
  56.             $qb->setMaxResults($limit)
  57.             ->setFirstResult($page $limit);
  58.         }
  59.         return $qb->getQuery()->getResult();
  60.     }
  61.     public function countProduitGroup(
  62.         int $idProduit,
  63.         ?string $reference,
  64.         array $declinations = [],   // [declinationId => valueId|valueId[]]
  65.         bool $withDeleted false
  66.     ) {
  67.         $qb $this->createQueryBuilder('p')
  68.             ->select('COUNT(p)')
  69.             ->leftJoin('p.produit''pp')
  70.             ->andWhere('pp.id = :produit')->setParameter('produit'$idProduit);
  71.         if ($reference) {
  72.             $qb->andWhere('UPPER(p.reference) LIKE :reference')
  73.             ->setParameter('reference''%'.mb_strtoupper($reference).'%');
  74.         }
  75.         $i 0;
  76.         foreach ($declinations as $declId => $val) {
  77.             if ($val === null || $val === '' || $val === [] ) { continue; }
  78.             $i++;
  79.             $alias 'gdv'.$i;
  80.             $paramDecl 'd'.$i;
  81.             $paramVal  'v'.$i;
  82.             $vals is_array($val) ? array_values(array_unique($val)) : [ (int)$val ];
  83.             $qb->innerJoin('p.groupDeclinationValues'$alias'WITH',
  84.                 $alias.'.declination = :'.$paramDecl.' AND '.$alias.'.value IN (:'.$paramVal.')'
  85.             )
  86.             ->setParameter($paramDecl, (int)$declId)
  87.             ->setParameter($paramVal$vals);
  88.         }
  89.         if (!$withDeleted) {
  90.             $qb->andWhere('pp.deletedAt IS NULL');
  91.         }
  92.         return (int)$qb->getQuery()->getSingleScalarResult();
  93.     }
  94.     public function searchItem($query,$isAvailable=false,$maxResult=5,$withDeleted=false) {
  95.         $qb $this->createQueryBuilder('p');
  96.         $qb->select('p.id, p.name, p.reference, p.description, p.price_ht, p.buyingPriceTtc')
  97.                 ->innerJoin("p.produit""pp")
  98.                 ->addSelect("pp.unit As unit")
  99.                 ->leftJoin("pp.tva""pptva")
  100.                 ->addSelect("pptva.id As tva_id")
  101.                 ->addSelect("pptva.number As tva")
  102.                 ->where('UPPER(p.name) LIKE :name')->setParameter('name''%' strtoupper($query) . '%')
  103.                 ->orWhere('UPPER(p.reference) LIKE :reference')->setParameter('reference''%' strtoupper($query) . '%')
  104.                 ->andWhere('pp.deletedAt IS NULL');
  105.         $qb->leftJoin('p.stocks','s');
  106.         if($isAvailable$qb->andWhere('(s.qtStock - s.qtReserved) >= 1');
  107.         $qb->orderBy('p.createdAt''DESC');
  108.         $qb->setMaxResults($maxResult);
  109.         return $qb->getQuery()->getResult();
  110.     }
  111.     
  112.   
  113.     public function searchAndCountProduitDeclinations(
  114.         int $page,
  115.         int $limit,
  116.         $reference,
  117.         $name,
  118.         $categories,
  119.         array $declinationFilters = [],
  120.         $isAvailable,
  121.         $inPromo,
  122.         $qtMin null,
  123.         $qtMax null,
  124.         $buyingPriceMin null,
  125.         $buyingPriceMax null,
  126.         $priceMin null,
  127.         $priceMax null,
  128.         string $sortField 'createdAt',
  129.         string $sortType 'DESC',
  130.         bool $withDeleted false
  131.     ): array {
  132.         /* ===============================
  133.         1) QueryBuilder de base
  134.         =============================== */
  135.         $qb $this->createQueryBuilder('p');
  136.         $this->QueryBuilderSearch(
  137.             $qb,
  138.             $reference,
  139.             $name,
  140.             $categories,
  141.             $declinationFilters,
  142.             $isAvailable,
  143.             $inPromo,
  144.             $qtMin,
  145.             $qtMax,
  146.             $buyingPriceMin,
  147.             $buyingPriceMax,
  148.             $priceMin,
  149.             $priceMax,
  150.             $withDeleted
  151.         );
  152.         /* ===============================
  153.         2) COUNT (clone)
  154.         =============================== */
  155.         $qbCount = clone $qb;
  156.         $total = (int) $qbCount
  157.             ->select('COUNT(DISTINCT p.id)')
  158.             ->resetDQLPart('orderBy')
  159.             ->getQuery()
  160.             ->getSingleScalarResult();
  161.         /* ===============================
  162.         3) RESULTS (clone)
  163.         =============================== */
  164.         $qbResult = clone $qb;
  165.         $qbResult
  166.             ->orderBy(($sortField === 'qtStock' '' 'p.') . $sortField$sortType)
  167.             ->setFirstResult($page $limit)
  168.             ->setMaxResults($limit);
  169.         $data $qbResult->getQuery()->getResult();
  170.         return [
  171.             'data'  => $data,
  172.             'total' => $total,
  173.         ];
  174.     }
  175.     public function searchProduitDeclinations(
  176.         $page
  177.         $limit
  178.         $reference
  179.         $name
  180.         $categories
  181.         array $declinationFilters = [],
  182.         $isAvailable
  183.         $inPromo
  184.         $qtMin null
  185.         $qtMax null
  186.         $buyingPriceMin null
  187.         $buyingPriceMax null
  188.         $priceMin null
  189.         $priceMax null
  190.         $sortField 'createdAt'
  191.         $sortType 'DESC'
  192.         $withDeleted false
  193.     ) {
  194.         $qb $this->createQueryBuilder('p');
  195.         $qb $this->QueryBuilderSearch(
  196.             $qb
  197.             $reference
  198.             $name
  199.             $categories
  200.             $declinationFilters
  201.             $isAvailable
  202.             $inPromo
  203.             $qtMin
  204.             $qtMax
  205.             $buyingPriceMin
  206.             $buyingPriceMax
  207.             $priceMin
  208.             $priceMax
  209.             $withDeleted
  210.         );
  211.         $qb->orderBy(($sortField === 'qtStock' '' 'p.') . $sortField$sortType);
  212.         if ($page !== false$qb->setMaxResults($limit)->setFirstResult($page $limit);
  213.         return $qb->getQuery()->getResult();
  214.     }
  215.     public function countProduitDeclinations(
  216.             $reference
  217.             $name
  218.             $categories
  219.             array $declinationFilters = [],
  220.             $isAvailable
  221.             $inPromo
  222.             $qtMin null
  223.             $qtMax null
  224.             $buyingPriceMin null
  225.             $buyingPriceMax null
  226.             $priceMin null
  227.             $priceMax null
  228.             $withDeleted false
  229.         ) {
  230.             $qb $this->createQueryBuilder('p');
  231.             $qb->select('COUNT(p)');
  232.             $qb $this->QueryBuilderSearch($qb,  $reference$name$categories$declinationFilters,$isAvailable$inPromo$qtMin$qtMax$buyingPriceMin$buyingPriceMax$priceMin$priceMax$withDeleted );
  233.             return $qb->getQuery()->getSingleScalarResult();
  234.         }
  235.     
  236.     /*--Filtre liste declinaisons--*/
  237.     
  238.     private function QueryBuilderSearch($qb,$reference$name$categories, array $declinationFilters = [], $isAvailable$inPromo$qtMin null$qtMax null,$buyingPriceMin null$buyingPriceMax null$priceMin null$priceMax null$withDeleted false) {
  239.         if ($name) {
  240.             $qb->andWhere('UPPER(p.name) LIKE :name')
  241.             ->setParameter('name''%' strtoupper($name) . '%');
  242.         }
  243.         if ($reference) {
  244.             $qb->andWhere('UPPER(p.reference) LIKE :reference')
  245.             ->setParameter('reference'strtoupper($reference) . '%');
  246.         }
  247.         // đŸ” Filtres dynamiques sur les dĂ©clinaisons
  248.                
  249.         foreach ($declinationFilters as $declinationId => $valueId) {
  250.             if (empty($valueId)) {
  251.                 continue;
  252.             }
  253.             $alias 'gdv_' . (int)$declinationId;
  254.             $qb
  255.                 ->innerJoin('p.groupDeclinationValues'$alias)
  256.                 ->andWhere($alias '.declination = :decl_' $declinationId)
  257.                 ->andWhere($alias '.value = :val_' $declinationId)
  258.                 ->setParameter('decl_' $declinationId, (int)$declinationId)
  259.                 ->setParameter('val_' $declinationId, (int)$valueId);
  260.         }
  261.         // đŸ” Stock
  262.         $qb->leftJoin('p.stocks''s');
  263.         if ($isAvailable !== "") {
  264.             if ($isAvailable) {
  265.                 $qb->andWhere('(s.qtStock - s.qtReserved) >= 1');
  266.             } else {
  267.                 $qb->andWhere('(s.qtStock - s.qtReserved) <= 0');
  268.             }
  269.         }
  270.         // đŸ” Produit
  271.         $qb->leftJoin('p.produit''pp');
  272.         if ($categories) {
  273.             $qb->leftJoin('pp.categories''ppc')
  274.             ->andWhere('ppc.id = :categories')
  275.             ->setParameter('categories'$categories);
  276.         }
  277.         if ($inPromo !== "") {
  278.             if ($inPromo == '1') {
  279.                 $qb->join('pp.promotion''promo')
  280.                 ->andWhere(':now >= promo.startAt')
  281.                 ->andWhere(':now <= promo.endAt')
  282.                 ->setParameter('now', new \DateTime('now'));
  283.             } elseif ($inPromo == '0') {
  284.                 $qb->andWhere('pp.promotion IS NULL');
  285.             }
  286.         }
  287.         // đŸ” Prix
  288.         if ($buyingPriceMin$qb->andWhere('pp.buyingPriceTtc >= :buyingPriceMin')->setParameter('buyingPriceMin'$buyingPriceMin);
  289.         if ($buyingPriceMax$qb->andWhere('pp.buyingPriceTtc <= :buyingPriceMax')->setParameter('buyingPriceMax'$buyingPriceMax);
  290.         if ($priceMin)       $qb->andWhere('pp.price_ttc >= :priceMin')->setParameter('priceMin'$priceMin);
  291.         if ($priceMax)       $qb->andWhere('pp.price_ttc <= :priceMax')->setParameter('priceMax'$priceMax);
  292.         // đŸ” QuantitĂ©
  293.         if ($qtMin$qb->andWhere('s.qtStock >= :qtMin')->setParameter('qtMin'$qtMin);
  294.         if ($qtMax$qb->andWhere('s.qtStock <= :qtMax')->setParameter('qtMax'$qtMax);
  295.         // đŸ” Suppression
  296.         $qb->andWhere('pp.deletedAt IS ' . ($withDeleted 'NOT' '') . ' NULL');
  297.         return $qb;
  298.     }
  299.     public function findDeclinationValueWithDeclination($idDeclination$idProduit) {
  300.         $qb $this->createQueryBuilder('p');
  301.         $qb->leftJoin('p.produit''pp')->andWhere('pp.deletedAt IS NULL')
  302.                 ->andWhere('pp.id = :produit')->setParameter('produit'$idProduit);
  303.         $qb->leftJoin('p.groupDeclinationValues''pgc')
  304.                ->leftJoin('pgc.declination''pgcd')
  305.                ->leftJoin('pgc.value''pgcv')
  306.                ->andWhere('pgcv.id = :idDeclination')->setParameter('idDeclination'$idDeclination );
  307.         $qb->orderBy('p.reference''ASC');
  308.         return $qb->getQuery()->getResult();
  309.     }
  310.     
  311.     public function qtyAvailable($prdDec)
  312.     {
  313.         $qb $this->createQueryBuilder('p');
  314.         $qb->leftJoin('p.stocks','s')
  315.             ->Select('(s.qtStock - s.qtReserved) as qtAvailable')
  316.             ->where('p.id = :id')
  317.             ->setParameter('id'$prdDec->getId());
  318.         dd($qb->getQuery()->getSingleScalarResult());
  319.     }
  320.     public function qtyReserved($prdDec)
  321.     {
  322.         $qb $this->createQueryBuilder('p');
  323.         $qb->leftJoin('p.stocks','s')
  324.             ->Select('s.qtReserved as qtReserved')
  325.             ->where('p.id = :id')
  326.             ->setParameter('id'$prdDec->getId());
  327.         dd($qb->getQuery()->getSingleScalarResult());
  328.     }
  329.     //fonction et requĂȘte pour dĂ©clinaion 1 (Exemple : Couleur)
  330.    public function getStatsByDeclinationPosition($idProduit, ?string $dateBefore, ?string $dateAfter): array
  331.     {
  332.         $conn $this->getEntityManager()->getConnection();
  333.         $sql "
  334.             SELECT 
  335.                 dcl.name AS declinaison_label,
  336.                 v.name AS valeur,
  337.                 (
  338.                     SELECT f.image_name
  339.                     FROM produit_declination_value_file pdf
  340.                     JOIN file f ON f.id = pdf.file_id
  341.                     WHERE pdf.produit_declination_value_id = pdv.id
  342.                     LIMIT 1
  343.                 ) AS decli_image,
  344.                 SUM(ddp.quantity) AS qtTotal,
  345.                 SUM(CASE WHEN d.status NOT IN ('annule', 'retourne', 'retour-en-cours') THEN ddp.quantity ELSE 0 END) AS qtVendu,
  346.                 SUM(CASE WHEN d.status = 'annule' THEN ddp.quantity ELSE 0 END) AS qtAnnulee,
  347.                 SUM(CASE WHEN d.status IN ('retourne', 'retour-en-cours') THEN ddp.quantity ELSE 0 END) AS qtRetour,
  348.                 SUM(ddp.total_amount_ttc) AS montantTotal
  349.             FROM document_declination_produit ddp
  350.             JOIN produit_declination_value pdv ON ddp.produit_declination_value_id = pdv.id
  351.             JOIN group_declination_value gdv ON gdv.produit_declination_id = pdv.id
  352.             JOIN value_declination v ON v.id = gdv.value_id
  353.             JOIN declination dcl ON dcl.id = v.declination_id AND dcl.position = 1
  354.             JOIN document d ON d.id = ddp.document_id
  355.             WHERE pdv.produit_id = :idProduit
  356.             AND d.type = 'commande'
  357.             AND d.category = 'client'
  358.         ";
  359.         $params = ['idProduit' => $idProduit];
  360.         if ($dateBefore && $dateAfter) {
  361.             $sql .= " AND d.created_at BETWEEN :dateBefore AND :dateAfter";
  362.             $params['dateBefore'] = $dateBefore;
  363.             $params['dateAfter']  = $dateAfter;
  364.         } elseif ($dateBefore) {
  365.             $sql .= " AND d.created_at >= :dateBefore";
  366.             $params['dateBefore'] = $dateBefore;
  367.         } elseif ($dateAfter) {
  368.             $sql .= " AND d.created_at <= :dateAfter";
  369.             $params['dateAfter'] = $dateAfter;
  370.         }
  371.         $sql .= "
  372.             GROUP BY dcl.name, v.name
  373.             ORDER BY qtTotal DESC
  374.         ";
  375.         $stmt $conn->prepare($sql);
  376.         $result $stmt->executeQuery($params);
  377.         return $result->fetchAllAssociative();
  378.     }
  379.     //fonction et requĂȘte pour toutes les dĂ©clinaisons
  380.     public function getAllDeclinationsStats($idProduit, ?string $dateBefore, ?string $dateAfter): array
  381. {
  382.     $conn $this->getEntityManager()->getConnection();
  383.     $sql "
  384.         SELECT 
  385.             dcl1.name AS declinaison1_label,
  386.             v1.name   AS declinaison1_valeur,
  387.             pdv.id    AS decli_id,
  388.             -- DĂ©clinaison 2 (ex : Taille)
  389.             dcl2.name AS declinaison2_label,
  390.             v2.name   AS declinaison2_valeur,
  391.             -- Totaux
  392.             SUM(ddp.quantity) AS qtTotal,
  393.             SUM(
  394.                 CASE 
  395.                     WHEN d.status NOT IN ('annule', 'retourne', 'retour-en-cours') 
  396.                     THEN ddp.quantity 
  397.                     ELSE 0 
  398.                 END
  399.             ) AS qtVendu,
  400.             SUM(
  401.                 CASE 
  402.                     WHEN d.status = 'annule' 
  403.                     THEN ddp.quantity 
  404.                     ELSE 0 
  405.                 END
  406.             ) AS qtAnnulee,
  407.             SUM(
  408.                 CASE 
  409.                     WHEN d.status IN ('retourne', 'retour-en-cours') 
  410.                     THEN ddp.quantity 
  411.                     ELSE 0 
  412.                 END
  413.             ) AS qtRetour,
  414.             SUM(ddp.total_amount_ttc) AS montantTotal
  415.         FROM document_declination_produit ddp
  416.         JOIN produit_declination_value pdv 
  417.             ON ddp.produit_declination_value_id = pdv.id
  418.         -- DĂ©clinaison 1 (ex : Couleur)
  419.         JOIN group_declination_value gdv1 
  420.             ON gdv1.produit_declination_id = pdv.id
  421.         JOIN value_declination v1 
  422.             ON v1.id = gdv1.value_id
  423.         JOIN declination dcl1 
  424.             ON dcl1.id = v1.declination_id 
  425.            AND dcl1.position = 1
  426.         -- DĂ©clinaison 2 (ex : Taille)
  427.         JOIN group_declination_value gdv2 
  428.             ON gdv2.produit_declination_id = pdv.id
  429.         JOIN value_declination v2 
  430.             ON v2.id = gdv2.value_id
  431.         JOIN declination dcl2 
  432.             ON dcl2.id = v2.declination_id
  433.            AND dcl2.position = 2
  434.         JOIN document d 
  435.             ON d.id = ddp.document_id
  436.         WHERE pdv.produit_id = :idProduit
  437.           AND d.type = 'commande'
  438.           AND d.category = 'client'
  439.     ";
  440.     $params = ['idProduit' => $idProduit];
  441.     /* Gestion dynamique des dates */
  442.     if ($dateBefore !== null && $dateAfter !== null) {
  443.         $sql .= " AND d.created_at BETWEEN :dateBefore AND :dateAfter";
  444.         $params['dateBefore'] = $dateBefore;
  445.         $params['dateAfter']  = $dateAfter;
  446.     } elseif ($dateBefore !== null) {
  447.         $sql .= " AND d.created_at >= :dateBefore";
  448.         $params['dateBefore'] = $dateBefore;
  449.     } elseif ($dateAfter !== null) {
  450.         $sql .= " AND d.created_at <= :dateAfter";
  451.         $params['dateAfter'] = $dateAfter;
  452.     }
  453.     $sql .= "
  454.         GROUP BY dcl1.name, v1.name, v2.name, pdv.id
  455.         ORDER BY v1.name ASC, v2.name ASC
  456.     ";
  457.     $stmt   $conn->prepare($sql);
  458.     $result $stmt->executeQuery($params);
  459.     return $result->fetchAllAssociative();
  460. }
  461.     public function countByValue(ValueDeclination $value): int
  462.     {
  463.         return $this->createQueryBuilder('gdv')
  464.             ->select('COUNT(gdv.id)')
  465.             ->where('gdv.value = :val')
  466.             ->setParameter('val'$value)
  467.             ->getQuery()
  468.             ->getSingleScalarResult();
  469.     }
  470. }