From 76f25a038f4a4dae4ea8540fbaa347165569bc5a Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Sat, 22 Aug 2009 03:09:52 +0000 Subject: [PATCH] Fix: bug #27197 : Fix discount applied twice --- htdocs/admin/system/index.php | 6 +- htdocs/comm/remx.php | 4 +- htdocs/facture.class.php | 206 +++++++++--------- htdocs/fourn/fournisseur.facture.class.php | 11 +- .../modules/commande/pdf_einstein.modules.php | 2 +- .../modules/facture/pdf_crabe.modules.php | 2 +- .../propale/pdf_propale_azur.modules.php | 2 +- .../pdf/pdf_muscadet.modules.php | 2 +- htdocs/install/upgrade2.php | 153 +++++++++++++ htdocs/langs/en_US/install.lang | 1 + htdocs/langs/fr_FR/install.lang | 1 + htdocs/lib/databases/mssql.lib.php | 28 +-- mysql/migration/2.6.0-2.7.0.sql | 4 + mysql/tables/llx_facturedet.key.sql | 3 +- 14 files changed, 304 insertions(+), 121 deletions(-) diff --git a/htdocs/admin/system/index.php b/htdocs/admin/system/index.php index f35131378a0..d0d541ca89c 100644 --- a/htdocs/admin/system/index.php +++ b/htdocs/admin/system/index.php @@ -74,7 +74,8 @@ print "
\n"; // Php print ''; print "\n"; -print "\n"; +$phpversion=version_php(); +print "\n"; print "\n"; print '
".$langs->trans("Php")."
".$langs->trans("Version")."".version_php()."
".$langs->trans("Version")."".$phpversion."
".$langs->trans("PhpWebLink")."".php_sapi_name()."
'; @@ -83,7 +84,8 @@ print "
\n"; // Database print ''; print "\n"; -print "\n"; +$dbversion=$db->getVersion(); +print "\n"; print '
".$langs->trans("Database")."
".$langs->trans("Version")."" . $db->getVersion() . "
".$langs->trans("Version")."" .$dbversion. "
'; print '
'; diff --git a/htdocs/comm/remx.php b/htdocs/comm/remx.php index 2d29eee1638..d02b542cd38 100644 --- a/htdocs/comm/remx.php +++ b/htdocs/comm/remx.php @@ -294,7 +294,7 @@ if ($_socid > 0) print_titre($langs->trans("DiscountStillRemaining")); print ''; print ''; - print ''; + print ''; // Need 120+ for format with AM/PM print ''; print ''; print ''; @@ -430,7 +430,7 @@ if ($_socid > 0) print_titre($langs->trans("DiscountAlreadyCounted")); print '
'.$langs->trans("Date").''.$langs->trans("Date").''.$langs->trans("ReasonDiscount").''.$langs->trans("ConsumedBy").''.$langs->trans("AmountHT").'
'; print ''; - print ''; + print ''; // Need 120+ for format with AM/PM print ''; print ''; print ''; diff --git a/htdocs/facture.class.php b/htdocs/facture.class.php index 4c0f27fad33..3b65cf151dc 100644 --- a/htdocs/facture.class.php +++ b/htdocs/facture.class.php @@ -77,12 +77,12 @@ class Facture extends CommonObject //! 2=classified paid partially (close_code='discount_vat','badcustomer') or completely (close_code=null), //! 3=classified abandoned and no payment done (close_code='badcustomer','abandon' ou 'replaced') var $statut; - //! 1 si facture payée COMPLETEMENT, 0 sinon (ce champ ne devrait plus servir car insuffisant) + //! 1 if invoice paid COMPLETELY, 0 otherwise (ce champ ne devrait plus servir car insuffisant) var $paye; //! id of source invoice if replacement invoice or credit note var $fk_facture_source; //! Fermeture apres paiement partiel: discount_vat, badcustomer, abandon - //! Fermeture alors que aucun paiement: replaced (si remplacé), abandon + //! Fermeture alors que aucun paiement: replaced (si remplac�), abandon var $close_code; //! Commentaire si mis a paye sans paiement complet var $close_note; @@ -100,12 +100,12 @@ class Facture extends CommonObject var $nbtodo; var $nbtodolate; var $specimen; - //! Numero d'erreur de 512 à 1023 + //! Numero d'erreur de 512 � 1023 var $errno = 0; /** \brief Constructeur de la classe - \param DB handler accès base de données + \param DB handler acc�s base de donn�es \param socid id societe ('' par defaut) \param facid id facture ('' par defaut) */ @@ -260,7 +260,7 @@ class Facture extends CommonObject * Insert lines of invoices in database */ //dol_syslog("There is ".sizeof($this->lignes)." lines"); - for ($i = 0 ; $i < sizeof($this->lignes) ; $i++) + foreach ($this->lignes as $i => $val) { $newinvoiceline=new FactureLigne($this->db); $newinvoiceline=$this->lignes[$i]; @@ -281,7 +281,7 @@ class Facture extends CommonObject */ if (! $error && $this->fac_rec > 0) { - for ($i = 0 ; $i < sizeof($_facrec->lignes) ; $i++) + foreach ($_facrec->lignes as $i => $val) { if ($_facrec->lignes[$i]->produit_id) { @@ -376,11 +376,12 @@ class Facture extends CommonObject $facture->remise_percent = $this->remise_percent; $facture->lignes = $this->lignes; // Tableau des lignes de factures - $facture->products = $this->lignes; // Tant que products encore utilisé + $facture->products = $this->lignes; // Tant que products encore utilise - if ($invertdetail) + // Loop on each line of new invoice + foreach($facture->lignes as $i => $line) { - foreach($facture->lignes as $i => $line) + if ($invertdetail) { $facture->lignes[$i]->subprice = -$facture->lignes[$i]->subprice; $facture->lignes[$i]->price = -$facture->lignes[$i]->price; @@ -428,7 +429,17 @@ class Facture extends CommonObject $object->ref_client = ''; $object->close_code = ''; $object->close_note = ''; - $object->products = $object->lignes; // Tant que products encore utilisé + $object->products = $object->lignes; // Tant que products encore utilise + + // Loop on each line of new invoice + foreach($object->lignes as $i => $line) + { + if (($object->lignes[$i]->info_bits & 0x02) == 0x02) // We do not clone line of discounts + { + unset($object->lignes[$i]); + unset($object->products[$i]); // Tant que products encore utilise + } + } // Create clone $result=$object->create($user); @@ -849,7 +860,7 @@ class Facture extends CommonObject $facligne->desc=$remise->description; // Description ligne $facligne->tva_tx=$remise->tva_tx; $facligne->subprice=-$remise->amount_ht; - $facligne->fk_product=0; // Id produit prédéfini + $facligne->fk_product=0; // Id produit pr�d�fini $facligne->qty=1; $facligne->remise_percent=0; $facligne->rang=-1; @@ -869,7 +880,7 @@ class Facture extends CommonObject $result=$this->update_price(); if ($result > 0) { - // Crée lien entre remise et ligne de facture + // Cr�e lien entre remise et ligne de facture $result=$remise->link_to_invoice($lineid,0); if ($result < 0) { @@ -925,7 +936,7 @@ class Facture extends CommonObject /** * \brief Delete invoice - * \param rowid Id de la facture à supprimer + * \param rowid Id de la facture � supprimer * \return int <0 si ko, >0 si ok */ function delete($rowid=0) @@ -956,7 +967,7 @@ class Facture extends CommonObject $list_rowid_det[]=$obj->rowid; } - // On désaffecte de la facture les remises liées + // On d�saffecte de la facture les remises li�es if (sizeof($list_rowid_det)) { $sql = 'UPDATE '.MAIN_DB_PREFIX.'societe_remise_except'; @@ -1027,8 +1038,8 @@ class Facture extends CommonObject /** \brief Renvoi une date limite de reglement de facture en fonction des conditions de reglements de la facture et date de facturation - \param cond_reglement_id Condition de reglement à utiliser, 0=Condition actuelle de la facture - \return date Date limite de réglement si ok, <0 si ko + \param cond_reglement_id Condition de reglement � utiliser, 0=Condition actuelle de la facture + \return date Date limite de r�glement si ok, <0 si ko */ function calculate_date_lim_reglement($cond_reglement_id=0) { @@ -1060,7 +1071,7 @@ class Facture extends CommonObject // 1 : ajout du nombre de jours $datelim = $this->date + ( $cdr_nbjour * 3600 * 24 ); - // 2 : application de la règle "fin de mois" + // 2 : application de la r�gle "fin de mois" if ($cdr_fdm) { $mois=date('m', $datelim); @@ -1074,22 +1085,22 @@ class Facture extends CommonObject { $mois += 1; } - // On se déplace au début du mois suivant, et on retire un jour + // On se d�place au d�but du mois suivant, et on retire un jour $datelim=dol_mktime(12,0,0,$mois,1,$annee); $datelim -= (3600 * 24); } - // 3 : application du décalage + // 3 : application du d�calage $datelim += ( $cdr_decalage * 3600 * 24); return $datelim; } /** - * \brief Tag la facture comme payée complètement (close_code non renseigné) ou partiellement (close_code renseigné) + appel trigger BILL_PAYED + * \brief Tag la facture comme pay�e compl�tement (close_code non renseign�) ou partiellement (close_code renseign�) + appel trigger BILL_PAYED * \param user Objet utilisateur qui modifie - * \param close_code Code renseigné si on classe à payée complètement alors que paiement incomplet (cas ecompte par exemple) - * \param close_note Commentaire renseigné si on classe à payée alors que paiement incomplet (cas ecompte par exemple) + * \param close_code Code renseign� si on classe � pay�e compl�tement alors que paiement incomplet (cas ecompte par exemple) + * \param close_note Commentaire renseign� si on classe � pay�e alors que paiement incomplet (cas ecompte par exemple) * \return int <0 si ok, >0 si ok */ function set_paid($user,$close_code='',$close_note='') @@ -1129,9 +1140,9 @@ class Facture extends CommonObject /** - * \brief Tag la facture comme non payée complètement + appel trigger BILL_UNPAYED - * Fonction utilisée quand un paiement prélevement est refusé, - * ou quand une facture annulée et réouverte. + * \brief Tag la facture comme non pay�e compl�tement + appel trigger BILL_UNPAYED + * Fonction utilis�e quand un paiement pr�levement est refus�, + * ou quand une facture annul�e et r�ouverte. * \param user Object user that change status * \return int <0 si ok, >0 si ok */ @@ -1163,7 +1174,7 @@ class Facture extends CommonObject /** - \brief Tag la facture comme abandonnée, sans paiement dessus (exemple car facture de remplacement) + appel trigger BILL_CANCEL + \brief Tag la facture comme abandonn�e, sans paiement dessus (exemple car facture de remplacement) + appel trigger BILL_CANCEL \param user Objet utilisateur qui modifie \param close_code Code de fermeture \param close_note Commentaire de fermeture @@ -1186,8 +1197,8 @@ class Facture extends CommonObject $resql = $this->db->query($sql); if ($resql) { - // On désaffecte de la facture les remises liées - // car elles n'ont pas été utilisées vu que la facture est abandonnée. + // On d�saffecte de la facture les remises li�es + // car elles n'ont pas �t� utilis�es vu que la facture est abandonn�e. $sql = 'UPDATE '.MAIN_DB_PREFIX.'societe_remise_except'; $sql.= ' SET fk_facture = NULL'; $sql.= ' WHERE fk_facture = '.$this->id; @@ -1223,10 +1234,10 @@ class Facture extends CommonObject } /** - * \brief Tag la facture comme validée + appel trigger BILL_VALIDATE + * \brief Tag la facture comme valid�e + appel trigger BILL_VALIDATE * \param user Utilisateur qui valide la facture * \param soc Ne sert plus. \\TODO A virer - * \param force_number Référence à forcer de la facture + * \param force_number R�f�rence � forcer de la facture * \return int <0 si ko, >0 si ok */ function set_valid($user, $soc='', $force_number='') @@ -1335,10 +1346,10 @@ class Facture extends CommonObject $error++; } - // On vérifie si la facture était une provisoire + // On v�rifie si la facture �tait une provisoire if (! $error && (eregi('^\(PROV', $this->ref) || eregi('^PROV', $this->ref))) { - // La vérif qu'une remise n'est pas utilisée 2 fois est faite au moment de l'insertion de ligne + // La v�rif qu'une remise n'est pas utilis�e 2 fois est faite au moment de l'insertion de ligne } if (! $error) @@ -1346,7 +1357,7 @@ class Facture extends CommonObject // Define third party as a customer $result=$this->client->set_as_client(); - // Si activé on décrémente le produit principal et ses composants à la validation de facture + // Si activ� on d�cr�mente le produit principal et ses composants � la validation de facture if ($result >= 0 && $conf->stock->enabled && $conf->global->STOCK_CALCULATE_ON_BILL) { require_once(DOL_DOCUMENT_ROOT."/product/stock/mouvementstock.class.php"); @@ -1358,7 +1369,7 @@ class Facture extends CommonObject { $mouvP = new MouvementStock($this->db); // We decrease stock for product - $entrepot_id = "1"; // TODO ajouter possibilité de choisir l'entrepot + $entrepot_id = "1"; // TODO ajouter possibilit� de choisir l'entrepot $result=$mouvP->livraison($user, $this->lignes[$i]->fk_product, $entrepot_id, $this->lignes[$i]->qty, $this->lignes[$i]->subprice); if ($result < 0) { $error++; } } @@ -1372,7 +1383,7 @@ class Facture extends CommonObject if (eregi('^\(PROV', $this->ref) || eregi('^PROV', $this->ref)) { // On renomme repertoire facture ($this->ref = ancienne ref, $num = nouvelle ref) - // afin de ne pas perdre les fichiers attachés + // afin de ne pas perdre les fichiers attach�s $facref = dol_sanitizeFileName($this->ref); $snumfa = dol_sanitizeFileName($num); $dirsource = $conf->facture->dir_output.'/'.$facref; @@ -1442,7 +1453,7 @@ class Facture extends CommonObject dol_syslog("Facture::set_draft sql=".$sql, LOG_DEBUG); if ($this->db->query($sql)) { - // Si activé on décrémente le produit principal et ses composants à la validation de facture + // Si activ� on d�cr�mente le produit principal et ses composants � la validation de facture if ($result >= 0 && $conf->stock->enabled && $conf->global->STOCK_CALCULATE_ON_BILL) { require_once(DOL_DOCUMENT_ROOT."/product/stock/mouvementstock.class.php"); @@ -1453,7 +1464,7 @@ class Facture extends CommonObject { $mouvP = new MouvementStock($this->db); // We decrease stock for product - $entrepot_id = "1"; // TODO ajouter possibilité de choisir l'entrepot + $entrepot_id = "1"; // TODO ajouter possibilit� de choisir l'entrepot $result=$mouvP->reception($user, $this->lignes[$i]->fk_product, $entrepot_id, $this->lignes[$i]->qty, $this->lignes[$i]->subprice); } } @@ -1479,12 +1490,12 @@ class Facture extends CommonObject * \param facid Id de la facture * \param desc Description de la ligne * \param pu_ht Prix unitaire HT - * \param qty Quantité - * \param txtva Taux de tva forcé, sinon -1 - * \param fk_product Id du produit/service predéfini + * \param qty Quantit� + * \param txtva Taux de tva forc�, sinon -1 + * \param fk_product Id du produit/service pred�fini * \param remise_percent Pourcentage de remise de la ligne - * \param date_start Date de debut de validité du service - * \param date_end Date de fin de validité du service + * \param date_start Date de debut de validit� du service + * \param date_end Date de fin de validit� du service * \param ventil Code de ventilation comptable * \param info_bits Bits de type de lignes * \param fk_remise_except Id remise @@ -1492,8 +1503,8 @@ class Facture extends CommonObject * \param pu_ttc Prix unitaire TTC * \param type Type of line (0=product, 1=service) * \return int >0 if OK, <0 if KO - * \remarks Les parametres sont deja censé etre juste et avec valeurs finales a l'appel - * de cette methode. Aussi, pour le taux tva, il doit deja avoir ete défini + * \remarks Les parametres sont deja cens� etre juste et avec valeurs finales a l'appel + * de cette methode. Aussi, pour le taux tva, il doit deja avoir ete d�fini * par l'appelant par la methode get_default_tva(societe_vendeuse,societe_acheteuse,taux_produit) * et le desc doit deja avoir la bonne valeur (a l'appelant de gerer le multilangue) */ @@ -1614,8 +1625,8 @@ class Facture extends CommonObject * \param pu Prix unitaire (HT ou TTC selon price_base_type) * \param qty Quantity * \param remise_percent Pourcentage de remise de la ligne - * \param date_start Date de debut de validité du service - * \param date_end Date de fin de validité du service + * \param date_start Date de debut de validit� du service + * \param date_end Date de fin de validit� du service * \param tva_tx VAT Rate * \param price_base_type HT or TTC * \param info_bits Miscellanous informations @@ -1958,10 +1969,10 @@ class Facture extends CommonObject $sql.= ' AND type < 2'; if ($option == 'validated') $sql.= ' AND fk_statut = 1'; // PROTECTION BAD DATA - // Au cas ou base corrompue et qu'il y a une facture de remplacement validée - // et une autre non, on donne priorité à la validée. - // Ne devrait pas arriver (sauf si accès concurrentiel et que 2 personnes - // ont créé en meme temps une facture de remplacement pour la meme facture) + // Au cas ou base corrompue et qu'il y a une facture de remplacement valid�e + // et une autre non, on donne priorit� � la valid�e. + // Ne devrait pas arriver (sauf si acc�s concurrentiel et que 2 personnes + // ont cr�� en meme temps une facture de remplacement pour la meme facture) $sql.= ' ORDER BY fk_statut DESC'; $resql=$this->db->query($sql); @@ -1986,7 +1997,7 @@ class Facture extends CommonObject } /** - * \brief Retourne le libellé du type de facture + * \brief Retourne le libell� du type de facture * \return string Libelle */ function getLibType() @@ -2001,8 +2012,8 @@ class Facture extends CommonObject /** - * \brief Retourne le libellé du statut d'une facture (brouillon, validée, abandonnée, payée) - * \param mode 0=libellé long, 1=libellé court, 2=Picto + Libellé court, 3=Picto, 4=Picto + Libellé lon + * \brief Retourne le libell� du statut d'une facture (brouillon, valid�e, abandonn�e, pay�e) + * \param mode 0=libell� long, 1=libell� court, 2=Picto + Libell� court, 3=Picto, 4=Picto + Libell� lon * \param alreadypaid 0=Not payment already done, 1=Some payments already done * \return string Libelle */ @@ -2012,13 +2023,13 @@ class Facture extends CommonObject } /** - * \brief Renvoi le libellé d'un statut donné + * \brief Renvoi le libell� d'un statut donn� * \param paye Etat paye * \param statut Id statut - * \param mode 0=libellé long, 1=libellé court, 2=Picto + Libellé court, 3=Picto, 4=Picto + Libellé long, 5=Libellé court + Pict - * \param alreadypaid Montant deja payé + * \param mode 0=libell� long, 1=libell� court, 2=Picto + Libell� court, 3=Picto, 4=Picto + Libell� long, 5=Libell� court + Pict + * \param alreadypaid Montant deja pay� * \param type Type facture - * \return string Libellé du statut + * \return string Libell� du statut */ function LibStatut($paye,$statut,$mode=0,$alreadypaid=-1,$type=0) { @@ -2136,8 +2147,8 @@ class Facture extends CommonObject } /** - * \brief Renvoie la référence de facture suivante non utilisée en fonction du module - * de numérotation actif défini dans FACTURE_ADDON + * \brief Renvoie la r�f�rence de facture suivante non utilis�e en fonction du module + * de num�rotation actif d�fini dans FACTURE_ADDON * \param soc objet societe * \return string reference libre pour la facture */ @@ -2152,7 +2163,7 @@ class Facture extends CommonObject { $file = FACTURE_ADDON."/".FACTURE_ADDON.".modules.php"; - // Chargement de la classe de numérotation + // Chargement de la classe de num�rotation $classname = "mod_facture_".FACTURE_ADDON; require_once($dir.$file); @@ -2221,8 +2232,8 @@ class Facture extends CommonObject } /** - * \brief Change les conditions de réglement de la facture - * \param cond_reglement_id Id de la nouvelle condition de réglement + * \brief Change les conditions de r�glement de la facture + * \param cond_reglement_id Id de la nouvelle condition de r�glement * \param date Date to force payment term * \return int >0 si ok, <0 si ko */ @@ -2270,7 +2281,7 @@ class Facture extends CommonObject /** - * \brief Change le mode de réglement + * \brief Change le mode de r�glement * \param mode Id du nouveau mode * \return int >0 si ok, <0 si ko */ @@ -2304,13 +2315,13 @@ class Facture extends CommonObject /** - * \brief Renvoi si les lignes de facture sont ventilées et/ou exportées en compta - * \param user Utilisateur créant la demande + * \brief Renvoi si les lignes de facture sont ventil�es et/ou export�es en compta + * \param user Utilisateur cr�ant la demande * \return int <0 si ko, 0=non, 1=oui */ function getVentilExportCompta() { - // On vérifie si les lignes de factures ont été exportées en compta et/ou ventilées + // On v�rifie si les lignes de factures ont �t� export�es en compta et/ou ventil�es $ventilExportCompta = 0 ; for ($i = 0 ; $i < sizeof($this->lignes) ; $i++) { @@ -2332,9 +2343,9 @@ class Facture extends CommonObject /** - * \brief Renvoi si une facture peut etre supprimée complètement. - * La règle est la suivante: - * Si facture dernière, non provisoire, sans paiement et non exporté en compta -> oui fin de règle + * \brief Renvoi si une facture peut etre supprim�e compl�tement. + * La r�gle est la suivante: + * Si facture derni�re, non provisoire, sans paiement et non export� en compta -> oui fin de r�gle * Si facture brouillon et provisoire -> oui * \return int <0 si ko, 0=non, 1=oui */ @@ -2342,14 +2353,14 @@ class Facture extends CommonObject { global $conf; - // on vérifie si la facture est en numérotation provisoire + // on v�rifie si la facture est en num�rotation provisoire $facref = substr($this->ref, 1, 4); // Si facture non brouillon et non provisoire if ($facref != 'PROV' && $conf->global->FACTURE_ENABLE_EDITDELETE) { - // On ne peut supprimer que la dernière facture validée - // pour ne pas avoir de trou dans la numérotation + // On ne peut supprimer que la derni�re facture valid�e + // pour ne pas avoir de trou dans la num�rotation $sql = "SELECT MAX(facnumber)"; $sql.= " FROM ".MAIN_DB_PREFIX."facture"; $sql.= " WHERE entity = ".$conf->entity; @@ -2362,7 +2373,7 @@ class Facture extends CommonObject $ventilExportCompta = $this->getVentilExportCompta(); - // Si derniere facture et si non ventilée, on peut supprimer + // Si derniere facture et si non ventil�e, on peut supprimer if ($maxfacnumber[0] == $this->ref && $ventilExportCompta == 0) { return 1; @@ -2379,7 +2390,7 @@ class Facture extends CommonObject /** * \brief Renvoi liste des factures remplacables - * Statut validée ou abandonnée pour raison autre + non payée + aucun paiement + pas deja remplacée + * Statut valid�e ou abandonn�e pour raison autre + non pay�e + aucun paiement + pas deja remplac�e * \param socid Id societe * \return array Tableau des factures ('id'=>id, 'ref'=>ref, 'status'=>status, 'paymentornot'=>0/1) */ @@ -2396,7 +2407,7 @@ class Facture extends CommonObject $sql.= " LEFT JOIN ".MAIN_DB_PREFIX."facture as ff ON f.rowid = ff.fk_facture_source"; $sql.= " WHERE (f.fk_statut = 1 OR (f.fk_statut = 3 AND f.close_code = 'abandon'))"; $sql.= " AND f.entity = ".$conf->entity; - $sql.= " AND f.paye = 0"; // Pas classée payée complètement + $sql.= " AND f.paye = 0"; // Pas class�e pay�e compl�tement $sql.= " AND pf.fk_paiement IS NULL"; // Aucun paiement deja fait $sql.= " AND ff.fk_statut IS NULL"; // Renvoi vrai si pas facture de remplacement if ($socid > 0) $sql.=" AND f.fk_soc = ".$socid; @@ -2427,7 +2438,7 @@ class Facture extends CommonObject /** * \brief Renvoi liste des factures qualifiables pour correction par avoir * Les factures qui respectent les regles suivantes sont retournees: - * (validée + paiement en cours) ou classée (payée completement ou payée partiellement) + pas deja remplacée + pas deja avoi + * (valid�e + paiement en cours) ou class�e (pay�e completement ou pay�e partiellement) + pas deja remplac�e + pas deja avoi * \param socid Id societe * \return array Tableau des factures ($id => $ref) */ @@ -2444,8 +2455,8 @@ class Facture extends CommonObject $sql.= " WHERE f.entity = ".$conf->entity; $sql.= " AND f.fk_statut in (1,2)"; // $sql.= " WHERE f.fk_statut >= 1"; - // $sql.= " AND (f.paye = 1"; // Classée payée complètement - // $sql.= " OR f.close_code IS NOT NULL)"; // Classée payée partiellement + // $sql.= " AND (f.paye = 1"; // Class�e pay�e compl�tement + // $sql.= " OR f.close_code IS NOT NULL)"; // Class�e pay�e partiellement $sql.= " AND ff.type IS NULL"; // Renvoi vrai si pas facture de remplacement $sql.= " AND f.type != 2"; // Type non 2 si facture non avoir if ($socid > 0) $sql.=" AND f.fk_soc = ".$socid; @@ -2480,8 +2491,8 @@ class Facture extends CommonObject /** - * \brief Créé une demande de prélèvement - * \param user Utilisateur créant la demande + * \brief Cr�� une demande de pr�l�vement + * \param user Utilisateur cr�ant la demande * \return int <0 si ko, >0 si ok */ function demande_prelevement($user) @@ -2526,8 +2537,8 @@ class Facture extends CommonObject } else { - $this->error="Une demande existe déjà"; - dol_syslog('Facture::DemandePrelevement Impossible de créer une demande, demande déja en cours'); + $this->error="Une demande existe d�j�"; + dol_syslog('Facture::DemandePrelevement Impossible de cr�er une demande, demande d�ja en cours'); } } else @@ -2546,8 +2557,8 @@ class Facture extends CommonObject } /** - * \brief Supprime une demande de prélèvement - * \param user utilisateur créant la demande + * \brief Supprime une demande de pr�l�vement + * \param user utilisateur cr�ant la demande * \param did id de la demande a supprimer */ function demande_prelevement_delete($user, $did) @@ -2635,14 +2646,14 @@ class Facture extends CommonObject /** - * \brief Initialise la facture avec valeurs fictives aléatoire - * Sert à générer une facture pour l'aperu des modèles ou dem + * \brief Initialise la facture avec valeurs fictives al�atoire + * Sert � g�n�rer une facture pour l'aperu des mod�les ou dem */ function initAsSpecimen() { global $user,$langs,$conf; - // Charge tableau des id de société socids + // Charge tableau des id de soci�t� socids $socids = array(); $sql = "SELECT rowid"; @@ -2790,17 +2801,18 @@ class FactureLigne var $tva_tx; // Taux tva produit/service (example 19.6) var $subprice; // P.U. HT (example 100) var $remise_percent; // % de la remise ligne (example 20%) + var $fk_remise_except; // Link to line into llx_remise_except var $rang = 0; var $info_bits = 0; // Liste d'options cumulables: // Bit 0: 0 si TVA normal - 1 si TVA NPR - // Bit 1: 0 si ligne normal - 1 si bit discount + // Bit 1: 0 si ligne normal - 1 si bit discount (link to line into llx_remise_except) - //! Total HT de la ligne toute quantité et incluant la remise ligne + //! Total HT de la ligne toute quantite et incluant la remise ligne var $total_ht; - //! Total TVA de la ligne toute quantité et incluant la remise ligne + //! Total TVA de la ligne toute quantite et incluant la remise ligne var $total_tva; - //! Total TTC de la ligne toute quantité et incluant la remise ligne + //! Total TTC de la ligne toute quantite et incluant la remise ligne var $total_ttc; var $fk_code_ventilation = 0; @@ -2811,7 +2823,7 @@ class FactureLigne // Ne plus utiliser var $price; // P.U. HT apres remise % de ligne (exemple 80) - var $remise; // Montant calculé de la remise % sur PU HT (exemple 20) + var $remise; // Montant calcul� de la remise % sur PU HT (exemple 20) // From llx_product var $ref; // Reference produit @@ -2821,7 +2833,7 @@ class FactureLigne /** \brief Constructeur d'objets ligne de facture - \param DB handler d'accès base de donnée + \param DB handler d'acc�s base de donn�e */ function FactureLigne($DB) { @@ -2829,7 +2841,7 @@ class FactureLigne } /** - * \brief Recupére l'objet ligne de facture + * \brief Recupere l'objet ligne de facture * \param rowid id de la ligne de facture */ function fetch($rowid) @@ -2909,7 +2921,7 @@ class FactureLigne $rangtouse=$this->rang; if ($rangtouse == -1) { - // Récupère rang max de la facture dans $rangmax + // R�cup�re rang max de la facture dans $rangmax $sql = 'SELECT max(rang) as max FROM '.MAIN_DB_PREFIX.'facturedet'; $sql.= ' WHERE fk_facture ='.$this->fk_facture; $resql = $this->db->query($sql); @@ -2965,8 +2977,8 @@ class FactureLigne { $this->rowid=$this->db->last_insert_id(MAIN_DB_PREFIX.'facturedet'); - // Si fk_remise_except défini, on lie la remise à la facture - // ce qui la flague comme "consommée". + // Si fk_remise_except d�fini, on lie la remise � la facture + // ce qui la flague comme "consomm�e". if ($this->fk_remise_except) { $discount=new DiscountAbsolute($this->db); diff --git a/htdocs/fourn/fournisseur.facture.class.php b/htdocs/fourn/fournisseur.facture.class.php index 6defb02a2d9..dbf3c7dd01b 100644 --- a/htdocs/fourn/fournisseur.facture.class.php +++ b/htdocs/fourn/fournisseur.facture.class.php @@ -152,7 +152,7 @@ class FactureFournisseur extends Facture if ($resql) { $this->id = $this->db->last_insert_id(MAIN_DB_PREFIX.'facture_fourn'); - for ($i = 0 ; $i < sizeof($this->lignes) ; $i++) + foreach ($this->lignes as $i => $val) { $sql = 'INSERT INTO '.MAIN_DB_PREFIX.'facture_fourn_det (fk_facture_fourn)'; $sql .= ' VALUES ('.$this->id.');'; @@ -894,6 +894,15 @@ class FactureFournisseur extends Facture $object->close_code = ''; $object->close_note = ''; + // Loop on each line of new invoice + foreach($object->lignes as $i => $line) + { + if (($object->lignes[$i]->info_bits & 0x02) == 0x02) // We do not clone line of discounts + { + unset($object->lignes[$i]); + } + } + // Create clone $result=$object->create($user); diff --git a/htdocs/includes/modules/commande/pdf_einstein.modules.php b/htdocs/includes/modules/commande/pdf_einstein.modules.php index 5318a56a7d2..88d256a3fc8 100644 --- a/htdocs/includes/modules/commande/pdf_einstein.modules.php +++ b/htdocs/includes/modules/commande/pdf_einstein.modules.php @@ -277,7 +277,7 @@ class pdf_einstein extends ModelePDFCommandes // Collecte des totaux par valeur de tva dans $this->tva["taux"]=total_tva $tvaligne=$com->lignes[$i]->total_tva; $vatrate=(string) $com->lignes[$i]->tva_tx; - if ($com->lignes[$i]->info_bits & 0x01 == 0x01) $vatrate.='*'; + if (($com->lignes[$i]->info_bits & 0x01) == 0x01) $vatrate.='*'; $this->tva[$vatrate] += $tvaligne; $nexY+=2; // Passe espace entre les lignes diff --git a/htdocs/includes/modules/facture/pdf_crabe.modules.php b/htdocs/includes/modules/facture/pdf_crabe.modules.php index fda85dc0c14..7efb39b6a53 100644 --- a/htdocs/includes/modules/facture/pdf_crabe.modules.php +++ b/htdocs/includes/modules/facture/pdf_crabe.modules.php @@ -284,7 +284,7 @@ class pdf_crabe extends ModelePDFFactures $tvaligne=$fac->lignes[$i]->total_tva; if ($fac->remise_percent) $tvaligne-=($tvaligne*$fac->remise_percent)/100; $vatrate=(string) $fac->lignes[$i]->tva_tx; - if ($fac->lignes[$i]->info_bits & 0x01 == 0x01) $vatrate.='*'; + if (($fac->lignes[$i]->info_bits & 0x01) == 0x01) $vatrate.='*'; $this->tva[$vatrate] += $tvaligne; $nexY+=2; // Passe espace entre les lignes diff --git a/htdocs/includes/modules/propale/pdf_propale_azur.modules.php b/htdocs/includes/modules/propale/pdf_propale_azur.modules.php index b8dbdfa184e..74cbab8b194 100644 --- a/htdocs/includes/modules/propale/pdf_propale_azur.modules.php +++ b/htdocs/includes/modules/propale/pdf_propale_azur.modules.php @@ -292,7 +292,7 @@ class pdf_propale_azur extends ModelePDFPropales $tvaligne=$propale->lignes[$i]->total_tva; if ($propale->remise_percent) $tvaligne-=($tvaligne*$propale->remise_percent)/100; $vatrate=(string) $propale->lignes[$i]->tva_tx; - if ($propale->lignes[$i]->info_bits & 0x01 == 0x01) $vatrate.='*'; + if (($propale->lignes[$i]->info_bits & 0x01) == 0x01) $vatrate.='*'; $this->tva[$vatrate] += $tvaligne; $nexY+=2; // Passe espace entre les lignes diff --git a/htdocs/includes/modules/supplier_order/pdf/pdf_muscadet.modules.php b/htdocs/includes/modules/supplier_order/pdf/pdf_muscadet.modules.php index 406ce94ed76..c4ba2b60db5 100644 --- a/htdocs/includes/modules/supplier_order/pdf/pdf_muscadet.modules.php +++ b/htdocs/includes/modules/supplier_order/pdf/pdf_muscadet.modules.php @@ -279,7 +279,7 @@ class pdf_muscadet extends ModelePDFSuppliersOrders $tvaligne=$com->lignes[$i]->total_tva; if ($com->remise_percent) $tvaligne-=($tvaligne*$com->remise_percent)/100; $vatrate=(string) $com->lignes[$i]->tva_tx; - if ($com->lignes[$i]->info_bits & 0x01 == 0x01) $vatrate.='*'; + if (($com->lignes[$i]->info_bits & 0x01) == 0x01) $vatrate.='*'; $this->tva[$vatrate] += $tvaligne; $nexY+=2; // Passe espace entre les lignes diff --git a/htdocs/install/upgrade2.php b/htdocs/install/upgrade2.php index 933a6f226f5..7318b40413d 100644 --- a/htdocs/install/upgrade2.php +++ b/htdocs/install/upgrade2.php @@ -220,6 +220,7 @@ if (isset($_POST['action']) && eregi('upgrade',$_POST["action"])) migrate_commande_deliveryaddress($db,$langs,$conf); + migrate_restore_missing_links($db,$langs,$conf); // On commit dans tous les cas. // La procedure etant concue pour pouvoir passer plusieurs fois quelquesoit la situation. @@ -2184,6 +2185,158 @@ function migrate_commande_deliveryaddress($db,$langs,$conf) } +/* + * Migration du champ fk_remise_except dans llx_facturedet doit correspondre a + * lien dans llx_societe_remise_except vers llx_facturedet + */ +function migrate_restore_missing_links($db,$langs,$conf) +{ + dolibarr_install_syslog("upgrade2::migrate_restore_missing_links"); + + if (($db->type == 'mysql' || $db->type == 'mysqli')) + { + if (versioncompare($db->getVersionArray(),array(4,0)) < 0) + { + dolibarr_install_syslog("upgrade2::migrate_restore_missing_links Version of database too old to make this migrate action"); + return 0; + } + } + print ''; + + + print ''; +} + + /* A faire egalement: Modif statut paye et fk_facture des factures payes completement On recherche facture incorrecte: diff --git a/htdocs/langs/en_US/install.lang b/htdocs/langs/en_US/install.lang index 920d9e190d8..eef03a6ed7f 100644 --- a/htdocs/langs/en_US/install.lang +++ b/htdocs/langs/en_US/install.lang @@ -135,6 +135,7 @@ InstallChoiceSuggested=Install choice suggested by installer. ######### # upgrade ######### +MigrationFixData=Fix for denormalized data MigrationOrder=Data migration for customers' orders MigrationSupplierOrder=Data migration for suppliers' orders MigrationProposal=Data migration for commercial proposals diff --git a/htdocs/langs/fr_FR/install.lang b/htdocs/langs/fr_FR/install.lang index 57ee110c087..d5658329ac9 100644 --- a/htdocs/langs/fr_FR/install.lang +++ b/htdocs/langs/fr_FR/install.lang @@ -137,6 +137,7 @@ InstallChoiceSuggested=Choix suggéré par l'installeur. ######### # upgrade ######### +MigrationFixData=Correction de données dénormalisées MigrationOrder=Migration de données sur les commandes clients MigrationSupplierOrder=Migration de données sur les commandes fournisseurs MigrationProposal=Migration de données sur les propositions commerciales diff --git a/htdocs/lib/databases/mssql.lib.php b/htdocs/lib/databases/mssql.lib.php index 384c8ea3cd8..78be280c789 100644 --- a/htdocs/lib/databases/mssql.lib.php +++ b/htdocs/lib/databases/mssql.lib.php @@ -47,21 +47,21 @@ class DoliDb var $forcecollate='latin1_swedish_ci'; //! Version min database var $versionmin=array(2000); - //! Resultset de la derni�re requete + //! Resultset de la derniere requete var $results; - //! 1 si connect�, 0 sinon + //! 1 si connecte, 0 sinon var $connected; - //! 1 si base s�lectionn�, 0 sinon + //! 1 si base selectionne, 0 sinon var $database_selected; - //! Nom base s�lectionn�e + //! Nom base selectionnee var $database_name; //! Nom user base var $database_user; //! 1 si une transaction est en cours, 0 sinon var $transaction_opened; - //! Derniere requete ex�cut�e + //! Derniere requete executee var $lastquery; - //! Derniere requete ex�cut�e avec echec + //! Derniere requete executee avec echec var $lastqueryerror; //! Message erreur mysql var $lasterror; @@ -73,14 +73,14 @@ class DoliDb /** - \brief Ouverture d'une connexion vers le serveur et �ventuellement une database. - \param type Type de base de donn�es (mysql ou pgsql) - \param host Addresse de la base de donn�es - \param user Nom de l'utilisateur autoris� - \param pass Mot de passe - \param name Nom de la database - \param port Port of database server - \return int 1 en cas de succ�s, 0 sinon + * \brief Ouverture d'une connexion vers le serveur et eventuellement une database. + * \param type Type de base de donnees (mysql ou pgsql) + * \param host Addresse de la base de donnees + * \param user Nom de l'utilisateur autorise + * \param pass Mot de passe + * \param name Nom de la database + * \param port Port of database server + * \return int 1 en cas de succes, 0 sinon */ function DoliDb($type='mssql', $host, $user, $pass, $name='', $port=0) { diff --git a/mysql/migration/2.6.0-2.7.0.sql b/mysql/migration/2.6.0-2.7.0.sql index 6d61ceb4929..ec1aece8e3a 100644 --- a/mysql/migration/2.6.0-2.7.0.sql +++ b/mysql/migration/2.6.0-2.7.0.sql @@ -289,3 +289,7 @@ insert into llx_action_def (rowid,code,titre,description,objet_type) values (4,' insert into llx_c_tva(rowid,fk_pays,taux,recuperableonly,note,active) values ( 51, 5, '19','0','VAT standard rate',1); insert into llx_c_tva(rowid,fk_pays,taux,recuperableonly,note,active) values ( 52, 5, '7','0','VAT reduced rate', 1); insert into llx_c_tva(rowid,fk_pays,taux,recuperableonly,note,active) values ( 53, 5, '0','0','VAT Rate 0', 1); + +-- Add rule to avoid duplicate use of discount +update llx_facturedet set fk_remise_except = null where fk_remise_except = 0; +ALTER TABLE llx_facturedet ADD UNIQUE INDEX uk_fk_remise_except (fk_remise_except); diff --git a/mysql/tables/llx_facturedet.key.sql b/mysql/tables/llx_facturedet.key.sql index 26bf20c2de8..3421ae46655 100644 --- a/mysql/tables/llx_facturedet.key.sql +++ b/mysql/tables/llx_facturedet.key.sql @@ -19,8 +19,9 @@ -- =================================================================== --- Supprimme orhpelins pour permettre montée de la clé +-- Supprimme orhpelins pour permettre mont�e de la cl� -- V4 DELETE llx_facturedet FROM llx_facturedet LEFT JOIN llx_facture ON llx_facturedet.fk_facture = llx_facture.rowid WHERE llx_facture.rowid IS NULL; ALTER TABLE llx_facturedet ADD INDEX idx_facturedet_fk_facture (fk_facture); +ALTER TABLE llx_facturedet ADD UNIQUE INDEX uk_fk_remise_except (fk_remise_except); ALTER TABLE llx_facturedet ADD CONSTRAINT fk_facturedet_fk_facture FOREIGN KEY (fk_facture) REFERENCES llx_facture (rowid);
'.$langs->trans("Date").''.$langs->trans("Date").''.$langs->trans("ReasonDiscount").''.$langs->trans("ConsumedBy").''.$langs->trans("AmountHT").'
'; + + print '
'; + print ''.$langs->trans('MigrationFixData')." (1)
\n"; + + $error = 0; + + + // Restore missing link for this cross foreign key (link 1 <=> 1). Direction 1. + $table1='facturedet'; $field1='fk_remise_except'; + $table2='societe_remise_except'; $field2='fk_facture_line'; + + $db->begin(); + + $sql = "SELECT t1.rowid, t1.".$field1." as field"; + $sql.= " FROM ".MAIN_DB_PREFIX.$table1." as t1"; + $sql.= " WHERE t1.".$field1." IS NOT NULL AND t1.".$field1." NOT IN"; + $sql.= " (SELECT t2.rowid FROM ".MAIN_DB_PREFIX.$table2." as t2"; + $sql.= " WHERE t1.rowid = t2.".$field2.")"; + + dolibarr_install_syslog("upgrade2:migrate_restore_missing_links DIRECTION 1 sql=".$sql); + $resql = $db->query($sql); + if ($resql) + { + $i = 0; + $num = $db->num_rows($resql); + + if ($num) + { + while ($i < $num) + { + $obj = $db->fetch_object($resql); + + print 'Line '.$obj->rowid.' in '.$table1.' is linked to record '.$obj->field.' in '.$table2.' that has no link to '.$table1.'. We fix this.
'; + $sql = "UPDATE ".MAIN_DB_PREFIX.$table2." SET"; + $sql.= " ".$field2." = '".$obj->rowid."'"; + $sql.= " WHERE rowid=".$obj->field; + + $resql2=$db->query($sql); + if (! $resql2) + { + $error++; + dol_print_error($db); + } + //print ". "; + $i++; + } + + } + else print $langs->trans('AlreadyDone')."
\n"; + + if ($error == 0) + { + $db->commit(); + } + else + { + $db->rollback(); + } + } + else + { + dol_print_error($db); + $db->rollback(); + } + + print '
'; + + print '
'; + print ''.$langs->trans('MigrationFixData')." (2)
\n"; + + // Restore missing link for this cross foreign key (link 1 <=> 1). Direction 2. + $table2='facturedet'; $field2='fk_remise_except'; + $table1='societe_remise_except'; $field1='fk_facture_line'; + + $db->begin(); + + $sql = "SELECT t1.rowid, t1.".$field1." as field"; + $sql.= " FROM ".MAIN_DB_PREFIX.$table1." as t1"; + $sql.= " WHERE t1.".$field1." IS NOT NULL AND t1.".$field1." NOT IN"; + $sql.= " (SELECT t2.rowid FROM ".MAIN_DB_PREFIX.$table2." as t2"; + $sql.= " WHERE t1.rowid = t2.".$field2.")"; + + dolibarr_install_syslog("upgrade2:migrate_restore_missing_links DIRECTION 2 sql=".$sql); + $resql = $db->query($sql); + if ($resql) + { + $i = 0; + $num = $db->num_rows($resql); + + if ($num) + { + while ($i < $num) + { + $obj = $db->fetch_object($resql); + + print 'Line '.$obj->rowid.' in '.$table1.' is linked to record '.$obj->field.' in '.$table2.' that has no link to '.$table1.'. We fix this.
'; + $sql = "UPDATE ".MAIN_DB_PREFIX.$table2." SET"; + $sql.= " ".$field2." = '".$obj->rowid."'"; + $sql.= " WHERE rowid=".$obj->field; + + $resql2=$db->query($sql); + if (! $resql2) + { + $error++; + dol_print_error($db); + } + //print ". "; + $i++; + } + + } + else print $langs->trans('AlreadyDone')."
\n"; + + if ($error == 0) + { + $db->commit(); + } + else + { + $db->rollback(); + } + } + else + { + dol_print_error($db); + $db->rollback(); + } + + print '