Problème de calcul avec (SUM) Mysql /PHP

Résolu
Bonjour à tous,

Je rencontre un problème en essayant de faire le calcul des sommes payés pour une facture.
J'ai une table shoppings dans laquelle je rentre le prix ht, la tva, etc...
Pour une même facture je peux avoir plusieurs lignes (articles).

Quand j'additionne le prix ht, et la TVA des lignes d'une même facture, j'ai les bon chiffres.

par contre quand je fais la même chose sur la table paiements, c'est a dire que quand je fais la somme des paiements correspondant à une facture ça ne fonctionne pas, ça me sort des chiffres incohérents.

pourtant ils sont bien identifier par le numéro de facture, je n'arrive pas a savoir d’où viens le problème.

Dans la table shoppings il y a le champs id_invoice, dans la table paiements aussi il y le champs id_invoice.

le champs correspondant au paiement dans la table paiements s'apelle montant

ci-dessous avec la jointure de la table paiements



Dans cette image sans la jointure de la table paiement avec les bon chiffres



php>
$sql = "SUM(montant_tva) AS montant_tva, SUM(prix_ht) AS prix_ht, SUM(montant) AS montant , taux_tva, statut_type, invoice.id_invoice FROM shoppings
LEFT JOIN invoice ON (shoppings.id_invoice=invoice.id_invoice)

LEFT JOIN paiements ON (shoppings.id_invoice=paiements.id_invoice)

WHERE etat = 1";

13 réponses

Résumé de la discussion

Le problème concerne le calcul des sommes payées par facture lorsque plusieurs articles sont enregistrés dans la table shoppings et que les paiements sont agrégés par id_invoice. Plusieurs réponses indiquent que les sommes calculées séparément sur les lignes de shoppings semblent correctes, tandis que celles issues des paiements donnent des chiffres incohérents malgré l’identification par le même identifiant. Pour résoudre le problème, la solution retenue consiste à calculer séparément les totaux par facture via des sous-requêtes, puis à les réunir par id_invoice avec une jointure appropriée. En pratique, cela permet d obtenir une ligne par facture avec des totaux exacts même en présence de NULL ou de filtres supplémentaires.

Bobot (l’IA à votre service)
  1. Contributeur Ambassadeur
    bonjour, as-tu essayé d'ajouter une clause GROUP BY?
    0
    1. Bonjour,

      oui j'ai fait GROUP BY invoice.id_invoice à la ligne 43

      
      <script type="text/javascript">
                  $(document).ready(function(){
                      $('#tableData').paging({limit:15});
                  });
              </script>
      
      <?php
      
      
      //on inclus le fichier de connexion à la bdd 
      require_once "../inc/connexion.php";
      //connexion à la bdd
      $bdd = getDB();
      
      // on récupère PROPREMENT les variables AVANT de les utiliser
      $query = !empty($_POST["query"]) ? $_POST["query"]: NULL;
      //var_dump($query);
      //on prépare la requête SQL
      $sql = "SELECT SUM(montant) AS  prix_ttc, SUM(montant_tva) AS montant_tva, SUM(prix_ht) AS prix_ht,  taux_tva,   invoice.id_invoice FROM shoppings  
                                                                                                                   LEFT JOIN invoice ON (shoppings.id_invoice=invoice.id_invoice)  
                                                                                                                   LEFT JOIN paiements ON (shoppings.id_invoice=paiements.id_invoice)  
                                                                                              
      																											 WHERE  etat = 1";  
      
      
      //début du traitement :
      if($query){
       $search = $query;
      // var_dump($search);
      
       //si il y a une recherche on ajoute le WHERE à la requete :
        $sql .= "	AND etat = 1 AND invoice.id_invoice LIKE '%".$search."%' 
      
      	
      
                         ";
      				   
                  //     var_dump($sql);
      
      }
      //concaténation de  $sql = " SELECT * FROM customers  ";  pour afficher les entrées de client en DESC
      $sql .= "    GROUP by invoice.id_invoice DESC  " ;  
      //$sql .= " AND  type=1 OR (statut_type=1 OR statut_type=2 OR statut_type=3 OR statut_type=4 OR statut_type=5)  AND etat = 1 GROUP BY invoice.id_invoice DESC" ;  
      //Execution de la requete
      try{
        $requete = $bdd -> prepare($sql) ;  
        $requete->execute() ;
        $result = $requete->fetchAll(); // on stocke le resultat dans un array
      }catch(Exception $e){
        // en cas d'erreur :
         echo " Erreur ! ".$e->getMessage();
      }
      
      ?>
      
      <html>
        <head>
          <meta charset="utf-8">
        
        </head>
        <body>
          <?php
          $output = '';
      
          if(!empty($result)) {
          $output .= '</br>
                       
      		       <div class="box-body table-responsive no-padding" id="tableData">
      		       <table class="table table-striped ">
                        <thead>
                          <tr>
                            <th>ID </th>
      
                         
                            <th>Total HT</th>
                            <th>Total TVA</th>
                            <th>Total TTC</th>
                            <th>Paiement</th>
      
                          </tr>
                        </thead>
                        <tbody>';
         									try	
      		{
           $db = getDB();		
         }
         catch (Exception $e)
         {
           die('Erreur : ' . $e->getMessage());
         }
      
            foreach($result as $row){   	
      	  
      	  
      				
      		
      	//	$ttc = number_format ($row['prix_ttc'],2);
      	//	$paiements =number_format ($row['montant'],2) ;		
      	//	$balance  = $ttc - $paiements;
      				
              $output .= '
      
      	         <tr>
      			
      				<td  width="1%"> <a href="../form/invoice.php?id_invoice='. $row['id_invoice'] .' "><button type="button" class="btn btn-block btn-primary btn-xs flat">' . $row['id_invoice'] . '</td>
      
      			
      				<td width="6%">'. number_format ($row['prix_ht'],2).'</td>				       
      				<td width="6%">'. number_format ($row['montant_tva'],2).'</td>				       
      				<td width="6%">'. number_format ($row['prix_ttc'],2).'</td>				       
      	
      				</tr>
                  ';
            }
            echo '</tbody>
                </table></div>';
          } else {
            echo 'Données non trouvées';
          }
          echo $output;
          ?>
        </body>
      </html>
      
      
      0
      1. Contributeur Ambassadeur
        peux-tu donner la liste des champs de chaque table, ou, au minimum, ajouter le nom de la table à chaque champ dans le SELECT?
        peux-tu éviter de nous montrer des images, partages plutôt du texte.
        teste ta requête après avoir retiré les SUM: tout te semble-t'il logique?
        si, pour un même id_invoice, tu as plusieurs enregistrements dans la table shoppings ainsi que dans la table paiements, tu ne peux pas faire les sommes ainsi. cela devrait être clair quand tu exécutes la requête sans SUM.
        tu dois faire plutôt ainsi:
        select a.nfacture, a.prixtotal, b.montanttotal
        from
        (select invoice.id_invoice as nfacture, sum(prix_ht) as prixtotal from invoice left join shoppings ON shoppings.id_invoice=invoice.id_invoice) as a,
        (select invoice.id_invoice as nfacture, sum(montant) as montanttotal from invoice left join paiements ON paiements .id_invoice=invoice.id_invoice) as b
        where a.nfacture=b.nfacture
        0
        1. Voici la liste des champs de la table

          Table invoice :

          id_invoice
          id_customer
          created

          Table shoppings :

          id_shoppings
          id_invoice
          id_items
          prix_ht
          montant_tva
          etat

          Table paiements :

          id_paiement
          id_invoice
          montant
          method
          metodid
          date_paiement

          J'ai retirer les SUM, quand il y a plusieurs lignes ça m'affiche que le dernier qui insérer
          0
        2. ça m'affiche une ligne avec l’addition total est ça me dit Undefined index: id_invoice
          0
        3. Contributeur Ambassadeur
          @Jules_2569as-tu testé ma suggestion en dehors du PHP?
          0
      2. J'ai rien compris a votre requête, ça m'embrouille plus qu'autre chose.
        0
        1. Contributeur Ambassadeur
          ce sera sans doute plus clair de d'abord tester séparément avec ces deux requêtes, et d'en observer les résultats:
          select invoice.id_invoice as nfacture, sum(prix_ht) as prixtotal from invoice left join shoppings ON shoppings.id_invoice=invoice.id_invoice

          select invoice.id_invoice as nfacture, sum(montant) as montanttotal from invoice left join paiements ON paiements .id_invoice=invoice.id_invoice
          0
          1. Effectivement, c’est plus clair, les requêtes une par une fonctionne, les résultats sont corrects. Comment intégrer les deux ensembles?
            0
            1. Contributeur Ambassadeur
              comme suggéré en #3.
              si tu as sauvé et nommé les deux requetes individuelles, tu peux les utiliser ainsi:
              select a.nfacture, a.prixtotal, b.montanttotal
              from
              requete_un as a,
              requete_deux as b
              where a.nfacture=b.nfacture
              0
          2. Voici ce que j'ai fait :
            $sql ="
            select a.nfacture, a.prixtotal, b.montanttotal
            from
            select invoice.id_invoice as nfacture, sum(prix_ht) as prixtotal from invoice left join shoppings ON shoppings.id_invoice=invoice.id_invoice
             as a,
            select invoice.id_invoice as nfacture, sum(montant) as montanttotal from invoice left join paiements ON paiements .id_invoice=invoice.id_invoice 
             as b
            where a.nfacture=b.nfacture
            ";  
            


            J'ai le message ci-dessous :

            Erreur ! SQLSTATE[42000]: Syntax error or access violation: 1064 You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'select invoice.id_invoice as nfacture, sum(prix_ht) as prixtotal from invoice le' at line 3 Données non trouvées 
            
            0
            1. Modérateur
              Bonjour,
              Tu dois placer tes sous-requêtes dans des parenthèses
              SELECT a.*,b.*
              FROM
              ( select .. from table1....) as a
              ,( select .. from table2....) as b
              
              0
          3. J'ai ajouté les parenthèse, j'ai une seule ligne avec l’addition du prixtotal et pareil pour le montanttotal .

            j'ai fait GROUP BY nfacture. c'est pareil, il n'y a pas de message.

            $sql ="
            select a.nfacture, a.prixtotal, b.montanttotal
            from
            (select invoice.id_invoice as nfacture, sum(prix_ht) as prixtotal from invoice left join shoppings ON shoppings.id_invoice=invoice.id_invoice)
             as a,
            (select invoice.id_invoice as nfacture, sum(montant) as montanttotal from invoice left join paiements ON paiements .id_invoice=invoice.id_invoice )
             as b
            where a.nfacture=b.nfacture
            ";  
            
            ²
            0
            1. Contributeur Ambassadeur
              c'est préférable de d'abord tester les requêtes hors PHP.
              quel message attends-tu?
              tu obtiens une seule ligne, est-elle correcte? que contient-elle? qu'attends-tu d'autre?
              0
          4. Quand j'ai dis il n'y a pas de message, je voulais dire pas de message d'erreur. Je n'attends aucun message.

            la ligne que j'obtiens et l'addition du prix de toutes les factures et de tout les paiements. ce que j'attends c'est chaque facture (chaque ligne du tableau) a ses paiements, quand il en a pas ça met zéro.

            en gros pour chaque ligne (numéro de facture) du tableau je voudrais avoir le total ht, le montant de la tva, le total ttc de la table shoppings, et le paiement déjà reçu de la table paiements, pour pouvoir voir d'un coup d'oeil, le prix de la facture et le reste a payer a coté.

            après je ferais une soustraction du montant de la facture moins le paiements déjà reçu pour voir le solde restant a payer pour chaque facture.
            0
            1. Contributeur Ambassadeur
              en #12, tu indiquais que les requêtes une par une donnaient le résultat attendu, donc une ligne par facture. c'est bien cela?
              la requête combinée, testée en dehors de PHP, donne, quant à elle, une seule ligne?
              0
          5. je l'ai fait dans phpmyadmin, j'ai le même résultat, une seule ligne. Oui quand je les teste une par une ça me donne une ligne par facture.

            mes factures vont de 182 à 190, ça me fait une ligne avec l'id de la facture 182 la 1ère et a coté le total ht la dernière case le total des paiements.

            ça vient peut-être de la clause where? ou il manque un condition.
            0
            1. Contributeur Ambassadeur
              ou c'est la seule facture qui est présente dans les deux sous-requêtes?

              les totaux sont bien corrects pour la facture 182?

              si tu as trop peu de résultats, il y aurait plutôt trop de conditions dans le WHERE.

              peux-tu partager le texte SQL des trois requêtes, telles que tu fais dans phpmyadmin?
              0
          6. Non ce n'est pas la seule facture de présente. Par contre il y a des factures ou il n'y a pas encore d'articles (c'est a dire que la ligne n'existe que dans la table invoice) et des factures ou il n'y a pas de paiements reçu. je veux quand même qu'il me les affiches.

            Dans les exemples ci-dessous, pour certaines lignes du tableau, le paiements montanttotal peut être supérieur au prix de la facture prixtotal, c'est normal car il manque le montant de la tva qui doit s'ajouter au prixtotal.

            Quand je teste les requête une par une les totaux sont corrects.

            Même si je retire la clause WHERE, le résultat est le même une seule ligne

            Quand je teste la requêtes combinés ça me donne le résultat ci-dessous.:

            nfacture prixtotal montantotal
            182 1732 1287

            Tester une par une

            SELECT invoice.id_invoice AS nfacture, sum( prix_ht ) AS prixtotal
            FROM invoice
            LEFT JOIN shoppings ON ( shoppings.id_invoice = invoice.id_invoice )
            GROUP BY nfacture
            


            nfacture prixtotal
            182 416
            183 327
            184 189
            185 414
            186 109
            187 208
            188 NULL
            189 NULL
            190 NULL
            191 69

            Tester une par une

            SELECT invoice.id_invoice AS nfacture, sum( montant ) AS montanttotal
            FROM invoice
            LEFT JOIN paiements ON ( invoice.id_invoice = paiements.id_invoice )
            GROUP BY nfacture
            


            nfacture montanttotal
            182 181.8
            183 392.4
            184 226.8
            185 22.8
            186 130.8
            187 249.6
            188 NULL
            189 NULL
            190 NULL
            191 82.8
            0
            1. Contributeur Ambassadeur
              peux-tu montrer également la source SQL de la requête combinée, telle que tu la testes en phpmyadmin?
              0
            2. Contributeur Ambassadeur
              pour avoir 0 au lieu de NULL, tu peux faire:
              sum( ifnull(prix_ht,0) )
              0
            3. @yg_beCi-dessous la requête combinée avec son résultat plus bas

              select a.nfacture, a.prixtotal, b.montanttotal
              from
              (select invoice.id_invoice as nfacture, sum(prix_ht) as prixtotal from invoice left join shoppings ON shoppings.id_invoice=invoice.id_invoice)
               as a,
              (select invoice.id_invoice as nfacture, sum(montant) as montanttotal from invoice left join paiements ON paiements .id_invoice=invoice.id_invoice )
               as b
              where a.nfacture=b.nfacture    
              


              résultat requête combinée :

              nfacture prixtotal montantotal
              182 1732 1287
              0
            4. @Jules_2569J'ajoute que si je retire de la requête combinée la clause WHERE ou le GROUP BY, c'est toujours le même résultat.
              0
            5. @yg_beVoir #25 et #26
              0
          7. Ok merci, comme mes dernières réponses était plus haut que ton dernier messages, je pensais qu'il serait peut être pas pris en compte
            0
            1. Contributeur Ambassadeur
              des suggestions et une demande:
              - sois patient, n'imagine pas que nous n'avons rien d'autre à faire
              - essaie de nous donner le maximum d'information, de nous montrer le maximum d'éléments factuels, pour compléter tes idées et tes questions
              - fais nous confiance, nous essayons de t'aider, même si la réponse ne t'aide pas immédiatement. nous essayons en même temps de t'aider à court terme, et de t'aider à long terme, en te rendant autonome
              - respecte-nous
              - peux-tu marquer cette discussion comme résolue, et en ouvrir une nouvelle si utile?
              0
              1. Désolé d'avoir été impatient. J'ai bien compris ce que tu veux dire pour le reste.
                0