diff --git a/.editorconfig b/.editorconfig index 143f0739505..5b3e0d6a8df 100644 --- a/.editorconfig +++ b/.editorconfig @@ -8,14 +8,10 @@ charset = utf-8 end_of_line = lf insert_final_newline = true [*.php] -indent_style = space -indent_size = 4 +indent_style = tab [*.js] -indent_style = space -indent_size = 2 +indent_style = tab [*.css] -indent_style = space -indent_size = 2 +indent_style = tab [*.xml] -indent_style = space -indent_size = 4 +indent_style = tab diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 7fefd5100b5..a603fd242cc 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -3,7 +3,10 @@ How to contribute to Dolibarr Bug reports and feature requests -------------------------------- -** NEW ** + +*Note*: Issues are not a support forum. If you need help using the software, please use [the forums](http://www.dolibarr.org/forum). + +**NEW** Issues are now managed on [GitHub](https://github.com/Dolibarr/dolibarr/Issues). @@ -44,11 +47,11 @@ Use clear commit messages with the following structure:
 FIX|Fix #456 Short description (where #456 is number of bug fix, if it exists. In upper case to appear into ChangeLog)
 or
-CLOSE|Close #456 Short description (where #456 is number feature request, if it exists. In upper case to appear into ChangeLog)
+CLOSE|Close #456 Short description (where #456 is number of feature request, if it exists. In upper case to appear into ChangeLog)
 or
-NEW|New Short description (In upper case to appear into ChangeLog)
+NEW|New Short description (In upper case to appear into ChangeLog, use this if you add a feature not tracked, otherwise use CLOSE #456)
 or
-Short description (when the commit is not introducing feature or closing a bug)
+Short description (when the commit is not introducing feature nor closing a bug)
 
 Long description (Can span accross multiple lines).
 
diff --git a/COPYRIGHT b/COPYRIGHT index e4bd78e7bbf..3c7cb5bf1cf 100644 --- a/COPYRIGHT +++ b/COPYRIGHT @@ -18,6 +18,7 @@ CKEditor 4.3.3 LGPL-2.1+ Yes FPDI 1.5.2 Apache Software License 2.0 Yes PDF templates management GeoIP 1.4 LGPL-2.1+ Yes Sample code to make geoip convert (not into deb package) NuSoap 0.9.5 LGPL 2.1+ Yes Library to develop SOAP Web services (not into rpm and deb package) +PEAR Mail_MIME 1.8.9 BSD Yes NuSoap dependency odtPHP 1.0.1 GPL-2+ b Yes Library to build/edit ODT files PHPExcel 1.8.0 LGPL-2.1+ Yes Read/Write XLS files, read ODS files php-iban 1.4.6 LGPL-3+ Yes Parse and validate IBAN (and IIBAN) bank account information in PHP diff --git a/ChangeLog b/ChangeLog index 6ed93c77235..618231d8937 100644 --- a/ChangeLog +++ b/ChangeLog @@ -243,6 +243,12 @@ Dolibarr better: - Fix: Bad SEPA xml file creation - Fix: [ bug #1892 ] PHP Fatal error when using USER_UPDATE_SESSION trigger and adding a supplier invoice payment - Fix: Showing system error if not enough stock of product into orders creation with lines +- Fix: [ bug #2543 ] Untranslated "Contract" origin string when creating an invoice from a contract +- Fix: [ bug #2534 ] SQL error when editing a supplier invoice line +- Fix: [ bug #2535 ] Untranslated string in "Linked objects" page of a project +- Fix: [ bug #2545 ] Missing object_margin.png in Amarok theme +- Fix: [ bug #2542 ] Contracts store localtax preferences +- Fix: Bad permission assignments for stock movements actions ***** ChangeLog for 3.6.2 compared to 3.6.1 ***** - Fix: fix ErrorBadValueForParamNotAString error message in price customer multiprice. diff --git a/build/debian/changelog b/build/debian/changelog index 50d2b158e29..a8d056d77ab 100644 --- a/build/debian/changelog +++ b/build/debian/changelog @@ -3,4 +3,4 @@ dolibarr (3.8.0-3) UNRELEASED; urgency=low [ Laurent Destailleur (eldy) ] * New upstream release. - -- Laurent Destailleur (eldy) Tue, 3 Mar 2015 12:00:00 +0100 + -- Laurent Destailleur (eldy) Sun, 21 March 2015 12:00:00 +0100 diff --git a/dev/skeletons/skeleton_class.class.php b/dev/skeletons/skeleton_class.class.php index ff0c2f61200..1f5b56e661b 100644 --- a/dev/skeletons/skeleton_class.class.php +++ b/dev/skeletons/skeleton_class.class.php @@ -270,28 +270,20 @@ class Skeleton_Class extends CommonObject $resql = $this->db->query($sql); if (! $resql) { $error++; $this->errors[]="Error ".$this->db->lasterror(); } - if (! $error) + if (! $error && ! $notrigger) { - if (! $notrigger) - { - // Uncomment this and change MYOBJECT to your own tag if you - // want this action calls a trigger. + // Uncomment this and change MYOBJECT to your own tag if you + // want this action calls a trigger. - //// Call triggers - //$result=$this->call_trigger('MYOBJECT_MODIFY',$user); - //if ($result < 0) { $error++; //Do also what you must do to rollback action if trigger fail} - //// End call triggers - } + //// Call triggers + //$result=$this->call_trigger('MYOBJECT_MODIFY',$user); + //if ($result < 0) { $error++; //Do also what you must do to rollback action if trigger fail} + //// End call triggers } // Commit or rollback if ($error) { - foreach($this->errors as $errmsg) - { - dol_syslog(__METHOD__." ".$errmsg, LOG_ERR); - $this->error.=($this->error?', '.$errmsg:$errmsg); - } $this->db->rollback(); return -1*$error; } @@ -344,11 +336,6 @@ class Skeleton_Class extends CommonObject // Commit or rollback if ($error) { - foreach($this->errors as $errmsg) - { - dol_syslog(__METHOD__." ".$errmsg, LOG_ERR); - $this->error.=($this->error?', '.$errmsg:$errmsg); - } $this->db->rollback(); return -1*$error; } diff --git a/dev/translation/sanity_check_en_langfiles.php b/dev/translation/sanity_check_en_langfiles.php new file mode 100644 index 00000000000..b1ccca39dee --- /dev/null +++ b/dev/translation/sanity_check_en_langfiles.php @@ -0,0 +1,222 @@ + +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see . +*/ + +echo ""; +echo ""; + +echo ""; + +echo ""; +echo "

If you call this file with the argument \"?unused=true\" it searches for the translation strings that exist in en_US but are never used

"; +echo "

IMPORTANT: that can take quite a lot of time (up to 10 minutes), you need to tune the max_execution_time on your php.ini accordingly

"; +echo "

Happy translating :)

"; + +// directory containing the php and lang files +$htdocs = "../../htdocs/"; +// directory containing the english lang files +$workdir = $htdocs."langs/en_US/"; + +$files = scandir($workdir); +$exludefiles = array('.','..','README'); +$files = array_diff($files,$exludefiles); +$langstrings_3d = array(); +$langstrings_full = array(); +foreach ($files AS $file) { + $path_file = pathinfo($file); + // we're only interested in .lang files + if ($path_file['extension']=='lang') { + $content = file($workdir.$file); + foreach ($content AS $line => $row) { + // don't want comment lines + if (substr($row,0,1) !== '#') { + // don't want lines without the separator (why should those even be here, anyway...) + if (strpos($row,'=')!==false) { + $row_array = explode('=',$row); + $langstrings_3d[$path_file['basename']][$line+1]=$row_array[0]; + $langstrings_full[]=$row_array[0]; + $langstrings_dist[$row_array[0]]=$row_array[0]; + } + } + } + } +} + +foreach ($langstrings_3d AS $filename => $file) { + foreach ($file AS $linenum => $value) { + $keys = array_keys($langstrings_full, $value); + if (count($keys)>1) { + foreach ($keys AS $key) { + $dups[$value][$filename][$linenum] = ''; + } + } + } +} + +echo "

Duplicate strings in lang files in $workdir - ".count($dups)." found

"; +echo "
";
+
+echo " ";
+echo "";
+echo "";
+$count = 0;
+foreach ($dups as $string => $pages) {
+	$count++;
+	echo "";
+	echo "";
+	echo "";
+	echo "";
+}
+echo "";
+echo "
#StringFile and lines
$count$string"; + foreach ($pages AS $page => $lines ) { + echo "$page "; + foreach ($lines as $line => $nothing) { + echo "($line) "; + } + echo "
"; + } + echo "
"; + + +if ($_REQUEST['unused'] == 'true') { + + foreach ($langstrings_dist AS $value){ + $search = '\'trans("'.$value.'")\''; + $string = 'grep -R -m 1 -F --include=*.php '.$search.' '.$htdocs.'*'; + exec($string,$output); + if (empty($output)) { + $unused[$value] = true; + echo $value.'
'; + } + } + + echo "

Strings in en_US that are never used

"; + echo "
";
+	print_r($unused);
+}
+echo "";
+echo "";
+?>
\ No newline at end of file
diff --git a/htdocs/accountancy/journal/sellsjournal.php b/htdocs/accountancy/journal/sellsjournal.php
index 7605d54825c..c2c51bacd42 100644
--- a/htdocs/accountancy/journal/sellsjournal.php
+++ b/htdocs/accountancy/journal/sellsjournal.php
@@ -178,7 +178,7 @@ if ($result) {
 
 /*
  * Action
- * FIXME Action must be set before any view part
+ * FIXME Action must be set before any view part to respect MVC
  */
 
 // Bookkeeping Write
diff --git a/htdocs/adherents/admin/public.php b/htdocs/adherents/admin/public.php
index 0f92e017437..19fce918a31 100644
--- a/htdocs/adherents/admin/public.php
+++ b/htdocs/adherents/admin/public.php
@@ -164,7 +164,7 @@ print '';
 print '';
 print $langs->trans("DefaultAmount");
 print '';
-print '';;
+print '';
 print "\n";
 
 // Can edit
@@ -197,7 +197,7 @@ if (! empty($conf->paybox->enabled) || ! empty($conf->paypal->enabled))
     print '';
     print $langs->trans("MEMBER_PAYONLINE_SENDEMAIL");
     print '';
-	print '';;
+	print '';
     print "\n";
 }
 
diff --git a/htdocs/adherents/card.php b/htdocs/adherents/card.php
index 6aa9e074ff6..0fe6366ae58 100644
--- a/htdocs/adherents/card.php
+++ b/htdocs/adherents/card.php
@@ -249,7 +249,7 @@ if (empty($reshook))
 		}
 		$lastname=$_POST["lastname"];
 		$firstname=$_POST["firstname"];
-		$morphy=$morphy=$_POST["morphy"];;
+		$morphy=$morphy=$_POST["morphy"];
 		if ($morphy != 'mor' && empty($lastname)) {
 			$error++;
 			$langs->load("errors");
diff --git a/htdocs/adherents/class/adherent.class.php b/htdocs/adherents/class/adherent.class.php
index c8c4f9b9ad4..941f7b300fd 100644
--- a/htdocs/adherents/class/adherent.class.php
+++ b/htdocs/adherents/class/adherent.class.php
@@ -5,8 +5,9 @@
  * Copyright (C) 2004		Sebastien Di Cintio		
  * Copyright (C) 2004		Benoit Mortier			
  * Copyright (C) 2009-2012	Regis Houssin			
- * Copyright (C) 2014		Alexandre Spangaro		
+ * Copyright (C) 2014-2015	Alexandre Spangaro		
  * Copyright (C) 2015       Marcos García           
+ * Copyright (C) 2015       Frederic France         
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -77,7 +78,8 @@ class Adherent extends CommonObject
 
     var $morphy;
     var $public;
-    var $note;				// Private note
+    var $note_private;		// Private note
+    var $note_public;       // Public note
     var $statut;			// -1:brouillon, 0:resilie, >=1:valide,paye
     var $photo;
 
@@ -310,7 +312,7 @@ class Adherent extends CommonObject
         $sql.= " VALUES (";
         $sql.= " '".$this->db->idate($this->datec)."'";
         $sql.= ", ".($this->login?"'".$this->db->escape($this->login)."'":"null");
-        $sql.= ", ".($user->id>0?$user->id:"null");	// Can be null because member can be createb by a guest or a script
+        $sql.= ", ".($user->id>0?$user->id:"null");	// Can be null because member can be created by a guest or a script
         $sql.= ", null, null, '".$this->morphy."'";
         $sql.= ", '".$this->typeid."'";
         $sql.= ", ".$conf->entity;
@@ -445,9 +447,10 @@ class Adherent extends CommonObject
         $sql.= ", email='".$this->email."'";
         $sql.= ", skype='".$this->skype."'";
         $sql.= ", phone="   .($this->phone?"'".$this->db->escape($this->phone)."'":"null");
-        $sql.= ", phone_perso="  .($this->phone_perso?"'".$this->db->escape($this->phone_perso)."'":"null");
+        $sql.= ", phone_perso=" .($this->phone_perso?"'".$this->db->escape($this->phone_perso)."'":"null");
         $sql.= ", phone_mobile=" .($this->phone_mobile?"'".$this->db->escape($this->phone_mobile)."'":"null");
-        $sql.= ", note="    .($this->note?"'".$this->db->escape($this->note)."'":"null");
+        $sql.= ", note_private=" .($this->note_private?"'".$this->db->escape($this->note_private)."'":"null");
+        $sql.= ", note_public=" .($this->note_private?"'".$this->db->escape($this->note_public)."'":"null");
         $sql.= ", photo="   .($this->photo?"'".$this->photo."'":"null");
         $sql.= ", public='".$this->public."'";
         $sql.= ", statut="  .$this->statut;
@@ -473,7 +476,7 @@ class Adherent extends CommonObject
 		    $action='update';
 
             // Actions on extra fields (by external module)
-			// FIXME le hook fait double emploi avec le trigger !!
+			// TODO le hook fait double emploi avec le trigger !!
 		    $hookmanager->initHooks(array('memberdao'));
             $parameters=array('id'=>$this->id);
             $action='';
@@ -1053,7 +1056,8 @@ class Adherent extends CommonObject
     {
         global $langs;
 
-        $sql = "SELECT d.rowid, d.ref_ext, d.civility as civility_id, d.firstname, d.lastname, d.societe as company, d.fk_soc, d.statut, d.public, d.address, d.zip, d.town, d.note,";
+        $sql = "SELECT d.rowid, d.ref_ext, d.civility as civility_id, d.firstname, d.lastname, d.societe as company, d.fk_soc, d.statut, d.public, d.address, d.zip, d.town, d.note_private,";
+        $sql.= " d.note_public,";
         $sql.= " d.email, d.skype, d.phone, d.phone_perso, d.phone_mobile, d.login, d.pass,";
         $sql.= " d.photo, d.fk_adherent_type, d.morphy, d.entity,";
         $sql.= " d.datec as datec,";
@@ -1134,7 +1138,8 @@ class Adherent extends CommonObject
                 $this->datevalid		= $this->db->jdate($obj->datev);
                 $this->birth			= $this->db->jdate($obj->birthday);
 
-                $this->note				= $obj->note;
+                $this->note_private		= $obj->note_private;
+                $this->note_public      = $obj->note_public;
                 $this->morphy			= $obj->morphy;
 
                 $this->typeid			= $obj->fk_adherent_type;
@@ -1561,7 +1566,8 @@ class Adherent extends CommonObject
 
         $result='';
         $label = '' . $langs->trans("ShowMember") . '';
-        $label.= '
' . $langs->trans('Ref') . ': ' . $this->ref; + if (! empty($this->ref)) + $label.= '
' . $langs->trans('Ref') . ': ' . $this->ref; if (! empty($this->firstname) || ! empty($this->lastname)) $label.= '
' . $langs->trans('Name') . ': ' . $this->getFullName($langs); $linkclose = '" title="'.dol_escape_htmltag($label, 1).'" class="classfortooltip">'; @@ -1801,7 +1807,7 @@ class Adherent extends CommonObject $this->phone = '0999999999'; $this->phone_perso = '0999999998'; $this->phone_mobile = '0999999997'; - $this->note='No comment'; + $this->note_private='No comment'; $this->birth=time(); $this->photo=''; $this->public=1; @@ -1874,7 +1880,8 @@ class Adherent extends CommonObject if ($this->phone_perso && ! empty($conf->global->LDAP_MEMBER_FIELD_PHONE_PERSO)) $info[$conf->global->LDAP_MEMBER_FIELD_PHONE_PERSO] = $this->phone_perso; if ($this->phone_mobile && ! empty($conf->global->LDAP_MEMBER_FIELD_MOBILE)) $info[$conf->global->LDAP_MEMBER_FIELD_MOBILE] = $this->phone_mobile; if ($this->fax && ! empty($conf->global->LDAP_MEMBER_FIELD_FAX)) $info[$conf->global->LDAP_MEMBER_FIELD_FAX] = $this->fax; - if ($this->note && ! empty($conf->global->LDAP_MEMBER_FIELD_DESCRIPTION)) $info[$conf->global->LDAP_MEMBER_FIELD_DESCRIPTION] = $this->note; + if ($this->note_private && ! empty($conf->global->LDAP_MEMBER_FIELD_DESCRIPTION)) $info[$conf->global->LDAP_MEMBER_FIELD_DESCRIPTION] = $this->note_private; + if ($this->note_public && ! empty($conf->global->LDAP_MEMBER_FIELD_NOTE_PUBLIC)) $info[$conf->global->LDAP_MEMBER_FIELD_NOTE_PUBLIC] = $this->note_public; if ($this->birth && ! empty($conf->global->LDAP_MEMBER_FIELD_BIRTHDATE)) $info[$conf->global->LDAP_MEMBER_FIELD_BIRTHDATE] = dol_print_date($this->birth,'dayhourldap'); if (isset($this->statut) && ! empty($conf->global->LDAP_FIELD_MEMBER_STATUS)) $info[$conf->global->LDAP_FIELD_MEMBER_STATUS] = $this->statut; if ($this->datefin && ! empty($conf->global->LDAP_FIELD_MEMBER_END_LASTSUBSCRIPTION)) $info[$conf->global->LDAP_FIELD_MEMBER_END_LASTSUBSCRIPTION] = dol_print_date($this->datefin,'dayhourldap'); @@ -1947,4 +1954,21 @@ class Adherent extends CommonObject } } + /** + * Function used to replace a thirdparty id with another one. + * + * @param DoliDB $db Database handler + * @param int $origin_id Old thirdparty id + * @param int $dest_id New thirdparty id + * @return bool + */ + public static function replaceThirdparty($db, $origin_id, $dest_id) + { + $tables = array( + 'adherent' + ); + + return CommonObject::commonReplaceThirdparty($db, $origin_id, $dest_id, $tables); + } + } diff --git a/htdocs/adherents/class/adherent_type.class.php b/htdocs/adherents/class/adherent_type.class.php index cbf5b428cc0..ee15a261820 100644 --- a/htdocs/adherents/class/adherent_type.class.php +++ b/htdocs/adherents/class/adherent_type.class.php @@ -73,7 +73,7 @@ class AdherentType extends CommonObject { global $conf; - $this->statut=trim($this->statut); + $this->statut=(int) $this->statut; $sql = "INSERT INTO ".MAIN_DB_PREFIX."adherent_type ("; $sql.= "libelle"; diff --git a/htdocs/adherents/list.php b/htdocs/adherents/list.php index 41c06beebe9..a94f6750f55 100644 --- a/htdocs/adherents/list.php +++ b/htdocs/adherents/list.php @@ -110,7 +110,7 @@ if ($sall) if (is_numeric($sall)) $sql.= "d.rowid = ".$sall." OR "; $sql.=" d.firstname LIKE '%".$db->escape($sall)."%' OR d.lastname LIKE '%".$db->escape($sall)."%' OR d.societe LIKE '%".$db->escape($sall)."%'"; $sql.=" OR d.email LIKE '%".$db->escape($sall)."%' OR d.login LIKE '%".$db->escape($sall)."%' OR d.address LIKE '%".$db->escape($sall)."%'"; - $sql.=" OR d.town LIKE '%".$db->escape($sall)."%' OR d.note LIKE '%".$db->escape($sall)."%')"; + $sql.=" OR d.town LIKE '%".$db->escape($sall)."%' OR d.note_public LIKE '%".$db->escape($sall)."%' OR d.note_private LIKE '%".$db->escape($sall)."%')"; } } if ($type > 0) diff --git a/htdocs/adherents/note.php b/htdocs/adherents/note.php index 727b3a9bcdc..79b7db086e6 100644 --- a/htdocs/adherents/note.php +++ b/htdocs/adherents/note.php @@ -1,6 +1,7 @@ - * Copyright (C) 2004-2014 Laurent Destailleur +/* Copyright (C) 2004 Rodolphe Quiedeville + * Copyright (C) 2004-2014 Laurent Destailleur + * Copyright (C) 2015 Frederic France * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -19,7 +20,7 @@ /** * \file htdocs/adherents/note.php * \ingroup member - * \brief Tabe for note of a member + * \brief Tab for note of a member */ require '../main.inc.php'; @@ -45,26 +46,13 @@ if ($result > 0) $result=$adht->fetch($object->typeid); } +$permissionnote=$user->rights->adherent->creer; // Used by the include of actions_setnotes.inc.php /* * Actions */ -if ($action == 'update' && $user->rights->adherent->creer && ! $_POST["cancel"]) -{ - $db->begin(); - - $res=$object->update_note(dol_html_entity_decode(GETPOST('note'), ENT_QUOTES)); - if ($res < 0) - { - setEventMessage($object->error, 'errors'); - $db->rollback(); - } - else - { - $db->commit(); - } -} +include DOL_DOCUMENT_ROOT.'/core/actions_setnotes.inc.php'; // Must be include, not include_once @@ -82,7 +70,7 @@ if ($id) dol_fiche_head($head, 'note', $langs->trans("Member"), 0, 'user'); - print "
"; + print ""; print ''; print ''; @@ -129,49 +117,16 @@ if ($id) // Status print ''; - // Note - print ''; - print '"; - - if ($action == 'edit') - { - print ''; - } - print "
'.$langs->trans("Status").''.$object->getLibStatut(4).'
'.$langs->trans("Note").''; - if ($action == 'edit' && $user->rights->adherent->creer) - { - print ""; - print "id."\">"; - require_once DOL_DOCUMENT_ROOT.'/core/class/doleditor.class.php'; - $doleditor=new DolEditor('note',$object->note,'',280,'dolibarr_notes','',true,true,$conf->global->FCKEDITOR_ENABLE_SOCIETE,10,80); - $doleditor->Create(); - } - else - { - print nl2br($object->note); - } - print "
'; - print ''; - print '   '; - print ''; - print '
"; - print "
\n"; + print '
'; - /* - * Actions - */ - print ''; - print '
'; + $colwidth='20'; + $permission = $user->rights->adherent->creer; // Used by the include of notes.tpl.php + include DOL_DOCUMENT_ROOT.'/core/tpl/notes.tpl.php'; - if ($user->rights->adherent->creer && $action != 'edit') - { - print '"; - } - - print "
"; + dol_fiche_end(); } diff --git a/htdocs/adherents/type.php b/htdocs/adherents/type.php index 22b8cdbfd68..cdeaa21ba9f 100644 --- a/htdocs/adherents/type.php +++ b/htdocs/adherents/type.php @@ -386,7 +386,7 @@ if ($rowid > 0) { $sql.= " AND (d.firstname LIKE '%".$sall."%' OR d.lastname LIKE '%".$sall."%' OR d.societe LIKE '%".$sall."%'"; $sql.= " OR d.email LIKE '%".$sall."%' OR d.login LIKE '%".$sall."%' OR d.address LIKE '%".$sall."%'"; - $sql.= " OR d.town LIKE '%".$sall."%' OR d.note LIKE '%".$sall."%')"; + $sql.= " OR d.town LIKE '%".$sall."%' OR d.note_public LIKE '%".$sall."%' OR d.note_private LIKE '%".$sall."%')"; } if ($status != '') { diff --git a/htdocs/admin/askpricesupplier.php b/htdocs/admin/askpricesupplier.php index 6307e81042c..d2072a0c79c 100644 --- a/htdocs/admin/askpricesupplier.php +++ b/htdocs/admin/askpricesupplier.php @@ -319,7 +319,6 @@ foreach ($dirmodels as $reldir) // Info $htmltooltip=''; $htmltooltip.=''.$langs->trans("Version").': '.$module->getVersion().'
'; - $askpricesupplier->type=0; $nextval=$module->getNextValue($mysoc,$askpricesupplier); if ("$nextval" != $langs->trans("NotAvailable")) { // Keep " on nextval $htmltooltip.=''.$langs->trans("NextValue").': '; diff --git a/htdocs/admin/company.php b/htdocs/admin/company.php index a349973b3dc..b9b2d18d512 100644 --- a/htdocs/admin/company.php +++ b/htdocs/admin/company.php @@ -369,7 +369,7 @@ if ($action == 'edit' || $action == 'updateedit') // Logo $var=!$var; print ''; - print ''; } print ''; print "
'; + print ''; + $opcions=array($langs->trans("CalcLocaltax1").' '.$langs->trans("CalcLocaltax1Desc"),$langs->trans("CalcLocaltax2").' - '.$langs->trans("CalcLocaltax2Desc"),$langs->trans("CalcLocaltax3").' - '.$langs->trans("CalcLocaltax3Desc")); + print ''; print "
'; print ''; print ''; if (! empty($mysoc->logo_mini)) @@ -605,8 +605,9 @@ if ($action == 'edit' || $action == 'updateedit') } print '
'.$langs->trans("CalcLocaltax").': '; - $opcions=array($langs->transcountry("CalcLocaltax1",$mysoc->country_code),$langs->transcountry("CalcLocaltax2",$mysoc->country_code),$langs->transcountry("CalcLocaltax3",$mysoc->country_code)); print $form->selectarray("clt1", $opcions, $conf->global->MAIN_INFO_LOCALTAX_CALC1); print '
"; @@ -649,7 +650,6 @@ if ($action == 'edit' || $action == 'updateedit') print '
: '; - $opcions=array($langs->transcountry("CalcLocaltax1",$mysoc->country_code),$langs->transcountry("CalcLocaltax2",$mysoc->country_code),$langs->transcountry("CalcLocaltax3",$mysoc->country_code)); print $form->selectarray("clt2", $opcions, $conf->global->MAIN_INFO_LOCALTAX_CALC2); print '
"; @@ -754,7 +754,7 @@ else $var=!$var; print ''.$langs->trans("Logo").''; - print ''; + print ''; } print "
'; + print ''; diff --git a/htdocs/admin/dict.php b/htdocs/admin/dict.php index 4c3ac209423..f7c0d2c8bf7 100644 --- a/htdocs/admin/dict.php +++ b/htdocs/admin/dict.php @@ -923,7 +923,7 @@ if ($id) print ""; $colspan=count($fieldlist)+2; - if ($id == 4) $colspan++;; + if ($id == 4) $colspan++; if (! empty($alabelisused)) // Si un des champs est un libelle { diff --git a/htdocs/admin/ihm.php b/htdocs/admin/ihm.php index cbbcad66daa..88932c0de44 100644 --- a/htdocs/admin/ihm.php +++ b/htdocs/admin/ihm.php @@ -323,8 +323,6 @@ else // Show $var=true; // Language - print_fiche_titre($langs->trans("Language"),'',''); - print '
'; print '
'; print $mysoc->logo; print ''; @@ -1061,15 +1061,15 @@ else print '
'.$langs->trans("CalcLocaltax").': '; if($conf->global->MAIN_INFO_LOCALTAX_CALC2==0) { - print $langs->transcountry("CalcLocaltax1",$mysoc->country_code); + print $langs->trans("CalcLocaltax1").' - '.$langs->trans("CalcLocaltax1Desc"); } else if($conf->global->MAIN_INFO_LOCALTAX_CALC2==1) { - print $langs->transcountry("CalcLocaltax2",$mysoc->country_code); + print $langs->trans("CalcLocaltax2").' - '.$langs->trans("CalcLocaltax2Desc"); } else if($conf->global->MAIN_INFO_LOCALTAX_CALC2==2) { - print $langs->transcountry("CalcLocaltax3",$mysoc->country_code); + print $langs->trans("CalcLocaltax3").' - '.$langs->trans("CalcLocaltax3Desc"); } print '
'; print ''; diff --git a/htdocs/admin/index.php b/htdocs/admin/index.php index 6ec184d68ec..4416c8fed8f 100644 --- a/htdocs/admin/index.php +++ b/htdocs/admin/index.php @@ -100,6 +100,7 @@ print '
'; print '
'; // Add hook to add information +$parameters=array(); $reshook=$hookmanager->executeHooks('addHomeSetup',$parameters,$object,$action); // Note that $action and $object may have been modified by some hooks print $hookmanager->resPrint; if (empty($reshook)) diff --git a/htdocs/admin/ldap_members.php b/htdocs/admin/ldap_members.php index bddf16f8670..8bac5068143 100644 --- a/htdocs/admin/ldap_members.php +++ b/htdocs/admin/ldap_members.php @@ -65,13 +65,14 @@ if ($action == 'setvalue' && $user->admin) if (! dolibarr_set_const($db, 'LDAP_MEMBER_FIELD_PHONE',GETPOST("fieldphone"),'chaine',0,'',$conf->entity)) $error++; if (! dolibarr_set_const($db, 'LDAP_MEMBER_FIELD_PHONE_PERSO',GETPOST("fieldphoneperso"),'chaine',0,'',$conf->entity)) $error++; if (! dolibarr_set_const($db, 'LDAP_MEMBER_FIELD_MOBILE',GETPOST("fieldmobile"),'chaine',0,'',$conf->entity)) $error++; - if (! dolibarr_set_const($db, 'LDAP_MEMBER_FIELD_SKYPE',GETPOST("fieldskype"),'chaine',0,'',$conf->entity)) $error++; + if (! dolibarr_set_const($db, 'LDAP_MEMBER_FIELD_SKYPE',GETPOST("fieldskype"),'chaine',0,'',$conf->entity)) $error++; if (! dolibarr_set_const($db, 'LDAP_MEMBER_FIELD_FAX',GETPOST("fieldfax"),'chaine',0,'',$conf->entity)) $error++; if (! dolibarr_set_const($db, 'LDAP_MEMBER_FIELD_ADDRESS',GETPOST("fieldaddress"),'chaine',0,'',$conf->entity)) $error++; if (! dolibarr_set_const($db, 'LDAP_MEMBER_FIELD_ZIP',GETPOST("fieldzip"),'chaine',0,'',$conf->entity)) $error++; if (! dolibarr_set_const($db, 'LDAP_MEMBER_FIELD_TOWN',GETPOST("fieldtown"),'chaine',0,'',$conf->entity)) $error++; if (! dolibarr_set_const($db, 'LDAP_MEMBER_FIELD_COUNTRY',GETPOST("fieldcountry"),'chaine',0,'',$conf->entity)) $error++; if (! dolibarr_set_const($db, 'LDAP_MEMBER_FIELD_DESCRIPTION',GETPOST("fielddescription"),'chaine',0,'',$conf->entity)) $error++; + if (! dolibarr_set_const($db, 'LDAP_MEMBER_FIELD_NOTE_PUBLIC',GETPOST("fieldnotepublic"),'chaine',0,'',$conf->entity)) $error++; if (! dolibarr_set_const($db, 'LDAP_MEMBER_FIELD_BIRTHDATE',GETPOST("fieldbirthdate"),'chaine',0,'',$conf->entity)) $error++; if (! dolibarr_set_const($db, 'LDAP_FIELD_MEMBER_STATUS',GETPOST("fieldstatus"),'chaine',0,'',$conf->entity)) $error++; if (! dolibarr_set_const($db, 'LDAP_FIELD_MEMBER_END_LASTSUBSCRIPTION', GETPOST("fieldendlastsubscription"),'chaine',0,'',$conf->entity)) $error++; @@ -312,6 +313,14 @@ print ''; print ''; print ''; +// Public Note +$var=!$var; +print ''; +print ''; +print ''; + // Birthday $var=!$var; print ''; print ''; print ''; print ''; } diff --git a/htdocs/admin/prelevement.php b/htdocs/admin/prelevement.php index b56ee74e10f..81ae430b371 100644 --- a/htdocs/admin/prelevement.php +++ b/htdocs/admin/prelevement.php @@ -180,7 +180,7 @@ if (! empty($conf->global->MAIN_MODULE_NOTIFICATION)) $langs->load("mails"); print_titre($langs->trans("Notifications")); - $sql = "SELECT u.rowid, u.lastname, u.firstname, u.fk_societe, u.email"; + $sql = "SELECT u.rowid, u.lastname, u.firstname, u.fk_soc, u.email"; $sql.= " FROM ".MAIN_DB_PREFIX."user as u"; $sql.= " WHERE entity IN (0,".$conf->entity.")"; @@ -194,7 +194,7 @@ if (! empty($conf->global->MAIN_MODULE_NOTIFICATION)) { $obj = $db->fetch_object($resql); $var=!$var; - if (!$obj->fk_societe) + if (!$obj->fk_soc) { $username=dolGetFirstLastname($obj->firstname,$obj->lastname); $internalusers[$obj->rowid] = $username; diff --git a/htdocs/admin/supplier_order.php b/htdocs/admin/supplier_order.php index 5a3c3808201..b7c7d3b5c3d 100644 --- a/htdocs/admin/supplier_order.php +++ b/htdocs/admin/supplier_order.php @@ -182,43 +182,27 @@ else if ($action == 'set_SUPPLIER_ORDER_OTHER') $res3=1; }*/ - // TODO We add/delete permission until permission can have a condition on a global var - $r_id = 1190; - $entity = $conf->entity; - $r_desc=$langs->trans("Permission1190"); - $r_modul='fournisseur'; - $r_type='w'; - $r_perms='commande'; - $r_subperms='approve2'; - $r_def=0; + // TODO We add/delete permission here until permission can have a condition on a global var + include_once DOL_DOCUMENT_ROOT.'/core/modules/modFournisseur.class.php'; + $newmodule=new modFournisseur($db); + // clear default rights array + $newmodule->rights=array(); + // add new right + $r=0; + $newmodule->rights[$r][0] = 1190; + $newmodule->rights[$r][1] = $langs->trans("Permission1190"); + $newmodule->rights[$r][2] = 'w'; + $newmodule->rights[$r][3] = 0; + $newmodule->rights[$r][4] = 'commande'; + $newmodule->rights[$r][5] = 'approve2'; if ($conf->global->SUPPLIER_ORDER_DOUBLE_APPROVAL) { - $sql = "INSERT INTO ".MAIN_DB_PREFIX."rights_def"; - $sql.= " (id, entity, libelle, module, type, bydefault, perms, subperms)"; - $sql.= " VALUES "; - $sql.= "(".$r_id.",".$entity.",'".$db->escape($r_desc)."','".$r_modul."','".$r_type."',".$r_def.",'".$r_perms."','".$r_subperms."')"; - - $resqlinsert=$db->query($sql,1); - if (! $resqlinsert) - { - if ($db->errno() != "DB_ERROR_RECORD_ALREADY_EXISTS") - { - setEventMessage($db->lasterror(),'errors'); - $error++; - } - } + $newmodule->insert_permissions(1); } else { - $sql = "DELETE FROM ".MAIN_DB_PREFIX."rights_def"; - $sql.= " WHERE id = ".$r_id; - $resqldelete=$db->query($sql,1); - if (! $resqldelete) - { - setEventMessage($db->lasterror(),'errors'); - $error++; - } + $newmodule->delete_permissions(); } } diff --git a/htdocs/admin/tools/dolibarr_export.php b/htdocs/admin/tools/dolibarr_export.php index aec78f8aaac..c1f44b7c791 100644 --- a/htdocs/admin/tools/dolibarr_export.php +++ b/htdocs/admin/tools/dolibarr_export.php @@ -111,11 +111,6 @@ jQuery(document).ready(function() { print_fiche_titre($langs->trans("Backup"),'','setup'); print $langs->trans("BackupDesc",DOL_DATA_ROOT).'

'; -print $langs->trans("BackupDesc2",DOL_DATA_ROOT).'
'; -print $langs->trans("BackupDescX").'

'; -print $langs->trans("BackupDesc3",DOL_DATA_ROOT).'
'; -print $langs->trans("BackupDescY").'

'; - ?> @@ -124,9 +119,29 @@ print $langs->trans("BackupDescY").'

'; name="token" value="" /> -
-'.$langs->trans("DatabaseName").' : '.$dolibarr_main_db_name.''; ?> -
'.$langs->trans("Parameters").''.$langs->trans("Value").' 
'.$langs->trans("LDAPFieldDescriptionExample").' 
'.$langs->trans("LDAPFieldNotePublic").''; +print ''; +print ''.$langs->trans("LDAPFieldNotePublicExample").' 
'.$langs->trans("LDAPFieldBirthdate").''; diff --git a/htdocs/admin/notification.php b/htdocs/admin/notification.php index b9c163972ce..c06758cc356 100644 --- a/htdocs/admin/notification.php +++ b/htdocs/admin/notification.php @@ -174,8 +174,8 @@ if ($conf->societe->enabled) print ''.$notifiedevent['code'].''.$label.''; - $nb = $notify->countDefinedNotifications($notifiedevent['code'], 0); - print $nb; + $tmparray = $notify->getNotificationsArray($notifiedevent['code'], 0); + print count($tmparray); print '
+
1 + +trans("BackupDesc3",$dolibarr_main_db_name).'
'; +//print $langs->trans("BackupDescY").'
'; +print '
'; +?> + +
+ +trans("BackupDumpWizard")); + +print '
'; +print ''; +print ''; +print ''; +print '
'; +print $langs->trans("DatabaseName").' : '.$dolibarr_main_db_name.'
'; +print '
'; +?> +
@@ -182,7 +197,7 @@ print $langs->trans("BackupDescY").'

'; $fullpathofmysqldump=$conf->global->SYSTEMTOOLS_MYSQLDUMP; } ?>
-
@@ -317,7 +332,7 @@ print $langs->trans("BackupDescY").'

'; $fullpathofpgdump=$conf->global->SYSTEMTOOLS_POSTGRESQLDUMP; } ?>
- @@ -357,12 +372,12 @@ print $langs->trans("BackupDescY").'

';
- -
-trans("Destination"); ?> -: - +trans("Destination"); ?> --> +
+
+
+?> +
+
'; +?> - + +
+
admin->dir_output.'/backup','files',0,'','',$sortfield,(strtolower($sortorder)=='asc'?SORT_ASC:SORT_DESC),1); $result=$formfile->list_of_documents($filearray,null,'systemtools','',1,'backup/',1,0,$langs->trans("NoBackupFileAvailable"),0,$langs->trans("PreviousDumpFiles")); print '
'; +?> +
+
+ + + +
+ +
2 +trans("BackupDesc2",DOL_DATA_ROOT).'
'; +print $langs->trans("BackupDescX").'

'; +?> +
+ + + + +trans("Restore"),'','setup'); print $langs->trans("RestoreDesc",DOL_DATA_ROOT).'

'; +?> +
+1 +trans("RestoreDesc2",DOL_DATA_ROOT).'

'; -print $langs->trans("RestoreDesc3",DOL_DATA_ROOT).'

'; +?> +
+
+ +
+2 +trans("RestoreDesc3",$dolibarr_main_db_name).'

'; ?> -
-'.$langs->trans("DatabaseName").' : '.$dolibarr_main_db_name.''; ?> +trans("DatabaseName").' : '.$dolibarr_main_db_name.''; ?>

+ \n"; } diff --git a/htdocs/categories/categorie.php b/htdocs/categories/categorie.php index 76af3708c8b..1cd605ea9ca 100644 --- a/htdocs/categories/categorie.php +++ b/htdocs/categories/categorie.php @@ -341,7 +341,7 @@ else if ($id || $ref) llxHeader("","",$langs->trans("CardProduct".$product->type)); - $head=product_prepare_head($product, $user); + $head=product_prepare_head($product); $titre=$langs->trans("CardProduct".$product->type); $picto=($product->type== Product::TYPE_SERVICE?'service':'product'); dol_fiche_head($head, 'category', $titre,0,$picto); diff --git a/htdocs/categories/class/categorie.class.php b/htdocs/categories/class/categorie.class.php index 9a76211b828..8e6772dec5d 100644 --- a/htdocs/categories/class/categorie.class.php +++ b/htdocs/categories/class/categorie.class.php @@ -7,6 +7,7 @@ * Copyright (C) 2007 Patrick Raguin * Copyright (C) 2013 Juanjo Menent * Copyright (C) 2013 Philippe Grand + * Copyright (C) 2015 Marcos García * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -201,7 +202,7 @@ class Categorie extends CommonObject $action='create'; // Actions on extra fields (by external module or standard code) - // FIXME le hook fait double emploi avec le trigger !! + // TODO le hook fait double emploi avec le trigger !! $hookmanager->initHooks(array('HookModuleNamedao')); $parameters=array('socid'=>$this->id); $reshook=$hookmanager->executeHooks('insertExtraFields',$parameters,$this,$action); // Note that $action and $object may have been modified by some hooks @@ -294,7 +295,7 @@ class Categorie extends CommonObject $action='update'; // Actions on extra fields (by external module or standard code) - // FIXME le hook fait double emploi avec le trigger !! + // TODO le hook fait double emploi avec le trigger !! $hookmanager->initHooks(array('HookCategorydao')); $parameters=array(); $reshook=$hookmanager->executeHooks('insertExtraFields',$parameters,$this,$action); // Note that $action and $object may have been modified by some hooks @@ -1164,10 +1165,10 @@ class Categorie extends CommonObject { $cats = array(); - $typeid=-1; $table='';; + $typeid=-1; $table=''; if ($type == '0' || $type == 'product') { $typeid=0; $table='product'; $type='product'; } - else if ($type == '1' || $type == 'supplier') { $typeid=1; $table='societe'; $type='fournisseur'; } - else if ($type == '2' || $type == 'customer') { $typeid=2; $table='societe'; $type='societe'; } + else if ($type == '1' || $type == 'supplier') { $typeid=1; $table='soc'; $type='fournisseur'; } + else if ($type == '2' || $type == 'customer') { $typeid=2; $table='soc'; $type='societe'; } else if ($type == '3' || $type == 'member') { $typeid=3; $table='member'; $type='member'; } else if ($type == '4' || $type == 'contact') { $typeid=4; $table='socpeople'; $type='contact'; } @@ -1551,4 +1552,21 @@ class Categorie extends CommonObject $this->socid = 1; $this->type = 0; } + + /** + * Function used to replace a thirdparty id with another one. + * + * @param DoliDB $db Database handler + * @param int $origin_id Old thirdparty id + * @param int $dest_id New thirdparty id + * @return bool + */ + public static function replaceThirdparty(DoliDB $db, $origin_id, $dest_id) + { + $tables = array( + 'categorie_societe' + ); + + return CommonObject::commonReplaceThirdparty($db, $origin_id, $dest_id, $tables); + } } diff --git a/htdocs/comm/action/class/actioncomm.class.php b/htdocs/comm/action/class/actioncomm.class.php index 2e840abce76..543cf862d8f 100644 --- a/htdocs/comm/action/class/actioncomm.class.php +++ b/htdocs/comm/action/class/actioncomm.class.php @@ -333,7 +333,7 @@ class ActionComm extends CommonObject $action='create'; // Actions on extra fields (by external module or standard code) - // FIXME le hook fait double emploi avec le trigger !! + // TODO le hook fait double emploi avec le trigger !! $hookmanager->initHooks(array('actioncommdao')); $parameters=array('actcomm'=>$this->id); $reshook=$hookmanager->executeHooks('insertExtraFields',$parameters,$this,$action); // Note that $action and $object may have been modified by some hooks @@ -657,7 +657,7 @@ class ActionComm extends CommonObject $action='update'; // Actions on extra fields (by external module or standard code) - // FIXME le hook fait double emploi avec le trigger !! + // TODO le hook fait double emploi avec le trigger !! $hookmanager->initHooks(array('actioncommdao')); $parameters=array('actcomm'=>$this->id); $reshook=$hookmanager->executeHooks('insertExtraFields',$parameters,$this,$action); // Note that $action and $object may have been modified by some hooks @@ -1263,5 +1263,22 @@ class ActionComm extends CommonObject $this->userassigned[$user->id]=array('id'=>$user->id, 'transparency'=> 1); } + /** + * Function used to replace a thirdparty id with another one. + * + * @param DoliDB $db Database handler + * @param int $origin_id Old thirdparty id + * @param int $dest_id New thirdparty id + * @return bool + */ + public static function replaceThirdparty(DoliDB $db, $origin_id, $dest_id) + { + $tables = array( + 'actioncomm' + ); + + return CommonObject::commonReplaceThirdparty($db, $origin_id, $dest_id, $tables); + } + } diff --git a/htdocs/comm/action/class/ical.class.php b/htdocs/comm/action/class/ical.class.php index e7bddb8bd7e..54f97fa2117 100644 --- a/htdocs/comm/action/class/ical.class.php +++ b/htdocs/comm/action/class/ical.class.php @@ -220,8 +220,8 @@ class ICal } if (($key == "DTSTAMP") or ($key == "LAST-MODIFIED") or ($key == "CREATED")) $value = $this->ical_date_to_unix($value); - if ($key == "RRULE" ) $value = $this->ical_rrule($value); - + //if ($key == "RRULE" ) $value = $this->ical_rrule($value); + if (stristr($key,"DTSTART") or stristr($key,"DTEND") or stristr($key,"DTSTART;VALUE=DATE") or stristr($key,"DTEND;VALUE=DATE")) { if (stristr($key,"DTSTART;VALUE=DATE") or stristr($key,"DTEND;VALUE=DATE")) diff --git a/htdocs/comm/askpricesupplier/card.php b/htdocs/comm/askpricesupplier/card.php index 3a3b283f8e9..b87a579b0e8 100644 --- a/htdocs/comm/askpricesupplier/card.php +++ b/htdocs/comm/askpricesupplier/card.php @@ -1730,6 +1730,9 @@ if ($action == 'create') /* * Action presend */ + if (GETPOST('modelselected')) { + $action = 'presend'; + } if ($action == 'presend') { $object->fetch_projet(); @@ -1802,6 +1805,7 @@ if ($action == 'create') // Tableau des parametres complementaires $formmail->param['action'] = 'send'; $formmail->param['models'] = 'askpricesupplier_send'; + $formmail->param['models_id']=GETPOST('modelmailselected','int'); $formmail->param['id'] = $object->id; $formmail->param['returnurl'] = $_SERVER["PHP_SELF"] . '?id=' . $object->id; // Init list of files diff --git a/htdocs/comm/card.php b/htdocs/comm/card.php index 14bf6e42fe8..81e8b396963 100644 --- a/htdocs/comm/card.php +++ b/htdocs/comm/card.php @@ -155,7 +155,7 @@ if (empty($reshook)) if ($action == 'setoutstanding_limit') { $object->fetch($id); - $object->outstanding_limit=GETPOST('setoutstanding_limit'); + $object->outstanding_limit=GETPOST('outstanding_limit'); $result=$object->set_OutstandingBill($user); if ($result < 0) setEventMessage($object->error,'errors'); } @@ -406,9 +406,15 @@ if ($id > 0) $limit_field_type = (! empty($conf->global->MAIN_USE_JQUERY_JEDITABLE)) ? 'numeric' : 'amount'; print $form->editfieldval("OutstandingBill",'outstanding_limit',$object->outstanding_limit,$object,$user->rights->societe->creer,$limit_field_type,($object->outstanding_limit != '' ? price($object->outstanding_limit) : '')); // display amount and link to unpaid bill - $outstandigBills = $object->get_OutstandingBill(); - if ($outstandigBills != 0) - print " (".$langs->trans("CurrentOutstandingBill")." ".price($outstandigBills, '', $langs, 0, 0, -1, $conf->currency).')'; + $outstandingBills = $object->get_OutstandingBill(); + if ($outstandingBills != 0) { + print ' ('.$langs->trans("CurrentOutstandingBill"); + print ' '; + print price($outstandingBills, '', $langs, 0, -1, -1, $conf->currency); + print ''; + if ($outstandingBills > $object->outstanding_limit) print img_warning($langs->trans("OutstandingBillReached")); + print ')'; + } print ''; print ''; } @@ -627,7 +633,7 @@ if ($id > 0) print '
use_javascript_ajax) { ?> diff --git a/htdocs/admin/tools/export.php b/htdocs/admin/tools/export.php index 1668e4f4c67..ba3da7b443c 100644 --- a/htdocs/admin/tools/export.php +++ b/htdocs/admin/tools/export.php @@ -88,10 +88,10 @@ if (!empty($MemoryLimit)) $form=new Form($db); $formfile = new FormFile($db); -$help_url='EN:Backups|FR:Sauvegardes|ES:Copias_de_seguridad'; -llxHeader('','',$help_url); +//$help_url='EN:Backups|FR:Sauvegardes|ES:Copias_de_seguridad'; +//llxHeader('','',$help_url); -print_fiche_titre($langs->trans("Backup"),'','setup'); +//print_fiche_titre($langs->trans("Backup"),'','setup'); // Start with empty buffer @@ -165,13 +165,18 @@ if ($what == 'mysql') $paramclear.=' -p"'.str_replace(array('"','`'),array('\"','\`'),$dolibarr_main_db_pass).'"'; } + $_SESSION["commandbackuplastdone"]=$command." ".$paramcrypted; + $_SESSION["commandbackuptorun"]=""; + /* print ''.$langs->trans("RunCommandSummary").':
'."\n"; print '
'."\n"; print '
'; + //print $paramclear; // Now run command and show result print ''.$langs->trans("BackupResult").': '; + */ $errormsg=''; @@ -264,6 +269,9 @@ if ($what == 'mysqlnobin') { backup_tables($outputfile); } + + $_SESSION["commandbackuplastdone"]=""; + $_SESSION["commandbackuptorun"]=""; } // POSTGRESQL @@ -320,7 +328,9 @@ if ($what == 'postgresql') $paramcrypted.=" -w ".$dolibarr_main_db_name; $paramclear.=" -w ".$dolibarr_main_db_name; - print $langs->trans("RunCommandSummaryToLaunch").':
'."\n"; + $_SESSION["commandbackuplastdone"]=""; + $_SESSION["commandbackuptorun"]=$command." ".$paramcrypted; + /*print $langs->trans("RunCommandSummaryToLaunch").':
'."\n"; print '
'."\n"; print '
'; @@ -330,7 +340,7 @@ if ($what == 'postgresql') print $langs->trans("YouMustRunCommandFromCommandLineAfterLoginToUser",$dolibarr_main_db_user,$dolibarr_main_db_user); print '
'; - print '
'; + print '
';*/ $what=''; } @@ -339,34 +349,46 @@ if ($what == 'postgresql') // Si on a demande une generation -if ($what) -{ +//if ($what) +//{ if ($errormsg) { + setEventMessage($langs->trans("Error")." : ".$errormsg, 'errors'); + /* print '
'.$langs->trans("Error")." : ".$errormsg.'
'; - // print ''.$langs->trans("DownloadErrorFile").'
'; - print '
'; print '
'; + print '
';*/ } else - { - print '
'; - print $langs->trans("BackupFileSuccessfullyCreated").'.
'; - print $langs->trans("YouCanDownloadBackupFile"); - print '
'; - print '
'; + { + if ($what) + { + setEventMessage($langs->trans("BackupFileSuccessfullyCreated").'.
'.$langs->trans("YouCanDownloadBackupFile")); + /*print '
'; + print $langs->trans("BackupFileSuccessfullyCreated").'.
'; + print $langs->trans("YouCanDownloadBackupFile"); + print '
'; + print '
';*/ + } + else + { + setEventMessage($langs->trans("YouMustRunCommandFromCommandLineAfterLoginToUser",$dolibarr_main_db_user,$dolibarr_main_db_user)); + } } -} +//} +/* $filearray=dol_dir_list($conf->admin->dir_output.'/backup','files',0,'','',$sortfield,(strtolower($sortorder)=='asc'?SORT_ASC:SORT_DESC),1); $result=$formfile->list_of_documents($filearray,null,'systemtools','',1,'backup/',1,0,($langs->trans("NoBackupFileAvailable").'
'.$langs->trans("ToBuildBackupFileClickHere",DOL_URL_ROOT.'/admin/tools/dolibarr_export.php')),0,$langs->trans("PreviousDumpFiles")); print '
'; +*/ + +// Redirect t backup page +header("Location: dolibarr_export.php"); $time_end = time(); -llxFooter(); - $db->close(); diff --git a/htdocs/admin/tools/update.php b/htdocs/admin/tools/update.php index 7c85f820eab..27799ff1e93 100644 --- a/htdocs/admin/tools/update.php +++ b/htdocs/admin/tools/update.php @@ -29,6 +29,8 @@ include_once DOL_DOCUMENT_ROOT . '/core/lib/geturl.lib.php'; $langs->load("admin"); $langs->load("other"); +$action=GETPOST('action','alpha'); + if (! $user->admin) accessforbidden(); if (GETPOST('msg','alpha')) { @@ -43,14 +45,18 @@ $dolibarrroot=preg_replace('/([\\/]+)$/i','',DOL_DOCUMENT_ROOT); $dolibarrroot=preg_replace('/([^\\/]+)$/i','',$dolibarrroot); $dolibarrdataroot=preg_replace('/([\\/]+)$/i','',DOL_DATA_ROOT); +$dirins=DOL_DOCUMENT_ROOT.'/custom'; + + /* * Actions */ -if (GETPOST('action','alpha')=='install') +if ($action=='install') { $error=0; + // $original_file should match format module_modulename-x.y[.z].zip $original_file=basename($_FILES["fileinstall"]["name"]); $newfile=$conf->admin->dir_temp.'/'.$original_file.'/'.$original_file; @@ -72,33 +78,87 @@ if (GETPOST('action','alpha')=='install') if (! $error) { - @dol_delete_dir_recursive($conf->admin->dir_temp.'/'.$original_file); - dol_mkdir($conf->admin->dir_temp.'/'.$original_file); + if ($original_file) + { + @dol_delete_dir_recursive($conf->admin->dir_temp.'/'.$original_file); + dol_mkdir($conf->admin->dir_temp.'/'.$original_file); + } + + $tmpdir=preg_replace('/\.zip$/','',$original_file).'.dir'; + if ($tmpdir) + { + @dol_delete_dir_recursive($conf->admin->dir_temp.'/'.$tmpdir); + dol_mkdir($conf->admin->dir_temp.'/'.$tmpdir); + } $result=dol_move_uploaded_file($_FILES['fileinstall']['tmp_name'],$newfile,1,0,$_FILES['fileinstall']['error']); if ($result > 0) { - $documentrootalt=DOL_DOCUMENT_ROOT.'/extensions'; - $result=dol_uncompress($newfile,$documentrootalt); + $result=dol_uncompress($newfile,$conf->admin->dir_temp.'/'.$tmpdir); + if (! empty($result['error'])) { $langs->load("errors"); setEventMessage($langs->trans($result['error'],$original_file), 'errors'); + $error++; } else { - setEventMessage($langs->trans("SetupIsReadyForUse")); + // Now we move the dir of the module + $modulename=preg_replace('/module_/', '', $original_file); + $modulename=preg_replace('/\-[\d]+\.[\d]+.*$/', '', $modulename); + // Search dir $modulename + $modulenamedir=$conf->admin->dir_temp.'/'.$tmpdir.'/'.$modulename; + //var_dump($modulenamedir); + if (! dol_is_dir($modulenamedir)) + { + $modulenamedir=$conf->admin->dir_temp.'/'.$tmpdir.'/htdocs/'.$modulename; + //var_dump($modulenamedir); + if (! dol_is_dir($modulenamedir)) + { + setEventMessage($langs->trans("ErrorModuleFileSeemsToHaveAWrongFormat"), 'errors'); + $error++; + } + } + + if (! $error) + { + //var_dump($dirins); + @dol_delete_dir_recursive($dirins.'/'.$modulename); + $result=dolCopyDir($modulenamedir, $dirins.'/'.$modulename, '0444', 1); + if ($result <= 0) + { + setEventMessage($langs->trans("ErrorFailedToCopy"), 'errors'); + $error++; + } + } } } + else + { + $error++; + } + } + + if (! $error) + { + setEventMessage($langs->trans("SetupIsReadyForUse")); } } + /* * View */ -$dirins=DOL_DOCUMENT_ROOT.'/extensions'; -$dirins_ok=(is_dir($dirins)); + + +// Set dir where external modules are installed +if (! dol_is_dir($dirins)) +{ + dol_mkdir($dirins); +} +$dirins_ok=(dol_is_dir($dirins)); $wikihelp='EN:Installation_-_Upgrade|FR:Installation_-_Mise_à_jour|ES:Instalación_-_Actualización'; llxHeader('',$langs->trans("Upgrade"),$wikihelp); @@ -143,6 +203,8 @@ else } print '
'; + +// Upgrade print $langs->trans("Upgrade").'
'; print '
'; print $langs->trans("ThisIsProcessToFollow").'
'; @@ -162,20 +224,76 @@ print $langs->trans("RestoreLock",$dolibarrdataroot.'/install.lock').'
'; print '
'; print '
'; + +// Install external module + +$allowonlineinstall=true; +$allowfromweb=1; +if (dol_is_file($dolibarrdataroot.'/installmodules.lock')) $allowonlineinstall=false; + $fullurl=''.$urldolibarrmodules.''; +$message=''; +if (! empty($allowonlineinstall)) +{ + if (! in_array('/custom',explode(',',$dolibarr_main_url_root_alt))) + { + $message=info_admin($langs->trans("ConfFileMuseContainCustom", DOL_DOCUMENT_ROOT.'/custom', DOL_DOCUMENT_ROOT)); + $allowfromweb=-1; + } + else + { + if ($dirins_ok) + { + if (! is_writable(dol_osencode($dirins))) + { + $langs->load("errors"); + $message=info_admin($langs->trans("ErrorFailedToWriteInDir",$dirins)); + $allowfromweb=0; + } + } + else + { + + $message=info_admin($langs->trans("NotExistsDirect",$dirins).$langs->trans("InfDirAlt").$langs->trans("InfDirExample")); + $allowfromweb=0; + } + } +} +else +{ + $message=info_admin($langs->trans("InstallModuleFromWebHasBeenDisabledByFile",$dolibarrdataroot.'/installmodules.lock')); + $allowfromweb=0; +} + + + + + print $langs->trans("AddExtensionThemeModuleOrOther").'
'; print '
'; -print $langs->trans("ThisIsProcessToFollow").'
'; -print ''.$langs->trans("StepNb",1).': '; -print $langs->trans("FindPackageFromWebSite",$fullurl).'
'; -print ''.$langs->trans("StepNb",2).': '; -print $langs->trans("DownloadPackageFromWebSite",$fullurl).'
'; -print ''.$langs->trans("StepNb",3).': '; -print $langs->trans("UnpackPackageInDolibarrRoot",$dolibarrroot).'
'; -if (! empty($conf->global->MAIN_ONLINE_INSTALL_MODULE)) + +if ($allowfromweb < 1) { - if ($dirins_ok) + print $langs->trans("SomethingMakeInstallFromWebNotPossible"); + print $message; + //print $langs->trans("SomethingMakeInstallFromWebNotPossible2"); + print '
'; +} + + +if ($allowfromweb >= 0) +{ + if ($allowfromweb == 1) print $langs->trans("ThisIsProcessToFollow").'
'; + else print $langs->trans("ThisIsAlternativeProcessToFollow").'
'; + print ''.$langs->trans("StepNb",1).': '; + print $langs->trans("FindPackageFromWebSite",$fullurl).'
'; + print ''.$langs->trans("StepNb",2).': '; + print $langs->trans("DownloadPackageFromWebSite",$fullurl).'
'; + print ''.$langs->trans("StepNb",3).': '; + + if ($allowfromweb == 1) { + print $langs->trans("UnpackPackageInDolibarrRoot",$dirins).'
'; print '
'; print ''; print $langs->trans("YouCanSubmitFile").' '; @@ -184,16 +302,12 @@ if (! empty($conf->global->MAIN_ONLINE_INSTALL_MODULE)) } else { - $message=info_admin($langs->trans("NotExistsDirect",$dirins).$langs->trans("InfDirAlt").$langs->trans("InfDirExample")); - setEventMessage($message, 'warnings'); + print $langs->trans("UnpackPackageInDolibarrRoot",$dirins).'
'; + print ''.$langs->trans("StepNb",4).': '; + print $langs->trans("SetupIsReadyForUse").'
'; } } -else -{ - print ''.$langs->trans("StepNb",4).': '; - print $langs->trans("SetupIsReadyForUse").'
'; -} -print '
'; + if (! empty($result['return'])) { diff --git a/htdocs/bookmarks/class/bookmark.class.php b/htdocs/bookmarks/class/bookmark.class.php index aa92d2bedb9..06490f21cda 100644 --- a/htdocs/bookmarks/class/bookmark.class.php +++ b/htdocs/bookmarks/class/bookmark.class.php @@ -1,5 +1,6 @@ + * Copyright (C) 2015 Marcos García * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -210,4 +211,21 @@ class Bookmark } + /** + * Function used to replace a thirdparty id with another one. + * + * @param DoliDB $db Database handler + * @param int $origin_id Old thirdparty id + * @param int $dest_id New thirdparty id + * @return bool + */ + public static function replaceThirdparty(DoliDB $db, $origin_id, $dest_id) + { + $tables = array( + 'bookmark' + ); + + return CommonObject::commonReplaceThirdparty($db, $origin_id, $dest_id, $tables); + } + } diff --git a/htdocs/cashdesk/admin/cashdesk.php b/htdocs/cashdesk/admin/cashdesk.php index 7be283528b4..4739a55e2c8 100644 --- a/htdocs/cashdesk/admin/cashdesk.php +++ b/htdocs/cashdesk/admin/cashdesk.php @@ -164,7 +164,7 @@ if (! empty($conf->service->enabled)) $var=! $var; print '
'; print $langs->trans("CashdeskShowServices"); - print '';; + print ''; print $form->selectyesno("CASHDESK_SERVICES",$conf->global->CASHDESK_SERVICES,1); print "
'; print ''; - print ''; + print ''; } print '
'; + print ''; print ''; diff --git a/htdocs/compta/bank/class/account.class.php b/htdocs/compta/bank/class/account.class.php index 900a970d949..b6215165d35 100644 --- a/htdocs/compta/bank/class/account.class.php +++ b/htdocs/compta/bank/class/account.class.php @@ -781,8 +781,8 @@ class Account extends CommonObject $result=$this->deleteExtraFields(); if ($result < 0) { - return -1; dol_syslog(get_class($this)."::delete error -4 ".$this->error, LOG_ERR); + return -1; } } diff --git a/htdocs/compta/bank/index.php b/htdocs/compta/bank/index.php index 96a44ecd354..9f156e5f568 100644 --- a/htdocs/compta/bank/index.php +++ b/htdocs/compta/bank/index.php @@ -133,7 +133,7 @@ if (! $found) print ''; + print ''; } print '
'.$langs->trans("LastOrders",($num<=$MAXLIST?"":$MAXLIST)).''.$langs->trans("AllOrders").' '.$num.''; print ''; //if($num2 > 0) print ''; //else print ''; @@ -854,7 +860,7 @@ if ($id > 0) $facturestatic = new Facture($db); $sql = 'SELECT f.rowid as facid, f.facnumber, f.type, f.amount'; - $sql.= ', f.total'; + $sql.= ', f.total as total_ht'; $sql.= ', f.tva as total_tva'; $sql.= ', f.total_ttc'; $sql.= ', f.datef as df, f.datec as dc, f.paye as paye, f.fk_statut as statut'; @@ -896,7 +902,7 @@ if ($id > 0) $facturestatic->id = $objp->facid; $facturestatic->ref = $objp->facnumber; $facturestatic->type = $objp->type; - $facturestatic->total_ht = $objp->total; + $facturestatic->total_ht = $objp->total_ht; $facturestatic->total_tva = $objp->total_tva; $facturestatic->total_ttc = $objp->total_ttc; print $facturestatic->getNomUrl(1); @@ -909,7 +915,7 @@ if ($id > 0) { print ''; } - print ''; + print ''; print ''; print "\n"; diff --git a/htdocs/comm/index.php b/htdocs/comm/index.php index cb5a07c32d3..6705752e71e 100644 --- a/htdocs/comm/index.php +++ b/htdocs/comm/index.php @@ -1,6 +1,6 @@ - * Copyright (C) 2004-2013 Laurent Destailleur + * Copyright (C) 2004-2015 Laurent Destailleur * Copyright (C) 2005-2012 Regis Houssin * * This program is free software; you can redistribute it and/or modify @@ -67,7 +67,7 @@ if (! empty($conf->commande->enabled)) $orderstatic=new Commande($db); llxHeader(); -print_fiche_titre($langs->trans("CustomerArea")); +print_fiche_titre($langs->trans("CommercialArea")); print '
'; @@ -579,6 +579,103 @@ if (! empty($conf->propal->enabled) && $user->rights->propal->lire) } } +/* + * Opened Order + */ +if (! empty($conf->commande->enabled) && $user->rights->commande->lire) +{ + $langs->load("order"); + + $sql = "SELECT s.nom as name, s.rowid, c.rowid as commandeid, c.total as total_ttc, c.total_ht, c.tva as total_tva, c.ref, c.ref_client, c.fk_statut, c.date_valid as dv "; + $sql.= " FROM ".MAIN_DB_PREFIX."societe as s"; + $sql.= ", ".MAIN_DB_PREFIX."commande as c"; + if (! $user->rights->societe->client->voir && ! $socid) $sql.= ", ".MAIN_DB_PREFIX."societe_commerciaux as sc"; + $sql.= " WHERE c.fk_soc = s.rowid"; + $sql.= " AND c.entity = ".$conf->entity; + $sql.= " AND c.fk_statut = 1"; + if (! $user->rights->societe->client->voir && ! $socid) $sql.= " AND s.rowid = sc.fk_soc AND sc.fk_user = " .$user->id; + if ($socid) $sql.= " AND s.rowid = ".$socid; + $sql.= " ORDER BY c.rowid DESC"; + + $result=$db->query($sql); + if ($result) + { + $total = 0; + $num = $db->num_rows($result); + $i = 0; + if ($num > 0) + { + $var=true; + + print '
'.$langs->trans("LastCustomerOrders",($num<=$MAXLIST?"":$MAXLIST)).''.$langs->trans("AllOrders").' '.$num.''.img_picto($langs->trans("Statistics"),'stats').''.img_picto($langs->trans("CreateInvoiceForThisCustomer"),'object_bill').''.img_picto($langs->trans("NoOrdersToInvoice"),'object_bill').'!!!'.price($objp->total_ttc).''.price($objp->total_ht).''.($facturestatic->LibStatut($objp->paye,$objp->statut,5,$objp->am)).'
'; + print ''; + + $nbofloop=min($num, (empty($conf->global->MAIN_MAXLIST_OVERLOAD)?500:$conf->global->MAIN_MAXLIST_OVERLOAD)); + while ($i < $nbofloop) + { + $obj = $db->fetch_object($result); + $var=!$var; + print ''; + + // Ref + print '"; + + print ''; + print ''."\n"; + print ''; + print ''."\n"; + print ''."\n"; + $i++; + $total += $obj->total_ttc; + } + if ($num > $nbofloop) + { + print '"; + } + else if ($total>0) + { + print '"; + } + print "
'.$langs->trans("OrdersOpened").' '.$num.'
'; + + $orderstatic->id=$obj->commandeid; + $orderstatic->ref=$obj->ref; + $orderstatic->ref_client=$obj->ref_client; + $orderstatic->total_ht = $obj->total_ht; + $orderstatic->total_tva = $obj->total_tva; + $orderstatic->total_ttc = $obj->total_ttc; + + print ''; + print ''; + print ''; + print '
'; + print $orderstatic->getNomUrl(1); + print ''; + //if ($db->jdate($obj->dfv) < ($now - $conf->propal->cloture->warning_delay)) print img_warning($langs->trans("Late")); + print ''; + $filename=dol_sanitizeFileName($obj->ref); + $filedir=$conf->commande->dir_output . '/' . dol_sanitizeFileName($obj->ref); + $urlsource=$_SERVER['PHP_SELF'].'?id='.$obj->propalid; + print $formfile->getDocumentsLink($orderstatic->element, $filename, $filedir); + print '
'; + + print "
'; + $companystatic->id=$obj->rowid; + $companystatic->name=$obj->name; + $companystatic->client=$obj->client; + $companystatic->canvas=$obj->canvas; + print $companystatic->getNomUrl(1, 'company', 44); + print ''; + print dol_print_date($db->jdate($obj->dp),'day').''.price($obj->total_ttc).''.$orderstatic->LibStatut($obj->fk_statut,3).'
'.$langs->trans("XMoreLines", ($num - $nbofloop))."
'.$langs->trans("Total")."".price($total)." 

"; + } + } + else + { + dol_print_error($db); + } +} + + print ''; diff --git a/htdocs/comm/list.php b/htdocs/comm/list.php index 06b26d88f48..bc3be7b3ebe 100644 --- a/htdocs/comm/list.php +++ b/htdocs/comm/list.php @@ -105,7 +105,7 @@ $sql = "SELECT s.rowid, s.nom as name, s.client, s.zip, s.town, st.libelle as st $sql.= " s.datec, s.canvas"; if ((!$user->rights->societe->client->voir && !$socid) || $search_sale > 0) $sql .= ", sc.fk_soc, sc.fk_user"; // We need these fields in order to filter by sale (including the case where the user can only see his prospects) $sql.= " FROM ".MAIN_DB_PREFIX."societe as s"; -if (! empty($search_categ) || ! empty($catid)) $sql.= ' LEFT JOIN '.MAIN_DB_PREFIX."categorie_societe as cs ON s.rowid = cs.fk_societe"; // We need this table joined to the select in order to filter by categ +if (! empty($search_categ) || ! empty($catid)) $sql.= ' LEFT JOIN '.MAIN_DB_PREFIX."categorie_societe as cs ON s.rowid = cs.fk_soc"; // We need this table joined to the select in order to filter by categ if ((!$user->rights->societe->client->voir && !$socid) || $search_sale > 0) $sql.= ", ".MAIN_DB_PREFIX."societe_commerciaux as sc"; // We need this table joined to the select in order to filter by sale $sql.= ", ".MAIN_DB_PREFIX."c_stcomm as st"; $sql.= " WHERE s.fk_stcomm = st.id"; diff --git a/htdocs/comm/propal.php b/htdocs/comm/propal.php index c5288404eec..10d51feb798 100644 --- a/htdocs/comm/propal.php +++ b/htdocs/comm/propal.php @@ -303,7 +303,7 @@ if (empty($reshook)) $object->modelpdf = GETPOST('model'); $object->author = $user->id; // deprecated $object->note = GETPOST('note'); - $object->statut = 0; + $object->statut = Propal::STATUS_DRAFT; $object->fk_incoterms = GETPOST('incoterm_id', 'int'); $object->location_incoterms = GETPOST('location_incoterms', 'alpha'); @@ -543,52 +543,80 @@ if (empty($reshook)) } // Classify billed - else if ($action == 'classifybilled' && $user->rights->propal->cloturer) { - $object->cloture($user, 4, ''); + else if ($action == 'classifybilled' && $user->rights->propal->cloturer) + { + $result=$object->cloture($user, 4, ''); + if ($result < 0) + { + setEventMessages($object->error, $object->errors, 'errors'); + $error++; + } } // Reopen proposal - else if ($action == 'confirm_reopen' && $user->rights->propal->cloturer && ! GETPOST('cancel')) { + else if ($action == 'confirm_reopen' && $user->rights->propal->cloturer && ! GETPOST('cancel')) + { // prevent browser refresh from reopening proposal several times - if ($object->statut == 2 || $object->statut == 3 || $object->statut == 4) { + if ($object->statut == Propal::STATUS_SIGNED || $object->statut == Propal::STATUS_NOTSIGNED || $object->statut == Propal::STATUS_BILLED) { $object->reopen($user, 1); } } // Close proposal - else if ($action == 'setstatut' && $user->rights->propal->cloturer && ! GETPOST('cancel')) { + else if ($action == 'setstatut' && $user->rights->propal->cloturer && ! GETPOST('cancel')) + { if (! GETPOST('statut')) { setEventMessage($langs->trans("ErrorFieldRequired", $langs->transnoentities("CloseAs")), 'errors'); $action = 'statut'; } else { // prevent browser refresh from closing proposal several times - if ($object->statut == 1) { - $object->cloture($user, GETPOST('statut'), GETPOST('note')); + if ($object->statut == Propal::STATUS_VALIDATED) + { + $result=$object->cloture($user, GETPOST('statut'), GETPOST('note')); + if ($result < 0) + { + setEventMessages($object->error, $object->errors, 'errors'); + $error++; + } } } } // Classify billed - else if ($action == 'classifybilled' && $user->rights->propal->cloturer) { - $object->cloture($user, 4, ''); + else if ($action == 'classifybilled' && $user->rights->propal->cloturer) + { + $result=$object->cloture($user, 4, ''); + if ($result < 0) + { + setEventMessages($object->error, $object->errors, 'errors'); + $error++; + } } // Reopen proposal - else if ($action == 'confirm_reopen' && $user->rights->propal->cloturer && ! GETPOST('cancel')) { + else if ($action == 'confirm_reopen' && $user->rights->propal->cloturer && ! GETPOST('cancel')) + { // prevent browser refresh from reopening proposal several times - if ($object->statut == 2 || $object->statut == 3 || $object->statut == 4) { - $object->reopen($user, 1); + if ($object->statut == Propal::STATUS_SIGNED || $object->statut == Propal::STATUS_NOTSIGNED || $object->statut == Propal::STATUS_BILLED) + { + $result=$object->reopen($user, 1); + if ($result < 0) + { + setEventMessages($object->error, $object->errors, 'errors'); + $error++; + } } } // Close proposal - else if ($action == 'setstatut' && $user->rights->propal->cloturer && ! GETPOST('cancel')) { + else if ($action == 'setstatut' && $user->rights->propal->cloturer && ! GETPOST('cancel')) + { if (! GETPOST('statut')) { setEventMessage($langs->trans("ErrorFieldRequired", $langs->transnoentities("CloseAs")), 'errors'); $action = 'statut'; } else { // prevent browser refresh from closing proposal several times - if ($object->statut == 1) { + if ($object->statut == Propal::STATUS_VALIDATED) { $object->cloture($user, GETPOST('statut'), GETPOST('note')); } } @@ -1154,7 +1182,7 @@ if (empty($reshook)) if (! $error) { // Actions on extra fields (by external module or standard code) - // FIXME le hook fait double emploi avec le trigger !! + // TODO le hook fait double emploi avec le trigger !! $hookmanager->initHooks(array('propaldao')); $parameters = array('id' => $object->id); $reshook = $hookmanager->executeHooks('insertExtraFields', $parameters, $object, $action); // Note that $action and $object may have been @@ -1745,7 +1773,7 @@ if ($action == 'create') $absolute_discount = price2num($absolute_discount, 'MT'); $absolute_creditnote = price2num($absolute_creditnote, 'MT'); if ($absolute_discount) { - if ($object->statut > 0) { + if ($object->statut > Propal::STATUS_DRAFT) { print $langs->trans("CompanyHasAbsoluteDiscount", price($absolute_discount, 0, $langs, 0, 0, -1, $conf->currency)); } else { // Remise dispo de type non avoir @@ -1807,7 +1835,7 @@ if ($action == 'create') } else { if (! empty($object->fin_validite)) { print dol_print_date($object->fin_validite, 'daytext'); - if ($object->statut == 1 && $object->fin_validite < ($now - $conf->propal->cloture->warning_delay)) + if ($object->statut == Propal::STATUS_VALIDATED && $object->fin_validite < ($now - $conf->propal->cloture->warning_delay)) print img_warning($langs->trans("Late")); } else { print ' '; @@ -2091,7 +2119,7 @@ if ($action == 'create') '; - if (! empty($conf->use_javascript_ajax) && $object->statut == 0) { + if (! empty($conf->use_javascript_ajax) && $object->statut == Propal::STATUS_DRAFT) { include DOL_DOCUMENT_ROOT . '/core/tpl/ajaxrow.tpl.php'; } @@ -2101,7 +2129,7 @@ if ($action == 'create') $ret = $object->printObjectLines($action, $mysoc, $soc, $lineid, 1); // Form to add new line - if ($object->statut == 0 && $user->rights->propal->creer) + if ($object->statut == Propal::STATUS_DRAFT && $user->rights->propal->creer) { if ($action != 'editline') { @@ -2164,7 +2192,7 @@ if ($action == 'create') if ($action != 'statut' && $action != 'editline') { // Validate - if ($object->statut == 0 && $object->total_ttc >= 0 && count($object->lines) > 0 && + if ($object->statut == Propal::STATUS_DRAFT && $object->total_ttc >= 0 && count($object->lines) > 0 && ((empty($conf->global->MAIN_USE_ADVANCED_PERMS) && ! empty($user->rights->propal->creer)) || (! empty($conf->global->MAIN_USE_ADVANCED_PERMS) && ! empty($user->rights->propal->propal_advance->validate))) ) { @@ -2178,18 +2206,18 @@ if ($action == 'create') print '' . $langs->trans("AddAction") . ''; } // Edit - if ($object->statut == 1 && $user->rights->propal->creer) { + if ($object->statut == Propal::STATUS_VALIDATED && $user->rights->propal->creer) { print ''; } // ReOpen - if (($object->statut == 2 || $object->statut == 3 || $object->statut == 4) && $user->rights->propal->cloturer) { + if (($object->statut == Propal::STATUS_SIGNED || $object->statut == Propal::STATUS_NOTSIGNED || $object->statut == Propal::STATUS_BILLED) && $user->rights->propal->cloturer) { print ''; } // Send - if ($object->statut == 1 || $object->statut == 2) { + if ($object->statut == Propal::STATUS_VALIDATED || $object->statut == Propal::STATUS_SIGNED) { if (empty($conf->global->MAIN_USE_ADVANCED_PERMS) || $user->rights->propal->propal_advance->send) { print ''; } else @@ -2197,14 +2225,14 @@ if ($action == 'create') } // Create an order - if (! empty($conf->commande->enabled) && $object->statut == 2) { + if (! empty($conf->commande->enabled) && $object->statut == Propal::STATUS_SIGNED) { if ($user->rights->commande->creer) { print ''; } } // Create contract - if ($conf->contrat->enabled && $object->statut == 2) { + if ($conf->contrat->enabled && $object->statut == Propal::STATUS_SIGNED) { $langs->load("contracts"); if ($user->rights->contrat->creer) { @@ -2213,7 +2241,8 @@ if ($action == 'create') } // Create an invoice and classify billed - if ($object->statut == 2) { + if ($object->statut == Propal::STATUS_SIGNED) + { if (! empty($conf->facture->enabled) && $user->rights->facture->creer) { print ''; @@ -2227,7 +2256,7 @@ if ($action == 'create') } // Close - if ($object->statut == 1 && $user->rights->propal->cloturer) { + if ($object->statut == Propal::STATUS_VALIDATED && $user->rights->propal->cloturer) { print ''; } @@ -2288,6 +2317,10 @@ if ($action == 'create') /* * Action presend */ + //Select mail models is same action as presend + if (GETPOST('modelselected')) { + $action = 'presend'; + } if ($action == 'presend') { $object->fetch_projet(); @@ -2382,6 +2415,7 @@ if ($action == 'create') // Tableau des parametres complementaires $formmail->param['action'] = 'send'; $formmail->param['models'] = 'propal_send'; + $formmail->param['models_id']=GETPOST('modelmailselected','int'); $formmail->param['id'] = $object->id; $formmail->param['returnurl'] = $_SERVER["PHP_SELF"] . '?id=' . $object->id; // Init list of files diff --git a/htdocs/comm/propal/class/propal.class.php b/htdocs/comm/propal/class/propal.class.php index 0045bc88f91..43379eb221c 100644 --- a/htdocs/comm/propal/class/propal.class.php +++ b/htdocs/comm/propal/class/propal.class.php @@ -56,19 +56,56 @@ class Propal extends CommonObject var $id; - var $socid; // Id client - var $client; // Objet societe client (a charger par fetch_client) + /** + * ID of the client + * @var int + */ + var $socid; + /** + * Client (loaded by fetch_client) + * @var Societe + */ + var $client; var $contactid; var $fk_project; var $author; var $ref; var $ref_client; - var $statut; // 0 (draft), 1 (validated), 2 (signed), 3 (not signed), 4 (billed) - var $datec; // Date of creation - var $datev; // Date of validation - var $date; // Date of proposal - var $datep; // Same than date + + /** + * Status of the quote + * Check the following constants: + * - STATUS_DRAFT + * - STATUS_VALIDATED + * - STATUS_SIGNED + * - STATUS_NOTSIGNED + * - STATUS_BILLED + * @var int + */ + var $statut; + + /** + * Date of creation + * @var + */ + var $datec; + /** + * Date of validation + * @var + */ + var $datev; + /** + * Date of the quote + * @var + */ + var $date; + + /** + * Same than date ¿? + * @var + */ + var $datep; var $date_livraison; var $fin_validite; @@ -81,9 +118,19 @@ class Propal extends CommonObject var $total_localtax1; // Total Local Taxes 1 var $total_localtax2; // Total Local Taxes 2 var $total_ttc; // Total with tax - var $price; // deprecated (for compatibility) - var $tva; // deprecated (for compatibility) - var $total; // deprecated (for compatibility) + + /** + * @deprecated + */ + var $price; + /** + * @deprecated + */ + var $tva; + /** + * @deprecated + */ + var $total; var $cond_reglement_id; var $cond_reglement_code; @@ -93,10 +140,16 @@ class Propal extends CommonObject var $remise; var $remise_percent; var $remise_absolue; - var $note; // deprecated (for compatibility) + /** + * @deprecated + */ + var $note; var $note_private; var $note_public; - var $fk_delivery_address; // deprecated (for compatibility) + /** + * @deprecated + */ + var $fk_delivery_address; var $fk_address; var $address_type; var $address; @@ -122,12 +175,32 @@ class Propal extends CommonObject var $labelstatut_short=array(); var $specimen; - + //Incorterms var $fk_incoterms; var $location_incoterms; var $libelle_incoterms; //Used into tooltip + /** + * Draft status + */ + const STATUS_DRAFT = 0; + /** + * Validated status + */ + const STATUS_VALIDATED = 1; + /** + * Signed quote + */ + const STATUS_SIGNED = 2; + /** + * Not signed quote + */ + const STATUS_NOTSIGNED = 3; + /** + * Billed quote + */ + const STATUS_BILLED = 4; /** * Constructor @@ -365,7 +438,7 @@ class Propal extends CommonObject // Check parameters if ($type < 0) return -1; - if ($this->statut == 0) + if ($this->statut == self::STATUS_DRAFT) { $this->db->begin(); @@ -531,7 +604,7 @@ class Propal extends CommonObject if (empty($qty) && empty($special_code)) $special_code=3; // Set option tag if (! empty($qty) && $special_code == 3) $special_code=0; // Remove option tag - if ($this->statut == 0) + if ($this->statut == self::STATUS_DRAFT) { $this->db->begin(); @@ -657,7 +730,7 @@ class Propal extends CommonObject */ function deleteline($lineid) { - if ($this->statut == 0) + if ($this->statut == self::STATUS_DRAFT) { $line=new PropaleLigne($this->db); @@ -893,7 +966,7 @@ class Propal extends CommonObject $action='update'; // Actions on extra fields (by external module or standard code) - // FIXME le hook fait double emploi avec le trigger !! + // TODO le hook fait double emploi avec le trigger !! $hookmanager->initHooks(array('propaldao')); $parameters=array('socid'=>$this->id); $reshook=$hookmanager->executeHooks('insertExtraFields',$parameters,$this,$action); // Note that $action and $object may have been modified by some hooks @@ -1015,7 +1088,7 @@ class Propal extends CommonObject } $this->id=0; - $this->statut=0; + $this->statut=self::STATUS_DRAFT; if (empty($conf->global->PROPALE_ADDON) || ! is_readable(DOL_DOCUMENT_ROOT ."/core/modules/propale/".$conf->global->PROPALE_ADDON.".php")) { @@ -1197,10 +1270,10 @@ class Propal extends CommonObject //Incoterms $this->fk_incoterms = $obj->fk_incoterms; - $this->location_incoterms = $obj->location_incoterms; + $this->location_incoterms = $obj->location_incoterms; $this->libelle_incoterms = $obj->libelle_incoterms; - - if ($obj->fk_statut == 0) + + if ($obj->fk_statut == self::STATUS_DRAFT) { $this->brouillon = 1; } @@ -1236,7 +1309,7 @@ class Propal extends CommonObject $extrafieldsline=new ExtraFields($this->db); $line = new PropaleLigne($this->db); $extralabelsline=$extrafieldsline->fetch_name_optionals_label($line->table_element,true); - + $num = $this->db->num_rows($result); $i = 0; @@ -1290,7 +1363,7 @@ class Propal extends CommonObject $line->date_end = $objp->date_end; $line->fetch_optionals($line->id,$extralabelsline); - + $this->lines[$i] = $line; //dol_syslog("1 ".$line->fk_product); //print "xx $i ".$this->lines[$i]->fk_product; @@ -1329,7 +1402,7 @@ class Propal extends CommonObject $action='update'; // Actions on extra fields (by external module or standard code) - // FIXME le hook fait double emploi avec le trigger !! + // TODO le hook fait double emploi avec le trigger !! $hookmanager->initHooks(array('propaldao')); $parameters=array('id'=>$this->id); $reshook=$hookmanager->executeHooks('insertExtraFields',$parameters,$this,$action); // Note that $action and $object may have been modified by some hooks @@ -1395,8 +1468,8 @@ class Propal extends CommonObject $sql = "UPDATE ".MAIN_DB_PREFIX."propal"; $sql.= " SET ref = '".$num."',"; - $sql.= " fk_statut = 1, date_valid='".$this->db->idate($now)."', fk_user_valid=".$user->id; - $sql.= " WHERE rowid = ".$this->id." AND fk_statut = 0"; + $sql.= " fk_statut = ".self::STATUS_VALIDATED.", date_valid='".$this->db->idate($now)."', fk_user_valid=".$user->id; + $sql.= " WHERE rowid = ".$this->id." AND fk_statut = ".self::STATUS_DRAFT; dol_syslog(get_class($this)."::valid", LOG_DEBUG); $resql=$this->db->query($sql); @@ -1451,7 +1524,7 @@ class Propal extends CommonObject $this->ref=$num; $this->brouillon=0; - $this->statut = 1; + $this->statut = self::STATUS_VALIDATED; $this->user_valid_id=$user->id; $this->datev=$now; @@ -1486,7 +1559,7 @@ class Propal extends CommonObject if (! empty($user->rights->propal->creer)) { $sql = "UPDATE ".MAIN_DB_PREFIX."propal SET datep = '".$this->db->idate($date)."'"; - $sql.= " WHERE rowid = ".$this->id." AND fk_statut = 0"; + $sql.= " WHERE rowid = ".$this->id." AND fk_statut = ".self::STATUS_DRAFT; dol_syslog(get_class($this)."::set_date", LOG_DEBUG); if ($this->db->query($sql) ) @@ -1515,7 +1588,7 @@ class Propal extends CommonObject if (! empty($user->rights->propal->creer)) { $sql = "UPDATE ".MAIN_DB_PREFIX."propal SET fin_validite = ".($date_fin_validite!=''?"'".$this->db->idate($date_fin_validite)."'":'null'); - $sql.= " WHERE rowid = ".$this->id." AND fk_statut = 0"; + $sql.= " WHERE rowid = ".$this->id." AND fk_statut = ".self::STATUS_DRAFT; if ($this->db->query($sql) ) { $this->fin_validite = $date_fin_validite; @@ -1665,7 +1738,7 @@ class Propal extends CommonObject $remise = price2num($remise); $sql = "UPDATE ".MAIN_DB_PREFIX."propal SET remise_percent = ".$remise; - $sql.= " WHERE rowid = ".$this->id." AND fk_statut = 0"; + $sql.= " WHERE rowid = ".$this->id." AND fk_statut = ".self::STATUS_DRAFT; if ($this->db->query($sql) ) { @@ -1699,7 +1772,7 @@ class Propal extends CommonObject $sql = "UPDATE ".MAIN_DB_PREFIX."propal "; $sql.= " SET remise_absolue = ".$remise; - $sql.= " WHERE rowid = ".$this->id." AND fk_statut = 0"; + $sql.= " WHERE rowid = ".$this->id." AND fk_statut = ".self::STATUS_DRAFT; if ($this->db->query($sql) ) { @@ -1791,7 +1864,6 @@ class Propal extends CommonObject { global $langs,$conf; - $this->statut = $statut; $error=0; $now=dol_now(); @@ -1807,7 +1879,7 @@ class Propal extends CommonObject $modelpdf=$conf->global->PROPALE_ADDON_PDF_ODT_CLOSED?$conf->global->PROPALE_ADDON_PDF_ODT_CLOSED:$this->modelpdf; $trigger_name='PROPAL_CLOSE_REFUSED'; - if ($statut == 2) + if ($statut == self::STATUS_SIGNED) { $trigger_name='PROPAL_CLOSE_SIGNED'; $modelpdf=$conf->global->PROPALE_ADDON_PDF_ODT_TOBILL?$conf->global->PROPALE_ADDON_PDF_ODT_TOBILL:$this->modelpdf; @@ -1819,12 +1891,12 @@ class Propal extends CommonObject if ($result < 0) { - $this->error=$this->db->error(); + $this->error=$this->db->lasterror(); $this->db->rollback(); return -2; } } - if ($statut == 4) + if ($statut == self::STATUS_BILLED) { $trigger_name='PROPAL_CLASSIFY_BILLED'; } @@ -1850,7 +1922,9 @@ class Propal extends CommonObject if ( ! $error ) { - $this->db->commit(); + $this->statut = $statut; + + $this->db->commit(); return 1; } else @@ -1861,7 +1935,7 @@ class Propal extends CommonObject } else { - $this->error=$this->db->error(); + $this->error=$this->db->lasterror(); $this->db->rollback(); return -1; } @@ -1874,11 +1948,11 @@ class Propal extends CommonObject */ function classifyBilled() { - $sql = 'UPDATE '.MAIN_DB_PREFIX.'propal SET fk_statut = 4'; - $sql .= ' WHERE rowid = '.$this->id.' AND fk_statut > 0 ;'; + $sql = 'UPDATE '.MAIN_DB_PREFIX.'propal SET fk_statut = '.self::STATUS_BILLED; + $sql .= ' WHERE rowid = '.$this->id.' AND fk_statut > '.self::STATUS_DRAFT.' ;'; if ($this->db->query($sql) ) { - $this->statut=4; + $this->statut=self::STATUS_BILLED; return 1; } else @@ -1906,12 +1980,12 @@ class Propal extends CommonObject */ function set_draft($user) { - $sql = "UPDATE ".MAIN_DB_PREFIX."propal SET fk_statut = 0"; + $sql = "UPDATE ".MAIN_DB_PREFIX."propal SET fk_statut = ".self::STATUS_DRAFT; $sql.= " WHERE rowid = ".$this->id; if ($this->db->query($sql)) { - $this->statut = 0; + $this->statut = self::STATUS_DRAFT; $this->brouillon = 1; return 1; } @@ -1955,7 +2029,7 @@ class Propal extends CommonObject $sql.= " AND s.rowid = sc.fk_soc AND sc.fk_user = " .$user->id; } if ($socid) $sql.= " AND s.rowid = ".$socid; - if ($draft) $sql.= " AND p.fk_statut = 0"; + if ($draft) $sql.= " AND p.fk_statut = ".self::STATUS_DRAFT; if ($notcurrentuser > 0) $sql.= " AND p.fk_user_author <> ".$user->id; $sql.= $this->db->order($sortfield,$sortorder); $sql.= $this->db->plimit($limit,$offset); @@ -2225,7 +2299,7 @@ class Propal extends CommonObject function availability($availability_id) { dol_syslog('Propale::availability('.$availability_id.')'); - if ($this->statut >= 0) + if ($this->statut >= self::STATUS_DRAFT) { $sql = 'UPDATE '.MAIN_DB_PREFIX.'propal'; $sql .= ' SET fk_availability = '.$availability_id; @@ -2259,7 +2333,7 @@ class Propal extends CommonObject function demand_reason($demand_reason_id) { dol_syslog('Propale::demand_reason('.$demand_reason_id.')'); - if ($this->statut >= 0) + if ($this->statut >= self::STATUS_DRAFT) { $sql = 'UPDATE '.MAIN_DB_PREFIX.'propal'; $sql .= ' SET fk_input_reason = '.$demand_reason_id; @@ -2366,11 +2440,11 @@ class Propal extends CommonObject global $langs; $langs->load("propal"); - if ($statut==0) $statuttrans='statut0'; - if ($statut==1) $statuttrans='statut1'; - if ($statut==2) $statuttrans='statut3'; - if ($statut==3) $statuttrans='statut5'; - if ($statut==4) $statuttrans='statut6'; + if ($statut==self::STATUS_DRAFT) $statuttrans='statut0'; + if ($statut==self::STATUS_VALIDATED) $statuttrans='statut1'; + if ($statut==self::STATUS_SIGNED) $statuttrans='statut3'; + if ($statut==self::STATUS_NOTSIGNED) $statuttrans='statut5'; + if ($statut==self::STATUS_BILLED) $statuttrans='statut6'; if ($mode == 0) return $this->labelstatut[$statut]; if ($mode == 1) return $this->labelstatut_short[$statut]; @@ -2403,8 +2477,8 @@ class Propal extends CommonObject $clause = " AND"; } $sql.= $clause." p.entity = ".$conf->entity; - if ($mode == 'opened') $sql.= " AND p.fk_statut = 1"; - if ($mode == 'signed') $sql.= " AND p.fk_statut = 2"; + if ($mode == 'opened') $sql.= " AND p.fk_statut = ".self::STATUS_VALIDATED; + if ($mode == 'signed') $sql.= " AND p.fk_statut = ".self::STATUS_SIGNED; if ($user->societe_id) $sql.= " AND p.fk_soc = ".$user->societe_id; $resql=$this->db->query($sql); @@ -2415,12 +2489,12 @@ class Propal extends CommonObject if ($mode == 'opened') { $delay_warning=$conf->propal->cloture->warning_delay; - $statut = 1; + $statut = self::STATUS_VALIDATED; $label = $langs->trans("PropalsToClose"); } if ($mode == 'signed') { $delay_warning=$conf->propal->facturation->warning_delay; - $statut = 2; + $statut = self::STATUS_SIGNED; $label = $langs->trans("PropalsToBill"); } @@ -2806,7 +2880,22 @@ class Propal extends CommonObject return $this->commonGenerateDocument($modelpath, $modele, $outputlangs, $hidedetails, $hidedesc, $hideref); } + /** + * Function used to replace a thirdparty id with another one. + * + * @param DoliDB $db Database handler + * @param int $origin_id Old thirdparty id + * @param int $dest_id New thirdparty id + * @return bool + */ + public static function replaceThirdparty(DoliDB $db, $origin_id, $dest_id) + { + $tables = array( + 'propal' + ); + return CommonObject::commonReplaceThirdparty($db, $origin_id, $dest_id, $tables); + } } @@ -2827,7 +2916,14 @@ class PropaleLigne extends CommonObjectLine var $fk_parent_line; var $desc; // Description ligne var $fk_product; // Id produit predefini - var $product_type = 0; // Type 0 = product, 1 = Service + /** + * Product type. + * Use the following constants: + * - Product::TYPE_PRODUCT + * - Product::TYPE_SERVICE + * @var int + */ + var $product_type = Product::TYPE_PRODUCT; var $qty; var $tva_tx; diff --git a/htdocs/comm/propal/note.php b/htdocs/comm/propal/note.php index 9292684d06f..05cd2db3f04 100644 --- a/htdocs/comm/propal/note.php +++ b/htdocs/comm/propal/note.php @@ -126,7 +126,7 @@ if ($id > 0 || ! empty($ref)) if ($object->fin_validite) { print dol_print_date($object->fin_validite,'daytext'); - if ($object->statut == 1 && $object->fin_validite < ($now - $conf->propal->cloture->warning_delay)) print img_warning($langs->trans("Late")); + if ($object->statut == Propal::STATUS_VALIDATED && $object->fin_validite < ($now - $conf->propal->cloture->warning_delay)) print img_warning($langs->trans("Late")); } else { diff --git a/htdocs/comm/prospect/list.php b/htdocs/comm/prospect/list.php index b2202a21b88..1ab843da188 100644 --- a/htdocs/comm/prospect/list.php +++ b/htdocs/comm/prospect/list.php @@ -201,7 +201,7 @@ if ((!$user->rights->societe->client->voir && !$socid) || $search_sale > 0) $sql $sql .= " FROM ".MAIN_DB_PREFIX."c_stcomm as st"; $sql.= ", ".MAIN_DB_PREFIX."societe as s"; $sql.= " LEFT JOIN ".MAIN_DB_PREFIX."c_departements as d on (d.rowid = s.fk_departement)"; -if (! empty($search_categ) || ! empty($catid)) $sql.= ' LEFT JOIN '.MAIN_DB_PREFIX."categorie_societe as cs ON s.rowid = cs.fk_societe"; // We need this table joined to the select in order to filter by categ +if (! empty($search_categ) || ! empty($catid)) $sql.= ' LEFT JOIN '.MAIN_DB_PREFIX."categorie_societe as cs ON s.rowid = cs.fk_soc"; // We need this table joined to the select in order to filter by categ if ((!$user->rights->societe->client->voir && !$socid) || $search_sale > 0) $sql.= ", ".MAIN_DB_PREFIX."societe_commerciaux as sc"; // We need this table joined to the select in order to filter by sale $sql.= " WHERE s.fk_stcomm = st.id"; $sql.= " AND s.client IN (2, 3)"; diff --git a/htdocs/commande/card.php b/htdocs/commande/card.php index 162fa01a424..f174ab9e8ff 100644 --- a/htdocs/commande/card.php +++ b/htdocs/commande/card.php @@ -1125,7 +1125,7 @@ if (empty($reshook)) if (! $error) { // Actions on extra fields (by external module or standard code) - // FIXME le hook fait double emploi avec le trigger !! + // TODO le hook fait double emploi avec le trigger !! $hookmanager->initHooks(array('orderdao')); $parameters = array('id' => $object->id); $reshook = $hookmanager->executeHooks('insertExtraFields', $parameters, $object, $action); // Note that $action and $object may have been modified by @@ -2404,6 +2404,7 @@ if ($action == 'create' && $user->rights->commande->creer) // Tableau des parametres complementaires $formmail->param['action'] = 'send'; $formmail->param['models'] = 'order_send'; + $formmail->param['models_id']=GETPOST('modelmailselected','int'); $formmail->param['orderid'] = $object->id; $formmail->param['returnurl'] = $_SERVER["PHP_SELF"] . '?id=' . $object->id; diff --git a/htdocs/commande/class/commande.class.php b/htdocs/commande/class/commande.class.php index 9c9322d3ef5..91b17273513 100644 --- a/htdocs/commande/class/commande.class.php +++ b/htdocs/commande/class/commande.class.php @@ -53,8 +53,17 @@ class Commande extends CommonOrder var $id; - var $socid; // Id client - var $client; // Objet societe client (a charger par fetch_client) + /** + * Client ID + * @var int + */ + var $socid; + + /** + * Client (loaded by fetch_client) + * @var Societe + */ + var $client; var $ref; var $ref_client; @@ -71,31 +80,13 @@ class Commande extends CommonOrder * - STATUS_CLOSED * @var int */ - var $statut; // -1=Canceled, 0=Draft, 1=Validated, (2=Accepted/On process not managed for customer orders), 3=Closed (Delivered=Sent/Received, billed or not) + var $statut; + /** + * @deprecated + */ var $facturee; // deprecated var $billed; // billed or not - /** - * Canceled status - */ - const STATUS_CANCELED = -1; - /** - * Draft status - */ - const STATUS_DRAFT = 0; - /** - * Validated status - */ - const STATUS_VALIDATED = 1; - /** - * Accepted/On process not managed for customer orders - */ - const STATUS_ACCEPTED = 2; - /** - * Closed (Sent/Received, billed or not) - */ - const STATUS_CLOSED = 3; - var $brouillon; var $cond_reglement_id; var $cond_reglement_code; @@ -155,6 +146,27 @@ class Commande extends CommonOrder */ const STOCK_NOT_ENOUGH_FOR_ORDER = -3; + /** + * Canceled status + */ + const STATUS_CANCELED = -1; + /** + * Draft status + */ + const STATUS_DRAFT = 0; + /** + * Validated status + */ + const STATUS_VALIDATED = 1; + /** + * Accepted/On process not managed for customer orders + */ + const STATUS_ACCEPTED = 2; + /** + * Closed (Sent/Received, billed or not) + */ + const STATUS_CLOSED = 3; + /** * Constructor @@ -792,7 +804,7 @@ class Commande extends CommonOrder $this->lines[$i]->fk_fournprice, $this->lines[$i]->pa_ht, $this->lines[$i]->label, - $this->lines[$i]->array_options, + $this->lines[$i]->array_options, $this->lines[$i]->fk_unit ); if ($result < 0) @@ -865,28 +877,25 @@ class Commande extends CommonOrder if (! $error) { - $action='create'; + //$action='create'; // Actions on extra fields (by external module or standard code) - // FIXME le hook fait double emploi avec le trigger !! - $hookmanager->initHooks(array('orderdao')); + // TODO le hook fait double emploi avec le trigger !! + /*$hookmanager->initHooks(array('orderdao')); $parameters=array('socid'=>$this->id); $reshook=$hookmanager->executeHooks('insertExtraFields',$parameters,$this,$action); // Note that $action and $object may have been modified by some hooks if (empty($reshook)) { if (empty($conf->global->MAIN_EXTRAFIELDS_DISABLED)) // For avoid conflicts if trigger used - { + {*/ $result=$this->insertExtraFields(); - if ($result < 0) - { - $error++; - } - } + if ($result < 0) $error++; + /* } } - else if ($reshook < 0) $error++; + else if ($reshook < 0) $error++;*/ } - if (! $notrigger) + if (! $error && ! $notrigger) { // Call trigger $result=$this->call_trigger('ORDER_CREATE',$user); @@ -894,29 +903,27 @@ class Commande extends CommonOrder // End call triggers } - if (!$error) { + if (! $error) + { $this->db->commit(); return $this->id; } - - foreach($this->errors as $errmsg) - { - dol_syslog(get_class($this)."::create ".$errmsg, LOG_ERR); - $this->error.=($this->error?', '.$errmsg:$errmsg); - } - $this->db->rollback(); - return -1*$error; - + else + { + $this->db->rollback(); + return -1*$error; + } } else - { + { + $this->error=$this->db->lasterror(); $this->db->rollback(); return -1; } } } else - { + { dol_print_error($this->db); $this->db->rollback(); return -1; @@ -2668,7 +2675,7 @@ class Commande extends CommonOrder $action='create'; // Actions on extra fields (by external module or standard code) - // FIXME le hook fait double emploi avec le trigger !! + // TODO le hook fait double emploi avec le trigger !! $hookmanager->initHooks(array('orderdao')); $parameters=array('id'=>$this->id); $reshook=$hookmanager->executeHooks('insertExtraFields',$parameters,$this,$action); // Note that $action and $object may have been modified by some hooks @@ -3299,6 +3306,23 @@ class Commande extends CommonOrder return $this->commonGenerateDocument($modelpath, $modele, $outputlangs, $hidedetails, $hidedesc, $hideref); } + + /** + * Function used to replace a thirdparty id with another one. + * + * @param DoliDB $db Database handler + * @param int $origin_id Old thirdparty id + * @param int $dest_id New thirdparty id + * @return bool + */ + public static function replaceThirdparty(DoliDB $db, $origin_id, $dest_id) + { + $tables = array( + 'commande' + ); + + return CommonObject::commonReplaceThirdparty($db, $origin_id, $dest_id, $tables); + } } diff --git a/htdocs/compta/bank/account.php b/htdocs/compta/bank/account.php index 6ba80304188..ce2bbc5381e 100644 --- a/htdocs/compta/bank/account.php +++ b/htdocs/compta/bank/account.php @@ -403,7 +403,7 @@ if ($id > 0 || ! empty($ref)) print ''; if ($nbcategories) { - print '
'.$langs->trans("Category").': '; + print '
'.$langs->trans("Rubrique").': '; } print '
'.$langs->trans("None").' // Total foreach ($total as $key=>$solde) { - print '
'.$langs->trans("Total ").$key.''.price($solde, 0, $langs, 0, 0, -1, $key).'
'.$langs->trans("Total").' '.$key.''.price($solde, 0, $langs, 0, 0, -1, $key).'
'; @@ -186,7 +186,7 @@ if (! $found) // Total foreach ($total as $key=>$solde) { - print '
'.$langs->trans("Total ").$key.''.price($solde, 0, $langs, 0, 0, -1, $key).'
'.$langs->trans("Total").' '.$key.''.price($solde, 0, $langs, 0, 0, -1, $key).'
'; @@ -253,7 +253,7 @@ if (! $found) // Total foreach ($total as $key=>$solde) { - print '
'.$langs->trans("Total ").$key.''.price($solde, 0, $langs, 0, 0, -1, $key).'
'.$langs->trans("Total").' '.$key.''.price($solde, 0, $langs, 0, 0, -1, $key).'
"; diff --git a/htdocs/compta/bank/releve.php b/htdocs/compta/bank/releve.php index 6f207b198cf..c89f45d0d2c 100644 --- a/htdocs/compta/bank/releve.php +++ b/htdocs/compta/bank/releve.php @@ -379,7 +379,7 @@ else elseif ($links[$key]['type']=='payment_supplier') { $paymentsupplierstatic->id=$links[$key]['url_id']; - $paymentsupplierstatic->ref=$langs->trans("Payment");; + $paymentsupplierstatic->ref=$langs->trans("Payment"); print ' '.$paymentsupplierstatic->getNomUrl(1); $newline=0; } diff --git a/htdocs/compta/bank/search.php b/htdocs/compta/bank/search.php index a1e114430ce..f367149a19c 100644 --- a/htdocs/compta/bank/search.php +++ b/htdocs/compta/bank/search.php @@ -178,9 +178,10 @@ if ($resql) print '
'."\n"; print ''."\n"; - $moreforfilter .= $langs->trans('Period') . ' ' . $langs->trans('StartDate') . ': '; - $moreforfilter .= $form->select_date($search_dt_start, 'search_start_dt', 0, 0, 1, "search_form", 1, 1, 1); - $moreforfilter .= $langs->trans('EndDate') . ':' . $form->select_date($search_dt_end, 'search_end_dt', 0, 0, 1, "search_form", 1, 1, 1); + $moreforfilter .= $langs->trans('Period') . ' ('.$langs->trans('DateOperationShort').') : ' . $langs->trans('StartDate') . ' '; + $moreforfilter .= $form->select_date($search_dt_start, 'search_start_dt', 0, 0, 1, "search_form", 1, 0, 1); + $moreforfilter .= ' - '; + $moreforfilter .= $langs->trans('EndDate') . ' ' . $form->select_date($search_dt_end, 'search_end_dt', 0, 0, 1, "search_form", 1, 0, 1); if ($moreforfilter) { diff --git a/htdocs/compta/bank/treso.php b/htdocs/compta/bank/treso.php index 91c41aa5e3c..292742315bb 100644 --- a/htdocs/compta/bank/treso.php +++ b/htdocs/compta/bank/treso.php @@ -329,8 +329,8 @@ if ($_REQUEST["account"] || $_REQUEST["ref"]) // Solde actuel $var=!$var; print ''; - print ''.$langs->trans("FutureBalance").''; - print ''.price($solde).''; + print ''.$langs->trans("FutureBalance").' ('.$acct->currency_code.')'; + print ''.price($solde, 0, $langs, 0, 0, -1, $acct->currency_code).''; print ''; print ""; diff --git a/htdocs/compta/bank/virement.php b/htdocs/compta/bank/virement.php index 5583edbe357..0c2c62c052f 100644 --- a/htdocs/compta/bank/virement.php +++ b/htdocs/compta/bank/virement.php @@ -79,7 +79,7 @@ if ($action == 'add') $accountto=new Account($db); $accountto->fetch(GETPOST('account_to','int')); - if ($accountto->id != $accountfrom->id) + if (($accountto->id != $accountfrom->id) && ($accountto->currency_code == $accountfrom->currency_code)) { $db->begin(); diff --git a/htdocs/compta/facture.php b/htdocs/compta/facture.php index e57c07bc754..84da04033b7 100644 --- a/htdocs/compta/facture.php +++ b/htdocs/compta/facture.php @@ -5,13 +5,15 @@ * Copyright (C) 2005 Marc Barilley / Ocebo * Copyright (C) 2005-2012 Regis Houssin * Copyright (C) 2006 Andre Cianfarani - * Copyright (C) 2010-2013 Juanjo Menent + * Copyright (C) 2010-2015 Juanjo Menent * Copyright (C) 2012-2013 Christophe Battarel * Copyright (C) 2012-2013 Cédric Salvador * Copyright (C) 2012-2014 Raphaël Doursenaud * Copyright (C) 2013 Jean-Francois FERRY * Copyright (C) 2013-2014 Florian Henry - * Copyright (C) 2014 Ferran Marcet + * Copyright (C) 2013 Cédric Salvador + * Copyright (C) 2014 Ferran Marcet + * Copyright (C) 2015 Marcos García * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -1077,7 +1079,11 @@ if (empty($reshook)) $array_options = $lines[$i]->array_options; } - $result = $object->addline($desc, $lines[$i]->subprice, $lines[$i]->qty, $lines[$i]->tva_tx, $lines[$i]->localtax1_tx, $lines[$i]->localtax2_tx, $lines[$i]->fk_product, $lines[$i]->remise_percent, $date_start, $date_end, 0, $lines[$i]->info_bits, $lines[$i]->fk_remise_except, 'HT', 0, $product_type, $lines[$i]->rang, $lines[$i]->special_code, $object->origin, $lines[$i]->rowid, $fk_parent_line, $lines[$i]->fk_fournprice, $lines[$i]->pa_ht, $label, $array_options, $lines[$i]->situation_percent, $lines[$i]->fk_prev_id, $lines[$i]->fk_unit); + // View third's localtaxes for now + $localtax1_tx = get_localtax($lines[$i]->tva_tx, 1, $object->client); + $localtax2_tx = get_localtax($lines[$i]->tva_tx, 2, $object->client); + + $result = $object->addline($desc, $lines[$i]->subprice, $lines[$i]->qty, $lines[$i]->tva_tx, $localtax1_tx, $localtax2_tx, $lines[$i]->fk_product, $lines[$i]->remise_percent, $date_start, $date_end, 0, $lines[$i]->info_bits, $lines[$i]->fk_remise_except, 'HT', 0, $product_type, $lines[$i]->rang, $lines[$i]->special_code, $object->origin, $lines[$i]->rowid, $fk_parent_line, $lines[$i]->fk_fournprice, $lines[$i]->pa_ht, $label, $array_options, $lines[$i]->situation_percent, $lines[$i]->fk_prev_id, $lines[$i]->fk_unit); if ($result > 0) { $lineid = $result; @@ -1817,7 +1823,7 @@ if (empty($reshook)) if (! $error) { // Actions on extra fields (by external module or standard code) - // FIXME le hook fait double emploi avec le trigger !! + // TODO le hook fait double emploi avec le trigger !! $hookmanager->initHooks(array('invoicedao')); $parameters = array('id' => $object->id); $reshook = $hookmanager->executeHooks('insertExtraFields', $parameters, $object, $action); // Note that $action and $object may have been modified by @@ -1972,12 +1978,12 @@ if ($action == 'create') print $soc->getNomUrl(1); print ''; // Outstanding Bill - $outstandigBills = $soc->get_OutstandingBill(); + $outstandingBills = $soc->get_OutstandingBill(); print ' (' . $langs->trans('CurrentOutstandingBill') . ': '; - print price($outstandigBills, '', $langs, 0, 0, -1, $conf->currency); + print price($outstandingBills, '', $langs, 0, 0, -1, $conf->currency); if ($soc->outstanding_limit != '') { - if ($outstandigBills > $soc->outstanding_limit) print img_warning($langs->trans("OutstandingBillReached")); + if ($outstandingBills > $soc->outstanding_limit) print img_warning($langs->trans("OutstandingBillReached")); print ' / ' . price($soc->outstanding_limit, '', $langs, 0, 0, -1, $conf->currency); } print ')'; @@ -2366,15 +2372,25 @@ if ($action == 'create') print ''; print ''; - $newclassname = $classname; - if ($newclassname == 'Propal') - $newclassname = 'CommercialProposal'; - elseif ($newclassname == 'Commande') - $newclassname = 'Order'; - elseif ($newclassname == 'Expedition') - $newclassname = 'Sending'; - elseif ($newclassname == 'Fichinter') - $newclassname = 'Intervention'; + switch ($classname) { + case 'Propal': + $newclassname = 'CommercialProposal'; + break; + case 'Commande': + $newclassname = 'Order'; + break; + case 'Expedition': + $newclassname = 'Sending'; + break; + case 'Contrat': + $newclassname = 'Contract'; + break; + case 'Fichinter': + $newclassname = 'Intervention'; + break; + default: + $newclassname = $classname; + } print '' . $langs->trans($newclassname) . '' . $objectsrc->getNomUrl(1); //We check if Origin document has already an invoice attached to it @@ -2828,11 +2844,11 @@ if ($action == 'create') print '   '; print '(' . $langs->trans('OtherBills') . ''; // Outstanding Bill - $outstandigBills = $soc->get_OutstandingBill(); + $outstandingBills = $soc->get_OutstandingBill(); print ' - ' . $langs->trans('CurrentOutstandingBill') . ': '; - print price($outstandigBills, '', $langs, 0, 0, - 1, $conf->currency); + print price($outstandingBills, '', $langs, 0, 0, - 1, $conf->currency); if ($soc->outstanding_limit != '') { - if ($outstandigBills > $soc->outstanding_limit) + if ($outstandingBills > $soc->outstanding_limit) print img_warning($langs->trans("OutstandingBillReached")); print ' / ' . price($soc->outstanding_limit); } @@ -3729,6 +3745,10 @@ if ($action == 'create') } print '
'; + //Select mail models is same action as presend + if (GETPOST('modelselected')) { + $action = 'presend'; + } if ($action != 'prerelance' && $action != 'presend') { print '
'; @@ -3949,6 +3969,7 @@ if ($action == 'create') // Tableau des parametres complementaires du post $formmail->param['action'] = $action; $formmail->param['models'] = $modelmail; + $formmail->param['models_id']=GETPOST('modelmailselected','int'); $formmail->param['facid'] = $object->id; $formmail->param['returnurl'] = $_SERVER["PHP_SELF"] . '?id=' . $object->id; diff --git a/htdocs/compta/facture/class/facture-rec.class.php b/htdocs/compta/facture/class/facture-rec.class.php index 94053299f79..077299baa7d 100644 --- a/htdocs/compta/facture/class/facture-rec.class.php +++ b/htdocs/compta/facture/class/facture-rec.class.php @@ -5,6 +5,7 @@ * Copyright (C) 2010-2011 Juanjo Menent * Copyright (C) 2012 Cedric Salvador * Copyright (C) 2013 Florian Henry + * Copyright (C) 2015 Marcos García * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -599,5 +600,21 @@ class FactureRec extends Facture $this->usenewprice = 1; } - + + /** + * Function used to replace a thirdparty id with another one. + * + * @param DoliDB $db Database handler + * @param int $origin_id Old thirdparty id + * @param int $dest_id New thirdparty id + * @return bool + */ + public static function replaceThirdparty(DoliDB $db, $origin_id, $dest_id) + { + $tables = array( + 'facture_rec' + ); + + return CommonObject::commonReplaceThirdparty($db, $origin_id, $dest_id, $tables); + } } diff --git a/htdocs/compta/facture/class/facture.class.php b/htdocs/compta/facture/class/facture.class.php index 9f81fc4420c..920f165f83f 100644 --- a/htdocs/compta/facture/class/facture.class.php +++ b/htdocs/compta/facture/class/facture.class.php @@ -137,7 +137,7 @@ class Facture extends CommonInvoice var $specimen; var $fac_rec; - + //Incoterms var $fk_incoterms; var $location_incoterms; @@ -563,7 +563,7 @@ class Facture extends CommonInvoice $action='create'; // Actions on extra fields (by external module or standard code) - // FIXME le hook fait double emploi avec le trigger !! + // TODO le hook fait double emploi avec le trigger !! $hookmanager->initHooks(array('invoicedao')); $parameters=array('invoiceid'=>$this->id); $reshook=$hookmanager->executeHooks('insertExtraFields',$parameters,$this,$action); // Note that $action and $object may have been modified by some hooks @@ -1045,9 +1045,9 @@ class Facture extends CommonInvoice //Incoterms $this->fk_incoterms = $obj->fk_incoterms; - $this->location_incoterms = $obj->location_incoterms; + $this->location_incoterms = $obj->location_incoterms; $this->libelle_incoterms = $obj->libelle_incoterms; - + if ($this->statut == self::STATUS_DRAFT) $this->brouillon = 1; // Retreive all extrafield for invoice @@ -3618,7 +3618,7 @@ class Facture extends CommonInvoice $this->db->commit(); return 1; } else { - $this->error = $this->db->error(); + $this->error = $this->db->lasterror(); dol_syslog(get_class($this) . "::update Error setFinal " . $sql, LOG_ERR); $this->db->rollback(); return -1; @@ -3641,12 +3641,29 @@ class Facture extends CommonInvoice $last = $res['max(situation_counter)']; return ($last == $this->situation_counter); } else { - $this->error = $this->db->error(); + $this->error = $this->db->lasterror(); dol_syslog(get_class($this) . "::select Error " . $this->error, LOG_ERR); $this->db->rollback(); return -1; } } + + /** + * Function used to replace a thirdparty id with another one. + * + * @param DoliDB $db Database handler + * @param int $origin_id Old thirdparty id + * @param int $dest_id New thirdparty id + * @return bool + */ + public static function replaceThirdparty(DoliDB $db, $origin_id, $dest_id) + { + $tables = array( + 'facture' + ); + + return CommonObject::commonReplaceThirdparty($db, $origin_id, $dest_id, $tables); + } } /** diff --git a/htdocs/compta/facture/impayees.php b/htdocs/compta/facture/mergepdftool.php similarity index 88% rename from htdocs/compta/facture/impayees.php rename to htdocs/compta/facture/mergepdftool.php index d91b52b2166..3f3315fda04 100644 --- a/htdocs/compta/facture/impayees.php +++ b/htdocs/compta/facture/mergepdftool.php @@ -1,7 +1,7 @@ * Copyright (C) 2004 Eric Seigne - * Copyright (C) 2004-2014 Laurent Destailleur + * Copyright (C) 2004-2015 Laurent Destailleur * Copyright (C) 2005-2012 Regis Houssin * Copyright (C) 2012 Cédric Salvador * Copyright (C) 2014 Raphaël Doursenaud @@ -24,17 +24,19 @@ */ /** - * \file htdocs/compta/facture/impayees.php + * \file htdocs/compta/facture/mergepdftool.php * \ingroup facture - * \brief Page to list and build liste of unpaid invoices + * \brief Page to list and build doc of selected invoices */ require '../../main.inc.php'; require_once DOL_DOCUMENT_ROOT.'/core/class/html.formfile.class.php'; +require_once DOL_DOCUMENT_ROOT.'/core/class/html.formother.class.php'; require_once DOL_DOCUMENT_ROOT.'/compta/facture/class/facture.class.php'; require_once DOL_DOCUMENT_ROOT.'/compta/paiement/class/paiement.class.php'; require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php'; require_once DOL_DOCUMENT_ROOT.'/core/lib/pdf.lib.php'; +require_once DOL_DOCUMENT_ROOT.'/core/lib/date.lib.php'; $langs->load("mails"); $langs->load("bills"); @@ -44,6 +46,18 @@ $action = GETPOST('action','alpha'); $option = GETPOST('option'); $mode=GETPOST('mode'); $builddoc_generatebutton=GETPOST('builddoc_generatebutton'); +$month = GETPOST("month","int"); +$year = GETPOST("year","int"); +$filter = GETPOST("filtre"); +if (GETPOST('button_search')) +{ + $filter=GETPOST('filtre',2); + if ($filter != 'payed:0') $option=''; +} +if ($option == 'late') $filter = 'paye:0'; +if ($option == 'unpaidall') $filter = 'paye:0'; +if ($mode == 'sendremind' && $filter == '') $filter = 'paye:0'; +if ($filter == '') $filter = 'paye:0'; // Security check if ($user->societe_id) $socid=$user->societe_id; @@ -54,6 +68,20 @@ if (! $user->rights->societe->client->voir || $socid) $diroutputpdf.='/private/' $resultmasssend=''; +if (GETPOST("button_removefilter_x") || GETPOST("button_removefilter")) // Both test must be present to be compatible with all browsers +{ + $search_ref=""; + $search_ref_supplier=""; + $search_label=""; + $search_company=""; + $search_amount_no_tax=""; + $search_amount_all_tax=""; + $year=""; + $month=""; + $filter=""; +} + + /* * Action @@ -297,8 +325,14 @@ if ($action == "builddoc" && $user->rights->facture->lire && ! GETPOST('button_s dol_mkdir($diroutputpdf); // Save merged file - $filename=strtolower(dol_sanitizeFileName($langs->transnoentities("Unpaid"))); - if ($option=='late') $filename.='_'.strtolower(dol_sanitizeFileName($langs->transnoentities("Late"))); + $filename=strtolower(dol_sanitizeFileName($langs->transnoentities("Invoices"))); + if ($filter=='paye:0') + { + if ($option=='late') $filename.='_'.strtolower(dol_sanitizeFileName($langs->transnoentities("Unpaid"))).'_'.strtolower(dol_sanitizeFileName($langs->transnoentities("Late"))); + else $filename.='_'.strtolower(dol_sanitizeFileName($langs->transnoentities("Unpaid"))); + } + if ($year) $filename.='_'.$year; + if ($month) $filename.='_'.$month; if ($pagecount) { $now=dol_now(); @@ -306,6 +340,9 @@ if ($action == "builddoc" && $user->rights->facture->lire && ! GETPOST('button_s $pdf->Output($file,'F'); if (! empty($conf->global->MAIN_UMASK)) @chmod($file, octdec($conf->global->MAIN_UMASK)); + + $langs->load("exports"); + setEventMessage($langs->trans('FileSuccessfullyBuilt',$filename.'_'.dol_print_date($now,'dayhourlog'))); } else { @@ -340,9 +377,9 @@ if ($action == 'remove_file') $form = new Form($db); $formfile = new FormFile($db); +$formother = new FormOther($db); -$title=$langs->trans("BillsCustomersUnpaid"); -if ($option=='late') $title=$langs->trans("BillsCustomersUnpaid"); +$title=$langs->trans("MergingPDFTool"); llxHeader('',$title); @@ -410,14 +447,15 @@ $sql.= ",".MAIN_DB_PREFIX."facture as f"; $sql.= " LEFT JOIN ".MAIN_DB_PREFIX."paiement_facture as pf ON f.rowid=pf.fk_facture "; $sql.= " WHERE f.fk_soc = s.rowid"; $sql.= " AND f.entity = ".$conf->entity; -$sql.= " AND f.type IN (0,1,3,5) AND f.fk_statut = 1"; -$sql.= " AND f.paye = 0"; +$sql.= " AND f.type IN (0,1,3,5)"; +if ($filter == 'paye:0') $sql.= " AND f.fk_statut = 1"; +//$sql.= " AND f.paye = 0"; if ($option == 'late') $sql.=" AND f.date_lim_reglement < '".$db->idate(dol_now() - $conf->facture->client->warning_delay)."'"; if (! $user->rights->societe->client->voir && ! $socid) $sql .= " AND s.rowid = sc.fk_soc AND sc.fk_user = " .$user->id; if (! empty($socid)) $sql .= " AND s.rowid = ".$socid; -if (GETPOST('filtre')) +if ($filter && $filter != -1) // GETPOST('filtre') may be a string { - $filtrearr = explode(",", GETPOST('filtre')); + $filtrearr = explode(",", $filter); foreach ($filtrearr as $fil) { $filt = explode(":", $fil); @@ -427,10 +465,21 @@ if (GETPOST('filtre')) if ($search_ref) $sql .= " AND f.facnumber LIKE '%".$db->escape($search_ref)."%'"; if ($search_refcustomer) $sql .= " AND f.ref_client LIKE '%".$db->escape($search_refcustomer)."%'"; if ($search_societe) $sql .= " AND s.nom LIKE '%".$db->escape($search_societe)."%'"; -if ($search_paymentmode) $sql .= " AND f.fk_mode_reglement = ".$search_paymentmode.""; +if ($search_paymentmode) $sql .= " AND f.fk_mode_reglement = ".$search_paymentmode.""; if ($search_montant_ht) $sql .= " AND f.total = '".$db->escape($search_montant_ht)."'"; if ($search_montant_ttc) $sql .= " AND f.total_ttc = '".$db->escape($search_montant_ttc)."'"; if (GETPOST('sf_ref')) $sql .= " AND f.facnumber LIKE '%".$db->escape(GETPOST('sf_ref'))."%'"; +if ($month > 0) +{ + if ($year > 0) + $sql.= " AND f.datef BETWEEN '".$db->idate(dol_get_first_day($year,$month,false))."' AND '".$db->idate(dol_get_last_day($year,$month,false))."'"; + else + $sql.= " AND date_format(f.datef, '%m') = '$month'"; +} +else if ($year > 0) +{ + $sql.= " AND f.datef BETWEEN '".$db->idate(dol_get_first_day($year,1,false))."' AND '".$db->idate(dol_get_last_day($year,12,false))."'"; +} $sql.= " GROUP BY s.nom, s.rowid, s.email, f.rowid, f.facnumber, f.ref_client, f.increment, f.total, f.tva, f.total_ttc, f.localtax1, f.localtax2, f.revenuestamp,"; $sql.= " f.datef, f.date_lim_reglement, f.paye, f.fk_statut, f.type, fk_mode_reglement"; if (! $user->rights->societe->client->voir && ! $socid) $sql .= ", sc.fk_soc, sc.fk_user "; @@ -438,7 +487,7 @@ $sql.= " ORDER BY "; $listfield=explode(',',$sortfield); foreach ($listfield as $key => $value) $sql.=$listfield[$key]." ".$sortorder.","; $sql.= " f.facnumber DESC"; - +//print $sql; //$sql .= $db->plimit($limit+1,$offset); $resql = $db->query($sql); @@ -454,30 +503,36 @@ if ($resql) $param=""; $param.=(! empty($socid)?"&socid=".$socid:""); - $param.=(! empty($option)?"&option=".$option:""); if ($search_ref) $param.='&search_ref='.urlencode($search_ref); - if ($search_refcustomer) $param.='&search_ref='.urlencode($search_refcustomer); + if ($search_refcustomer) $param.='&search_ref='.urlencode($search_refcustomer); if ($search_societe) $param.='&search_societe='.urlencode($search_societe); if ($search_societe) $param.='&search_paymentmode='.urlencode($search_paymentmode); if ($search_montant_ht) $param.='&search_montant_ht='.urlencode($search_montant_ht); if ($search_montant_ttc) $param.='&search_montant_ttc='.urlencode($search_montant_ttc); if ($late) $param.='&late='.urlencode($late); - + if ($mode) $param.='&mode='.urlencode($mode); $urlsource=$_SERVER['PHP_SELF'].'?sortfield='.$sortfield.'&sortorder='.$sortorder; $urlsource.=str_replace('&','&',$param); - $titre=(! empty($socid)?$langs->trans("BillsCustomersUnpaidForCompany",$soc->name):$langs->trans("BillsCustomersUnpaid")); + //$titre=(! empty($socid)?$langs->trans("BillsCustomersUnpaidForCompany",$soc->name):$langs->trans("BillsCustomersUnpaid")); + $titre=(! empty($socid)?$langs->trans("BillsCustomersForCompany",$soc->name):$langs->trans("BillsCustomers")); if ($option == 'late') $titre.=' ('.$langs->trans("Late").')'; - else $titre.=' ('.$langs->trans("All").')'; + //else $titre.=' ('.$langs->trans("All").')'; $link=''; - if (empty($option)) $link=''.$langs->trans("ShowUnpaidLateOnly").''; - elseif ($option == 'late') $link=''.$langs->trans("ShowUnpaidAll").''; + if (empty($option) || $option == 'late') $link.=($link?' - ':'').''.$langs->trans("ShowUnpaidAll").''; + if (empty($option) || $option == 'unpaidall') $link.=($link?' - ':'').''.$langs->trans("ShowUnpaidLateOnly").''; + + $param.=(! empty($option)?"&option=".$option:""); + print_fiche_titre($titre,$link); //print_barre_liste($titre,$page,$_SERVER["PHP_SELF"],$param,$sortfield,$sortorder,'',0); // We don't want pagination on this page print ''; + if (GETPOST('modelselected')) { + $action = 'presend'; + } if (! empty($mode) && $action == 'presend') { include_once DOL_DOCUMENT_ROOT.'/core/class/html.formmail.class.php'; @@ -520,6 +575,7 @@ if ($resql) // Tableau des parametres complementaires du post $formmail->param['action']=$action; $formmail->param['models']=$modelmail; + $formmail->param['models_id']=GETPOST('modelmailselected','int'); $formmail->param['facid']=$object->id; $formmail->param['returnurl']=$_SERVER["PHP_SELF"].'?id='.$object->id; @@ -574,7 +630,11 @@ if ($resql) print ''; print ''; print ''; - print ' '; + print ''; + print ''; + $syear = $year; + $formother->select_year($syear?$syear:-1,'year',1, 20, 5); + print ''; print ' '; print ''; print ''; @@ -586,21 +646,22 @@ if ($resql) print ' '; print ' '; print ''; + $liststatus=array('paye:0'=>$langs->trans("Unpaid"), 'paye:1'=>$langs->trans("Paid")); + print $form->selectarray('filtre', $liststatus, $filter, 1); + print ''; + print ''; print ''; print ''; - print ''; + print '
'; if (empty($mode)) { - print ''; if ($conf->use_javascript_ajax) print ''.$langs->trans("All").' / '.$langs->trans("None").''; - print ''; } else { - print ''; if ($conf->use_javascript_ajax) print ''.$langs->trans("All").' / '.$langs->trans("None").''; - print ''; } + print ''; print "\n"; if ($num > 0) diff --git a/htdocs/compta/index.php b/htdocs/compta/index.php index 698676829d1..d0d2bbb2f8f 100644 --- a/htdocs/compta/index.php +++ b/htdocs/compta/index.php @@ -2,6 +2,7 @@ /* Copyright (C) 2001-2005 Rodolphe Quiedeville * Copyright (C) 2004-2013 Laurent Destailleur * Copyright (C) 2005-2012 Regis Houssin + * Copyright (C) 2015 Juanjo Menent * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -321,7 +322,7 @@ if (! empty($conf->facture->enabled) && $user->rights->facture->lire) $sql.= " AND f.entity = ".$conf->entity; if (!$user->rights->societe->client->voir && !$socid) $sql.= " AND s.rowid = sc.fk_soc AND sc.fk_user = " .$user->id; if ($socid) $sql.= " AND f.fk_soc = ".$socid; - $sql.= " GROUP BY f.rowid, f.facnumber, f.fk_statut, f.type, f.total, f.total_ttc, f.paye, f.tms, f.date_lim_reglement, s.nom, s.rowid"; + $sql.= " GROUP BY f.rowid, f.facnumber, f.fk_statut, f.type, f.total, f.tva, f.total_ttc, f.paye, f.tms, f.date_lim_reglement, s.nom, s.rowid, s.code_client"; $sql.= " ORDER BY f.tms DESC "; $sql.= $db->plimit($max, 0); @@ -426,7 +427,7 @@ if (! empty($conf->fournisseur->enabled) && $user->rights->fournisseur->facture- $sql.= " AND ff.entity = ".$conf->entity; if (!$user->rights->societe->client->voir && !$socid) $sql.= " AND s.rowid = sc.fk_soc AND sc.fk_user = ".$user->id; if ($socid) $sql.= " AND ff.fk_soc = ".$socid; - $sql.= " GROUP BY ff.rowid, ff.ref, ff.fk_statut, ff.libelle, ff.total_ht, ff.tva, ff.total_ttc, ff.tms, ff.paye, s.nom, s.rowid"; + $sql.= " GROUP BY ff.rowid, ff.ref, ff.fk_statut, ff.libelle, ff.total_ht, ff.tva, ff.total_tva, ff.total_ttc, ff.tms, ff.paye, s.nom, s.rowid, s.code_fournisseur"; $sql.= " ORDER BY ff.tms DESC "; $sql.= $db->plimit($max, 0); @@ -658,7 +659,7 @@ if (! empty($conf->facture->enabled) && ! empty($conf->commande->enabled) && $us if ($socid) $sql.= " AND c.fk_soc = ".$socid; $sql.= " AND c.fk_statut = 3"; $sql.= " AND c.facture = 0"; - $sql.= " GROUP BY s.nom, s.rowid, c.rowid, c.ref, c.facture, c.fk_statut, c.total_ht, c.total_ttc"; + $sql.= " GROUP BY s.nom, s.rowid, s.code_client, c.rowid, c.ref, c.facture, c.fk_statut, c.tva, c.total_ht, c.total_ttc"; $resql = $db->query($sql); if ( $resql ) @@ -762,7 +763,7 @@ if (! empty($conf->facture->enabled) && $user->rights->facture->lire) $sql.= " AND f.entity = ".$conf->entity; if (!$user->rights->societe->client->voir && !$socid) $sql.= " AND s.rowid = sc.fk_soc AND sc.fk_user = " .$user->id; if ($socid) $sql.= " AND f.fk_soc = ".$socid; - $sql.= " GROUP BY f.rowid, f.facnumber, f.fk_statut, f.datef, f.type, f.total, f.total_ttc, f.paye, f.tms, f.date_lim_reglement, s.nom, s.rowid"; + $sql.= " GROUP BY f.rowid, f.facnumber, f.fk_statut, f.datef, f.type, f.total, f.tva, f.total_ttc, f.paye, f.tms, f.date_lim_reglement, s.nom, s.rowid, s.code_client"; $sql.= " ORDER BY f.datef ASC, f.facnumber ASC"; $resql = $db->query($sql); @@ -876,8 +877,8 @@ if (! empty($conf->fournisseur->enabled) && $user->rights->fournisseur->facture- $sql.= " AND ff.fk_statut = 1"; if (!$user->rights->societe->client->voir && !$socid) $sql.= " AND s.rowid = sc.fk_soc AND sc.fk_user = ".$user->id; if ($socid) $sql.= " AND ff.fk_soc = ".$socid; - $sql.= " GROUP BY ff.rowid, ff.ref, ff.fk_statut, ff.libelle, ff.total_ht, ff.tva, ff.total_ttc, ff.paye,"; - $sql.= " s.nom, s.rowid"; + $sql.= " GROUP BY ff.rowid, ff.ref, ff.fk_statut, ff.libelle, ff.total_ht, ff.tva, ff.total_tva, ff.total_ttc, ff.paye,"; + $sql.= " s.nom, s.rowid, s.code_client, s.code_fournisseur"; $resql=$db->query($sql); if ($resql) diff --git a/htdocs/compta/localtax/class/localtax.class.php b/htdocs/compta/localtax/class/localtax.class.php index 994e3cca40c..04461117271 100644 --- a/htdocs/compta/localtax/class/localtax.class.php +++ b/htdocs/compta/localtax/class/localtax.class.php @@ -109,13 +109,21 @@ class Localtax extends CommonObject if ($result < 0) $error++; // End call triggers - //FIXME: Add rollback if trigger fail - - return $this->id; + if (! $error) + { + $this->db->commit(); + return $this->id; + } + else + { + $this->db->rollback(); + return -1; + } } else - { + { $this->error="Error ".$this->db->lasterror(); + $this->db->rollback(); return -1; } } @@ -141,7 +149,9 @@ class Localtax extends CommonObject $this->fk_user_creat=trim($this->fk_user_creat); $this->fk_user_modif=trim($this->fk_user_modif); - // Update request + $this->db->begin(); + + // Update request $sql = "UPDATE ".MAIN_DB_PREFIX."localtax SET"; $sql.= " localtaxtype=".$this->ltt.","; $sql.= " tms=".$this->db->idate($this->tms).","; @@ -160,20 +170,27 @@ class Localtax extends CommonObject if (! $resql) { $this->error="Error ".$this->db->lasterror(); - return -1; + $error++; } - if (! $notrigger) + if (! $error && ! $notrigger) { // Call trigger $result=$this->call_trigger('LOCALTAX_MODIFY',$user); if ($result < 0) $error++; // End call triggers - - //FIXME: Add rollback if trigger fail } - return 1; + if (! $error) + { + $this->db->commit(); + return 1; + } + else + { + $this->db->rollback(); + return -1; + } } diff --git a/htdocs/compta/paiement/class/paiement.class.php b/htdocs/compta/paiement/class/paiement.class.php index 883110e9d5b..077bbde2420 100644 --- a/htdocs/compta/paiement/class/paiement.class.php +++ b/htdocs/compta/paiement/class/paiement.class.php @@ -70,9 +70,10 @@ class Paiement extends CommonObject * Load payment from database * * @param int $id Id of payment to get + * @param int $ref Ref of payment to get (same as $id) * @return int <0 if KO, 0 if not found, >0 if OK */ - function fetch($id) + function fetch($id, $ref='') { $sql = 'SELECT p.rowid, p.datep as dp, p.amount, p.statut, p.fk_bank,'; $sql.= ' c.code as type_code, c.libelle as type_libelle,'; @@ -81,7 +82,10 @@ class Paiement extends CommonObject $sql.= ' FROM '.MAIN_DB_PREFIX.'c_paiement as c, '.MAIN_DB_PREFIX.'paiement as p'; $sql.= ' LEFT JOIN '.MAIN_DB_PREFIX.'bank as b ON p.fk_bank = b.rowid '; $sql.= ' WHERE p.fk_paiement = c.id'; - $sql.= ' AND p.rowid = '.$id; + if ($ref) + $sql.= ' AND p.rowid = '.$ref; + else + $sql.= ' AND p.rowid = '.$id; dol_syslog(get_class($this)."::fetch", LOG_DEBUG); $result = $this->db->query($sql); diff --git a/htdocs/compta/prelevement/class/ligneprelevement.class.php b/htdocs/compta/prelevement/class/ligneprelevement.class.php index 2b71c5c8004..0cc1b3d2f94 100644 --- a/htdocs/compta/prelevement/class/ligneprelevement.class.php +++ b/htdocs/compta/prelevement/class/ligneprelevement.class.php @@ -2,6 +2,7 @@ /* Copyright (C) 2005 Rodolphe Quiedeville * Copyright (C) 2005-2009 Regis Houssin * Copyright (C) 2010-2011 Juanjo Menent + * Copyright (C) 2015 Marcos García * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -61,7 +62,7 @@ class LignePrelevement * Recupere l'objet prelevement * * @param int $rowid id de la facture a recuperer - * @return void|int + * @return integer */ function fetch($rowid) { @@ -156,5 +157,22 @@ class LignePrelevement if ($statut==3) return $langs->trans($this->statuts[$statut]).' '.img_picto($langs->trans($this->statuts[$statut]),'statut8'); } } + + /** + * Function used to replace a thirdparty id with another one. + * + * @param DoliDB $db Database handler + * @param int $origin_id Old thirdparty id + * @param int $dest_id New thirdparty id + * @return bool + */ + public static function replaceThirdparty(DoliDB $db, $origin_id, $dest_id) + { + $tables = array( + 'prelevement_lignes' + ); + + return CommonObject::commonReplaceThirdparty($db, $origin_id, $dest_id, $tables); + } } diff --git a/htdocs/compta/salaries/class/paymentsalary.class.php b/htdocs/compta/salaries/class/paymentsalary.class.php index 0db00c10c7f..f7da679196b 100644 --- a/htdocs/compta/salaries/class/paymentsalary.class.php +++ b/htdocs/compta/salaries/class/paymentsalary.class.php @@ -95,6 +95,8 @@ class PaymentSalary extends CommonObject return -1; } + $this->db->begin(); + // Update request $sql = "UPDATE ".MAIN_DB_PREFIX."payment_salary SET"; @@ -129,11 +131,18 @@ class PaymentSalary extends CommonObject $result=$this->call_trigger('PAYMENT_SALARY_MODIFY',$user); if ($result < 0) $error++; // End call triggers - - //FIXME: Add rollback if trigger fail } - return 1; + if (! $error) + { + $this->db->commit(); + return 1; + } + else + { + $this->db->rollback(); + return -1; + } } diff --git a/htdocs/compta/salaries/index.php b/htdocs/compta/salaries/index.php index 484010c9f03..81788f2d9de 100644 --- a/htdocs/compta/salaries/index.php +++ b/htdocs/compta/salaries/index.php @@ -83,7 +83,7 @@ $form = new Form($db); $salstatic = new PaymentSalary($db); $userstatic = new User($db); -$sql = "SELECT u.rowid as uid, u.lastname, u.firstname, u.login, u.email, u.admin, u.salary as current_salary, u.fk_societe as fk_soc,"; +$sql = "SELECT u.rowid as uid, u.lastname, u.firstname, u.login, u.email, u.admin, u.salary as current_salary, u.fk_soc as fk_soc,"; $sql.= " s.rowid, s.fk_user, s.amount, s.salary, s.label, s.datev as dm, s.fk_typepayment as type, s.num_payment,"; $sql.= " pst.code as payment_code"; $sql.= " FROM ".MAIN_DB_PREFIX."payment_salary as s"; diff --git a/htdocs/compta/sociales/document.php b/htdocs/compta/sociales/document.php index ad5af8f84c2..f87791dfed9 100644 --- a/htdocs/compta/sociales/document.php +++ b/htdocs/compta/sociales/document.php @@ -88,8 +88,8 @@ llxHeader("",$langs->trans("SocialContribution"),$help_url); if ($object->id) { $alreadypayed=$object->getSommePaiement(); - - $head=tax_prepare_head($object, $user); + + $head=tax_prepare_head($object); dol_fiche_head($head, 'documents', $langs->trans("SocialContribution"), 0, 'bill'); diff --git a/htdocs/compta/stats/casoc.php b/htdocs/compta/stats/casoc.php index a4c4663dc40..0f352defc5e 100644 --- a/htdocs/compta/stats/casoc.php +++ b/htdocs/compta/stats/casoc.php @@ -183,7 +183,7 @@ if ($modecompta == 'CREANCES-DETTES') { $sql.= " FROM ".MAIN_DB_PREFIX."facture as f, ".MAIN_DB_PREFIX."societe as s"; if ($selected_cat === -2) // Without any category { - $sql.= " LEFT OUTER JOIN ".MAIN_DB_PREFIX."categorie_societe as cs ON s.rowid = cs.fk_societe"; + $sql.= " LEFT OUTER JOIN ".MAIN_DB_PREFIX."categorie_societe as cs ON s.rowid = cs.fk_soc"; } else if ($selected_cat) // Into a specific category { @@ -201,13 +201,13 @@ if ($modecompta == 'CREANCES-DETTES') { } if ($selected_cat === -2) // Without any category { - $sql.=" AND cs.fk_societe is null"; + $sql.=" AND cs.fk_soc is null"; } else if ($selected_cat) { // Into a specific category $sql.= " AND (c.rowid = ".$selected_cat; if ($subcat) $sql.=" OR c.fk_parent = " . $selected_cat; $sql.= ")"; - $sql.= " AND cs.fk_categorie = c.rowid AND cs.fk_societe = s.rowid"; + $sql.= " AND cs.fk_categorie = c.rowid AND cs.fk_soc = s.rowid"; } } else { /* @@ -221,7 +221,7 @@ if ($modecompta == 'CREANCES-DETTES') { $sql.= ", ".MAIN_DB_PREFIX."societe as s"; if ($selected_cat === -2) // Without any category { - $sql.= " LEFT OUTER JOIN ".MAIN_DB_PREFIX."categorie_societe as cs ON s.rowid = cs.fk_societe"; + $sql.= " LEFT OUTER JOIN ".MAIN_DB_PREFIX."categorie_societe as cs ON s.rowid = cs.fk_soc"; } else if ($selected_cat) // Into a specific category { @@ -235,13 +235,13 @@ if ($modecompta == 'CREANCES-DETTES') { } if ($selected_cat === -2) // Without any category { - $sql.=" AND cs.fk_societe is null"; + $sql.=" AND cs.fk_soc is null"; } else if ($selected_cat) { // Into a specific category $sql.= " AND (c.rowid = ".$selected_cat; if ($subcat) $sql.=" OR c.fk_parent = " . $selected_cat; $sql.= ")"; - $sql.= " AND cs.fk_categorie = c.rowid AND cs.fk_societe = s.rowid"; + $sql.= " AND cs.fk_categorie = c.rowid AND cs.fk_soc = s.rowid"; } } $sql.= " AND f.entity = ".$conf->entity; diff --git a/htdocs/compta/stats/index.php b/htdocs/compta/stats/index.php index f704ca90f73..a44cb4ed48e 100644 --- a/htdocs/compta/stats/index.php +++ b/htdocs/compta/stats/index.php @@ -298,7 +298,7 @@ for ($mois = 1+$nb_mois_decalage ; $mois <= 12+$nb_mois_decalage ; $mois++) if ($annee_decalage != $year_end) print ' '; } - $total_ht[$annee]+=!empty($cum_ht[$case]) ? $cum_ht[$case] : 0;; + $total_ht[$annee]+=!empty($cum_ht[$case]) ? $cum_ht[$case] : 0; $total[$annee]+=$cum[$case]; } diff --git a/htdocs/compta/tva/class/tva.class.php b/htdocs/compta/tva/class/tva.class.php index 948b5096fa3..fa8a71a24e4 100644 --- a/htdocs/compta/tva/class/tva.class.php +++ b/htdocs/compta/tva/class/tva.class.php @@ -89,7 +89,9 @@ class Tva extends CommonObject // Check parameters // Put here code to add control on parameters values - // Insert request + $this->db->begin(); + + // Insert request $sql = "INSERT INTO ".MAIN_DB_PREFIX."tva("; $sql.= "tms,"; $sql.= "datep,"; @@ -126,13 +128,22 @@ class Tva extends CommonObject if ($result < 0) $error++; // End call triggers - //FIXME: Add rollback if trigger fail - return $this->id; + if (! $error) + { + $this->db->commit(); + return $this->id; + } + else + { + $this->db->rollback(); + return -1; + } } else - { - $this->error="Error ".$this->db->lasterror(); - return -1; + { + $this->error="Error ".$this->db->lasterror(); + $this->db->rollback(); + return -1; } } @@ -160,7 +171,9 @@ class Tva extends CommonObject // Check parameters // Put here code to add control on parameters values - // Update request + $this->db->begin(); + + // Update request $sql = "UPDATE ".MAIN_DB_PREFIX."tva SET"; $sql.= " tms=".$this->db->idate($this->tms).","; @@ -181,20 +194,27 @@ class Tva extends CommonObject if (! $resql) { $this->error="Error ".$this->db->lasterror(); - return -1; + $error++; } - if (! $notrigger) + if (! $error && ! $notrigger) { // Call trigger $result=$this->call_trigger('TVA_MODIFY',$user); if ($result < 0) $error++; // End call triggers - - //FIXME: Add rollback if trigger fail } - return 1; + if (! $error) + { + $this->db->commit(); + return 1; + } + else + { + $this->db->rollback(); + return -1; + } } diff --git a/htdocs/contact/card.php b/htdocs/contact/card.php index f8ebe12cd9b..5936e596fb7 100644 --- a/htdocs/contact/card.php +++ b/htdocs/contact/card.php @@ -255,7 +255,7 @@ if (empty($reshook)) } else { - setEventMessage($object->error,$object->errors,'errors'); + setEventMessages($object->error,$object->errors,'errors'); } } diff --git a/htdocs/contact/class/contact.class.php b/htdocs/contact/class/contact.class.php index 19ea13f6a39..a61b0ea37bf 100644 --- a/htdocs/contact/class/contact.class.php +++ b/htdocs/contact/class/contact.class.php @@ -8,6 +8,7 @@ * Copyright (C) 2013 Florian Henry * Copyright (C) 2013 Alexandre Spangaro * Copyright (C) 2013 Juanjo Menent + * Copyright (C) 2015 Marcos García * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -1084,4 +1085,20 @@ class Contact extends CommonObject } } -} + /** + * Function used to replace a thirdparty id with another one. + * + * @param DoliDB $db Database handler + * @param int $origin_id Old thirdparty id + * @param int $dest_id New thirdparty id + * @return bool + */ + public static function replaceThirdparty(DoliDB $db, $origin_id, $dest_id) + { + $tables = array( + 'socpeople' + ); + + return CommonObject::commonReplaceThirdparty($db, $origin_id, $dest_id, $tables); + } +} \ No newline at end of file diff --git a/htdocs/contact/document.php b/htdocs/contact/document.php index 970f3543c45..2241a1e67f1 100644 --- a/htdocs/contact/document.php +++ b/htdocs/contact/document.php @@ -79,7 +79,7 @@ llxHeader("",$langs->trans("Contact"), $helpurl); if ($object->id) { - $head = contact_prepare_head($object, $user); + $head = contact_prepare_head($object); dol_fiche_head($head, 'documents', $langs->trans("Contact"), 0, 'contact'); diff --git a/htdocs/contrat/card.php b/htdocs/contrat/card.php index 0d44703782c..a3c3e6c2c6e 100644 --- a/htdocs/contrat/card.php +++ b/htdocs/contrat/card.php @@ -973,6 +973,8 @@ if ($action == 'create') print ''."\n"; print ''; + dol_fiche_head(); + print ''; // Ref @@ -1068,7 +1070,9 @@ if ($action == 'create') print "
\n"; - print '
'; + dol_fiche_end(); + + print '
'; if (is_object($objectsrc)) { @@ -1080,10 +1084,8 @@ if ($action == 'create') print '
'.$langs->trans("Note").': '.$langs->trans("OnlyLinesWithTypeServiceAreUsed"); } } - + print "\n"; - - dol_fiche_end(); } else /* *************************************************************************** */ @@ -1285,7 +1287,9 @@ else $usemargins=0; if (! empty($conf->margin->enabled) && ! empty($object->element) && in_array($object->element,array('facture','propal','commande'))) $usemargins=1; - // Title line for service + $var=false; + + // Title line for service $cursorline=1; while ($cursorline <= $nbofservices) { @@ -1326,8 +1330,6 @@ else print ' '; print "\n"; - $var=true; - $objp = $db->fetch_object($result); $var=!$var; @@ -1355,12 +1357,12 @@ else } else { - print "".dol_htmlentitiesbr($objp->description)."\n"; + print ''.dol_htmlentitiesbr($objp->description)."\n"; } // TVA print ''.vatrate($objp->tva_tx,'%',$objp->info_bits).''; // Prix - print ''.price($objp->subprice)."\n"; + print ''.($objp->subprice != '' ? price($objp->subprice) : '')."\n"; // Quantite print ''.$objp->qty.''; //Unit @@ -1368,7 +1370,7 @@ else // Remise if ($objp->remise_percent > 0) { - print ''.$objp->remise_percent."%\n"; + print ''.$objp->remise_percent."%\n"; } else { @@ -1515,7 +1517,7 @@ else print ''; print $langs->trans("DateStartPlanned").' '; $form->select_date($db->jdate($objp->date_debut),"date_start_update",$usehm,$usehm,($db->jdate($objp->date_debut)>0?0:1),"update"); - print '
'.$langs->trans("DateEndPlanned").' '; + print '   '.$langs->trans("DateEndPlanned").' '; $form->select_date($db->jdate($objp->date_fin),"date_end_update",$usehm,$usehm,($db->jdate($objp->date_fin)>0?0:1),"update"); print ''; @@ -1539,7 +1541,7 @@ else if ($object->statut > 0) { - print ''; + print ''; print '
'; print "\n"; } @@ -1555,7 +1557,7 @@ else if ($action == 'deleteline' && ! $_REQUEST["cancel"] && $user->rights->contrat->creer && $object->lines[$cursorline-1]->id == GETPOST('rowid')) { print $form->formconfirm($_SERVER["PHP_SELF"]."?id=".$object->id."&lineid=".GETPOST('rowid'),$langs->trans("DeleteContractLine"),$langs->trans("ConfirmDeleteContractLine"),"confirm_deleteline",'',0,1); - if ($ret == 'html') print '
'; + if ($ret == 'html') print '
'; } /* @@ -1575,7 +1577,7 @@ else array('type' => 'select', 'name' => 'newcid', 'values' => $arraycontractid)); $form->form_confirm($_SERVER["PHP_SELF"]."?id=".$object->id."&lineid=".GETPOST('rowid'),$langs->trans("MoveToAnotherContract"),$langs->trans("ConfirmMoveToAnotherContract"),"confirm_move",$formquestion); - print '
'; + print '
'; } /* @@ -1587,7 +1589,7 @@ else $dateactend = dol_mktime(12, 0, 0, GETPOST('endmonth'), GETPOST('endday'), GETPOST('endyear')); $comment = GETPOST('comment'); $form->form_confirm($_SERVER["PHP_SELF"]."?id=".$object->id."&ligne=".GETPOST('ligne')."&date=".$dateactstart."&dateend=".$dateactend."&comment=".urlencode($comment),$langs->trans("ActivateService"),$langs->trans("ConfirmActivateService",dol_print_date($dateactstart,"%A %d %B %Y")),"confirm_active", '', 0, 1); - print '
'; + print '
'; } /* @@ -1599,7 +1601,7 @@ else $dateactend = dol_mktime(12, 0, 0, GETPOST('endmonth'), GETPOST('endday'), GETPOST('endyear')); $comment = GETPOST('comment'); $form->form_confirm($_SERVER["PHP_SELF"]."?id=".$object->id."&ligne=".GETPOST('ligne')."&date=".$dateactstart."&dateend=".$dateactend."&comment=".urlencode($comment), $langs->trans("CloseService"), $langs->trans("ConfirmCloseService",dol_print_date($dateactend,"%A %d %B %Y")), "confirm_closeline", '', 0, 1); - print '
'; + print '
'; } @@ -1608,7 +1610,7 @@ else { print ''; - print ''; + print ''; print ''; print ''; print "\n"; - print ''; + print ''; print ''; + // Status + $alreadypaid=$object->getSommePaiement(); + print ''; + + // Amount + print ''; + print ''; + + // Amount Local Taxes + //TODO: Place into a function to control showing by country or study better option + if ($societe->localtax1_assuj=="1") //Localtax1 + { + print ''; + print ''; + print ''; + } + if ($societe->localtax2_assuj=="1") //Localtax2 + { + print ''; + print ''; + print ''; + } + print ''; + print '
'.$langs->trans("ServiceStatus").': '.$object->lines[$cursorline-1]->getLibStatut(4).''; if ($user->societe_id == 0) @@ -1625,7 +1627,7 @@ else print '
'; // Si pas encore active @@ -1664,7 +1666,7 @@ else print '
'; print ''; - print ''; + print '
'; // Definie date debut et fin par defaut $dateactstart = $objp->date_debut; @@ -1714,7 +1716,7 @@ else print ''; - print '
'; + print '
'; // Definie date debut et fin par defaut $dateactstart = $objp->date_debut_reelle; diff --git a/htdocs/contrat/class/contrat.class.php b/htdocs/contrat/class/contrat.class.php index aa96db049fd..ac01abe6cd1 100644 --- a/htdocs/contrat/class/contrat.class.php +++ b/htdocs/contrat/class/contrat.class.php @@ -1136,7 +1136,7 @@ class Contrat extends CommonObject if (isset($this->ref_supplier)) $this->ref_supplier=trim($this->ref_supplier); if (isset($this->ref_ext)) $this->ref_ext=trim($this->ref_ext); if (isset($this->entity)) $this->entity=trim($this->entity); - if (isset($this->statut)) $this->statut=trim($this->statut); + if (isset($this->statut)) $this->statut=(int) $this->statut; if (isset($this->fk_soc)) $this->fk_soc=trim($this->fk_soc); if (isset($this->fk_projet)) $this->fk_projet=trim($this->fk_projet); if (isset($this->fk_commercial_signature)) $this->fk_commercial_signature=trim($this->fk_commercial_signature); @@ -2123,6 +2123,23 @@ class Contrat extends CommonObject return $this->commonGenerateDocument($modelpath, $modele, $outputlangs, $hidedetails, $hidedesc, $hideref); } + + /** + * Function used to replace a thirdparty id with another one. + * + * @param DoliDB $db Database handler + * @param int $origin_id Old thirdparty id + * @param int $dest_id New thirdparty id + * @return bool + */ + public static function replaceThirdparty(DoliDB $db, $origin_id, $dest_id) + { + $tables = array( + 'contrat' + ); + + return CommonObject::commonReplaceThirdparty($db, $origin_id, $dest_id, $tables); + } } @@ -2430,7 +2447,7 @@ class ContratLigne extends CommonObjectLine // Clean parameters $this->fk_contrat=trim($this->fk_contrat); $this->fk_product=trim($this->fk_product); - $this->statut=trim($this->statut); + $this->statut=(int) $this->statut; $this->label=trim($this->label); $this->description=trim($this->description); $this->tva_tx=trim($this->tva_tx); @@ -2452,7 +2469,12 @@ class ContratLigne extends CommonObjectLine $this->fk_user_ouverture=trim($this->fk_user_ouverture); $this->fk_user_cloture=trim($this->fk_user_cloture); $this->commentaire=trim($this->commentaire); - + //if (empty($this->subprice)) $this->subprice = 0; + if (empty($this->price_ht)) $this->price_ht = 0; + if (empty($this->total_ht)) $this->total_ht = 0; + if (empty($this->total_tva)) $this->total_tva = 0; + if (empty($this->total_ttc)) $this->total_ttc = 0; + // Check parameters // Put here code to add control on parameters values @@ -2496,8 +2518,8 @@ class ContratLigne extends CommonObjectLine $sql.= " remise_percent='".$this->remise_percent."',"; $sql.= " remise=".($this->remise?"'".$this->remise."'":"null").","; $sql.= " fk_remise_except=".($this->fk_remise_except?"'".$this->fk_remise_except."'":"null").","; - $sql.= " subprice='".$this->subprice."',"; - $sql.= " price_ht='".$this->price_ht."',"; + $sql.= " subprice=".($this->subprice != '' ? $this->subprice : "null").","; + $sql.= " price_ht=".($this->price_ht != '' ? $this->price_ht : "null").","; $sql.= " total_ht='".$this->total_ht."',"; $sql.= " total_tva='".$this->total_tva."',"; $sql.= " total_localtax1='".$this->total_localtax1."',"; diff --git a/htdocs/core/actions_sendmails.inc.php b/htdocs/core/actions_sendmails.inc.php index 10712b971bc..fce813aaa05 100644 --- a/htdocs/core/actions_sendmails.inc.php +++ b/htdocs/core/actions_sendmails.inc.php @@ -63,7 +63,7 @@ if (! empty($_POST['removedfile'])) /* * Send mail */ -if (($action == 'send' || $action == 'relance') && ! $_POST['addfile'] && ! $_POST['removedfile'] && ! $_POST['cancel']) +if (($action == 'send' || $action == 'relance') && ! $_POST['addfile'] && ! $_POST['removedfile'] && ! $_POST['cancel'] && !$_POST['modelselected']) { $langs->load('mails'); diff --git a/htdocs/core/boxes/box_activity.php b/htdocs/core/boxes/box_activity.php index 7fdb3510afe..f7e09d33583 100644 --- a/htdocs/core/boxes/box_activity.php +++ b/htdocs/core/boxes/box_activity.php @@ -1,6 +1,6 @@ - * Copyright (C) 2005-2013 Laurent Destailleur + * Copyright (C) 2005-2015 Laurent Destailleur * Copyright (C) 2014-2015 Frederic France * * This program is free software; you can redistribute it and/or modify @@ -80,7 +80,7 @@ class box_activity extends ModeleBoxes $nbofyears=2; if (! empty($conf->global->MAIN_BOX_ACTIVITY_DURATION)) $nbofyears=$conf->global->MAIN_BOX_ACTIVITY_DURATION; - $textHead = $langs->trans("Activity").' '.$nbofyears.' '.$langs->trans("DurationYears").''; + $textHead = $langs->trans("Activity").' - '.$langs->trans("LastXMonthRolling", $nbofyears*12); $this->info_box_head = array( 'text' => $textHead, 'limit'=> dol_strlen($textHead), @@ -102,7 +102,8 @@ class box_activity extends ModeleBoxes $refresh = dol_cache_refresh($cachedir, $filename, $cachetime); $data = array(); - if ($refresh) { + if ($refresh) + { $sql = "SELECT f.fk_statut, SUM(f.total_ttc) as Mnttot, COUNT(*) as nb"; $sql.= " FROM (".MAIN_DB_PREFIX."societe as s,".MAIN_DB_PREFIX."facture as f"; if (!$user->rights->societe->client->voir && !$user->societe_id) $sql.= ", ".MAIN_DB_PREFIX."societe_commerciaux as sc"; diff --git a/htdocs/core/boxes/box_graph_product_distribution.php b/htdocs/core/boxes/box_graph_product_distribution.php index 74d106b7f69..eb2d3a183bf 100644 --- a/htdocs/core/boxes/box_graph_product_distribution.php +++ b/htdocs/core/boxes/box_graph_product_distribution.php @@ -1,5 +1,5 @@ +/* Copyright (C) 2013-2015 Laurent Destailleur * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -70,18 +70,6 @@ class box_graph_product_distribution extends ModeleBoxes include_once DOL_DOCUMENT_ROOT.'/comm/propal/class/propal.class.php'; include_once DOL_DOCUMENT_ROOT.'/commande/class/commande.class.php'; - $text = $langs->trans("BoxProductDistribution",$max); - $this->info_box_head = array( - 'text' => $text, - 'limit'=> dol_strlen($text), - 'graph'=> 1, - 'sublink'=>'', - 'subtext'=>$langs->trans("Filter"), - 'subpicto'=>'filter.png', - 'subclass'=>'linkobject', - 'target'=>'none' // Set '' to get target="_blank" - ); - $param_year='DOLUSERCOOKIE_box_'.$this->boxcode.'_year'; $param_showinvoicenb='DOLUSERCOOKIE_box_'.$this->boxcode.'_showinvoicenb'; $param_showpropalnb='DOLUSERCOOKIE_box_'.$this->boxcode.'_showpropalnb'; @@ -110,6 +98,20 @@ class box_graph_product_distribution extends ModeleBoxes $nowarray=dol_getdate(dol_now(),true); if (empty($year)) $year=$nowarray['year']; + + $text = $langs->trans("BoxProductDistribution",$max).' - '.$langs->trans("Year").': '.$year; + $this->info_box_head = array( + 'text' => $text, + 'limit'=> dol_strlen($text), + 'graph'=> 1, + 'sublink'=>'', + 'subtext'=>$langs->trans("Filter"), + 'subpicto'=>'filter.png', + 'subclass'=>'linkobject', + 'target'=>'none' // Set '' to get target="_blank" + ); + + $nbofgraph=0; if ($showinvoicenb) $nbofgraph++; if ($showpropalnb) $nbofgraph++; diff --git a/htdocs/core/boxes/box_produits_alerte_stock.php b/htdocs/core/boxes/box_produits_alerte_stock.php index 8096dfdec10..06442571b6e 100644 --- a/htdocs/core/boxes/box_produits_alerte_stock.php +++ b/htdocs/core/boxes/box_produits_alerte_stock.php @@ -4,6 +4,7 @@ * Copyright (C) 2005-2012 Regis Houssin * Copyright (C) 2005-2012 Maxime Kohlhaas * Copyright (C) 2015 Frederic France + * Copyright (C) 2015 Juanjo Menent * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -73,7 +74,7 @@ class box_produits_alerte_stock extends ModeleBoxes $sql.= " AND p.tosell = 1 AND p.seuil_stock_alerte > 0"; if (empty($user->rights->produit->lire)) $sql.=' AND p.fk_product_type != 0'; if (empty($user->rights->service->lire)) $sql.=' AND p.fk_product_type != 1'; - $sql.= " GROUP BY p.rowid, p.label, p.price, p.price_base_type, p.price_ttc, p.fk_product_type, p.tms, p.tosell, p.tobuy, p.seuil_stock_alerte"; + $sql.= " GROUP BY p.rowid, p.ref, p.label, p.price, p.price_base_type, p.price_ttc, p.fk_product_type, p.tms, p.tosell, p.tobuy, p.seuil_stock_alerte"; $sql.= " HAVING SUM(".$db->ifsql("s.reel IS NULL","0","s.reel").") < p.seuil_stock_alerte"; $sql.= $db->order('p.seuil_stock_alerte', 'DESC'); $sql.= $db->plimit($max, 0); diff --git a/htdocs/core/class/CMailFile.class.php b/htdocs/core/class/CMailFile.class.php index 61ea308df39..967b764dc65 100644 --- a/htdocs/core/class/CMailFile.class.php +++ b/htdocs/core/class/CMailFile.class.php @@ -514,8 +514,12 @@ class CMailFile return $res; } - - // Encode subject according to RFC 2822 - http://en.wikipedia.org/wiki/MIME#Encoded-Word + /** + * Encode subject according to RFC 2822 - http://en.wikipedia.org/wiki/MIME#Encoded-Word + * + * @param string $stringtoencode String to encode + * @return string string encoded + */ function encodetorfc2822($stringtoencode) { global $conf; @@ -639,7 +643,7 @@ class CMailFile /** * Create SMTP headers (mode = 'mail') * - * @return smtp headers + * @return string headers */ function write_smtpheaders() { @@ -690,7 +694,7 @@ class CMailFile * * @param array $filename_list Array of filenames * @param array $mimefilename_list Array of mime types - * @return array mime headers + * @return string mime headers */ function write_mimeheaders($filename_list, $mimefilename_list) { diff --git a/htdocs/core/class/commoninvoice.class.php b/htdocs/core/class/commoninvoice.class.php index 1a7ebfc34c8..42265846d04 100644 --- a/htdocs/core/class/commoninvoice.class.php +++ b/htdocs/core/class/commoninvoice.class.php @@ -60,6 +60,34 @@ abstract class CommonInvoice extends CommonObject */ const TYPE_SITUATION = 5; + /** + * Draft + */ + const STATUS_DRAFT = 0; + + /** + * Validated (need to be paid) + */ + const STATUS_VALIDATED = 1; + + /** + * Classified paid. + * If paid partially, $this->close_code can be: + * - CLOSECODE_DISCOUNTVAT + * - CLOSECODE_BADDEBT + * If paid completelly, this->close_code will be null + */ + const STATUS_CLOSED = 2; + + /** + * Classified abandoned and no payment done. + * $this->close_code can be: + * - CLOSECODE_BADDEBT + * - CLOSECODE_ABANDONED + * - CLOSECODE_REPLACED + */ + const STATUS_ABANDONED = 3; + /** * Return amount of payments already done * @@ -188,7 +216,7 @@ abstract class CommonInvoice extends CommonObject * Return label of object status * * @param int $mode 0=long label, 1=short label, 2=Picto + short label, 3=Picto, 4=Picto + long label, 5=short label + picto - * @param double $alreadypaid 0=No payment already done, >0=Some payments were already done (we recommand to put here amount payed if you have it, 1 otherwise) + * @param integer $alreadypaid 0=No payment already done, >0=Some payments were already done (we recommand to put here amount payed if you have it, 1 otherwise) * @return string Label */ function getLibStatut($mode=0,$alreadypaid=-1) @@ -202,7 +230,7 @@ abstract class CommonInvoice extends CommonObject * @param int $paye Status field paye * @param int $status Id status * @param int $mode 0=long label, 1=short label, 2=Picto + short label, 3=Picto, 4=Picto + long label, 5=short label + picto - * @param double $alreadypaid 0=No payment already done, >0=Some payments were already done (we recommand to put here amount payed if you have it, 1 otherwise) + * @param integer $alreadypaid 0=No payment already done, >0=Some payments were already done (we recommand to put here amount payed if you have it, 1 otherwise) * @param int $type Type facture * @return string Libelle du statut */ @@ -326,7 +354,7 @@ abstract class CommonInvoice extends CommonObject * Renvoi une date limite de reglement de facture en fonction des * conditions de reglements de la facture et date de facturation * - * @param string $cond_reglement Condition of payment (code or id) to use. If 0, we use current condition. + * @param integer $cond_reglement Condition of payment (code or id) to use. If 0, we use current condition. * @return date Date limite de reglement si ok, <0 si ko */ function calculate_date_lim_reglement($cond_reglement=0) diff --git a/htdocs/core/class/commonobject.class.php b/htdocs/core/class/commonobject.class.php index 029d7a28a8e..0139d080e25 100644 --- a/htdocs/core/class/commonobject.class.php +++ b/htdocs/core/class/commonobject.class.php @@ -6,7 +6,7 @@ * Copyright (C) 2010-2014 Juanjo Menent * Copyright (C) 2012-2013 Christophe Battarel * Copyright (C) 2011-2014 Philippe Grand - * Copyright (C) 2012-2014 Marcos García + * Copyright (C) 2012-2015 Marcos García * Copyright (C) 2012-2014 Raphaël Doursenaud * Copyright (C) 2012 Cedric Salvador * @@ -1612,7 +1612,7 @@ abstract class CommonObject } if (! in_array($suffix,array('','_public','_private'))) { - dol_syslog(get_class($this)."::upate_note Parameter suffix must be empty, '_private' or '_public'", LOG_ERR); + dol_syslog(get_class($this)."::update_note Parameter suffix must be empty, '_private' or '_public'", LOG_ERR); return -2; } @@ -1888,10 +1888,11 @@ abstract class CommonObject * @param int $targetid Object target id * @param string $targettype Object target type * @param string $clause 'OR' or 'AND' clause used when both source id and target id are provided + * @param int $alsosametype 0=Return only links to different object than source. 1=Include also link to objects of same type. * @return void * @see add_object_linked, updateObjectLinked, deleteObjectLinked */ - function fetchObjectLinked($sourceid='',$sourcetype='',$targetid='',$targettype='',$clause='OR') + function fetchObjectLinked($sourceid='',$sourcetype='',$targetid='',$targettype='',$clause='OR',$alsosametype=1) { global $conf; @@ -1925,7 +1926,7 @@ abstract class CommonObject return -1; } - // Links beetween objects are stored in this table + // Links between objects are stored in table element_element $sql = 'SELECT fk_source, sourcetype, fk_target, targettype'; $sql.= ' FROM '.MAIN_DB_PREFIX.'element_element'; $sql.= " WHERE "; @@ -1984,7 +1985,7 @@ abstract class CommonObject $classpath = $element.'/class'; - // To work with non standard path + // To work with non standard classpath or module name if ($objecttype == 'facture') { $classpath = 'compta/facture/class'; } @@ -2020,7 +2021,7 @@ abstract class CommonObject $classfile = 'fournisseur.commande'; $classname = 'CommandeFournisseur'; } - if ($conf->$module->enabled && $element != $this->element) + if ($conf->$module->enabled && (($element != $this->element) || $alsosametype)) { dol_include_once('/'.$classpath.'/'.$classfile.'.class.php'); @@ -3225,7 +3226,7 @@ abstract class CommonObject $marginInfo = $this->getMarginInfos($force_price); - if (! empty($conf->global->MARGIN_ADD_SHOWHIDE_BUTTON)) // FIXME Warning this feature rely on an external js file that may be removed. Using native js function document.cookie should be better + if (! empty($conf->global->MARGIN_ADD_SHOWHIDE_BUTTON)) // TODO Warning this feature rely on an external js file that may be removed. Using native js function document.cookie should be better { print $langs->trans('ShowMarginInfos').' : '; $hidemargininfos = $_COOKIE['DOLUSER_MARGININFO_HIDE_SHOW']; @@ -3360,25 +3361,26 @@ abstract class CommonObject $this->db->begin(); $sql = "DELETE FROM ".MAIN_DB_PREFIX."element_resources"; - $sql.= " WHERE rowid =".$rowid; + $sql.= " WHERE rowid=".$rowid; dol_syslog(get_class($this)."::delete_resource", LOG_DEBUG); - if ($this->db->query($sql)) - { - if (! $notrigger) + $resql=$this->db->query($sql); + if (! $resql) + { + $this->error=$this->db->lasterror(); + $this->db->rollback(); + return -1; + } + else + { + if (! $notrigger) { $result=$this->call_trigger(strtoupper($element).'_DELETE_RESOURCE', $user); if ($result < 0) { $this->db->rollback(); return -1; } } - - return 1; - } - else - { - $this->error=$this->db->lasterror(); - $this->db->rollback(); - return -1; - } + $this->db->commit(); + return 1; + } } @@ -3905,5 +3907,27 @@ abstract class CommonObject return $user->rights->{$this->element}; } + /** + * Function used to replace a thirdparty id with another one. + * This function is meant to be called from replaceThirdparty with the appropiate tables + * Column name fk_soc MUST be used to identify thirdparties + * + * @param DoliDB $db Database handler + * @param int $origin_id Old thirdparty id + * @param int $dest_id New thirdparty id + * @param array $tables Tables that need to be changed + * @return bool + */ + public static function commonReplaceThirdparty(DoliDB $db, $origin_id, $dest_id, array $tables) + { + foreach ($tables as $table) { + $sql = 'UPDATE '.MAIN_DB_PREFIX.$table.' SET fk_soc = '.$dest_id.' WHERE fk_soc = '.$origin_id; + if (!$db->query($sql)) { + return false; + } + } + + return true; + } } diff --git a/htdocs/core/class/dolgraph.class.php b/htdocs/core/class/dolgraph.class.php index 15a0535598d..b65c5c8ede4 100644 --- a/htdocs/core/class/dolgraph.class.php +++ b/htdocs/core/class/dolgraph.class.php @@ -115,7 +115,7 @@ class DolGraph * Set Y precision * * @param float $which_prec Precision - * @return string + * @return boolean */ function SetPrecisionY($which_prec) { @@ -187,7 +187,7 @@ class DolGraph * Set y label * * @param string $label Y label - * @return boolean True + * @return boolean|null True */ function SetYLabel($label) { @@ -198,7 +198,7 @@ class DolGraph * Set width * * @param int $w Width - * @return boolean True + * @return boolean|null True */ function SetWidth($w) { @@ -554,7 +554,7 @@ class DolGraph /** * Return min value of all data * - * @return int Max value of all data + * @return double Max value of all data */ function GetFloorMinValue() { @@ -578,7 +578,7 @@ class DolGraph * * @param string $file Image file name to use to save onto disk (also used as javascript unique id) * @param string $fileurl Url path to show image if saved onto disk - * @return void + * @return integer|null */ function draw($file,$fileurl='') { diff --git a/htdocs/core/class/dolprintipp.class.php b/htdocs/core/class/dolprintipp.class.php index 252b742cc9d..4b934b331f3 100644 --- a/htdocs/core/class/dolprintipp.class.php +++ b/htdocs/core/class/dolprintipp.class.php @@ -18,7 +18,7 @@ /** * \file htdocs/core/class/dolprintipp.class.php - * \brief A set of functions for using printIPP + * \brief List jobs printed with driver printipp */ /** @@ -57,78 +57,6 @@ class dolprintIPP } - /** - * Return list of available printers - * - * @return array list of printers - */ - function getlist_available_printers() - { - global $conf,$db; - include_once DOL_DOCUMENT_ROOT.'/includes/printipp/CupsPrintIPP.php'; - $ipp = new CupsPrintIPP(); - $ipp->setLog(DOL_DATA_ROOT.'/printipp.log','file',3); // logging very verbose - $ipp->setHost($this->host); - $ipp->setPort($this->port); - $ipp->setUserName($this->userid); - if (! empty($this->user)) $ipp->setAuthentication($this->user,$this->password); - $ipp->getPrinters(); - return $ipp->available_printers; - } - - /** - * Print selected file - * - * @param string $file file - * @param string $module module - * - * @return string '' if OK, Error message if KO - */ - function print_file($file, $module) - { - global $conf,$db; - - include_once DOL_DOCUMENT_ROOT.'/includes/printipp/CupsPrintIPP.php'; - - $ipp = new CupsPrintIPP(); - $ipp->setLog(DOL_DATA_ROOT.'/dolibarr_printipp.log','file',3); // logging very verbose - $ipp->setHost($this->host); - $ipp->setPort($this->port); - $ipp->setJobName($file,true); - $ipp->setUserName($this->userid); - if (! empty($this->user)) $ipp->setAuthentication($this->user,$this->password); - - // select printer uri for module order, propal,... - $sql = 'SELECT rowid,printer_uri,copy FROM '.MAIN_DB_PREFIX.'printer_ipp WHERE module="'.$module.'"'; - $result = $this->db->query($sql); - if ($result) - { - $obj = $this->db->fetch_object($result); - if ($obj) - { - $ipp->setPrinterURI($obj->printer_uri); - } - else - { - if (! empty($conf->global->PRINTIPP_URI_DEFAULT)) - { - $ipp->setPrinterURI($conf->global->PRINTIPP_URI_DEFAULT); - } - else - { - return 'NoDefaultPrinterDefined'; - } - } - } - - // Set number of copy - $ipp->setCopies($obj->copy); - $ipp->setData(DOL_DATA_ROOT.'/'.$module.'/'.$file); - $ipp->printJob(); - - return ''; - } - /** * List jobs print * @@ -191,25 +119,4 @@ class dolprintIPP print "
"; } - /** - * Get printer detail - * - * @param string $uri URI - * @return array List of attributes - */ - function get_printer_detail($uri) - { - global $conf,$db; - - include_once DOL_DOCUMENT_ROOT.'/includes/printipp/CupsPrintIPP.php'; - $ipp = new CupsPrintIPP(); - $ipp->setLog(DOL_DATA_ROOT.'/printipp.log','file',3); // logging very verbose - $ipp->setHost($this->host); - $ipp->setPort($this->port); - $ipp->setUserName($this->userid); - if (! empty($this->user)) $ipp->setAuthentication($this->user,$this->password); - $ipp->setPrinterURI($uri); - $ipp->getPrinterAttributes(); - return $ipp->printer_attributes; - } } diff --git a/htdocs/core/class/events.class.php b/htdocs/core/class/events.class.php index 4ab3ce8f6fe..f94252d076d 100644 --- a/htdocs/core/class/events.class.php +++ b/htdocs/core/class/events.class.php @@ -31,7 +31,6 @@ /** * Events class - * Initialy built by build_class_from_table on 2008-02-28 17:25 */ class Events // extends CommonObject { @@ -41,6 +40,8 @@ class Events // extends CommonObject var $id; var $db; + var $error; + var $tms; var $type; var $entity; diff --git a/htdocs/core/class/extrafields.class.php b/htdocs/core/class/extrafields.class.php index 16e6af25cc7..a9a44fc27d1 100644 --- a/htdocs/core/class/extrafields.class.php +++ b/htdocs/core/class/extrafields.class.php @@ -568,11 +568,11 @@ class ExtraFields global $conf; if ( empty($elementtype) ) return array(); - + if ($elementtype == 'thirdparty') $elementtype='societe'; $array_name_label=array(); - + // For avoid conflicts with external modules if (!$forceload && !empty($conf->global->MAIN_EXTRAFIELDS_DISABLED)) return $array_name_label; @@ -602,7 +602,7 @@ class ExtraFields $this->attribute_elementtype[$tab->name]=$tab->elementtype; $this->attribute_unique[$tab->name]=$tab->fieldunique; $this->attribute_required[$tab->name]=$tab->fieldrequired; - $this->attribute_param[$tab->name]=unserialize($tab->param); + $this->attribute_param[$tab->name]=($tab->param ? unserialize($tab->param) : ''); $this->attribute_pos[$tab->name]=$tab->pos; $this->attribute_alwayseditable[$tab->name]=$tab->alwayseditable; $this->attribute_perms[$tab->name]=$tab->perms; @@ -1056,7 +1056,7 @@ class ExtraFields elseif ($type == 'link') { $out=''; - + $param_list=array_keys($param['options']); // 0 : ObjectName // 1 : classPath diff --git a/htdocs/core/class/hookmanager.class.php b/htdocs/core/class/hookmanager.class.php index 5cb0ca81faf..94ea025879a 100644 --- a/htdocs/core/class/hookmanager.class.php +++ b/htdocs/core/class/hookmanager.class.php @@ -192,7 +192,7 @@ class HookManager dol_syslog("Error on hook module=".$module.", method ".$method.", class ".get_class($actionclassinstance).", hooktype=".$hooktype.(empty($this->error)?'':" ".$this->error).(empty($this->errors)?'':" ".join(",",$this->errors)), LOG_ERR); } - if (is_array($actionclassinstance->results)) $this->resArray =array_merge($this->resArray, $actionclassinstance->results); + if (isset($actionclassinstance->results) && is_array($actionclassinstance->results)) $this->resArray =array_merge($this->resArray, $actionclassinstance->results); if (! empty($actionclassinstance->resprints)) $this->resPrint.=$actionclassinstance->resprints; } // Generic hooks that return a string or array (printSearchForm, printLeftBlock, formAddObjectLine, formBuilddocOptions, ...) diff --git a/htdocs/core/class/html.form.class.php b/htdocs/core/class/html.form.class.php index 3613680038d..41c3fbf86c9 100644 --- a/htdocs/core/class/html.form.class.php +++ b/htdocs/core/class/html.form.class.php @@ -868,7 +868,7 @@ class Form * * @param string $selected Preselected type * @param string $htmlname Name of field in form - * @param string $filter optional filters criteras (example: 's.rowid <> x') + * @param string $filter optional filters criteras (example: 's.rowid <> x', 's.client in (1,3)') * @param int $showempty Add an empty field * @param int $showtype Show third party type in combolist (customer, prospect or supplier) * @param int $forcecombo Force to use combo box @@ -1306,7 +1306,7 @@ class Form $sql.= " WHERE u.entity IN (0,".$conf->entity.")"; } } - if (! empty($user->societe_id)) $sql.= " AND u.fk_societe = ".$user->societe_id; + if (! empty($user->societe_id)) $sql.= " AND u.fk_soc = ".$user->societe_id; if (is_array($exclude) && $excludeUsers) $sql.= " AND u.rowid NOT IN ('".$excludeUsers."')"; if (is_array($include) && $includeUsers) $sql.= " AND u.rowid IN ('".$includeUsers."')"; if (! empty($conf->global->USER_HIDE_INACTIVE_IN_COMBOBOX)) $sql.= " AND u.statut <> 0"; @@ -1529,7 +1529,7 @@ class Form print img_picto($langs->trans("Search"), 'search'); } } - print ''; + print ''; if ($hidelabel == 3) { print img_picto($langs->trans("Search"), 'search'); } @@ -1646,7 +1646,7 @@ class Form require_once DOL_DOCUMENT_ROOT.'/product/dynamic_price/class/price_parser.class.php'; $num = $this->db->num_rows($result); - $out.=''; $out.=''; $i = 0; @@ -2919,7 +2919,7 @@ class Form { print ''; $i++; @@ -2978,10 +2978,11 @@ class Form * @param string $htmlname HTML field name * @param int $maxlength Maximum length for labels * @param int $excludeafterid Exclude all categories after this leaf in category tree. + * @param int $outputmode 0=HTML select string, 1=Array * @return string * @see select_categories */ - function select_all_categories($type, $selected='', $htmlname="parent", $maxlength=64, $excludeafterid=0) + function select_all_categories($type, $selected='', $htmlname="parent", $maxlength=64, $excludeafterid=0, $outputmode=0) { global $langs; $langs->load("categories"); @@ -2990,6 +2991,7 @@ class Form $cate_arbo = $cat->get_full_arbo($type,$excludeafterid); $output = ''; $output.= "\n"; - return $output; + + if ($outputmode) return $outarray; + return $output; } /** diff --git a/htdocs/core/class/html.formmail.class.php b/htdocs/core/class/html.formmail.class.php index 9e7686f70ce..3c799b767af 100644 --- a/htdocs/core/class/html.formmail.class.php +++ b/htdocs/core/class/html.formmail.class.php @@ -32,7 +32,7 @@ require_once DOL_DOCUMENT_ROOT .'/core/class/html.form.class.php'; * $formmail->proprietes=1 ou chaine ou tableau de valeurs * $formmail->show_form() affiche le formulaire */ -class FormMail +class FormMail extends Form { var $db; @@ -71,6 +71,8 @@ class FormMail var $error; + public $lines_model; + /** * Constructor @@ -242,7 +244,7 @@ class FormMail else { $out=''; - + // Define list of attached files $listofpaths=array(); $listofnames=array(); @@ -263,8 +265,11 @@ class FormMail } // Get message template - $arraydefaultmessage=$this->getEMailTemplate($this->db, $this->param["models"], $user, $outputlangs); - + $model_id=0; + if (array_key_exists('models_id',$this->param)) { + $model_id=$this->param["models_id"]; + } + $arraydefaultmessage=$this->getEMailTemplate($this->db, $this->param["models"], $user, $outputlangs, $model_id); $out.= "\n\n"; if ($this->withform == 1) @@ -277,6 +282,28 @@ class FormMail { $out.= ''."\n"; } + + $result = $this->fetchAllEMailTemplate($this->param["models"], $user, $outputlangs); + if ($result<0) { + setEventMessage($this->error,'errors'); + } + $modelmail_array=array(); + foreach($this->lines_model as $line) { + $modelmail_array[$line->id]=$line->label; + } + + if (count($modelmail_array)>0) { + $out.= ''; + $out.= ''; + $out.= ''; + $out.= '
'."\n"; + $out.= $langs->trans('SelectMailModel').':'.$this->selectarray('modelmailselected', $modelmail_array,$model_id); + $out.= ''; + if ($user->admin) $out.= info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"),1); + $out.= '
'; + } + + $out.= ''."\n"; // Substitution array @@ -617,8 +644,8 @@ class FormMail $defaultmessage = dol_nl2br($defaultmessage); } - - if (isset($_POST["message"])) $defaultmessage=$_POST["message"]; + + if (isset($_POST["message"]) && ! $_POST['modelselected']) $defaultmessage=$_POST["message"]; else { $defaultmessage=make_substitutions($defaultmessage,$this->substit); @@ -690,9 +717,10 @@ class FormMail * @param string $type_template Get message for key module * @param string $user Use template public or limited to this user * @param Translate $outputlangs Output lang object + * @param int $id Id template to find * @return array array('topic'=>,'content'=>,..) */ - private function getEMailTemplate($db, $type_template, $user, $outputlangs) + private function getEMailTemplate($db, $type_template, $user, $outputlangs,$id=0) { $ret=array(); @@ -702,6 +730,7 @@ class FormMail $sql.= " AND entity IN (".getEntity("c_email_templates").")"; $sql.= " AND (fk_user is NULL or fk_user = 0 or fk_user = ".$user->id.")"; if (is_object($outputlangs)) $sql.= " AND (lang = '".$outputlangs->defaultlang."' OR lang IS NULL OR lang = '')"; + if (!empty($id)) $sql.= " AND rowid=".$id; $sql.= $db->order("lang,label","ASC"); //print $sql; @@ -745,5 +774,98 @@ class FormMail return -1; } } + + /** + * Find if template exists + * Search into table c_email_templates + * + * @param string $type_template Get message for key module + * @param string $user Use template public or limited to this user + * @param Translate $outputlangs Output lang object + * @return int <0 if KO, + */ + public function isEMailTemplate($type_template, $user, $outputlangs) + { + $ret=array(); + + $sql = "SELECT label, topic, content, lang"; + $sql.= " FROM ".MAIN_DB_PREFIX.'c_email_templates'; + $sql.= " WHERE type_template='".$this->db->escape($type_template)."'"; + $sql.= " AND entity IN (".getEntity("c_email_templates").")"; + $sql.= " AND (fk_user is NULL or fk_user = 0 or fk_user = ".$user->id.")"; + if (is_object($outputlangs)) $sql.= " AND (lang = '".$outputlangs->defaultlang."' OR lang IS NULL OR lang = '')"; + $sql.= $this->db->order("lang,label","ASC"); + //print $sql; + + $resql = $this->db->query($sql); + if ($resql) + { + $num= $this->db->num_rows($resql); + $this->db->free($resql); + return $num; + } + else + { + $this->error=get_class($this).' '.__METHOD__.' ERROR:'.$this->db->lasterror(); + return -1; + } + } + + /** + * Find if template exists + * Search into table c_email_templates + * + * @param string $type_template Get message for key module + * @param string $user Use template public or limited to this user + * @param Translate $outputlangs Output lang object + * @return int <0 if KO, + */ + public function fetchAllEMailTemplate($type_template, $user, $outputlangs) + { + $ret=array(); + + $sql = "SELECT rowid, label, topic, content, lang"; + $sql.= " FROM ".MAIN_DB_PREFIX.'c_email_templates'; + $sql.= " WHERE type_template='".$this->db->escape($type_template)."'"; + $sql.= " AND entity IN (".getEntity("c_email_templates").")"; + $sql.= " AND (fk_user is NULL or fk_user = 0 or fk_user = ".$user->id.")"; + if (is_object($outputlangs)) $sql.= " AND (lang = '".$outputlangs->defaultlang."' OR lang IS NULL OR lang = '')"; + $sql.= $this->db->order("lang,label","ASC"); + //print $sql; + + $resql = $this->db->query($sql); + if ($resql) + { + $this->lines_model=array(); + while ($obj = $this->db->fetch_object($resql)) + { + $line = new ModelMail(); + $line->id=$obj->rowid; + $line->label=$obj->label; + $line->topic=$obj->topic; + $line->content=$obj->lacontentbel; + $line->lang=$obj->lang; + $this->lines_model[]=$line; + } + $this->db->free($resql); + return $num; + } + else + { + $this->error=get_class($this).' '.__METHOD__.' ERROR:'.$this->db->lasterror(); + return -1; + } + } } +/** + * ModelMail + */ +class ModelMail +{ + public $id; + public $label; + public $topic; + public $content; + public $lang; +} diff --git a/htdocs/core/class/html.formother.class.php b/htdocs/core/class/html.formother.class.php index 786d2c53a34..3233b479b6c 100644 --- a/htdocs/core/class/html.formother.class.php +++ b/htdocs/core/class/html.formother.class.php @@ -374,9 +374,13 @@ class FormOther if ($conf->use_javascript_ajax) { include_once DOL_DOCUMENT_ROOT . '/core/lib/ajax.lib.php'; + $comboenhancement = ajax_combobox($htmlname); - $out.=$comboenhancement; - $nodatarole=($comboenhancement?' data-role="none"':''); + if ($comboenhancement) + { + $out.=$comboenhancement; + $nodatarole=($comboenhancement?' data-role="none"':''); + } } // Select each sales and print them in a select input $out.=''; + print ''; print ''; if ($showproject) print ''; print ''; @@ -504,9 +504,10 @@ function projectLinesa(&$inc, $parent, &$lines, &$level, $var, $showproject, &$t * @param string $tasksrole Array of roles user has on task * @param string $mine Show only task lines I am assigned to * @param int $restricteditformytask 0=No restriction, 1=Enable add time only if task is a task i am affected to + * @param int $preselectedday Preselected day * @return $inc */ -function projectLinesPerDay(&$inc, $parent, $lines, &$level, &$projectsrole, &$tasksrole, $mine, $restricteditformytask=0) +function projectLinesPerDay(&$inc, $parent, $lines, &$level, &$projectsrole, &$tasksrole, $mine, $restricteditformytask=0, $preselectedday='') { global $db, $user, $bc, $langs; global $form, $formother, $projectstatic, $taskstatic; @@ -527,6 +528,12 @@ function projectLinesPerDay(&$inc, $parent, $lines, &$level, &$projectsrole, &$t { $var = !$var; $lastprojectid=$lines[$i]->fk_project; + + if ($preselectedday) + { + $projectstatic->id = $lines[$i]->fk_project; + $projectstatic->loadTimeSpent($preselectedday, 0, $fuser->id); // Load time spent into this->weekWorkLoad and this->weekWorkLoadPerTaks for all day of a week + } } // If we want all or we have a role on task, we show it @@ -549,7 +556,7 @@ function projectLinesPerDay(&$inc, $parent, $lines, &$level, &$projectsrole, &$t // Ref print ''; // Label task @@ -559,7 +566,7 @@ function projectLinesPerDay(&$inc, $parent, $lines, &$level, &$projectsrole, &$t $taskstatic->ref=$lines[$i]->label; $taskstatic->date_start=$lines[$i]->date_start; $taskstatic->date_end=$lines[$i]->date_end; - print $taskstatic->getNomUrl(0); + print $taskstatic->getNomUrl(0,'withproject'); //print "
"; //for ($k = 0 ; $k < $level ; $k++) print "   "; //print get_date_range($lines[$i]->date_start,$lines[$i]->date_end,'',$langs,0); @@ -613,14 +620,21 @@ function projectLinesPerDay(&$inc, $parent, $lines, &$level, &$projectsrole, &$t // Form to add new time print ''; print ''; print $tableCell; } + + print ''; + print "\n"; } diff --git a/htdocs/core/lib/tax.lib.php b/htdocs/core/lib/tax.lib.php index bee6999d183..a163047e61b 100644 --- a/htdocs/core/lib/tax.lib.php +++ b/htdocs/core/lib/tax.lib.php @@ -36,7 +36,7 @@ */ function tax_prepare_head(ChargeSociales $object) { - global $langs, $conf; + global $langs, $conf, $user; $h = 0; $head = array(); @@ -496,7 +496,7 @@ function vat_by_date($db, $y, $q, $date_start, $date_end, $modetax, $direction, $sql.= " AND f.fk_statut in (1,2)"; // Paid (partially or completely) if (! empty($conf->global->FACTURE_DEPOSITS_ARE_JUST_PAYMENTS)) $sql.= " AND f.type IN (0,1,2,5)"; else $sql.= " AND f.type IN (0,1,2,3,5)"; - $sql.= " AND f.rowid = d.".$fk_facture;; + $sql.= " AND f.rowid = d.".$fk_facture; $sql.= " AND pf.".$fk_facture2." = f.rowid"; $sql.= " AND pa.rowid = pf.".$fk_payment; if ($y && $m) diff --git a/htdocs/core/menus/init_menu_auguria.sql b/htdocs/core/menus/init_menu_auguria.sql index f481abdcf0c..fd4d41ce6a7 100644 --- a/htdocs/core/menus/init_menu_auguria.sql +++ b/htdocs/core/menus/init_menu_auguria.sql @@ -93,7 +93,8 @@ insert into llx_menu (module, enabled, menu_handler, type, rowid, mainmenu, left insert into llx_menu (module, enabled, menu_handler, type, rowid, mainmenu, leftmenu, fk_menu, url, titre, level, langs, perms, target, usertype, position, entity) values ('', '$conf->product->enabled', __HANDLER__, 'left', 2801__+MAX_llx_menu__, 'products', '', 2800__+MAX_llx_menu__, '/product/card.php?leftmenu=product&action=create&type=0', 'NewProduct', 1, 'products', '$user->rights->produit->creer', '', 2, 0, __ENTITY__); insert into llx_menu (module, enabled, menu_handler, type, rowid, mainmenu, leftmenu, fk_menu, url, titre, level, langs, perms, target, usertype, position, entity) values ('', '$conf->product->enabled', __HANDLER__, 'left', 2802__+MAX_llx_menu__, 'products', '', 2800__+MAX_llx_menu__, '/product/list.php?leftmenu=product&type=0', 'List', 1, 'products', '$user->rights->produit->lire', '', 2, 1, __ENTITY__); insert into llx_menu (module, enabled, menu_handler, type, rowid, mainmenu, leftmenu, fk_menu, url, titre, level, langs, perms, target, usertype, position, entity) values ('', '$conf->product->enabled', __HANDLER__, 'left', 2803__+MAX_llx_menu__, 'products', '', 2800__+MAX_llx_menu__, '/product/reassort.php?type=0', 'Stocks', 1, 'products', '$user->rights->produit->lire && $user->rights->stock->lire', '', 2, 4, __ENTITY__); -insert into llx_menu (module, enabled, menu_handler, type, rowid, mainmenu, leftmenu, fk_menu, url, titre, level, langs, perms, target, usertype, position, entity) values ('', '$conf->propal->enabled', __HANDLER__, 'left', 2804__+MAX_llx_menu__, 'products', '', 2800__+MAX_llx_menu__, '/product/popuprop.php?leftmenu=stats&type=0', 'Statistics', 1, 'main', '$user->rights->produit->lire', '', 2, 5, __ENTITY__); +insert into llx_menu (module, enabled, menu_handler, type, rowid, mainmenu, leftmenu, fk_menu, url, titre, level, langs, perms, target, usertype, position, entity) values ('', '$conf->productbatch->enabled', __HANDLER__, 'left', 2805__+MAX_llx_menu__, 'products', '', 2800__+MAX_llx_menu__, '/product/reassortlot.php?type=0', 'StocksByLotSerial', 1, 'products', '$user->rights->produit->lire && $user->rights->stock->lire', '', 2, 5, __ENTITY__); +insert into llx_menu (module, enabled, menu_handler, type, rowid, mainmenu, leftmenu, fk_menu, url, titre, level, langs, perms, target, usertype, position, entity) values ('', '$conf->propal->enabled', __HANDLER__, 'left', 2804__+MAX_llx_menu__, 'products', '', 2800__+MAX_llx_menu__, '/product/popuprop.php?leftmenu=stats&type=0', 'Statistics', 1, 'main', '$user->rights->produit->lire', '', 2, 6, __ENTITY__); -- Product - Services insert into llx_menu (module, enabled, menu_handler, type, rowid, mainmenu, leftmenu, fk_menu, url, titre, level, langs, perms, target, usertype, position, entity) values ('', '$conf->service->enabled', __HANDLER__, 'left', 2900__+MAX_llx_menu__, 'products', 'service', 3__+MAX_llx_menu__, '/product/index.php?leftmenu=service&type=1', 'Services', 0, 'products', '$user->rights->service->lire', '', 2, 1, __ENTITY__); insert into llx_menu (module, enabled, menu_handler, type, rowid, mainmenu, leftmenu, fk_menu, url, titre, level, langs, perms, target, usertype, position, entity) values ('', '$conf->service->enabled', __HANDLER__, 'left', 2901__+MAX_llx_menu__, 'products', '', 2900__+MAX_llx_menu__, '/product/card.php?leftmenu=service&action=create&type=1', 'NewService', 1, 'products', '$user->rights->service->creer', '', 2, 0, __ENTITY__); @@ -104,8 +105,8 @@ insert into llx_menu (module, enabled, menu_handler, type, rowid, mainmenu, left insert into llx_menu (module, enabled, menu_handler, type, rowid, mainmenu, leftmenu, fk_menu, url, titre, level, langs, perms, target, usertype, position, entity) values ('', '$conf->stock->enabled', __HANDLER__, 'left', 3101__+MAX_llx_menu__, 'products', '', 3100__+MAX_llx_menu__, '/product/stock/card.php?action=create', 'MenuNewWarehouse', 1, 'stocks', '$user->rights->stock->creer', '', 2, 0, __ENTITY__); insert into llx_menu (module, enabled, menu_handler, type, rowid, mainmenu, leftmenu, fk_menu, url, titre, level, langs, perms, target, usertype, position, entity) values ('', '$conf->stock->enabled', __HANDLER__, 'left', 3102__+MAX_llx_menu__, 'products', '', 3100__+MAX_llx_menu__, '/product/stock/list.php', 'List', 1, 'stocks', '$user->rights->stock->lire', '', 2, 1, __ENTITY__); insert into llx_menu (module, enabled, menu_handler, type, rowid, mainmenu, leftmenu, fk_menu, url, titre, level, langs, perms, target, usertype, position, entity) values ('', '$conf->stock->enabled', __HANDLER__, 'left', 3104__+MAX_llx_menu__, 'products', '', 3100__+MAX_llx_menu__, '/product/stock/mouvement.php', 'Movements', 1, 'stocks', '$user->rights->stock->mouvement->lire', '', 2, 3, __ENTITY__); -insert into llx_menu (module, enabled, menu_handler, type, rowid, mainmenu, leftmenu, fk_menu, url, titre, level, langs, perms, target, usertype, position, entity) values ('', '$conf->stock->enabled && $conf->fournisseur->enabled', __HANDLER__, 'left', 3105__+MAX_llx_menu__, 'products', '', 3100__+MAX_llx_menu__, '/product/stock/replenish.php', 'Replenishments', 1, 'stocks', '$user->rights->stock->mouvement->lire && $user->rights->fournisseur->lire', '', 2, 4, __ENTITY__); -insert into llx_menu (module, enabled, menu_handler, type, rowid, mainmenu, leftmenu, fk_menu, url, titre, level, langs, perms, target, usertype, position, entity) values ('', '$conf->stock->enabled && $conf->fournisseur->enabled', __HANDLER__, 'left', 3106__+MAX_llx_menu__, 'products', '', 3100__+MAX_llx_menu__, '/product/stock/massstockmove.php', 'StockTransfer', 1, 'stocks', '$user->rights->stock->mouvement->lire && $user->rights->fournisseur->lire', '', 2, 5, __ENTITY__); +insert into llx_menu (module, enabled, menu_handler, type, rowid, mainmenu, leftmenu, fk_menu, url, titre, level, langs, perms, target, usertype, position, entity) values ('', '$conf->stock->enabled && $conf->fournisseur->enabled', __HANDLER__, 'left', 3105__+MAX_llx_menu__, 'products', '', 3100__+MAX_llx_menu__, '/product/stock/replenish.php', 'Replenishments', 1, 'stocks', '$user->rights->stock->mouvement->creer && $user->rights->fournisseur->lire', '', 2, 4, __ENTITY__); +insert into llx_menu (module, enabled, menu_handler, type, rowid, mainmenu, leftmenu, fk_menu, url, titre, level, langs, perms, target, usertype, position, entity) values ('', '$conf->stock->enabled', __HANDLER__, 'left', 3106__+MAX_llx_menu__, 'products', '', 3100__+MAX_llx_menu__, '/product/stock/massstockmove.php', 'StockTransfer', 1, 'stocks', '$user->rights->stock->mouvement->creer', '', 2, 5, __ENTITY__); -- Product - Categories insert into llx_menu (module, enabled, menu_handler, type, rowid, mainmenu, leftmenu, fk_menu, url, titre, level, langs, perms, target, usertype, position, entity) values ('', '$conf->categorie->enabled', __HANDLER__, 'left', 3200__+MAX_llx_menu__, 'products', 'cat', 3__+MAX_llx_menu__, '/categories/index.php?leftmenu=cat&type=0', 'Categories', 0, 'categories', '$user->rights->categorie->lire', '', 2, 4, __ENTITY__); @@ -165,9 +166,16 @@ insert into llx_menu (module, enabled, menu_handler, type, rowid, mainmenu, left insert into llx_menu (module, enabled, menu_handler, type, rowid, mainmenu, leftmenu, fk_menu, url, titre, level, langs, perms, target, usertype, position, entity) values ('', '$conf->facture->enabled', __HANDLER__, 'left', 1700__+MAX_llx_menu__, 'accountancy', 'customer_bills', 6__+MAX_llx_menu__, '/compta/facture/list.php?leftmenu=customers_bills', 'BillsCustomers', 0, 'bills', '$user->rights->facture->lire', '', 2, 3, __ENTITY__); insert into llx_menu (module, enabled, menu_handler, type, rowid, mainmenu, leftmenu, fk_menu, url, titre, level, langs, perms, target, usertype, position, entity) values ('', '$conf->facture->enabled', __HANDLER__, 'left', 1701__+MAX_llx_menu__, 'accountancy', '', 1700__+MAX_llx_menu__, '/compta/facture.php?action=create&leftmenu=customers_bills', 'NewBill', 1, 'bills', '$user->rights->facture->creer', '', 2, 3, __ENTITY__); insert into llx_menu (module, enabled, menu_handler, type, rowid, mainmenu, leftmenu, fk_menu, url, titre, level, langs, perms, target, usertype, position, entity) values ('', '$conf->facture->enabled', __HANDLER__, 'left', 1702__+MAX_llx_menu__, 'accountancy', '', 1700__+MAX_llx_menu__, '/compta/facture/fiche-rec.php?leftmenu=customers_bills', 'Repeatable', 1, 'bills', '$user->rights->facture->lire', '', 2, 4, __ENTITY__); -insert into llx_menu (module, enabled, menu_handler, type, rowid, mainmenu, leftmenu, fk_menu, url, titre, level, langs, perms, target, usertype, position, entity) values ('', '$conf->facture->enabled', __HANDLER__, 'left', 1703__+MAX_llx_menu__, 'accountancy', '', 1700__+MAX_llx_menu__, '/compta/facture/impayees.php?action=facturer&leftmenu=customers_bills', 'Unpaid', 1, 'bills', '$user->rights->facture->lire', '', 2, 5, __ENTITY__); +insert into llx_menu (module, enabled, menu_handler, type, rowid, mainmenu, leftmenu, fk_menu, url, titre, level, langs, perms, target, usertype, position, entity) values ('', '$conf->facture->enabled', __HANDLER__, 'left', 1705__+MAX_llx_menu__, 'accountancy', '', 1700__+MAX_llx_menu__, '/compta/facture/list.php?leftmenu=customers_bills', 'List', 1, 'bills', '$user->rights->facture->lire', '', 2, 5, __ENTITY__); + +insert into llx_menu (module, enabled, menu_handler, type, rowid, mainmenu, leftmenu, fk_menu, url, titre, level, langs, perms, target, usertype, position, entity) values ('', '$conf->facture->enabled', __HANDLER__, 'left', 1720__+MAX_llx_menu__, 'accountancy', '', 1705__+MAX_llx_menu__, '/compta/facture/list.php?leftmenu=customers_bills&search_status=0', 'BillShortStatusDraft', 2, 'bills', '$user->rights->facture->lire', '', 2, 1, __ENTITY__); +insert into llx_menu (module, enabled, menu_handler, type, rowid, mainmenu, leftmenu, fk_menu, url, titre, level, langs, perms, target, usertype, position, entity) values ('', '$conf->facture->enabled', __HANDLER__, 'left', 1721__+MAX_llx_menu__, 'accountancy', '', 1705__+MAX_llx_menu__, '/compta/facture/list.php?leftmenu=customers_bills&search_status=1', 'BillShortStatusNotPaid', 2, 'bills', '$user->rights->facture->lire', '', 2, 2, __ENTITY__); +insert into llx_menu (module, enabled, menu_handler, type, rowid, mainmenu, leftmenu, fk_menu, url, titre, level, langs, perms, target, usertype, position, entity) values ('', '$conf->facture->enabled', __HANDLER__, 'left', 1722__+MAX_llx_menu__, 'accountancy', '', 1705__+MAX_llx_menu__, '/compta/facture/list.php?leftmenu=customers_bills&search_status=2', 'BillShortStatusPaid', 2, 'bills', '$user->rights->facture->lire', '', 2, 3, __ENTITY__); +insert into llx_menu (module, enabled, menu_handler, type, rowid, mainmenu, leftmenu, fk_menu, url, titre, level, langs, perms, target, usertype, position, entity) values ('', '$conf->facture->enabled', __HANDLER__, 'left', 1723__+MAX_llx_menu__, 'accountancy', '', 1705__+MAX_llx_menu__, '/compta/facture/list.php?leftmenu=customers_bills&search_status=3', 'BillShortStatusCanceled', 2, 'bills', '$user->rights->facture->lire', '', 2, 4, __ENTITY__); + insert into llx_menu (module, enabled, menu_handler, type, rowid, mainmenu, leftmenu, fk_menu, url, titre, level, langs, perms, target, usertype, position, entity) values ('', '$conf->facture->enabled', __HANDLER__, 'left', 1704__+MAX_llx_menu__, 'accountancy', '', 1700__+MAX_llx_menu__, '/compta/paiement/list.php?leftmenu=customers_bills', 'Payments', 1, 'bills', '$user->rights->facture->lire', '', 2, 6, __ENTITY__); insert into llx_menu (module, enabled, menu_handler, type, rowid, mainmenu, leftmenu, fk_menu, url, titre, level, langs, perms, target, usertype, position, entity) values ('', '$conf->facture->enabled', __HANDLER__, 'left', 1710__+MAX_llx_menu__, 'accountancy', '', 1704__+MAX_llx_menu__, '/compta/paiement/rapport.php?leftmenu=customers_bills', 'Reportings', 2, 'bills', '$user->rights->facture->lire', '', 2, 1, __ENTITY__); +insert into llx_menu (module, enabled, menu_handler, type, rowid, mainmenu, leftmenu, fk_menu, url, titre, level, langs, perms, target, usertype, position, entity) values ('', '$conf->facture->enabled', __HANDLER__, 'left', 1703__+MAX_llx_menu__, 'accountancy', '', 1700__+MAX_llx_menu__, '/compta/facture/mergepdftool.php?action=facturer&leftmenu=customers_bills', 'MergingPDFTool', 1, 'bills', '$user->rights->facture->lire', '', 2, 7, __ENTITY__); insert into llx_menu (module, enabled, menu_handler, type, rowid, mainmenu, leftmenu, fk_menu, url, titre, level, langs, perms, target, usertype, position, entity) values ('', '$conf->facture->enabled', __HANDLER__, 'left', 1714__+MAX_llx_menu__, 'accountancy', '', 1700__+MAX_llx_menu__, '/compta/facture/stats/index.php?leftmenu=customers_bills', 'Statistics', 1, 'bills', '$user->rights->facture->lire', '', 2, 8, __ENTITY__); -- Accountancy - Orders to bill insert into llx_menu (module, enabled, menu_handler, type, rowid, mainmenu, leftmenu, fk_menu, url, titre, level, langs, perms, target, usertype, position, entity) values ('', '$conf->commande->enabled', __HANDLER__, 'left', 1900__+MAX_llx_menu__, 'accountancy', 'orders', 6__+MAX_llx_menu__, '/commande/list.php?leftmenu=orders&viewstatut=3', 'MenuOrdersToBill', 0, 'orders', '$user->rights->commande->lire', '', 0, 3, __ENTITY__); diff --git a/htdocs/core/menus/standard/eldy.lib.php b/htdocs/core/menus/standard/eldy.lib.php index d6ee928b121..e076e674be2 100644 --- a/htdocs/core/menus/standard/eldy.lib.php +++ b/htdocs/core/menus/standard/eldy.lib.php @@ -1,7 +1,7 @@ * Copyright (C) 2010 Regis Houssin - * Copyright (C) 2012-2014 Juanjo Menent + * Copyright (C) 2012-2015 Juanjo Menent * Copyright (C) 2013 Cédric Salvador * Copyright (C) 2015 Marcos García * @@ -218,9 +218,9 @@ function print_eldy_menu($db,$atarget,$type_user,&$tabMenu,&$menu,$noout=0) // Tools - $tmpentry=array('enabled'=>(! empty($conf->barcode->enabled) || ! empty($conf->mailing->enabled) || ! empty($conf->export->enabled) || ! empty($conf->import->enabled) || ! empty($conf->opensurvey->enabled)), - 'perms'=>(! empty($conf->barcode->enabled) || ! empty($user->rights->mailing->lire) || ! empty($user->rights->export->lire) || ! empty($user->rights->import->run) || ! empty($user->rights->opensurvey->read)), - 'module'=>'mailing|export|import|opensurvey'); + $tmpentry=array('enabled'=>(! empty($conf->barcode->enabled) || ! empty($conf->mailing->enabled) || ! empty($conf->export->enabled) || ! empty($conf->import->enabled) || ! empty($conf->opensurvey->enabled) || ! empty($conf->resource->enabled)), + 'perms'=>(! empty($conf->barcode->enabled) || ! empty($user->rights->mailing->lire) || ! empty($user->rights->export->lire) || ! empty($user->rights->import->run) || ! empty($user->rights->opensurvey->read) || ! empty($user->rights->resource->read)), + 'module'=>'mailing|export|import|opensurvey|resource'); $showmode=dol_eldy_showmenu($type_user, $tmpentry, $listofmodulesforexternal); if ($showmode) { @@ -695,7 +695,7 @@ function print_left_eldy_menu($db,$menu_array_before,$menu_array_after,&$tabMenu if ((empty($leftmenu) || $leftmenu=="orders_suppliers") && empty($conf->global->SUPPLIER_ORDER_HIDE_VALIDATED)) $newmenu->add("/fourn/commande/list.php?leftmenu=orders_suppliers&statut=1", $langs->trans("StatusOrderValidated"), 2, $user->rights->fournisseur->commande->lire); if (empty($leftmenu) || $leftmenu=="orders_suppliers") $newmenu->add("/fourn/commande/list.php?leftmenu=orders_suppliers&statut=2", $langs->trans("StatusOrderApprovedShort"), 2, $user->rights->fournisseur->commande->lire); if (empty($leftmenu) || $leftmenu=="orders_suppliers") $newmenu->add("/fourn/commande/list.php?leftmenu=orders_suppliers&statut=3", $langs->trans("StatusOrderOnProcessShort"), 2, $user->rights->fournisseur->commande->lire); - if (empty($leftmenu) || $leftmenu=="orders_suppliers") $newmenu->add("/fourn/commande/list.php?leftmenu=orders_suppliers&statut=4", $langs->trans("StatusOrderReceivedPartially"), 2, $user->rights->fournisseur->commande->lire); + if (empty($leftmenu) || $leftmenu=="orders_suppliers") $newmenu->add("/fourn/commande/list.php?leftmenu=orders_suppliers&statut=4", $langs->trans("StatusOrderReceivedPartiallyShort"), 2, $user->rights->fournisseur->commande->lire); if (empty($leftmenu) || $leftmenu=="orders_suppliers") $newmenu->add("/fourn/commande/list.php?leftmenu=orders_suppliers&statut=5", $langs->trans("StatusOrderReceivedAll"), 2, $user->rights->fournisseur->commande->lire); if (empty($leftmenu) || $leftmenu=="orders_suppliers") $newmenu->add("/fourn/commande/list.php?leftmenu=orders_suppliers&statut=6,7", $langs->trans("StatusOrderCanceled"), 2, $user->rights->fournisseur->commande->lire); if (empty($leftmenu) || $leftmenu=="orders_suppliers") $newmenu->add("/fourn/commande/list.php?leftmenu=orders_suppliers&statut=9", $langs->trans("StatusOrderRefused"), 2, $user->rights->fournisseur->commande->lire); @@ -741,27 +741,30 @@ function print_left_eldy_menu($db,$menu_array_before,$menu_array_after,&$tabMenu if (! empty($conf->facture->enabled)) { $langs->load("bills"); - $newmenu->add("/compta/facture/list.php?leftmenu=customers_bills",$langs->trans("BillsCustomers"),0,$user->rights->facture->lire, '', $mainmenu, 'customers_bills'); - $newmenu->add("/compta/facture.php?action=create&leftmenu=customers_bills",$langs->trans("NewBill"),1,$user->rights->facture->creer); - $newmenu->add("/compta/facture/fiche-rec.php?leftmenu=customers_bills",$langs->trans("Repeatables"),1,$user->rights->facture->lire); + $newmenu->add("/compta/facture/list.php",$langs->trans("BillsCustomers"),0,$user->rights->facture->lire, '', $mainmenu, 'customers_bills'); + $newmenu->add("/compta/facture.php?action=create",$langs->trans("NewBill"),1,$user->rights->facture->creer); + $newmenu->add("/compta/facture/fiche-rec.php",$langs->trans("Repeatables"),1,$user->rights->facture->lire); $newmenu->add("/compta/facture/list.php?leftmenu=customers_bills",$langs->trans("List"),1,$user->rights->facture->lire); - if (empty($leftmenu) || ($leftmenu == 'customers_bills')) { + if (empty($leftmenu) || ($leftmenu == 'customers_bills')) + { $newmenu->add("/compta/facture/list.php?leftmenu=customers_bills&search_status=0",$langs->trans("BillShortStatusDraft"),2,$user->rights->facture->lire); - $newmenu->add("/compta/facture/impayees.php?leftmenu=customers_bills",$langs->trans("BillShortStatusNotPaid"),2,$user->rights->facture->lire); + $newmenu->add("/compta/facture/list.php?leftmenu=customers_bills&search_status=1",$langs->trans("BillShortStatusNotPaid"),2,$user->rights->facture->lire); $newmenu->add("/compta/facture/list.php?leftmenu=customers_bills&search_status=2",$langs->trans("BillShortStatusPaid"),2,$user->rights->facture->lire); $newmenu->add("/compta/facture/list.php?leftmenu=customers_bills&search_status=3",$langs->trans("BillShortStatusCanceled"),2,$user->rights->facture->lire); } - $newmenu->add("/compta/paiement/list.php?leftmenu=customers_bills_payments",$langs->trans("Payments"),1,$user->rights->facture->lire); + $newmenu->add("/compta/paiement/list.php",$langs->trans("Payments"),1,$user->rights->facture->lire); if (! empty($conf->global->BILL_ADD_PAYMENT_VALIDATION)) { - $newmenu->add("/compta/paiement/avalider.php?leftmenu=customers_bills_payments",$langs->trans("MenuToValid"),2,$user->rights->facture->lire); + $newmenu->add("/compta/paiement/avalider.php",$langs->trans("MenuToValid"),2,$user->rights->facture->lire); } - $newmenu->add("/compta/paiement/rapport.php?leftmenu=customers_bills_payments",$langs->trans("Reportings"),2,$user->rights->facture->lire); + $newmenu->add("/compta/paiement/rapport.php",$langs->trans("Reportings"),2,$user->rights->facture->lire); - $newmenu->add("/compta/facture/stats/index.php?leftmenu=customers_bills", $langs->trans("Statistics"),1,$user->rights->facture->lire); + $newmenu->add("/compta/facture/mergepdftool.php",$langs->trans("MergingPDFTool"),1,$user->rights->facture->lire); + + $newmenu->add("/compta/facture/stats/index.php", $langs->trans("Statistics"),1,$user->rights->facture->lire); } // Suppliers @@ -1052,14 +1055,19 @@ function print_left_eldy_menu($db,$menu_array_before,$menu_array_after,&$tabMenu $newmenu->add("/product/index.php?leftmenu=product&type=0", $langs->trans("Products"), 0, $user->rights->produit->lire, '', $mainmenu, 'product'); $newmenu->add("/product/card.php?leftmenu=product&action=create&type=0", $langs->trans("NewProduct"), 1, $user->rights->produit->creer); $newmenu->add("/product/list.php?leftmenu=product&type=0", $langs->trans("List"), 1, $user->rights->produit->lire); - if (! empty($conf->propal->enabled)) - { - $newmenu->add("/product/popuprop.php?leftmenu=stats&type=0", $langs->trans("Statistics"), 1, $user->rights->produit->lire && $user->rights->propale->lire); - } if (! empty($conf->stock->enabled)) { $newmenu->add("/product/reassort.php?type=0", $langs->trans("Stocks"), 1, $user->rights->produit->lire && $user->rights->stock->lire); } + if (! empty($conf->productbatch->enabled)) + { + $langs->load("stocks"); + $newmenu->add("/product/reassortlot.php?type=0", $langs->trans("StocksByLotSerial"), 1, $user->rights->produit->lire && $user->rights->stock->lire); + } + if (! empty($conf->propal->enabled)) + { + $newmenu->add("/product/popuprop.php?leftmenu=stats&type=0", $langs->trans("Statistics"), 1, $user->rights->produit->lire && $user->rights->propale->lire); + } } // Services @@ -1091,8 +1099,8 @@ function print_left_eldy_menu($db,$menu_array_before,$menu_array_after,&$tabMenu $newmenu->add("/product/stock/card.php?action=create", $langs->trans("MenuNewWarehouse"), 1, $user->rights->stock->creer); $newmenu->add("/product/stock/list.php", $langs->trans("List"), 1, $user->rights->stock->lire); $newmenu->add("/product/stock/mouvement.php", $langs->trans("Movements"), 1, $user->rights->stock->mouvement->lire); - if ($conf->fournisseur->enabled) $newmenu->add("/product/stock/replenish.php", $langs->trans("Replenishment"), 1, $user->rights->stock->mouvement->lire && $user->rights->fournisseur->lire); - if ($conf->fournisseur->enabled) $newmenu->add("/product/stock/massstockmove.php", $langs->trans("StockTransfer"), 1, $user->rights->stock->mouvement->lire && $user->rights->fournisseur->lire); + if ($conf->fournisseur->enabled) $newmenu->add("/product/stock/replenish.php", $langs->trans("Replenishment"), 1, $user->rights->stock->mouvement->creer && $user->rights->fournisseur->lire); + $newmenu->add("/product/stock/massstockmove.php", $langs->trans("StockTransfer"), 1, $user->rights->stock->mouvement->creer); } // Expeditions @@ -1102,6 +1110,9 @@ function print_left_eldy_menu($db,$menu_array_before,$menu_array_after,&$tabMenu $newmenu->add("/expedition/index.php?leftmenu=sendings", $langs->trans("Shipments"), 0, $user->rights->expedition->lire, '', $mainmenu, 'sendings'); $newmenu->add("/expedition/card.php?action=create2&leftmenu=sendings", $langs->trans("NewSending"), 1, $user->rights->expedition->creer); $newmenu->add("/expedition/list.php?leftmenu=sendings", $langs->trans("List"), 1, $user->rights->expedition->lire); + if (empty($leftmenu) || $leftmenu=="sendings") $newmenu->add("/expedition/list.php?leftmenu=sendings&viewstatut=0", $langs->trans("StatusSendingDraftShort"), 2, $user->rights->expedition->lire); + if (empty($leftmenu) || $leftmenu=="sendings") $newmenu->add("/expedition/list.php?leftmenu=sendings&viewstatut=1", $langs->trans("StatusSendingValidatedShort"), 2, $user->rights->expedition->lire); + if (empty($leftmenu) || $leftmenu=="sendings") $newmenu->add("/expedition/list.php?leftmenu=sendings&viewstatut=2", $langs->trans("StatusSendingProcessedShort"), 2, $user->rights->expedition->lire); $newmenu->add("/expedition/stats/index.php?leftmenu=sendings", $langs->trans("Statistics"), 1, $user->rights->expedition->lire); } diff --git a/htdocs/core/modules/contract/doc/pdf_strato.modules.php b/htdocs/core/modules/contract/doc/pdf_strato.modules.php index 46364b23d0d..9b5b80ceeaf 100644 --- a/htdocs/core/modules/contract/doc/pdf_strato.modules.php +++ b/htdocs/core/modules/contract/doc/pdf_strato.modules.php @@ -452,7 +452,7 @@ class pdf_strato extends ModelePDFContract * Show top header of page. * * @param PDF $pdf Object PDF - * @param Object $object Object to show + * @param CommonObject $object Object to show * @param int $showaddress 0=no, 1=yes * @param Translate $outputlangs Object lang for output * @return void @@ -631,10 +631,10 @@ class pdf_strato extends ModelePDFContract * Show footer of page. Need this->emetteur object * * @param PDF $pdf PDF - * @param Object $object Object to show + * @param CommonObject $object Object to show * @param Translate $outputlangs Object lang for output * @param int $hidefreetext 1=Hide free text - * @return void + * @return integer */ function _pagefoot(&$pdf,$object,$outputlangs,$hidefreetext=0) { diff --git a/htdocs/core/modules/facture/doc/pdf_crabe.modules.php b/htdocs/core/modules/facture/doc/pdf_crabe.modules.php index 9ee7c7b32b5..c6c290ac204 100644 --- a/htdocs/core/modules/facture/doc/pdf_crabe.modules.php +++ b/htdocs/core/modules/facture/doc/pdf_crabe.modules.php @@ -68,7 +68,7 @@ class pdf_crabe extends ModelePDFFactures */ public $posxprogress; - + /** * Constructor * @@ -303,7 +303,7 @@ class pdf_crabe extends ModelePDFFactures } // Situation invoice handling - if ($object->situation_cycle_ref) + if ($object->situation_cycle_ref) { $this->situationinvoice = True; $progress_width = 14; @@ -342,16 +342,16 @@ class pdf_crabe extends ModelePDFFactures $pdf->writeHTMLCell(190, 3, $this->posxdesc-1, $tab_top-1, dol_htmlentitiesbr($desc_incoterms), 0, 1); $nexY = $pdf->GetY(); $height_incoterms=$nexY-$tab_top; - + // Rect prend une longueur en 3eme param $pdf->SetDrawColor(192,192,192); $pdf->Rect($this->marge_gauche, $tab_top-1, $this->page_largeur-$this->marge_gauche-$this->marge_droite, $height_incoterms+1); - + $tab_top = $nexY+6; $height_incoterms += 4; } } - + // Affiche notes $notetoshow=empty($object->note_public)?'':$object->note_public; if (! empty($conf->global->MAIN_ADD_SALE_REP_SIGNATURE_IN_NOTE)) @@ -534,7 +534,7 @@ class pdf_crabe extends ModelePDFFactures $total_excl_tax = pdf_getlinetotalexcltax($object, $i, $outputlangs, $hidedetails); $pdf->SetXY($this->postotalht, $curY); $pdf->MultiCell($this->page_largeur-$this->marge_droite-$this->postotalht, 3, $total_excl_tax, 0, 'R', 0); - + // Collecte des totaux par valeur de tva dans $this->tva["taux"]=total_tva $prev_progress = $object->lines[$i]->get_prev_progress(); if ($prev_progress > 0) // Compute progress from previous situation @@ -1523,12 +1523,12 @@ class pdf_crabe extends ModelePDFFactures $pdf->MultiCell(100, 3, $outputlangs->transnoentities("DateEcheance")." : " . dol_print_date($object->date_lim_reglement,"day",false,$outputlangs,true), '', 'R'); } - if ($object->client->code_client) + if ($object->thirdparty->code_client) { $posy+=3; $pdf->SetXY($posx,$posy); $pdf->SetTextColor(0,0,60); - $pdf->MultiCell(100, 3, $outputlangs->transnoentities("CustomerCode")." : " . $outputlangs->transnoentities($object->client->code_client), '', 'R'); + $pdf->MultiCell(100, 3, $outputlangs->transnoentities("CustomerCode")." : " . $outputlangs->transnoentities($object->thirdparty->code_client), '', 'R'); } $posy+=1; diff --git a/htdocs/core/modules/import/import_csv.modules.php b/htdocs/core/modules/import/import_csv.modules.php index 22008bb054d..da59679b1be 100644 --- a/htdocs/core/modules/import/import_csv.modules.php +++ b/htdocs/core/modules/import/import_csv.modules.php @@ -376,7 +376,7 @@ class ImportCsv extends ModeleImports if ($obj) $tablewithentity_cache[$tablename]=1; // table contains entity field else $tablewithentity_cache[$tablename]=0; // table does not contains entity field } - else dol_print_error($this->db);; + else dol_print_error($this->db); } else { diff --git a/htdocs/core/modules/import/modules_import.php b/htdocs/core/modules/import/modules_import.php index 49fb7decd69..4fa5052a90a 100644 --- a/htdocs/core/modules/import/modules_import.php +++ b/htdocs/core/modules/import/modules_import.php @@ -63,7 +63,7 @@ class ModeleImports * Charge en memoire et renvoie la liste des modeles actifs * * @param DoliDB $db Database handler - * @param string $maxfilenamelength Max length of value to show + * @param integer $maxfilenamelength Max length of value to show * @return array List of templates */ function liste_modeles($db,$maxfilenamelength=0) diff --git a/htdocs/core/modules/livraison/modules_livraison.php b/htdocs/core/modules/livraison/modules_livraison.php index 22c25bcfd5f..0a439ed8fe7 100644 --- a/htdocs/core/modules/livraison/modules_livraison.php +++ b/htdocs/core/modules/livraison/modules_livraison.php @@ -42,7 +42,7 @@ abstract class ModelePDFDeliveryOrder extends CommonDocGenerator * Return list of active generation modules * * @param DoliDB $db Database handler - * @param string $maxfilenamelength Max length of value to show + * @param integer $maxfilenamelength Max length of value to show * @return array List of templates */ static function liste_modeles($db,$maxfilenamelength=0) @@ -151,7 +151,7 @@ abstract class ModeleNumRefDeliveryOrder * Create object on disk * * @param DoliDB $db objet base de donnee - * @param Object $object object delivery + * @param Livraison $object object delivery * @param string $modele force le modele a utiliser ('' to not force) * @param Translate $outputlangs objet lang a utiliser pour traduction * @return int 0 if KO, 1 if OK diff --git a/htdocs/core/modules/mailings/contacts1.modules.php b/htdocs/core/modules/mailings/contacts1.modules.php index 3f8df87cd7a..558b83ed53f 100644 --- a/htdocs/core/modules/mailings/contacts1.modules.php +++ b/htdocs/core/modules/mailings/contacts1.modules.php @@ -60,7 +60,7 @@ class mailing_contacts1 extends MailingTargets * array of SQL request that returns two field: * One called "label", One called "nb". * - * @return array Array with SQL requests + * @return string[] Array with SQL requests */ function getSqlArrayForStats() { @@ -85,7 +85,7 @@ class mailing_contacts1 extends MailingTargets * For example if this selector is used to extract 500 different * emails from a text file, this function must return 500. * - * @param string $sql Requete sql de comptage + * @param string $sql Requete sql de comptage * @return int */ function getNbOfRecipients($sql='') diff --git a/htdocs/core/modules/mailings/contacts2.modules.php b/htdocs/core/modules/mailings/contacts2.modules.php index fe49ce56b35..b1e22110f5e 100644 --- a/htdocs/core/modules/mailings/contacts2.modules.php +++ b/htdocs/core/modules/mailings/contacts2.modules.php @@ -152,7 +152,7 @@ class mailing_contacts2 extends MailingTargets /** * Return here number of distinct emails returned by your selector. * - * @param string $sql Requete sql de comptage + * @param string $sql Requete sql de comptage * @return int */ function getNbOfRecipients($sql='') diff --git a/htdocs/core/modules/mailings/contacts3.modules.php b/htdocs/core/modules/mailings/contacts3.modules.php index 92640291088..0c1ccc86d61 100644 --- a/htdocs/core/modules/mailings/contacts3.modules.php +++ b/htdocs/core/modules/mailings/contacts3.modules.php @@ -88,7 +88,7 @@ class mailing_contacts3 extends MailingTargets $sql.= " AND sp.entity IN (".getEntity('societe', 1).")"; $sql.= " AND sp.email NOT IN (SELECT email FROM ".MAIN_DB_PREFIX."mailing_cibles WHERE fk_mailing=".$mailing_id.")"; if ($filtersarray[0] <> 'all') $sql.= " AND cs.fk_categorie = c.rowid"; - if ($filtersarray[0] <> 'all') $sql.= " AND cs.fk_societe = sp.fk_soc"; + if ($filtersarray[0] <> 'all') $sql.= " AND cs.fk_soc = sp.fk_soc"; if ($filtersarray[0] <> 'all') $sql.= " AND c.label = '".$this->db->escape($filtersarray[0])."'"; $sql.= " ORDER BY sp.lastname, sp.firstname"; @@ -144,7 +144,7 @@ class mailing_contacts3 extends MailingTargets $statssql[$i].= " AND sp.email != ''"; // Note that null != '' is false $statssql[$i].= " AND sp.entity IN (".getEntity('societe', 1).")"; $statssql[$i].= " AND cs.fk_categorie = c.rowid"; - $statssql[$i].= " AND cs.fk_societe = sp.fk_soc"; + $statssql[$i].= " AND cs.fk_soc = sp.fk_soc"; $statssql[$i].= " GROUP BY c.label"; $statssql[$i].= " ORDER BY nb DESC"; $statssql[$i].= " LIMIT $i,1"; @@ -157,7 +157,7 @@ class mailing_contacts3 extends MailingTargets /** * Return here number of distinct emails returned by your selector. * - * @param string $sql Requete sql de comptage + * @param string $sql Requete sql de comptage * @return int Number of recipients */ function getNbOfRecipients($sql='') @@ -183,7 +183,7 @@ class mailing_contacts3 extends MailingTargets $sql.= " AND sp.entity IN (".getEntity('societe', 1).")"; $sql.= " AND sp.email != ''"; // Note that null != '' is false $sql.= " AND cs.fk_categorie = c.rowid"; - $sql.= " AND cs.fk_societe = sp.fk_soc"; + $sql.= " AND cs.fk_soc = sp.fk_soc"; */ // La requete doit retourner un champ "nb" pour etre comprise // par parent::getNbOfRecipients @@ -210,7 +210,7 @@ class mailing_contacts3 extends MailingTargets $sql.= " AND sp.no_email = 0"; $sql.= " AND sp.entity IN (".getEntity('societe', 1).")"; $sql.= " AND cs.fk_categorie = c.rowid"; - $sql.= " AND cs.fk_societe = sp.fk_soc"; + $sql.= " AND cs.fk_soc = sp.fk_soc"; $sql.= " GROUP BY c.label"; $sql.= " ORDER BY c.label"; diff --git a/htdocs/core/modules/mailings/contacts4.modules.php b/htdocs/core/modules/mailings/contacts4.modules.php index 59355b372fe..56134d38932 100644 --- a/htdocs/core/modules/mailings/contacts4.modules.php +++ b/htdocs/core/modules/mailings/contacts4.modules.php @@ -145,7 +145,7 @@ class mailing_contacts4 extends MailingTargets $statssql[$i].= " AND sp.email != ''"; // Note that null != '' is false $statssql[$i].= " AND sp.entity IN (".getEntity('societe', 1).")"; $statssql[$i].= " AND cs.fk_categorie = c.rowid"; - $statssql[$i].= " AND cs.fk_societe = sp.fk_soc"; + $statssql[$i].= " AND cs.fk_soc = sp.fk_soc"; $statssql[$i].= " GROUP BY c.label"; $statssql[$i].= " ORDER BY nb DESC"; $statssql[$i].= " LIMIT $i,1"; @@ -158,7 +158,7 @@ class mailing_contacts4 extends MailingTargets /** * Return here number of distinct emails returned by your selector. * - * @param string $sql Requete sql de comptage + * @param string $sql Requete sql de comptage * @return int Number of recipients */ function getNbOfRecipients($sql='') @@ -183,7 +183,7 @@ class mailing_contacts4 extends MailingTargets $sql.= " AND sp.entity IN (".getEntity('societe', 1).")"; $sql.= " AND sp.email != ''"; // Note that null != '' is false $sql.= " AND cs.fk_categorie = c.rowid"; - $sql.= " AND cs.fk_societe = sp.fk_soc"; + $sql.= " AND cs.fk_soc = sp.fk_soc"; */ // La requete doit retourner un champ "nb" pour etre comprise // par parent::getNbOfRecipients diff --git a/htdocs/core/modules/mailings/example.modules.php b/htdocs/core/modules/mailings/example.modules.php index a7eb1b0b839..428285fb20b 100644 --- a/htdocs/core/modules/mailings/example.modules.php +++ b/htdocs/core/modules/mailings/example.modules.php @@ -100,8 +100,8 @@ class mailing_example extends MailingTargets * For example if this selector is used to extract 500 different * emails from a text file, this function must return 500. * - * @param string $sql Requete sql de comptage - * @return int + * @param string $sql Requete sql de comptage + * @return int|string Number of recipient or '?' */ function getNbOfRecipients($sql='') { diff --git a/htdocs/core/modules/mailings/fraise.modules.php b/htdocs/core/modules/mailings/fraise.modules.php index dd6e18dfa91..963e8ef0c28 100644 --- a/htdocs/core/modules/mailings/fraise.modules.php +++ b/htdocs/core/modules/mailings/fraise.modules.php @@ -63,7 +63,7 @@ class mailing_fraise extends MailingTargets * array of SQL request that returns two field: * One called "label", One called "nb". * - * @return array Array with SQL requests + * @return string[] Array with SQL requests */ function getSqlArrayForStats() { @@ -86,8 +86,8 @@ class mailing_fraise extends MailingTargets * For example if this selector is used to extract 500 different * emails from a text file, this function must return 500. * - * @param string $sql Requete sql de comptage - * @return int Nb of recipients + * @param string $sql Requete sql de comptage + * @return int Nb of recipients */ function getNbOfRecipients($sql='') { diff --git a/htdocs/core/modules/mailings/framboise.modules.php b/htdocs/core/modules/mailings/framboise.modules.php index c647466e796..e25ffad5f1b 100644 --- a/htdocs/core/modules/mailings/framboise.modules.php +++ b/htdocs/core/modules/mailings/framboise.modules.php @@ -150,8 +150,8 @@ class mailing_framboise extends MailingTargets * For example if this selector is used to extract 500 different * emails from a text file, this function must return 500. * - * @param string $sql Requete sql de comptage - * @return int Nb of recipients + * @param string $sql Requete sql de comptage + * @return int Nb of recipients */ function getNbOfRecipients($sql='') { diff --git a/htdocs/core/modules/mailings/modules_mailings.php b/htdocs/core/modules/mailings/modules_mailings.php index 5561526a7ff..2508440c147 100644 --- a/htdocs/core/modules/mailings/modules_mailings.php +++ b/htdocs/core/modules/mailings/modules_mailings.php @@ -72,8 +72,8 @@ class MailingTargets // This can't be abstract as it is used for some method /** * Retourne nombre de destinataires * - * @param string $sql Requete sql de comptage - * @return int Nb de destinataires si ok, < 0 si erreur + * @param string $sql Sql request to count + * @return int Nb of recipient, or <0 if error */ function getNbOfRecipients($sql) { @@ -85,7 +85,7 @@ class MailingTargets // This can't be abstract as it is used for some method } else { - $this->error=$this->db->error(); + $this->error=$this->db->lasterror(); return -1; } } diff --git a/htdocs/core/modules/mailings/thirdparties.modules.php b/htdocs/core/modules/mailings/thirdparties.modules.php index df8ec79f988..cfccc1ff673 100644 --- a/htdocs/core/modules/mailings/thirdparties.modules.php +++ b/htdocs/core/modules/mailings/thirdparties.modules.php @@ -74,7 +74,7 @@ class mailing_thirdparties extends MailingTargets $sql.= " WHERE s.email <> ''"; $sql.= " AND s.entity IN (".getEntity('societe', 1).")"; $sql.= " AND s.email NOT IN (SELECT email FROM ".MAIN_DB_PREFIX."mailing_cibles WHERE fk_mailing=".$mailing_id.")"; - $sql.= " AND cs.fk_societe = s.rowid"; + $sql.= " AND cs.fk_soc = s.rowid"; $sql.= " AND c.rowid = cs.fk_categorie"; $sql.= " AND c.rowid='".$this->db->escape($_POST['filter'])."'"; $sql.= " UNION "; @@ -83,7 +83,7 @@ class mailing_thirdparties extends MailingTargets $sql.= " WHERE s.email <> ''"; $sql.= " AND s.entity IN (".getEntity('societe', 1).")"; $sql.= " AND s.email NOT IN (SELECT email FROM ".MAIN_DB_PREFIX."mailing_cibles WHERE fk_mailing=".$mailing_id.")"; - $sql.= " AND cs.fk_societe = s.rowid"; + $sql.= " AND cs.fk_soc = s.rowid"; $sql.= " AND c.rowid = cs.fk_categorie"; $sql.= " AND c.rowid='".$this->db->escape($_POST['filter'])."'"; } @@ -157,7 +157,7 @@ class mailing_thirdparties extends MailingTargets * emails from a text file, this function must return 500. * * @param string $sql Requete sql de comptage - * @return int Nb of recipients + * @return int Nb of recipients */ function getNbOfRecipients($sql='') { diff --git a/htdocs/core/modules/mailings/xinputfile.modules.php b/htdocs/core/modules/mailings/xinputfile.modules.php index 777621fa432..7b6f8361d24 100644 --- a/htdocs/core/modules/mailings/xinputfile.modules.php +++ b/htdocs/core/modules/mailings/xinputfile.modules.php @@ -73,8 +73,8 @@ class mailing_xinputfile extends MailingTargets * For example if this selector is used to extract 500 different * emails from a text file, this function must return 500. * - * @param string $sql Requete sql de comptage - * @return int '' means NA + * @param string $sql Sql request to count + * @return string '' means NA */ function getNbOfRecipients($sql='') { diff --git a/htdocs/core/modules/mailings/xinputuser.modules.php b/htdocs/core/modules/mailings/xinputuser.modules.php index 0d01aa53912..7832d1f6a93 100644 --- a/htdocs/core/modules/mailings/xinputuser.modules.php +++ b/htdocs/core/modules/mailings/xinputuser.modules.php @@ -73,8 +73,8 @@ class mailing_xinputuser extends MailingTargets * For example if this selector is used to extract 500 different * emails from a text file, this function must return 500. * - * @param string $sql Requete sql de comptage - * @return int '' means NA + * @param string $sql Sql request to count + * @return string '' means NA */ function getNbOfRecipients($sql='') { diff --git a/htdocs/core/modules/modBanque.class.php b/htdocs/core/modules/modBanque.class.php index 246aac2b6d7..df698b26a90 100644 --- a/htdocs/core/modules/modBanque.class.php +++ b/htdocs/core/modules/modBanque.class.php @@ -143,9 +143,9 @@ class modBanque extends DolibarrModules $this->export_code[$r]=$this->rights_class.'_'.$r; $this->export_label[$r]='Ecritures bancaires et releves'; $this->export_permission[$r]=array(array("banque","export")); - $this->export_fields_array[$r]=array('b.rowid'=>'IdTransaction','ba.ref'=>'AccountRef','ba.label'=>'AccountLabel','b.datev'=>'DateValue','b.dateo'=>'DateOperation','b.label'=>'Label','b.num_chq'=>'ChequeOrTransferNumber','-b.amount'=>'Debit','b.amount'=>'Credit','b.num_releve'=>'AccountStatement','b.datec'=>"DateCreation","bu.url_id"=>"IdThirdParty","s.nom"=>"ThirdParty","s.code_compta"=>"CustomerAccountancyCode","s.code_compta_fournisseur"=>"SupplierAccountancyCode"); - $this->export_TypeFields_array[$r]=array('ba.ref'=>'Text','ba.label'=>'Text','b.datev'=>'Date','b.dateo'=>'Date','b.label'=>'Text','b.num_chq'=>'Text','-b.amount'=>'Number','b.amount'=>'Number','b.num_releve'=>'Text','b.datec'=>"Date","bu.url_id"=>"Text","s.nom"=>"Text","s.code_compta"=>"Text","s.code_compta_fournisseur"=>"Text"); - $this->export_entities_array[$r]=array('b.rowid'=>'account','ba.ref'=>'account','ba.label'=>'account','b.datev'=>'account','b.dateo'=>'account','b.label'=>'account','b.num_chq'=>'account','-b.amount'=>'account','b.amount'=>'account','b.num_releve'=>'account','b.datec'=>"account","bu.url_id"=>"company","s.nom"=>"company","s.code_compta"=>"company","s.code_compta_fournisseur"=>"company"); + $this->export_fields_array[$r]=array('b.rowid'=>'IdTransaction','ba.ref'=>'AccountRef','ba.label'=>'AccountLabel','b.datev'=>'DateValue','b.dateo'=>'DateOperation','b.label'=>'Label','b.num_chq'=>'ChequeOrTransferNumber','b.fk_bordereau'=>'ChequeBordereau','-b.amount'=>'Debit','b.amount'=>'Credit','b.num_releve'=>'AccountStatement','b.datec'=>"DateCreation","bu.url_id"=>"IdThirdParty","s.nom"=>"ThirdParty","s.code_compta"=>"CustomerAccountancyCode","s.code_compta_fournisseur"=>"SupplierAccountancyCode"); + $this->export_TypeFields_array[$r]=array('ba.ref'=>'Text','ba.label'=>'Text','b.datev'=>'Date','b.dateo'=>'Date','b.label'=>'Text','b.num_chq'=>'Text','b.fk_bordereau'=>'Text','-b.amount'=>'Number','b.amount'=>'Number','b.num_releve'=>'Text','b.datec'=>"Date","bu.url_id"=>"Text","s.nom"=>"Text","s.code_compta"=>"Text","s.code_compta_fournisseur"=>"Text"); + $this->export_entities_array[$r]=array('b.rowid'=>'account','ba.ref'=>'account','ba.label'=>'account','b.datev'=>'account','b.dateo'=>'account','b.label'=>'account','b.num_chq'=>'account','b.fk_bordereau'=>'account','-b.amount'=>'account','b.amount'=>'account','b.num_releve'=>'account','b.datec'=>"account","bu.url_id"=>"company","s.nom"=>"company","s.code_compta"=>"company","s.code_compta_fournisseur"=>"company"); $this->export_special_array[$r]=array('-b.amount'=>'NULLIFNEG','b.amount'=>'NULLIFNEG'); if (empty($conf->fournisseur->enabled)) { @@ -164,11 +164,11 @@ class modBanque extends DolibarrModules $this->export_code[$r]=$this->rights_class.'_'.$r; $this->export_label[$r]='Bordereaux remise Chq/Fact'; $this->export_permission[$r]=array(array("banque","export")); - $this->export_fields_array[$r]=array("bch.number"=>"Numero","bch.ref_ext"=>"RefExt",'ba.ref'=>'AccountRef','ba.label'=>'AccountLabel','b.datev'=>'DateValue','b.num_chq'=>'ChequeOrTransferNumber','b.amount'=>'Credit','b.num_releve'=>'AccountStatement','b.datec'=>"DateCreation", + $this->export_fields_array[$r]=array("bch.rowid"=>"bordereauid","bch.number"=>"Numero","bch.ref_ext"=>"RefExt",'ba.ref'=>'AccountRef','ba.label'=>'AccountLabel','b.datev'=>'DateValue','b.num_chq'=>'ChequeOrTransferNumber','b.amount'=>'Credit','b.num_releve'=>'AccountStatement','b.datec'=>"DateCreation", "bch.date_bordereau"=>"Date","bch.amount"=>"Total","bch.nbcheque"=>"NbCheque","bu.url_id"=>"IdThirdParty","s.nom"=>"ThirdParty","f.facnumber"=>"InvoiceRef" ); $this->export_TypeFields_array[$r]=array('ba.ref'=>'Text','ba.label'=>'Text','b.datev'=>'Date','b.num_chq'=>'Text','b.amount'=>'Number','b.num_releve'=>'Text','b.datec'=>"Date", - "bch.date_bordereau"=>"Date","bch.number"=>"Number","bch.ref_ext"=>"Text","bch.amount"=>"Number","bch.nbcheque"=>"NumBer","bu.url_id"=>"Text","s.nom"=>"Text","f.facnumber"=>"Text" + "bch.date_bordereau"=>"Date","bch.rowid"=>"Number","bch.number"=>"Number","bch.ref_ext"=>"Text","bch.amount"=>"Number","bch.nbcheque"=>"NumBer","bu.url_id"=>"Text","s.nom"=>"Text","f.facnumber"=>"Text" ); $this->export_entities_array[$r]=array('ba.ref'=>'account','ba.label'=>'account','b.datev'=>'account','b.num_chq'=>'account','b.amount'=>'account','b.num_releve'=>'account','b.datec'=>"account", "bu.url_id"=>"company","s.nom"=>"company","s.code_compta"=>"company","s.code_compta_fournisseur"=>"company","f.facnumber"=>"invoice"); diff --git a/htdocs/core/modules/modCategorie.class.php b/htdocs/core/modules/modCategorie.class.php index 3084677c4ef..51a55d0cab0 100644 --- a/htdocs/core/modules/modCategorie.class.php +++ b/htdocs/core/modules/modCategorie.class.php @@ -121,7 +121,7 @@ class modCategorie extends DolibarrModules $this->export_entities_array[$r]=array('s.rowid'=>'company','s.nom'=>'company','s.prefix_comm'=>"company",'s.client'=>"company",'s.datec'=>"company",'s.tms'=>"company",'s.code_client'=>"company",'s.address'=>"company",'s.zip'=>"company",'s.town'=>"company",'c.label'=>"company",'c.code'=>"company",'s.phone'=>"company",'s.fax'=>"company",'s.url'=>"company",'s.email'=>"company",'s.siret'=>"company",'s.siren'=>"company",'s.ape'=>"company",'s.idprof4'=>"company",'s.tva_intra'=>"company",'s.capital'=>"company",'s.note_public'=>"company"); // We define here only fields that use another picto $this->export_sql_start[$r]='SELECT DISTINCT '; $this->export_sql_end[$r] =' FROM '.MAIN_DB_PREFIX.'categorie as u, '.MAIN_DB_PREFIX.'categorie_fournisseur as cf, '.MAIN_DB_PREFIX.'societe as s LEFT JOIN '.MAIN_DB_PREFIX.'c_typent as t ON s.fk_typent = t.id LEFT JOIN '.MAIN_DB_PREFIX.'c_country as c ON s.fk_pays = c.rowid LEFT JOIN '.MAIN_DB_PREFIX.'c_effectif as ce ON s.fk_effectif = ce.id LEFT JOIN '.MAIN_DB_PREFIX.'c_forme_juridique as cfj ON s.fk_forme_juridique = cfj.code'; - $this->export_sql_end[$r] .=' WHERE u.rowid = cf.fk_categorie AND cf.fk_societe = s.rowid'; + $this->export_sql_end[$r] .=' WHERE u.rowid = cf.fk_categorie AND cf.fk_soc = s.rowid'; $this->export_sql_end[$r] .=' AND u.entity IN ('.getEntity('category',1).')'; $this->export_sql_end[$r] .=' AND u.type = 1'; // Supplier categories @@ -136,7 +136,7 @@ class modCategorie extends DolibarrModules $this->export_entities_array[$r]=array('s.rowid'=>'company','s.nom'=>'company','s.prefix_comm'=>"company",'s.client'=>"company",'s.datec'=>"company",'s.tms'=>"company",'s.code_client'=>"company",'s.address'=>"company",'s.zip'=>"company",'s.town'=>"company",'c.label'=>"company",'c.code'=>"company",'s.phone'=>"company",'s.fax'=>"company",'s.url'=>"company",'s.email'=>"company",'s.siret'=>"company",'s.siren'=>"company",'s.ape'=>"company",'s.idprof4'=>"company",'s.tva_intra'=>"company",'s.capital'=>"company",'s.note_public'=>"company",'s.fk_prospectlevel'=>'company','s.fk_stcomm'=>'company'); // We define here only fields that use another picto $this->export_sql_start[$r]='SELECT DISTINCT '; $this->export_sql_end[$r] =' FROM '.MAIN_DB_PREFIX.'categorie as u, '.MAIN_DB_PREFIX.'categorie_societe as cf, '.MAIN_DB_PREFIX.'societe as s LEFT JOIN '.MAIN_DB_PREFIX.'c_typent as t ON s.fk_typent = t.id LEFT JOIN '.MAIN_DB_PREFIX.'c_country as c ON s.fk_pays = c.rowid LEFT JOIN '.MAIN_DB_PREFIX.'c_effectif as ce ON s.fk_effectif = ce.id LEFT JOIN '.MAIN_DB_PREFIX.'c_forme_juridique as cfj ON s.fk_forme_juridique = cfj.code'; - $this->export_sql_end[$r] .=' WHERE u.rowid = cf.fk_categorie AND cf.fk_societe = s.rowid'; + $this->export_sql_end[$r] .=' WHERE u.rowid = cf.fk_categorie AND cf.fk_soc = s.rowid'; $this->export_sql_end[$r] .=' AND u.entity IN ('.getEntity('category',1).')'; $this->export_sql_end[$r] .=' AND u.type = 2'; // Customer/Prospect categories @@ -316,14 +316,14 @@ class modCategorie extends DolibarrModules $this->import_icon[$r]=$this->picto; $this->import_entities_array[$r]=array(); // We define here only fields that use another icon that the one defined into import_icon $this->import_tables_array[$r]=array('cs'=>MAIN_DB_PREFIX.'categorie_societe'); - $this->import_fields_array[$r]=array('cs.fk_categorie'=>"Category*",'cs.fk_societe'=>"ThirdParty*" + $this->import_fields_array[$r]=array('cs.fk_categorie'=>"Category*",'cs.fk_soc'=>"ThirdParty*" ); $this->import_convertvalue_array[$r]=array( 'cs.fk_categorie'=>array('rule'=>'fetchidfromref','classfile'=>'/categories/class/categorie.class.php','class'=>'Categorie','method'=>'fetch','element'=>'category'), - 'cs.fk_societe'=>array('rule'=>'fetchidfromref','classfile'=>'/societe/class/societe.class.php','class'=>'Societe','method'=>'fetch','element'=>'ThirdParty') + 'cs.fk_soc'=>array('rule'=>'fetchidfromref','classfile'=>'/societe/class/societe.class.php','class'=>'Societe','method'=>'fetch','element'=>'ThirdParty') ); - $this->import_examplevalues_array[$r]=array('cs.fk_categorie'=>"Imported category",'cs.fk_societe'=>"MyBigCompany"); + $this->import_examplevalues_array[$r]=array('cs.fk_categorie'=>"Imported category",'cs.fk_soc'=>"MyBigCompany"); } if (! empty($conf->fournisseur->enabled)) @@ -335,14 +335,14 @@ class modCategorie extends DolibarrModules $this->import_icon[$r]=$this->picto; $this->import_entities_array[$r]=array(); // We define here only fields that use another icon that the one defined into import_icon $this->import_tables_array[$r]=array('cs'=>MAIN_DB_PREFIX.'categorie_fournisseur'); - $this->import_fields_array[$r]=array('cs.fk_categorie'=>"Category*",'cs.fk_societe'=>"Supplier*" + $this->import_fields_array[$r]=array('cs.fk_categorie'=>"Category*",'cs.fk_soc'=>"Supplier*" ); $this->import_convertvalue_array[$r]=array( 'cs.fk_categorie'=>array('rule'=>'fetchidfromref','classfile'=>'/categories/class/categorie.class.php','class'=>'Categorie','method'=>'fetch','element'=>'category'), - 'cs.fk_societe'=>array('rule'=>'fetchidfromref','classfile'=>'/societe/class/societe.class.php','class'=>'Societe','method'=>'fetch','element'=>'ThirdParty') + 'cs.fk_soc'=>array('rule'=>'fetchidfromref','classfile'=>'/societe/class/societe.class.php','class'=>'Societe','method'=>'fetch','element'=>'ThirdParty') ); - $this->import_examplevalues_array[$r]=array('cs.fk_categorie'=>"Imported category",'cs.fk_societe'=>"MyBigCompany"); + $this->import_examplevalues_array[$r]=array('cs.fk_categorie'=>"Imported category",'cs.fk_soc'=>"MyBigCompany"); } } diff --git a/htdocs/core/modules/modFournisseur.class.php b/htdocs/core/modules/modFournisseur.class.php index 2e42c1f8b66..dc537426179 100644 --- a/htdocs/core/modules/modFournisseur.class.php +++ b/htdocs/core/modules/modFournisseur.class.php @@ -161,6 +161,14 @@ class modFournisseur extends DolibarrModules $this->rights[$r][4] = 'commande'; $this->rights[$r][5] = 'approuver'; + /*$r++; + $this->rights[$r][0] = 1191; + $this->rights[$r][1] = 'Approuver une commande fournisseur (si supérieur hiérarchique)'; + $this->rights[$r][2] = 'w'; + $this->rights[$r][3] = 0; + $this->rights[$r][4] = 'commande'; + $this->rights[$r][5] = 'approve_ifsupervisor_advance';*/ + $r++; $this->rights[$r][0] = 1186; $this->rights[$r][1] = 'Commander une commande fournisseur'; @@ -250,6 +258,18 @@ class modFournisseur extends DolibarrModules $this->rights[$r][4] = 'commande'; $this->rights[$r][5] = 'export'; + if ($conf->global->SUPPLIER_ORDER_DOUBLE_APPROVAL) + { + $r++; + $this->rights[$r][0] = 1190; + $this->rights[$r][1] = 'Approve supplier order (second level)'; // $langs->trans("Permission1190"); + $this->rights[$r][2] = 'w'; + $this->rights[$r][3] = 0; + $this->rights[$r][4] = 'commande'; + $this->rights[$r][5] = 'approve2'; + } + + // Exports //-------- $r=0; diff --git a/htdocs/core/modules/modProductBatch.class.php b/htdocs/core/modules/modProductBatch.class.php index 50d53f72c57..bf77943ea6c 100644 --- a/htdocs/core/modules/modProductBatch.class.php +++ b/htdocs/core/modules/modProductBatch.class.php @@ -51,7 +51,7 @@ class modProductBatch extends DolibarrModules $this->rights_class = 'productbatch'; // Possible values for version are: 'development', 'experimental', 'dolibarr' or version - $this->version = 'experimental'; + $this->version = 'dolibarr'; // Key used in llx_const table to save module status enabled/disabled (where dluo is value of property name of module in uppercase) $this->const_name = 'MAIN_MODULE_'.strtoupper($this->name); $this->special = 0; @@ -113,15 +113,15 @@ class modProductBatch extends DolibarrModules function init($options='') { global $db,$conf; - + $sql = array(); - + if(! empty($conf->cashdesk->enabled)) { if (!$conf->global->CASHDESK_NO_DECREASE_STOCK) { $res = dolibarr_set_const($db,"CASHDESK_NO_DECREASE_STOCK",1,'chaine',0,'',$conf->entity); } } - + return $this->_init($sql, $options); } diff --git a/htdocs/core/modules/modResource.class.php b/htdocs/core/modules/modResource.class.php index e63f44c3945..da1f807ecac 100644 --- a/htdocs/core/modules/modResource.class.php +++ b/htdocs/core/modules/modResource.class.php @@ -61,7 +61,7 @@ class modResource extends DolibarrModules // (where XXX is value of numeric property 'numero' of module) $this->description = "Manage resources (printers, cars, room, ...) you can then share into events"; // Possible values for version are: 'development', 'experimental' or version - $this->version = 'development'; + $this->version = 'dolibarr'; // Key used in llx_const table to save module status enabled/disabled // (where MYMODULE is value of property name of module in uppercase) $this->const_name = 'MAIN_MODULE_' . strtoupper($this->name); @@ -114,8 +114,7 @@ class modResource extends DolibarrModules $this->requiredby = array('modPlace'); // Minimum version of PHP required by module $this->phpmin = array(5, 3); - // Minimum version of Dolibarr required by module - $this->need_dolibarr_version = array(3, 5); + $this->langfiles = array("resource@resource"); // langfiles@resource // Constants // List of particular constants to add when module is enabled diff --git a/htdocs/core/modules/modStock.class.php b/htdocs/core/modules/modStock.class.php index 8f6840a21b0..63613862550 100644 --- a/htdocs/core/modules/modStock.class.php +++ b/htdocs/core/modules/modStock.class.php @@ -42,7 +42,7 @@ class modStock extends DolibarrModules */ function __construct($db) { - global $conf; + global $conf, $langs; $this->db = $db; $this->numero = 52; @@ -123,16 +123,35 @@ class modStock extends DolibarrModules $this->export_label[$r]="WarehousesAndProducts"; // Translation key (used only if key ExportDataset_xxx_z not found) $this->export_permission[$r]=array(array("stock","lire")); $this->export_fields_array[$r]=array('e.rowid'=>'IdWarehouse','e.label'=>'LocationSummary','e.description'=>'DescWareHouse','e.lieu'=>'LieuWareHouse','e.address'=>'Address','e.zip'=>'Zip','e.town'=>'Town','p.rowid'=>"ProductId",'p.ref'=>"Ref",'p.fk_product_type'=>"Type",'p.label'=>"Label",'p.description'=>"Description",'p.note'=>"Note",'p.price'=>"Price",'p.tva_tx'=>'VAT','p.tosell'=>"OnSell",'p.duration'=>"Duration",'p.datec'=>'DateCreation','p.tms'=>'DateModification','ps.reel'=>'Stock'); - $this->export_TypeFields_array[$r]=array('e.rowid'=>'List:entrepot:LabelWareHouse','e.label'=>'Text','e.lieu'=>'Text','e.address'=>'Text','e.zip'=>'Text','e.town'=>'Text','p.rowid'=>"List:produit:label",'p.ref'=>"Text",'p.fk_product_type'=>"Text",'p.label'=>"Text",'p.description'=>"Text",'p.note'=>"Text",'p.price'=>"Number",'p.tva_tx'=>'Number','p.tosell'=>"Boolean",'p.duration'=>"Duree",'p.datec'=>'Date','p.tms'=>'Date','ps.reel'=>'Number'); + $this->export_TypeFields_array[$r]=array('e.rowid'=>'List:entrepot:label','e.label'=>'Text','e.lieu'=>'Text','e.address'=>'Text','e.zip'=>'Text','e.town'=>'Text','p.rowid'=>"List:product:label",'p.ref'=>"Text",'p.fk_product_type'=>"Text",'p.label'=>"Text",'p.description'=>"Text",'p.note'=>"Text",'p.price'=>"Number",'p.tva_tx'=>'Number','p.tosell'=>"Boolean",'p.duration'=>"Duree",'p.datec'=>'Date','p.tms'=>'Date','ps.reel'=>'Number'); $this->export_entities_array[$r]=array('e.rowid'=>'warehouse','e.label'=>'warehouse','e.description'=>'warehouse','e.lieu'=>'warehouse','e.address'=>'warehouse','e.zip'=>'warehouse','e.town'=>'warehouse','p.rowid'=>"product",'p.ref'=>"product",'p.fk_product_type'=>"product",'p.label'=>"product",'p.description'=>"product",'p.note'=>"product",'p.price'=>"product",'p.tva_tx'=>'product','p.tosell'=>"product",'p.duration'=>"product",'p.datec'=>'product','p.tms'=>'product','ps.reel'=>'stock'); $this->export_aggregate_array[$r]=array('ps.reel'=>'SUM'); // TODO Not used yet - $this->export_dependencies_array[$r]=array('stock'=>array('p.rowid','e.rowid')); // To add unique key if we ask a field of a child to avoid the DISTINCT to discard them - + $this->export_dependencies_array[$r]=array('stock'=>array('p.rowid','e.rowid')); // We must keep this until the aggregate_array is used. To add unique key if we ask a field of a child to avoid the DISTINCT to discard them. $this->export_sql_start[$r]='SELECT DISTINCT '; $this->export_sql_end[$r] =' FROM '.MAIN_DB_PREFIX.'product as p, '.MAIN_DB_PREFIX.'product_stock as ps, '.MAIN_DB_PREFIX.'entrepot as e'; $this->export_sql_end[$r] .=' WHERE p.rowid = ps.fk_product AND ps.fk_entrepot = e.rowid'; $this->export_sql_end[$r] .=' AND e.entity IN ('.getEntity('stock',1).')'; + if ($conf->productbatch->enabled) + { + $langs->load("productbatch"); + + // This request is same than previous but without field ps.stock (real stock in warehouse) and with link to subtable productbatch + $r++; + + $this->export_code[$r]=$this->rights_class.'_'.$r; + $this->export_label[$r]="WarehousesAndProductsBatchDetail"; // Translation key (used only if key ExportDataset_xxx_z not found) + $this->export_permission[$r]=array(array("stock","lire")); + $this->export_fields_array[$r]=array('e.rowid'=>'IdWarehouse','e.label'=>'LocationSummary','e.description'=>'DescWareHouse','e.lieu'=>'LieuWareHouse','e.address'=>'Address','e.zip'=>'Zip','e.town'=>'Town','p.rowid'=>"ProductId",'p.ref'=>"Ref",'p.fk_product_type'=>"Type",'p.label'=>"Label",'p.description'=>"Description",'p.note'=>"Note",'p.price'=>"Price",'p.tva_tx'=>'VAT','p.tosell'=>"OnSell",'p.duration'=>"Duration",'p.datec'=>'DateCreation','p.tms'=>'DateModification','pb.rowid'=>'Id','pb.batch'=>'Batch','pb.eatby'=>'l_eatby','pb.sellby'=>'l_sellby','pb.qty'=>'Qty'); + $this->export_TypeFields_array[$r]=array('e.rowid'=>'List:entrepot:label','e.label'=>'Text','e.lieu'=>'Text','e.address'=>'Text','e.zip'=>'Text','e.town'=>'Text','p.rowid'=>"List:product:label",'p.ref'=>"Text",'p.fk_product_type'=>"Text",'p.label'=>"Text",'p.description'=>"Text",'p.note'=>"Text",'p.price'=>"Number",'p.tva_tx'=>'Number','p.tosell'=>"Boolean",'p.duration'=>"Duree",'p.datec'=>'Date','p.tms'=>'Date','pb.batch'=>'Text','pb.eatby'=>'Date','pb.sellby'=>'Date','pb.qty'=>'Number'); + $this->export_entities_array[$r]=array('e.rowid'=>'warehouse','e.label'=>'warehouse','e.description'=>'warehouse','e.lieu'=>'warehouse','e.address'=>'warehouse','e.zip'=>'warehouse','e.town'=>'warehouse','p.rowid'=>"product",'p.ref'=>"product",'p.fk_product_type'=>"product",'p.label'=>"product",'p.description'=>"product",'p.note'=>"product",'p.price'=>"product",'p.tva_tx'=>'product','p.tosell'=>"product",'p.duration'=>"product",'p.datec'=>'product','p.tms'=>'product','pb.rowid'=>'batch','pb.batch'=>'batch','pb.eatby'=>'batch','pb.sellby'=>'batch','pb.qty'=>'batch'); + $this->export_aggregate_array[$r]=array('ps.reel'=>'SUM'); // TODO Not used yet + $this->export_dependencies_array[$r]=array('batch'=>array('pb.rowid')); // We must keep this until the aggregate_array is used. To add unique key if we ask a field of a child to avoid the DISTINCT to discard them. + $this->export_sql_start[$r]='SELECT DISTINCT '; + $this->export_sql_end[$r] =' FROM '.MAIN_DB_PREFIX.'product as p, '.MAIN_DB_PREFIX.'product_stock as ps, '.MAIN_DB_PREFIX.'entrepot as e, '.MAIN_DB_PREFIX.'product_batch as pb'; + $this->export_sql_end[$r] .=' WHERE p.rowid = ps.fk_product AND ps.fk_entrepot = e.rowid AND ps.rowid = pb.fk_product_stock'; + $this->export_sql_end[$r] .=' AND e.entity IN ('.getEntity('stock',1).')'; + } // Imports //-------- diff --git a/htdocs/core/modules/modUser.class.php b/htdocs/core/modules/modUser.class.php index c683c2b34cc..fd7efdae5bc 100644 --- a/htdocs/core/modules/modUser.class.php +++ b/htdocs/core/modules/modUser.class.php @@ -209,10 +209,10 @@ class modUser extends DolibarrModules $this->export_code[$r]=$this->rights_class.'_'.$r; $this->export_label[$r]='Liste des utilisateurs Dolibarr et attributs'; $this->export_permission[$r]=array(array("user","user","export")); - $this->export_fields_array[$r]=array('u.rowid'=>"Id",'u.login'=>"Login",'u.lastname'=>"Lastname",'u.firstname'=>"Firstname",'u.office_phone'=>'Phone','u.office_fax'=>'Fax','u.email'=>'EMail','u.datec'=>"DateCreation",'u.tms'=>"DateLastModification",'u.admin'=>"Administrator",'u.statut'=>'Status','u.note'=>"Note",'u.datelastlogin'=>'LastConnexion','u.datepreviouslogin'=>'PreviousConnexion','u.fk_socpeople'=>"IdContact",'u.fk_societe'=>"IdCompany",'u.fk_member'=>"MemberId"); - $this->export_TypeFields_array[$r]=array('u.login'=>"Text",'u.lastname'=>"Text",'u.firstname'=>"Text",'u.office_phone'=>'Text','u.office_fax'=>'Text','u.email'=>'Text','u.datec'=>"Date",'u.tms'=>"Date",'u.admin'=>"Boolean",'u.statut'=>'Status','u.note'=>"Text",'u.datelastlogin'=>'Date','u.datepreviouslogin'=>'Date','u.fk_societe'=>"List:societe:nom:rowid",'u.fk_member'=>"List:adherent:nom"); + $this->export_fields_array[$r]=array('u.rowid'=>"Id",'u.login'=>"Login",'u.lastname'=>"Lastname",'u.firstname'=>"Firstname",'u.office_phone'=>'Phone','u.office_fax'=>'Fax','u.email'=>'EMail','u.datec'=>"DateCreation",'u.tms'=>"DateLastModification",'u.admin'=>"Administrator",'u.statut'=>'Status','u.note'=>"Note",'u.datelastlogin'=>'LastConnexion','u.datepreviouslogin'=>'PreviousConnexion','u.fk_socpeople'=>"IdContact",'u.fk_soc'=>"IdCompany",'u.fk_member'=>"MemberId"); + $this->export_TypeFields_array[$r]=array('u.login'=>"Text",'u.lastname'=>"Text",'u.firstname'=>"Text",'u.office_phone'=>'Text','u.office_fax'=>'Text','u.email'=>'Text','u.datec'=>"Date",'u.tms'=>"Date",'u.admin'=>"Boolean",'u.statut'=>'Status','u.note'=>"Text",'u.datelastlogin'=>'Date','u.datepreviouslogin'=>'Date','u.fk_soc'=>"List:societe:nom:rowid",'u.fk_member'=>"List:adherent:nom"); - $this->export_entities_array[$r]=array('u.rowid'=>"user",'u.login'=>"user",'u.lastname'=>"user",'u.firstname'=>"user",'u.office_phone'=>'user','u.office_fax'=>'user','u.email'=>'user','u.datec'=>"user",'u.tms'=>"user",'u.admin'=>"user",'u.statut'=>'user','u.note'=>"user",'u.datelastlogin'=>'user','u.datepreviouslogin'=>'user','u.fk_socpeople'=>"contact",'u.fk_societe'=>"company",'u.fk_member'=>"member"); + $this->export_entities_array[$r]=array('u.rowid'=>"user",'u.login'=>"user",'u.lastname'=>"user",'u.firstname'=>"user",'u.office_phone'=>'user','u.office_fax'=>'user','u.email'=>'user','u.datec'=>"user",'u.tms'=>"user",'u.admin'=>"user",'u.statut'=>'user','u.note'=>"user",'u.datelastlogin'=>'user','u.datepreviouslogin'=>'user','u.fk_socpeople'=>"contact",'u.fk_soc'=>"company",'u.fk_member'=>"member"); if (empty($conf->adherent->enabled)) { unset($this->export_fields_array[$r]['u.fk_member']); diff --git a/htdocs/core/modules/printing/modules_printing.php b/htdocs/core/modules/printing/modules_printing.php index 3b53711f58c..7bb9ac98f58 100644 --- a/htdocs/core/modules/printing/modules_printing.php +++ b/htdocs/core/modules/printing/modules_printing.php @@ -49,7 +49,7 @@ class PrintingDriver * Return list of printing driver * * @param DoliDB $db Database handler - * @param string $maxfilenamelength Max length of value to show + * @param integer $maxfilenamelength Max length of value to show * @return array List of drivers */ static function listDrivers($db,$maxfilenamelength=0) diff --git a/htdocs/core/modules/printing/printgcp.modules.php b/htdocs/core/modules/printing/printgcp.modules.php index 302adaeb965..a0e0d37d074 100644 --- a/htdocs/core/modules/printing/printgcp.modules.php +++ b/htdocs/core/modules/printing/printgcp.modules.php @@ -254,7 +254,7 @@ class printing_printgcp extends PrintingDriver /** * Login into Google Account * - * @return string true or false + * @return boolean true or false */ function GoogleLogin() { @@ -324,8 +324,8 @@ class printing_printgcp extends PrintingDriver * * @param string $url url to hit * @param array $postfields array of post fields - * @param array $headers array of http headers - * @return array response from curl + * @param string[] $headers array of http headers + * @return string response from curl */ private function makeCurl($url,$postfields=array(),$headers=array()) { diff --git a/htdocs/core/modules/product/modules_product.class.php b/htdocs/core/modules/product/modules_product.class.php index 0bfd3f8f03e..e08ea074bbd 100644 --- a/htdocs/core/modules/product/modules_product.class.php +++ b/htdocs/core/modules/product/modules_product.class.php @@ -105,7 +105,7 @@ abstract class ModeleProductCode * Renvoi la liste des modeles de numérotation * * @param DoliDB $db Database handler - * @param string $maxfilenamelength Max length of value to show + * @param integer $maxfilenamelength Max length of value to show * @return array List of numbers */ static function liste_modeles($db,$maxfilenamelength=0) diff --git a/htdocs/core/modules/project/doc/doc_generic_project_odt.modules.php b/htdocs/core/modules/project/doc/doc_generic_project_odt.modules.php index f19d8a0e3a0..6e2601797f8 100644 --- a/htdocs/core/modules/project/doc/doc_generic_project_odt.modules.php +++ b/htdocs/core/modules/project/doc/doc_generic_project_odt.modules.php @@ -105,7 +105,7 @@ class doc_generic_project_odt extends ModelePDFProjects /** * Define array with couple substitution key => substitution value * - * @param Object $object Main object to use as data source + * @param Project $object Main object to use as data source * @param Translate $outputlangs Lang object to use for output * @return array Array of substitution */ diff --git a/htdocs/core/modules/project/task/doc/doc_generic_task_odt.modules.php b/htdocs/core/modules/project/task/doc/doc_generic_task_odt.modules.php index 8a9669dadf1..31172a32f43 100644 --- a/htdocs/core/modules/project/task/doc/doc_generic_task_odt.modules.php +++ b/htdocs/core/modules/project/task/doc/doc_generic_task_odt.modules.php @@ -416,7 +416,7 @@ class doc_generic_task_odt extends ModelePDFTask $project= new Project($this->db); $project->fetch($object->fk_project); - $dir = $conf->projet->dir_output. "/" . $project->ref. "/";; + $dir = $conf->projet->dir_output. "/" . $project->ref. "/"; $objectref = dol_sanitizeFileName($object->ref); if (! preg_match('/specimen/i',$objectref)) $dir.= "/" . $objectref; $file = $dir . "/" . $objectref . ".odt"; diff --git a/htdocs/core/modules/propale/doc/pdf_azur.modules.php b/htdocs/core/modules/propale/doc/pdf_azur.modules.php index f560bc97653..00c1c61ed57 100644 --- a/htdocs/core/modules/propale/doc/pdf_azur.modules.php +++ b/htdocs/core/modules/propale/doc/pdf_azur.modules.php @@ -617,6 +617,57 @@ class pdf_azur extends ModelePDFPropales $this->_pagefoot($pdf,$object,$outputlangs); if (method_exists($pdf,'AliasNbPages')) $pdf->AliasNbPages(); + //If propal merge product PDF is active + if (!empty($conf->global->PRODUIT_PDF_MERGE_PROPAL)) + { + require_once DOL_DOCUMENT_ROOT.'/product/class/propalmergepdfproduct.class.php'; + + $already_merged = array (); + foreach ( $object->lines as $line ) { + if (! empty($line->fk_product) && ! (in_array($line->fk_product, $already_merged))) { + // Find the desire PDF + $filetomerge = new Propalmergepdfproduct($this->db); + + if ($conf->global->MAIN_MULTILANGS) { + $filetomerge->fetch_by_product($line->fk_product, $outputlangs->defaultlang); + } else { + $filetomerge->fetch_by_product($line->fk_product); + } + + $already_merged[] = $line->fk_product; + + // If PDF is selected and file is not empty + if (count($filetomerge->lines) > 0) { + foreach ( $filetomerge->lines as $linefile ) { + if (! empty($linefile->id) && ! empty($linefile->file_name)) { + if (! empty($conf->product->enabled)) + $filetomerge_dir = $conf->product->multidir_output[$conf->entity] . '/' . dol_sanitizeFileName($line->product_ref); + elseif (! empty($conf->service->enabled)) + $filetomerge_dir = $conf->service->multidir_output[$conf->entity] . '/' . dol_sanitizeFileName($line->product_ref); + + dol_syslog(get_class($this) . ':: upload_dir=' . $filetomerge_dir, LOG_DEBUG); + + $infile = $filetomerge_dir . '/' . $linefile->file_name; + if (is_file($infile)) { + $pagecount = $pdf->setSourceFile($infile); + for($i = 1; $i <= $pagecount; $i ++) { + $tplidx = $pdf->ImportPage($i); + $s = $pdf->getTemplatesize($tplidx); + $pdf->AddPage($s['h'] > $s['w'] ? 'P' : 'L'); + $pdf->useTemplate($tplidx); + } + } + } + } + } + } + } + } + + //exit; + + + $pdf->Close(); $pdf->Output($file,'F'); diff --git a/htdocs/core/modules/propale/modules_propale.php b/htdocs/core/modules/propale/modules_propale.php index 9b0cc1d82a2..9ad90e9e3b5 100644 --- a/htdocs/core/modules/propale/modules_propale.php +++ b/htdocs/core/modules/propale/modules_propale.php @@ -43,7 +43,7 @@ abstract class ModelePDFPropales extends CommonDocGenerator * Return list of active generation modules * * @param DoliDB $db Database handler - * @param string $maxfilenamelength Max length of value to show + * @param integer $maxfilenamelength Max length of value to show * @return array List of templates */ static function liste_modeles($db,$maxfilenamelength=0) @@ -149,7 +149,7 @@ abstract class ModeleNumRefPropales * Create a document onto disk according to template module. * * @param DoliDB $db Database handler - * @param object $object Object proposal + * @param Propal $object Object proposal * @param string $modele Force model to use ('' to not force) * @param Translate $outputlangs Object langs to use for output * @param int $hidedetails Hide details of lines diff --git a/htdocs/core/modules/rapport/pdf_paiement.class.php b/htdocs/core/modules/rapport/pdf_paiement.class.php index b7aea75836f..83bbb0a59b4 100644 --- a/htdocs/core/modules/rapport/pdf_paiement.class.php +++ b/htdocs/core/modules/rapport/pdf_paiement.class.php @@ -60,8 +60,8 @@ class pdf_paiement $this->tab_top = 30; $this->line_height = 5; - $this->line_per_page = 25; - $this->tab_height = 230; //$this->line_height * $this->line_per_page; + $this->line_per_page = 40; + $this->tab_height = $this->page_hauteur - $this->marge_haute - $this->marge_basse - $this->tab_top - 5; // must be > $this->line_height * $this->line_per_page and < $this->page_hauteur - $this->marge_haute - $this->marge_basse - $this->tab_top - 5; $this->posxdate=$this->marge_gauche+2; $this->posxpaymenttype=42; @@ -71,6 +71,7 @@ class pdf_paiement $this->posxpaymentamount=162; if ($this->page_largeur < 210) // To work with US executive format { + $this->line_per_page = 35; $this->posxpaymenttype-=10; $this->posxinvoice-=0; $this->posxinvoiceamount-=10; @@ -145,6 +146,17 @@ class pdf_paiement $num=0; $lines=array(); + // count number of ligne of payement + $sql = "SELECT p.rowid as prowid"; + $sql.= " FROM ".MAIN_DB_PREFIX."paiement as p"; + $sql.= " WHERE p.datep BETWEEN '".$this->db->idate(dol_get_first_day($year,$month))."' AND '".$this->db->idate(dol_get_last_day($year,$month))."'"; + $result = $this->db->query($sql); + if ($result) + { + $numpaiement = $this->db->num_rows($result); + } + + // number of bill $sql = "SELECT p.datep as dp, f.facnumber"; //$sql .= ", c.libelle as paiement_type, p.num_paiement"; $sql.= ", c.code as paiement_code, p.num_paiement"; @@ -201,9 +213,9 @@ class pdf_paiement dol_print_error($this->db); } - $pages = intval($num / $this->line_per_page); + $pages = intval(($num + $numpaiement) / $this->line_per_page); - if (($lines % $this->line_per_page)>0) + if ((($num + $numpaiement) % $this->line_per_page)>0) { $pages++; } @@ -231,7 +243,7 @@ class pdf_paiement // New page $pdf->AddPage(); $pagenb++; - $this->_pagehead($pdf, $pages, 1, $outputlangs); + $this->_pagehead($pdf, $pagenb, 1, $outputlangs); $pdf->SetFont('','', 9); $pdf->MultiCell(0, 3, ''); // Set interline to 3 $pdf->SetTextColor(0,0,0); @@ -292,8 +304,8 @@ class pdf_paiement $pdf->SetXY($this->posxdate, 16); $pdf->MultiCell(80, 2, $outputlangs->transnoentities("DateBuild")." : ".dol_print_date(time(),"day",false,$outputlangs,true), 0, 'L'); - $pdf->SetXY($this->posxdate, 22); - $pdf->MultiCell(80, 2, $outputlangs->transnoentities("Page")." : ".$page, 0, 'L'); + $pdf->SetXY($this->posxdate+100, 16); + $pdf->MultiCell(80, 2, $outputlangs->transnoentities("Page")." : ".$page, 0, 'R'); // Title line @@ -348,9 +360,17 @@ class pdf_paiement for ($j = 0 ; $j < $numlines ; $j++) { $i = $j; + if ($yp > $this->tab_height -5) + { + $page++; + $pdf->AddPage(); + $this->_pagehead($pdf, $page, 0, $outputlangs); + $pdf->SetFont('','', $default_font_size - 1); + $yp = 0; + } if ($oldprowid <> $lines[$j][7]) { - if ($yp > 200) + if ($yp > $this->tab_height -10) { $page++; $pdf->AddPage(); @@ -380,7 +400,7 @@ class pdf_paiement // BankAccount $pdf->SetXY($this->posxbankaccount, $this->tab_top + 10 + $yp); $pdf->MultiCell($this->posxbankaccount - $this->posxdate, $this->line_height, $lines[$j][8], 0, 'L', 0); - + // Invoice amount $pdf->SetXY($this->posxinvoiceamount, $this->tab_top + 10 + $yp); $pdf->MultiCell($this->posxpaymentamount- $this->posxinvoiceamount - 1, $this->line_height, $lines[$j][5], 0, 'R', 0); diff --git a/htdocs/core/modules/societe/modules_societe.class.php b/htdocs/core/modules/societe/modules_societe.class.php index f1fc05d29db..72090a581ea 100644 --- a/htdocs/core/modules/societe/modules_societe.class.php +++ b/htdocs/core/modules/societe/modules_societe.class.php @@ -39,7 +39,7 @@ abstract class ModeleThirdPartyDoc extends CommonDocGenerator * Return list of active generation modules * * @param DoliDB $db Database handler - * @param string $maxfilenamelength Max length of value to show + * @param integer $maxfilenamelength Max length of value to show * @return array List of templates */ static function liste_modeles($db,$maxfilenamelength=0) @@ -142,7 +142,7 @@ abstract class ModeleThirdPartyCode * Renvoi la liste des modeles de numéroation * * @param DoliDB $db Database handler - * @param string $maxfilenamelength Max length of value to show + * @param integer $maxfilenamelength Max length of value to show * @return array List of numbers */ static function liste_modeles($db,$maxfilenamelength=0) diff --git a/htdocs/core/modules/supplier_invoice/modules_facturefournisseur.php b/htdocs/core/modules/supplier_invoice/modules_facturefournisseur.php index 51eb675057e..03dc42280cb 100644 --- a/htdocs/core/modules/supplier_invoice/modules_facturefournisseur.php +++ b/htdocs/core/modules/supplier_invoice/modules_facturefournisseur.php @@ -41,7 +41,7 @@ abstract class ModelePDFSuppliersInvoices extends CommonDocGenerator * Return list of active generation models * * @param DoliDB $db Database handler - * @param string $maxfilenamelength Max length of value to show + * @param integer $maxfilenamelength Max length of value to show * @return array List of numbers */ static function liste_modeles($db,$maxfilenamelength=0) diff --git a/htdocs/core/modules/supplier_invoice/pdf/pdf_canelle.modules.php b/htdocs/core/modules/supplier_invoice/pdf/pdf_canelle.modules.php index 78d7f42fab2..8b803eece33 100644 --- a/htdocs/core/modules/supplier_invoice/pdf/pdf_canelle.modules.php +++ b/htdocs/core/modules/supplier_invoice/pdf/pdf_canelle.modules.php @@ -274,16 +274,16 @@ class pdf_canelle extends ModelePDFSuppliersInvoices $pdf->writeHTMLCell(190, 3, $this->posxdesc-1, $tab_top-1, dol_htmlentitiesbr($desc_incoterms), 0, 1); $nexY = $pdf->GetY(); $height_incoterms=$nexY-$tab_top; - + // Rect prend une longueur en 3eme param $pdf->SetDrawColor(192,192,192); $pdf->Rect($this->marge_gauche, $tab_top-1, $this->page_largeur-$this->marge_gauche-$this->marge_droite, $height_incoterms+1); - + $tab_top = $nexY+6; $height_incoterms += 4; } } - + // Affiche notes if (! empty($object->note_public)) { @@ -819,7 +819,7 @@ class pdf_canelle extends ModelePDFSuppliersInvoices * Show payments table * * @param PDF $pdf Object PDF - * @param Object $object Object invoice + * @param FactureFournisseur $object Object invoice * @param int $posy Position y in PDF * @param Translate $outputlangs Object langs for output * @return int <0 if KO, >0 if OK @@ -903,7 +903,7 @@ class pdf_canelle extends ModelePDFSuppliersInvoices * Show top header of page. * * @param PDF $pdf Object PDF - * @param Object $object Object to show + * @param FactureFournisseur $object Object to show * @param int $showaddress 0=no, 1=yes * @param Translate $outputlangs Object lang for output * @return void @@ -957,46 +957,57 @@ class pdf_canelle extends ModelePDFSuppliersInvoices $pdf->SetXY($posx,$posy); $pdf->SetTextColor(0,0,60); $pdf->MultiCell(100, 3, $outputlangs->transnoentities("SupplierInvoice")." ".$outputlangs->convToOutputCharset($object->ref), '', 'R'); - - $pdf->SetFont('','B', $default_font_size); + $posy+=1; if ($object->ref_supplier) { $posy+=4; + $pdf->SetFont('','B', $default_font_size); $pdf->SetXY($posx,$posy); $pdf->SetTextColor(0,0,60); $pdf->MultiCell(100, 4, $outputlangs->transnoentities("RefSupplier")." : " . $object->ref_supplier, '', 'R'); + $posy+=1; } $pdf->SetFont('','', $default_font_size - 1); - $posy+=6; if (! empty($conf->global->PDF_SHOW_PROJECT)) { $object->fetch_projet(); - $pdf->SetXY($posx,$posy); if (! empty($object->project->ref)) { - $langs->load("projects"); + $posy+=4; + $pdf->SetXY($posx,$posy); + $langs->load("projects"); $pdf->SetTextColor(0,0,60); $pdf->MultiCell(100, 3, $outputlangs->transnoentities("Project")." : " . (empty($object->project->ref)?'':$object->projet->ref), '', 'R'); - $posy+=4; } } - $pdf->SetXY($posx,$posy); if ($object->date) { + $posy+=4; + $pdf->SetXY($posx,$posy); $pdf->SetTextColor(0,0,60); $pdf->MultiCell(100, 4, $outputlangs->transnoentities("Date")." : " . dol_print_date($object->date,"day",false,$outputlangs,true), '', 'R'); } else { + $posy+=4; + $pdf->SetXY($posx,$posy); $pdf->SetTextColor(255,0,0); $pdf->MultiCell(100, 4, strtolower($outputlangs->transnoentities("OrderToProcess")), '', 'R'); } - $posy+=2; + if ($object->thirdparty->code_fournisseur) + { + $posy+=4; + $pdf->SetXY($posx,$posy); + $pdf->SetTextColor(0,0,60); + $pdf->MultiCell(100, 3, $outputlangs->transnoentities("SupplierCode")." : " . $outputlangs->transnoentities($object->thirdparty->code_fournisseur), '', 'R'); + } + + $posy+=1; $pdf->SetTextColor(0,0,60); // Show list of linked objects @@ -1090,7 +1101,7 @@ class pdf_canelle extends ModelePDFSuppliersInvoices * Show footer of page. Need this->emetteur object * * @param PDF $pdf PDF - * @param Object $object Object to show + * @param FactureFournisseur $object Object to show * @param Translate $outputlangs Object lang for output * @param int $hidefreetext 1=Hide free text * @return int Return height of bottom margin including footer text diff --git a/htdocs/core/modules/supplier_order/modules_commandefournisseur.php b/htdocs/core/modules/supplier_order/modules_commandefournisseur.php index bc544363b39..a968955ea73 100644 --- a/htdocs/core/modules/supplier_order/modules_commandefournisseur.php +++ b/htdocs/core/modules/supplier_order/modules_commandefournisseur.php @@ -44,7 +44,7 @@ abstract class ModelePDFSuppliersOrders extends CommonDocGenerator * Return list of active generation models * * @param DoliDB $db Database handler - * @param string $maxfilenamelength Max length of value to show + * @param integer $maxfilenamelength Max length of value to show * @return array List of templates */ static function liste_modeles($db,$maxfilenamelength=0) @@ -143,7 +143,7 @@ abstract class ModeleNumRefSuppliersOrders * Create a document onto disk according to template model. * * @param DoliDB $db Database handler - * @param Object $object Object supplier order + * @param CommandeFournisseur $object Object supplier order * @param string $modele Force template to use ('' to not force) * @param Translate $outputlangs Object lang to use for traduction * @param int $hidedetails Hide details of lines diff --git a/htdocs/core/modules/supplier_order/pdf/pdf_muscadet.modules.php b/htdocs/core/modules/supplier_order/pdf/pdf_muscadet.modules.php index 9a0291d5e8d..ef34c1bf50b 100644 --- a/htdocs/core/modules/supplier_order/pdf/pdf_muscadet.modules.php +++ b/htdocs/core/modules/supplier_order/pdf/pdf_muscadet.modules.php @@ -282,16 +282,16 @@ class pdf_muscadet extends ModelePDFSuppliersOrders $pdf->writeHTMLCell(190, 3, $this->posxdesc-1, $tab_top-1, dol_htmlentitiesbr($desc_incoterms), 0, 1); $nexY = $pdf->GetY(); $height_incoterms=$nexY-$tab_top; - + // Rect prend une longueur en 3eme param $pdf->SetDrawColor(192,192,192); $pdf->Rect($this->marge_gauche, $tab_top-1, $this->page_largeur-$this->marge_gauche-$this->marge_droite, $height_incoterms+1); - + $tab_top = $nexY+6; $height_incoterms += 4; } } - + // Affiche notes if (! empty($object->note_public)) { @@ -1001,51 +1001,67 @@ class pdf_muscadet extends ModelePDFSuppliersOrders $pdf->SetTextColor(0,0,60); $title=$outputlangs->transnoentities("SupplierOrder")." ".$outputlangs->convToOutputCharset($object->ref); $pdf->MultiCell(100, 3, $title, '', 'R'); - - $pdf->SetFont('','B', $default_font_size); + $posy+=1; if ($object->ref_supplier) { $posy+=4; + $pdf->SetFont('','B', $default_font_size); $pdf->SetXY($posx,$posy); $pdf->SetTextColor(0,0,60); $pdf->MultiCell(100, 3, $outputlangs->transnoentities("RefSupplier")." : " . $outputlangs->convToOutputCharset($object->ref_supplier), '', 'R'); + $posy+=1; } $pdf->SetFont('','', $default_font_size -1); - $posy+=6; if (! empty($conf->global->PDF_SHOW_PROJECT)) { $object->fetch_projet(); - $pdf->SetXY($posx,$posy); if (! empty($object->project->ref)) { + $posy+=4; + $pdf->SetXY($posx,$posy); $langs->load("projects"); $pdf->SetTextColor(0,0,60); $pdf->MultiCell(100, 3, $outputlangs->transnoentities("Project")." : " . (empty($object->project->ref)?'':$object->projet->ref), '', 'R'); - $posy+=4; } } - $pdf->SetXY($posx,$posy); if (! empty($object->date_commande)) { + $posy+=4; + $pdf->SetXY($posx,$posy); $pdf->SetTextColor(0,0,60); $pdf->MultiCell(100, 3, $outputlangs->transnoentities("OrderDate")." : " . dol_print_date($object->date_commande,"day",false,$outputlangs,true), '', 'R'); } else { + $posy+=4; + $pdf->SetXY($posx,$posy); $pdf->SetTextColor(255,0,0); $pdf->MultiCell(100, 3, $outputlangs->transnoentities("OrderToProcess"), '', 'R'); } $pdf->SetTextColor(0,0,60); $usehourmin='day'; - if ( empty($conf->global->SUPPLIER_ORDER_USE_HOUR_FOR_DELIVERY_DATE)) $usehourmin='dayhour'; - if (! empty($object->date_livraison)) $pdf->MultiCell(190, 3, $outputlangs->transnoentities("DateDeliveryPlanned")." : " . dol_print_date($object->date_livraison,$usehourmin,false,$outputlangs,true), '', 'R'); + if (empty($conf->global->SUPPLIER_ORDER_USE_HOUR_FOR_DELIVERY_DATE)) $usehourmin='dayhour'; + if (! empty($object->date_livraison)) + { + $posy+=4; + $pdf->SetXY($posx-90,$posy); + $pdf->MultiCell(190, 3, $outputlangs->transnoentities("DateDeliveryPlanned")." : " . dol_print_date($object->date_livraison,$usehourmin,false,$outputlangs,true), '', 'R'); + } - $posy+=5; + if ($object->thirdparty->code_fournisseur) + { + $posy+=4; + $pdf->SetXY($posx,$posy); + $pdf->SetTextColor(0,0,60); + $pdf->MultiCell(100, 3, $outputlangs->transnoentities("SupplierCode")." : " . $outputlangs->transnoentities($object->thirdparty->code_fournisseur), '', 'R'); + } + + $posy+=1; $pdf->SetTextColor(0,0,60); // Show list of linked objects diff --git a/htdocs/core/modules/syslog/mod_syslog_chromephp.php b/htdocs/core/modules/syslog/mod_syslog_chromephp.php index 3e24901f5af..9ea39caaf50 100644 --- a/htdocs/core/modules/syslog/mod_syslog_chromephp.php +++ b/htdocs/core/modules/syslog/mod_syslog_chromephp.php @@ -55,7 +55,7 @@ class mod_syslog_chromephp extends LogHandler implements LogHandlerInterface set_include_path($conf->global->SYSLOG_CHROMEPHP_INCLUDEPATH); //print 'rrrrr'.get_include_path(); - $res = include_once('ChromePhp.php'); + $res = @include_once('ChromePhp.php'); if (! $res) $res=@include_once('ChromePhp.class.php'); restore_include_path(); diff --git a/htdocs/core/tpl/admin_extrafields_add.tpl.php b/htdocs/core/tpl/admin_extrafields_add.tpl.php index f5e6c957b1a..269232ddb76 100644 --- a/htdocs/core/tpl/admin_extrafields_add.tpl.php +++ b/htdocs/core/tpl/admin_extrafields_add.tpl.php @@ -56,7 +56,7 @@ else if (type == 'boolean') { size.val('').attr('disabled','disabled'); unique.attr('disabled','disabled'); jQuery("#value_choice").hide();jQuery("#helpchkbxlst").hide();} else if (type == 'price') { size.val('').attr('disabled','disabled'); unique.attr('disabled','disabled'); jQuery("#value_choice").hide();jQuery("#helpchkbxlst").hide();} else if (type == 'select') { size.val('').attr('disabled','disabled'); unique.attr('disabled','disabled'); jQuery("#value_choice").show();jQuery("#helpselect").show();jQuery("#helpsellist").hide();jQuery("#helpchkbxlst").hide();jQuery("#helplink").hide();} - else if (type == 'link') { size.val('').attr('disabled','disabled'); unique.attr('disabled','disabled'); jQuery("#value_choice").show();jQuery("#helpselect").hide();jQuery("#helpsellist").hide();;jQuery("#helpchkbxlst").hide();jQuery("#helplink").show();} + else if (type == 'link') { size.val('').attr('disabled','disabled'); unique.attr('disabled','disabled'); jQuery("#value_choice").show();jQuery("#helpselect").hide();jQuery("#helpsellist").hide();jQuery("#helpchkbxlst").hide();jQuery("#helplink").show();} else if (type == 'sellist') { size.val('').attr('disabled','disabled'); unique.attr('disabled','disabled'); jQuery("#value_choice").show();jQuery("#helpselect").hide();jQuery("#helpsellist").show();jQuery("#helpchkbxlst").hide();jQuery("#helplink").hide();} else if (type == 'radio') { size.val('').attr('disabled','disabled'); unique.attr('disabled','disabled'); jQuery("#value_choice").show();jQuery("#helpselect").show();jQuery("#helpsellist").hide();jQuery("#helpchkbxlst").hide();jQuery("#helplink").hide();} else if (type == 'checkbox') { size.val('').attr('disabled','disabled'); unique.attr('disabled','disabled'); jQuery("#value_choice").show();jQuery("#helpselect").show();jQuery("#helpsellist").hide();jQuery("#helpchkbxlst").hide();jQuery("#helplink").hide();} diff --git a/htdocs/core/tpl/admin_extrafields_edit.tpl.php b/htdocs/core/tpl/admin_extrafields_edit.tpl.php index 76713be57df..9ce0183ab50 100644 --- a/htdocs/core/tpl/admin_extrafields_edit.tpl.php +++ b/htdocs/core/tpl/admin_extrafields_edit.tpl.php @@ -99,7 +99,7 @@ if(($type == 'select') || ($type == 'sellist') || ($type == 'checkbox') || ($typ diff --git a/htdocs/core/tpl/objectline_edit.tpl.php b/htdocs/core/tpl/objectline_edit.tpl.php index 035a24d3b7f..f93595456d2 100644 --- a/htdocs/core/tpl/objectline_edit.tpl.php +++ b/htdocs/core/tpl/objectline_edit.tpl.php @@ -23,6 +23,7 @@ * $object (invoice, order, ...) * $conf * $langs + * $seller, $nuyer * $dateSelector * $forceall (0 by default, 1 for supplier invoices/orders) * $senderissupplier (0 by default, 1 for supplier invoices/orders) diff --git a/htdocs/core/tpl/objectline_view.tpl.php b/htdocs/core/tpl/objectline_view.tpl.php index e581e65269b..c2b66778d33 100644 --- a/htdocs/core/tpl/objectline_view.tpl.php +++ b/htdocs/core/tpl/objectline_view.tpl.php @@ -53,7 +53,9 @@ if (empty($usemargins)) $usemargins=0; - + diff --git a/htdocs/core/tpl/resource_view.tpl.php b/htdocs/core/tpl/resource_view.tpl.php index d57b66cc331..75a69996603 100644 --- a/htdocs/core/tpl/resource_view.tpl.php +++ b/htdocs/core/tpl/resource_view.tpl.php @@ -90,7 +90,7 @@ if( (array) $linked_resources && count($linked_resources) > 0) print img_edit(); print ''; print ' '; - print ''; + print ''; print img_delete(); print ''; print ''; diff --git a/htdocs/core/triggers/interface_50_modAgenda_ActionsAuto.class.php b/htdocs/core/triggers/interface_50_modAgenda_ActionsAuto.class.php index 0ab64d406c8..46a6cd0daa6 100644 --- a/htdocs/core/triggers/interface_50_modAgenda_ActionsAuto.class.php +++ b/htdocs/core/triggers/interface_50_modAgenda_ActionsAuto.class.php @@ -79,6 +79,7 @@ class InterfaceActionsAuto extends DolibarrTriggers if ($action == 'COMPANY_CREATE') { $langs->load("other"); + $langs->load("companies"); $object->actiontypecode='AC_OTH_AUTO'; if (empty($object->actionmsg2)) $object->actionmsg2=$langs->transnoentities("NewCompanyToDolibarr",$object->name); @@ -91,7 +92,8 @@ class InterfaceActionsAuto extends DolibarrTriggers } elseif ($action == 'COMPANY_SENTBYMAIL') { - $langs->load("orders"); + $langs->load("other"); + $langs->load("orders"); if (empty($object->actiontypecode)) $object->actiontypecode='AC_OTH_AUTO'; if (empty($object->actionmsg2)) dol_syslog('Trigger called with property actionmsg2 on object not defined', LOG_ERR); @@ -114,7 +116,8 @@ class InterfaceActionsAuto extends DolibarrTriggers } elseif ($action == 'PROPAL_VALIDATE') { - $langs->load("propal"); + $langs->load("other"); + $langs->load("propal"); $object->actiontypecode='AC_OTH_AUTO'; if (empty($object->actionmsg2)) $object->actionmsg2=$langs->transnoentities("PropalValidatedInDolibarr",($object->newref?$object->newref:$object->ref)); @@ -125,7 +128,8 @@ class InterfaceActionsAuto extends DolibarrTriggers } elseif ($action == 'PROPAL_SENTBYMAIL') { - $langs->load("propal"); + $langs->load("other"); + $langs->load("propal"); $object->actiontypecode='AC_OTH_AUTO'; if (empty($object->actionmsg2)) $object->actionmsg2=$langs->transnoentities("ProposalSentByEMail",$object->ref); @@ -140,7 +144,8 @@ class InterfaceActionsAuto extends DolibarrTriggers } elseif ($action == 'PROPAL_CLOSE_SIGNED') { - $langs->load("propal"); + $langs->load("other"); + $langs->load("propal"); $object->actiontypecode='AC_OTH_AUTO'; if (empty($object->actionmsg2)) $object->actionmsg2=$langs->transnoentities("PropalClosedSignedInDolibarr",$object->ref); @@ -151,7 +156,8 @@ class InterfaceActionsAuto extends DolibarrTriggers } elseif ($action == 'PROPAL_CLASSIFY_BILLED') { - $langs->load("propal"); + $langs->load("other"); + $langs->load("propal"); $object->actiontypecode='AC_OTH_AUTO'; if (empty($object->actionmsg2)) $object->actionmsg2=$langs->transnoentities("PropalClassifiedBilledInDolibarr",$object->ref); @@ -162,7 +168,8 @@ class InterfaceActionsAuto extends DolibarrTriggers } elseif ($action == 'PROPAL_CLOSE_REFUSED') { - $langs->load("propal"); + $langs->load("other"); + $langs->load("propal"); $object->actiontypecode='AC_OTH_AUTO'; if (empty($object->actionmsg2)) $object->actionmsg2=$langs->transnoentities("PropalClosedRefusedInDolibarr",$object->ref); @@ -184,7 +191,8 @@ class InterfaceActionsAuto extends DolibarrTriggers } elseif ($action == 'ORDER_CLOSE') { - $langs->load("orders"); + $langs->load("other"); + $langs->load("orders"); $object->actiontypecode='AC_OTH_AUTO'; if (empty($object->actionmsg2)) $object->actionmsg2=$langs->transnoentities("OrderDeliveredInDolibarr",$object->ref); @@ -195,7 +203,8 @@ class InterfaceActionsAuto extends DolibarrTriggers } elseif ($action == 'ORDER_CLASSIFY_BILLED') { - $langs->load("orders"); + $langs->load("other"); + $langs->load("orders"); $object->actiontypecode='AC_OTH_AUTO'; if (empty($object->actionmsg2)) $object->actionmsg2=$langs->transnoentities("OrderBilledInDolibarr",$object->ref); @@ -206,7 +215,8 @@ class InterfaceActionsAuto extends DolibarrTriggers } elseif ($action == 'ORDER_CANCEL') { - $langs->load("orders"); + $langs->load("other"); + $langs->load("orders"); $object->actiontypecode='AC_OTH_AUTO'; if (empty($object->actionmsg2)) $object->actionmsg2=$langs->transnoentities("OrderCanceledInDolibarr",$object->ref); @@ -217,7 +227,8 @@ class InterfaceActionsAuto extends DolibarrTriggers } elseif ($action == 'ORDER_SENTBYMAIL') { - $langs->load("orders"); + $langs->load("other"); + $langs->load("orders"); $object->actiontypecode='AC_OTH_AUTO'; if (empty($object->actionmsg2)) $object->actionmsg2=$langs->transnoentities("OrderSentByEMail",$object->ref); @@ -421,7 +432,8 @@ class InterfaceActionsAuto extends DolibarrTriggers } elseif ($action == 'ORDER_SUPPLIER_VALIDATE') { - $langs->load("orders"); + $langs->load("other"); + $langs->load("orders"); $object->actiontypecode='AC_OTH_AUTO'; if (empty($object->actionmsg2)) $object->actionmsg2=$langs->transnoentities("OrderValidatedInDolibarr",($object->newref?$object->newref:$object->ref)); @@ -432,6 +444,7 @@ class InterfaceActionsAuto extends DolibarrTriggers } elseif ($action == 'ORDER_SUPPLIER_APPROVE') { + $langs->load("other"); $langs->load("orders"); $object->actiontypecode='AC_OTH_AUTO'; @@ -443,6 +456,7 @@ class InterfaceActionsAuto extends DolibarrTriggers } elseif ($action == 'ORDER_SUPPLIER_REFUSE') { + $langs->load("other"); $langs->load("orders"); $object->actiontypecode='AC_OTH_AUTO'; diff --git a/htdocs/expedition/card.php b/htdocs/expedition/card.php index fa451f74f1c..879b66ebb39 100644 --- a/htdocs/expedition/card.php +++ b/htdocs/expedition/card.php @@ -1513,6 +1513,10 @@ else if ($id || $ref) /* * Action presend */ + //Select mail models is same action as presend + if (GETPOST('modelselected')) { + $action = 'presend'; + } if ($action == 'presend') { $ref = dol_sanitizeFileName($object->ref); @@ -1611,6 +1615,7 @@ else if ($id || $ref) // Tableau des parametres complementaires $formmail->param['action']='send'; $formmail->param['models']='shipping_send'; + $formmail->param['models_id']=GETPOST('modelmailselected','int'); $formmail->param['shippingid']=$object->id; $formmail->param['returnurl']=$_SERVER["PHP_SELF"].'?id='.$object->id; diff --git a/htdocs/expedition/class/expedition.class.php b/htdocs/expedition/class/expedition.class.php index f357d03eb36..24ce24bae47 100644 --- a/htdocs/expedition/class/expedition.class.php +++ b/htdocs/expedition/class/expedition.class.php @@ -6,7 +6,7 @@ * Copyright (C) 2011-2013 Juanjo Menent * Copyright (C) 2013 Florian Henry * Copyright (C) 2014 Cedric GROSS - * Copyright (C) 2014 Marcos García + * Copyright (C) 2014-2015 Marcos García * Copyright (C) 2014 Francis Appels * * This program is free software; you can redistribute it and/or modify @@ -492,9 +492,9 @@ class Expedition extends CommonObject //Incoterms $this->fk_incoterms = $obj->fk_incoterms; - $this->location_incoterms = $obj->location_incoterms; + $this->location_incoterms = $obj->location_incoterms; $this->libelle_incoterms = $obj->libelle_incoterms; - + $this->db->free($result); if ($this->statut == 0) $this->brouillon = 1; @@ -878,7 +878,7 @@ class Expedition extends CommonObject if (isset($this->fk_delivery_address)) $this->fk_delivery_address=trim($this->fk_delivery_address); if (isset($this->shipping_method_id)) $this->shipping_method_id=trim($this->shipping_method_id); if (isset($this->tracking_number)) $this->tracking_number=trim($this->tracking_number); - if (isset($this->statut)) $this->statut=trim($this->statut); + if (isset($this->statut)) $this->statut=(int) $this->statut; if (isset($this->trueDepth)) $this->trueDepth=trim($this->trueDepth); if (isset($this->trueWidth)) $this->trueWidth=trim($this->trueWidth); if (isset($this->trueHeight)) $this->trueHeight=trim($this->trueHeight); @@ -1673,6 +1673,22 @@ class Expedition extends CommonObject return $this->commonGenerateDocument($modelpath, $modele, $outputlangs, 0, 0, 0); } + /** + * Function used to replace a thirdparty id with another one. + * + * @param DoliDB $db Database handler + * @param int $origin_id Old thirdparty id + * @param int $dest_id New thirdparty id + * @return bool + */ + public static function replaceThirdparty(DoliDB $db, $origin_id, $dest_id) + { + $tables = array( + 'expedition' + ); + + return CommonObject::commonReplaceThirdparty($db, $origin_id, $dest_id, $tables); + } } diff --git a/htdocs/expedition/list.php b/htdocs/expedition/list.php index d9e26368a74..195687a4ab7 100644 --- a/htdocs/expedition/list.php +++ b/htdocs/expedition/list.php @@ -51,6 +51,8 @@ if (! $sortfield) $sortfield="e.ref"; if (! $sortorder) $sortorder="DESC"; $limit = $conf->liste_limit; +$viewstatut=GETPOST('viewstatut'); + // Purge search criteria if (GETPOST("button_removefilter_x") || GETPOST("button_removefilter")) // Both test are required to be compatible with all browsers { @@ -78,8 +80,8 @@ if (!$user->rights->societe->client->voir && !$socid) // Internal user with no p } $sql.= ")"; $sql.= " LEFT JOIN ".MAIN_DB_PREFIX."societe as s ON s.rowid = e.fk_soc"; -$sql.= " LEFT JOIN ".MAIN_DB_PREFIX."element_element as ee ON e.rowid = ee.fk_source AND ee.sourcetype = 'shipping'"; -$sql.= " LEFT JOIN ".MAIN_DB_PREFIX."livraison as l ON l.rowid = ee.fk_target AND ee.targettype = 'delivery'"; +$sql.= " LEFT JOIN ".MAIN_DB_PREFIX."element_element as ee ON e.rowid = ee.fk_source AND ee.sourcetype = 'shipping' AND ee.targettype = 'delivery'"; +$sql.= " LEFT JOIN ".MAIN_DB_PREFIX."livraison as l ON l.rowid = ee.fk_target"; $sql.= " WHERE e.entity = ".$conf->entity; if (!$user->rights->societe->client->voir && !$socid) // Internal user with no permission to see all { @@ -90,6 +92,9 @@ if ($socid) { $sql.= " AND e.fk_soc = ".$socid; } +if ($viewstatut <> '') { + $sql.= " AND e.fk_statut = ".$viewstatut; +} if ($search_ref_exp) $sql .= natural_search('e.ref', $search_ref_exp); if ($search_ref_liv) $sql .= natural_search('l.ref', $search_ref_liv); if ($search_company) $sql .= natural_search('s.nom', $search_company); @@ -120,11 +125,10 @@ if ($resql) print_liste_field_titre($langs->trans("Ref"), $_SERVER["PHP_SELF"],"e.ref","",$param,'',$sortfield,$sortorder); print_liste_field_titre($langs->trans("Company"), $_SERVER["PHP_SELF"],"s.nom", "", $param,'align="left"',$sortfield,$sortorder); print_liste_field_titre($langs->trans("DateDeliveryPlanned"), $_SERVER["PHP_SELF"],"e.date_delivery","",$param, 'align="center"',$sortfield,$sortorder); - if($conf->expedition_bon->enabled) { - print_liste_field_titre($langs->trans("DeliveryOrder"), $_SERVER["PHP_SELF"],"e.date_expedition","",$param, '',$sortfield,$sortorder); - } - if($conf->livraison_bon->enabled) { - print_liste_field_titre($langs->trans("DateReceived"), $_SERVER["PHP_SELF"],"e.date_expedition","",$param, 'align="center"',$sortfield,$sortorder); + if($conf->livraison_bon->enabled) + { + print_liste_field_titre($langs->trans("DeliveryOrder"), $_SERVER["PHP_SELF"],"l.ref","",$param, '',$sortfield,$sortorder); + print_liste_field_titre($langs->trans("DateReceived"), $_SERVER["PHP_SELF"],"l.date_delivery","",$param, 'align="center"',$sortfield,$sortorder); } print_liste_field_titre($langs->trans("Status"), $_SERVER["PHP_SELF"],"e.fk_statut","",$param,'align="right"',$sortfield,$sortorder); print ''; @@ -138,13 +142,14 @@ if ($resql) print ''; + // Date print ''; - if($conf->expedition_bon->enabled) { + if ($conf->livraison_bon->enabled) + { print ''; } print '\n"; - if($conf->expedition_bon->enabled) { - // Date real - print ''."\n"; - } - if($conf->livraison_bon->enabled) { - print ''."\n"; + + if ($conf->livraison_bon->enabled) + { + $shipment->fetchObjectLinked($shipment->id,$shipment->element); + $receiving=(! empty($shipment->linkedObjects['delivery'][0])?$shipment->linkedObjects['delivery'][0]:''); + + // Ref + print ''; + + print ''."\n"; } diff --git a/htdocs/expensereport/class/expensereport.class.php b/htdocs/expensereport/class/expensereport.class.php index 0d30602987f..c6c638f06f3 100755 --- a/htdocs/expensereport/class/expensereport.class.php +++ b/htdocs/expensereport/class/expensereport.class.php @@ -623,7 +623,7 @@ class ExpenseReport extends CommonObject print $langs->trans('Draft').' '.img_picto($langs->trans('Draft'),'statut0'); break; case 2: - print $langs->trans('TripForValid').' '.img_picto($langs->trans('TripForValid'),'statut3');; + print $langs->trans('TripForValid').' '.img_picto($langs->trans('TripForValid'),'statut3'); break; case 5: print $langs->trans('TripForPaid').' '.img_picto($langs->trans('TripForPaid'),'statut3'); diff --git a/htdocs/exports/class/export.class.php b/htdocs/exports/class/export.class.php index d3b23915eb7..c044dfc4704 100644 --- a/htdocs/exports/class/export.class.php +++ b/htdocs/exports/class/export.class.php @@ -328,7 +328,7 @@ class Export function conditionDate($Field, $Value, $Sens) { // TODO date_format is forbidden, not performant and not portable. Use instead BETWEEN - if (strlen($Value)==4) $Condition=" date_format(".$Field.",'%Y') ".$Sens." ".$Value; + if (strlen($Value)==4) $Condition=" date_format(".$Field.",'%Y') ".$Sens." '".$Value."'"; elseif (strlen($Value)==6) $Condition=" date_format(".$Field.",'%Y%m') ".$Sens." '".$Value."'"; else $Condition=" date_format(".$Field.",'%Y%m%d') ".$Sens." ".$Value; return $Condition; diff --git a/htdocs/exports/export.php b/htdocs/exports/export.php index c2a5ee9d205..4b565069b5c 100644 --- a/htdocs/exports/export.php +++ b/htdocs/exports/export.php @@ -58,6 +58,7 @@ $entitytoicon = array( 'account' => 'account', 'product' => 'product', 'warehouse' => 'stock', + 'batch' => 'stock', 'category' => 'category', 'shipment' => 'sending', 'shipment_line'=> 'sending', @@ -88,7 +89,8 @@ $entitytolang = array( 'product' => 'Product', 'service' => 'Service', 'stock' => 'Stock', - 'warehouse' => 'Warehouse', + 'batch' => 'Batch', + 'warehouse' => 'Warehouse', 'category' => 'Category', 'other' => 'Other', 'trip' => 'TripsAndExpenses', diff --git a/htdocs/fichinter/card.php b/htdocs/fichinter/card.php index 9eb9b243830..b0f0e2695ec 100644 --- a/htdocs/fichinter/card.php +++ b/htdocs/fichinter/card.php @@ -847,7 +847,7 @@ else if ($action == 'update_extras') if (! $error) { // Actions on extra fields (by external module or standard code) - // FIXME le hook fait double emploi avec le trigger !! + // TODO le hook fait double emploi avec le trigger !! $hookmanager->initHooks(array('interventiondao')); $parameters=array('id'=>$object->id); $reshook=$hookmanager->executeHooks('insertExtraFields',$parameters,$object,$action); // Note that $action and $object may have been modified by some hooks @@ -1732,6 +1732,9 @@ else if ($id > 0 || ! empty($ref)) /* * Action presend */ + if (GETPOST('modelselected')) { + $action = 'presend'; + } if ($action == 'presend') { $ref = dol_sanitizeFileName($object->ref); @@ -1819,6 +1822,7 @@ else if ($id > 0 || ! empty($ref)) // Tableau des parametres complementaires $formmail->param['action']='send'; $formmail->param['models']='fichinter_send'; + $formmail->param['models_id']=GETPOST('modelmailselected','int'); $formmail->param['fichinter_id']=$object->id; $formmail->param['returnurl']=$_SERVER["PHP_SELF"].'?id='.$object->id; diff --git a/htdocs/fichinter/class/fichinter.class.php b/htdocs/fichinter/class/fichinter.class.php index baf2555a905..b72dec1f6fa 100644 --- a/htdocs/fichinter/class/fichinter.class.php +++ b/htdocs/fichinter/class/fichinter.class.php @@ -3,6 +3,7 @@ * Copyright (C) 2004-2014 Laurent Destailleur * Copyright (C) 2005-2012 Regis Houssin * Copyright (C) 2011-2013 Juanjo Menent + * Copyright (C) 2015 Marcos García * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -1011,6 +1012,23 @@ class Fichinter extends CommonObject return -1; } } + + /** + * Function used to replace a thirdparty id with another one. + * + * @param DoliDB $db Database handler + * @param int $origin_id Old thirdparty id + * @param int $dest_id New thirdparty id + * @return bool + */ + public static function replaceThirdparty(DoliDB $db, $origin_id, $dest_id) + { + $tables = array( + 'fichinter' + ); + + return CommonObject::commonReplaceThirdparty($db, $origin_id, $dest_id, $tables); + } } /** diff --git a/htdocs/fichinter/document.php b/htdocs/fichinter/document.php index fd039efff24..bd6746c98e4 100644 --- a/htdocs/fichinter/document.php +++ b/htdocs/fichinter/document.php @@ -88,7 +88,7 @@ if ($object->id) { $object->fetch_thirdparty(); - $head=fichinter_prepare_head($object, $user); + $head=fichinter_prepare_head($object); dol_fiche_head($head, 'documents', $langs->trans("InterventionCard"), 0, 'intervention'); diff --git a/htdocs/filefunc.inc.php b/htdocs/filefunc.inc.php index 15bee891775..13b2d8d1669 100644 --- a/htdocs/filefunc.inc.php +++ b/htdocs/filefunc.inc.php @@ -8,6 +8,7 @@ * Copyright (C) 2005 Simon Tosser * Copyright (C) 2006 Andre Cianfarani * Copyright (C) 2010 Juanjo Menent + * Copyright (C) 2015 Bahfir Abbes * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -66,6 +67,14 @@ $conffiletoshow = "htdocs/conf/conf.php"; //$conffile = "/etc/dolibarr/conf.php"; //$conffiletoshow = "/etc/dolibarr/conf.php"; +//replace conf filename with "conf" parameter on url by GET +if (!empty($_GET['conf'])) { + setcookie('dolconf', $_GET['conf'],0,'/'); + $conffile = 'conf/' . $_GET['conf'] . '.php'; +} else { + $conffile = 'conf/' . (!empty($_COOKIE['dolconf']) ? $_COOKIE['dolconf'] : 'conf') . '.php'; +} + // Include configuration $result=@include_once $conffile; // Keep @ because with some error reporting this break the redirect diff --git a/htdocs/fourn/card.php b/htdocs/fourn/card.php index 97004783ae6..8ee2b9a23b8 100644 --- a/htdocs/fourn/card.php +++ b/htdocs/fourn/card.php @@ -3,7 +3,7 @@ * Copyright (C) 2003 Eric Seigne * Copyright (C) 2004-2014 Laurent Destailleur * Copyright (C) 2005-2010 Regis Houssin - * Copyright (C) 2010-2014 Juanjo Menent + * Copyright (C) 2010-2015 Juanjo Menent * Copyright (C) 2014 Jean Heimburger * Copyright (C) 2015 Marcos García * @@ -35,11 +35,11 @@ require_once DOL_DOCUMENT_ROOT.'/core/lib/company.lib.php'; require_once DOL_DOCUMENT_ROOT.'/core/class/extrafields.class.php'; if (! empty($conf->adherent->enabled)) require_once DOL_DOCUMENT_ROOT.'/adherents/class/adherent.class.php'; +$langs->load('companies'); $langs->load('suppliers'); $langs->load('products'); $langs->load('bills'); $langs->load('orders'); -$langs->load('companies'); $langs->load('commercial'); $action = GETPOST('action'); @@ -201,13 +201,13 @@ if ($object->id > 0) // Local Taxes if ($mysoc->useLocalTax(1)) { - print ''; } if ($mysoc->useLocalTax(2)) { - print ''; } @@ -364,7 +364,7 @@ if ($object->id > 0) /* - * Last orders + * Last supplier orders */ $orderstatic = new CommandeFournisseur($db); @@ -409,7 +409,7 @@ if ($object->id > 0) print ''; print ''; - // Delai livraison jours + // Delivery delay (in days) print ''; print ''; print ''; @@ -2040,7 +2040,7 @@ elseif (! empty($object->id)) // Show object lines $inputalsopricewithtax=0; if (! empty($object->lines)) - $ret = $object->printObjectLines($action, $soc, $mysoc, $lineid, 1); + $ret = $object->printObjectLines($action, $societe, $mysoc, $lineid, 1); $num = count($object->lines); @@ -2246,6 +2246,9 @@ elseif (! empty($object->id)) /* * Action presend */ + if (GETPOST('modelselected')) { + $action = 'presend'; + } if ($action == 'presend') { $ref = dol_sanitizeFileName($object->ref); @@ -2338,6 +2341,7 @@ elseif (! empty($object->id)) // Tableau des parametres complementaires $formmail->param['action']='send'; $formmail->param['models']='order_supplier_send'; + $formmail->param['models_id']=GETPOST('modelmailselected','int'); $formmail->param['orderid']=$object->id; $formmail->param['returnurl']=$_SERVER["PHP_SELF"].'?id='.$object->id; @@ -2673,7 +2677,7 @@ elseif (! empty($object->id)) print ''.$langs->trans("Disapprove").''; } } - if (in_array($object->statut, array(5, 6, 7, 9))) + if (in_array($object->statut, array(3, 5, 6, 7, 9))) { if ($user->rights->fournisseur->commande->commander) { @@ -2682,20 +2686,22 @@ elseif (! empty($object->id)) } // Create bill - if (! empty($conf->fournisseur->enabled) && ($object->statut >= 2 && $object->statut != 9)) // 2 means accepted + if (! empty($conf->facture->enabled)) { - if ($user->rights->fournisseur->facture->creer) + if (! empty($conf->fournisseur->enabled) && ($object->statut >= 2 && $object->statut != 9)) // 2 means accepted { - print ''.$langs->trans("CreateBill").''; + if ($user->rights->fournisseur->facture->creer) + { + print ''.$langs->trans("CreateBill").''; + } + + //if ($user->rights->fournisseur->commande->creer && $object->statut > 2) + //{ + // print ''.$langs->trans("ClassifyBilled").''; + //} } - - //if ($user->rights->fournisseur->commande->creer && $object->statut > 2) - //{ - // print ''.$langs->trans("ClassifyBilled").''; - //} } - // Create a remote order using WebService only if module is activated if (! empty($conf->syncsupplierwebservices->enabled) && $object->statut >= 2) // 2 means accepted { @@ -2758,6 +2764,7 @@ elseif (! empty($object->id)) /* * Commander (action=commande) */ + print ''."\n"; print ''; print ''; print ''; @@ -2766,7 +2773,7 @@ elseif (! empty($object->id)) //print ''; print ''; print '\n"; // Ref supplier - print ''; // Third party @@ -1788,8 +1786,8 @@ else print ''; // Label - print ''; - print ''; + print ''; + print ''; /* * List of payments @@ -1853,7 +1851,7 @@ else } print ''; print ''; + $form_permission = $object->statutrights->fournisseur->facture->creer && $object->getSommePaiement() <= 0; + // Date - print ''; // Due date - print ''; // Conditions de reglement par defaut @@ -1962,8 +1962,9 @@ else $alreadypaid=$object->getSommePaiement(); print ''; - print ''; - print ''; + print ''; - print ''; - print ''; + print ''; + print ''; } if ($societe->localtax2_assuj=="1") //Localtax2 { print ''; - print ''; - print ''; + print ''; + print ''; } - print ''; + print ''; // Project if (! empty($conf->projet->enabled)) @@ -2081,7 +2082,7 @@ else '; - if (! empty($conf->use_javascript_ajax) && $object->statut == 0) { + if (! empty($conf->use_javascript_ajax) && $object->statut == FactureFournisseur::STATUS_DRAFT) { include DOL_DOCUMENT_ROOT . '/core/tpl/ajaxrow.tpl.php'; } @@ -2279,7 +2280,7 @@ else } */ // Form to add new line - if ($object->statut == 0 && $user->rights->fournisseur->facture->creer) + if ($object->statut == FactureFournisseur::STATUS_DRAFT && $user->rights->fournisseur->facture->creer) { if ($action != 'editline') { @@ -2310,7 +2311,7 @@ else print '
'; // Modify a validated invoice with no payments - if ($object->statut == 1 && $action != 'edit' && $object->getSommePaiement() == 0 && $user->rights->fournisseur->facture->creer) + if ($object->statut == FactureFournisseur::STATUS_VALIDATED && $action != 'edit' && $object->getSommePaiement() == 0 && $user->rights->fournisseur->facture->creer) { print ''.$langs->trans('Modify').''; } @@ -2329,7 +2330,7 @@ else } // Send by mail - if (($object->statut == 1 || $object->statut == 2)) + if (($object->statut == FactureFournisseur::STATUS_VALIDATED || $object->statut == FactureFournisseur::STATUS_CLOSED)) { if (empty($conf->global->MAIN_USE_ADVANCED_PERMS) || $user->rights->fournisseur->supplier_invoice_advance->send) { @@ -2340,13 +2341,13 @@ else // Make payments - if ($action != 'edit' && $object->statut == 1 && $object->paye == 0 && $user->societe_id == 0) + if ($action != 'edit' && $object->statut == FactureFournisseur::STATUS_VALIDATED && $object->paye == 0 && $user->societe_id == 0) { print ''.$langs->trans('DoPayment').''; // must use facid because id is for payment id not invoice } // Classify paid - if ($action != 'edit' && $object->statut == 1 && $object->paye == 0 && $user->societe_id == 0) + if ($action != 'edit' && $object->statut == FactureFournisseur::STATUS_VALIDATED && $object->paye == 0 && $user->societe_id == 0) { print ''.$langs->trans('ClassifyPaid').''; @@ -2355,7 +2356,7 @@ else } // Validate - if ($action != 'edit' && $object->statut == 0) + if ($action != 'edit' && $object->statut == FactureFournisseur::STATUS_DRAFT) { if (count($object->lines)) { @@ -2498,6 +2499,9 @@ else /* * Show mail form */ + if (GETPOST('modelselected')) { + $action = 'presend'; + } if ($action == 'presend') { $ref = dol_sanitizeFileName($object->ref); @@ -2584,6 +2588,7 @@ else // Tableau des parametres complementaires $formmail->param['action']='send'; $formmail->param['models']='invoice_supplier_send'; + $formmail->param['models_id']=GETPOST('modelmailselected','int'); $formmail->param['facid']=$object->id; $formmail->param['returnurl']=$_SERVER["PHP_SELF"].'?id='.$object->id; diff --git a/htdocs/fourn/facture/contact.php b/htdocs/fourn/facture/contact.php index aaee42e9add..7348f3b7590 100644 --- a/htdocs/fourn/facture/contact.php +++ b/htdocs/fourn/facture/contact.php @@ -1,6 +1,6 @@ - * Copyright (C) 2005-2014 Laurent Destailleur + * Copyright (C) 2005-2015 Laurent Destailleur * Copyright (C) 2005-2012 Regis Houssin * * This program is free software; you can redistribute it and/or modify @@ -200,6 +200,30 @@ if ($id > 0 || ! empty($ref)) print $form->editfieldval("Label",'label',$object->label,$object,0); print ''; + // Status + $alreadypaid=$object->getSommePaiement(); + print '
'; + + // Amount + print ''; + print ''; + + // Amount Local Taxes + //TODO: Place into a function to control showing by country or study better option + if ($societe->localtax1_assuj=="1") //Localtax1 + { + print ''; + print ''; + print ''; + } + if ($societe->localtax2_assuj=="1") //Localtax2 + { + print ''; + print ''; + print ''; + } + print ''; + print "
'.$langs->trans("Total").''; $taskstatic->ref=($lines[$i]->ref?$lines[$i]->ref:$lines[$i]->id); - print $taskstatic->getNomUrl(1); + print $taskstatic->getNomUrl(1,'withproject'); print ''; - $s=''; - $s.=$form->select_date('',$lines[$i]->id,1,1,2,"addtime",1,0,1,$disabledtask); - print $s; + $tableCell=$form->select_date($preselectedday,$lines[$i]->id,1,1,2,"addtime",0,0,1,$disabledtask); + print $tableCell; print ''; - //$s.='   '; - $s=$form->select_duration($lines[$i]->id.'duration','',$disabledtask,'text',0,1); - //$s.=' '; - print $s; + + $dayWorkLoad = $projectstatic->weekWorkLoadPerTask[$preselectedday][$lines[$i]->id]; + $alreadyspent=''; + if ($dayWorkLoad > 0) $alreadyspent=convertSecondToTime($dayWorkLoad,'allhourmin'); + + $tableCell=''; + $tableCell.=''; + $tableCell.=' + '; + //$tableCell.='   '; + $tableCell.=$form->select_duration($lines[$i]->id.'duration','',$disabledtask,'text',0,1); + //$tableCell.=' '; + print $tableCell; print ''; @@ -633,7 +647,7 @@ function projectLinesPerDay(&$inc, $parent, $lines, &$level, &$projectsrole, &$t $inc++; $level++; - if ($lines[$i]->id) projectLinesPerDay($inc, $lines[$i]->id, $lines, $level, $projectsrole, $tasksrole, $mine, $restricteditformytask); + if ($lines[$i]->id) projectLinesPerDay($inc, $lines[$i]->id, $lines, $level, $projectsrole, $tasksrole, $mine, $restricteditformytask, $preselectedday); $level--; } else @@ -776,18 +790,30 @@ function projectLinesPerWeek(&$inc, $firstdaytoshow, $fuser, $parent, $lines, &$ for ($idw = 0; $idw < 7; $idw++) { $tmpday=dol_time_plus_duree($firstdaytoshow, $idw, 'd'); + $tmparray=dol_getdate($tmpday); $dayWorkLoad = $projectstatic->weekWorkLoadPerTask[$tmpday][$lines[$i]->id]; $alreadyspent=''; if ($dayWorkLoad > 0) $alreadyspent=convertSecondToTime($dayWorkLoad,'allhourmin'); $tableCell =''; $tableCell.=''; - $tableCell.='+'; - $tableCell.=''; + //$placeholder=' placeholder="00:00"'; + $placeholder=''; + //if (! $disabledtask) + //{ + $tableCell.='+'; + $tableCell.=''; + //} $tableCell.=''; + if ((! $lines[$i]->public) && $disabledproject) print $form->textwithpicto('',$langs->trans("YouAreNotContactOfProject")); + else if ($disabledtask) print $form->textwithpicto('',$langs->trans("TaskIsNotAffectedToYou")); + print '
- + textwithpicto('', $langs->trans("ExtrafieldParamHelp".$type),1,0)?>
- info_bits & 2) == 2) { ?> + info_bits & 2) == 2) { + ?> fk_product > 0) { - echo $form->textwithtooltip($text,$description,3,'','',$i,0,(!empty($line->fk_parent_line)?img_picto('', 'rightarrow'):'')); - + // Show range echo get_date_range($line->date_start, $line->date_end); @@ -128,7 +129,7 @@ if (empty($usemargins)) $usemargins=0;
tva_tx,'%',$line->info_bits); ?>pu_ht); ?>subprice); ?> pu_ttc)?price($line->pu_ttc):price($line->subprice)); ?> '; print ''; print ' '; print ''; - } - if($conf->livraison_bon->enabled) { + print ' '; @@ -188,14 +193,23 @@ if ($resql) { }*/ print "'; - print dol_print_date($db->jdate($objp->date_expedition),"day"); - print ''; + + // Date real + print ''; + print dol_print_date($db->jdate($objp->date_expedition),"day"); + print ''; + print !empty($receiving) ? $receiving->getNomUrl($db) : ''; + print ''; print dol_print_date($db->jdate($objp->date_reception),"day"); print '
'.$langs->trans("LocalTax1IsUsed").''; + print '
'.$langs->transcountry("LocalTax1IsUsed", $mysoc->country_code).''; print yn($object->localtax1_assuj); print '
'.$langs->trans("LocalTax2IsUsed").''; + print '
'.$langs->transcountry("LocalTax2IsUsed", $mysoc->country_code).''; print yn($object->localtax2_assuj); print '
'; - print ''; + print '
'.$langs->trans("LastOrders",($num<$MAXLIST?"":$MAXLIST)).'
'; print ''; print ''; print '
'.$langs->trans("LastSupplierOrders",($num<$MAXLIST?"":$MAXLIST)).''.$langs->trans("AllOrders").' '.$num.''.img_picto($langs->trans("Statistics"),'stats').'
'; @@ -455,7 +455,7 @@ if ($object->id > 0) } /* - * Last invoices + * Last supplier invoices */ $MAXLIST=5; @@ -471,7 +471,7 @@ if ($object->id > 0) $sql.= ' LEFT JOIN '.MAIN_DB_PREFIX.'paiementfourn_facturefourn as pf ON f.rowid=pf.fk_facturefourn'; $sql.= ' WHERE f.fk_soc = '.$object->id; $sql.= " AND f.entity =".$conf->entity; - $sql.= ' GROUP BY f.rowid,f.libelle,f.ref,f.ref_supplier,f.fk_statut,f.datef,f.total_ttc,f.paye'; + $sql.= ' GROUP BY f.rowid,f.libelle,f.ref,f.ref_supplier,f.fk_statut,f.datef,f.total_ht,f.total_tva,f.total_ttc,f.paye'; $sql.= ' ORDER BY f.datef DESC'; $resql=$db->query($sql); if ($resql) diff --git a/htdocs/fourn/class/fournisseur.commande.class.php b/htdocs/fourn/class/fournisseur.commande.class.php index 3cd07d7fc53..3b6de210928 100644 --- a/htdocs/fourn/class/fournisseur.commande.class.php +++ b/htdocs/fourn/class/fournisseur.commande.class.php @@ -52,7 +52,11 @@ class CommandeFournisseur extends CommonOrder var $id; - var $ref; // TODO deprecated + /** + * TODO: Remove + * @deprecated + */ + var $ref; var $product_ref; var $ref_supplier; var $brouillon; @@ -1066,6 +1070,12 @@ class CommandeFournisseur extends CommonOrder } } + if (! $error) + { + $result=$this->insertExtraFields(); + if ($result < 0) $error++; + } + if (! $error && ! $notrigger) { // Call trigger @@ -1381,19 +1391,25 @@ class CommandeFournisseur extends CommonOrder */ function dispatchProduct($user, $product, $qty, $entrepot, $price=0, $comment='', $eatby='', $sellby='', $batch='', $fk_commandefourndet=0, $notrigger=0) { - global $conf; + global $conf, $langs; + $error = 0; require_once DOL_DOCUMENT_ROOT .'/product/stock/class/mouvementstock.class.php'; - // Check parameters - if ($entrepot <= 0 || $qty <= 0) + // Check parameters (if test are wrong here, there is bug into caller) + if ($entrepot <= 0) { - $this->error='BadValueForParameterWarehouseOrQty'; + $this->error='ErrorBadValueForParameterWarehouse'; + return -1; + } + if ($qty <= 0) + { + $this->error='ErrorBadValueForParameterQty'; return -1; } $dispatchstatus = 1; - if (! empty($conf->global->SUPPLIER_ORDER_USE_DISPATCH_STATUS)) $dispatchstatus = 0; // Setting dispatch status (a validation step after receiving products) will be done manually to 1 if this option is on + if (! empty($conf->global->SUPPLIER_ORDER_USE_DISPATCH_STATUS)) $dispatchstatus = 0; // Setting dispatch status (a validation step after receiving products) will be done manually to 1 or 2 if this option is on $now=dol_now(); @@ -1418,13 +1434,11 @@ class CommandeFournisseur extends CommonOrder $result=$this->call_trigger('LINEORDER_SUPPLIER_DISPATCH',$user); if ($result < 0) { - $this->db->rollback(); + $error++; return -1; } // End call triggers } - - $this->db->commit(); } else { @@ -1433,7 +1447,7 @@ class CommandeFournisseur extends CommonOrder } // Si module stock gere et que incrementation faite depuis un dispatching en stock - if (!$error && $entrepot > 0 && ! empty($conf->stock->enabled) && ! empty($conf->global->STOCK_CALCULATE_ON_SUPPLIER_DISPATCH_ORDER)) + if (! $error && $entrepot > 0 && ! empty($conf->stock->enabled) && ! empty($conf->global->STOCK_CALCULATE_ON_SUPPLIER_DISPATCH_ORDER)) { $mouv = new MouvementStock($this->db); @@ -1445,13 +1459,13 @@ class CommandeFournisseur extends CommonOrder if ($result < 0) { $this->error=$mouv->error; - dol_syslog(get_class($this)."::dispatchProduct ".$this->error, LOG_ERR); + $this->errors=$mouv->errors; + dol_syslog(get_class($this)."::dispatchProduct ".$this->error." ".join(',',$this->errors), LOG_ERR); $error++; } } } - //TODO: Check if there is a current transaction in DB but seems not. if ($error == 0) { $this->db->commit(); @@ -1464,7 +1478,7 @@ class CommandeFournisseur extends CommonOrder } } else - { + { $this->error='BadStatusForObject'; return -2; } @@ -1731,18 +1745,37 @@ class CommandeFournisseur extends CommonOrder if ($type == 'nev') $statut = 7; if ($type == 'can') $statut = 7; - if (! $error && ! empty($conf->global->SUPPLIER_ORDER_USE_DISPATCH_STATUS) && ($type == 'tot')) - { - // If option SUPPLIER_ORDER_USE_DISPATCH_STATUS is on, we check all reception are approved to allow status "total/done" - $dispatchedlinearray=$this->getDispachedLines(0); - if (count($dispatchedlinearray) > 0) + // Some checks to accept the record + if (! empty($conf->global->SUPPLIER_ORDER_USE_DISPATCH_STATUS)) + { + // If option SUPPLIER_ORDER_USE_DISPATCH_STATUS is on, we check all reception are approved to allow status "total/done" + if (! $error && ($type == 'tot')) + { + $dispatchedlinearray=$this->getDispachedLines(0); + if (count($dispatchedlinearray) > 0) + { + $result=-1; + $error++; + $this->errors[]='ErrorCantSetReceptionToTotalDoneWithReceptionToApprove'; + dol_syslog('ErrorCantSetReceptionToTotalDoneWithReceptionToApprove', LOG_DEBUG); + } + + } + if (! $error && ! empty($conf->global->SUPPLIER_ORDER_USE_DISPATCH_STATUS_NEED_APPROVE) && ($type == 'tot')) // Accept to move to rception done, only if status of all line are ok (refuse denied) { - $result=-1; - $error++; - $this->errors[]='ErrorCantSetReceptionToTotalDoneWithReceptionToApprove'; - dol_syslog('ErrorCantSetReceptionToTotalDoneWithReceptionToApprove', LOG_DEBUG); + $dispatcheddenied=$this->getDispachedLines(2); + if (count($dispatchedlinearray) > 0) + { + $result=-1; + $error++; + $this->errors[]='ErrorCantSetReceptionToTotalDoneWithReceptionDenied'; + dol_syslog('ErrorCantSetReceptionToTotalDoneWithReceptionDenied', LOG_DEBUG); + } } - } + } + + // TODO LDR01 Add option to accept only if ALL predefined products are received (same qty). + if (! $error && ! ($statut == 4 or $statut == 5 or $statut == 7)) { @@ -2367,7 +2400,7 @@ class CommandeFournisseur extends CommonOrder } } - if ($nb === 0) return $langs->trans('Undefined'); + if ($nb === 0) return ''; else return $nb.' '.$langs->trans('Days'); } @@ -2382,6 +2415,23 @@ class CommandeFournisseur extends CommonOrder return $user->rights->fournisseur->commande; } + + /** + * Function used to replace a thirdparty id with another one. + * + * @param DoliDB $db Database handler + * @param int $origin_id Old thirdparty id + * @param int $dest_id New thirdparty id + * @return bool + */ + public static function replaceThirdparty(DoliDB $db, $origin_id, $dest_id) + { + $tables = array( + 'commande_fournisseur' + ); + + return CommonObject::commonReplaceThirdparty($db, $origin_id, $dest_id, $tables); + } } diff --git a/htdocs/fourn/class/fournisseur.commande.dispatch.class.php b/htdocs/fourn/class/fournisseur.commande.dispatch.class.php index e7aea53945e..4d6f75444b8 100644 --- a/htdocs/fourn/class/fournisseur.commande.dispatch.class.php +++ b/htdocs/fourn/class/fournisseur.commande.dispatch.class.php @@ -495,16 +495,19 @@ class CommandeFournisseurDispatch extends CommonObject { if ($statut==0) return img_picto($langs->trans($this->statuts[$statut]),'statut0'); if ($statut==1) return img_picto($langs->trans($this->statuts[$statut]),'statut4'); + if ($statut==2) return img_picto($langs->trans($this->statuts[$statut]),'statut8'); } if ($mode == 4) { if ($statut==0) return img_picto($langs->trans($this->statuts[$statut]),'statut0').' '.$langs->trans($this->statuts[$statut]); if ($statut==1) return img_picto($langs->trans($this->statuts[$statut]),'statut4').' '.$langs->trans($this->statuts[$statut]); + if ($statut==2) return img_picto($langs->trans($this->statuts[$statut]),'statut8').' '.$langs->trans($this->statuts[$statut]); } if ($mode == 5) { if ($statut==0) return ''.$langs->trans($this->statutshort[$statut]).' '.img_picto($langs->trans($this->statuts[$statut]),'statut0'); if ($statut==1) return ''.$langs->trans($this->statutshort[$statut]).' '.img_picto($langs->trans($this->statuts[$statut]),'statut4'); + if ($statut==2) return ''.$langs->trans($this->statutshort[$statut]).' '.img_picto($langs->trans($this->statuts[$statut]),'statut8'); } } diff --git a/htdocs/fourn/class/fournisseur.facture.class.php b/htdocs/fourn/class/fournisseur.facture.class.php index 19cb26cf17b..59ea5544681 100644 --- a/htdocs/fourn/class/fournisseur.facture.class.php +++ b/htdocs/fourn/class/fournisseur.facture.class.php @@ -55,10 +55,15 @@ class FactureFournisseur extends CommonInvoice var $socid; //Check constants for types var $type = self::TYPE_STANDARD; - //! 0=draft, - //! 1=validated - //! 2=classified paid partially (close_code='discount_vat','badcustomer') or completely (close_code=null), - //! Also 2, should be 3=classified abandoned and no payment done (close_code='badcustomer','abandon' ou 'replaced') + + /** + * Check constants for more info: + * - STATUS_DRAFT + * - STATUS_VALIDATED + * - STATUS_PAID + * - STATUS_ABANDONED + * @var int + */ var $statut; //! 1 si facture payee COMPLETEMENT, 0 sinon (ce champ ne devrait plus servir car insuffisant) var $paye; @@ -100,7 +105,7 @@ class FactureFournisseur extends CommonInvoice var $fk_incoterms; var $location_incoterms; var $libelle_incoterms; //Used into tooltip - + var $extraparams=array(); /** @@ -248,7 +253,7 @@ class FactureFournisseur extends CommonInvoice $action='create'; // Actions on extra fields (by external module or standard code) - // FIXME le hook fait double emploi avec le trigger !! + // TODO le hook fait double emploi avec le trigger !! $hookmanager->initHooks(array('supplierinvoicedao')); $parameters=array('socid'=>$this->id); $reshook=$hookmanager->executeHooks('insertExtraFields',$parameters,$this,$action); // Note that $action and $object may have been modified by some hooks @@ -423,9 +428,9 @@ class FactureFournisseur extends CommonInvoice //Incoterms $this->fk_incoterms = $obj->fk_incoterms; - $this->location_incoterms = $obj->location_incoterms; + $this->location_incoterms = $obj->location_incoterms; $this->libelle_incoterms = $obj->libelle_incoterms; - + $this->extraparams = (array) json_decode($obj->extraparams, true); $this->socid = $obj->socid; @@ -438,7 +443,7 @@ class FactureFournisseur extends CommonInvoice $extralabels=$extrafields->fetch_name_optionals_label($this->table_element,true); $this->fetch_optionals($this->id,$extralabels); - if ($this->statut == 0) $this->brouillon = 1; + if ($this->statut == self::STATUS_DRAFT) $this->brouillon = 1; $result=$this->fetch_lines(); if ($result < 0) @@ -502,7 +507,8 @@ class FactureFournisseur extends CommonInvoice $this->lines[$i]->product_ref = $obj->product_ref; // Internal reference $this->lines[$i]->ref = $obj->product_ref; // deprecated. $this->lines[$i]->ref_supplier = $obj->ref_supplier; // Reference product supplier TODO Rename field ref to ref_supplier into table llx_facture_fourn_det and llx_commande_fournisseurdet and update fields it into updateline - $this->lines[$i]->libelle = $obj->label; // This field may contains label of product (when invoice create from order) + $this->lines[$i]->libelle = $obj->label; // Deprecated + $this->lines[$i]->label = $obj->label; // This field may contains label of product (when invoice create from order) $this->lines[$i]->product_desc = $obj->product_desc; // Description du produit $this->lines[$i]->subprice = $obj->pu_ht; $this->lines[$i]->pu_ht = $obj->pu_ht; @@ -520,6 +526,7 @@ class FactureFournisseur extends CommonInvoice $this->lines[$i]->total_ttc = $obj->total_ttc; $this->lines[$i]->fk_product = $obj->fk_product; $this->lines[$i]->product_type = $obj->product_type; + $this->lines[$i]->product_label = $obj->label; $this->lines[$i]->info_bits = $obj->info_bits; $this->lines[$i]->fk_parent_line = $obj->fk_parent_line; $this->lines[$i]->special_code = $obj->special_code; @@ -572,7 +579,7 @@ class FactureFournisseur extends CommonInvoice // if (isset($this->total_localtax1)) $this->total_localtax1=trim($this->total_localtax1); // if (isset($this->total_localtax2)) $this->total_localtax2=trim($this->total_localtax2); if (isset($this->total_ttc)) $this->total_ttc=trim($this->total_ttc); - if (isset($this->statut)) $this->statut=trim($this->statut); + if (isset($this->statut)) $this->statut=(int) $this->statut; if (isset($this->author)) $this->author=trim($this->author); if (isset($this->fk_user_valid)) $this->fk_user_valid=trim($this->fk_user_valid); if (isset($this->fk_facture_source)) $this->fk_facture_source=trim($this->fk_facture_source); @@ -886,7 +893,7 @@ class FactureFournisseur extends CommonInvoice $error=0; // Protection - if ($this->statut > 0) // This is to avoid to validate twice (avoid errors on logs and stock management) + if ($this->statut > self::STATUS_DRAFT) // This is to avoid to validate twice (avoid errors on logs and stock management) { dol_syslog(get_class($this)."::validate no draft status", LOG_WARNING); return 0; @@ -995,7 +1002,7 @@ class FactureFournisseur extends CommonInvoice if (! $error) { $this->ref = $num; - $this->statut=1; + $this->statut=self::STATUS_VALIDATED; //$this->date_validation=$now; this is stored into log table } @@ -1032,7 +1039,7 @@ class FactureFournisseur extends CommonInvoice $error=0; - if ($this->statut == 0) + if ($this->statut == self::STATUS_DRAFT) { dol_syslog(get_class($this)."::set_draft already draft status", LOG_WARNING); return 0; @@ -1403,7 +1410,7 @@ class FactureFournisseur extends CommonInvoice */ function info($id) { - $sql = 'SELECT c.rowid, datec, tms as datem,'; + $sql = 'SELECT c.rowid, datec, tms as datem, '; $sql.= ' fk_user_author, fk_user_valid'; $sql.= ' FROM '.MAIN_DB_PREFIX.'facture_fourn as c'; $sql.= ' WHERE c.rowid = '.$id; @@ -1429,7 +1436,7 @@ class FactureFournisseur extends CommonInvoice } $this->date_creation = $obj->datec; $this->date_modification = $obj->datem; - //$this->date_validation = $obj->datev; Should be stored in log table + //$this->date_validation = $obj->datev; // This field is not available. Should be store into log table and using this function should be replaced with showing content of log (like for supplier orders) } $this->db->free($result); } @@ -1746,7 +1753,7 @@ class FactureFournisseur extends CommonInvoice // Load source object $object->fetch($fromid); $object->id=0; - $object->statut=0; + $object->statut=self::STATUS_DRAFT; // Clear fields $object->ref_supplier=$langs->trans("CopyOf").' '.$object->ref_supplier; @@ -1847,7 +1854,22 @@ class FactureFournisseur extends CommonInvoice return $user->rights->fournisseur->facture; } + /** + * Function used to replace a thirdparty id with another one. + * + * @param DoliDB $db Database handler + * @param int $origin_id Old thirdparty id + * @param int $dest_id New thirdparty id + * @return bool + */ + public static function replaceThirdparty(DoliDB $db, $origin_id, $dest_id) + { + $tables = array( + 'facture_fourn' + ); + return CommonObject::commonReplaceThirdparty($db, $origin_id, $dest_id, $tables); + } } diff --git a/htdocs/fourn/class/fournisseur.product.class.php b/htdocs/fourn/class/fournisseur.product.class.php index adc1f3a50fc..48c238d60be 100755 --- a/htdocs/fourn/class/fournisseur.product.class.php +++ b/htdocs/fourn/class/fournisseur.product.class.php @@ -4,6 +4,7 @@ * Copyright (C) 2009-2014 Regis Houssin * Copyright (C) 2011 Juanjo Menent * Copyright (C) 2012 Christophe Battarel + * Copyright (C) 2015 Marcos García * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -154,7 +155,7 @@ class ProductFournisseur extends Product * @param float $remise_percent Discount regarding qty (percent) * @param float $remise Discount regarding qty (amount) * @param int $newnpr Set NPR or not - * @param int $delivery_time_days Delay in days for delivery (max) + * @param int $delivery_time_days Delay in days for delivery (max). May be '' if not defined. * @return int <0 if KO, >=0 if OK */ function update_buyprice($qty, $buyprice, $user, $price_base_type, $fourn, $availability, $ref_fourn, $tva_tx, $charges=0, $remise_percent=0, $remise=0, $newnpr=0, $delivery_time_days=0) @@ -167,7 +168,7 @@ class ProductFournisseur extends Product if (empty($charges)) $charges=0; if (empty($availability)) $availability=0; if (empty($remise_percent)) $remise_percent=0; - if (empty($delivery_time_days)) $delivery_time_days=0; + if ($delivery_time_days != '' && ! is_numeric($delivery_time_days)) $delivery_time_days = ''; if ($price_base_type == 'TTC') { //$ttx = get_default_tva($fourn,$mysoc,$this->id); // We must use the VAT rate defined by user and not calculate it @@ -202,7 +203,7 @@ class ProductFournisseur extends Product $sql.= " entity = ".$conf->entity.","; $sql.= " info_bits = ".$newnpr.","; $sql.= " charges = ".$charges.","; - $sql.= " delivery_time_days = ".$delivery_time_days; + $sql.= " delivery_time_days = ".($delivery_time_days != '' ? $delivery_time_days : 'null'); $sql.= " WHERE rowid = ".$this->product_fourn_price_id; // TODO Add price_base_type and price_ttc @@ -360,7 +361,7 @@ class ProductFournisseur extends Product $this->fk_product = $obj->fk_product; $this->fk_availability = $obj->fk_availability; $this->delivery_time_days = $obj->delivery_time_days; - //$this->fourn_tva_npr = $obj->fourn_tva_npr; // FIXME this field not exist in llx_product_fournisseur_price + //$this->fourn_tva_npr = $obj->fourn_tva_npr; // TODO this field not exist in llx_product_fournisseur_price. We should add it ? $this->fk_supplier_price_expression = $obj->fk_supplier_price_expression; if (empty($ignore_expression) && !empty($this->fk_supplier_price_expression)) { @@ -437,16 +438,16 @@ class ProductFournisseur extends Product $prodfourn->fourn_remise_percent = $record["remise_percent"]; $prodfourn->fourn_remise = $record["remise"]; $prodfourn->fourn_unitprice = $record["unitprice"]; - $prodfourn->fourn_charges = $record["charges"]; - $prodfourn->fourn_unitcharges = $record["unitcharges"]; + $prodfourn->fourn_charges = $record["charges"]; + $prodfourn->fourn_unitcharges = $record["unitcharges"]; $prodfourn->fourn_tva_tx = $record["tva_tx"]; $prodfourn->fourn_id = $record["fourn_id"]; $prodfourn->fourn_name = $record["supplier_name"]; $prodfourn->fk_availability = $record["fk_availability"]; $prodfourn->delivery_time_days = $record["delivery_time_days"]; $prodfourn->id = $prodid; - $prodfourn->fourn_tva_npr = $record["info_bits"]; - $prodfourn->fk_supplier_price_expression = $record["fk_supplier_price_expression"]; + $prodfourn->fourn_tva_npr = $record["info_bits"]; + $prodfourn->fk_supplier_price_expression = $record["fk_supplier_price_expression"]; if (!empty($prodfourn->fk_supplier_price_expression)) { $priceparser = new PriceParser($this->db); @@ -631,17 +632,19 @@ class ProductFournisseur extends Product /** * Display supplier of product * - * @param int $withpicto Add picto - * @param string $option Target of link ('', 'customer', 'prospect', 'supplier') - * @return string String with supplier price + * @param int $withpicto Add picto + * @param string $option Target of link ('', 'customer', 'prospect', 'supplier') + * @param int $maxlen Max length of name + * @param integer $notooltip 1=Disable tooltip + * @return string String with supplier price * TODO Remove this method. Use getNomUrl directly. */ - function getSocNomUrl($withpicto=0,$option='supplier') + function getSocNomUrl($withpicto=0,$option='supplier',$maxlen=0,$notooltip=0) { $thirdparty = new Fournisseur($this->db); $thirdparty->fetch($this->fourn_id); - return $thirdparty->getNomUrl($withpicto,$option); + return $thirdparty->getNomUrl($withpicto,$option,$maxlen,$notooltip); } /** @@ -649,15 +652,34 @@ class ProductFournisseur extends Product * * @param int $showunitprice Show "Unit price" into output string * @param int $showsuptitle Show "Supplier" into output string + * @param int $maxlen Max length of name + * @param integer $notooltip 1=Disable tooltip * @return string String with supplier price */ - function display_price_product_fournisseur($showunitprice=1,$showsuptitle=1) + function display_price_product_fournisseur($showunitprice=1,$showsuptitle=1,$maxlen=0,$notooltip=0) { global $langs; $langs->load("suppliers"); - $out=($showunitprice?price($this->fourn_unitprice).' '.$langs->trans("HT").'   (':'').($showsuptitle?$langs->trans("Supplier").': ':'').$this->getSocNomUrl(1, 'supplier').' / '.$langs->trans("SupplierRef").': '.$this->fourn_ref.($showunitprice?')':''); + $out=($showunitprice?price($this->fourn_unitprice).' '.$langs->trans("HT").'   (':'').($showsuptitle?$langs->trans("Supplier").': ':'').$this->getSocNomUrl(1, 'supplier', $maxlen, $notooltip).' / '.$langs->trans("SupplierRef").': '.$this->fourn_ref.($showunitprice?')':''); return $out; } + /** + * Function used to replace a thirdparty id with another one. + * + * @param DoliDB $db Database handler + * @param int $origin_id Old thirdparty id + * @param int $dest_id New thirdparty id + * @return bool + */ + public static function replaceThirdparty(DoliDB $db, $origin_id, $dest_id) + { + $tables = array( + 'product_fournisseur_price' + ); + + return CommonObject::commonReplaceThirdparty($db, $origin_id, $dest_id, $tables); + } + } diff --git a/htdocs/fourn/commande/card.php b/htdocs/fourn/commande/card.php index cbbeaa99499..fe6751c28f2 100644 --- a/htdocs/fourn/commande/card.php +++ b/htdocs/fourn/commande/card.php @@ -140,6 +140,7 @@ if (empty($reshook)) { $result=$object->setValueFrom('ref_supplier',GETPOST('ref_supplier','alpha')); if ($result < 0) setEventMessages($object->error, $object->errors, 'errors'); + else $object->ref_supplier = GETPOST('ref_supplier','alpha'); // The setValueFrom does not set new property of object } // Set incoterm @@ -190,12 +191,13 @@ if (empty($reshook)) if ($result < 0) setEventMessages($object->error, $object->errors, 'errors'); } - if ($action == 'reopen' && $user->rights->fournisseur->commande->approuver) + if ($action == 'reopen') // no test on permission here, permission to use will depends on status { - if (in_array($object->statut, array(1, 2, 5, 6, 7, 9))) + if (in_array($object->statut, array(1, 2, 3, 5, 6, 7, 9))) { if ($object->statut == 1) $newstatus=0; // Validated->Draft else if ($object->statut == 2) $newstatus=0; // Approved->Draft + else if ($object->statut == 3) $newstatus=2; // Ordered->Approved else if ($object->statut == 5) $newstatus=4; // Received->Received partially else if ($object->statut == 6) $newstatus=2; // Canceled->Approved else if ($object->statut == 7) $newstatus=3; // Canceled->Process running @@ -834,7 +836,7 @@ if (empty($reshook)) if (! $error) { // Actions on extra fields (by external module or standard code) - // FIXME le hook fait double emploi avec le trigger !! + // TODO le hook fait double emploi avec le trigger !! $hookmanager->initHooks(array('supplierorderdao')); $parameters=array('id'=>$object->id); @@ -918,22 +920,20 @@ if (empty($reshook)) } $object_id = $object->create($user); - if ($object_id > 0) { dol_include_once('/' . $element . '/class/' . $subelement . '.class.php'); $classname = ucfirst($subelement); $srcobject = new $classname($db); - $srcobject->fetch($object->origin_id); - - $object->set_date_livraison($user, $srcobject->date_livraison); - $object->set_id_projet($user, $srcobject->fk_project); dol_syslog("Try to find source object origin=" . $object->origin . " originid=" . $object->origin_id . " to add lines"); $result = $srcobject->fetch($object->origin_id); if ($result > 0) { + $object->set_date_livraison($user, $srcobject->date_livraison); + $object->set_id_projet($user, $srcobject->fk_project); + $lines = $srcobject->lines; if (empty($lines) && method_exists($srcobject, 'fetch_lines')) { @@ -952,40 +952,40 @@ if (empty($reshook)) if (empty($lines[$i]->subprice) || $lines[$i]->qty <= 0) continue; - $label = (! empty($lines [$i]->label) ? $lines [$i]->label : ''); - $desc = (! empty($lines [$i]->desc) ? $lines [$i]->desc : $lines [$i]->libelle); - $product_type = (! empty($lines [$i]->product_type) ? $lines [$i]->product_type : 0); + $label = (! empty($lines[$i]->label) ? $lines[$i]->label : ''); + $desc = (! empty($lines[$i]->desc) ? $lines[$i]->desc : $lines[$i]->libelle); + $product_type = (! empty($lines[$i]->product_type) ? $lines[$i]->product_type : 0); // Reset fk_parent_line for no child products and special product - if (($lines [$i]->product_type != 9 && empty($lines [$i]->fk_parent_line)) || $lines [$i]->product_type == 9) { + if (($lines[$i]->product_type != 9 && empty($lines[$i]->fk_parent_line)) || $lines[$i]->product_type == 9) { $fk_parent_line = 0; } // Extrafields - if (empty($conf->global->MAIN_EXTRAFIELDS_DISABLED) && method_exists($lines [$i], 'fetch_optionals')) // For avoid conflicts if + if (empty($conf->global->MAIN_EXTRAFIELDS_DISABLED) && method_exists($lines[$i], 'fetch_optionals')) // For avoid conflicts if // trigger used { - $lines [$i]->fetch_optionals($lines [$i]->rowid); - $array_option = $lines [$i]->array_options; + $lines[$i]->fetch_optionals($lines[$i]->rowid); + $array_option = $lines[$i]->array_options; } - $idprod = $productsupplier->find_min_price_product_fournisseur($lines [$i]->fk_product, $lines [$i]->qty); + $idprod = $productsupplier->find_min_price_product_fournisseur($lines[$i]->fk_product, $lines[$i]->qty); $res = $productsupplier->fetch($idProductFourn); $result = $object->addline( $desc, - $lines [$i]->subprice, - $lines [$i]->qty, - $lines [$i]->tva_tx, - $lines [$i]->localtax1_tx, - $lines [$i]->localtax2_tx, - $lines [$i]->fk_product, + $lines[$i]->subprice, + $lines[$i]->qty, + $lines[$i]->tva_tx, + $lines[$i]->localtax1_tx, + $lines[$i]->localtax2_tx, + $lines[$i]->fk_product, $productsupplier->product_fourn_price_id, $productsupplier->ref_fourn, - $lines [$i]->remise_percent, + $lines[$i]->remise_percent, 'HT', 0, - $lines [$i]->product_type, + $lines[$i]->product_type, '', '', null, @@ -998,7 +998,7 @@ if (empty($reshook)) } // Defined the new fk_parent_line - if ($result > 0 && $lines [$i]->product_type == 9) { + if ($result > 0 && $lines[$i]->product_type == 9) { $fk_parent_line = $result; } } @@ -1010,11 +1010,11 @@ if (empty($reshook)) if ($reshook < 0) $error ++; } else { - setEventMessage($srcobject->error, 'errors'); + setEventMessages($srcobject->error, $srcobject->errors, 'errors'); $error ++; } } else { - setEventMessage($object->error, 'errors'); + setEventMessages($object->error, $object->errors, 'errors'); $error ++; } } @@ -1024,7 +1024,7 @@ if (empty($reshook)) if ($id < 0) { $error++; - setEventMessage($langs->trans($object->error), 'errors'); + setEventMessages($object->error, $object->errors, 'errors'); } } } @@ -1913,7 +1913,7 @@ elseif (! empty($object->id)) print '
'.$langs->trans('NbDaysToDelivery').' '.img_picto($langs->trans('DescNbDaysToDelivery'), 'info', 'style="cursor:help"').''.$object->getMaxDeliveryTimeDay($langs).'
'.$langs->trans("ToOrder").'
'.$langs->trans("OrderDate").''; $date_com = dol_mktime(0, 0, 0, GETPOST('remonth'), GETPOST('reday'), GETPOST('reyear')); - print $form->select_date($date_com,'','','','',"commande"); + print $form->select_date($date_com,'',1,1,'',"commande"); print '
'.$langs->trans("OrderMode").''; @@ -2785,6 +2792,7 @@ elseif (! empty($object->id)) /* * Receptionner (action=livraison) */ + print ''."\n"; print ''; print ''; print ''; @@ -2792,7 +2800,7 @@ elseif (! empty($object->id)) print ''; //print ''; print '\n"; print ""; $linktoprod=''.img_object($langs->trans("ShowProduct"),'product').' '.$objp->ref.''; @@ -443,16 +480,6 @@ if ($id > 0 || ! empty($ref)) print ""; } - // To show detail cref and description value, we must make calculation by cref - //print ($objp->cref?' ('.$objp->cref.')':''); - //if ($objp->description) print '
'.nl2br($objp->description); - if ((empty($conf->productbatch->enabled)) || $objp->tobatch==0) - { - $suffix='_'.$i; - } else { - $suffix='_0_'.$i; - } - $up_ht_disc=$objp->subprice; if (! empty($objp->remise_percent) && empty($conf->global->STOCK_EXCLUDE_DISCOUNT_FOR_PMP)) $up_ht_disc=price2num($up_ht_disc * (100 - $objp->remise_percent) / 100, 'MU'); @@ -476,13 +503,15 @@ if ($id > 0 || ! empty($ref)) print ''; print ''; print ''; print ''; print ''; // Qty ordered + qty already dispatached } @@ -495,7 +524,7 @@ if ($id > 0 || ! empty($ref)) print ''; print ''; } - print ''; + print ''; print ''; // Warehouse @@ -553,7 +582,8 @@ if ($id > 0 || ! empty($ref)) dol_fiche_end(); - // List of already dispatching + + // List of lines already dispatched $sql = "SELECT p.ref, p.label,"; $sql.= " e.rowid as warehouse_id, e.label as entrepot,"; $sql.= " cfd.rowid as dispatchlineid, cfd.fk_product, cfd.qty, cfd.eatby, cfd.sellby, cfd.batch, cfd.comment, cfd.status"; @@ -643,11 +673,13 @@ if ($id > 0 || ! empty($ref)) { if (empty($objp->status)) { - print ''.$langs->trans("Check").''; + print ''.$langs->trans("Approve").''; + print ''.$langs->trans("Deny").''; } else { - print ''.$langs->trans("Uncheck").''; + print ''.$langs->trans("Disapprove").''; + print ''.$langs->trans("Deny").''; } } else @@ -656,11 +688,18 @@ if ($id > 0 || ! empty($ref)) if ($commande->statut == 5) $disabled=1; if (empty($objp->status)) { - print 'dispatchlineid.'">'.$langs->trans("Check").''; + print 'dispatchlineid.'">'.$langs->trans("Approve").''; + print 'dispatchlineid.'">'.$langs->trans("Deny").''; } - else + if ($objp->status == 1) { - print 'dispatchlineid.'">'.$langs->trans("Uncheck").''; + print 'dispatchlineid.'">'.$langs->trans("Reinit").''; + print 'dispatchlineid.'">'.$langs->trans("Deny").''; + } + if ($objp->status == 2) + { + print 'dispatchlineid.'">'.$langs->trans("Reinit").''; + print 'dispatchlineid.'">'.$langs->trans("Approve").''; } } print ''; diff --git a/htdocs/fourn/commande/list.php b/htdocs/fourn/commande/list.php index 386caad8134..88cf3a48555 100644 --- a/htdocs/fourn/commande/list.php +++ b/htdocs/fourn/commande/list.php @@ -316,7 +316,7 @@ if ($resql) print "
'.$langs->trans("Receive").'
'.$langs->trans("DeliveryDate").''; - print $form->select_date('','','','','',"commande"); + print $form->select_date('','',1,1,'',"commande"); print "
".$langs->trans("Delivery")."\n"; diff --git a/htdocs/fourn/commande/dispatch.php b/htdocs/fourn/commande/dispatch.php index 84b03f1953a..b3d1c9b12dd 100644 --- a/htdocs/fourn/commande/dispatch.php +++ b/htdocs/fourn/commande/dispatch.php @@ -101,6 +101,23 @@ if ($action == 'uncheckdispatchline' && } } +if ($action == 'denydispatchline' && + ! ((empty($conf->global->MAIN_USE_ADVANCED_PERMS) && empty($user->rights->fournisseur->commande->receptionner)) + || (! empty($conf->global->MAIN_USE_ADVANCED_PERMS) && empty($user->rights->fournisseur->commande_advance->check))) +) +{ + $supplierorderdispatch = new CommandeFournisseurDispatch($db); + $result=$supplierorderdispatch->fetch($lineid); + if (! $result) dol_print_error($db); + $result=$supplierorderdispatch->setStatut(2); + if ($result < 0) + { + setEventMessages($supplierorderdispatch->error, $supplierorderdispatch->errors, 'errors'); + $error++; + $action=''; + } +} + if ($action == 'dispatch' && $user->rights->fournisseur->commande->receptionner) { $commande = new CommandeFournisseur($db); @@ -110,11 +127,15 @@ if ($action == 'dispatch' && $user->rights->fournisseur->commande->receptionner) $db->begin(); + $pos=0; foreach($_POST as $key => $value) { if (preg_match('/^product_([0-9]+)$/i', $key, $reg)) // without batch module enabled { - $numline=$reg[1] + 1; // line of product + $pos++; + + //$numline=$reg[1] + 1; // line of product + $numline=$pos; $prod = "product_".$reg[1]; $qty = "qty_".$reg[1]; $ent = "entrepot_".$reg[1]; @@ -123,7 +144,7 @@ if ($action == 'dispatch' && $user->rights->fournisseur->commande->receptionner) if (GETPOST($qty) > 0) // We ask to move a qty { - if (! GETPOST($ent,'int') > 0) + if (! (GETPOST($ent,'int') > 0)) { dol_syslog('No dispatch for line '.$key.' as no warehouse choosed'); $text = $langs->transnoentities('Warehouse').', '.$langs->transnoentities('Line').' ' .($numline); @@ -133,7 +154,7 @@ if ($action == 'dispatch' && $user->rights->fournisseur->commande->receptionner) if (! $error) { - $result = $commande->DispatchProduct($user, GETPOST($prod,'int'),GETPOST($qty), GETPOST($ent,'int'), GETPOST($pu), GETPOST("comment"), '', '', '', GETPOST($fk_commandefourndet, 'int'), $notrigger); + $result = $commande->DispatchProduct($user, GETPOST($prod,'int'), GETPOST($qty), GETPOST($ent,'int'), GETPOST($pu), GETPOST("comment"), '', '', '', GETPOST($fk_commandefourndet, 'int'), $notrigger); if ($result < 0) { setEventMessages($commande->error, $commande->errors, 'errors'); @@ -144,8 +165,11 @@ if ($action == 'dispatch' && $user->rights->fournisseur->commande->receptionner) } if (preg_match('/^product_([0-9]+)_([0-9]+)$/i', $key, $reg)) // with batch module enabled { + $pos++; + //eat-by date dispatch - $numline=$reg[2] + 1; // line of product + //$numline=$reg[2] + 1; // line of product + $numline=$pos; $prod = "product_".$reg[1]."_".$reg[2]; $qty = "qty_".$reg[1]."_".$reg[2]; $ent = "entrepot_".$reg[1]."_".$reg[2]; @@ -185,7 +209,6 @@ if ($action == 'dispatch' && $user->rights->fournisseur->commande->receptionner) } } } - } if (! $notrigger && ! $error) @@ -413,6 +436,20 @@ if ($id > 0 || ! empty($ref)) $nbproduct++; $var=!$var; + + // To show detail cref and description value, we must make calculation by cref + //print ($objp->cref?' ('.$objp->cref.')':''); + //if ($objp->description) print '
'.nl2br($objp->description); + if ((empty($conf->productbatch->enabled)) || $objp->tobatch==0) + { + $suffix='_'.$i; + } else { + $suffix='_0_'.$i; + } + + + print "\n"; + print ''."\n"; print "
'; - print ''; + print ''; print ''; - $form->select_date('','dlc'.$suffix,'','',1,""); + $dlcdatesuffix=dol_mktime(0, 0, 0, GETPOST('dlc'.$suffix.'month'), GETPOST('dlc'.$suffix.'day'), GETPOST('dlc'.$suffix.'year')); + $form->select_date($dlcdatesuffix,'dlc'.$suffix,'','',1,""); print ''; - $form->select_date('','dluo'.$suffix,'','',1,""); + $dluodatesuffix=dol_mktime(0, 0, 0, GETPOST('dluo'.$suffix.'month'), GETPOST('dluo'.$suffix.'day'), GETPOST('dluo'.$suffix.'year')); + $form->select_date($dluodatesuffix,'dluo'.$suffix,'','',1,""); print ' 
\n"; print "\n"; - print '
'.img_help(1,'').' '.$langs->trans("ToBillSeveralOrderSelectCustomer", $langs->transnoentitiesnoconv("CreateInvoiceForThisCustomer")).'
'; + if (! empty($conf->facture->enable)) print '
'.img_help(1,'').' '.$langs->trans("ToBillSeveralOrderSelectCustomer", $langs->transnoentitiesnoconv("CreateInvoiceForThisCustomer")).'
'; $db->free($resql); } diff --git a/htdocs/fourn/commande/orderstoinvoice.php b/htdocs/fourn/commande/orderstoinvoice.php index 6792e9356b1..6cd0dfb02c2 100644 --- a/htdocs/fourn/commande/orderstoinvoice.php +++ b/htdocs/fourn/commande/orderstoinvoice.php @@ -7,6 +7,7 @@ * Copyright (C) 2012 David Rodriguez Martinez * Copyright (C) 2012 Juanjo Menent * Copyright (C) 2014 Florian Henry + * Copyright (C) 2015 Marcos García * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -160,32 +161,14 @@ if (($action == 'create' || $action == 'add') && empty($mesgs)) { $object->date_echeance = $object->calculate_date_lim_reglement(); if ($_POST['origin'] && $_POST['originid']) { - $object->origin = $_POST['origin']; - $object->origin_id = $orders_id[$ii]; $object->linked_objects = $orders_id; $id = $object->create($user); if ($id > 0) { foreach ( $orders_id as $origin => $origin_id ) { - $origin_id = (! empty($origin_id) ? $origin_id : $object->origin_id); - $db->begin(); - $sql = "INSERT INTO " . MAIN_DB_PREFIX . "element_element ("; - $sql .= "fk_source"; - $sql .= ", sourcetype"; - $sql .= ", fk_target"; - $sql .= ", targettype"; - $sql .= ") VALUES ("; - $sql .= $origin_id; - $sql .= ", '" . $object->origin . "'"; - $sql .= ", " . $id; - $sql .= ", '" . $object->element . "'"; - $sql .= ")"; + $origin_id = (! empty($origin_id) ? $origin_id : $orders_id[$ii]); - if ($db->query($sql)) { - $db->commit(); - } else { - $db->rollback(); - } + $object->add_object_linked($_POST['origin'], $origin_id); } while ( $ii < $nn ) { @@ -577,7 +560,7 @@ if (($action != 'create' && $action != 'add') || ! empty($mesgs)) { print '
'; print ''; print ''; - print '
'; + print '
'; // print ''.$langs->trans("GoBack").''; print ''; print '
'; diff --git a/htdocs/fourn/facture/card.php b/htdocs/fourn/facture/card.php index e93d06ad530..4c401c2c540 100644 --- a/htdocs/fourn/facture/card.php +++ b/htdocs/fourn/facture/card.php @@ -288,7 +288,7 @@ if (empty($reshook)) elseif ($action == 'deletepaiement' && $user->rights->fournisseur->facture->creer) { $object->fetch($id); - if ($object->statut == 1 && $object->paye == 0) + if ($object->statut == FactureFournisseur::STATUS_VALIDATED && $object->paye == 0) { $paiementfourn = new PaiementFourn($db); $result=$paiementfourn->fetch(GETPOST('paiement_id')); @@ -547,27 +547,25 @@ if (empty($reshook)) { $up = price2num(GETPOST('price_ht')); $price_base_type = 'HT'; - $result=$object->addline($desc, $ht, $qty, $tva_tx, $localtax1_tx, $localtax2_tx, 0, 0, '', $remise_percent, $price_base_type, 0, $type,'','', $date_start, $date_end); } else { $up = price2num(GETPOST('price_ttc')); $price_base_type = 'TTC'; - $result=$object->addline($desc, $ht, $qty, $tva_tx, $localtax1_tx, $localtax2_tx, 0, 0, '', $remise_percent, $price_base_type, $ttc, $type,'','', $date_start, $date_end); } - if (GETPOST('idprod')) + if (GETPOST('productid')) { $prod = new Product($db); - $prod->fetch($_POST['idprod']); + $prod->fetch(GETPOST('productid')); $label = $prod->description; - if (trim($_POST['desc']) != trim($label)) $label=$_POST['desc']; + if (trim($_POST['product_desc']) != trim($label)) $label=$_POST['product_desc']; $type = $prod->type; } else { - $label = $_POST['desc']; + $label = $_POST['product_desc']; $type = $_POST["type"]?$_POST["type"]:0; } @@ -589,7 +587,7 @@ if (empty($reshook)) } } - $result=$object->updateline(GETPOST('lineid'), $label, $up, $tva_tx, $localtax1_tx, $localtax2_tx, GETPOST('qty'), GETPOST('idprod'), $price_base_type, 0, $type, $remise_percent, 0, $date_start, $date_end, $array_options); + $result=$object->updateline(GETPOST('lineid'), $label, $up, $tva_tx, $localtax1_tx, $localtax2_tx, GETPOST('qty'), GETPOST('productid'), $price_base_type, 0, $type, $remise_percent, 0, $date_start, $date_end, $array_options); if ($result >= 0) { unset($_POST['label']); @@ -867,8 +865,8 @@ if (empty($reshook)) elseif ($action == 'reopen' && $user->rights->fournisseur->facture->creer) { $result = $object->fetch($id); - if ($object->statut == 2 - || ($object->statut == 3 && $object->close_code != 'replaced')) + if ($object->statut == FactureFournisseur::STATUS_CLOSED + || ($object->statut == FactureFournisseur::STATUS_ABANDONED && $object->close_code != 'replaced')) { $result = $object->set_unpaid($user); if ($result > 0) @@ -1139,7 +1137,7 @@ if (empty($reshook)) if (!$error) { // Actions on extra fields (by external module or standard code) - // FIXME le hook fait double emploi avec le trigger !! + // TODO le hook fait double emploi avec le trigger !! $hookmanager->initHooks(array('supplierinvoicedao')); $parameters=array('id'=>$object->id); @@ -1739,8 +1737,8 @@ else print "
'.$form->editfieldkey("RefSupplier",'ref_supplier',$object->ref_supplier,$object,($object->statut<2 && $user->rights->fournisseur->facture->creer)).''; - print $form->editfieldval("RefSupplier",'ref_supplier',$object->ref_supplier,$object,($object->statut<2 && $user->rights->fournisseur->facture->creer)); + print '
'.$form->editfieldkey("RefSupplier",'ref_supplier',$object->ref_supplier,$object,($object->statutrights->fournisseur->facture->creer)).''; + print $form->editfieldval("RefSupplier",'ref_supplier',$object->ref_supplier,$object,($object->statutrights->fournisseur->facture->creer)); print '
'.$form->editfieldkey("Label",'label',$object->label,$object,($object->statut<2 && $user->rights->fournisseur->facture->creer)).''.$form->editfieldval("Label",'label',$object->label,$object,($object->statut<2 && $user->rights->fournisseur->facture->creer)).'
'.$form->editfieldkey("Label",'label',$object->label,$object,($object->statutrights->fournisseur->facture->creer)).''.$form->editfieldval("Label",'label',$object->label,$object,($object->statutrights->fournisseur->facture->creer)).''.price($objp->amount).''; - if ($object->statut == 1 && $object->paye == 0 && $user->societe_id == 0) + if ($object->statut == FactureFournisseur::STATUS_VALIDATED && $object->paye == 0 && $user->societe_id == 0) { print 'rowid.'">'; print img_delete(); @@ -1891,15 +1889,17 @@ else print '
'.$form->editfieldkey("Date",'datef',$object->datep,$object,($object->statut<2 && $user->rights->fournisseur->facture->creer && $object->getSommePaiement() <= 0),'datepicker').''; - print $form->editfieldval("Date",'datef',$object->datep,$object,($object->statut<2 && $user->rights->fournisseur->facture->creer && $object->getSommePaiement() <= 0),'datepicker'); + print '
'.$form->editfieldkey("Date",'datef',$object->datep,$object,$form_permission,'datepicker').''; + print $form->editfieldval("Date",'datef',$object->datep,$object,$form_permission,'datepicker'); print '
'.$form->editfieldkey("DateMaxPayment",'date_lim_reglement',$object->date_echeance,$object,($object->statut<2 && $user->rights->fournisseur->facture->creer && $object->getSommePaiement() <= 0),'datepicker').''; - print $form->editfieldval("DateMaxPayment",'date_lim_reglement',$object->date_echeance,$object,($object->statut<2 && $user->rights->fournisseur->facture->creer && $object->getSommePaiement() <= 0),'datepicker'); - if ($action != 'editdate_lim_reglement' && $object->statut < 2 && $object->date_echeance && $object->date_echeance < ($now - $conf->facture->fournisseur->warning_delay)) print img_warning($langs->trans('Late')); + print '
'.$form->editfieldkey("DateMaxPayment",'date_lim_reglement',$object->date_echeance,$object,$form_permission,'datepicker').''; + print $form->editfieldval("DateMaxPayment",'date_lim_reglement',$object->date_echeance,$object,$form_permission,'datepicker'); + if ($action != 'editdate_lim_reglement' && $object->statut < FactureFournisseur::STATUS_CLOSED && $object->date_echeance && $object->date_echeance < ($now - $conf->facture->fournisseur->warning_delay)) print img_warning($langs->trans('Late')); print '
'.$langs->trans('Status').''.$object->getLibStatut(4,$alreadypaid).'
'.$langs->trans('AmountHT').''.price($object->total_ht,1,$langs,0,-1,-1,$conf->currency).' 
'.$langs->trans('AmountVAT').''.price($object->total_tva,1,$langs,0,-1,-1,$conf->currency).''; + // Amount + print '
'.$langs->trans('AmountHT').''.price($object->total_ht,1,$langs,0,-1,-1,$conf->currency).'
'.$langs->trans('AmountVAT').''.price($object->total_tva,1,$langs,0,-1,-1,$conf->currency).''; if (GETPOST('calculationrule')) $calculationrule=GETPOST('calculationrule','alpha'); else $calculationrule=(empty($conf->global->MAIN_ROUNDOFTOTAL_NOT_TOTALOFROUND)?'totalofround':'roundoftotal'); if ($calculationrule == 'totalofround') $calculationrulenum=1; @@ -1980,16 +1981,16 @@ else if ($societe->localtax1_assuj=="1") //Localtax1 { print '
'.$langs->transcountry("AmountLT1",$societe->country_code).''.price($object->total_localtax1,1,$langs,0,-1,-1,$conf->currency).' 
'.price($object->total_localtax1,1,$langs,0,-1,-1,$conf->currency).'
'.$langs->transcountry("AmountLT2",$societe->country_code).''.price($object->total_localtax2,1,$langs,0,-1,-1,$conf->currency).' 
'.price($object->total_localtax2,1,$langs,0,-1,-1,$conf->currency).'
'.$langs->trans('AmountTTC').''.price($object->total_ttc,1,$langs,0,-1,-1,$conf->currency).' 
'.$langs->trans('AmountTTC').''.price($object->total_ttc,1,$langs,0,-1,-1,$conf->currency).'
'.$langs->trans('Status').''.$object->getLibStatut(4,$alreadypaid).'
'.$langs->trans('AmountHT').''.price($object->total_ht,1,$langs,0,-1,-1,$conf->currency).'
'.$langs->trans('AmountVAT').''.price($object->total_tva,1,$langs,0,-1,-1,$conf->currency).'
'.$langs->transcountry("AmountLT1",$societe->country_code).''.price($object->total_localtax1,1,$langs,0,-1,-1,$conf->currency).'
'.$langs->transcountry("AmountLT2",$societe->country_code).''.price($object->total_localtax2,1,$langs,0,-1,-1,$conf->currency).'
'.$langs->trans('AmountTTC').''.price($object->total_ttc,1,$langs,0,-1,-1,$conf->currency).'
"; dol_fiche_end(); diff --git a/htdocs/fourn/facture/document.php b/htdocs/fourn/facture/document.php index c7219c6e415..e6fed653421 100644 --- a/htdocs/fourn/facture/document.php +++ b/htdocs/fourn/facture/document.php @@ -168,6 +168,30 @@ if ($object->id > 0) print $form->editfieldval("Label",'label',$object->label,$object,0); print '
'.$langs->trans('Status').''.$object->getLibStatut(4,$alreadypaid).'
'.$langs->trans('AmountHT').''.price($object->total_ht,1,$langs,0,-1,-1,$conf->currency).'
'.$langs->trans('AmountVAT').''.price($object->total_tva,1,$langs,0,-1,-1,$conf->currency).'
'.$langs->transcountry("AmountLT1",$societe->country_code).''.price($object->total_localtax1,1,$langs,0,-1,-1,$conf->currency).'
'.$langs->transcountry("AmountLT2",$societe->country_code).''.price($object->total_localtax2,1,$langs,0,-1,-1,$conf->currency).'
'.$langs->trans('AmountTTC').''.price($object->total_ttc,1,$langs,0,-1,-1,$conf->currency).'

'; print ''; diff --git a/htdocs/fourn/facture/info.php b/htdocs/fourn/facture/info.php index e45833c53f1..7033d555c0e 100644 --- a/htdocs/fourn/facture/info.php +++ b/htdocs/fourn/facture/info.php @@ -31,11 +31,11 @@ require_once DOL_DOCUMENT_ROOT.'/core/lib/fourn.lib.php'; $langs->load('bills'); -$facid = isset($_GET["facid"])?$_GET["facid"]:''; +$id = GETPOST("facid",'int'); // Security check if ($user->societe_id) $socid=$user->societe_id; -$result = restrictedArea($user, 'fournisseur', $facid, 'facture_fourn', 'facture'); +$result = restrictedArea($user, 'fournisseur', $id, 'facture_fourn', 'facture'); @@ -45,22 +45,22 @@ $result = restrictedArea($user, 'fournisseur', $facid, 'facture_fourn', 'facture llxHeader(); -$fac = new FactureFournisseur($db); -$fac->fetch($_GET["facid"]); -$fac->info($_GET["facid"]); +$object = new FactureFournisseur($db); +$object->fetch($id); +$object->info($id); $soc = new Societe($db); -$soc->fetch($fac->socid); +$soc->fetch($object->socid); -$head = facturefourn_prepare_head($fac); +$head = facturefourn_prepare_head($object); $titre=$langs->trans('SupplierInvoice'); dol_fiche_head($head, 'info', $langs->trans('SupplierInvoice'), 0, 'bill'); print '
'; -dol_print_object_info($fac); +dol_print_object_info($object); print '
'; print '
'; -$db->close(); - llxFooter(); + +$db->close(); diff --git a/htdocs/fourn/facture/list.php b/htdocs/fourn/facture/list.php index 3c1b0f06cb6..836d214e19a 100644 --- a/htdocs/fourn/facture/list.php +++ b/htdocs/fourn/facture/list.php @@ -120,7 +120,7 @@ if ($mode == 'search') $now=dol_now(); $form=new Form($db); -$htmlother=new FormOther($db); +$formother=new FormOther($db); $formfile = new FormFile($db); llxHeader('',$langs->trans("SuppliersInvoices"),'EN:Suppliers_Invoices|FR:FactureFournisseur|ES:Facturas_de_proveedores'); @@ -245,7 +245,7 @@ if ($resql) print ' '; print "\n"; - // Lignes des champs de filtre + // Line for filters print ''; print ''; @@ -259,10 +259,8 @@ if ($resql) } print ''; print ''; - //print ' '.$langs->trans('Year').': '; $syear = $year; - //if ($syear == '') $syear = date("Y"); - $htmlother->select_year($syear?$syear:-1,'year',1, 20, 5); + $formother->select_year($syear?$syear:-1,'year',1, 20, 5); print ''; print ' '; print ''; diff --git a/htdocs/fourn/facture/note.php b/htdocs/fourn/facture/note.php index 7d68a3c5a95..3a4528d827e 100644 --- a/htdocs/fourn/facture/note.php +++ b/htdocs/fourn/facture/note.php @@ -139,6 +139,30 @@ if ($object->id > 0) print $form->editfieldval("Label",'label',$object->label,$object,0); print ''; + // Status + $alreadypaid=$object->getSommePaiement(); + print ''.$langs->trans('Status').''.$object->getLibStatut(4,$alreadypaid).''; + + // Amount + print ''.$langs->trans('AmountHT').''.price($object->total_ht,1,$langs,0,-1,-1,$conf->currency).''; + print ''.$langs->trans('AmountVAT').''.price($object->total_tva,1,$langs,0,-1,-1,$conf->currency).''; + + // Amount Local Taxes + //TODO: Place into a function to control showing by country or study better option + if ($societe->localtax1_assuj=="1") //Localtax1 + { + print ''.$langs->transcountry("AmountLT1",$societe->country_code).''; + print ''.price($object->total_localtax1,1,$langs,0,-1,-1,$conf->currency).''; + print ''; + } + if ($societe->localtax2_assuj=="1") //Localtax2 + { + print ''.$langs->transcountry("AmountLT2",$societe->country_code).''; + print ''.price($object->total_localtax2,1,$langs,0,-1,-1,$conf->currency).''; + print ''; + } + print ''.$langs->trans('AmountTTC').''.price($object->total_ttc,1,$langs,0,-1,-1,$conf->currency).''; + print ""; print '
'; diff --git a/htdocs/fourn/facture/paiement.php b/htdocs/fourn/facture/paiement.php index a2e6b9d22bc..e1b57b60c91 100644 --- a/htdocs/fourn/facture/paiement.php +++ b/htdocs/fourn/facture/paiement.php @@ -424,7 +424,7 @@ if ($action == 'create' || $action == 'confirm_paiement' || $action == 'add_paie // Bouton Enregistrer if ($action != 'add_paiement') { - print '<
'.$langs->trans("ClosePaidInvoicesAutomatically"); + print '
'.$langs->trans("ClosePaidInvoicesAutomatically"); print '
'; } diff --git a/htdocs/fourn/list.php b/htdocs/fourn/list.php index 77202f989fe..c44aa39622d 100644 --- a/htdocs/fourn/list.php +++ b/htdocs/fourn/list.php @@ -108,7 +108,7 @@ $result=$hookmanager->executeHooks('printFieldListSelect',$parameters); // No $sql.=$hookmanager->resPrint; $sql.= " FROM ".MAIN_DB_PREFIX."societe as s"; $sql.= " LEFT JOIN ".MAIN_DB_PREFIX."societe_extrafields as ef ON ef.fk_object = s.rowid"; -if (! empty($search_categ) || ! empty($catid)) $sql.= ' LEFT JOIN '.MAIN_DB_PREFIX."categorie_fournisseur as cf ON s.rowid = cf.fk_societe"; // We need this table joined to the select in order to filter by categ +if (! empty($search_categ) || ! empty($catid)) $sql.= ' LEFT JOIN '.MAIN_DB_PREFIX."categorie_fournisseur as cf ON s.rowid = cf.fk_soc"; // We need this table joined to the select in order to filter by categ $sql.= ", ".MAIN_DB_PREFIX."c_stcomm as st"; if (!$user->rights->societe->client->voir && !$socid) $sql .= ", ".MAIN_DB_PREFIX."societe_commerciaux as sc"; $sql.= " WHERE s.fk_stcomm = st.id AND s.fournisseur = 1"; diff --git a/htdocs/includes/nusoap/lib/Mail/PEAR.php b/htdocs/includes/nusoap/lib/Mail/PEAR.php deleted file mode 100644 index 406ef9c23ba..00000000000 --- a/htdocs/includes/nusoap/lib/Mail/PEAR.php +++ /dev/null @@ -1,1100 +0,0 @@ - - * @author Stig Bakken - * @author Tomas V.V.Cox - * @author Greg Beaver - * @copyright 1997-2006 The PHP Group - * @license http://www.php.net/license/3_0.txt PHP License 3.0 - * @link http://pear.php.net/package/PEAR - * @since File available since Release 0.1 - */ - -/**#@+ - * ERROR constants - */ -define('PEAR_ERROR_RETURN', 1); -define('PEAR_ERROR_PRINT', 2); -define('PEAR_ERROR_TRIGGER', 4); -define('PEAR_ERROR_DIE', 8); -define('PEAR_ERROR_CALLBACK', 16); -/** - * WARNING: obsolete - * @deprecated - */ -define('PEAR_ERROR_EXCEPTION', 32); -/**#@-*/ -define('PEAR_ZE2', (function_exists('version_compare') && - version_compare(zend_version(), "2-dev", "ge"))); - -if (substr(PHP_OS, 0, 3) == 'WIN') { - define('OS_WINDOWS', true); - define('OS_UNIX', false); - define('PEAR_OS', 'Windows'); -} else { - define('OS_WINDOWS', false); - define('OS_UNIX', true); - define('PEAR_OS', 'Unix'); // blatant assumption -} - -// instant backwards compatibility -if (!defined('PATH_SEPARATOR')) { - if (OS_WINDOWS) { - define('PATH_SEPARATOR', ';'); - } else { - define('PATH_SEPARATOR', ':'); - } -} - -$GLOBALS['_PEAR_default_error_mode'] = PEAR_ERROR_RETURN; -$GLOBALS['_PEAR_default_error_options'] = E_USER_NOTICE; -$GLOBALS['_PEAR_destructor_object_list'] = array(); -$GLOBALS['_PEAR_shutdown_funcs'] = array(); -$GLOBALS['_PEAR_error_handler_stack'] = array(); - -@ini_set('track_errors', true); - -/** - * Base class for other PEAR classes. Provides rudimentary - * emulation of destructors. - * - * If you want a destructor in your class, inherit PEAR and make a - * destructor method called _yourclassname (same name as the - * constructor, but with a "_" prefix). Also, in your constructor you - * have to call the PEAR constructor: $this->PEAR();. - * The destructor method will be called without parameters. Note that - * at in some SAPI implementations (such as Apache), any output during - * the request shutdown (in which destructors are called) seems to be - * discarded. If you need to get any debug information from your - * destructor, use error_log(), syslog() or something similar. - * - * IMPORTANT! To use the emulated destructors you need to create the - * objects by reference: $obj =& new PEAR_child; - * - * @category pear - * @package PEAR - * @author Stig Bakken - * @author Tomas V.V. Cox - * @author Greg Beaver - * @copyright 1997-2006 The PHP Group - * @license http://www.php.net/license/3_0.txt PHP License 3.0 - * @version Release: 1.4.11 - * @link http://pear.php.net/package/PEAR - * @see PEAR_Error - * @since Class available since PHP 4.0.2 - * @link http://pear.php.net/manual/en/core.pear.php#core.pear.pear - */ -class PEAR -{ - // {{{ properties - - /** - * Whether to enable internal debug messages. - * - * @var bool - * @access private - */ - var $_debug = false; - - /** - * Default error mode for this object. - * - * @var int - * @access private - */ - var $_default_error_mode = null; - - /** - * Default error options used for this object when error mode - * is PEAR_ERROR_TRIGGER. - * - * @var int - * @access private - */ - var $_default_error_options = null; - - /** - * Default error handler (callback) for this object, if error mode is - * PEAR_ERROR_CALLBACK. - * - * @var string - * @access private - */ - var $_default_error_handler = ''; - - /** - * Which class to use for error objects. - * - * @var string - * @access private - */ - var $_error_class = 'PEAR_Error'; - - /** - * An array of expected errors. - * - * @var array - * @access private - */ - var $_expected_errors = array(); - - // }}} - - // {{{ constructor - - /** - * Constructor. Registers this object in - * $_PEAR_destructor_object_list for destructor emulation if a - * destructor object exists. - * - * @param string $error_class (optional) which class to use for - * error objects, defaults to PEAR_Error. - * @access public - * @return void - */ - function PEAR($error_class = null) - { - $classname = strtolower(get_class($this)); - if ($this->_debug) { - print "PEAR constructor called, class=$classname\n"; - } - if ($error_class !== null) { - $this->_error_class = $error_class; - } - while ($classname && strcasecmp($classname, "pear")) { - $destructor = "_$classname"; - if (method_exists($this, $destructor)) { - global $_PEAR_destructor_object_list; - $_PEAR_destructor_object_list[] = &$this; - if (!isset($GLOBALS['_PEAR_SHUTDOWN_REGISTERED'])) { - register_shutdown_function("_PEAR_call_destructors"); - $GLOBALS['_PEAR_SHUTDOWN_REGISTERED'] = true; - } - break; - } else { - $classname = get_parent_class($classname); - } - } - } - - // }}} - // {{{ destructor - - /** - * Destructor (the emulated type of...). Does nothing right now, - * but is included for forward compatibility, so subclass - * destructors should always call it. - * - * See the note in the class desciption about output from - * destructors. - * - * @access public - * @return void - */ - function _PEAR() { - if ($this->_debug) { - printf("PEAR destructor called, class=%s\n", strtolower(get_class($this))); - } - } - - // }}} - // {{{ getStaticProperty() - - /** - * If you have a class that's mostly/entirely static, and you need static - * properties, you can use this method to simulate them. Eg. in your method(s) - * do this: $myVar = &PEAR::getStaticProperty('myclass', 'myVar'); - * You MUST use a reference, or they will not persist! - * - * @access public - * @param string $class The calling classname, to prevent clashes - * @param string $var The variable to retrieve. - * @return mixed A reference to the variable. If not set it will be - * auto initialised to NULL. - */ - function &getStaticProperty($class, $var) - { - static $properties; - return $properties[$class][$var]; - } - - // }}} - // {{{ registerShutdownFunc() - - /** - * Use this function to register a shutdown method for static - * classes. - * - * @access public - * @param mixed $func The function name (or array of class/method) to call - * @param mixed $args The arguments to pass to the function - * @return void - */ - function registerShutdownFunc($func, $args = array()) - { - // if we are called statically, there is a potential - // that no shutdown func is registered. Bug #6445 - if (!isset($GLOBALS['_PEAR_SHUTDOWN_REGISTERED'])) { - register_shutdown_function("_PEAR_call_destructors"); - $GLOBALS['_PEAR_SHUTDOWN_REGISTERED'] = true; - } - $GLOBALS['_PEAR_shutdown_funcs'][] = array($func, $args); - } - - // }}} - // {{{ isError() - - /** - * Tell whether a value is a PEAR error. - * - * @param mixed $data the value to test - * @param int $code if $data is an error object, return true - * only if $code is a string and - * $obj->getMessage() == $code or - * $code is an integer and $obj->getCode() == $code - * @access public - * @return bool true if parameter is an error - */ - function isError($data, $code = null) - { - if (is_a($data, 'PEAR_Error')) { - if (is_null($code)) { - return true; - } elseif (is_string($code)) { - return $data->getMessage() == $code; - } else { - return $data->getCode() == $code; - } - } - return false; - } - - // }}} - // {{{ setErrorHandling() - - /** - * Sets how errors generated by this object should be handled. - * Can be invoked both in objects and statically. If called - * statically, setErrorHandling sets the default behaviour for all - * PEAR objects. If called in an object, setErrorHandling sets - * the default behaviour for that object. - * - * @param int $mode - * One of PEAR_ERROR_RETURN, PEAR_ERROR_PRINT, - * PEAR_ERROR_TRIGGER, PEAR_ERROR_DIE, - * PEAR_ERROR_CALLBACK or PEAR_ERROR_EXCEPTION. - * - * @param mixed $options - * When $mode is PEAR_ERROR_TRIGGER, this is the error level (one - * of E_USER_NOTICE, E_USER_WARNING or E_USER_ERROR). - * - * When $mode is PEAR_ERROR_CALLBACK, this parameter is expected - * to be the callback function or method. A callback - * function is a string with the name of the function, a - * callback method is an array of two elements: the element - * at index 0 is the object, and the element at index 1 is - * the name of the method to call in the object. - * - * When $mode is PEAR_ERROR_PRINT or PEAR_ERROR_DIE, this is - * a printf format string used when printing the error - * message. - * - * @access public - * @return void - * @see PEAR_ERROR_RETURN - * @see PEAR_ERROR_PRINT - * @see PEAR_ERROR_TRIGGER - * @see PEAR_ERROR_DIE - * @see PEAR_ERROR_CALLBACK - * @see PEAR_ERROR_EXCEPTION - * - * @since PHP 4.0.5 - */ - - function setErrorHandling($mode = null, $options = null) - { - if (isset($this) && is_a($this, 'PEAR')) { - $setmode = &$this->_default_error_mode; - $setoptions = &$this->_default_error_options; - } else { - $setmode = &$GLOBALS['_PEAR_default_error_mode']; - $setoptions = &$GLOBALS['_PEAR_default_error_options']; - } - - switch ($mode) { - case PEAR_ERROR_EXCEPTION: - case PEAR_ERROR_RETURN: - case PEAR_ERROR_PRINT: - case PEAR_ERROR_TRIGGER: - case PEAR_ERROR_DIE: - case null: - $setmode = $mode; - $setoptions = $options; - break; - - case PEAR_ERROR_CALLBACK: - $setmode = $mode; - // class/object method callback - if (is_callable($options)) { - $setoptions = $options; - } else { - trigger_error("invalid error callback", E_USER_WARNING); - } - break; - - default: - trigger_error("invalid error mode", E_USER_WARNING); - break; - } - } - - // }}} - // {{{ expectError() - - /** - * This method is used to tell which errors you expect to get. - * Expected errors are always returned with error mode - * PEAR_ERROR_RETURN. Expected error codes are stored in a stack, - * and this method pushes a new element onto it. The list of - * expected errors are in effect until they are popped off the - * stack with the popExpect() method. - * - * Note that this method can not be called statically - * - * @param mixed $code a single error code or an array of error codes to expect - * - * @return int the new depth of the "expected errors" stack - * @access public - */ - function expectError($code = '*') - { - if (is_array($code)) { - array_push($this->_expected_errors, $code); - } else { - array_push($this->_expected_errors, array($code)); - } - return sizeof($this->_expected_errors); - } - - // }}} - // {{{ popExpect() - - /** - * This method pops one element off the expected error codes - * stack. - * - * @return array the list of error codes that were popped - */ - function popExpect() - { - return array_pop($this->_expected_errors); - } - - // }}} - // {{{ _checkDelExpect() - - /** - * This method checks unsets an error code if available - * - * @param mixed error code - * @return bool true if the error code was unset, false otherwise - * @access private - * @since PHP 4.3.0 - */ - function _checkDelExpect($error_code) - { - $deleted = false; - - foreach ($this->_expected_errors AS $key => $error_array) { - if (in_array($error_code, $error_array)) { - unset($this->_expected_errors[$key][array_search($error_code, $error_array)]); - $deleted = true; - } - - // clean up empty arrays - if (0 == count($this->_expected_errors[$key])) { - unset($this->_expected_errors[$key]); - } - } - return $deleted; - } - - // }}} - // {{{ delExpect() - - /** - * This method deletes all occurences of the specified element from - * the expected error codes stack. - * - * @param mixed $error_code error code that should be deleted - * @return mixed list of error codes that were deleted or error - * @access public - * @since PHP 4.3.0 - */ - function delExpect($error_code) - { - $deleted = false; - - if ((is_array($error_code) && (0 != count($error_code)))) { - // $error_code is a non-empty array here; - // we walk through it trying to unset all - // values - foreach($error_code as $key => $error) { - if ($this->_checkDelExpect($error)) { - $deleted = true; - } else { - $deleted = false; - } - } - return $deleted ? true : PEAR::raiseError("The expected error you submitted does not exist"); // IMPROVE ME - } elseif (!empty($error_code)) { - // $error_code comes alone, trying to unset it - if ($this->_checkDelExpect($error_code)) { - return true; - } else { - return PEAR::raiseError("The expected error you submitted does not exist"); // IMPROVE ME - } - } else { - // $error_code is empty - return PEAR::raiseError("The expected error you submitted is empty"); // IMPROVE ME - } - } - - // }}} - // {{{ raiseError() - - /** - * This method is a wrapper that returns an instance of the - * configured error class with this object's default error - * handling applied. If the $mode and $options parameters are not - * specified, the object's defaults are used. - * - * @param mixed $message a text error message or a PEAR error object - * - * @param int $code a numeric error code (it is up to your class - * to define these if you want to use codes) - * - * @param int $mode One of PEAR_ERROR_RETURN, PEAR_ERROR_PRINT, - * PEAR_ERROR_TRIGGER, PEAR_ERROR_DIE, - * PEAR_ERROR_CALLBACK, PEAR_ERROR_EXCEPTION. - * - * @param mixed $options If $mode is PEAR_ERROR_TRIGGER, this parameter - * specifies the PHP-internal error level (one of - * E_USER_NOTICE, E_USER_WARNING or E_USER_ERROR). - * If $mode is PEAR_ERROR_CALLBACK, this - * parameter specifies the callback function or - * method. In other error modes this parameter - * is ignored. - * - * @param string $userinfo If you need to pass along for example debug - * information, this parameter is meant for that. - * - * @param string $error_class The returned error object will be - * instantiated from this class, if specified. - * - * @param bool $skipmsg If true, raiseError will only pass error codes, - * the error message parameter will be dropped. - * - * @access public - * @return object a PEAR error object - * @see PEAR::setErrorHandling - * @since PHP 4.0.5 - */ - function &raiseError($message = null, - $code = null, - $mode = null, - $options = null, - $userinfo = null, - $error_class = null, - $skipmsg = false) - { - // The error is yet a PEAR error object - if (is_object($message)) { - $code = $message->getCode(); - $userinfo = $message->getUserInfo(); - $error_class = $message->getType(); - $message->error_message_prefix = ''; - $message = $message->getMessage(); - } - - if (isset($this) && isset($this->_expected_errors) && sizeof($this->_expected_errors) > 0 && sizeof($exp = end($this->_expected_errors))) { - if ($exp[0] == "*" || - (is_int(reset($exp)) && in_array($code, $exp)) || - (is_string(reset($exp)) && in_array($message, $exp))) { - $mode = PEAR_ERROR_RETURN; - } - } - // No mode given, try global ones - if ($mode === null) { - // Class error handler - if (isset($this) && isset($this->_default_error_mode)) { - $mode = $this->_default_error_mode; - $options = $this->_default_error_options; - // Global error handler - } elseif (isset($GLOBALS['_PEAR_default_error_mode'])) { - $mode = $GLOBALS['_PEAR_default_error_mode']; - $options = $GLOBALS['_PEAR_default_error_options']; - } - } - - if ($error_class !== null) { - $ec = $error_class; - } elseif (isset($this) && isset($this->_error_class)) { - $ec = $this->_error_class; - } else { - $ec = 'PEAR_Error'; - } - if ($skipmsg) { - $a = new $ec($code, $mode, $options, $userinfo); - return $a; - } else { - $a = new $ec($message, $code, $mode, $options, $userinfo); - return $a; - } - } - - // }}} - // {{{ throwError() - - /** - * Simpler form of raiseError with fewer options. In most cases - * message, code and userinfo are enough. - * - * @param string $message - * - */ - function &throwError($message = null, - $code = null, - $userinfo = null) - { - if (isset($this) && is_a($this, 'PEAR')) { - $a = &$this->raiseError($message, $code, null, null, $userinfo); - return $a; - } else { - $a = &PEAR::raiseError($message, $code, null, null, $userinfo); - return $a; - } - } - - // }}} - function staticPushErrorHandling($mode, $options = null) - { - $stack = &$GLOBALS['_PEAR_error_handler_stack']; - $def_mode = &$GLOBALS['_PEAR_default_error_mode']; - $def_options = &$GLOBALS['_PEAR_default_error_options']; - $stack[] = array($def_mode, $def_options); - switch ($mode) { - case PEAR_ERROR_EXCEPTION: - case PEAR_ERROR_RETURN: - case PEAR_ERROR_PRINT: - case PEAR_ERROR_TRIGGER: - case PEAR_ERROR_DIE: - case null: - $def_mode = $mode; - $def_options = $options; - break; - - case PEAR_ERROR_CALLBACK: - $def_mode = $mode; - // class/object method callback - if (is_callable($options)) { - $def_options = $options; - } else { - trigger_error("invalid error callback", E_USER_WARNING); - } - break; - - default: - trigger_error("invalid error mode", E_USER_WARNING); - break; - } - $stack[] = array($mode, $options); - return true; - } - - function staticPopErrorHandling() - { - $stack = &$GLOBALS['_PEAR_error_handler_stack']; - $setmode = &$GLOBALS['_PEAR_default_error_mode']; - $setoptions = &$GLOBALS['_PEAR_default_error_options']; - array_pop($stack); - list($mode, $options) = $stack[sizeof($stack) - 1]; - array_pop($stack); - switch ($mode) { - case PEAR_ERROR_EXCEPTION: - case PEAR_ERROR_RETURN: - case PEAR_ERROR_PRINT: - case PEAR_ERROR_TRIGGER: - case PEAR_ERROR_DIE: - case null: - $setmode = $mode; - $setoptions = $options; - break; - - case PEAR_ERROR_CALLBACK: - $setmode = $mode; - // class/object method callback - if (is_callable($options)) { - $setoptions = $options; - } else { - trigger_error("invalid error callback", E_USER_WARNING); - } - break; - - default: - trigger_error("invalid error mode", E_USER_WARNING); - break; - } - return true; - } - - // {{{ pushErrorHandling() - - /** - * Push a new error handler on top of the error handler options stack. With this - * you can easily override the actual error handler for some code and restore - * it later with popErrorHandling. - * - * @param mixed $mode (same as setErrorHandling) - * @param mixed $options (same as setErrorHandling) - * - * @return bool Always true - * - * @see PEAR::setErrorHandling - */ - function pushErrorHandling($mode, $options = null) - { - $stack = &$GLOBALS['_PEAR_error_handler_stack']; - if (isset($this) && is_a($this, 'PEAR')) { - $def_mode = &$this->_default_error_mode; - $def_options = &$this->_default_error_options; - } else { - $def_mode = &$GLOBALS['_PEAR_default_error_mode']; - $def_options = &$GLOBALS['_PEAR_default_error_options']; - } - $stack[] = array($def_mode, $def_options); - - if (isset($this) && is_a($this, 'PEAR')) { - $this->setErrorHandling($mode, $options); - } else { - PEAR::setErrorHandling($mode, $options); - } - $stack[] = array($mode, $options); - return true; - } - - // }}} - // {{{ popErrorHandling() - - /** - * Pop the last error handler used - * - * @return bool Always true - * - * @see PEAR::pushErrorHandling - */ - function popErrorHandling() - { - $stack = &$GLOBALS['_PEAR_error_handler_stack']; - array_pop($stack); - list($mode, $options) = $stack[sizeof($stack) - 1]; - array_pop($stack); - if (isset($this) && is_a($this, 'PEAR')) { - $this->setErrorHandling($mode, $options); - } else { - PEAR::setErrorHandling($mode, $options); - } - return true; - } - - // }}} - // {{{ loadExtension() - - /** - * OS independant PHP extension load. Remember to take care - * on the correct extension name for case sensitive OSes. - * - * @param string $ext The extension name - * @return bool Success or not on the dl() call - */ - function loadExtension($ext) - { - if (!extension_loaded($ext)) { - // if either returns true dl() will produce a FATAL error, stop that - if ((ini_get('enable_dl') != 1) || (ini_get('safe_mode') == 1)) { - return false; - } - if (OS_WINDOWS) { - $suffix = '.dll'; - } elseif (PHP_OS == 'HP-UX') { - $suffix = '.sl'; - } elseif (PHP_OS == 'AIX') { - $suffix = '.a'; - } elseif (PHP_OS == 'OSX') { - $suffix = '.bundle'; - } else { - $suffix = '.so'; - } - return @dl('php_'.$ext.$suffix) || @dl($ext.$suffix); - } - return true; - } - - // }}} -} - -// {{{ _PEAR_call_destructors() - -function _PEAR_call_destructors() -{ - global $_PEAR_destructor_object_list; - if (is_array($_PEAR_destructor_object_list) && - sizeof($_PEAR_destructor_object_list)) - { - reset($_PEAR_destructor_object_list); - if (@PEAR::getStaticProperty('PEAR', 'destructlifo')) { - $_PEAR_destructor_object_list = array_reverse($_PEAR_destructor_object_list); - } - while (list($k, $objref) = each($_PEAR_destructor_object_list)) { - $classname = get_class($objref); - while ($classname) { - $destructor = "_$classname"; - if (method_exists($objref, $destructor)) { - $objref->$destructor(); - break; - } else { - $classname = get_parent_class($classname); - } - } - } - // Empty the object list to ensure that destructors are - // not called more than once. - $_PEAR_destructor_object_list = array(); - } - - // Now call the shutdown functions - if (is_array($GLOBALS['_PEAR_shutdown_funcs']) AND !empty($GLOBALS['_PEAR_shutdown_funcs'])) { - foreach ($GLOBALS['_PEAR_shutdown_funcs'] as $value) { - call_user_func_array($value[0], $value[1]); - } - } -} - -// }}} -/** - * Standard PEAR error class for PHP 4 - * - * This class is supserseded by {@link PEAR_Exception} in PHP 5 - * - * @category pear - * @package PEAR - * @author Stig Bakken - * @author Tomas V.V. Cox - * @author Gregory Beaver - * @copyright 1997-2006 The PHP Group - * @license http://www.php.net/license/3_0.txt PHP License 3.0 - * @version Release: 1.4.11 - * @link http://pear.php.net/manual/en/core.pear.pear-error.php - * @see PEAR::raiseError(), PEAR::throwError() - * @since Class available since PHP 4.0.2 - */ -class PEAR_Error -{ - // {{{ properties - - var $error_message_prefix = ''; - var $mode = PEAR_ERROR_RETURN; - var $level = E_USER_NOTICE; - var $code = -1; - var $message = ''; - var $userinfo = ''; - var $backtrace = null; - - // }}} - // {{{ constructor - - /** - * PEAR_Error constructor - * - * @param string $message message - * - * @param int $code (optional) error code - * - * @param int $mode (optional) error mode, one of: PEAR_ERROR_RETURN, - * PEAR_ERROR_PRINT, PEAR_ERROR_DIE, PEAR_ERROR_TRIGGER, - * PEAR_ERROR_CALLBACK or PEAR_ERROR_EXCEPTION - * - * @param mixed $options (optional) error level, _OR_ in the case of - * PEAR_ERROR_CALLBACK, the callback function or object/method - * tuple. - * - * @param string $userinfo (optional) additional user/debug info - * - * @access public - * - */ - function PEAR_Error($message = 'unknown error', $code = null, - $mode = null, $options = null, $userinfo = null) - { - if ($mode === null) { - $mode = PEAR_ERROR_RETURN; - } - $this->message = $message; - $this->code = $code; - $this->mode = $mode; - $this->userinfo = $userinfo; - if (function_exists("debug_backtrace")) { - if (@!PEAR::getStaticProperty('PEAR_Error', 'skiptrace')) { - $this->backtrace = debug_backtrace(); - } - } - if ($mode & PEAR_ERROR_CALLBACK) { - $this->level = E_USER_NOTICE; - $this->callback = $options; - } else { - if ($options === null) { - $options = E_USER_NOTICE; - } - $this->level = $options; - $this->callback = null; - } - if ($this->mode & PEAR_ERROR_PRINT) { - if (is_null($options) || is_int($options)) { - $format = "%s"; - } else { - $format = $options; - } - printf($format, $this->getMessage()); - } - if ($this->mode & PEAR_ERROR_TRIGGER) { - trigger_error($this->getMessage(), $this->level); - } - if ($this->mode & PEAR_ERROR_DIE) { - $msg = $this->getMessage(); - if (is_null($options) || is_int($options)) { - $format = "%s"; - if (substr($msg, -1) != "\n") { - $msg .= "\n"; - } - } else { - $format = $options; - } - die(sprintf($format, $msg)); - } - if ($this->mode & PEAR_ERROR_CALLBACK) { - if (is_callable($this->callback)) { - call_user_func($this->callback, $this); - } - } - if ($this->mode & PEAR_ERROR_EXCEPTION) { - trigger_error("PEAR_ERROR_EXCEPTION is obsolete, use class PEAR_Exception for exceptions", E_USER_WARNING); - eval('$e = new Exception($this->message, $this->code);throw($e);'); - } - } - - // }}} - // {{{ getMode() - - /** - * Get the error mode from an error object. - * - * @return int error mode - * @access public - */ - function getMode() { - return $this->mode; - } - - // }}} - // {{{ getCallback() - - /** - * Get the callback function/method from an error object. - * - * @return mixed callback function or object/method array - * @access public - */ - function getCallback() { - return $this->callback; - } - - // }}} - // {{{ getMessage() - - - /** - * Get the error message from an error object. - * - * @return string full error message - * @access public - */ - function getMessage() - { - return ($this->error_message_prefix . $this->message); - } - - - // }}} - // {{{ getCode() - - /** - * Get error code from an error object - * - * @return int error code - * @access public - */ - function getCode() - { - return $this->code; - } - - // }}} - // {{{ getType() - - /** - * Get the name of this error/exception. - * - * @return string error/exception name (type) - * @access public - */ - function getType() - { - return get_class($this); - } - - // }}} - // {{{ getUserInfo() - - /** - * Get additional user-supplied information. - * - * @return string user-supplied information - * @access public - */ - function getUserInfo() - { - return $this->userinfo; - } - - // }}} - // {{{ getDebugInfo() - - /** - * Get additional debug information supplied by the application. - * - * @return string debug information - * @access public - */ - function getDebugInfo() - { - return $this->getUserInfo(); - } - - // }}} - // {{{ getBacktrace() - - /** - * Get the call backtrace from where the error was generated. - * Supported with PHP 4.3.0 or newer. - * - * @param int $frame (optional) what frame to fetch - * @return array Backtrace, or NULL if not available. - * @access public - */ - function getBacktrace($frame = null) - { - if (defined('PEAR_IGNORE_BACKTRACE')) { - return null; - } - if ($frame === null) { - return $this->backtrace; - } - return $this->backtrace[$frame]; - } - - // }}} - // {{{ addUserInfo() - - function addUserInfo($info) - { - if (empty($this->userinfo)) { - $this->userinfo = $info; - } else { - $this->userinfo .= " ** $info"; - } - } - - // }}} - // {{{ toString() - - /** - * Make a string representation of this object. - * - * @return string a string with an object summary - * @access public - */ - function toString() { - $modes = array(); - $levels = array(E_USER_NOTICE => 'notice', - E_USER_WARNING => 'warning', - E_USER_ERROR => 'error'); - if ($this->mode & PEAR_ERROR_CALLBACK) { - if (is_array($this->callback)) { - $callback = (is_object($this->callback[0]) ? - strtolower(get_class($this->callback[0])) : - $this->callback[0]) . '::' . - $this->callback[1]; - } else { - $callback = $this->callback; - } - return sprintf('[%s: message="%s" code=%d mode=callback '. - 'callback=%s prefix="%s" info="%s"]', - strtolower(get_class($this)), $this->message, $this->code, - $callback, $this->error_message_prefix, - $this->userinfo); - } - if ($this->mode & PEAR_ERROR_PRINT) { - $modes[] = 'print'; - } - if ($this->mode & PEAR_ERROR_TRIGGER) { - $modes[] = 'trigger'; - } - if ($this->mode & PEAR_ERROR_DIE) { - $modes[] = 'die'; - } - if ($this->mode & PEAR_ERROR_RETURN) { - $modes[] = 'return'; - } - return sprintf('[%s: message="%s" code=%d mode=%s level=%s '. - 'prefix="%s" info="%s"]', - strtolower(get_class($this)), $this->message, $this->code, - implode("|", $modes), $levels[$this->level], - $this->error_message_prefix, - $this->userinfo); - } - - // }}} -} - -/* - * Local Variables: - * mode: php - * tab-width: 4 - * c-basic-offset: 4 - * End: - */ -?> diff --git a/htdocs/includes/nusoap/lib/Mail/RFC822.php b/htdocs/includes/nusoap/lib/Mail/RFC822.php deleted file mode 100644 index 51849fee4a1..00000000000 --- a/htdocs/includes/nusoap/lib/Mail/RFC822.php +++ /dev/null @@ -1,922 +0,0 @@ - | -// | Chuck Hagenbuch | -// +-----------------------------------------------------------------------+ - -/** - * RFC 822 Email address list validation Utility - * - * What is it? - * - * This class will take an address string, and parse it into it's consituent - * parts, be that either addresses, groups, or combinations. Nested groups - * are not supported. The structure it returns is pretty straight forward, - * and is similar to that provided by the imap_rfc822_parse_adrlist(). Use - * print_r() to view the structure. - * - * How do I use it? - * - * $address_string = 'My Group: "Richard" (A comment), ted@example.com (Ted Bloggs), Barney;'; - * $structure = Mail_RFC822::parseAddressList($address_string, 'example.com', true) - * print_r($structure); - * - * @author Richard Heyes - * @author Chuck Hagenbuch - * @license BSD - * @package Mail - */ -class Mail_RFC822 { - - /** - * The address being parsed by the RFC822 object. - * @var string $address - */ - var $address = ''; - - /** - * The default domain to use for unqualified addresses. - * @var string $default_domain - */ - var $default_domain = 'localhost'; - - /** - * Should we return a nested array showing groups, or flatten everything? - * @var boolean $nestGroups - */ - var $nestGroups = true; - - /** - * Whether or not to validate atoms for non-ascii characters. - * @var boolean $validate - */ - var $validate = true; - - /** - * The array of raw addresses built up as we parse. - * @var array $addresses - */ - var $addresses = array(); - - /** - * The final array of parsed address information that we build up. - * @var array $structure - */ - var $structure = array(); - - /** - * The current error message, if any. - * @var string $error - */ - var $error = null; - - /** - * An internal counter/pointer. - * @var integer $index - */ - var $index = null; - - /** - * The number of groups that have been found in the address list. - * @var integer $num_groups - * @access public - */ - var $num_groups = 0; - - /** - * A variable so that we can tell whether or not we're inside a - * Mail_RFC822 object. - * @var boolean $mailRFC822 - */ - var $mailRFC822 = true; - - /** - * A limit after which processing stops - * @var int $limit - */ - var $limit = null; - - /** - * Sets up the object. The address must either be set here or when - * calling parseAddressList(). One or the other. - * - * @access public - * @param string $address The address(es) to validate. - * @param string $default_domain Default domain/host etc. If not supplied, will be set to localhost. - * @param boolean $nest_groups Whether to return the structure with groups nested for easier viewing. - * @param boolean $validate Whether to validate atoms. Turn this off if you need to run addresses through before encoding the personal names, for instance. - * - * @return object Mail_RFC822 A new Mail_RFC822 object. - */ - function Mail_RFC822($address = null, $default_domain = null, $nest_groups = null, $validate = null, $limit = null) - { - if (isset($address)) $this->address = $address; - if (isset($default_domain)) $this->default_domain = $default_domain; - if (isset($nest_groups)) $this->nestGroups = $nest_groups; - if (isset($validate)) $this->validate = $validate; - if (isset($limit)) $this->limit = $limit; - } - - /** - * Starts the whole process. The address must either be set here - * or when creating the object. One or the other. - * - * @access public - * @param string $address The address(es) to validate. - * @param string $default_domain Default domain/host etc. - * @param boolean $nest_groups Whether to return the structure with groups nested for easier viewing. - * @param boolean $validate Whether to validate atoms. Turn this off if you need to run addresses through before encoding the personal names, for instance. - * - * @return array A structured array of addresses. - */ - function parseAddressList($address = null, $default_domain = null, $nest_groups = null, $validate = null, $limit = null) - { - if (!isset($this) || !isset($this->mailRFC822)) { - $obj = new Mail_RFC822($address, $default_domain, $nest_groups, $validate, $limit); - return $obj->parseAddressList(); - } - - if (isset($address)) $this->address = $address; - if (isset($default_domain)) $this->default_domain = $default_domain; - if (isset($nest_groups)) $this->nestGroups = $nest_groups; - if (isset($validate)) $this->validate = $validate; - if (isset($limit)) $this->limit = $limit; - - $this->structure = array(); - $this->addresses = array(); - $this->error = null; - $this->index = null; - - // Unfold any long lines in $this->address. - $this->address = preg_replace('/\r?\n/', "\r\n", $this->address); - $this->address = preg_replace('/\r\n(\t| )+/', ' ', $this->address); - - while ($this->address = $this->_splitAddresses($this->address)); - - if ($this->address === false || isset($this->error)) { - require_once 'PEAR.php'; - return PEAR::raiseError($this->error); - } - - // Validate each address individually. If we encounter an invalid - // address, stop iterating and return an error immediately. - foreach ($this->addresses as $address) { - $valid = $this->_validateAddress($address); - - if ($valid === false || isset($this->error)) { - require_once 'PEAR.php'; - return PEAR::raiseError($this->error); - } - - if (!$this->nestGroups) { - $this->structure = array_merge($this->structure, $valid); - } else { - $this->structure[] = $valid; - } - } - - return $this->structure; - } - - /** - * Splits an address into separate addresses. - * - * @access private - * @param string $address The addresses to split. - * @return boolean Success or failure. - */ - function _splitAddresses($address) - { - if (!empty($this->limit) && count($this->addresses) == $this->limit) { - return ''; - } - - if ($this->_isGroup($address) && !isset($this->error)) { - $split_char = ';'; - $is_group = true; - } elseif (!isset($this->error)) { - $split_char = ','; - $is_group = false; - } elseif (isset($this->error)) { - return false; - } - - // Split the string based on the above ten or so lines. - $parts = explode($split_char, $address); - $string = $this->_splitCheck($parts, $split_char); - - // If a group... - if ($is_group) { - // If $string does not contain a colon outside of - // brackets/quotes etc then something's fubar. - - // First check there's a colon at all: - if (strpos($string, ':') === false) { - $this->error = 'Invalid address: ' . $string; - return false; - } - - // Now check it's outside of brackets/quotes: - if (!$this->_splitCheck(explode(':', $string), ':')) { - return false; - } - - // We must have a group at this point, so increase the counter: - $this->num_groups++; - } - - // $string now contains the first full address/group. - // Add to the addresses array. - $this->addresses[] = array( - 'address' => trim($string), - 'group' => $is_group - ); - - // Remove the now stored address from the initial line, the +1 - // is to account for the explode character. - $address = trim(substr($address, strlen($string) + 1)); - - // If the next char is a comma and this was a group, then - // there are more addresses, otherwise, if there are any more - // chars, then there is another address. - if ($is_group && substr($address, 0, 1) == ','){ - $address = trim(substr($address, 1)); - return $address; - - } elseif (strlen($address) > 0) { - return $address; - - } else { - return ''; - } - - // If you got here then something's off - return false; - } - - /** - * Checks for a group at the start of the string. - * - * @access private - * @param string $address The address to check. - * @return boolean Whether or not there is a group at the start of the string. - */ - function _isGroup($address) - { - // First comma not in quotes, angles or escaped: - $parts = explode(',', $address); - $string = $this->_splitCheck($parts, ','); - - // Now we have the first address, we can reliably check for a - // group by searching for a colon that's not escaped or in - // quotes or angle brackets. - if (count($parts = explode(':', $string)) > 1) { - $string2 = $this->_splitCheck($parts, ':'); - return ($string2 !== $string); - } else { - return false; - } - } - - /** - * A common function that will check an exploded string. - * - * @access private - * @param array $parts The exloded string. - * @param string $char The char that was exploded on. - * @return mixed False if the string contains unclosed quotes/brackets, or the string on success. - */ - function _splitCheck($parts, $char) - { - $string = $parts[0]; - - for ($i = 0; $i < count($parts); $i++) { - if ($this->_hasUnclosedQuotes($string) - || $this->_hasUnclosedBrackets($string, '<>') - || $this->_hasUnclosedBrackets($string, '[]') - || $this->_hasUnclosedBrackets($string, '()') - || substr($string, -1) == '\\') { - if (isset($parts[$i + 1])) { - $string = $string . $char . $parts[$i + 1]; - } else { - $this->error = 'Invalid address spec. Unclosed bracket or quotes'; - return false; - } - } else { - $this->index = $i; - break; - } - } - - return $string; - } - - /** - * Checks if a string has an unclosed quotes or not. - * - * @access private - * @param string $string The string to check. - * @return boolean True if there are unclosed quotes inside the string, false otherwise. - */ - function _hasUnclosedQuotes($string) - { - $string = explode('"', $string); - $string_cnt = count($string); - - for ($i = 0; $i < (count($string) - 1); $i++) - if (substr($string[$i], -1) == '\\') - $string_cnt--; - - return ($string_cnt % 2 === 0); - } - - /** - * Checks if a string has an unclosed brackets or not. IMPORTANT: - * This function handles both angle brackets and square brackets; - * - * @access private - * @param string $string The string to check. - * @param string $chars The characters to check for. - * @return boolean True if there are unclosed brackets inside the string, false otherwise. - */ - function _hasUnclosedBrackets($string, $chars) - { - $num_angle_start = substr_count($string, $chars[0]); - $num_angle_end = substr_count($string, $chars[1]); - - $this->_hasUnclosedBracketsSub($string, $num_angle_start, $chars[0]); - $this->_hasUnclosedBracketsSub($string, $num_angle_end, $chars[1]); - - if ($num_angle_start < $num_angle_end) { - $this->error = 'Invalid address spec. Unmatched quote or bracket (' . $chars . ')'; - return false; - } else { - return ($num_angle_start > $num_angle_end); - } - } - - /** - * Sub function that is used only by hasUnclosedBrackets(). - * - * @access private - * @param string $string The string to check. - * @param integer &$num The number of occurences. - * @param string $char The character to count. - * @return integer The number of occurences of $char in $string, adjusted for backslashes. - */ - function _hasUnclosedBracketsSub($string, &$num, $char) - { - $parts = explode($char, $string); - for ($i = 0; $i < count($parts); $i++){ - if (substr($parts[$i], -1) == '\\' || $this->_hasUnclosedQuotes($parts[$i])) - $num--; - if (isset($parts[$i + 1])) - $parts[$i + 1] = $parts[$i] . $char . $parts[$i + 1]; - } - - return $num; - } - - /** - * Function to begin checking the address. - * - * @access private - * @param string $address The address to validate. - * @return mixed False on failure, or a structured array of address information on success. - */ - function _validateAddress($address) - { - $is_group = false; - $addresses = array(); - - if ($address['group']) { - $is_group = true; - - // Get the group part of the name - $parts = explode(':', $address['address']); - $groupname = $this->_splitCheck($parts, ':'); - $structure = array(); - - // And validate the group part of the name. - if (!$this->_validatePhrase($groupname)){ - $this->error = 'Group name did not validate.'; - return false; - } else { - // Don't include groups if we are not nesting - // them. This avoids returning invalid addresses. - if ($this->nestGroups) { - $structure = new stdClass; - $structure->groupname = $groupname; - } - } - - $address['address'] = ltrim(substr($address['address'], strlen($groupname . ':'))); - } - - // If a group then split on comma and put into an array. - // Otherwise, Just put the whole address in an array. - if ($is_group) { - while (strlen($address['address']) > 0) { - $parts = explode(',', $address['address']); - $addresses[] = $this->_splitCheck($parts, ','); - $address['address'] = trim(substr($address['address'], strlen(end($addresses) . ','))); - } - } else { - $addresses[] = $address['address']; - } - - // Check that $addresses is set, if address like this: - // Groupname:; - // Then errors were appearing. - if (!count($addresses)){ - $this->error = 'Empty group.'; - return false; - } - - // Trim the whitespace from all of the address strings. - array_map('trim', $addresses); - - // Validate each mailbox. - // Format could be one of: name - // geezer@domain.com - // geezer - // ... or any other format valid by RFC 822. - for ($i = 0; $i < count($addresses); $i++) { - if (!$this->validateMailbox($addresses[$i])) { - if (empty($this->error)) { - $this->error = 'Validation failed for: ' . $addresses[$i]; - } - return false; - } - } - - // Nested format - if ($this->nestGroups) { - if ($is_group) { - $structure->addresses = $addresses; - } else { - $structure = $addresses[0]; - } - - // Flat format - } else { - if ($is_group) { - $structure = array_merge($structure, $addresses); - } else { - $structure = $addresses; - } - } - - return $structure; - } - - /** - * Function to validate a phrase. - * - * @access private - * @param string $phrase The phrase to check. - * @return boolean Success or failure. - */ - function _validatePhrase($phrase) - { - // Splits on one or more Tab or space. - $parts = preg_split('/[ \\x09]+/', $phrase, -1, PREG_SPLIT_NO_EMPTY); - - $phrase_parts = array(); - while (count($parts) > 0){ - $phrase_parts[] = $this->_splitCheck($parts, ' '); - for ($i = 0; $i < $this->index + 1; $i++) - array_shift($parts); - } - - foreach ($phrase_parts as $part) { - // If quoted string: - if (substr($part, 0, 1) == '"') { - if (!$this->_validateQuotedString($part)) { - return false; - } - continue; - } - - // Otherwise it's an atom: - if (!$this->_validateAtom($part)) return false; - } - - return true; - } - - /** - * Function to validate an atom which from rfc822 is: - * atom = 1* - * - * If validation ($this->validate) has been turned off, then - * validateAtom() doesn't actually check anything. This is so that you - * can split a list of addresses up before encoding personal names - * (umlauts, etc.), for example. - * - * @access private - * @param string $atom The string to check. - * @return boolean Success or failure. - */ - function _validateAtom($atom) - { - if (!$this->validate) { - // Validation has been turned off; assume the atom is okay. - return true; - } - - // Check for any char from ASCII 0 - ASCII 127 - if (!preg_match('/^[\\x00-\\x7E]+$/i', $atom, $matches)) { - return false; - } - - // Check for specials: - if (preg_match('/[][()<>@,;\\:". ]/', $atom)) { - return false; - } - - // Check for control characters (ASCII 0-31): - if (preg_match('/[\\x00-\\x1F]+/', $atom)) { - return false; - } - - return true; - } - - /** - * Function to validate quoted string, which is: - * quoted-string = <"> *(qtext/quoted-pair) <"> - * - * @access private - * @param string $qstring The string to check - * @return boolean Success or failure. - */ - function _validateQuotedString($qstring) - { - // Leading and trailing " - $qstring = substr($qstring, 1, -1); - - // Perform check, removing quoted characters first. - return !preg_match('/[\x0D\\\\"]/', preg_replace('/\\\\./', '', $qstring)); - } - - /** - * Function to validate a mailbox, which is: - * mailbox = addr-spec ; simple address - * / phrase route-addr ; name and route-addr - * - * @access public - * @param string &$mailbox The string to check. - * @return boolean Success or failure. - */ - function validateMailbox(&$mailbox) - { - // A couple of defaults. - $phrase = ''; - $comment = ''; - $comments = array(); - - // Catch any RFC822 comments and store them separately. - $_mailbox = $mailbox; - while (strlen(trim($_mailbox)) > 0) { - $parts = explode('(', $_mailbox); - $before_comment = $this->_splitCheck($parts, '('); - if ($before_comment != $_mailbox) { - // First char should be a (. - $comment = substr(str_replace($before_comment, '', $_mailbox), 1); - $parts = explode(')', $comment); - $comment = $this->_splitCheck($parts, ')'); - $comments[] = $comment; - - // +1 is for the trailing ) - $_mailbox = substr($_mailbox, strpos($_mailbox, $comment)+strlen($comment)+1); - } else { - break; - } - } - - foreach ($comments as $comment) { - $mailbox = str_replace("($comment)", '', $mailbox); - } - - $mailbox = trim($mailbox); - - // Check for name + route-addr - if (substr($mailbox, -1) == '>' && substr($mailbox, 0, 1) != '<') { - $parts = explode('<', $mailbox); - $name = $this->_splitCheck($parts, '<'); - - $phrase = trim($name); - $route_addr = trim(substr($mailbox, strlen($name.'<'), -1)); - - if ($this->_validatePhrase($phrase) === false || ($route_addr = $this->_validateRouteAddr($route_addr)) === false) { - return false; - } - - // Only got addr-spec - } else { - // First snip angle brackets if present. - if (substr($mailbox, 0, 1) == '<' && substr($mailbox, -1) == '>') { - $addr_spec = substr($mailbox, 1, -1); - } else { - $addr_spec = $mailbox; - } - - if (($addr_spec = $this->_validateAddrSpec($addr_spec)) === false) { - return false; - } - } - - // Construct the object that will be returned. - $mbox = new stdClass(); - - // Add the phrase (even if empty) and comments - $mbox->personal = $phrase; - $mbox->comment = isset($comments) ? $comments : array(); - - if (isset($route_addr)) { - $mbox->mailbox = $route_addr['local_part']; - $mbox->host = $route_addr['domain']; - $route_addr['adl'] !== '' ? $mbox->adl = $route_addr['adl'] : ''; - } else { - $mbox->mailbox = $addr_spec['local_part']; - $mbox->host = $addr_spec['domain']; - } - - $mailbox = $mbox; - return true; - } - - /** - * This function validates a route-addr which is: - * route-addr = "<" [route] addr-spec ">" - * - * Angle brackets have already been removed at the point of - * getting to this function. - * - * @access private - * @param string $route_addr The string to check. - * @return mixed False on failure, or an array containing validated address/route information on success. - */ - function _validateRouteAddr($route_addr) - { - // Check for colon. - if (strpos($route_addr, ':') !== false) { - $parts = explode(':', $route_addr); - $route = $this->_splitCheck($parts, ':'); - } else { - $route = $route_addr; - } - - // If $route is same as $route_addr then the colon was in - // quotes or brackets or, of course, non existent. - if ($route === $route_addr){ - unset($route); - $addr_spec = $route_addr; - if (($addr_spec = $this->_validateAddrSpec($addr_spec)) === false) { - return false; - } - } else { - // Validate route part. - if (($route = $this->_validateRoute($route)) === false) { - return false; - } - - $addr_spec = substr($route_addr, strlen($route . ':')); - - // Validate addr-spec part. - if (($addr_spec = $this->_validateAddrSpec($addr_spec)) === false) { - return false; - } - } - - if (isset($route)) { - $return['adl'] = $route; - } else { - $return['adl'] = ''; - } - - $return = array_merge($return, $addr_spec); - return $return; - } - - /** - * Function to validate a route, which is: - * route = 1#("@" domain) ":" - * - * @access private - * @param string $route The string to check. - * @return mixed False on failure, or the validated $route on success. - */ - function _validateRoute($route) - { - // Split on comma. - $domains = explode(',', trim($route)); - - foreach ($domains as $domain) { - $domain = str_replace('@', '', trim($domain)); - if (!$this->_validateDomain($domain)) return false; - } - - return $route; - } - - /** - * Function to validate a domain, though this is not quite what - * you expect of a strict internet domain. - * - * domain = sub-domain *("." sub-domain) - * - * @access private - * @param string $domain The string to check. - * @return mixed False on failure, or the validated domain on success. - */ - function _validateDomain($domain) - { - // Note the different use of $subdomains and $sub_domains - $subdomains = explode('.', $domain); - - while (count($subdomains) > 0) { - $sub_domains[] = $this->_splitCheck($subdomains, '.'); - for ($i = 0; $i < $this->index + 1; $i++) - array_shift($subdomains); - } - - foreach ($sub_domains as $sub_domain) { - if (!$this->_validateSubdomain(trim($sub_domain))) - return false; - } - - // Managed to get here, so return input. - return $domain; - } - - /** - * Function to validate a subdomain: - * subdomain = domain-ref / domain-literal - * - * @access private - * @param string $subdomain The string to check. - * @return boolean Success or failure. - */ - function _validateSubdomain($subdomain) - { - if (preg_match('|^\[(.*)]$|', $subdomain, $arr)){ - if (!$this->_validateDliteral($arr[1])) return false; - } else { - if (!$this->_validateAtom($subdomain)) return false; - } - - // Got here, so return successful. - return true; - } - - /** - * Function to validate a domain literal: - * domain-literal = "[" *(dtext / quoted-pair) "]" - * - * @access private - * @param string $dliteral The string to check. - * @return boolean Success or failure. - */ - function _validateDliteral($dliteral) - { - return !preg_match('/(.)[][\x0D\\\\]/', $dliteral, $matches) && $matches[1] != '\\'; - } - - /** - * Function to validate an addr-spec. - * - * addr-spec = local-part "@" domain - * - * @access private - * @param string $addr_spec The string to check. - * @return mixed False on failure, or the validated addr-spec on success. - */ - function _validateAddrSpec($addr_spec) - { - $addr_spec = trim($addr_spec); - - // Split on @ sign if there is one. - if (strpos($addr_spec, '@') !== false) { - $parts = explode('@', $addr_spec); - $local_part = $this->_splitCheck($parts, '@'); - $domain = substr($addr_spec, strlen($local_part . '@')); - - // No @ sign so assume the default domain. - } else { - $local_part = $addr_spec; - $domain = $this->default_domain; - } - - if (($local_part = $this->_validateLocalPart($local_part)) === false) return false; - if (($domain = $this->_validateDomain($domain)) === false) return false; - - // Got here so return successful. - return array('local_part' => $local_part, 'domain' => $domain); - } - - /** - * Function to validate the local part of an address: - * local-part = word *("." word) - * - * @access private - * @param string $local_part - * @return mixed False on failure, or the validated local part on success. - */ - function _validateLocalPart($local_part) - { - $parts = explode('.', $local_part); - $words = array(); - - // Split the local_part into words. - while (count($parts) > 0){ - $words[] = $this->_splitCheck($parts, '.'); - for ($i = 0; $i < $this->index + 1; $i++) { - array_shift($parts); - } - } - - // Validate each word. - foreach ($words as $word) { - // If this word contains an unquoted space, it is invalid. (6.2.4) - if (strpos($word, ' ') && $word[0] !== '"') - { - return false; - } - - if ($this->_validatePhrase(trim($word)) === false) return false; - } - - // Managed to get here, so return the input. - return $local_part; - } - - /** - * Returns an approximate count of how many addresses are in the - * given string. This is APPROXIMATE as it only splits based on a - * comma which has no preceding backslash. Could be useful as - * large amounts of addresses will end up producing *large* - * structures when used with parseAddressList(). - * - * @param string $data Addresses to count - * @return int Approximate count - */ - function approximateCount($data) - { - return count(preg_split('/(?@. This can be sufficient for most - * people. Optional stricter mode can be utilised which restricts - * mailbox characters allowed to alphanumeric, full stop, hyphen - * and underscore. - * - * @param string $data Address to check - * @param boolean $strict Optional stricter mode - * @return mixed False if it fails, an indexed array - * username/domain if it matches - */ - function isValidInetAddress($data, $strict = false) - { - $regex = $strict ? '/^([.0-9a-z_-]+)@(([0-9a-z-]+\.)+[0-9a-z]{2,4})$/i' : '/^([*+!.&#$|\'\\%\/0-9a-z^_`{}=?~:-]+)@(([0-9a-z-]+\.)+[0-9a-z]{2,4})$/i'; - if (preg_match($regex, trim($data), $matches)) { - return array($matches[1], $matches[2]); - } else { - return false; - } - } - -} diff --git a/htdocs/includes/nusoap/lib/Mail/mail.php b/htdocs/includes/nusoap/lib/Mail/mail.php deleted file mode 100644 index 58c01d95f33..00000000000 --- a/htdocs/includes/nusoap/lib/Mail/mail.php +++ /dev/null @@ -1,128 +0,0 @@ - | -// +----------------------------------------------------------------------+ -// - -/** - * internal PHP-mail() implementation of the PEAR Mail:: interface. - * @package Mail - */ -class Mail_mail extends Mail { - - /** - * Any arguments to pass to the mail() function. - * @var string - */ - var $_params = ''; - - /** - * Constructor. - * - * Instantiates a new Mail_mail:: object based on the parameters - * passed in. - * - * @param array $params Extra arguments for the mail() function. - */ - function Mail_mail($params = null) - { - /* The other mail implementations accept parameters as arrays. - * In the interest of being consistent, explode an array into - * a string of parameter arguments. */ - if (is_array($params)) { - $this->_params = join(' ', $params); - } else { - $this->_params = $params; - } - - /* Because the mail() function may pass headers as command - * line arguments, we can't guarantee the use of the standard - * "\r\n" separator. Instead, we use the system's native line - * separator. */ - $this->sep = (strstr(PHP_OS, 'WIN')) ? "\r\n" : "\n"; - } - - /** - * Implements Mail_mail::send() function using php's built-in mail() - * command. - * - * @param mixed $recipients Either a comma-seperated list of recipients - * (RFC822 compliant), or an array of recipients, - * each RFC822 valid. This may contain recipients not - * specified in the headers, for Bcc:, resending - * messages, etc. - * - * @param array $headers The array of headers to send with the mail, in an - * associative array, where the array key is the - * header name (ie, 'Subject'), and the array value - * is the header value (ie, 'test'). The header - * produced from those values would be 'Subject: - * test'. - * - * @param string $body The full text of the message body, including any - * Mime parts, etc. - * - * @return mixed Returns true on success, or a PEAR_Error - * containing a descriptive error message on - * failure. - * - * @access public - */ - function send($recipients, $headers, $body) - { - // If we're passed an array of recipients, implode it. - if (is_array($recipients)) { - $recipients = implode(', ', $recipients); - } - - // Get the Subject out of the headers array so that we can - // pass it as a seperate argument to mail(). - $subject = ''; - if (isset($headers['Subject'])) { - $subject = $headers['Subject']; - unset($headers['Subject']); - } - - // Flatten the headers out. - $headerElements = $this->prepareHeaders($headers); - if (PEAR::isError($headerElements)) { - return $headerElements; - } - list(, $text_headers) = $headerElements; - - /* - * We only use mail()'s optional fifth parameter if the additional - * parameters have been provided and we're not running in safe mode. - */ - if (empty($this->_params) || ini_get('safe_mode')) { - $result = mail($recipients, $subject, $body, $text_headers); - } else { - $result = mail($recipients, $subject, $body, $text_headers, - $this->_params); - } - - /* - * If the mail() function returned failure, we need to create a - * PEAR_Error object and return it instead of the boolean result. - */ - if ($result === false) { - $result = PEAR::raiseError('mail() returned failure'); - } - - return $result; - } - -} diff --git a/htdocs/includes/nusoap/lib/Mail/mime.php b/htdocs/includes/nusoap/lib/Mail/mime.php index 3d44f050062..50297dd3e2f 100644 --- a/htdocs/includes/nusoap/lib/Mail/mime.php +++ b/htdocs/includes/nusoap/lib/Mail/mime.php @@ -1,135 +1,221 @@ | -// | Tomas V.V.Cox (port to PEAR) | -// +-----------------------------------------------------------------------+ -// +/** + * The Mail_Mime class is used to create MIME E-mail messages + * + * The Mail_Mime class provides an OO interface to create MIME + * enabled email messages. This way you can create emails that + * contain plain-text bodies, HTML bodies, attachments, inline + * images and specific headers. + * + * Compatible with PHP versions 4 and 5 + * + * LICENSE: This LICENSE is in the BSD license style. + * Copyright (c) 2002-2003, Richard Heyes + * Copyright (c) 2003-2006, PEAR + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * - Neither the name of the authors, nor the names of its contributors + * may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + * + * @category Mail + * @package Mail_Mime + * @author Richard Heyes + * @author Tomas V.V. Cox + * @author Cipriano Groenendal + * @author Sean Coates + * @author Aleksander Machniak + * @copyright 2003-2006 PEAR + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version CVS: $Id$ + * @link http://pear.php.net/package/Mail_mime + * + * This class is based on HTML Mime Mail class from + * Richard Heyes which was based also + * in the mime_mail.class by Tobias Ratschiller + * and Sascha Schumann + */ -require_once('PEAR.php'); -require_once('Mail/mimePart.php'); /** - * Mime mail composer class. Can handle: text and html bodies, embedded html - * images and attachments. - * Documentation and examples of this class are avaible here: - * http://pear.php.net/manual/ + * require PEAR * - * @notes This class is based on HTML Mime Mail class from - * Richard Heyes which was based also - * in the mime_mail.class by Tobias Ratschiller and - * Sascha Schumann + * This package depends on PEAR to raise errors. + */ +require_once 'PEAR.php'; + +/** + * require Mail_mimePart * - * @author Richard Heyes - * @author Tomas V.V.Cox - * @package Mail - * @access public + * Mail_mimePart contains the code required to + * create all the different parts a mail can + * consist of. + */ +require_once 'Mail/mimePart.php'; + + +/** + * The Mail_Mime class provides an OO interface to create MIME + * enabled email messages. This way you can create emails that + * contain plain-text bodies, HTML bodies, attachments, inline + * images and specific headers. + * + * @category Mail + * @package Mail_Mime + * @author Richard Heyes + * @author Tomas V.V. Cox + * @author Cipriano Groenendal + * @author Sean Coates + * @copyright 2003-2006 PEAR + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: @package_version@ + * @link http://pear.php.net/package/Mail_mime */ class Mail_mime { /** * Contains the plain text part of the email + * * @var string + * @access private */ var $_txtbody; + /** * Contains the html part of the email + * * @var string + * @access private */ var $_htmlbody; - /** - * contains the mime encoded text - * @var string - */ - var $_mime; - /** - * contains the multipart content - * @var string - */ - var $_multipart; + /** * list of the attached images + * * @var array + * @access private */ var $_html_images = array(); + /** * list of the attachements + * * @var array + * @access private */ var $_parts = array(); - /** - * Build parameters - * @var array - */ - var $_build_params = array(); + /** * Headers for the mail + * * @var array + * @access private */ var $_headers = array(); - /** - * End Of Line sequence (for serialize) - * @var string - */ - var $_eol; + /** + * Build parameters + * + * @var array + * @access private + */ + var $_build_params = array( + // What encoding to use for the headers + // Options: quoted-printable or base64 + 'head_encoding' => 'quoted-printable', + // What encoding to use for plain text + // Options: 7bit, 8bit, base64, or quoted-printable + 'text_encoding' => 'quoted-printable', + // What encoding to use for html + // Options: 7bit, 8bit, base64, or quoted-printable + 'html_encoding' => 'quoted-printable', + // The character set to use for html + 'html_charset' => 'ISO-8859-1', + // The character set to use for text + 'text_charset' => 'ISO-8859-1', + // The character set to use for headers + 'head_charset' => 'ISO-8859-1', + // End-of-line sequence + 'eol' => "\r\n", + // Delay attachment files IO until building the message + 'delay_file_io' => false + ); /** * Constructor function * + * @param mixed $params Build parameters that change the way the email + * is built. Should be an associative array. + * See $_build_params. + * + * @return void * @access public */ - function Mail_mime($crlf = "\r\n") + function Mail_mime($params = array()) { - $this->_setEOL($crlf); - $this->_build_params = array( - 'text_encoding' => '7bit', - 'html_encoding' => 'quoted-printable', - '7bit_wrap' => 998, - 'html_charset' => 'ISO-8859-1', - 'text_charset' => 'ISO-8859-1', - 'head_charset' => 'ISO-8859-1' - ); + // Backward-compatible EOL setting + if (is_string($params)) { + $this->_build_params['eol'] = $params; + } else if (defined('MAIL_MIME_CRLF') && !isset($params['eol'])) { + $this->_build_params['eol'] = MAIL_MIME_CRLF; + } + + // Update build parameters + if (!empty($params) && is_array($params)) { + while (list($key, $value) = each($params)) { + $this->_build_params[$key] = $value; + } + } } /** - * Wakeup (unserialize) - re-sets EOL constant + * Set build parameter value * - * @access private + * @param string $name Parameter name + * @param string $value Parameter value + * + * @return void + * @access public + * @since 1.6.0 */ - function __wakeup() + function setParam($name, $value) { - $this->_setEOL($this->_eol); + $this->_build_params[$name] = $value; + } + + /** + * Get build parameter value + * + * @param string $name Parameter name + * + * @return mixed Parameter value + * @access public + * @since 1.6.0 + */ + function getParam($name) + { + return isset($this->_build_params[$name]) ? $this->_build_params[$name] : null; } /** @@ -138,14 +224,15 @@ class Mail_mime * text/plain part that emails clients who don't support * html should show. * - * @param string $data Either a string or - * the file name with the contents - * @param bool $isfile If true the first param should be treated - * as a file name, else as a string (default) - * @param bool $append If true the text or file is appended to - * the existing body, else the old body is - * overwritten - * @return mixed true on success or PEAR_Error object + * @param string $data Either a string or + * the file name with the contents + * @param bool $isfile If true the first param should be treated + * as a file name, else as a string (default) + * @param bool $append If true the text or file is appended to + * the existing body, else the old body is + * overwritten + * + * @return mixed True on success or PEAR_Error object * @access public */ function setTXTBody($data, $isfile = false, $append = false) @@ -158,7 +245,7 @@ class Mail_mime } } else { $cont = $this->_file2str($data); - if (PEAR::isError($cont)) { + if ($this->_isError($cont)) { return $cont; } if (!$append) { @@ -167,17 +254,31 @@ class Mail_mime $this->_txtbody .= $cont; } } + return true; } /** - * Adds a html part to the mail + * Get message text body * - * @param string $data Either a string or the file name with the - * contents - * @param bool $isfile If true the first param should be treated - * as a file name, else as a string (default) - * @return mixed true on success or PEAR_Error object + * @return string Text body + * @access public + * @since 1.6.0 + */ + function getTXTBody() + { + return $this->_txtbody; + } + + /** + * Adds a html part to the mail. + * + * @param string $data Either a string or the file name with the + * contents + * @param bool $isfile A flag that determines whether $data is a + * filename, or a string(false, default) + * + * @return bool True on success * @access public */ function setHTMLBody($data, $isfile = false) @@ -186,7 +287,7 @@ class Mail_mime $this->_htmlbody = $data; } else { $cont = $this->_file2str($data); - if (PEAR::isError($cont)) { + if ($this->_isError($cont)) { return $cont; } $this->_htmlbody = $cont; @@ -195,106 +296,193 @@ class Mail_mime return true; } + /** + * Get message HTML body + * + * @return string HTML body + * @access public + * @since 1.6.0 + */ + function getHTMLBody() + { + return $this->_htmlbody; + } + /** * Adds an image to the list of embedded images. * - * @param string $file The image file name OR image data itself - * @param string $c_type The content type - * @param string $name The filename of the image. - * Only use if $file is the image data - * @param bool $isfilename Whether $file is a filename or not - * Defaults to true - * @return mixed true on success or PEAR_Error object + * @param string $file The image file name OR image data itself + * @param string $c_type The content type + * @param string $name The filename of the image. + * Only used if $file is the image data. + * @param bool $isfile Whether $file is a filename or not. + * Defaults to true + * @param string $content_id Desired Content-ID of MIME part + * Defaults to generated unique ID + * + * @return bool True on success * @access public */ - function addHTMLImage($file, $c_type='application/octet-stream', - $name = '', $isfilename = true) - { - $filedata = ($isfilename === true) ? $this->_file2str($file) - : $file; - if ($isfilename === true) { - $filename = ($name == '' ? basename($file) : basename($name)); + function addHTMLImage($file, + $c_type='application/octet-stream', + $name = '', + $isfile = true, + $content_id = null + ) { + $bodyfile = null; + + if ($isfile) { + // Don't load file into memory + if ($this->_build_params['delay_file_io']) { + $filedata = null; + $bodyfile = $file; + } else { + if ($this->_isError($filedata = $this->_file2str($file))) { + return $filedata; + } + } + $filename = ($name ? $name : $file); } else { - $filename = basename($name); + $filedata = $file; + $filename = $name; } - if (PEAR::isError($filedata)) { - return $filedata; + + if (!$content_id) { + $content_id = preg_replace('/[^0-9a-zA-Z]/', '', uniqid(time(), true)); } + $this->_html_images[] = array( - 'body' => $filedata, - 'name' => $filename, - 'c_type' => $c_type, - 'cid' => md5(uniqid(time())) - ); + 'body' => $filedata, + 'body_file' => $bodyfile, + 'name' => $filename, + 'c_type' => $c_type, + 'cid' => $content_id + ); + return true; } /** * Adds a file to the list of attachments. * - * @param string $file The file name of the file to attach - * OR the file data itself - * @param string $c_type The content type - * @param string $name The filename of the attachment - * Only use if $file is the file data - * @param bool $isFilename Whether $file is a filename or not - * Defaults to true - * @return mixed true on success or PEAR_Error object + * @param string $file The file name of the file to attach + * or the file contents itself + * @param string $c_type The content type + * @param string $name The filename of the attachment + * Only use if $file is the contents + * @param bool $isfile Whether $file is a filename or not. Defaults to true + * @param string $encoding The type of encoding to use. Defaults to base64. + * Possible values: 7bit, 8bit, base64 or quoted-printable. + * @param string $disposition The content-disposition of this file + * Defaults to attachment. + * Possible values: attachment, inline. + * @param string $charset The character set of attachment's content. + * @param string $language The language of the attachment + * @param string $location The RFC 2557.4 location of the attachment + * @param string $n_encoding Encoding of the attachment's name in Content-Type + * By default filenames are encoded using RFC2231 method + * Here you can set RFC2047 encoding (quoted-printable + * or base64) instead + * @param string $f_encoding Encoding of the attachment's filename + * in Content-Disposition header. + * @param string $description Content-Description header + * @param string $h_charset The character set of the headers e.g. filename + * If not specified, $charset will be used + * @param array $add_headers Additional part headers. Array keys can be in form + * of : + * + * @return mixed True on success or PEAR_Error object * @access public */ - function addAttachment($file, $c_type = 'application/octet-stream', - $name = '', $isfilename = true, - $encoding = 'base64') - { - $filedata = ($isfilename === true) ? $this->_file2str($file) - : $file; - if ($isfilename === true) { + function addAttachment($file, + $c_type = 'application/octet-stream', + $name = '', + $isfile = true, + $encoding = 'base64', + $disposition = 'attachment', + $charset = '', + $language = '', + $location = '', + $n_encoding = null, + $f_encoding = null, + $description = '', + $h_charset = null, + $add_headers = array() + ) { + $bodyfile = null; + + if ($isfile) { + // Don't load file into memory + if ($this->_build_params['delay_file_io']) { + $filedata = null; + $bodyfile = $file; + } else { + if ($this->_isError($filedata = $this->_file2str($file))) { + return $filedata; + } + } // Force the name the user supplied, otherwise use $file - $filename = (!empty($name)) ? $name : $file; + $filename = ($name ? $name : $this->_basename($file)); } else { + $filedata = $file; $filename = $name; } - if (empty($filename)) { - return PEAR::raiseError( - 'The supplied filename for the attachment can\'t be empty' - ); - } - $filename = basename($filename); - if (PEAR::isError($filedata)) { - return $filedata; + + if (!strlen($filename)) { + $msg = "The supplied filename for the attachment can't be empty"; + return $this->_raiseError($msg); } $this->_parts[] = array( - 'body' => $filedata, - 'name' => $filename, - 'c_type' => $c_type, - 'encoding' => $encoding - ); + 'body' => $filedata, + 'body_file' => $bodyfile, + 'name' => $filename, + 'c_type' => $c_type, + 'charset' => $charset, + 'encoding' => $encoding, + 'language' => $language, + 'location' => $location, + 'disposition' => $disposition, + 'description' => $description, + 'add_headers' => $add_headers, + 'name_encoding' => $n_encoding, + 'filename_encoding' => $f_encoding, + 'headers_charset' => $h_charset, + ); + return true; } /** * Get the contents of the given file name as string * - * @param string $file_name path of file to process - * @return string contents of $file_name + * @param string $file_name Path of file to process + * + * @return string Contents of $file_name * @access private */ - function &_file2str($file_name) + function _file2str($file_name) { + // Check state of file and raise an error properly + if (!file_exists($file_name)) { + return $this->_raiseError('File not found: ' . $file_name); + } + if (!is_file($file_name)) { + return $this->_raiseError('Not a regular file: ' . $file_name); + } if (!is_readable($file_name)) { - return PEAR::raiseError('File is not readable ' . $file_name); + return $this->_raiseError('File is not readable: ' . $file_name); } - if (!$fd = fopen($file_name, 'rb')) { - return PEAR::raiseError('Could not open ' . $file_name); + + // Temporarily reset magic_quotes_runtime and read file contents + if ($magic_quote_setting = get_magic_quotes_runtime()) { + @ini_set('magic_quotes_runtime', 0); } - $filesize = filesize($file_name); - if ($filesize == 0){ - $cont = ""; - }else{ - $cont = fread($fd, $filesize); + $cont = file_get_contents($file_name); + if ($magic_quote_setting) { + @ini_set('magic_quotes_runtime', $magic_quote_setting); } - fclose($fd); + return $cont; } @@ -302,31 +490,37 @@ class Mail_mime * Adds a text subpart to the mimePart object and * returns it during the build process. * - * @param mixed The object to add the part to, or - * null if a new object is to be created. - * @param string The text to add. - * @return object The text mimePart object + * @param mixed &$obj The object to add the part to, or + * anything else if a new object is to be created. + * @param string $text The text to add. + * + * @return object The text mimePart object * @access private */ - function &_addTextPart(&$obj, $text) + function &_addTextPart(&$obj, $text = '') { $params['content_type'] = 'text/plain'; $params['encoding'] = $this->_build_params['text_encoding']; $params['charset'] = $this->_build_params['text_charset']; + $params['eol'] = $this->_build_params['eol']; + if (is_object($obj)) { - return $obj->addSubpart($text, $params); + $ret = $obj->addSubpart($text, $params); } else { - return new Mail_mimePart($text, $params); + $ret = new Mail_mimePart($text, $params); } + + return $ret; } /** * Adds a html subpart to the mimePart object and * returns it during the build process. * - * @param mixed The object to add the part to, or - * null if a new object is to be created. - * @return object The html mimePart object + * @param mixed &$obj The object to add the part to, or + * anything else if a new object is to be created. + * + * @return object The html mimePart object * @access private */ function &_addHtmlPart(&$obj) @@ -334,11 +528,15 @@ class Mail_mime $params['content_type'] = 'text/html'; $params['encoding'] = $this->_build_params['html_encoding']; $params['charset'] = $this->_build_params['html_charset']; + $params['eol'] = $this->_build_params['eol']; + if (is_object($obj)) { - return $obj->addSubpart($this->_htmlbody, $params); + $ret = $obj->addSubpart($this->_htmlbody, $params); } else { - return new Mail_mimePart($this->_htmlbody, $params); + $ret = new Mail_mimePart($this->_htmlbody, $params); } + + return $ret; } /** @@ -346,13 +544,17 @@ class Mail_mime * the initial content-type and returns it during the * build process. * - * @return object The multipart/mixed mimePart object + * @return object The multipart/mixed mimePart object * @access private */ function &_addMixedPart() { $params['content_type'] = 'multipart/mixed'; - return new Mail_mimePart('', $params); + $params['eol'] = $this->_build_params['eol']; + + // Create empty multipart/mixed Mail_mimePart object to return + $ret = new Mail_mimePart('', $params); + return $ret; } /** @@ -360,19 +562,24 @@ class Mail_mime * object (or creates one), and returns it during * the build process. * - * @param mixed The object to add the part to, or - * null if a new object is to be created. - * @return object The multipart/mixed mimePart object + * @param mixed &$obj The object to add the part to, or + * anything else if a new object is to be created. + * + * @return object The multipart/mixed mimePart object * @access private */ function &_addAlternativePart(&$obj) { $params['content_type'] = 'multipart/alternative'; + $params['eol'] = $this->_build_params['eol']; + if (is_object($obj)) { - return $obj->addSubpart('', $params); + $ret = $obj->addSubpart('', $params); } else { - return new Mail_mimePart('', $params); + $ret = new Mail_mimePart('', $params); } + + return $ret; } /** @@ -380,28 +587,34 @@ class Mail_mime * object (or creates one), and returns it during * the build process. * - * @param mixed The object to add the part to, or - * null if a new object is to be created - * @return object The multipart/mixed mimePart object + * @param mixed &$obj The object to add the part to, or + * anything else if a new object is to be created + * + * @return object The multipart/mixed mimePart object * @access private */ function &_addRelatedPart(&$obj) { $params['content_type'] = 'multipart/related'; + $params['eol'] = $this->_build_params['eol']; + if (is_object($obj)) { - return $obj->addSubpart('', $params); + $ret = $obj->addSubpart('', $params); } else { - return new Mail_mimePart('', $params); + $ret = new Mail_mimePart('', $params); } + + return $ret; } /** * Adds an html image subpart to a mimePart object * and returns it during the build process. * - * @param object The mimePart to add the image to - * @param array The image information - * @return object The image mimePart object + * @param object &$obj The mimePart to add the image to + * @param array $value The image information + * + * @return object The image mimePart object * @access private */ function &_addHtmlImagePart(&$obj, $value) @@ -409,89 +622,281 @@ class Mail_mime $params['content_type'] = $value['c_type']; $params['encoding'] = 'base64'; $params['disposition'] = 'inline'; - $params['dfilename'] = $value['name']; + $params['filename'] = $value['name']; $params['cid'] = $value['cid']; - $obj->addSubpart($value['body'], $params); + $params['body_file'] = $value['body_file']; + $params['eol'] = $this->_build_params['eol']; + + if (!empty($value['name_encoding'])) { + $params['name_encoding'] = $value['name_encoding']; + } + if (!empty($value['filename_encoding'])) { + $params['filename_encoding'] = $value['filename_encoding']; + } + + $ret = $obj->addSubpart($value['body'], $params); + return $ret; } /** * Adds an attachment subpart to a mimePart object * and returns it during the build process. * - * @param object The mimePart to add the image to - * @param array The attachment information - * @return object The image mimePart object + * @param object &$obj The mimePart to add the image to + * @param array $value The attachment information + * + * @return object The image mimePart object * @access private */ function &_addAttachmentPart(&$obj, $value) { - $params['content_type'] = $value['c_type']; + $params['eol'] = $this->_build_params['eol']; + $params['filename'] = $value['name']; $params['encoding'] = $value['encoding']; - $params['disposition'] = 'attachment'; - $params['dfilename'] = $value['name']; - $obj->addSubpart($value['body'], $params); + $params['content_type'] = $value['c_type']; + $params['body_file'] = $value['body_file']; + $params['disposition'] = isset($value['disposition']) ? + $value['disposition'] : 'attachment'; + + // content charset + if (!empty($value['charset'])) { + $params['charset'] = $value['charset']; + } + // headers charset (filename, description) + if (!empty($value['headers_charset'])) { + $params['headers_charset'] = $value['headers_charset']; + } + if (!empty($value['language'])) { + $params['language'] = $value['language']; + } + if (!empty($value['location'])) { + $params['location'] = $value['location']; + } + if (!empty($value['name_encoding'])) { + $params['name_encoding'] = $value['name_encoding']; + } + if (!empty($value['filename_encoding'])) { + $params['filename_encoding'] = $value['filename_encoding']; + } + if (!empty($value['description'])) { + $params['description'] = $value['description']; + } + if (is_array($value['add_headers'])) { + $params['headers'] = $value['add_headers']; + } + + $ret = $obj->addSubpart($value['body'], $params); + return $ret; + } + + /** + * Returns the complete e-mail, ready to send using an alternative + * mail delivery method. Note that only the mailpart that is made + * with Mail_Mime is created. This means that, + * YOU WILL HAVE NO TO: HEADERS UNLESS YOU SET IT YOURSELF + * using the $headers parameter! + * + * @param string $separation The separation between these two parts. + * @param array $params The Build parameters passed to the + * get() function. See get() for more info. + * @param array $headers The extra headers that should be passed + * to the headers() method. + * See that function for more info. + * @param bool $overwrite Overwrite the existing headers with new. + * + * @return mixed The complete e-mail or PEAR error object + * @access public + */ + function getMessage($separation = null, $params = null, $headers = null, + $overwrite = false + ) { + if ($separation === null) { + $separation = $this->_build_params['eol']; + } + + $body = $this->get($params); + + if ($this->_isError($body)) { + return $body; + } + + return $this->txtHeaders($headers, $overwrite) . $separation . $body; + } + + /** + * Returns the complete e-mail body, ready to send using an alternative + * mail delivery method. + * + * @param array $params The Build parameters passed to the + * get() method. See get() for more info. + * + * @return mixed The e-mail body or PEAR error object + * @access public + * @since 1.6.0 + */ + function getMessageBody($params = null) + { + return $this->get($params, null, true); + } + + /** + * Writes (appends) the complete e-mail into file. + * + * @param string $filename Output file location + * @param array $params The Build parameters passed to the + * get() method. See get() for more info. + * @param array $headers The extra headers that should be passed + * to the headers() function. + * See that function for more info. + * @param bool $overwrite Overwrite the existing headers with new. + * + * @return mixed True or PEAR error object + * @access public + * @since 1.6.0 + */ + function saveMessage($filename, $params = null, $headers = null, $overwrite = false) + { + // Check state of file and raise an error properly + if (file_exists($filename) && !is_writable($filename)) { + return $this->_raiseError('File is not writable: ' . $filename); + } + + // Temporarily reset magic_quotes_runtime and read file contents + if ($magic_quote_setting = get_magic_quotes_runtime()) { + @ini_set('magic_quotes_runtime', 0); + } + + if (!($fh = fopen($filename, 'ab'))) { + return $this->_raiseError('Unable to open file: ' . $filename); + } + + // Write message headers into file (skipping Content-* headers) + $head = $this->txtHeaders($headers, $overwrite, true); + if (fwrite($fh, $head) === false) { + return $this->_raiseError('Error writing to file: ' . $filename); + } + + fclose($fh); + + if ($magic_quote_setting) { + @ini_set('magic_quotes_runtime', $magic_quote_setting); + } + + // Write the rest of the message into file + $res = $this->get($params, $filename); + + return $res ? $res : true; + } + + /** + * Writes (appends) the complete e-mail body into file. + * + * @param string $filename Output file location + * @param array $params The Build parameters passed to the + * get() method. See get() for more info. + * + * @return mixed True or PEAR error object + * @access public + * @since 1.6.0 + */ + function saveMessageBody($filename, $params = null) + { + // Check state of file and raise an error properly + if (file_exists($filename) && !is_writable($filename)) { + return $this->_raiseError('File is not writable: ' . $filename); + } + + // Temporarily reset magic_quotes_runtime and read file contents + if ($magic_quote_setting = get_magic_quotes_runtime()) { + @ini_set('magic_quotes_runtime', 0); + } + + if (!($fh = fopen($filename, 'ab'))) { + return $this->_raiseError('Unable to open file: ' . $filename); + } + + // Write the rest of the message into file + $res = $this->get($params, $filename, true); + + return $res ? $res : true; } /** * Builds the multipart message from the list ($this->_parts) and * returns the mime content. * - * @param array Build parameters that change the way the email - * is built. Should be associative. Can contain: - * text_encoding - What encoding to use for plain text - * Default is 7bit - * html_encoding - What encoding to use for html - * Default is quoted-printable - * 7bit_wrap - Number of characters before text is - * wrapped in 7bit encoding - * Default is 998 - * html_charset - The character set to use for html. - * Default is iso-8859-1 - * text_charset - The character set to use for text. - * Default is iso-8859-1 - * head_charset - The character set to use for headers. - * Default is iso-8859-1 - * @return string The mime content + * @param array $params Build parameters that change the way the email + * is built. Should be associative. See $_build_params. + * @param resource $filename Output file where to save the message instead of + * returning it + * @param boolean $skip_head True if you want to return/save only the message + * without headers + * + * @return mixed The MIME message content string, null or PEAR error object * @access public */ - function &get($build_params = null) + function get($params = null, $filename = null, $skip_head = false) { - if (isset($build_params)) { - while (list($key, $value) = each($build_params)) { + if (isset($params)) { + while (list($key, $value) = each($params)) { $this->_build_params[$key] = $value; } } - if (!empty($this->_html_images) AND isset($this->_htmlbody)) { - foreach ($this->_html_images as $value) { - $regex = '#(\s)((?i)src|background|href(?-i))\s*=\s*(["\']?)' . preg_quote($value['name'], '#') . - '\3#'; - $rep = '\1\2=\3cid:' . $value['cid'] .'\3'; - $this->_htmlbody = preg_replace($regex, $rep, - $this->_htmlbody - ); + if (isset($this->_headers['From'])) { + // Bug #11381: Illegal characters in domain ID + if (preg_match('#(@[0-9a-zA-Z\-\.]+)#', $this->_headers['From'], $matches)) { + $domainID = $matches[1]; + } else { + $domainID = '@localhost'; + } + foreach ($this->_html_images as $i => $img) { + $cid = $this->_html_images[$i]['cid']; + if (!preg_match('#'.preg_quote($domainID).'$#', $cid)) { + $this->_html_images[$i]['cid'] = $cid . $domainID; + } } } - $null = null; - $attachments = !empty($this->_parts) ? true : false; - $form_images = !empty($this->_html_images) ? true : false; - $form = !empty($this->_htmlbody) ? true : false; - $text = (!$form AND !empty($this->_txtbody)) ? true : false; + if (count($this->_html_images) && isset($this->_htmlbody)) { + foreach ($this->_html_images as $key => $value) { + $regex = array(); + $regex[] = '#(\s)((?i)src|background|href(?-i))\s*=\s*(["\']?)' . + preg_quote($value['name'], '#') . '\3#'; + $regex[] = '#(?i)url(?-i)\(\s*(["\']?)' . + preg_quote($value['name'], '#') . '\1\s*\)#'; + + $rep = array(); + $rep[] = '\1\2=\3cid:' . $value['cid'] .'\3'; + $rep[] = 'url(\1cid:' . $value['cid'] . '\1)'; + + $this->_htmlbody = preg_replace($regex, $rep, $this->_htmlbody); + $this->_html_images[$key]['name'] + = $this->_basename($this->_html_images[$key]['name']); + } + } + + $this->_checkParams(); + + $null = -1; + $attachments = count($this->_parts) > 0; + $html_images = count($this->_html_images) > 0; + $html = strlen($this->_htmlbody) > 0; + $text = !$html && strlen($this->_txtbody); switch (true) { - case $text AND !$attachments: + case $text && !$attachments: $message =& $this->_addTextPart($null, $this->_txtbody); break; - case !$text AND !$form AND $attachments: + case !$text && !$html && $attachments: $message =& $this->_addMixedPart(); for ($i = 0; $i < count($this->_parts); $i++) { $this->_addAttachmentPart($message, $this->_parts[$i]); } break; - case $text AND $attachments: + case $text && $attachments: $message =& $this->_addMixedPart(); $this->_addTextPart($message, $this->_txtbody); for ($i = 0; $i < count($this->_parts); $i++) { @@ -499,7 +904,7 @@ class Mail_mime } break; - case $form AND !$attachments AND !$form_images: + case $html && !$attachments && !$html_images: if (isset($this->_txtbody)) { $message =& $this->_addAlternativePart($null); $this->_addTextPart($message, $this->_txtbody); @@ -509,22 +914,53 @@ class Mail_mime } break; - case $form AND !$attachments AND $form_images: + case $html && !$attachments && $html_images: + // * Content-Type: multipart/alternative; + // * text + // * Content-Type: multipart/related; + // * html + // * image... if (isset($this->_txtbody)) { $message =& $this->_addAlternativePart($null); $this->_addTextPart($message, $this->_txtbody); - $related =& $this->_addRelatedPart($message); + + $ht =& $this->_addRelatedPart($message); + $this->_addHtmlPart($ht); + for ($i = 0; $i < count($this->_html_images); $i++) { + $this->_addHtmlImagePart($ht, $this->_html_images[$i]); + } } else { + // * Content-Type: multipart/related; + // * html + // * image... $message =& $this->_addRelatedPart($null); - $related =& $message; + $this->_addHtmlPart($message); + for ($i = 0; $i < count($this->_html_images); $i++) { + $this->_addHtmlImagePart($message, $this->_html_images[$i]); + } + } + /* + // #13444, #9725: the code below was a non-RFC compliant hack + // * Content-Type: multipart/related; + // * Content-Type: multipart/alternative; + // * text + // * html + // * image... + $message =& $this->_addRelatedPart($null); + if (isset($this->_txtbody)) { + $alt =& $this->_addAlternativePart($message); + $this->_addTextPart($alt, $this->_txtbody); + $this->_addHtmlPart($alt); + } else { + $this->_addHtmlPart($message); } - $this->_addHtmlPart($related); for ($i = 0; $i < count($this->_html_images); $i++) { - $this->_addHtmlImagePart($related, $this->_html_images[$i]); + $this->_addHtmlImagePart($message, $this->_html_images[$i]); } + */ break; - case $form AND $attachments AND !$form_images: + case $html && $attachments && !$html_images: $message =& $this->_addMixedPart(); if (isset($this->_txtbody)) { $alt =& $this->_addAlternativePart($message); @@ -538,7 +974,7 @@ class Mail_mime } break; - case $form AND $attachments AND $form_images: + case $html && $attachments && $html_images: $message =& $this->_addMixedPart(); if (isset($this->_txtbody)) { $alt =& $this->_addAlternativePart($message); @@ -555,17 +991,35 @@ class Mail_mime $this->_addAttachmentPart($message, $this->_parts[$i]); } break; - } - if (isset($message)) { - $output = $message->encode(); - $this->_headers = array_merge($this->_headers, - $output['headers']); - return $output['body']; + if (!isset($message)) { + return null; + } + // Use saved boundary + if (!empty($this->_build_params['boundary'])) { + $boundary = $this->_build_params['boundary']; } else { - return false; + $boundary = null; + } + + // Write output to file + if ($filename) { + // Append mimePart message headers and body into file + $headers = $message->encodeToFile($filename, $boundary, $skip_head); + if ($this->_isError($headers)) { + return $headers; + } + $this->_headers = array_merge($this->_headers, $headers); + return null; + } else { + $output = $message->encode($boundary, $skip_head); + if ($this->_isError($output)) { + return $output; + } + $this->_headers = array_merge($this->_headers, $output['headers']); + return $output['body']; } } @@ -574,48 +1028,148 @@ class Mail_mime * (MIME-Version and Content-Type). Format of argument is: * $array['header-name'] = 'header-value'; * - * @param array $xtra_headers Assoc array with any extra headers. - * Optional. - * @return array Assoc array with the mime headers + * @param array $xtra_headers Assoc array with any extra headers (optional) + * (Don't set Content-Type for multipart messages here!) + * @param bool $overwrite Overwrite already existing headers. + * @param bool $skip_content Don't return content headers: Content-Type, + * Content-Disposition and Content-Transfer-Encoding + * + * @return array Assoc array with the mime headers * @access public */ - function &headers($xtra_headers = null) + function headers($xtra_headers = null, $overwrite = false, $skip_content = false) { - // Content-Type header should already be present, - // So just add mime version header + // Add mime version header $headers['MIME-Version'] = '1.0'; - if (isset($xtra_headers)) { + + // Content-Type and Content-Transfer-Encoding headers should already + // be present if get() was called, but we'll re-set them to make sure + // we got them when called before get() or something in the message + // has been changed after get() [#14780] + if (!$skip_content) { + $headers += $this->_contentHeaders(); + } + + if (!empty($xtra_headers)) { $headers = array_merge($headers, $xtra_headers); } - $this->_headers = array_merge($headers, $this->_headers); - return $this->_encodeHeaders($this->_headers); + if ($overwrite) { + $this->_headers = array_merge($this->_headers, $headers); + } else { + $this->_headers = array_merge($headers, $this->_headers); + } + + $headers = $this->_headers; + + if ($skip_content) { + unset($headers['Content-Type']); + unset($headers['Content-Transfer-Encoding']); + unset($headers['Content-Disposition']); + } else if (!empty($this->_build_params['ctype'])) { + $headers['Content-Type'] = $this->_build_params['ctype']; + } + + $encodedHeaders = $this->_encodeHeaders($headers); + return $encodedHeaders; } /** * Get the text version of the headers * (usefull if you want to use the PHP mail() function) * - * @param array $xtra_headers Assoc array with any extra headers. - * Optional. - * @return string Plain text headers + * @param array $xtra_headers Assoc array with any extra headers (optional) + * (Don't set Content-Type for multipart messages here!) + * @param bool $overwrite Overwrite the existing headers with new. + * @param bool $skip_content Don't return content headers: Content-Type, + * Content-Disposition and Content-Transfer-Encoding + * + * @return string Plain text headers * @access public */ - function txtHeaders($xtra_headers = null) + function txtHeaders($xtra_headers = null, $overwrite = false, $skip_content = false) { - $headers = $this->headers($xtra_headers); - $ret = ''; - foreach ($headers as $key => $val) { - $ret .= "$key: $val" . MAIL_MIME_CRLF; + $headers = $this->headers($xtra_headers, $overwrite, $skip_content); + + // Place Received: headers at the beginning of the message + // Spam detectors often flag messages with it after the Subject: as spam + if (isset($headers['Received'])) { + $received = $headers['Received']; + unset($headers['Received']); + $headers = array('Received' => $received) + $headers; } + + $ret = ''; + $eol = $this->_build_params['eol']; + + foreach ($headers as $key => $val) { + if (is_array($val)) { + foreach ($val as $value) { + $ret .= "$key: $value" . $eol; + } + } else { + $ret .= "$key: $val" . $eol; + } + } + return $ret; } + /** + * Sets message Content-Type header. + * Use it to build messages with various content-types e.g. miltipart/raport + * not supported by _contentHeaders() function. + * + * @param string $type Type name + * @param array $params Hash array of header parameters + * + * @return void + * @access public + * @since 1.7.0 + */ + function setContentType($type, $params = array()) + { + $header = $type; + + $eol = !empty($this->_build_params['eol']) + ? $this->_build_params['eol'] : "\r\n"; + + // add parameters + $token_regexp = '#([^\x21\x23-\x27\x2A\x2B\x2D' + . '\x2E\x30-\x39\x41-\x5A\x5E-\x7E])#'; + if (is_array($params)) { + foreach ($params as $name => $value) { + if ($name == 'boundary') { + $this->_build_params['boundary'] = $value; + } + if (!preg_match($token_regexp, $value)) { + $header .= ";$eol $name=$value"; + } else { + $value = addcslashes($value, '\\"'); + $header .= ";$eol $name=\"$value\""; + } + } + } + + // add required boundary parameter if not defined + if (preg_match('/^multipart\//i', $type)) { + if (empty($this->_build_params['boundary'])) { + $this->_build_params['boundary'] = '=_' . md5(rand() . microtime()); + } + + $header .= ";$eol boundary=\"".$this->_build_params['boundary']."\""; + } + + $this->_build_params['ctype'] = $header; + } + /** * Sets the Subject header * - * @param string $subject String to set the subject to - * access public + * @param string $subject String to set the subject to. + * + * @return void + * @access public */ function setSubject($subject) { @@ -625,7 +1179,9 @@ class Mail_mime /** * Set an email to the From (the sender) header * - * @param string $email The email direction to add + * @param string $email The email address to use + * + * @return void * @access public */ function setFrom($email) @@ -633,11 +1189,31 @@ class Mail_mime $this->_headers['From'] = $email; } + /** + * Add an email to the To header + * (multiple calls to this method are allowed) + * + * @param string $email The email direction to add + * + * @return void + * @access public + */ + function addTo($email) + { + if (isset($this->_headers['To'])) { + $this->_headers['To'] .= ", $email"; + } else { + $this->_headers['To'] = $email; + } + } + /** * Add an email to the Cc (carbon copy) header * (multiple calls to this method are allowed) * - * @param string $email The email direction to add + * @param string $email The email direction to add + * + * @return void * @access public */ function addCc($email) @@ -653,7 +1229,9 @@ class Mail_mime * Add an email to the Bcc (blank carbon copy) header * (multiple calls to this method are allowed) * - * @param string $email The email direction to add + * @param string $email The email direction to add + * + * @return void * @access public */ function addBcc($email) @@ -666,61 +1244,251 @@ class Mail_mime } /** - * Encodes a header as per RFC2047 + * Since the PHP send function requires you to specify + * recipients (To: header) separately from the other + * headers, the To: header is not properly encoded. + * To fix this, you can use this public method to + * encode your recipients before sending to the send + * function * - * @param string $input The header data to encode - * @return string Encoded data + * @param string $recipients A comma-delimited list of recipients + * + * @return string Encoded data + * @access public + */ + function encodeRecipients($recipients) + { + $input = array("To" => $recipients); + $retval = $this->_encodeHeaders($input); + return $retval["To"] ; + } + + /** + * Encodes headers as per RFC2047 + * + * @param array $input The header data to encode + * @param array $params Extra build parameters + * + * @return array Encoded data * @access private */ - function _encodeHeaders($input) + function _encodeHeaders($input, $params = array()) { + $build_params = $this->_build_params; + while (list($key, $value) = each($params)) { + $build_params[$key] = $value; + } + foreach ($input as $hdr_name => $hdr_value) { - preg_match_all('/(\w*[\x80-\xFF]+\w*)/', $hdr_value, $matches); - foreach ($matches[1] as $value) { - /* - * preg_replace /e modifier is deprecated in PHP 5.5 - * but anonymous functions for use in preg_replace_callback are only available from 5.3.0 - */ - if (version_compare(PHP_VERSION, '5.3.0') >= 0) { - $replacement = preg_replace_callback( - '/([\x80-\xFF])/', - function ($m) { - return "=" . strtoupper(dechex(ord($m[1]))); - }, - $value + if (is_array($hdr_value)) { + foreach ($hdr_value as $idx => $value) { + $input[$hdr_name][$idx] = $this->encodeHeader( + $hdr_name, $value, + $build_params['head_charset'], $build_params['head_encoding'] ); - } else { - $replacement = preg_replace('/([\x80-\xFF])/e', - '"=" . - strtoupper(dechex(ord("\1")))', - $value); } - $hdr_value = str_replace($value, '=?' . - $this->_build_params['head_charset'] . - '?Q?' . $replacement . '?=', - $hdr_value); + } else { + $input[$hdr_name] = $this->encodeHeader( + $hdr_name, $hdr_value, + $build_params['head_charset'], $build_params['head_encoding'] + ); } - $input[$hdr_name] = $hdr_value; } return $input; } /** - * Set the object's end-of-line and define the constant if applicable + * Encodes a header as per RFC2047 * - * @param string $eol End Of Line sequence + * @param string $name The header name + * @param string $value The header data to encode + * @param string $charset Character set name + * @param string $encoding Encoding name (base64 or quoted-printable) + * + * @return string Encoded header data (without a name) + * @access public + * @since 1.5.3 + */ + function encodeHeader($name, $value, $charset, $encoding) + { + $mime_part = new Mail_mimePart; + return $mime_part->encodeHeader( + $name, $value, $charset, $encoding, $this->_build_params['eol'] + ); + } + + /** + * Get file's basename (locale independent) + * + * @param string $filename Filename + * + * @return string Basename * @access private */ - function _setEOL($eol) + function _basename($filename) { - $this->_eol = $eol; - if (!defined('MAIL_MIME_CRLF')) { - define('MAIL_MIME_CRLF', $this->_eol, true); + // basename() is not unicode safe and locale dependent + if (stristr(PHP_OS, 'win') || stristr(PHP_OS, 'netware')) { + return preg_replace('/^.*[\\\\\\/]/', '', $filename); + } else { + return preg_replace('/^.*[\/]/', '', $filename); } } - + /** + * Get Content-Type and Content-Transfer-Encoding headers of the message + * + * @return array Headers array + * @access private + */ + function _contentHeaders() + { + $attachments = count($this->_parts) ? true : false; + $html_images = count($this->_html_images) ? true : false; + $html = strlen($this->_htmlbody) ? true : false; + $text = (!$html && strlen($this->_txtbody)) ? true : false; + $headers = array(); + + // See get() + switch (true) { + case $text && !$attachments: + $headers['Content-Type'] = 'text/plain'; + break; + + case !$text && !$html && $attachments: + case $text && $attachments: + case $html && $attachments && !$html_images: + case $html && $attachments && $html_images: + $headers['Content-Type'] = 'multipart/mixed'; + break; + + case $html && !$attachments && !$html_images && isset($this->_txtbody): + case $html && !$attachments && $html_images && isset($this->_txtbody): + $headers['Content-Type'] = 'multipart/alternative'; + break; + + case $html && !$attachments && !$html_images && !isset($this->_txtbody): + $headers['Content-Type'] = 'text/html'; + break; + + case $html && !$attachments && $html_images && !isset($this->_txtbody): + $headers['Content-Type'] = 'multipart/related'; + break; + + default: + return $headers; + } + + $this->_checkParams(); + + $eol = !empty($this->_build_params['eol']) + ? $this->_build_params['eol'] : "\r\n"; + + if ($headers['Content-Type'] == 'text/plain') { + // single-part message: add charset and encoding + $charset = 'charset=' . $this->_build_params['text_charset']; + // place charset parameter in the same line, if possible + // 26 = strlen("Content-Type: text/plain; ") + $headers['Content-Type'] + .= (strlen($charset) + 26 <= 76) ? "; $charset" : ";$eol $charset"; + $headers['Content-Transfer-Encoding'] + = $this->_build_params['text_encoding']; + } else if ($headers['Content-Type'] == 'text/html') { + // single-part message: add charset and encoding + $charset = 'charset=' . $this->_build_params['html_charset']; + // place charset parameter in the same line, if possible + $headers['Content-Type'] + .= (strlen($charset) + 25 <= 76) ? "; $charset" : ";$eol $charset"; + $headers['Content-Transfer-Encoding'] + = $this->_build_params['html_encoding']; + } else { + // multipart message: and boundary + if (!empty($this->_build_params['boundary'])) { + $boundary = $this->_build_params['boundary']; + } else if (!empty($this->_headers['Content-Type']) + && preg_match('/boundary="([^"]+)"/', $this->_headers['Content-Type'], $m) + ) { + $boundary = $m[1]; + } else { + $boundary = '=_' . md5(rand() . microtime()); + } + + $this->_build_params['boundary'] = $boundary; + $headers['Content-Type'] .= ";$eol boundary=\"$boundary\""; + } + + return $headers; + } + + /** + * Validate and set build parameters + * + * @return void + * @access private + */ + function _checkParams() + { + $encodings = array('7bit', '8bit', 'base64', 'quoted-printable'); + + $this->_build_params['text_encoding'] + = strtolower($this->_build_params['text_encoding']); + $this->_build_params['html_encoding'] + = strtolower($this->_build_params['html_encoding']); + + if (!in_array($this->_build_params['text_encoding'], $encodings)) { + $this->_build_params['text_encoding'] = '7bit'; + } + if (!in_array($this->_build_params['html_encoding'], $encodings)) { + $this->_build_params['html_encoding'] = '7bit'; + } + + // text body + if ($this->_build_params['text_encoding'] == '7bit' + && !preg_match('/ascii/i', $this->_build_params['text_charset']) + && preg_match('/[^\x00-\x7F]/', $this->_txtbody) + ) { + $this->_build_params['text_encoding'] = 'quoted-printable'; + } + // html body + if ($this->_build_params['html_encoding'] == '7bit' + && !preg_match('/ascii/i', $this->_build_params['html_charset']) + && preg_match('/[^\x00-\x7F]/', $this->_htmlbody) + ) { + $this->_build_params['html_encoding'] = 'quoted-printable'; + } + } + + /** + * PEAR::isError implementation + * + * @param mixed $data Object + * + * @return bool True if object is an instance of PEAR_Error + * @access private + */ + function _isError($data) + { + // PEAR::isError() is not PHP 5.4 compatible (see Bug #19473) + if (is_object($data) && is_a($data, 'PEAR_Error')) { + return true; + } + + return false; + } + + /** + * PEAR::raiseError implementation + * + * @param $message A text error message + * + * @return PEAR_Error Instance of PEAR_Error + * @access private + */ + function _raiseError($message) + { + // PEAR::raiseError() is not PHP 5.4 compatible + return new PEAR_Error($message); + } } // End of class -?> diff --git a/htdocs/includes/nusoap/lib/Mail/mimeDecode.php b/htdocs/includes/nusoap/lib/Mail/mimeDecode.php deleted file mode 100644 index 7ac931c2fb4..00000000000 --- a/htdocs/includes/nusoap/lib/Mail/mimeDecode.php +++ /dev/null @@ -1,836 +0,0 @@ - | -// +-----------------------------------------------------------------------+ - -require_once 'PEAR.php'; - -/** -* +----------------------------- IMPORTANT ------------------------------+ -* | Usage of this class compared to native php extensions such as | -* | mailparse or imap, is slow and may be feature deficient. If available| -* | you are STRONGLY recommended to use the php extensions. | -* +----------------------------------------------------------------------+ -* -* Mime Decoding class -* -* This class will parse a raw mime email and return -* the structure. Returned structure is similar to -* that returned by imap_fetchstructure(). -* -* USAGE: (assume $input is your raw email) -* -* $decode = new Mail_mimeDecode($input, "\r\n"); -* $structure = $decode->decode(); -* print_r($structure); -* -* Or statically: -* -* $params['input'] = $input; -* $structure = Mail_mimeDecode::decode($params); -* print_r($structure); -* -* TODO: -* o Implement multipart/appledouble -* o UTF8: ??? - - > 4. We have also found a solution for decoding the UTF-8 - > headers. Therefore I made the following function: - > - > function decode_utf8($txt) { - > $trans=array("�‘"=>"õ","ű"=>"û","Ő"=>"�•","Ű" - =>"�›"); - > $txt=strtr($txt,$trans); - > return(utf8_decode($txt)); - > } - > - > And I have inserted the following line to the class: - > - > if (strtolower($charset)=="utf-8") $text=decode_utf8($text); - > - > ... before the following one in the "_decodeHeader" function: - > - > $input = str_replace($encoded, $text, $input); - > - > This way from now on it can easily decode the UTF-8 headers too. - -* -* @author Richard Heyes -* @package Mail -*/ -class Mail_mimeDecode extends PEAR -{ - /** - * The raw email to decode - * @var string - */ - var $_input; - - /** - * The header part of the input - * @var string - */ - var $_header; - - /** - * The body part of the input - * @var string - */ - var $_body; - - /** - * If an error occurs, this is used to store the message - * @var string - */ - var $_error; - - /** - * Flag to determine whether to include bodies in the - * returned object. - * @var boolean - */ - var $_include_bodies; - - /** - * Flag to determine whether to decode bodies - * @var boolean - */ - var $_decode_bodies; - - /** - * Flag to determine whether to decode headers - * @var boolean - */ - var $_decode_headers; - - /** - * Constructor. - * - * Sets up the object, initialise the variables, and splits and - * stores the header and body of the input. - * - * @param string The input to decode - * @access public - */ - function Mail_mimeDecode($input) - { - list($header, $body) = $this->_splitBodyHeader($input); - - $this->_input = $input; - $this->_header = $header; - $this->_body = $body; - $this->_decode_bodies = false; - $this->_include_bodies = true; - } - - /** - * Begins the decoding process. If called statically - * it will create an object and call the decode() method - * of it. - * - * @param array An array of various parameters that determine - * various things: - * include_bodies - Whether to include the body in the returned - * object. - * decode_bodies - Whether to decode the bodies - * of the parts. (Transfer encoding) - * decode_headers - Whether to decode headers - * input - If called statically, this will be treated - * as the input - * @return object Decoded results - * @access public - */ - function decode($params = null) - { - // determine if this method has been called statically - $isStatic = !(isset($this) && get_class($this) == __CLASS__); - - // Have we been called statically? - // If so, create an object and pass details to that. - if ($isStatic AND isset($params['input'])) { - - $obj = new Mail_mimeDecode($params['input']); - $structure = $obj->decode($params); - - // Called statically but no input - } elseif ($isStatic) { - return PEAR::raiseError('Called statically and no input given'); - - // Called via an object - } else { - $this->_include_bodies = isset($params['include_bodies']) ? - $params['include_bodies'] : false; - $this->_decode_bodies = isset($params['decode_bodies']) ? - $params['decode_bodies'] : false; - $this->_decode_headers = isset($params['decode_headers']) ? - $params['decode_headers'] : false; - - $structure = $this->_decode($this->_header, $this->_body); - if ($structure === false) { - $structure = $this->raiseError($this->_error); - } - } - - return $structure; - } - - /** - * Performs the decoding. Decodes the body string passed to it - * If it finds certain content-types it will call itself in a - * recursive fashion - * - * @param string Header section - * @param string Body section - * @return object Results of decoding process - * @access private - */ - function _decode($headers, $body, $default_ctype = 'text/plain') - { - $return = new stdClass; - $return->headers = array(); - $headers = $this->_parseHeaders($headers); - - foreach ($headers as $value) { - if (isset($return->headers[strtolower($value['name'])]) AND !is_array($return->headers[strtolower($value['name'])])) { - $return->headers[strtolower($value['name'])] = array($return->headers[strtolower($value['name'])]); - $return->headers[strtolower($value['name'])][] = $value['value']; - - } elseif (isset($return->headers[strtolower($value['name'])])) { - $return->headers[strtolower($value['name'])][] = $value['value']; - - } else { - $return->headers[strtolower($value['name'])] = $value['value']; - } - } - - reset($headers); - while (list($key, $value) = each($headers)) { - $headers[$key]['name'] = strtolower($headers[$key]['name']); - switch ($headers[$key]['name']) { - - case 'content-type': - $content_type = $this->_parseHeaderValue($headers[$key]['value']); - - if (preg_match('/([0-9a-z+.-]+)\/([0-9a-z+.-]+)/i', $content_type['value'], $regs)) { - $return->ctype_primary = $regs[1]; - $return->ctype_secondary = $regs[2]; - } - - if (isset($content_type['other'])) { - while (list($p_name, $p_value) = each($content_type['other'])) { - $return->ctype_parameters[$p_name] = $p_value; - } - } - break; - - case 'content-disposition': - $content_disposition = $this->_parseHeaderValue($headers[$key]['value']); - $return->disposition = $content_disposition['value']; - if (isset($content_disposition['other'])) { - while (list($p_name, $p_value) = each($content_disposition['other'])) { - $return->d_parameters[$p_name] = $p_value; - } - } - break; - - case 'content-transfer-encoding': - $content_transfer_encoding = $this->_parseHeaderValue($headers[$key]['value']); - break; - } - } - - if (isset($content_type)) { - switch (strtolower($content_type['value'])) { - case 'text/plain': - $encoding = isset($content_transfer_encoding) ? $content_transfer_encoding['value'] : '7bit'; - $this->_include_bodies ? $return->body = ($this->_decode_bodies ? $this->_decodeBody($body, $encoding) : $body) : null; - break; - - case 'text/html': - $encoding = isset($content_transfer_encoding) ? $content_transfer_encoding['value'] : '7bit'; - $this->_include_bodies ? $return->body = ($this->_decode_bodies ? $this->_decodeBody($body, $encoding) : $body) : null; - break; - - case 'multipart/parallel': - case 'multipart/report': // RFC1892 - case 'multipart/signed': // PGP - case 'multipart/digest': - case 'multipart/alternative': - case 'multipart/related': - case 'multipart/mixed': - if(!isset($content_type['other']['boundary'])){ - $this->_error = 'No boundary found for ' . $content_type['value'] . ' part'; - return false; - } - - $default_ctype = (strtolower($content_type['value']) === 'multipart/digest') ? 'message/rfc822' : 'text/plain'; - - $parts = $this->_boundarySplit($body, $content_type['other']['boundary']); - for ($i = 0; $i < count($parts); $i++) { - list($part_header, $part_body) = $this->_splitBodyHeader($parts[$i]); - $part = $this->_decode($part_header, $part_body, $default_ctype); - if($part === false) - $part = $this->raiseError($this->_error); - $return->parts[] = $part; - } - break; - - case 'message/rfc822': - $obj = new Mail_mimeDecode($body); - $return->parts[] = $obj->decode(array('include_bodies' => $this->_include_bodies, - 'decode_bodies' => $this->_decode_bodies, - 'decode_headers' => $this->_decode_headers)); - unset($obj); - break; - - default: - if(!isset($content_transfer_encoding['value'])) - $content_transfer_encoding['value'] = '7bit'; - $this->_include_bodies ? $return->body = ($this->_decode_bodies ? $this->_decodeBody($body, $content_transfer_encoding['value']) : $body) : null; - break; - } - - } else { - $ctype = explode('/', $default_ctype); - $return->ctype_primary = $ctype[0]; - $return->ctype_secondary = $ctype[1]; - $this->_include_bodies ? $return->body = ($this->_decode_bodies ? $this->_decodeBody($body) : $body) : null; - } - - return $return; - } - - /** - * Given the output of the above function, this will return an - * array of references to the parts, indexed by mime number. - * - * @param object $structure The structure to go through - * @param string $mime_number Internal use only. - * @return array Mime numbers - */ - function &getMimeNumbers(&$structure, $no_refs = false, $mime_number = '', $prepend = '') - { - $return = array(); - if (!empty($structure->parts)) { - if ($mime_number != '') { - $structure->mime_id = $prepend . $mime_number; - $return[$prepend . $mime_number] = &$structure; - } - for ($i = 0; $i < count($structure->parts); $i++) { - - - if (!empty($structure->headers['content-type']) AND substr(strtolower($structure->headers['content-type']), 0, 8) == 'message/') { - $prepend = $prepend . $mime_number . '.'; - $_mime_number = ''; - } else { - $_mime_number = ($mime_number == '' ? $i + 1 : sprintf('%s.%s', $mime_number, $i + 1)); - } - - $arr = &Mail_mimeDecode::getMimeNumbers($structure->parts[$i], $no_refs, $_mime_number, $prepend); - foreach ($arr as $key => $val) { - $no_refs ? $return[$key] = '' : $return[$key] = &$arr[$key]; - } - } - } else { - if ($mime_number == '') { - $mime_number = '1'; - } - $structure->mime_id = $prepend . $mime_number; - $no_refs ? $return[$prepend . $mime_number] = '' : $return[$prepend . $mime_number] = &$structure; - } - - return $return; - } - - /** - * Given a string containing a header and body - * section, this function will split them (at the first - * blank line) and return them. - * - * @param string Input to split apart - * @return array Contains header and body section - * @access private - */ - function _splitBodyHeader($input) - { - if (preg_match("/^(.*?)\r?\n\r?\n(.*)/s", $input, $match)) { - return array($match[1], $match[2]); - } - $this->_error = 'Could not split header and body'; - return false; - } - - /** - * Parse headers given in $input and return - * as assoc array. - * - * @param string Headers to parse - * @return array Contains parsed headers - * @access private - */ - function _parseHeaders($input) - { - - if ($input !== '') { - // Unfold the input - $input = preg_replace("/\r?\n/", "\r\n", $input); - $input = preg_replace("/\r\n(\t| )+/", ' ', $input); - $headers = explode("\r\n", trim($input)); - - foreach ($headers as $value) { - $hdr_name = substr($value, 0, $pos = strpos($value, ':')); - $hdr_value = substr($value, $pos+1); - if($hdr_value[0] == ' ') - $hdr_value = substr($hdr_value, 1); - - $return[] = array( - 'name' => $hdr_name, - 'value' => $this->_decode_headers ? $this->_decodeHeader($hdr_value) : $hdr_value - ); - } - } else { - $return = array(); - } - - return $return; - } - - /** - * Function to parse a header value, - * extract first part, and any secondary - * parts (after ;) This function is not as - * robust as it could be. Eg. header comments - * in the wrong place will probably break it. - * - * @param string Header value to parse - * @return array Contains parsed result - * @access private - */ - function _parseHeaderValue($input) - { - - if (($pos = strpos($input, ';')) !== false) { - - $return['value'] = trim(substr($input, 0, $pos)); - $input = trim(substr($input, $pos+1)); - - if (strlen($input) > 0) { - - // This splits on a semi-colon, if there's no preceeding backslash - // Now works with quoted values; had to glue the \; breaks in PHP - // the regex is already bordering on incomprehensible - $splitRegex = '/([^;\'"]*[\'"]([^\'"]*([^\'"]*)*)[\'"][^;\'"]*|([^;]+))(;|$)/'; - preg_match_all($splitRegex, $input, $matches); - $parameters = array(); - for ($i=0; $i_quotedPrintableDecode($input); - break; - - case 'base64': - return base64_decode($input); - break; - - default: - return $input; - } - } - - /** - * Given a quoted-printable string, this - * function will decode and return it. - * - * @param string Input body to decode - * @return string Decoded body - * @access private - */ - function _quotedPrintableDecode($input) - { - // Remove soft line breaks - $input = preg_replace("/=\r?\n/", '', $input); - - // Replace encoded characters - $input = preg_replace('/=([a-f0-9]{2})/ie', "chr(hexdec('\\1'))", $input); - - return $input; - } - - /** - * Checks the input for uuencoded files and returns - * an array of them. Can be called statically, eg: - * - * $files =& Mail_mimeDecode::uudecode($some_text); - * - * It will check for the begin 666 ... end syntax - * however and won't just blindly decode whatever you - * pass it. - * - * @param string Input body to look for attahcments in - * @return array Decoded bodies, filenames and permissions - * @access public - * @author Unknown - */ - function &uudecode($input) - { - // Find all uuencoded sections - preg_match_all("/begin ([0-7]{3}) (.+)\r?\n(.+)\r?\nend/Us", $input, $matches); - - for ($j = 0; $j < count($matches[3]); $j++) { - - $str = $matches[3][$j]; - $filename = $matches[2][$j]; - $fileperm = $matches[1][$j]; - - $file = ''; - $str = preg_split("/\r?\n/", trim($str)); - $strlen = count($str); - - for ($i = 0; $i < $strlen; $i++) { - $pos = 1; - $d = 0; - $len=(int)(((ord(substr($str[$i],0,1)) -32) - ' ') & 077); - - while (($d + 3 <= $len) AND ($pos + 4 <= strlen($str[$i]))) { - $c0 = (ord(substr($str[$i],$pos,1)) ^ 0x20); - $c1 = (ord(substr($str[$i],$pos+1,1)) ^ 0x20); - $c2 = (ord(substr($str[$i],$pos+2,1)) ^ 0x20); - $c3 = (ord(substr($str[$i],$pos+3,1)) ^ 0x20); - $file .= chr(((($c0 - ' ') & 077) << 2) | ((($c1 - ' ') & 077) >> 4)); - - $file .= chr(((($c1 - ' ') & 077) << 4) | ((($c2 - ' ') & 077) >> 2)); - - $file .= chr(((($c2 - ' ') & 077) << 6) | (($c3 - ' ') & 077)); - - $pos += 4; - $d += 3; - } - - if (($d + 2 <= $len) && ($pos + 3 <= strlen($str[$i]))) { - $c0 = (ord(substr($str[$i],$pos,1)) ^ 0x20); - $c1 = (ord(substr($str[$i],$pos+1,1)) ^ 0x20); - $c2 = (ord(substr($str[$i],$pos+2,1)) ^ 0x20); - $file .= chr(((($c0 - ' ') & 077) << 2) | ((($c1 - ' ') & 077) >> 4)); - - $file .= chr(((($c1 - ' ') & 077) << 4) | ((($c2 - ' ') & 077) >> 2)); - - $pos += 3; - $d += 2; - } - - if (($d + 1 <= $len) && ($pos + 2 <= strlen($str[$i]))) { - $c0 = (ord(substr($str[$i],$pos,1)) ^ 0x20); - $c1 = (ord(substr($str[$i],$pos+1,1)) ^ 0x20); - $file .= chr(((($c0 - ' ') & 077) << 2) | ((($c1 - ' ') & 077) >> 4)); - - } - } - $files[] = array('filename' => $filename, 'fileperm' => $fileperm, 'filedata' => $file); - } - - return $files; - } - - /** - * getSendArray() returns the arguments required for Mail::send() - * used to build the arguments for a mail::send() call - * - * Usage: - * $mailtext = Full email (for example generated by a template) - * $decoder = new Mail_mimeDecode($mailtext); - * $parts = $decoder->getSendArray(); - * if (!PEAR::isError($parts) { - * list($recipents,$headers,$body) = $parts; - * $mail = Mail::factory('smtp'); - * $mail->send($recipents,$headers,$body); - * } else { - * echo $parts->message; - * } - * @return mixed array of recipeint, headers,body or Pear_Error - * @access public - * @author Alan Knowles - */ - function getSendArray() - { - // prevent warning if this is not set - $this->_decode_headers = FALSE; - $headerlist =$this->_parseHeaders($this->_header); - $to = ""; - if (!$headerlist) { - return $this->raiseError("Message did not contain headers"); - } - foreach($headerlist as $item) { - $header[$item['name']] = $item['value']; - switch (strtolower($item['name'])) { - case "to": - case "cc": - case "bcc": - $to = ",".$item['value']; - default: - break; - } - } - if ($to == "") { - return $this->raiseError("Message did not contain any recipents"); - } - $to = substr($to,1); - return array($to,$header,$this->_body); - } - - /** - * Returns a xml copy of the output of - * Mail_mimeDecode::decode. Pass the output in as the - * argument. This function can be called statically. Eg: - * - * $output = $obj->decode(); - * $xml = Mail_mimeDecode::getXML($output); - * - * The DTD used for this should have been in the package. Or - * alternatively you can get it from cvs, or here: - * http://www.phpguru.org/xmail/xmail.dtd. - * - * @param object Input to convert to xml. This should be the - * output of the Mail_mimeDecode::decode function - * @return string XML version of input - * @access public - */ - function getXML($input) - { - $crlf = "\r\n"; - $output = '' . $crlf . - '' . $crlf . - '' . $crlf . - Mail_mimeDecode::_getXML($input) . - ''; - - return $output; - } - - /** - * Function that does the actual conversion to xml. Does a single - * mimepart at a time. - * - * @param object Input to convert to xml. This is a mimepart object. - * It may or may not contain subparts. - * @param integer Number of tabs to indent - * @return string XML version of input - * @access private - */ - function _getXML($input, $indent = 1) - { - $htab = "\t"; - $crlf = "\r\n"; - $output = ''; - $headers = @(array)$input->headers; - - foreach ($headers as $hdr_name => $hdr_value) { - - // Multiple headers with this name - if (is_array($headers[$hdr_name])) { - for ($i = 0; $i < count($hdr_value); $i++) { - $output .= Mail_mimeDecode::_getXML_helper($hdr_name, $hdr_value[$i], $indent); - } - - // Only one header of this sort - } else { - $output .= Mail_mimeDecode::_getXML_helper($hdr_name, $hdr_value, $indent); - } - } - - if (!empty($input->parts)) { - for ($i = 0; $i < count($input->parts); $i++) { - $output .= $crlf . str_repeat($htab, $indent) . '' . $crlf . - Mail_mimeDecode::_getXML($input->parts[$i], $indent+1) . - str_repeat($htab, $indent) . '' . $crlf; - } - } elseif (isset($input->body)) { - $output .= $crlf . str_repeat($htab, $indent) . 'body . ']]>' . $crlf; - } - - return $output; - } - - /** - * Helper function to _getXML(). Returns xml of a header. - * - * @param string Name of header - * @param string Value of header - * @param integer Number of tabs to indent - * @return string XML version of input - * @access private - */ - function _getXML_helper($hdr_name, $hdr_value, $indent) - { - $htab = "\t"; - $crlf = "\r\n"; - $return = ''; - - $new_hdr_value = ($hdr_name != 'received') ? Mail_mimeDecode::_parseHeaderValue($hdr_value) : array('value' => $hdr_value); - $new_hdr_name = str_replace(' ', '-', ucwords(str_replace('-', ' ', $hdr_name))); - - // Sort out any parameters - if (!empty($new_hdr_value['other'])) { - foreach ($new_hdr_value['other'] as $paramname => $paramvalue) { - $params[] = str_repeat($htab, $indent) . $htab . '' . $crlf . - str_repeat($htab, $indent) . $htab . $htab . '' . htmlspecialchars($paramname) . '' . $crlf . - str_repeat($htab, $indent) . $htab . $htab . '' . htmlspecialchars($paramvalue) . '' . $crlf . - str_repeat($htab, $indent) . $htab . '' . $crlf; - } - - $params = implode('', $params); - } else { - $params = ''; - } - - $return = str_repeat($htab, $indent) . '
' . $crlf . - str_repeat($htab, $indent) . $htab . '' . htmlspecialchars($new_hdr_name) . '' . $crlf . - str_repeat($htab, $indent) . $htab . '' . htmlspecialchars($new_hdr_value['value']) . '' . $crlf . - $params . - str_repeat($htab, $indent) . '
' . $crlf; - - return $return; - } - -} // End of class -?> diff --git a/htdocs/includes/nusoap/lib/Mail/mimePart.php b/htdocs/includes/nusoap/lib/Mail/mimePart.php index e44caa25570..93e891bc67c 100644 --- a/htdocs/includes/nusoap/lib/Mail/mimePart.php +++ b/htdocs/includes/nusoap/lib/Mail/mimePart.php @@ -1,196 +1,284 @@ | -// +-----------------------------------------------------------------------+ +/** + * The Mail_mimePart class is used to create MIME E-mail messages + * + * This class enables you to manipulate and build a mime email + * from the ground up. The Mail_Mime class is a userfriendly api + * to this class for people who aren't interested in the internals + * of mime mail. + * This class however allows full control over the email. + * + * Compatible with PHP versions 4 and 5 + * + * LICENSE: This LICENSE is in the BSD license style. + * Copyright (c) 2002-2003, Richard Heyes + * Copyright (c) 2003-2006, PEAR + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * - Neither the name of the authors, nor the names of its contributors + * may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + * + * @category Mail + * @package Mail_Mime + * @author Richard Heyes + * @author Cipriano Groenendal + * @author Sean Coates + * @author Aleksander Machniak + * @copyright 2003-2006 PEAR + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version CVS: $Id$ + * @link http://pear.php.net/package/Mail_mime + */ + /** -* -* Raw mime encoding class -* -* What is it? -* This class enables you to manipulate and build -* a mime email from the ground up. -* -* Why use this instead of mime.php? -* mime.php is a userfriendly api to this class for -* people who aren't interested in the internals of -* mime mail. This class however allows full control -* over the email. -* -* Eg. -* -* // Since multipart/mixed has no real body, (the body is -* // the subpart), we set the body argument to blank. -* -* $params['content_type'] = 'multipart/mixed'; -* $email = new Mail_mimePart('', $params); -* -* // Here we add a text part to the multipart we have -* // already. Assume $body contains plain text. -* -* $params['content_type'] = 'text/plain'; -* $params['encoding'] = '7bit'; -* $text = $email->addSubPart($body, $params); -* -* // Now add an attachment. Assume $attach is -* the contents of the attachment -* -* $params['content_type'] = 'application/zip'; -* $params['encoding'] = 'base64'; -* $params['disposition'] = 'attachment'; -* $params['dfilename'] = 'example.zip'; -* $attach =& $email->addSubPart($body, $params); -* -* // Now build the email. Note that the encode -* // function returns an associative array containing two -* // elements, body and headers. You will need to add extra -* // headers, (eg. Mime-Version) before sending. -* -* $email = $message->encode(); -* $email['headers'][] = 'Mime-Version: 1.0'; -* -* -* Further examples are available at http://www.phpguru.org -* -* TODO: -* - Set encode() to return the $obj->encoded if encode() -* has already been run. Unless a flag is passed to specifically -* re-build the message. -* -* @author Richard Heyes -* @package Mail -*/ - -class Mail_mimePart { - - /** + * The Mail_mimePart class is used to create MIME E-mail messages + * + * This class enables you to manipulate and build a mime email + * from the ground up. The Mail_Mime class is a userfriendly api + * to this class for people who aren't interested in the internals + * of mime mail. + * This class however allows full control over the email. + * + * @category Mail + * @package Mail_Mime + * @author Richard Heyes + * @author Cipriano Groenendal + * @author Sean Coates + * @author Aleksander Machniak + * @copyright 2003-2006 PEAR + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version Release: @package_version@ + * @link http://pear.php.net/package/Mail_mime + */ +class Mail_mimePart +{ + /** * The encoding type of this part + * * @var string + * @access private */ var $_encoding; - /** + /** * An array of subparts + * * @var array + * @access private */ var $_subparts; - /** + /** * The output of this part after being built + * * @var string + * @access private */ var $_encoded; - /** + /** * Headers for this part + * * @var array + * @access private */ var $_headers; - /** + /** * The body of this part (not encoded) + * * @var string + * @access private */ var $_body; /** - * Constructor. - * - * Sets up the object. - * - * @param $body - The body of the mime part if any. - * @param $params - An associative array of parameters: - * content_type - The content type for this part eg multipart/mixed - * encoding - The encoding to use, 7bit, 8bit, base64, or quoted-printable - * cid - Content ID to apply - * disposition - Content disposition, inline or attachment - * dfilename - Optional filename parameter for content disposition - * description - Content description - * charset - Character set to use - * @access public - */ + * The location of file with body of this part (not encoded) + * + * @var string + * @access private + */ + var $_body_file; + + /** + * The end-of-line sequence + * + * @var string + * @access private + */ + var $_eol = "\r\n"; + + + /** + * Constructor. + * + * Sets up the object. + * + * @param string $body The body of the mime part if any. + * @param array $params An associative array of optional parameters: + * content_type - The content type for this part eg multipart/mixed + * encoding - The encoding to use, 7bit, 8bit, + * base64, or quoted-printable + * charset - Content character set + * cid - Content ID to apply + * disposition - Content disposition, inline or attachment + * filename - Filename parameter for content disposition + * description - Content description + * name_encoding - Encoding of the attachment name (Content-Type) + * By default filenames are encoded using RFC2231 + * Here you can set RFC2047 encoding (quoted-printable + * or base64) instead + * filename_encoding - Encoding of the attachment filename (Content-Disposition) + * See 'name_encoding' + * headers_charset - Charset of the headers e.g. filename, description. + * If not set, 'charset' will be used + * eol - End of line sequence. Default: "\r\n" + * headers - Hash array with additional part headers. Array keys can be + * in form of : + * body_file - Location of file with part's body (instead of $body) + * + * @access public + */ function Mail_mimePart($body = '', $params = array()) { - if (!defined('MAIL_MIMEPART_CRLF')) { - define('MAIL_MIMEPART_CRLF', defined('MAIL_MIME_CRLF') ? MAIL_MIME_CRLF : "\r\n", TRUE); + if (!empty($params['eol'])) { + $this->_eol = $params['eol']; + } else if (defined('MAIL_MIMEPART_CRLF')) { // backward-copat. + $this->_eol = MAIL_MIMEPART_CRLF; + } + + // Additional part headers + if (!empty($params['headers']) && is_array($params['headers'])) { + $headers = $params['headers']; } foreach ($params as $key => $value) { switch ($key) { - case 'content_type': - $headers['Content-Type'] = $value . (isset($charset) ? '; charset="' . $charset . '"' : ''); - break; + case 'encoding': + $this->_encoding = $value; + $headers['Content-Transfer-Encoding'] = $value; + break; - case 'encoding': - $this->_encoding = $value; - $headers['Content-Transfer-Encoding'] = $value; - break; + case 'cid': + $headers['Content-ID'] = '<' . $value . '>'; + break; - case 'cid': - $headers['Content-ID'] = '<' . $value . '>'; - break; + case 'location': + $headers['Content-Location'] = $value; + break; - case 'disposition': - $headers['Content-Disposition'] = $value . (isset($dfilename) ? '; filename="' . $dfilename . '"' : ''); - break; + case 'body_file': + $this->_body_file = $value; + break; - case 'dfilename': - if (isset($headers['Content-Disposition'])) { - $headers['Content-Disposition'] .= '; filename="' . $value . '"'; - } else { - $dfilename = $value; - } - break; - - case 'description': - $headers['Content-Description'] = $value; - break; - - case 'charset': - if (isset($headers['Content-Type'])) { - $headers['Content-Type'] .= '; charset="' . $value . '"'; - } else { - $charset = $value; - } - break; + // for backward compatibility + case 'dfilename': + $params['filename'] = $value; + break; } } // Default content-type - if (!isset($headers['Content-Type'])) { - $headers['Content-Type'] = 'text/plain'; + if (empty($params['content_type'])) { + $params['content_type'] = 'text/plain'; } - //Default encoding + // Content-Type + $headers['Content-Type'] = $params['content_type']; + if (!empty($params['charset'])) { + $charset = "charset={$params['charset']}"; + // place charset parameter in the same line, if possible + if ((strlen($headers['Content-Type']) + strlen($charset) + 16) <= 76) { + $headers['Content-Type'] .= '; '; + } else { + $headers['Content-Type'] .= ';' . $this->_eol . ' '; + } + $headers['Content-Type'] .= $charset; + + // Default headers charset + if (!isset($params['headers_charset'])) { + $params['headers_charset'] = $params['charset']; + } + } + + // header values encoding parameters + $h_charset = !empty($params['headers_charset']) ? $params['headers_charset'] : 'US-ASCII'; + $h_language = !empty($params['language']) ? $params['language'] : null; + $h_encoding = !empty($params['name_encoding']) ? $params['name_encoding'] : null; + + + if (!empty($params['filename'])) { + $headers['Content-Type'] .= ';' . $this->_eol; + $headers['Content-Type'] .= $this->_buildHeaderParam( + 'name', $params['filename'], $h_charset, $h_language, $h_encoding + ); + } + + // Content-Disposition + if (!empty($params['disposition'])) { + $headers['Content-Disposition'] = $params['disposition']; + if (!empty($params['filename'])) { + $headers['Content-Disposition'] .= ';' . $this->_eol; + $headers['Content-Disposition'] .= $this->_buildHeaderParam( + 'filename', $params['filename'], $h_charset, $h_language, + !empty($params['filename_encoding']) ? $params['filename_encoding'] : null + ); + } + + // add attachment size + $size = $this->_body_file ? filesize($this->_body_file) : strlen($body); + if ($size) { + $headers['Content-Disposition'] .= ';' . $this->_eol . ' size=' . $size; + } + } + + if (!empty($params['description'])) { + $headers['Content-Description'] = $this->encodeHeader( + 'Content-Description', $params['description'], $h_charset, $h_encoding, + $this->_eol + ); + } + + // Search and add existing headers' parameters + foreach ($headers as $key => $value) { + $items = explode(':', $key); + if (count($items) == 2) { + $header = $items[0]; + $param = $items[1]; + if (isset($headers[$header])) { + $headers[$header] .= ';' . $this->_eol; + } + $headers[$header] .= $this->_buildHeaderParam( + $param, $value, $h_charset, $h_language, $h_encoding + ); + unset($headers[$key]); + } + } + + // Default encoding if (!isset($this->_encoding)) { $this->_encoding = '7bit'; } @@ -202,41 +290,60 @@ class Mail_mimePart { } /** - * encode() - * * Encodes and returns the email. Also stores * it in the encoded member variable * + * @param string $boundary Pre-defined boundary string + * * @return An associative array containing two elements, * body and headers. The headers element is itself - * an indexed array. + * an indexed array. On error returns PEAR error object. * @access public */ - function encode() + function encode($boundary=null) { $encoded =& $this->_encoded; - if (!empty($this->_subparts)) { - srand((double)microtime()*1000000); - $boundary = '=_' . md5(rand() . microtime()); - $this->_headers['Content-Type'] .= ';' . MAIL_MIMEPART_CRLF . "\t" . 'boundary="' . $boundary . '"'; + if (count($this->_subparts)) { + $boundary = $boundary ? $boundary : '=_' . md5(rand() . microtime()); + $eol = $this->_eol; + + $this->_headers['Content-Type'] .= ";$eol boundary=\"$boundary\""; + + $encoded['body'] = ''; - // Add body parts to $subparts for ($i = 0; $i < count($this->_subparts); $i++) { - $headers = array(); + $encoded['body'] .= '--' . $boundary . $eol; $tmp = $this->_subparts[$i]->encode(); - foreach ($tmp['headers'] as $key => $value) { - $headers[] = $key . ': ' . $value; + if ($this->_isError($tmp)) { + return $tmp; } - $subparts[] = implode(MAIL_MIMEPART_CRLF, $headers) . MAIL_MIMEPART_CRLF . MAIL_MIMEPART_CRLF . $tmp['body']; + foreach ($tmp['headers'] as $key => $value) { + $encoded['body'] .= $key . ': ' . $value . $eol; + } + $encoded['body'] .= $eol . $tmp['body'] . $eol; } - $encoded['body'] = '--' . $boundary . MAIL_MIMEPART_CRLF . - implode('--' . $boundary . MAIL_MIMEPART_CRLF, $subparts) . - '--' . $boundary.'--' . MAIL_MIMEPART_CRLF; + $encoded['body'] .= '--' . $boundary . '--' . $eol; + } else if ($this->_body) { + $encoded['body'] = $this->_getEncodedData($this->_body, $this->_encoding); + } else if ($this->_body_file) { + // Temporarily reset magic_quotes_runtime for file reads and writes + if ($magic_quote_setting = get_magic_quotes_runtime()) { + @ini_set('magic_quotes_runtime', 0); + } + $body = $this->_getEncodedDataFromFile($this->_body_file, $this->_encoding); + if ($magic_quote_setting) { + @ini_set('magic_quotes_runtime', $magic_quote_setting); + } + + if ($this->_isError($body)) { + return $body; + } + $encoded['body'] = $body; } else { - $encoded['body'] = $this->_getEncodedData($this->_body, $this->_encoding) . MAIL_MIMEPART_CRLF; + $encoded['body'] = ''; } // Add headers to $encoded @@ -246,105 +353,908 @@ class Mail_mimePart { } /** - * &addSubPart() + * Encodes and saves the email into file. File must exist. + * Data will be appended to the file. * - * Adds a subpart to current mime part and returns - * a reference to it + * @param string $filename Output file location + * @param string $boundary Pre-defined boundary string + * @param boolean $skip_head True if you don't want to save headers * - * @param $body The body of the subpart, if any. - * @param $params The parameters for the subpart, same - * as the $params argument for constructor. - * @return A reference to the part you just added. It is - * crucial if using multipart/* in your subparts that - * you use =& in your script when calling this function, - * otherwise you will not be able to add further subparts. + * @return array An associative array containing message headers + * or PEAR error object * @access public + * @since 1.6.0 */ - function &addSubPart($body, $params) + function encodeToFile($filename, $boundary=null, $skip_head=false) { - $this->_subparts[] = new Mail_mimePart($body, $params); - return $this->_subparts[count($this->_subparts) - 1]; + if (file_exists($filename) && !is_writable($filename)) { + $err = $this->_raiseError('File is not writeable: ' . $filename); + return $err; + } + + if (!($fh = fopen($filename, 'ab'))) { + $err = $this->_raiseError('Unable to open file: ' . $filename); + return $err; + } + + // Temporarily reset magic_quotes_runtime for file reads and writes + if ($magic_quote_setting = get_magic_quotes_runtime()) { + @ini_set('magic_quotes_runtime', 0); + } + + $res = $this->_encodePartToFile($fh, $boundary, $skip_head); + + fclose($fh); + + if ($magic_quote_setting) { + @ini_set('magic_quotes_runtime', $magic_quote_setting); + } + + return $this->_isError($res) ? $res : $this->_headers; } /** - * _getEncodedData() + * Encodes given email part into file * + * @param string $fh Output file handle + * @param string $boundary Pre-defined boundary string + * @param boolean $skip_head True if you don't want to save headers + * + * @return array True on sucess or PEAR error object + * @access private + */ + function _encodePartToFile($fh, $boundary=null, $skip_head=false) + { + $eol = $this->_eol; + + if (count($this->_subparts)) { + $boundary = $boundary ? $boundary : '=_' . md5(rand() . microtime()); + $this->_headers['Content-Type'] .= ";$eol boundary=\"$boundary\""; + } + + if (!$skip_head) { + foreach ($this->_headers as $key => $value) { + fwrite($fh, $key . ': ' . $value . $eol); + } + $f_eol = $eol; + } else { + $f_eol = ''; + } + + if (count($this->_subparts)) { + for ($i = 0; $i < count($this->_subparts); $i++) { + fwrite($fh, $f_eol . '--' . $boundary . $eol); + $res = $this->_subparts[$i]->_encodePartToFile($fh); + if ($this->_isError($res)) { + return $res; + } + $f_eol = $eol; + } + + fwrite($fh, $eol . '--' . $boundary . '--' . $eol); + + } else if ($this->_body) { + fwrite($fh, $f_eol . $this->_getEncodedData($this->_body, $this->_encoding)); + } else if ($this->_body_file) { + fwrite($fh, $f_eol); + $res = $this->_getEncodedDataFromFile( + $this->_body_file, $this->_encoding, $fh + ); + if ($this->_isError($res)) { + return $res; + } + } + + return true; + } + + /** + * Adds a subpart to current mime part and returns + * a reference to it + * + * @param string $body The body of the subpart, if any. + * @param array $params The parameters for the subpart, same + * as the $params argument for constructor. + * + * @return Mail_mimePart A reference to the part you just added. In PHP4, it is + * crucial if using multipart/* in your subparts that + * you use =& in your script when calling this function, + * otherwise you will not be able to add further subparts. + * @access public + */ + function &addSubpart($body, $params) + { + $this->_subparts[] = $part = new Mail_mimePart($body, $params); + return $part; + } + + /** * Returns encoded data based upon encoding passed to it * - * @param $data The data to encode. - * @param $encoding The encoding type to use, 7bit, base64, - * or quoted-printable. + * @param string $data The data to encode. + * @param string $encoding The encoding type to use, 7bit, base64, + * or quoted-printable. + * + * @return string * @access private */ function _getEncodedData($data, $encoding) { switch ($encoding) { - case '8bit': - case '7bit': - return $data; - break; + case 'quoted-printable': + return $this->_quotedPrintableEncode($data); + break; - case 'quoted-printable': - return $this->_quotedPrintableEncode($data); - break; + case 'base64': + return rtrim(chunk_split(base64_encode($data), 76, $this->_eol)); + break; - case 'base64': - return rtrim(chunk_split(base64_encode($data), 76, MAIL_MIMEPART_CRLF)); - break; - - default: - return $data; + case '8bit': + case '7bit': + default: + return $data; } } /** - * quoteadPrintableEncode() + * Returns encoded data based upon encoding passed to it * + * @param string $filename Data file location + * @param string $encoding The encoding type to use, 7bit, base64, + * or quoted-printable. + * @param resource $fh Output file handle. If set, data will be + * stored into it instead of returning it + * + * @return string Encoded data or PEAR error object + * @access private + */ + function _getEncodedDataFromFile($filename, $encoding, $fh=null) + { + if (!is_readable($filename)) { + $err = $this->_raiseError('Unable to read file: ' . $filename); + return $err; + } + + if (!($fd = fopen($filename, 'rb'))) { + $err = $this->_raiseError('Could not open file: ' . $filename); + return $err; + } + + $data = ''; + + switch ($encoding) { + case 'quoted-printable': + while (!feof($fd)) { + $buffer = $this->_quotedPrintableEncode(fgets($fd)); + if ($fh) { + fwrite($fh, $buffer); + } else { + $data .= $buffer; + } + } + break; + + case 'base64': + while (!feof($fd)) { + // Should read in a multiple of 57 bytes so that + // the output is 76 bytes per line. Don't use big chunks + // because base64 encoding is memory expensive + $buffer = fread($fd, 57 * 9198); // ca. 0.5 MB + $buffer = base64_encode($buffer); + $buffer = chunk_split($buffer, 76, $this->_eol); + if (feof($fd)) { + $buffer = rtrim($buffer); + } + + if ($fh) { + fwrite($fh, $buffer); + } else { + $data .= $buffer; + } + } + break; + + case '8bit': + case '7bit': + default: + while (!feof($fd)) { + $buffer = fread($fd, 1048576); // 1 MB + if ($fh) { + fwrite($fh, $buffer); + } else { + $data .= $buffer; + } + } + } + + fclose($fd); + + if (!$fh) { + return $data; + } + } + + /** * Encodes data to quoted-printable standard. * - * @param $input The data to encode - * @param $line_max Optional max line length. Should - * not be more than 76 chars + * @param string $input The data to encode + * @param int $line_max Optional max line length. Should + * not be more than 76 chars + * + * @return string Encoded data * * @access private */ function _quotedPrintableEncode($input , $line_max = 76) { + $eol = $this->_eol; + /* + // imap_8bit() is extremely fast, but doesn't handle properly some characters + if (function_exists('imap_8bit') && $line_max == 76) { + $input = preg_replace('/\r?\n/', "\r\n", $input); + $input = imap_8bit($input); + if ($eol != "\r\n") { + $input = str_replace("\r\n", $eol, $input); + } + return $input; + } + */ $lines = preg_split("/\r?\n/", $input); - $eol = MAIL_MIMEPART_CRLF; $escape = '='; $output = ''; - while(list(, $line) = each($lines)){ - - $linlen = strlen($line); + while (list($idx, $line) = each($lines)) { $newline = ''; + $i = 0; - for ($i = 0; $i < $linlen; $i++) { - $char = substr($line, $i, 1); + while (isset($line[$i])) { + $char = $line[$i]; $dec = ord($char); + $i++; - if (($dec == 32) AND ($i == ($linlen - 1))){ // convert space at eol only + if (($dec == 32) && (!isset($line[$i]))) { + // convert space at eol only $char = '=20'; - - } elseif(($dec == 9) AND ($i == ($linlen - 1))) { // convert tab at eol only - $char = '=09'; - } elseif($dec == 9) { - ; // Do nothing if a tab. - } elseif(($dec == 61) OR ($dec < 32 ) OR ($dec > 126)) { - $char = $escape . strtoupper(sprintf('%02s', dechex($dec))); + } elseif ($dec == 9 && isset($line[$i])) { + ; // Do nothing if a TAB is not on eol + } elseif (($dec == 61) || ($dec < 32) || ($dec > 126)) { + $char = $escape . sprintf('%02X', $dec); + } elseif (($dec == 46) && (($newline == '') + || ((strlen($newline) + strlen("=2E")) >= $line_max)) + ) { + // Bug #9722: convert full-stop at bol, + // some Windows servers need this, won't break anything (cipri) + // Bug #11731: full-stop at bol also needs to be encoded + // if this line would push us over the line_max limit. + $char = '=2E'; } - if ((strlen($newline) + strlen($char)) >= $line_max) { // MAIL_MIMEPART_CRLF is not counted - $output .= $newline . $escape . $eol; // soft line break; " =\r\n" is okay + // Note, when changing this line, also change the ($dec == 46) + // check line, as it mimics this line due to Bug #11731 + // EOL is not counted + if ((strlen($newline) + strlen($char)) >= $line_max) { + // soft line break; " =\r\n" is okay + $output .= $newline . $escape . $eol; $newline = ''; } $newline .= $char; } // end of for $output .= $newline . $eol; + unset($lines[$idx]); } - $output = substr($output, 0, -1 * strlen($eol)); // Don't want last crlf + // Don't want last crlf + $output = substr($output, 0, -1 * strlen($eol)); return $output; } + + /** + * Encodes the parameter of a header. + * + * @param string $name The name of the header-parameter + * @param string $value The value of the paramter + * @param string $charset The characterset of $value + * @param string $language The language used in $value + * @param string $encoding Parameter encoding. If not set, parameter value + * is encoded according to RFC2231 + * @param int $maxLength The maximum length of a line. Defauls to 75 + * + * @return string + * + * @access private + */ + function _buildHeaderParam($name, $value, $charset=null, $language=null, + $encoding=null, $maxLength=75 + ) { + // RFC 2045: + // value needs encoding if contains non-ASCII chars or is longer than 78 chars + if (!preg_match('#[^\x20-\x7E]#', $value)) { + $token_regexp = '#([^\x21\x23-\x27\x2A\x2B\x2D' + . '\x2E\x30-\x39\x41-\x5A\x5E-\x7E])#'; + if (!preg_match($token_regexp, $value)) { + // token + if (strlen($name) + strlen($value) + 3 <= $maxLength) { + return " {$name}={$value}"; + } + } else { + // quoted-string + $quoted = addcslashes($value, '\\"'); + if (strlen($name) + strlen($quoted) + 5 <= $maxLength) { + return " {$name}=\"{$quoted}\""; + } + } + } + + // RFC2047: use quoted-printable/base64 encoding + if ($encoding == 'quoted-printable' || $encoding == 'base64') { + return $this->_buildRFC2047Param($name, $value, $charset, $encoding); + } + + // RFC2231: + $encValue = preg_replace_callback( + '/([^\x21\x23\x24\x26\x2B\x2D\x2E\x30-\x39\x41-\x5A\x5E-\x7E])/', + array($this, '_encodeReplaceCallback'), $value + ); + $value = "$charset'$language'$encValue"; + + $header = " {$name}*={$value}"; + if (strlen($header) <= $maxLength) { + return $header; + } + + $preLength = strlen(" {$name}*0*="); + $maxLength = max(16, $maxLength - $preLength - 3); + $maxLengthReg = "|(.{0,$maxLength}[^\%][^\%])|"; + + $headers = array(); + $headCount = 0; + while ($value) { + $matches = array(); + $found = preg_match($maxLengthReg, $value, $matches); + if ($found) { + $headers[] = " {$name}*{$headCount}*={$matches[0]}"; + $value = substr($value, strlen($matches[0])); + } else { + $headers[] = " {$name}*{$headCount}*={$value}"; + $value = ''; + } + $headCount++; + } + + $headers = implode(';' . $this->_eol, $headers); + return $headers; + } + + /** + * Encodes header parameter as per RFC2047 if needed + * + * @param string $name The parameter name + * @param string $value The parameter value + * @param string $charset The parameter charset + * @param string $encoding Encoding type (quoted-printable or base64) + * @param int $maxLength Encoded parameter max length. Default: 76 + * + * @return string Parameter line + * @access private + */ + function _buildRFC2047Param($name, $value, $charset, + $encoding='quoted-printable', $maxLength=76 + ) { + // WARNING: RFC 2047 says: "An 'encoded-word' MUST NOT be used in + // parameter of a MIME Content-Type or Content-Disposition field", + // but... it's supported by many clients/servers + $quoted = ''; + + if ($encoding == 'base64') { + $value = base64_encode($value); + $prefix = '=?' . $charset . '?B?'; + $suffix = '?='; + + // 2 x SPACE, 2 x '"', '=', ';' + $add_len = strlen($prefix . $suffix) + strlen($name) + 6; + $len = $add_len + strlen($value); + + while ($len > $maxLength) { + // We can cut base64-encoded string every 4 characters + $real_len = floor(($maxLength - $add_len) / 4) * 4; + $_quote = substr($value, 0, $real_len); + $value = substr($value, $real_len); + + $quoted .= $prefix . $_quote . $suffix . $this->_eol . ' '; + $add_len = strlen($prefix . $suffix) + 4; // 2 x SPACE, '"', ';' + $len = strlen($value) + $add_len; + } + $quoted .= $prefix . $value . $suffix; + + } else { + // quoted-printable + $value = $this->encodeQP($value); + $prefix = '=?' . $charset . '?Q?'; + $suffix = '?='; + + // 2 x SPACE, 2 x '"', '=', ';' + $add_len = strlen($prefix . $suffix) + strlen($name) + 6; + $len = $add_len + strlen($value); + + while ($len > $maxLength) { + $length = $maxLength - $add_len; + // don't break any encoded letters + if (preg_match("/^(.{0,$length}[^\=][^\=])/", $value, $matches)) { + $_quote = $matches[1]; + } + + $quoted .= $prefix . $_quote . $suffix . $this->_eol . ' '; + $value = substr($value, strlen($_quote)); + $add_len = strlen($prefix . $suffix) + 4; // 2 x SPACE, '"', ';' + $len = strlen($value) + $add_len; + } + + $quoted .= $prefix . $value . $suffix; + } + + return " {$name}=\"{$quoted}\""; + } + + /** + * Encodes a header as per RFC2047 + * + * @param string $name The header name + * @param string $value The header data to encode + * @param string $charset Character set name + * @param string $encoding Encoding name (base64 or quoted-printable) + * @param string $eol End-of-line sequence. Default: "\r\n" + * + * @return string Encoded header data (without a name) + * @access public + * @since 1.6.1 + */ + function encodeHeader($name, $value, $charset='ISO-8859-1', + $encoding='quoted-printable', $eol="\r\n" + ) { + // Structured headers + $comma_headers = array( + 'from', 'to', 'cc', 'bcc', 'sender', 'reply-to', + 'resent-from', 'resent-to', 'resent-cc', 'resent-bcc', + 'resent-sender', 'resent-reply-to', + 'mail-reply-to', 'mail-followup-to', + 'return-receipt-to', 'disposition-notification-to', + ); + $other_headers = array( + 'references', 'in-reply-to', 'message-id', 'resent-message-id', + ); + + $name = strtolower($name); + + if (in_array($name, $comma_headers)) { + $separator = ','; + } else if (in_array($name, $other_headers)) { + $separator = ' '; + } + + if (!$charset) { + $charset = 'ISO-8859-1'; + } + + // Structured header (make sure addr-spec inside is not encoded) + if (!empty($separator)) { + // Simple e-mail address regexp + $email_regexp = '([^\s<]+|("[^\r\n"]+"))@\S+'; + + $parts = Mail_mimePart::_explodeQuotedString("[\t$separator]", $value); + $value = ''; + + foreach ($parts as $part) { + $part = preg_replace('/\r?\n[\s\t]*/', $eol . ' ', $part); + $part = trim($part); + + if (!$part) { + continue; + } + if ($value) { + $value .= $separator == ',' ? $separator . ' ' : ' '; + } else { + $value = $name . ': '; + } + + // let's find phrase (name) and/or addr-spec + if (preg_match('/^<' . $email_regexp . '>$/', $part)) { + $value .= $part; + } else if (preg_match('/^' . $email_regexp . '$/', $part)) { + // address without brackets and without name + $value .= $part; + } else if (preg_match('/<*' . $email_regexp . '>*$/', $part, $matches)) { + // address with name (handle name) + $address = $matches[0]; + $word = str_replace($address, '', $part); + $word = trim($word); + // check if phrase requires quoting + if ($word) { + // non-ASCII: require encoding + if (preg_match('#([^\s\x21-\x7E]){1}#', $word)) { + if ($word[0] == '"' && $word[strlen($word)-1] == '"') { + // de-quote quoted-string, encoding changes + // string to atom + $search = array("\\\"", "\\\\"); + $replace = array("\"", "\\"); + $word = str_replace($search, $replace, $word); + $word = substr($word, 1, -1); + } + // find length of last line + if (($pos = strrpos($value, $eol)) !== false) { + $last_len = strlen($value) - $pos; + } else { + $last_len = strlen($value); + } + $word = Mail_mimePart::encodeHeaderValue( + $word, $charset, $encoding, $last_len, $eol + ); + } else if (($word[0] != '"' || $word[strlen($word)-1] != '"') + && preg_match('/[\(\)\<\>\\\.\[\]@,;:"]/', $word) + ) { + // ASCII: quote string if needed + $word = '"'.addcslashes($word, '\\"').'"'; + } + } + $value .= $word.' '.$address; + } else { + // addr-spec not found, don't encode (?) + $value .= $part; + } + + // RFC2822 recommends 78 characters limit, use 76 from RFC2047 + $value = wordwrap($value, 76, $eol . ' '); + } + + // remove header name prefix (there could be EOL too) + $value = preg_replace( + '/^'.$name.':('.preg_quote($eol, '/').')* /', '', $value + ); + } else { + // Unstructured header + // non-ASCII: require encoding + if (preg_match('#([^\s\x21-\x7E]){1}#', $value)) { + if ($value[0] == '"' && $value[strlen($value)-1] == '"') { + // de-quote quoted-string, encoding changes + // string to atom + $search = array("\\\"", "\\\\"); + $replace = array("\"", "\\"); + $value = str_replace($search, $replace, $value); + $value = substr($value, 1, -1); + } + $value = Mail_mimePart::encodeHeaderValue( + $value, $charset, $encoding, strlen($name) + 2, $eol + ); + } else if (strlen($name.': '.$value) > 78) { + // ASCII: check if header line isn't too long and use folding + $value = preg_replace('/\r?\n[\s\t]*/', $eol . ' ', $value); + $tmp = wordwrap($name.': '.$value, 78, $eol . ' '); + $value = preg_replace('/^'.$name.':\s*/', '', $tmp); + // hard limit 998 (RFC2822) + $value = wordwrap($value, 998, $eol . ' ', true); + } + } + + return $value; + } + + /** + * Explode quoted string + * + * @param string $delimiter Delimiter expression string for preg_match() + * @param string $string Input string + * + * @return array String tokens array + * @access private + */ + function _explodeQuotedString($delimiter, $string) + { + $result = array(); + $strlen = strlen($string); + + for ($q=$p=$i=0; $i < $strlen; $i++) { + if ($string[$i] == "\"" + && (empty($string[$i-1]) || $string[$i-1] != "\\") + ) { + $q = $q ? false : true; + } else if (!$q && preg_match("/$delimiter/", $string[$i])) { + $result[] = substr($string, $p, $i - $p); + $p = $i + 1; + } + } + + $result[] = substr($string, $p); + return $result; + } + + /** + * Encodes a header value as per RFC2047 + * + * @param string $value The header data to encode + * @param string $charset Character set name + * @param string $encoding Encoding name (base64 or quoted-printable) + * @param int $prefix_len Prefix length. Default: 0 + * @param string $eol End-of-line sequence. Default: "\r\n" + * + * @return string Encoded header data + * @access public + * @since 1.6.1 + */ + function encodeHeaderValue($value, $charset, $encoding, $prefix_len=0, $eol="\r\n") + { + // #17311: Use multibyte aware method (requires mbstring extension) + if ($result = Mail_mimePart::encodeMB($value, $charset, $encoding, $prefix_len, $eol)) { + return $result; + } + + // Generate the header using the specified params and dynamicly + // determine the maximum length of such strings. + // 75 is the value specified in the RFC. + $encoding = $encoding == 'base64' ? 'B' : 'Q'; + $prefix = '=?' . $charset . '?' . $encoding .'?'; + $suffix = '?='; + $maxLength = 75 - strlen($prefix . $suffix); + $maxLength1stLine = $maxLength - $prefix_len; + + if ($encoding == 'B') { + // Base64 encode the entire string + $value = base64_encode($value); + + // We can cut base64 every 4 characters, so the real max + // we can get must be rounded down. + $maxLength = $maxLength - ($maxLength % 4); + $maxLength1stLine = $maxLength1stLine - ($maxLength1stLine % 4); + + $cutpoint = $maxLength1stLine; + $output = ''; + + while ($value) { + // Split translated string at every $maxLength + $part = substr($value, 0, $cutpoint); + $value = substr($value, $cutpoint); + $cutpoint = $maxLength; + // RFC 2047 specifies that any split header should + // be separated by a CRLF SPACE. + if ($output) { + $output .= $eol . ' '; + } + $output .= $prefix . $part . $suffix; + } + $value = $output; + } else { + // quoted-printable encoding has been selected + $value = Mail_mimePart::encodeQP($value); + + // This regexp will break QP-encoded text at every $maxLength + // but will not break any encoded letters. + $reg1st = "|(.{0,$maxLength1stLine}[^\=][^\=])|"; + $reg2nd = "|(.{0,$maxLength}[^\=][^\=])|"; + + if (strlen($value) > $maxLength1stLine) { + // Begin with the regexp for the first line. + $reg = $reg1st; + $output = ''; + while ($value) { + // Split translated string at every $maxLength + // But make sure not to break any translated chars. + $found = preg_match($reg, $value, $matches); + + // After this first line, we need to use a different + // regexp for the first line. + $reg = $reg2nd; + + // Save the found part and encapsulate it in the + // prefix & suffix. Then remove the part from the + // $value_out variable. + if ($found) { + $part = $matches[0]; + $len = strlen($matches[0]); + $value = substr($value, $len); + } else { + $part = $value; + $value = ''; + } + + // RFC 2047 specifies that any split header should + // be separated by a CRLF SPACE + if ($output) { + $output .= $eol . ' '; + } + $output .= $prefix . $part . $suffix; + } + $value = $output; + } else { + $value = $prefix . $value . $suffix; + } + } + + return $value; + } + + /** + * Encodes the given string using quoted-printable + * + * @param string $str String to encode + * + * @return string Encoded string + * @access public + * @since 1.6.0 + */ + function encodeQP($str) + { + // Bug #17226 RFC 2047 restricts some characters + // if the word is inside a phrase, permitted chars are only: + // ASCII letters, decimal digits, "!", "*", "+", "-", "/", "=", and "_" + + // "=", "_", "?" must be encoded + $regexp = '/([\x22-\x29\x2C\x2E\x3A-\x40\x5B-\x60\x7B-\x7E\x80-\xFF])/'; + $str = preg_replace_callback( + $regexp, array('Mail_mimePart', '_qpReplaceCallback'), $str + ); + + return str_replace(' ', '_', $str); + } + + /** + * Encodes the given string using base64 or quoted-printable. + * This method makes sure that encoded-word represents an integral + * number of characters as per RFC2047. + * + * @param string $str String to encode + * @param string $charset Character set name + * @param string $encoding Encoding name (base64 or quoted-printable) + * @param int $prefix_len Prefix length. Default: 0 + * @param string $eol End-of-line sequence. Default: "\r\n" + * + * @return string Encoded string + * @access public + * @since 1.8.0 + */ + function encodeMB($str, $charset, $encoding, $prefix_len=0, $eol="\r\n") + { + if (!function_exists('mb_substr') || !function_exists('mb_strlen')) { + return; + } + + $encoding = $encoding == 'base64' ? 'B' : 'Q'; + // 75 is the value specified in the RFC + $prefix = '=?' . $charset . '?'.$encoding.'?'; + $suffix = '?='; + $maxLength = 75 - strlen($prefix . $suffix); + + // A multi-octet character may not be split across adjacent encoded-words + // So, we'll loop over each character + // mb_stlen() with wrong charset will generate a warning here and return null + $length = mb_strlen($str, $charset); + $result = ''; + $line_length = $prefix_len; + + if ($encoding == 'B') { + // base64 + $start = 0; + $prev = ''; + + for ($i=1; $i<=$length; $i++) { + // See #17311 + $chunk = mb_substr($str, $start, $i-$start, $charset); + $chunk = base64_encode($chunk); + $chunk_len = strlen($chunk); + + if ($line_length + $chunk_len == $maxLength || $i == $length) { + if ($result) { + $result .= "\n"; + } + $result .= $chunk; + $line_length = 0; + $start = $i; + } else if ($line_length + $chunk_len > $maxLength) { + if ($result) { + $result .= "\n"; + } + if ($prev) { + $result .= $prev; + } + $line_length = 0; + $start = $i - 1; + } else { + $prev = $chunk; + } + } + } else { + // quoted-printable + // see encodeQP() + $regexp = '/([\x22-\x29\x2C\x2E\x3A-\x40\x5B-\x60\x7B-\x7E\x80-\xFF])/'; + + for ($i=0; $i<=$length; $i++) { + $char = mb_substr($str, $i, 1, $charset); + // RFC recommends underline (instead of =20) in place of the space + // that's one of the reasons why we're not using iconv_mime_encode() + if ($char == ' ') { + $char = '_'; + $char_len = 1; + } else { + $char = preg_replace_callback( + $regexp, array('Mail_mimePart', '_qpReplaceCallback'), $char + ); + $char_len = strlen($char); + } + + if ($line_length + $char_len > $maxLength) { + if ($result) { + $result .= "\n"; + } + $line_length = 0; + } + + $result .= $char; + $line_length += $char_len; + } + } + + if ($result) { + $result = $prefix + .str_replace("\n", $suffix.$eol.' '.$prefix, $result).$suffix; + } + + return $result; + } + + /** + * Callback function to replace extended characters (\x80-xFF) with their + * ASCII values (RFC2047: quoted-printable) + * + * @param array $matches Preg_replace's matches array + * + * @return string Encoded character string + * @access private + */ + function _qpReplaceCallback($matches) + { + return sprintf('=%02X', ord($matches[1])); + } + + /** + * Callback function to replace extended characters (\x80-xFF) with their + * ASCII values (RFC2231) + * + * @param array $matches Preg_replace's matches array + * + * @return string Encoded character string + * @access private + */ + function _encodeReplaceCallback($matches) + { + return sprintf('%%%02X', ord($matches[1])); + } + + /** + * PEAR::isError implementation + * + * @param mixed $data Object + * + * @return bool True if object is an instance of PEAR_Error + * @access private + */ + function _isError($data) + { + // PEAR::isError() is not PHP 5.4 compatible (see Bug #19473) + if (is_object($data) && is_a($data, 'PEAR_Error')) { + return true; + } + + return false; + } + + /** + * PEAR::raiseError implementation + * + * @param $message A text error message + * + * @return PEAR_Error Instance of PEAR_Error + * @access private + */ + function _raiseError($message) + { + // PEAR::raiseError() is not PHP 5.4 compatible + return new PEAR_Error($message); + } + } // End of class -?> diff --git a/htdocs/includes/nusoap/lib/Mail/null.php b/htdocs/includes/nusoap/lib/Mail/null.php deleted file mode 100644 index 5e220a5a39c..00000000000 --- a/htdocs/includes/nusoap/lib/Mail/null.php +++ /dev/null @@ -1,58 +0,0 @@ - | -// +----------------------------------------------------------------------+ -// -// - -/** - * Null implementation of the PEAR Mail:: interface. - * @access public - * @package Mail - */ -class Mail_null extends Mail { - - /** - * Implements Mail_null::send() function. Silently discards all - * mail. - * - * @param mixed $recipients Either a comma-seperated list of recipients - * (RFC822 compliant), or an array of recipients, - * each RFC822 valid. This may contain recipients not - * specified in the headers, for Bcc:, resending - * messages, etc. - * - * @param array $headers The array of headers to send with the mail, in an - * associative array, where the array key is the - * header name (ie, 'Subject'), and the array value - * is the header value (ie, 'test'). The header - * produced from those values would be 'Subject: - * test'. - * - * @param string $body The full text of the message body, including any - * Mime parts, etc. - * - * @return mixed Returns true on success, or a PEAR_Error - * containing a descriptive error message on - * failure. - * @access public - */ - function send($recipients, $headers, $body) - { - return true; - } - -} diff --git a/htdocs/includes/nusoap/lib/Mail/sendmail.php b/htdocs/includes/nusoap/lib/Mail/sendmail.php deleted file mode 100644 index fc492489a90..00000000000 --- a/htdocs/includes/nusoap/lib/Mail/sendmail.php +++ /dev/null @@ -1,144 +0,0 @@ - | -// +----------------------------------------------------------------------+ - -/** - * Sendmail implementation of the PEAR Mail:: interface. - * @access public - * @package Mail - */ -class Mail_sendmail extends Mail { - - /** - * The location of the sendmail or sendmail wrapper binary on the - * filesystem. - * @var string - */ - var $sendmail_path = '/usr/sbin/sendmail'; - - /** - * Any extra command-line parameters to pass to the sendmail or - * sendmail wrapper binary. - * @var string - */ - var $sendmail_args = ''; - - /** - * Constructor. - * - * Instantiates a new Mail_sendmail:: object based on the parameters - * passed in. It looks for the following parameters: - * sendmail_path The location of the sendmail binary on the - * filesystem. Defaults to '/usr/sbin/sendmail'. - * - * sendmail_args Any extra parameters to pass to the sendmail - * or sendmail wrapper binary. - * - * If a parameter is present in the $params array, it replaces the - * default. - * - * @param array $params Hash containing any parameters different from the - * defaults. - * @access public - */ - function Mail_sendmail($params) - { - if (isset($params['sendmail_path'])) $this->sendmail_path = $params['sendmail_path']; - if (isset($params['sendmail_args'])) $this->sendmail_args = $params['sendmail_args']; - - /* - * Because we need to pass message headers to the sendmail program on - * the commandline, we can't guarantee the use of the standard "\r\n" - * separator. Instead, we use the system's native line separator. - */ - $this->sep = (strstr(PHP_OS, 'WIN')) ? "\r\n" : "\n"; - } - - /** - * Implements Mail::send() function using the sendmail - * command-line binary. - * - * @param mixed $recipients Either a comma-seperated list of recipients - * (RFC822 compliant), or an array of recipients, - * each RFC822 valid. This may contain recipients not - * specified in the headers, for Bcc:, resending - * messages, etc. - * - * @param array $headers The array of headers to send with the mail, in an - * associative array, where the array key is the - * header name (ie, 'Subject'), and the array value - * is the header value (ie, 'test'). The header - * produced from those values would be 'Subject: - * test'. - * - * @param string $body The full text of the message body, including any - * Mime parts, etc. - * - * @return mixed Returns true on success, or a PEAR_Error - * containing a descriptive error message on - * failure. - * @access public - */ - function send($recipients, $headers, $body) - { - $recipients = $this->parseRecipients($recipients); - if (PEAR::isError($recipients)) { - return $recipients; - } - $recipients = escapeShellCmd(implode(' ', $recipients)); - - $headerElements = $this->prepareHeaders($headers); - if (PEAR::isError($headerElements)) { - return $headerElements; - } - list($from, $text_headers) = $headerElements; - - if (!isset($from)) { - return PEAR::raiseError('No from address given.'); - } elseif (strstr($from, ' ') || - strstr($from, ';') || - strstr($from, '&') || - strstr($from, '`')) { - return PEAR::raiseError('From address specified with dangerous characters.'); - } - - $result = 0; - if (@is_file($this->sendmail_path)) { - $from = escapeShellCmd($from); - $mail = popen($this->sendmail_path . (!empty($this->sendmail_args) ? ' ' . $this->sendmail_args : '') . " -f$from -- $recipients", 'w'); - fputs($mail, $text_headers); - fputs($mail, $this->sep); // newline to end the headers section - fputs($mail, $body); - $result = pclose($mail); - if (version_compare(phpversion(), '4.2.3') == -1) { - // With older php versions, we need to shift the - // pclose result to get the exit code. - $result = $result >> 8 & 0xFF; - } - } else { - return PEAR::raiseError('sendmail [' . $this->sendmail_path . '] is not a valid file'); - } - - if ($result != 0) { - return PEAR::raiseError('sendmail returned error code ' . $result, - $result); - } - - return true; - } - -} diff --git a/htdocs/includes/nusoap/lib/Mail/smtp.php b/htdocs/includes/nusoap/lib/Mail/smtp.php deleted file mode 100644 index 200d5dacaa9..00000000000 --- a/htdocs/includes/nusoap/lib/Mail/smtp.php +++ /dev/null @@ -1,222 +0,0 @@ - | -// | Jon Parise | -// +----------------------------------------------------------------------+ - -/** - * SMTP implementation of the PEAR Mail:: interface. Requires the PEAR - * Net_SMTP:: class. - * @access public - * @package Mail - */ -class Mail_smtp extends Mail { - - /** - * The SMTP host to connect to. - * @var string - */ - var $host = 'localhost'; - - /** - * The port the SMTP server is on. - * @var integer - */ - var $port = 25; - - /** - * Should SMTP authentication be used? - * - * This value may be set to true, false or the name of a specific - * authentication method. - * - * If the value is set to true, the Net_SMTP package will attempt to use - * the best authentication method advertised by the remote SMTP server. - * - * @var mixed - */ - var $auth = false; - - /** - * The username to use if the SMTP server requires authentication. - * @var string - */ - var $username = ''; - - /** - * The password to use if the SMTP server requires authentication. - * @var string - */ - var $password = ''; - - /** - * Hostname or domain that will be sent to the remote SMTP server in the - * HELO / EHLO message. - * - * @var string - */ - var $localhost = 'localhost'; - - /** - * SMTP connection timeout value. NULL indicates no timeout. - * - * @var integer - */ - var $timeout = null; - - /** - * Whether to use VERP or not. If not a boolean, the string value - * will be used as the VERP separators. - * - * @var mixed boolean or string - */ - var $verp = false; - - /** - * Turn on Net_SMTP debugging? - * - * @var boolean $debug - */ - var $debug = false; - - /** - * Constructor. - * - * Instantiates a new Mail_smtp:: object based on the parameters - * passed in. It looks for the following parameters: - * host The server to connect to. Defaults to localhost. - * port The port to connect to. Defaults to 25. - * auth SMTP authentication. Defaults to none. - * username The username to use for SMTP auth. No default. - * password The password to use for SMTP auth. No default. - * localhost The local hostname / domain. Defaults to localhost. - * timeout The SMTP connection timeout. Defaults to none. - * verp Whether to use VERP or not. Defaults to false. - * debug Activate SMTP debug mode? Defaults to false. - * - * If a parameter is present in the $params array, it replaces the - * default. - * - * @param array Hash containing any parameters different from the - * defaults. - * @access public - */ - function Mail_smtp($params) - { - if (isset($params['host'])) $this->host = $params['host']; - if (isset($params['port'])) $this->port = $params['port']; - if (isset($params['auth'])) $this->auth = $params['auth']; - if (isset($params['username'])) $this->username = $params['username']; - if (isset($params['password'])) $this->password = $params['password']; - if (isset($params['localhost'])) $this->localhost = $params['localhost']; - if (isset($params['timeout'])) $this->timeout = $params['timeout']; - if (isset($params['verp'])) $this->verp = $params['verp']; - if (isset($params['debug'])) $this->debug = (boolean)$params['debug']; - } - - /** - * Implements Mail::send() function using SMTP. - * - * @param mixed $recipients Either a comma-seperated list of recipients - * (RFC822 compliant), or an array of recipients, - * each RFC822 valid. This may contain recipients not - * specified in the headers, for Bcc:, resending - * messages, etc. - * - * @param array $headers The array of headers to send with the mail, in an - * associative array, where the array key is the - * header name (e.g., 'Subject'), and the array value - * is the header value (e.g., 'test'). The header - * produced from those values would be 'Subject: - * test'. - * - * @param string $body The full text of the message body, including any - * Mime parts, etc. - * - * @return mixed Returns true on success, or a PEAR_Error - * containing a descriptive error message on - * failure. - * @access public - */ - function send($recipients, $headers, $body) - { - include_once 'Net/SMTP.php'; - - if (!($smtp = &new Net_SMTP($this->host, $this->port, $this->localhost))) { - return PEAR::raiseError('unable to instantiate Net_SMTP object'); - } - - if ($this->debug) { - $smtp->setDebug(true); - } - - if (PEAR::isError($smtp->connect($this->timeout))) { - return PEAR::raiseError('unable to connect to smtp server ' . - $this->host . ':' . $this->port); - } - - if ($this->auth) { - $method = is_string($this->auth) ? $this->auth : ''; - - if (PEAR::isError($smtp->auth($this->username, $this->password, - $method))) { - return PEAR::raiseError('unable to authenticate to smtp server'); - } - } - - $headerElements = $this->prepareHeaders($headers); - if (PEAR::isError($headerElements)) { - return $headerElements; - } - list($from, $text_headers) = $headerElements; - - /* Since few MTAs are going to allow this header to be forged - * unless it's in the MAIL FROM: exchange, we'll use - * Return-Path instead of From: if it's set. */ - if (!empty($headers['Return-Path'])) { - $from = $headers['Return-Path']; - } - - if (!isset($from)) { - return PEAR::raiseError('No from address given'); - } - - $args['verp'] = $this->verp; - if (PEAR::isError($smtp->mailFrom($from, $args))) { - return PEAR::raiseError('unable to set sender to [' . $from . ']'); - } - - $recipients = $this->parseRecipients($recipients); - if (PEAR::isError($recipients)) { - return $recipients; - } - - foreach ($recipients as $recipient) { - if (PEAR::isError($res = $smtp->rcptTo($recipient))) { - return PEAR::raiseError('unable to add recipient [' . - $recipient . ']: ' . $res->getMessage()); - } - } - - if (PEAR::isError($smtp->data($text_headers . "\r\n" . $body))) { - return PEAR::raiseError('unable to send data'); - } - - $smtp->disconnect(); - return true; - } - -} diff --git a/htdocs/includes/nusoap/lib/Mail/xmail.dtd b/htdocs/includes/nusoap/lib/Mail/xmail.dtd deleted file mode 100755 index 9f42ca8b331..00000000000 --- a/htdocs/includes/nusoap/lib/Mail/xmail.dtd +++ /dev/null @@ -1,19 +0,0 @@ - - - - - - - - - - - - - - - - - - - diff --git a/htdocs/includes/nusoap/lib/Mail/xmail.xsl b/htdocs/includes/nusoap/lib/Mail/xmail.xsl deleted file mode 100755 index 0b948913f84..00000000000 --- a/htdocs/includes/nusoap/lib/Mail/xmail.xsl +++ /dev/null @@ -1,70 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - : - - - - - - - - ; - - =" - - " - - - - - - - - - - - - - - - - - - - - -- - - - - ---- - - - - - - - - - - - \ No newline at end of file diff --git a/htdocs/install/mysql/data/llx_c_tva.sql b/htdocs/install/mysql/data/llx_c_tva.sql index 7b42efdae0e..7ad3fd91443 100644 --- a/htdocs/install/mysql/data/llx_c_tva.sql +++ b/htdocs/install/mysql/data/llx_c_tva.sql @@ -49,7 +49,7 @@ insert into llx_c_tva(rowid,fk_pays,taux,recuperableonly,note,active) values (41 insert into llx_c_tva(rowid,fk_pays,taux,recuperableonly,note,active) values (412, 41, '10','0','VAT reduced rate', 1); insert into llx_c_tva(rowid,fk_pays,taux,recuperableonly,note,active) values (413, 41, '0','0','VAT Rate 0',1); --- BRASIL (id country=59) +-- BRASIL (id country=56) insert into llx_c_tva(rowid,fk_pays,taux,recuperableonly,note,active) values (561, 56, '0','0','VAT reduced rate',1); -- BULGARIA (id country=59) @@ -139,6 +139,10 @@ insert into llx_c_tva(rowid,fk_pays,taux,recuperableonly,note,active) values (83 insert into llx_c_tva(rowid,fk_pays,taux,recuperableonly,note,active) values (84, 8, '9','0','VAT reduced rate',1); insert into llx_c_tva(rowid,fk_pays,taux,recuperableonly,note,active) values (85, 8, '4.8','0','VAT reduced rate',1); +-- IVORY COST (id country=21) +insert into llx_c_tva(rowid,fk_pays,taux,recuperableonly,localtax1,localtax1_type,localtax2,localtax2_type,note,active) values (211, 21, '0','0',0,0,0,0,'IVA Rate 0',1); +insert into llx_c_tva(rowid,fk_pays,taux,recuperableonly,localtax1,localtax1_type,localtax2,localtax2_type,note,active) values (212, 21, '18','0',7.5,2,0,0,'IVA standard rate',1); + -- JAPAN (id country=123) insert into llx_c_tva(rowid,fk_pays,taux,recuperableonly,note,active) values (1231, 123, '0','0','VAT Rate 0',1); insert into llx_c_tva(rowid,fk_pays,taux,recuperableonly,note,active) values (1232, 123, '5','0','VAT Rate 5',1); @@ -215,6 +219,11 @@ INSERT INTO llx_c_tva(rowid,fk_pays,taux,recuperableonly,note,active) VALUES ( 2 INSERT INTO llx_c_tva(rowid,fk_pays,taux,recuperableonly,note,active) VALUES (861, 86, '13', '0', 'IVA 13', 1); INSERT INTO llx_c_tva(rowid,fk_pays,taux,recuperableonly,note,active) VALUES (862, 86, '0', '0', 'SIN IVA', 1); +-- SENEGAL (id country=22) +insert into llx_c_tva(rowid,fk_pays,taux,recuperableonly,note,active) values (221, 22, '18', '0', 'VAT standard rate',1); +insert into llx_c_tva(rowid,fk_pays,taux,recuperableonly,note,active) values (222, 22, '10', '0', 'VAT reduced rate',1); +insert into llx_c_tva(rowid,fk_pays,taux,recuperableonly,note,active) values (223, 22, '0', '0', 'VAT Rate 0', 1); + -- SLOVAKIA (id country=201) INSERT INTO llx_c_tva(rowid,fk_pays,taux,recuperableonly,note,active) VALUES (2011, 201, '19', '0', 'VAT standard rate', 1); INSERT INTO llx_c_tva(rowid,fk_pays,taux,recuperableonly,note,active) VALUES (2012, 201, '10', '0', 'VAT reduced rate', 1); diff --git a/htdocs/install/mysql/migration/3.6.0-3.7.0.sql b/htdocs/install/mysql/migration/3.6.0-3.7.0.sql index 9423b6ab607..0c44708c6db 100755 --- a/htdocs/install/mysql/migration/3.6.0-3.7.0.sql +++ b/htdocs/install/mysql/migration/3.6.0-3.7.0.sql @@ -1174,3 +1174,8 @@ ALTER TABLE llx_commande_fournisseur_dispatch ADD COLUMN fk_commandefourndet INT ALTER TABLE llx_extrafields ADD COLUMN perms varchar(255) after fieldrequired; ALTER TABLE llx_extrafields ADD COLUMN list integer DEFAULT 0 after perms; +-- IVORY COST (id country=21) +insert into llx_c_tva(rowid,fk_pays,taux,recuperableonly,localtax1,localtax1_type,localtax2,localtax2_type,note,active) values (211, 21, '0','0',0,0,0,0,'IVA Rate 0',1); +insert into llx_c_tva(rowid,fk_pays,taux,recuperableonly,localtax1,localtax1_type,localtax2,localtax2_type,note,active) values (212, 21, '18','0',7.5,2,0,0,'IVA standard rate',1); + +ALTER TABLE llx_livraison MODIFY COLUMN date_delivery DATETIME NULL DEFAULT NULL; diff --git a/htdocs/install/mysql/migration/3.7.0-3.8.0.sql b/htdocs/install/mysql/migration/3.7.0-3.8.0.sql index 469c5e218c0..586ee98150d 100755 --- a/htdocs/install/mysql/migration/3.7.0-3.8.0.sql +++ b/htdocs/install/mysql/migration/3.7.0-3.8.0.sql @@ -64,6 +64,7 @@ create table llx_payment_loan fk_user_modif integer )ENGINE=innodb; +ALTER TABLE llx_extrafields ADD COLUMN fieldrequired integer DEFAULT 0; ALTER TABLE llx_extrafields ADD COLUMN perms varchar(255) after fieldrequired; ALTER TABLE llx_extrafields ADD COLUMN list integer DEFAULT 0 after perms; @@ -180,6 +181,8 @@ ALTER TABLE llx_stock_mouvement ADD COLUMN batch varchar(30) DEFAULT NULL; ALTER TABLE llx_stock_mouvement ADD COLUMN eatby date DEFAULT NULL; ALTER TABLE llx_stock_mouvement ADD COLUMN sellby date DEFAULT NULL; +UPDATE llx_product_batch SET batch = 'unknown' WHERE batch IS NULL; +ALTER TABLE llx_product_batch MODIFY COLUMN batch varchar(30) NOT NULL; CREATE TABLE llx_expensereport ( @@ -377,6 +380,9 @@ CREATE TABLE llx_askpricesupplierdet_extrafields ( -- End Module AskPriceSupplier -- +ALTER TABLE llx_commande_fournisseur ADD COLUMN date_approve2 datetime after date_approve; +ALTER TABLE llx_commande_fournisseur ADD COLUMN fk_user_approve2 integer after fk_user_approve; + ALTER TABLE llx_societe ADD COLUMN fk_incoterms integer; ALTER TABLE llx_societe ADD COLUMN location_incoterms varchar(255); ALTER TABLE llx_propal ADD COLUMN fk_incoterms integer; @@ -385,8 +391,6 @@ ALTER TABLE llx_commande ADD COLUMN fk_incoterms integer; ALTER TABLE llx_commande ADD COLUMN location_incoterms varchar(255); ALTER TABLE llx_commande_fournisseur ADD COLUMN fk_incoterms integer; ALTER TABLE llx_commande_fournisseur ADD COLUMN location_incoterms varchar(255); -ALTER TABLE llx_commande_fournisseur ADD COLUMN date_approve2 datetime after date_approve; -ALTER TABLE llx_commande_fournisseur ADD COLUMN fk_user_approve2 integer after fk_user_approve; ALTER TABLE llx_facture ADD COLUMN fk_incoterms integer; ALTER TABLE llx_facture ADD COLUMN location_incoterms varchar(255); ALTER TABLE llx_facture_fourn ADD COLUMN fk_incoterms integer; @@ -512,6 +516,27 @@ create table llx_c_price_global_variable_updater next_update integer DEFAULT 0, last_status text DEFAULT NULL )ENGINE=innodb; + +ALTER TABLE llx_adherent CHANGE COLUMN note note_private text DEFAULT NULL; +ALTER TABLE llx_adherent ADD COLUMN note_public text DEFAULT NULL after note_private; + +CREATE TABLE IF NOT EXISTS llx_propal_merge_pdf_product ( + rowid integer NOT NULL auto_increment PRIMARY KEY, + fk_product integer NOT NULL, + file_name varchar(200) NOT NULL, + lang varchar(5) DEFAULT NULL, + fk_user_author integer DEFAULT NULL, + fk_user_mod integer NOT NULL, + datec datetime NOT NULL, + tms timestamp NOT NULL, + import_key varchar(14) DEFAULT NULL +) ENGINE=InnoDB; + + +-- Feature request: A page to merge two thirdparties into one #2613 +ALTER TABLE llx_categorie_societe CHANGE COLUMN fk_societe fk_soc INTEGER NOT NULL; +ALTER TABLE llx_societe CHANGE COLUMN fk_societe fk_soc INTEGER NOT NULL; +ALTER TABLE llx_user CHANGE COLUMN fk_societe fk_soc INTEGER NOT NULL; -- Units create table llx_c_units( rowid integer AUTO_INCREMENT PRIMARY KEY, diff --git a/htdocs/install/mysql/tables/llx_adherent.sql b/htdocs/install/mysql/tables/llx_adherent.sql index e7f9c246834..493d5b1124d 100644 --- a/htdocs/install/mysql/tables/llx_adherent.sql +++ b/htdocs/install/mysql/tables/llx_adherent.sql @@ -54,7 +54,8 @@ create table llx_adherent statut smallint NOT NULL DEFAULT 0, public smallint NOT NULL DEFAULT 0, -- certain champ de la fiche sont ils public ou pas ? datefin datetime, -- date de fin de validite de la cotisation - note text, + note_private text DEFAULT NULL, + note_public text DEFAULT NULL, datevalid datetime, -- date de validation datec datetime, -- date de creation tms timestamp, -- date de modification diff --git a/htdocs/install/mysql/tables/llx_categorie_fournisseur.key.sql b/htdocs/install/mysql/tables/llx_categorie_fournisseur.key.sql index d8e84769cf0..7293c152b9a 100644 --- a/htdocs/install/mysql/tables/llx_categorie_fournisseur.key.sql +++ b/htdocs/install/mysql/tables/llx_categorie_fournisseur.key.sql @@ -17,9 +17,9 @@ -- -- ============================================================================ -ALTER TABLE llx_categorie_fournisseur ADD PRIMARY KEY pk_categorie_fournisseur (fk_categorie, fk_societe); +ALTER TABLE llx_categorie_fournisseur ADD PRIMARY KEY pk_categorie_fournisseur (fk_categorie, fk_soc); ALTER TABLE llx_categorie_fournisseur ADD INDEX idx_categorie_fournisseur_fk_categorie (fk_categorie); -ALTER TABLE llx_categorie_fournisseur ADD INDEX idx_categorie_fournisseur_fk_societe (fk_societe); +ALTER TABLE llx_categorie_fournisseur ADD INDEX idx_categorie_fournisseur_fk_societe (fk_soc); ALTER TABLE llx_categorie_fournisseur ADD CONSTRAINT fk_categorie_fournisseur_categorie_rowid FOREIGN KEY (fk_categorie) REFERENCES llx_categorie (rowid); -ALTER TABLE llx_categorie_fournisseur ADD CONSTRAINT fk_categorie_fournisseur_fk_soc FOREIGN KEY (fk_societe) REFERENCES llx_societe (rowid); +ALTER TABLE llx_categorie_fournisseur ADD CONSTRAINT fk_categorie_fournisseur_fk_soc FOREIGN KEY (fk_soc) REFERENCES llx_societe (rowid); diff --git a/htdocs/install/mysql/tables/llx_categorie_fournisseur.sql b/htdocs/install/mysql/tables/llx_categorie_fournisseur.sql index 90df0e6f969..5a270b1fad9 100644 --- a/htdocs/install/mysql/tables/llx_categorie_fournisseur.sql +++ b/htdocs/install/mysql/tables/llx_categorie_fournisseur.sql @@ -22,6 +22,6 @@ create table llx_categorie_fournisseur ( fk_categorie integer NOT NULL, - fk_societe integer NOT NULL, + fk_soc integer NOT NULL, import_key varchar(14) )ENGINE=innodb; diff --git a/htdocs/install/mysql/tables/llx_categorie_societe.key.sql b/htdocs/install/mysql/tables/llx_categorie_societe.key.sql index 6c912acb4c4..17605fc3520 100644 --- a/htdocs/install/mysql/tables/llx_categorie_societe.key.sql +++ b/htdocs/install/mysql/tables/llx_categorie_societe.key.sql @@ -16,9 +16,9 @@ -- -- ============================================================================ -ALTER TABLE llx_categorie_societe ADD PRIMARY KEY pk_categorie_societe (fk_categorie, fk_societe); +ALTER TABLE llx_categorie_societe ADD PRIMARY KEY pk_categorie_societe (fk_categorie, fk_soc); ALTER TABLE llx_categorie_societe ADD INDEX idx_categorie_societe_fk_categorie (fk_categorie); -ALTER TABLE llx_categorie_societe ADD INDEX idx_categorie_societe_fk_societe (fk_societe); +ALTER TABLE llx_categorie_societe ADD INDEX idx_categorie_societe_fk_societe (fk_soc); ALTER TABLE llx_categorie_societe ADD CONSTRAINT fk_categorie_societe_categorie_rowid FOREIGN KEY (fk_categorie) REFERENCES llx_categorie (rowid); -ALTER TABLE llx_categorie_societe ADD CONSTRAINT fk_categorie_societe_fk_soc FOREIGN KEY (fk_societe) REFERENCES llx_societe (rowid); +ALTER TABLE llx_categorie_societe ADD CONSTRAINT fk_categorie_societe_fk_soc FOREIGN KEY (fk_soc) REFERENCES llx_societe (rowid); diff --git a/htdocs/install/mysql/tables/llx_categorie_societe.sql b/htdocs/install/mysql/tables/llx_categorie_societe.sql index 6543fc52bc8..c347d40c372 100644 --- a/htdocs/install/mysql/tables/llx_categorie_societe.sql +++ b/htdocs/install/mysql/tables/llx_categorie_societe.sql @@ -20,6 +20,6 @@ create table llx_categorie_societe ( fk_categorie integer NOT NULL, - fk_societe integer NOT NULL, + fk_soc integer NOT NULL, import_key varchar(14) )ENGINE=innodb; diff --git a/htdocs/install/mysql/tables/llx_commande.sql b/htdocs/install/mysql/tables/llx_commande.sql index 7bf22df1a1d..3511aa7ec78 100644 --- a/htdocs/install/mysql/tables/llx_commande.sql +++ b/htdocs/install/mysql/tables/llx_commande.sql @@ -62,10 +62,12 @@ create table llx_commande fk_mode_reglement integer, -- mode de reglement date_livraison date default NULL, - fk_shipping_method integer, -- shipping method id + fk_shipping_method integer, -- shipping method id fk_availability integer NULL, fk_input_reason integer, -- id coming from c_input_reason, '0' if no defined fk_delivery_address integer, -- delivery address (deprecated) + fk_incoterms integer, -- for incoterms + location_incoterms varchar(255), -- for incoterms import_key varchar(14), extraparams varchar(255) -- for stock other parameters with json format diff --git a/htdocs/install/mysql/tables/llx_commande_fournisseur.sql b/htdocs/install/mysql/tables/llx_commande_fournisseur.sql index 247c8e8d6af..33588d8bf66 100644 --- a/htdocs/install/mysql/tables/llx_commande_fournisseur.sql +++ b/htdocs/install/mysql/tables/llx_commande_fournisseur.sql @@ -62,6 +62,8 @@ create table llx_commande_fournisseur fk_cond_reglement integer, -- condition de reglement fk_mode_reglement integer, -- mode de reglement fk_input_method integer default 0, -- id coming from c_input_reason, '0' if no defined + fk_incoterms integer, -- for incoterms + location_incoterms varchar(255), -- for incoterms import_key varchar(14), extraparams varchar(255) -- for stock other parameters with json format diff --git a/htdocs/install/mysql/tables/llx_contrat.sql b/htdocs/install/mysql/tables/llx_contrat.sql index 0e75c50305b..73e29e8bdd4 100644 --- a/htdocs/install/mysql/tables/llx_contrat.sql +++ b/htdocs/install/mysql/tables/llx_contrat.sql @@ -23,12 +23,12 @@ create table llx_contrat rowid integer AUTO_INCREMENT PRIMARY KEY, ref varchar(30), -- contrat reference ref_supplier varchar(30), -- suplier contract ref - ref_ext varchar(30), -- external contract ref - entity integer DEFAULT 1 NOT NULL, -- multi company id + ref_ext varchar(30), -- external contract ref + entity integer DEFAULT 1 NOT NULL, -- multi company id tms timestamp, - datec datetime, -- creation date + datec datetime, -- creation date date_contrat datetime, - statut smallint DEFAULT 0, + statut smallint DEFAULT 0, -- not used. deprecated mise_en_service datetime, fin_validite datetime, date_cloture datetime, diff --git a/htdocs/install/mysql/tables/llx_expedition.sql b/htdocs/install/mysql/tables/llx_expedition.sql index 0a152b13069..d142a5cc628 100644 --- a/htdocs/install/mysql/tables/llx_expedition.sql +++ b/htdocs/install/mysql/tables/llx_expedition.sql @@ -50,6 +50,8 @@ create table llx_expedition weight float, -- weight note_private text, note_public text, - model_pdf varchar(255) + model_pdf varchar(255), + fk_incoterms integer, -- for incoterms + location_incoterms varchar(255) -- for incoterms )ENGINE=innodb; diff --git a/htdocs/install/mysql/tables/llx_facture.sql b/htdocs/install/mysql/tables/llx_facture.sql index eada5b46c2e..93a376c599c 100644 --- a/htdocs/install/mysql/tables/llx_facture.sql +++ b/htdocs/install/mysql/tables/llx_facture.sql @@ -75,6 +75,9 @@ create table llx_facture note_private text, note_public text, model_pdf varchar(255), + + fk_incoterms integer, -- for incoterms + location_incoterms varchar(255), -- for incoterms import_key varchar(14), extraparams varchar(255), -- for stock other parameters with json format diff --git a/htdocs/install/mysql/tables/llx_facture_fourn.sql b/htdocs/install/mysql/tables/llx_facture_fourn.sql index 33773b7a9cb..703b86841f9 100644 --- a/htdocs/install/mysql/tables/llx_facture_fourn.sql +++ b/htdocs/install/mysql/tables/llx_facture_fourn.sql @@ -60,12 +60,14 @@ create table llx_facture_fourn fk_projet integer, -- projet auquel est associee la facture fk_account integer, -- bank account - fk_cond_reglement integer, -- condition de reglement (30 jours, fin de mois ...) - fk_mode_reglement integer, -- mode de reglement (CHQ, VIR, ...) - date_lim_reglement date, -- date limite de reglement + fk_cond_reglement integer, -- condition de reglement (30 jours, fin de mois ...) + fk_mode_reglement integer, -- mode de reglement (CHQ, VIR, ...) + date_lim_reglement date, -- date limite de reglement note_private text, note_public text, + fk_incoterms integer, -- for incoterms + location_incoterms varchar(255), -- for incoterms model_pdf varchar(255), import_key varchar(14), extraparams varchar(255) -- for stock other parameters with json format diff --git a/htdocs/install/mysql/tables/llx_facture_rec.sql b/htdocs/install/mysql/tables/llx_facture_rec.sql index cba4b580cf0..7c1151f36ca 100644 --- a/htdocs/install/mysql/tables/llx_facture_rec.sql +++ b/htdocs/install/mysql/tables/llx_facture_rec.sql @@ -50,9 +50,9 @@ create table llx_facture_rec note_private text, note_public text, - usenewprice integer DEFAULT 0, - frequency integer, - unit_frequency varchar(2) DEFAULT 'd', + usenewprice integer DEFAULT 0, -- update invoice with current price of product instead of recorded price + frequency integer, -- frequency (for example: 3 for every 3 month) + unit_frequency varchar(2) DEFAULT 'm', -- 'm' for month (date_when must be a day <= 28), 'y' for year, ... date_when datetime DEFAULT NULL, -- date for next gen (when an invoice is generated, this field must be updated with next date) date_last_gen datetime DEFAULT NULL, -- date for last gen (date with last successfull generation of invoice) diff --git a/htdocs/install/mysql/tables/llx_livraison.sql b/htdocs/install/mysql/tables/llx_livraison.sql index 486212158aa..c999cfdb3c2 100644 --- a/htdocs/install/mysql/tables/llx_livraison.sql +++ b/htdocs/install/mysql/tables/llx_livraison.sql @@ -33,12 +33,14 @@ create table llx_livraison fk_user_author integer, -- createur du bon de livraison date_valid datetime, -- date de validation fk_user_valid integer, -- valideur du bon de livraison - date_delivery date DEFAULT NULL, -- delivery date + date_delivery datetime DEFAULT NULL, -- delivery date fk_address integer, -- delivery address (deprecated) fk_statut smallint DEFAULT 0, total_ht double(24,8) DEFAULT 0, note_private text, note_public text, - model_pdf varchar(255) + model_pdf varchar(255), + fk_incoterms integer, -- for incoterms + location_incoterms varchar(255) -- for incoterms )ENGINE=innodb; diff --git a/htdocs/install/mysql/tables/llx_product_batch.key.sql b/htdocs/install/mysql/tables/llx_product_batch.key.sql index f1f24c8b81a..d022beac743 100644 --- a/htdocs/install/mysql/tables/llx_product_batch.key.sql +++ b/htdocs/install/mysql/tables/llx_product_batch.key.sql @@ -16,5 +16,6 @@ -- -- ============================================================================ -ALTER TABLE llx_product_batch ADD INDEX idx_fk_product_stock (fk_product_stock); +ALTER TABLE llx_product_batch ADD INDEX idx_fk_product_stock(fk_product_stock); +ALTER TABLE llx_product_batch ADD INDEX idx_batch(batch); ALTER TABLE llx_product_batch ADD CONSTRAINT fk_product_batch_fk_product_stock FOREIGN KEY (fk_product_stock) REFERENCES llx_product_stock (rowid); diff --git a/htdocs/install/mysql/tables/llx_product_batch.sql b/htdocs/install/mysql/tables/llx_product_batch.sql index cbcca4ecacd..1cf72151304 100644 --- a/htdocs/install/mysql/tables/llx_product_batch.sql +++ b/htdocs/install/mysql/tables/llx_product_batch.sql @@ -21,7 +21,7 @@ CREATE TABLE llx_product_batch ( fk_product_stock integer NOT NULL, eatby datetime DEFAULT NULL, sellby datetime DEFAULT NULL, - batch varchar(30) DEFAULT NULL, + batch varchar(30) NOT NULL, qty double NOT NULL DEFAULT 0, import_key varchar(14) DEFAULT NULL ) ENGINE=InnoDB; diff --git a/htdocs/install/mysql/tables/llx_propal.sql b/htdocs/install/mysql/tables/llx_propal.sql index 90996073021..8090b1fcb4d 100644 --- a/htdocs/install/mysql/tables/llx_propal.sql +++ b/htdocs/install/mysql/tables/llx_propal.sql @@ -65,6 +65,8 @@ create table llx_propal fk_shipping_method integer, -- shipping method id fk_availability integer NULL, fk_input_reason integer, + fk_incoterms integer, -- for incoterms + location_incoterms varchar(255), -- for incoterms import_key varchar(14), extraparams varchar(255), -- for stock other parameters with json format fk_delivery_address integer -- delivery address (deprecated) diff --git a/htdocs/install/mysql/tables/llx_propal_merge_pdf_product.sql b/htdocs/install/mysql/tables/llx_propal_merge_pdf_product.sql new file mode 100644 index 00000000000..93af93c9190 --- /dev/null +++ b/htdocs/install/mysql/tables/llx_propal_merge_pdf_product.sql @@ -0,0 +1,28 @@ +-- +-- Copyright (C) 2013 Florian HENRY +-- +-- This program is free software: you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation, either version 3 of the License, or +-- (at your option) any later version. +-- +-- This program is distributed in the hope that it will be useful, +-- but WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-- GNU General Public License for more details. +-- +-- You should have received a copy of the GNU General Public License +-- along with this program. If not, see . + +CREATE TABLE IF NOT EXISTS llx_propal_merge_pdf_product ( + rowid integer NOT NULL auto_increment PRIMARY KEY, + fk_product integer NOT NULL, + file_name varchar(200) NOT NULL, + lang varchar(5) DEFAULT NULL, + fk_user_author integer DEFAULT NULL, + fk_user_mod integer NOT NULL, + datec datetime NOT NULL, + tms timestamp NOT NULL, + import_key varchar(14) DEFAULT NULL +) ENGINE=InnoDB; + diff --git a/htdocs/install/mysql/tables/llx_societe.sql b/htdocs/install/mysql/tables/llx_societe.sql index e28cf062224..b3464f9fc1f 100644 --- a/htdocs/install/mysql/tables/llx_societe.sql +++ b/htdocs/install/mysql/tables/llx_societe.sql @@ -70,6 +70,8 @@ create table llx_societe fournisseur tinyint DEFAULT 0, -- fournisseur 0/1 supplier_account varchar(32), -- compte client chez un fournisseur fk_prospectlevel varchar(12), -- prospect level (in llx_c_prospectlevel) + fk_incoterms integer, -- for incoterms + location_incoterms varchar(255), -- for incoterms customer_bad tinyint DEFAULT 0, -- mauvais payeur 0/1 customer_rate real DEFAULT 0, -- taux fiabilite client (0 a 1) supplier_rate real DEFAULT 0, -- taux fiabilite fournisseur (0 a 1) diff --git a/htdocs/install/mysql/tables/llx_societe_remise_except.key.sql b/htdocs/install/mysql/tables/llx_societe_remise_except.key.sql index 22f95455b31..0b66e7984d9 100644 --- a/htdocs/install/mysql/tables/llx_societe_remise_except.key.sql +++ b/htdocs/install/mysql/tables/llx_societe_remise_except.key.sql @@ -29,8 +29,8 @@ ALTER TABLE llx_societe_remise_except ADD INDEX idx_societe_remise_except_fk_fac ALTER TABLE llx_societe_remise_except ADD CONSTRAINT fk_societe_remise_fk_user FOREIGN KEY (fk_user) REFERENCES llx_user (rowid); -ALTER TABLE llx_societe_remise_except ADD CONSTRAINT fk_societe_remise_fk_soc FOREIGN KEY (fk_soc) REFERENCES llx_societe (rowid); -ALTER TABLE llx_societe_remise_except ADD CONSTRAINT fk_societe_remise_fk_facture_line FOREIGN KEY (fk_facture_line) REFERENCES llx_facturedet (rowid); +ALTER TABLE llx_societe_remise_except ADD CONSTRAINT fk_soc_remise_fk_soc FOREIGN KEY (fk_soc) REFERENCES llx_societe (rowid); +ALTER TABLE llx_societe_remise_except ADD CONSTRAINT fk_soc_remise_fk_facture_line FOREIGN KEY (fk_facture_line) REFERENCES llx_facturedet (rowid); ALTER TABLE llx_societe_remise_except ADD CONSTRAINT fk_societe_remise_fk_facture FOREIGN KEY (fk_facture) REFERENCES llx_facture (rowid); ALTER TABLE llx_societe_remise_except ADD CONSTRAINT fk_societe_remise_fk_facture_source FOREIGN KEY (fk_facture_source) REFERENCES llx_facture (rowid); diff --git a/htdocs/install/mysql/tables/llx_user.key.sql b/htdocs/install/mysql/tables/llx_user.key.sql index 897228a9c43..8232e7cacb7 100644 --- a/htdocs/install/mysql/tables/llx_user.key.sql +++ b/htdocs/install/mysql/tables/llx_user.key.sql @@ -21,7 +21,7 @@ ALTER TABLE llx_user ADD UNIQUE INDEX uk_user_login (login, entity); -ALTER TABLE llx_user ADD INDEX uk_user_fk_societe (fk_societe); +ALTER TABLE llx_user ADD INDEX uk_user_fk_societe (fk_soc); ALTER TABLE llx_user ADD UNIQUE INDEX uk_user_fk_socpeople (fk_socpeople); ALTER TABLE llx_user ADD UNIQUE INDEX uk_user_fk_member (fk_member); diff --git a/htdocs/install/mysql/tables/llx_user.sql b/htdocs/install/mysql/tables/llx_user.sql index 28385298125..a4c04f4e864 100644 --- a/htdocs/install/mysql/tables/llx_user.sql +++ b/htdocs/install/mysql/tables/llx_user.sql @@ -52,7 +52,7 @@ create table llx_user admin smallint DEFAULT 0, module_comm smallint DEFAULT 1, module_compta smallint DEFAULT 1, - fk_societe integer, + fk_soc integer, fk_socpeople integer, fk_member integer, fk_user integer, -- Hierarchic parent diff --git a/htdocs/install/pgsql/functions/functions.sql b/htdocs/install/pgsql/functions/functions.sql index 3bf5255a5fc..37d5630fbea 100644 --- a/htdocs/install/pgsql/functions/functions.sql +++ b/htdocs/install/pgsql/functions/functions.sql @@ -119,7 +119,7 @@ CREATE TRIGGER update_customer_modtime BEFORE UPDATE ON llx_user FOR EACH ROW EX CREATE TRIGGER update_customer_modtime BEFORE UPDATE ON llx_user_extrafields FOR EACH ROW EXECUTE PROCEDURE update_modified_column_tms(); CREATE TRIGGER update_customer_modtime BEFORE UPDATE ON llx_usergroup FOR EACH ROW EXECUTE PROCEDURE update_modified_column_tms(); CREATE TRIGGER update_customer_modtime BEFORE UPDATE ON llx_cronjob FOR EACH ROW EXECUTE PROCEDURE update_modified_column_tms(); -CREATE TRIGGER update_customer_modtime BEFORE UPDATE ON llx_printer_ipp FOR EACH ROW EXECUTE PROCEDURE update_modified_column_tms(); +CREATE TRIGGER update_customer_modtime BEFORE UPDATE ON llx_printing FOR EACH ROW EXECUTE PROCEDURE update_modified_column_tms(); CREATE OR REPLACE FUNCTION update_modified_column_date_m() RETURNS TRIGGER AS $$ BEGIN NEW.date_m = now(); RETURN NEW; END; $$ LANGUAGE plpgsql; CREATE TRIGGER update_customer_modtime BEFORE UPDATE ON llx_ecm_directories FOR EACH ROW EXECUTE PROCEDURE update_modified_column_date_m(); diff --git a/htdocs/install/upgrade2.php b/htdocs/install/upgrade2.php index e75b7d8389c..8d63f02ddc8 100644 --- a/htdocs/install/upgrade2.php +++ b/htdocs/install/upgrade2.php @@ -3391,7 +3391,7 @@ function migrate_mode_reglement($db,$langs,$conf) if ($resqla && $resql) { - foreach($elements['tables'] as $table) // FIXME We must not update tables if oldid is not renamed + foreach($elements['tables'] as $table) { $sql = "UPDATE ".MAIN_DB_PREFIX.$table." SET "; $sql.= "fk_mode_reglement = ".$elements['new_id'][$key]; diff --git a/htdocs/langs/en_US/admin.lang b/htdocs/langs/en_US/admin.lang index 3741d3ded66..5ca742f0816 100755 --- a/htdocs/langs/en_US/admin.lang +++ b/htdocs/langs/en_US/admin.lang @@ -297,10 +297,11 @@ MenuHandlers=Menu handlers MenuAdmin=Menu editor DoNotUseInProduction=Do not use in production ThisIsProcessToFollow=This is setup to process: +ThisIsAlternativeProcessToFollow=This is an alternative setup to process: StepNb=Step %s FindPackageFromWebSite=Find a package that provides feature you want (for example on official web site %s). DownloadPackageFromWebSite=Download package %s. -UnpackPackageInDolibarrRoot=Unpack package file into Dolibarr's root directory %s +UnpackPackageInDolibarrRoot=Unpack package file into directory dedicated to external modules: %s SetupIsReadyForUse=Install is finished and Dolibarr is ready to use with this new component. NotExistsDirect=The alternative root directory is not defined.
InfDirAlt=Since version 3 it is possible to define an alternative root directory.This allows you to store, same place, plug-ins and custom templates.
Just create a directory at the root of Dolibarr (eg: custom).
@@ -397,7 +398,7 @@ ExtrafieldParamHelpsellist=Parameters list comes from a table
Syntax : table_ ExtrafieldParamHelpchkbxlst=Parameters list comes from a table
Syntax : table_name:label_field:id_field::filter
Example : c_typent:libelle:id::filter

filter can be a simple test (eg active=1) to display only active value
if you want to filter on extrafields use syntaxt extra.fieldcode=... (where field code is the code of extrafield)

In order to have the list depending on another :
c_typent:libelle:id:parent_list_code|parent_column:filter LibraryToBuildPDF=Library used to build PDF WarningUsingFPDF=Warning: Your conf.php contains directive dolibarr_pdf_force_fpdf=1. This means you use the FPDF library to generate PDF files. This library is old and does not support a lot of features (Unicode, image transparency, cyrillic, arab and asiatic languages, ...), so you may experience errors during PDF generation.
To solve this and have a full support of PDF generation, please download TCPDF library, then comment or remove the line $dolibarr_pdf_force_fpdf=1, and add instead $dolibarr_lib_TCPDF_PATH='path_to_TCPDF_dir' -LocalTaxDesc=Some countries apply 2 or 3 taxes on each invoice line. If this is the case, choose type for second and third tax and its rate. Possible type are:
1 : local tax apply on products and services without vat (vat is not applied on local tax)
2 : local tax apply on products and services before vat (vat is calculated on amount + localtax)
3 : local tax apply on products without vat (vat is not applied on local tax)
4 : local tax apply on products before vat (vat is calculated on amount + localtax)
5 : local tax apply on services without vat (vat is not applied on local tax)
6 : local tax apply on services before vat (vat is calculated on amount + localtax) +LocalTaxDesc=Some countries apply 2 or 3 taxes on each invoice line. If this is the case, choose type for second and third tax and its rate. Possible type are:
1 : local tax apply on products and services without vat (localtax is calculated on amount without tax)
2 : local tax apply on products and services including vat (localtax is calculated on amount + main tax)
3 : local tax apply on products without vat (localtax is calculated on amount without tax)
4 : local tax apply on products including vat (vat is calculated on amount + main vat)
5 : local tax apply on services without vat (localtax is calculated on amount without tax)
6 : local tax apply on services including vat (localtax is calculated on amount + tax) SMS=SMS LinkToTestClickToDial=Enter a phone number to call to show a link to test the ClickToDial url for user %s RefreshPhoneLink=Refresh link @@ -540,8 +541,8 @@ Module6000Name=Workflow Module6000Desc=Workflow management Module20000Name=Leave Requests management Module20000Desc=Declare and follow employees leaves requests -Module39000Name=Product batch -Module39000Desc=Batch or serial number, eat-by and sell-by date management on products +Module39000Name=Product lot +Module39000Desc=Lot or serial number, eat-by and sell-by date management on products Module50000Name=PayBox Module50000Desc=Module to offer an online payment page by credit card with PayBox Module50100Name=Point of sales @@ -558,8 +559,6 @@ Module59000Name=Margins Module59000Desc=Module to manage margins Module60000Name=Commissions Module60000Desc=Module to manage commissions -Module150010Name=Batch number, eat-by date and sell-by date -Module150010Desc=batch number, eat-by date and sell-by date management for product Permission11=Read customer invoices Permission12=Create/modify customer invoices Permission13=Unvalidate customer invoices @@ -853,12 +852,12 @@ LocalTax2IsUsedDescES= The RE rate by default when creating prospects, invoices, LocalTax2IsNotUsedDescES= By default the proposed IRPF is 0. End of rule. LocalTax2IsUsedExampleES= In Spain, freelancers and independent professionals who provide services and companies who have chosen the tax system of modules. LocalTax2IsNotUsedExampleES= In Spain they are bussines not subject to tax system of modules. -CalcLocaltax=Reports -CalcLocaltax1ES=Sales - Purchases +CalcLocaltax=Reports on local taxes +CalcLocaltax1=Sales - Purchases CalcLocaltax1Desc=Local Taxes reports are calculated with the difference between localtaxes sales and localtaxes purchases -CalcLocaltax2ES=Purchases +CalcLocaltax2=Purchases CalcLocaltax2Desc=Local Taxes reports are the total of localtaxes purchases -CalcLocaltax3ES=Sales +CalcLocaltax3=Sales CalcLocaltax3Desc=Local Taxes reports are the total of localtaxes sales LabelUsedByDefault=Label used by default if no translation can be found for code LabelOnDocuments=Label on documents @@ -1018,14 +1017,14 @@ NoEventOrNoAuditSetup=No security event has been recorded yet. This can be norma NoEventFoundWithCriteria=No security event has been found for such search criterias. SeeLocalSendMailSetup=See your local sendmail setup BackupDesc=To make a complete backup of Dolibarr, you must: -BackupDesc2=* Save content of documents directory (%s) that contains all uploaded and generated files (you can make a zip for example). -BackupDesc3=* Save content of your database into a dump file. For this, you can use following assistant. +BackupDesc2=Save content of documents directory (%s) that contains all uploaded and generated files (you can make a zip for example). +BackupDesc3=Save content of your database (%s) into a dump file. For this, you can use following assistant. BackupDescX=Archived directory should be stored in a secure place. BackupDescY=The generated dump file should be stored in a secure place. BackupPHPWarning=Backup can't be guaranted with this method. Prefer previous one RestoreDesc=To restore a Dolibarr backup, you must: -RestoreDesc2=* Restore archive file (zip file for example) of documents directory to extract tree of files in documents directory of a new Dolibarr installation or into this current documents directoy (%s). -RestoreDesc3=* Restore the data, from a backup dump file, into the database of the new Dolibarr installation or into the database of this current installation. Warning, once restore is finished, you must use a login/password, that existed when backup was made, to connect again. To restore a backup database into this current installation, you can follow this assistant. +RestoreDesc2=Restore archive file (zip file for example) of documents directory to extract tree of files in documents directory of a new Dolibarr installation or into this current documents directoy (%s). +RestoreDesc3=Restore the data, from a backup dump file, into the database of the new Dolibarr installation or into the database of this current installation (%s). Warning, once restore is finished, you must use a login/password, that existed when backup was made, to connect again. To restore a backup database into this current installation, you can follow this assistant. RestoreMySQL=MySQL import ForcedToByAModule= This rule is forced to %s by an activated module PreviousDumpFiles=Available database backup dump files @@ -1078,7 +1077,7 @@ TotalNumberOfActivatedModules=Total number of activated feature modules: %s 100 000), you can increase speed by setting constant PRODUCT_DONOTSEARCH_ANYWHERE to 1 in Setup->Other. Search will then be limited to start of string. UseSearchToSelectProduct=Use a search form to choose a product (rather than a drop-down list). @@ -1541,7 +1543,7 @@ CashDeskBankAccountForCB= Default account to use to receive payments by credit c CashDeskDoNotDecreaseStock=Disable stock decrease when a sell is done from Point of Sale (if "no", stock decrease is done for each sell done from POS, whatever is option set into module Stock). CashDeskIdWareHouse=Force and restrict warehouse to use for stock decrease StockDecreaseForPointOfSaleDisabled=Stock decrease from Point Of Sale disabled -StockDecreaseForPointOfSaleDisabledbyBatch=Stock decrease in POS is not compatible with batch management +StockDecreaseForPointOfSaleDisabledbyBatch=Stock decrease in POS is not compatible with lot management CashDeskYouDidNotDisableStockDecease=You did not disable stock decrease when making a sell from Point Of Sale. So a warehouse is required. ##### Bookmark ##### BookmarkSetup=Bookmark module setup @@ -1594,7 +1596,7 @@ OpenFiscalYear=Open fiscal year CloseFiscalYear=Close fiscal year DeleteFiscalYear=Delete fiscal year ConfirmDeleteFiscalYear=Are you sure to delete this fiscal year ? -Opened=Opened +Opened=Open Closed=Closed AlwaysEditable=Can always be edited MAIN_APPLICATION_TITLE=Force visible name of application (warning: setting your own name here may break autofill login feature when using DoliDroid mobile application) @@ -1617,3 +1619,8 @@ ListOfNotificationsPerContact=List of notifications per contact* ListOfFixedNotifications=List of fixed notifications GoOntoContactCardToAddMore=Go on the tab "Notifications" of a thirdparty contact to add or remove notifications for contacts/addresses Threshold=Threshold +BackupDumpWizard=Wizard to build database backup dump file +SomethingMakeInstallFromWebNotPossible=Installation of external module is not possible from the web interface for the following reason: +SomethingMakeInstallFromWebNotPossible2=For this reason, process to upgrade described here is only manual steps a privileged user can do. +InstallModuleFromWebHasBeenDisabledByFile=Install of external module from application has been disabled by your administrator. You must ask him to remove the file %s to allow this feature. +ConfFileMuseContainCustom=Installing an external module from application save the module files into directory %s. To have this directory processed by Dolibarr, you must setup your conf/conf.php to have option
- $dolibarr_main_url_root_alt enabled to value $dolibarr_main_url_root_alt="/custom"
- $dolibarr_main_document_root_alt enabled to value "%s/custom" diff --git a/htdocs/langs/en_US/agenda.lang b/htdocs/langs/en_US/agenda.lang index 87a22582431..dd485291e73 100644 --- a/htdocs/langs/en_US/agenda.lang +++ b/htdocs/langs/en_US/agenda.lang @@ -55,7 +55,6 @@ OrderBilledInDolibarr=Order %s classified billed OrderApprovedInDolibarr=Order %s approved OrderRefusedInDolibarr=Order %s refused OrderBackToDraftInDolibarr=Order %s go back to draft status -OrderCanceledInDolibarr=Order %s canceled ProposalSentByEMail=Commercial proposal %s sent by EMail OrderSentByEMail=Customer order %s sent by EMail InvoiceSentByEMail=Customer invoice %s sent by EMail diff --git a/htdocs/langs/en_US/askpricesupplier.lang b/htdocs/langs/en_US/askpricesupplier.lang index b75a3284146..882b2fc2290 100644 --- a/htdocs/langs/en_US/askpricesupplier.lang +++ b/htdocs/langs/en_US/askpricesupplier.lang @@ -9,7 +9,7 @@ CommRequests=Price requests SearchRequest=Find a request DraftRequests=Draft requests LastModifiedRequests=Last %s modified price requests -RequestsOpened=Opened price requests +RequestsOpened=Open price requests AskPriceSupplierArea=Area price requests suppliers Askpricesupplier=Price request supplier NewAskPrice=New price request @@ -26,7 +26,7 @@ DeleteAsk=Delete request ValidateAsk=Validate request AddAsk=Create a request AskpricesupplierDraft=Drafts -AskpricesupplierOpened=Opened +AskpricesupplierOpened=Open AskpricesupplierStatusDraft=Draft (needs to be validated) AskpricesupplierStatusValidated=Validated (request is open) AskpricesupplierStatusOpened=Validated (request is open) @@ -35,7 +35,7 @@ AskpricesupplierStatusSigned=Accepted AskpricesupplierStatusNotSigned=Refused AskpricesupplierStatusDraftShort=Draft AskpricesupplierStatusValidatedShort=Validated -AskpricesupplierStatusOpenedShort=Opened +AskpricesupplierStatusOpenedShort=Open AskpricesupplierStatusClosedShort=Closed AskpricesupplierStatusSignedShort=Accepted AskpricesupplierStatusNotSignedShort=Refused @@ -54,4 +54,4 @@ CommercialAsk=Price request DefaultModelAskPriceSupplierCreate=Default model creation DefaultModelAskPriceSupplierToBill=Default template when closing a price request (accepted) DefaultModelAskPriceSupplierClosed=Default template when closing a price request (refused) -ListOfAskPriceSupplier=Liste des demandes de prix fournisseurs \ No newline at end of file +ListOfAskPriceSupplier=Liste des demandes de prix fournisseurs diff --git a/htdocs/langs/en_US/banks.lang b/htdocs/langs/en_US/banks.lang index a2306950fb4..f363ffa56c6 100644 --- a/htdocs/langs/en_US/banks.lang +++ b/htdocs/langs/en_US/banks.lang @@ -94,12 +94,12 @@ Conciliate=Reconcile Conciliation=Reconciliation ConciliationForAccount=Reconcile this account IncludeClosedAccount=Include closed accounts -OnlyOpenedAccount=Only opened accounts +OnlyOpenedAccount=Only open accounts AccountToCredit=Account to credit AccountToDebit=Account to debit DisableConciliation=Disable reconciliation feature for this account ConciliationDisabled=Reconciliation feature disabled -StatusAccountOpened=Opened +StatusAccountOpened=Open StatusAccountClosed=Closed AccountIdShort=Number EditBankRecord=Edit record @@ -163,3 +163,5 @@ LabelRIB=BAN Label NoBANRecord=No BAN record DeleteARib=Delete BAN record ConfirmDeleteRib=Are you sure you want to delete this BAN record ? +StartDate=Start date +EndDate=End date diff --git a/htdocs/langs/en_US/bills.lang b/htdocs/langs/en_US/bills.lang index ac8e6da082b..3e645e84834 100644 --- a/htdocs/langs/en_US/bills.lang +++ b/htdocs/langs/en_US/bills.lang @@ -298,6 +298,7 @@ RelatedCustomerInvoices=Related customer invoices RelatedSupplierInvoices=Related supplier invoices LatestRelatedBill=Latest related invoice WarningBillExist=Warning, one or more invoice already exist +MergingPDFTool=Merging PDF tool # PaymentConditions PaymentConditionShortRECEP=Immediate @@ -429,5 +430,5 @@ NotLastInCycle=This invoice in not the last in cycle and must not be modified. DisabledBecauseNotLastInCycle=The next situation already exists. DisabledBecauseFinal=This situation is final. CantBeLessThanMinPercent=The progress can't be smaller than its value in the previous situation. -NoSituations=No opened situations +NoSituations=No open situations InvoiceSituationLast=Final and general invoice diff --git a/htdocs/langs/en_US/boxes.lang b/htdocs/langs/en_US/boxes.lang index bf118b9b88e..b61cf77019f 100644 --- a/htdocs/langs/en_US/boxes.lang +++ b/htdocs/langs/en_US/boxes.lang @@ -19,7 +19,7 @@ BoxLastContracts=Last contracts BoxLastContacts=Last contacts/addresses BoxLastMembers=Last members BoxFicheInter=Last interventions -BoxCurrentAccounts=Opened accounts balance +BoxCurrentAccounts=Open accounts balance BoxSalesTurnover=Sales turnover BoxTotalUnpaidCustomerBills=Total unpaid customer's invoices BoxTotalUnpaidSuppliersBills=Total unpaid supplier's invoices @@ -47,7 +47,7 @@ BoxTitleLastModifiedMembers=Last %s members BoxTitleLastFicheInter=Last %s modified intervention BoxTitleOldestUnpaidCustomerBills=Oldest %s unpaid customer invoices BoxTitleOldestUnpaidSupplierBills=Oldest %s unpaid supplier invoices -BoxTitleCurrentAccounts=Opened account's balances +BoxTitleCurrentAccounts=Open accounts balances BoxTitleSalesTurnover=Sales turnover BoxTitleTotalUnpaidCustomerBills=Unpaid customer invoices BoxTitleTotalUnpaidSuppliersBills=Unpaid supplier invoices @@ -94,3 +94,4 @@ BoxProductDistributionFor=Distribution of %s for %s ForCustomersInvoices=Customers invoices ForCustomersOrders=Customers orders ForProposals=Proposals +LastXMonthRolling=The last %s month rolling diff --git a/htdocs/langs/en_US/categories.lang b/htdocs/langs/en_US/categories.lang index 11b1dc8eac0..a73526ca08a 100644 --- a/htdocs/langs/en_US/categories.lang +++ b/htdocs/langs/en_US/categories.lang @@ -42,19 +42,19 @@ ImpossibleAddCat=Impossible to add the tag/category ImpossibleAssociateCategory=Impossible to associate the tag/category to WasAddedSuccessfully=%s was added successfully. ObjectAlreadyLinkedToCategory=Element is already linked to this tag/category. -CategorySuccessfullyCreated=This tag/category %s has been added with success. -ProductIsInCategories=Product/service owns to following tags/categories -SupplierIsInCategories=Third party owns to following suppliers tags/categories -CompanyIsInCustomersCategories=This third party owns to following customers/prospects tags/categories -CompanyIsInSuppliersCategories=This third party owns to following suppliers tags/categories -MemberIsInCategories=This member owns to following members tags/categories -ContactIsInCategories=This contact owns to following contacts tags/categories +CategorySuccessfullyCreated=This tag/category %s has been added successfully. +ProductIsInCategories=Product/service is linked to following tags/categories +SupplierIsInCategories=Third party is linked to following suppliers tags/categories +CompanyIsInCustomersCategories=This third party is linked to following customers/prospects tags/categories +CompanyIsInSuppliersCategories=This third party is linked to following suppliers tags/categories +MemberIsInCategories=This member is linked to following members tags/categories +ContactIsInCategories=This contact is linked to following contacts tags/categories ProductHasNoCategory=This product/service is not in any tags/categories SupplierHasNoCategory=This supplier is not in any tags/categories CompanyHasNoCategory=This company is not in any tags/categories MemberHasNoCategory=This member is not in any tags/categories ContactHasNoCategory=This contact is not in any tags/categories -ClassifyInCategory=Classify in tag/category +ClassifyInCategory=Add to tag/category NoneCategory=None NotCategorized=Without tag/category CategoryExistsAtSameLevel=This category already exists with this ref @@ -67,13 +67,13 @@ ContentsNotVisibleByAllShort=Contents not visible by all CategoriesTree=Tags/categories tree DeleteCategory=Delete tag/category ConfirmDeleteCategory=Are you sure you want to delete this tag/category ? -RemoveFromCategory=Remove link with tag/categorie -RemoveFromCategoryConfirm=Are you sure you want to remove link between the transaction and the tag/category ? +RemoveFromCategory=Remove link with tag/category +RemoveFromCategoryConfirm=Are you sure you want to unlink the transaction from the tag/category ? NoCategoriesDefined=No tag/category defined -SuppliersCategoryShort=Suppliers tags/category -CustomersCategoryShort=Customers tags/category -ProductsCategoryShort=Products tags/category -MembersCategoryShort=Members tags/category +SuppliersCategoryShort=Suppliers tag/category +CustomersCategoryShort=Customers tag/category +ProductsCategoryShort=Products tag/category +MembersCategoryShort=Members tag/category SuppliersCategoriesShort=Suppliers tags/categories CustomersCategoriesShort=Customers tags/categories CustomersProspectsCategoriesShort=Custo./Prosp. categories @@ -107,4 +107,4 @@ CategoriesSetup=Tags/categories setup CategorieRecursiv=Link with parent tag/category automatically CategorieRecursivHelp=If activated, product will also linked to parent category when adding into a subcategory AddProductServiceIntoCategory=Add the following product/service -ShowCategory=Show tag/category \ No newline at end of file +ShowCategory=Show tag/category diff --git a/htdocs/langs/en_US/companies.lang b/htdocs/langs/en_US/companies.lang index 7bfaf799f3a..e700271368d 100644 --- a/htdocs/langs/en_US/companies.lang +++ b/htdocs/langs/en_US/companies.lang @@ -411,4 +411,9 @@ MonkeyNumRefModelDesc=Return numero with format %syymm-nnnn for customer code an LeopardNumRefModelDesc=The code is free. This code can be modified at any time. ManagingDirectors=Manager(s) name (CEO, director, president...) SearchThirdparty=Search thirdparty -SearchContact=Search contact \ No newline at end of file +SearchContact=Search contact +MergeOriginThirdparty=Origin thirdparty +MergeThirdparties=Merge thirdparties +ConfirmMergeThirdparties=Are you sure you want to merge this thirdparty? All linked objects (invoices...) will be linked with the destination thirdparty +ThirdpartiesMergeSuccess=Thirdparties have been merged +ErrorThirdpartiesMerge=There was an error when deleting the thirdparties. Please check the log. Changes have been reverted. \ No newline at end of file diff --git a/htdocs/langs/en_US/cron.lang b/htdocs/langs/en_US/cron.lang index cf5e1a6198c..5d7abf732ab 100644 --- a/htdocs/langs/en_US/cron.lang +++ b/htdocs/langs/en_US/cron.lang @@ -26,11 +26,11 @@ CronLastOutput=Last run output CronLastResult=Last result code CronListOfCronJobs=List of scheduled jobs CronCommand=Command -CronList=Scheduled job +CronList=Scheduled jobs CronDelete=Delete scheduled jobs -CronConfirmDelete=Are you sure you want to delete this scheduled jobs ? +CronConfirmDelete=Are you sure you want to delete these scheduled jobs ? CronExecute=Launch scheduled jobs -CronConfirmExecute=Are you sure to execute this scheduled jobs now ? +CronConfirmExecute=Are you sure you want to execute these scheduled jobs now ? CronInfo=Scheduled job module allow to execute job that have been planned CronWaitingJobs=Waiting jobs CronTask=Job @@ -39,8 +39,8 @@ CronDtStart=Start date CronDtEnd=End date CronDtNextLaunch=Next execution CronDtLastLaunch=Last execution -CronFrequency=Frequancy -CronClass=Classe +CronFrequency=Frequency +CronClass=Class CronMethod=Method CronModule=Module CronAction=Action @@ -55,7 +55,7 @@ CronEach=Every JobFinished=Job launched and finished #Page card CronAdd= Add jobs -CronHourStart= Start Hour and date of task +CronHourStart= Start hour and date of task CronEvery= And execute task each CronObject= Instance/Object to create CronArgs=Parameters @@ -79,10 +79,10 @@ CronCreateJob=Create new Scheduled Job # Info CronInfoPage=Information # Common -CronType=Task type +CronType=Job type CronType_method=Call method of a Dolibarr Class CronType_command=Shell command CronMenu=Cron CronCannotLoadClass=Cannot load class %s or object %s UseMenuModuleToolsToAddCronJobs=Go into menu "Home - Modules tools - Job list" to see and edit scheduled jobs. -TaskDisabled=Task disabled +TaskDisabled=Job disabled diff --git a/htdocs/langs/en_US/errors.lang b/htdocs/langs/en_US/errors.lang index 37670b7f003..4266107d8a3 100755 --- a/htdocs/langs/en_US/errors.lang +++ b/htdocs/langs/en_US/errors.lang @@ -159,14 +159,17 @@ ErrorPriceExpression22=Negative result '%s' ErrorPriceExpressionInternal=Internal error '%s' ErrorPriceExpressionUnknown=Unknown error '%s' ErrorSrcAndTargetWarehouseMustDiffers=Source and target warehouses must differs -ErrorTryToMakeMoveOnProductRequiringBatchData=Error, trying to make a stock movement without batch/serial information, on a product requiring batch/serial information -ErrorCantSetReceptionToTotalDoneWithReceptionToApprove=All recorded receptions must first be verified before being allowed to do this action +ErrorTryToMakeMoveOnProductRequiringBatchData=Error, trying to make a stock movement without lot/serial information, on a product requiring lot/serial information +ErrorCantSetReceptionToTotalDoneWithReceptionToApprove=All recorded receptions must first be verified (approved or denied) before being allowed to do this action +ErrorCantSetReceptionToTotalDoneWithReceptionDenied=All recorded receptions must first be verified (approved) before being allowed to do this action ErrorGlobalVariableUpdater0=HTTP request failed with error '%s' ErrorGlobalVariableUpdater1=Invalid JSON format '%s' ErrorGlobalVariableUpdater2=Missing parameter '%s' ErrorGlobalVariableUpdater3=The requested data was not found in result ErrorGlobalVariableUpdater4=SOAP client failed with error '%s' ErrorGlobalVariableUpdater5=No global variable selected +ErrorFieldMustBeANumeric=Field %s must be a numeric value +ErrorFieldMustBeAnInteger=Field %s must be an integer # Warnings WarningMandatorySetupNotComplete=Mandatory setup parameters are not yet defined diff --git a/htdocs/langs/en_US/interventions.lang b/htdocs/langs/en_US/interventions.lang index c79da05364e..67d4f61d9f1 100644 --- a/htdocs/langs/en_US/interventions.lang +++ b/htdocs/langs/en_US/interventions.lang @@ -50,4 +50,4 @@ ArcticNumRefModelError=Failed to activate PacificNumRefModelDesc1=Return numero with format %syymm-nnnn where yy is year, mm is month and nnnn is a sequence with no break and no return to 0 PacificNumRefModelError=An intervention card starting with $syymm already exists and is not compatible with this model of sequence. Remove it or rename it to activate this module. PrintProductsOnFichinter=Print products on intervention card -PrintProductsOnFichinterDetails=forinterventions generated from orders +PrintProductsOnFichinterDetails=interventions generated from orders diff --git a/htdocs/langs/en_US/main.lang b/htdocs/langs/en_US/main.lang index bd2112cf871..7ef4c291d2a 100644 --- a/htdocs/langs/en_US/main.lang +++ b/htdocs/langs/en_US/main.lang @@ -220,6 +220,7 @@ Next=Next Cards=Cards Card=Card Now=Now +HourStart=Start hour Date=Date DateAndHour=Date and hour DateStart=Date start @@ -300,7 +301,7 @@ UnitPriceHT=Unit price (net) UnitPriceTTC=Unit price PriceU=U.P. PriceUHT=U.P. (net) -AskPriceSupplierUHT=P.U. HT Requested +AskPriceSupplierUHT=U.P. net Requested PriceUTTC=U.P. Amount=Amount AmountInvoice=Invoice amount @@ -420,7 +421,7 @@ Reportings=Reporting Draft=Draft Drafts=Drafts Validated=Validated -Opened=Opened +Opened=Open New=New Discount=Discount Unknown=Unknown @@ -700,6 +701,8 @@ SelectElementAndClickRefresh=Select an element and click Refresh PrintFile=Print File %s ShowTransaction=Show transaction GoIntoSetupToChangeLogo=Go into Home - Setup - Company to change logo or go into Home - Setup - Display to hide. +Deny=Deny +Denied=Denied # Week day Monday=Monday Tuesday=Tuesday @@ -729,3 +732,4 @@ ShortThursday=T ShortFriday=F ShortSaturday=S ShortSunday=S +SelectMailModel=Select email template diff --git a/htdocs/langs/en_US/orders.lang b/htdocs/langs/en_US/orders.lang index 278fb39f0ee..7f2902a96e6 100644 --- a/htdocs/langs/en_US/orders.lang +++ b/htdocs/langs/en_US/orders.lang @@ -16,14 +16,14 @@ SupplierOrder=Supplier order SuppliersOrders=Suppliers orders SuppliersOrdersRunning=Current suppliers orders CustomerOrder=Customer order -CustomersOrders=Customers orders -CustomersOrdersRunning=Current customer's orders -CustomersOrdersAndOrdersLines=Customer orders and order's lines -OrdersToValid=Customers orders to validate -OrdersToBill=Customers orders delivered -OrdersInProcess=Customers orders in process -OrdersToProcess=Customers orders to process -SuppliersOrdersToProcess=Supplier's orders to process +CustomersOrders=Customer orders +CustomersOrdersRunning=Current customer orders +CustomersOrdersAndOrdersLines=Customer orders and order lines +OrdersToValid=Customer orders to validate +OrdersToBill=Customer orders delivered +OrdersInProcess=Customer orders in process +OrdersToProcess=Customer orders to process +SuppliersOrdersToProcess=Supplier orders to process StatusOrderCanceledShort=Canceled StatusOrderDraftShort=Draft StatusOrderValidatedShort=Validated @@ -75,11 +75,13 @@ AddToMyOrders=Add to my orders AddToOtherOrders=Add to other orders AddToDraftOrders=Add to draft order ShowOrder=Show order -NoOpenedOrders=No opened orders -NoOtherOpenedOrders=No other opened orders +NoOpenedOrders=No open orders +NoOtherOpenedOrders=No other open orders NoDraftOrders=No draft orders OtherOrders=Other orders -LastOrders=Last %s orders +LastOrders=Last %s customer orders +LastCustomerOrders=Last %s customer orders +LastSupplierOrders=Last %s supplier orders LastModifiedOrders=Last %s modified orders LastClosedOrders=Last %s closed orders AllOrders=All orders diff --git a/htdocs/langs/en_US/other.lang b/htdocs/langs/en_US/other.lang index e3de07b3d5d..5cb000408da 100644 --- a/htdocs/langs/en_US/other.lang +++ b/htdocs/langs/en_US/other.lang @@ -203,6 +203,7 @@ NewKeyWillBe=Your new key to login to software will be ClickHereToGoTo=Click here to go to %s YouMustClickToChange=You must however first click on the following link to validate this password change ForgetIfNothing=If you didn't request this change, just forget this email. Your credentials are kept safe. +IfAmountHigherThan=If amount higher than %s ##### Calendar common ##### AddCalendarEntry=Add entry in calendar %s diff --git a/htdocs/langs/en_US/printing.lang b/htdocs/langs/en_US/printing.lang index f0cd2a40292..d86e998cf50 100644 --- a/htdocs/langs/en_US/printing.lang +++ b/htdocs/langs/en_US/printing.lang @@ -49,7 +49,6 @@ PRINTIPP_PORT=Port PRINTIPP_USER=Login PRINTIPP_PASSWORD=Password NoPrinterFound=No printers found (check your CUPS setup) -FileWasSentToPrinter=File %s was sent to printer NoDefaultPrinterDefined=No default printer defined DefaultPrinter=Default printer Printer=Printer diff --git a/htdocs/langs/en_US/productbatch.lang b/htdocs/langs/en_US/productbatch.lang index 45263681965..37ceaa49b38 100644 --- a/htdocs/langs/en_US/productbatch.lang +++ b/htdocs/langs/en_US/productbatch.lang @@ -1,21 +1,22 @@ # ProductBATCH language file - en_US - ProductBATCH -ManageLotSerial=Use batch/serial number -ProductStatusOnBatch=Yes (Batch/serial required) -ProductStatusNotOnBatch=No (Batch/serial not used) +ManageLotSerial=Use lot/serial number +ProductStatusOnBatch=Yes (lot/serial required) +ProductStatusNotOnBatch=No (lot/serial not used) ProductStatusOnBatchShort=Yes ProductStatusNotOnBatchShort=No -Batch=Batch/Serial -atleast1batchfield=Eat-by date or Sell-by date or Batch number -batch_number=Batch/Serial number +Batch=Lot/Serial +atleast1batchfield=Eat-by date or Sell-by date or Lot/Serial number +batch_number=Lot/Serial number +BatchNumberShort=Lot/Serial l_eatby=Eat-by date l_sellby=Sell-by date -DetailBatchNumber=Batch/Serial details -DetailBatchFormat=Batch/Serial: %s - Eat by: %s - Sell by: %s (Qty : %d) -printBatch=Batch: %s +DetailBatchNumber=Lot/Serial details +DetailBatchFormat=Lot/Serial: %s - Eat by: %s - Sell by: %s (Qty : %d) +printBatch=Lot/Serial: %s printEatby=Eat-by: %s printSellby=Sell-by: %s printQty=Qty: %d AddDispatchBatchLine=Add a line for Shelf Life dispatching BatchDefaultNumber=Undefined -WhenProductBatchModuleOnOptionAreForced=When module Batch/Serial is on, increase/decrease stock mode is forced to last choice and can't be edited. Other options can be defined as you want. -ProductDoesNotUseBatchSerial=This product does not use batch/serial number +WhenProductBatchModuleOnOptionAreForced=When module Lot/Serial is on, increase/decrease stock mode is forced to last choice and can't be edited. Other options can be defined as you want. +ProductDoesNotUseBatchSerial=This product does not use lot/serial number diff --git a/htdocs/langs/en_US/products.lang b/htdocs/langs/en_US/products.lang index 7d48bbc1a19..8ad095f4169 100644 --- a/htdocs/langs/en_US/products.lang +++ b/htdocs/langs/en_US/products.lang @@ -23,14 +23,14 @@ ProductOrService=Product or Service ProductsAndServices=Products and Services ProductsOrServices=Products or Services ProductsAndServicesOnSell=Products and Services for sale or for purchase -ProductsAndServicesNotOnSell=Products and Services out of sale +ProductsAndServicesNotOnSell=Products and Services not for sale ProductsAndServicesStatistics=Products and Services statistics ProductsStatistics=Products statistics -ProductsOnSell=Product for sale or for pruchase -ProductsNotOnSell=Product out of sale and out of purchase +ProductsOnSell=Product for sale or for purchase +ProductsNotOnSell=Product not for sale and not for purchase ProductsOnSellAndOnBuy=Products for sale and for purchase ServicesOnSell=Services for sale or for purchase -ServicesNotOnSell=Services out of sale +ServicesNotOnSell=Services not for sale ServicesOnSellAndOnBuy=Services for sale and for purchase InternalRef=Internal reference LastRecorded=Last products/services on sell recorded @@ -44,7 +44,7 @@ CardProduct1=Service card CardContract=Contract card Warehouse=Warehouse Warehouses=Warehouses -WarehouseOpened=Warehouse opened +WarehouseOpened=Warehouse open WarehouseClosed=Warehouse closed Stock=Stock Stocks=Stocks @@ -71,21 +71,21 @@ SellingPriceTTC=Selling price (inc. tax) PublicPrice=Public price CurrentPrice=Current price NewPrice=New price -MinPrice=Minim. selling price -MinPriceHT=Minim. selling price (net of tax) -MinPriceTTC=Minim. selling price (inc. tax) +MinPrice=Min. selling price +MinPriceHT=Min. selling price (net of tax) +MinPriceTTC=Min. selling price (inc. tax) CantBeLessThanMinPrice=The selling price can't be lower than minimum allowed for this product (%s without tax). This message can also appears if you type a too important discount. ContractStatus=Contract status ContractStatusClosed=Closed -ContractStatusRunning=Running +ContractStatusRunning=Ongoing ContractStatusExpired=expired -ContractStatusOnHold=Not running -ContractStatusToRun=To get running -ContractNotRunning=This contract is not running +ContractStatusOnHold=On hold +ContractStatusToRun=Make ongoing +ContractNotRunning=This contract is not ongoing ErrorProductAlreadyExists=A product with reference %s already exists. ErrorProductBadRefOrLabel=Wrong value for reference or label. ErrorProductClone=There was a problem while trying to clone the product or service. -ErrorPriceCantBeLowerThanMinPrice=Error Price Can't Be Lower Than Minimum Price. +ErrorPriceCantBeLowerThanMinPrice=Error, price can't be lower than minimum price. Suppliers=Suppliers SupplierRef=Supplier's product ref. ShowProduct=Show product @@ -117,12 +117,12 @@ ServiceLimitedDuration=If product is a service with limited duration: MultiPricesAbility=Several level of prices per product/service MultiPricesNumPrices=Number of prices MultiPriceLevelsName=Price categories -AssociatedProductsAbility=Activate the virtual package feature +AssociatedProductsAbility=Activate the package feature AssociatedProducts=Package product -AssociatedProductsNumber=Number of products composing this virtual package product +AssociatedProductsNumber=Number of products composing this package product ParentProductsNumber=Number of parent packaging product -IfZeroItIsNotAVirtualProduct=If 0, this product is not a virtual package product -IfZeroItIsNotUsedByVirtualProduct=If 0, this product is not used by any virtual package product +IfZeroItIsNotAVirtualProduct=If 0, this product is not a package product +IfZeroItIsNotUsedByVirtualProduct=If 0, this product is not used by any package product EditAssociate=Associate Translation=Translation KeywordFilter=Keyword filter @@ -179,12 +179,12 @@ CloneProduct=Clone product or service ConfirmCloneProduct=Are you sure you want to clone product or service %s ? CloneContentProduct=Clone all main informations of product/service ClonePricesProduct=Clone main informations and prices -CloneCompositionProduct=Clone packaged product/services +CloneCompositionProduct=Clone packaged product/service ProductIsUsed=This product is used NewRefForClone=Ref. of new product/service -CustomerPrices=Customers prices -SuppliersPrices=Suppliers prices -SuppliersPricesOfProductsOrServices=Suppliers prices (of products or services) +CustomerPrices=Customer prices +SuppliersPrices=Supplier prices +SuppliersPricesOfProductsOrServices=Supplier prices (of products or services) CustomCode=Customs code CountryOrigin=Origin country HiddenIntoCombo=Hidden into select lists @@ -240,7 +240,7 @@ CostPmpHT=Net total VWAP ProductUsedForBuild=Auto consumed by production ProductBuilded=Production completed ProductsMultiPrice=Product multi-price -ProductsOrServiceMultiPrice=Customers prices (of products or services, multi-prices) +ProductsOrServiceMultiPrice=Customer prices (of products or services, multi-prices) ProductSellByQuarterHT=Products turnover quarterly VWAP ServiceSellByQuarterHT=Services turnover quarterly VWAP Quarter1=1st. Quarter @@ -263,10 +263,10 @@ ResetBarcodeForAllRecords=Define barcode value for all records (this will also r PriceByCustomer=Different price for each customer PriceCatalogue=Unique price per product/service PricingRule=Rules for customer prices -AddCustomerPrice=Add price by customers +AddCustomerPrice=Add price by customer ForceUpdateChildPriceSoc=Set same price on customer subsidiaries PriceByCustomerLog=Price by customer log -MinimumPriceLimit=Minimum price can't be lower that %s +MinimumPriceLimit=Minimum price can't be lower then %s MinimumRecommendedPrice=Minimum recommended price is : %s PriceExpressionEditor=Price expression editor PriceExpressionSelected=Selected price expression @@ -292,4 +292,6 @@ GlobalVariableUpdaterHelp1=Parses WebService data from specified URL, NS specifi GlobalVariableUpdaterHelpFormat1=format is {"URL": "http://example.com/urlofws", "VALUE": "array,targetvalue", "NS": "http://example.com/urlofns", "METHOD": "myWSMethod", "DATA": {"your": "data, "to": "send"}} UpdateInterval=Update interval (minutes) LastUpdated=Last updated -CorrectlyUpdated=Correctly updated \ No newline at end of file +CorrectlyUpdated=Correctly updated +PropalMergePdfProductActualFile=Files use to add into PDF Azur are/is +PropalMergePdfProductChooseFile=Select PDF files diff --git a/htdocs/langs/en_US/projects.lang b/htdocs/langs/en_US/projects.lang index 40b1c2e308d..dde2aa7d469 100644 --- a/htdocs/langs/en_US/projects.lang +++ b/htdocs/langs/en_US/projects.lang @@ -11,9 +11,10 @@ ProjectsPublicDesc=This view presents all projects you are allowed to read. ProjectsPublicTaskDesc=This view presents all projects and tasks you are allowed to read. ProjectsDesc=This view presents all projects (your user permissions grant you permission to view everything). MyTasksDesc=This view is limited to projects or tasks you are a contact for (whatever is the type). -OnlyOpenedProject=Only opened projects are visible (projects with draft or closed status are not visible). +OnlyOpenedProject=Only open projects are visible (projects in draft or closed status are not visible). TasksPublicDesc=This view presents all projects and tasks you are allowed to read. TasksDesc=This view presents all projects and tasks (your user permissions grant you permission to view everything). +AllTaskVisibleButEditIfYouAreAssigned=All tasks for such project are visible, but you can enter time only for task you are assigned on. ProjectsArea=Projects area NewProject=New project AddProject=Create project @@ -28,7 +29,7 @@ ProjectsList=List of projects ShowProject=Show project SetProject=Set project NoProject=No project defined or owned -NbOpenTasks=Nb of opened tasks +NbOpenTasks=Nb of open tasks NbOfProjects=Nb of projects TimeSpent=Time spent TimeSpentByYou=Time spent by you @@ -40,7 +41,7 @@ TaskTimeSpent=Time spent on tasks TaskTimeUser=User TaskTimeNote=Note TaskTimeDate=Date -TasksOnOpenedProject=Tasks on opened projects +TasksOnOpenedProject=Tasks on open projects WorkloadNotDefined=Workload not defined NewTimeSpent=New time spent MyTimeSpent=My time spent @@ -94,7 +95,7 @@ DeleteATimeSpent=Delete time spent ConfirmDeleteATimeSpent=Are you sure you want to delete this time spent ? DoNotShowMyTasksOnly=See also tasks not assigned to me ShowMyTasksOnly=View only tasks assigned to me -TaskRessourceLinks=Ressources +TaskRessourceLinks=Resources ProjectsDedicatedToThisThirdParty=Projects dedicated to this third party NoTasks=No tasks for this project LinkedToAnotherCompany=Linked to other third party @@ -138,7 +139,7 @@ ProjectReferers=Refering objects SearchAProject=Search a project ProjectMustBeValidatedFirst=Project must be validated first ProjectDraft=Draft projects -FirstAddRessourceToAllocateTime=Associate a ressource to allocate time +FirstAddRessourceToAllocateTime=Associate a resource to allocate time InputPerDay=Input per day InputPerWeek=Input per week InputPerAction=Input per action diff --git a/htdocs/langs/en_US/propal.lang b/htdocs/langs/en_US/propal.lang index 2b6d12870a1..c57e9c38324 100644 --- a/htdocs/langs/en_US/propal.lang +++ b/htdocs/langs/en_US/propal.lang @@ -4,7 +4,7 @@ Proposal=Commercial proposal ProposalShort=Proposal ProposalsDraft=Draft commercial proposals ProposalDraft=Draft commercial proposal -ProposalsOpened=Opened commercial proposals +ProposalsOpened=Open commercial proposals Prop=Commercial proposals CommercialProposal=Commercial proposal CommercialProposals=Commercial proposals @@ -31,7 +31,7 @@ AmountOfProposalsByMonthHT=Amount by month (net of tax) NbOfProposals=Number of commercial proposals ShowPropal=Show proposal PropalsDraft=Drafts -PropalsOpened=Opened +PropalsOpened=Open PropalsNotBilled=Closed not billed PropalStatusDraft=Draft (needs to be validated) PropalStatusValidated=Validated (proposal is open) @@ -42,7 +42,7 @@ PropalStatusNotSigned=Not signed (closed) PropalStatusBilled=Billed PropalStatusDraftShort=Draft PropalStatusValidatedShort=Validated -PropalStatusOpenedShort=Opened +PropalStatusOpenedShort=Open PropalStatusClosedShort=Closed PropalStatusSignedShort=Signed PropalStatusNotSignedShort=Not signed @@ -51,8 +51,8 @@ PropalsToClose=Commercial proposals to close PropalsToBill=Signed commercial proposals to bill ListOfProposals=List of commercial proposals ActionsOnPropal=Events on proposal -NoOpenedPropals=No opened commercial proposals -NoOtherOpenedPropals=No other opened commercial proposals +NoOpenedPropals=No open commercial proposals +NoOtherOpenedPropals=No other open commercial proposals RefProposal=Commercial proposal ref SendPropalByMail=Send commercial proposal by mail AssociatedDocuments=Documents associated with the proposal: diff --git a/htdocs/langs/en_US/sendings.lang b/htdocs/langs/en_US/sendings.lang index 84088c3e023..1dc182c6fdc 100644 --- a/htdocs/langs/en_US/sendings.lang +++ b/htdocs/langs/en_US/sendings.lang @@ -53,7 +53,7 @@ DocumentModelSimple=Simple document model DocumentModelMerou=Merou A5 model WarningNoQtyLeftToSend=Warning, no products waiting to be shipped. StatsOnShipmentsOnlyValidated=Statistics conducted on shipments only validated. Date used is date of validation of shipment (planed delivery date is not always known). -DateDeliveryPlanned=Planed date of delivery +DateDeliveryPlanned=Planned date of delivery DateReceived=Date delivery received SendShippingByEMail=Send shipment by EMail SendShippingRef=Submission of shipment %s @@ -67,7 +67,7 @@ SendingRunning=Product from ordered customer orders SuppliersReceiptRunning=Product from ordered supplier orders ProductQtyInCustomersOrdersRunning=Product quantity into opened customers orders ProductQtyInSuppliersOrdersRunning=Product quantity into opened suppliers orders -ProductQtyInShipmentAlreadySent=Product quantity from opended customer order already sent +ProductQtyInShipmentAlreadySent=Product quantity from opened customer order already sent ProductQtyInSuppliersShipmentAlreadyRecevied=Product quantity from opened supplier order already received # Sending methods diff --git a/htdocs/langs/en_US/stocks.lang b/htdocs/langs/en_US/stocks.lang index 9019240490b..924878973bb 100644 --- a/htdocs/langs/en_US/stocks.lang +++ b/htdocs/langs/en_US/stocks.lang @@ -5,7 +5,7 @@ Warehouses=Warehouses NewWarehouse=New warehouse / Stock area WarehouseEdit=Modify warehouse MenuNewWarehouse=New warehouse -WarehouseOpened=Warehouse opened +WarehouseOpened=Warehouse open WarehouseClosed=Warehouse closed WarehouseSource=Source warehouse WarehouseSourceNotDefined=No warehouse defined, @@ -16,6 +16,7 @@ CancelSending=Cancel sending DeleteSending=Delete sending Stock=Stock Stocks=Stocks +StocksByLotSerial=Stock by lot/serial Movement=Movement Movements=Movements ErrorWarehouseRefRequired=Warehouse reference name is required @@ -78,6 +79,7 @@ IdWarehouse=Id warehouse DescWareHouse=Description warehouse LieuWareHouse=Localisation warehouse WarehousesAndProducts=Warehouses and products +WarehousesAndProductsBatchDetail=Warehouses and products (with detail per lot/serial) AverageUnitPricePMPShort=Weighted average input price AverageUnitPricePMP=Weighted average input price SellPriceMin=Selling Unit Price @@ -97,11 +99,11 @@ DesiredStock=Desired stock StockToBuy=To order Replenishment=Replenishment ReplenishmentOrders=Replenishment orders -VirtualDiffersFromPhysical=According to increase/decrease stock options, physical stock and virtual stock (physical + current orders) may differs +VirtualDiffersFromPhysical=According to increase/decrease stock options, physical stock and virtual stock (physical + current orders) may differ UseVirtualStockByDefault=Use virtual stock by default, instead of physical stock, for replenishment feature UseVirtualStock=Use virtual stock UsePhysicalStock=Use physical stock -CurentSelectionMode=Curent selection mode +CurentSelectionMode=Current selection mode CurentlyUsingVirtualStock=Virtual stock CurentlyUsingPhysicalStock=Physical stock RuleForStockReplenishment=Rule for stocks replenishment @@ -110,8 +112,8 @@ AlertOnly= Alerts only WarehouseForStockDecrease=The warehouse %s will be used for stock decrease WarehouseForStockIncrease=The warehouse %s will be used for stock increase ForThisWarehouse=For this warehouse -ReplenishmentStatusDesc=This is list of all product with a stock lower than desired stock (or lower than alert value if checkbox "alert only" is checked), and suggest you to create supplier orders to fill the difference. -ReplenishmentOrdersDesc=This is list of all opened supplier orders including predefined products. Only opened orders with predefined products, so that may affect stocks, are visible here. +ReplenishmentStatusDesc=This is a list of all products with a stock lower than desired stock (or lower than alert value if checkbox "alert only" is checked), and suggest you to create supplier orders to fill the difference. +ReplenishmentOrdersDesc=This is a list of all opened supplier orders including predefined products. Only opened orders with predefined products, so orders that may affect stocks, are visible here. Replenishments=Replenishments NbOfProductBeforePeriod=Quantity of product %s in stock before selected period (< %s) NbOfProductAfterPeriod=Quantity of product %s in stock after selected period (> %s) @@ -122,13 +124,16 @@ RecordMovement=Record transfert ReceivingForSameOrder=Receipts for this order StockMovementRecorded=Stock movements recorded RuleForStockAvailability=Rules on stock requirements -StockMustBeEnoughForInvoice=Stock level must be enough to add product/service into invoice -StockMustBeEnoughForOrder=Stock level must be enough to add product/service into order -StockMustBeEnoughForShipment= Stock level must be enough to add product/service into shipment +StockMustBeEnoughForInvoice=Stock level must be enough to add product/service to invoice +StockMustBeEnoughForOrder=Stock level must be enough to add product/service to order +StockMustBeEnoughForShipment= Stock level must be enough to add product/service to shipment MovementLabel=Label of movement InventoryCode=Movement or inventory code IsInPackage=Contained into package ShowWarehouse=Show warehouse -MovementCorrectStock=Stock content correction for product %s +MovementCorrectStock=Stock correction for product %s MovementTransferStock=Stock transfer of product %s into another warehouse -WarehouseMustBeSelectedAtFirstStepWhenProductBatchModuleOn=Source warehouse must be defined here when batch module is on. It will be used to list wich lot/serial is available for product that required lot/serial data for movement. If you want to send products from different warehouses, just make the shipment into several steps. +WarehouseMustBeSelectedAtFirstStepWhenProductBatchModuleOn=Source warehouse must be defined here when "Product lot" module is on. It will be used to list wich lot/serial is available for product that required lot/serial data for movement. If you want to send products from different warehouses, just make the shipment into several steps. +InventoryCodeShort=Inv./Mov. code +NoPendingReceptionOnSupplierOrder=No pending reception due to open supplier order +ThisSerialAlreadyExistWithDifferentDate=This lot/serial number (%s) already exists but with different eatby or sellby date (found %s but you enter %s). diff --git a/htdocs/langs/en_US/suppliers.lang b/htdocs/langs/en_US/suppliers.lang index 6b7010439c9..39b3ee8c3d9 100644 --- a/htdocs/langs/en_US/suppliers.lang +++ b/htdocs/langs/en_US/suppliers.lang @@ -42,5 +42,5 @@ SentToSuppliers=Sent to suppliers ListOfSupplierOrders=List of supplier orders MenuOrdersSupplierToBill=Supplier orders to invoice NbDaysToDelivery=Delivery delay in days -DescNbDaysToDelivery=The biggest delay is display among order product list +DescNbDaysToDelivery=The biggest deliver delay of the products from this order UseDoubleApproval=Use double approval (the second approval can be done by any user with the dedicated permission) \ No newline at end of file diff --git a/htdocs/langs/en_US/trips.lang b/htdocs/langs/en_US/trips.lang index b7d661478f6..d4e4e8c4359 100644 --- a/htdocs/langs/en_US/trips.lang +++ b/htdocs/langs/en_US/trips.lang @@ -7,7 +7,7 @@ TripsAndExpenses=Expenses reports TripsAndExpensesStatistics=Expense reports statistics TripCard=Expense report card AddTrip=Create expense report -ListOfTrips=List of expense report +ListOfTrips=List of expense reports ListOfFees=List of fees NewTrip=New expense report CompanyVisited=Company/foundation visited @@ -27,7 +27,7 @@ AnyOtherInThisListCanValidate=Person to inform for validation. TripSociete=Information company TripSalarie=Informations user TripNDF=Informations expense report -DeleteLine=Delete a ligne of the expense report +DeleteLine=Delete a line of the expense report ConfirmDeleteLine=Are you sure you want to delete this line ? PDFStandardExpenseReports=Standard template to generate a PDF document for expense report ExpenseReportLine=Expense report line @@ -40,11 +40,10 @@ TF_BUS=Bus TF_CAR=Car TF_PEAGE=Toll TF_ESSENCE=Fuel -TF_HOTEL=Hostel +TF_HOTEL=Hotel TF_TAXI=Taxi ErrorDoubleDeclaration=You have declared another expense report into a similar date range. -ListTripsAndExpenses=List of expense reports AucuneNDF=No expense reports found for this criteria AucuneLigne=There is no expense report declared yet AddLine=Add a line @@ -56,12 +55,12 @@ ModePaiement=Payment mode Note=Note Project=Project -VALIDATOR=User to inform for approbation +VALIDATOR=User responsible for approval VALIDOR=Approved by AUTHOR=Recorded by -AUTHORPAIEMENT=Paied by +AUTHORPAIEMENT=Paid by REFUSEUR=Denied by -CANCEL_USER=Canceled by +CANCEL_USER=Deleted by MOTIF_REFUS=Reason MOTIF_CANCEL=Reason @@ -72,10 +71,9 @@ DATE_VALIDE=Validation date DATE_CANCEL=Cancelation date DATE_PAIEMENT=Payment date -Deny=Deny TO_PAID=Pay BROUILLONNER=Reopen -SendToValid=Sent to approve +SendToValid=Sent on approval ModifyInfoGen=Edit ValidateAndSubmit=Validate and submit for approval @@ -94,32 +92,10 @@ ConfirmPaidTrip=Are you sure you want to change status of this expense report to CancelTrip=Cancel an expense report ConfirmCancelTrip=Are you sure you want to cancel this expense report ? -BrouillonnerTrip=Move back expense report to status "Draft"n +BrouillonnerTrip=Move back expense report to status "Draft" ConfirmBrouillonnerTrip=Are you sure you want to move this expense report to status "Draft" ? SaveTrip=Validate expense report ConfirmSaveTrip=Are you sure you want to validate this expense report ? -Synchro_Compta=NDF <-> Compte - -TripSynch=Synchronisation : Notes de frais <-> Compte courant -TripToSynch=Notes de frais à intégrer dans la compta -AucuneTripToSynch=Aucune note de frais n'est en statut "Payée". -ViewAccountSynch=Voir le compte - -ConfirmNdfToAccount=Êtes-vous sûr de vouloir intégrer cette note de frais dans le compte courant? -ndfToAccount=Note de frais - Intégration - -ConfirmAccountToNdf=Êtes-vous sûr de vouloir retirer cette note de frais du compte courant? -AccountToNdf=Note de frais - Retrait - -LINE_NOT_ADDED=Ligne non ajoutée : -NO_PROJECT=Aucun projet sélectionné. -NO_DATE=Aucune date sélectionnée. -NO_PRICE=Aucun prix indiqué. - -TripForValid=à Valider -TripForPaid=à Payer -TripPaid=Payée - NoTripsToExportCSV=No expense report to export for this period. diff --git a/htdocs/langs/en_US/workflow.lang b/htdocs/langs/en_US/workflow.lang index e08c88a9170..82af8e6c903 100644 --- a/htdocs/langs/en_US/workflow.lang +++ b/htdocs/langs/en_US/workflow.lang @@ -1,11 +1,11 @@ # Dolibarr language file - Source file is en_US - admin WorkflowSetup=Workflow module setup -WorkflowDesc=This module is designed to modify the behaviour of automatic actions into application. By default, workflow is opened (you make thing in order you want). You can activate the automatic actions that you are interesting in. -ThereIsNoWorkflowToModify=There is no workflow you can modify for module you have activated. -descWORKFLOW_PROPAL_AUTOCREATE_ORDER=Create a customer order automatically after a commercial proposal is signed -descWORKFLOW_PROPAL_AUTOCREATE_INVOICE=Create a customer invoice automatically after a commercial proposal is signed -descWORKFLOW_CONTRACT_AUTOCREATE_INVOICE=Create a customer invoice automatically after a contract is validated -descWORKFLOW_ORDER_AUTOCREATE_INVOICE=Create a customer invoice automatically after a customer order is closed +WorkflowDesc=This module is designed to modify the behaviour of automatic actions into application. By default, workflow is open (you can do things in the order you want). You can activate the automatic actions you are interested in. +ThereIsNoWorkflowToModify=There is no workflow to modify for the activated module. +descWORKFLOW_PROPAL_AUTOCREATE_ORDER=Automatically create a customer order after a commercial proposal is signed +descWORKFLOW_PROPAL_AUTOCREATE_INVOICEAutomatically create a customer invoice after a commercial proposal is signed +descWORKFLOW_CONTRACT_AUTOCREATE_INVOICEAutomatically create a customer invoice after a contract is validated +descWORKFLOW_ORDER_AUTOCREATE_INVOICEAutomatically create a customer invoice after a customer order is closed descWORKFLOW_ORDER_CLASSIFY_BILLED_PROPAL=Classify linked source proposal to billed when customer order is set to paid descWORKFLOW_INVOICE_CLASSIFY_BILLED_ORDER=Classify linked source customer order(s) to billed when customer invoice is set to paid descWORKFLOW_INVOICE_AMOUNT_CLASSIFY_BILLED_ORDER=Classify linked source customer order(s) to billed when customer invoice is validated diff --git a/htdocs/langs/fr_FR/admin.lang b/htdocs/langs/fr_FR/admin.lang index fd7e4b40acd..a890d2ea7f3 100644 --- a/htdocs/langs/fr_FR/admin.lang +++ b/htdocs/langs/fr_FR/admin.lang @@ -1606,7 +1606,7 @@ SalariesSetup=Configuration du module salariés SortOrder=Ordre de tri Format=Format TypePaymentDesc=0:Type de paiement client, 1:Type de paiement fournisseur, 2:Paiement de type client et fournisseur -IncludePath=Chemin Include (définir dans la variable %s) +IncludePath=Chemin Include (défini dans la variable %s) ExpenseReportsSetup=Configuration du module Notes de frais TemplatePDFExpenseReports=Modèles de documents pour générer les document de Notes de frais NoModueToManageStockDecrease=Aucun module capable d'assurer la réduction de stock en automatique a été activé. La réduction de stock se fera donc uniquement sur mise à jour manuelle. diff --git a/htdocs/langs/fr_FR/bills.lang b/htdocs/langs/fr_FR/bills.lang index 9e79b16af11..a6a4c1a85a4 100644 --- a/htdocs/langs/fr_FR/bills.lang +++ b/htdocs/langs/fr_FR/bills.lang @@ -190,7 +190,7 @@ AlreadyPaid=Déjà réglé AlreadyPaidBack=Déjà remboursé AlreadyPaidNoCreditNotesNoDeposits=Déjà réglé (hors avoirs et acomptes) Abandoned=Abandonné -RemainderToPay=Restant impayé +RemainderToPay=Reste à payer RemainderToTake=Montant restant à percevoir RemainderToPayBack=Montant à rembourser Rest=Créance @@ -294,8 +294,8 @@ TotalOfTwoDiscountMustEqualsOriginal=La somme du montant des 2 nouvelles réduct ConfirmRemoveDiscount=Êtes-vous sûr de vouloir supprimer cette réduction ? RelatedBill=Facture associée RelatedBills=Factures associées -RelatedCustomerInvoices=Related customer invoices -RelatedSupplierInvoices=Related supplier invoices +RelatedCustomerInvoices=Factures clients liées +RelatedSupplierInvoices=Factures fournisseurs liées LatestRelatedBill=Dernière facture en rapport WarningBillExist=Attention, une ou plusieurs factures existent déjà diff --git a/htdocs/langs/fr_FR/categories.lang b/htdocs/langs/fr_FR/categories.lang index 5a6ac7abc31..c310342feff 100644 --- a/htdocs/langs/fr_FR/categories.lang +++ b/htdocs/langs/fr_FR/categories.lang @@ -1,9 +1,9 @@ # Dolibarr language file - Source file is en_US - categories -Rubrique=Tag/Category -Rubriques=Tags/Categories -categories=tags/categories -TheCategorie=The tag/category -NoCategoryYet=No tag/category of this type created +Rubrique=Label/Catégorie +Rubriques=Labels/Catégories +categories=labels/catégories +TheCategorie=Le label/Catégorie +NoCategoryYet=Aucun label/catégorie de ce type n'a été créé In=Dans AddIn=Ajouter dans modify=modifier @@ -18,8 +18,8 @@ ContactsCategoriesArea=Contacts tags/categories area MainCats=Main tags/categories SubCats=Sous-catégories CatStatistics=Statistiques -CatList=List of tags/categories -AllCats=All tags/categories +CatList=Liste des labels/catégories +AllCats=Tous les labels/catégories ViewCat=View tag/category NewCat=Add tag/category NewCategory=New tag/category diff --git a/htdocs/langs/fr_FR/cron.lang b/htdocs/langs/fr_FR/cron.lang index 7c67426510d..b009c0b54d6 100644 --- a/htdocs/langs/fr_FR/cron.lang +++ b/htdocs/langs/fr_FR/cron.lang @@ -18,7 +18,7 @@ CronExplainHowToRunUnix=Sur un environnement Unix vous pouvez utiliser l'entrée CronExplainHowToRunWin=Sur un environement Microsoft(tm) Windows vous pouvez utiliser le planificateur de tache pour lancer cette commande toute les 5 minutes. # Menu CronJobs=Travaux programmés -CronListActive=Liste des travaux actifs/programmés +CronListActive=Liste des travaux CronListInactive=Liste des travaux inactifs # Page list CronDateLastRun=Dernier lancement diff --git a/htdocs/langs/fr_FR/donations.lang b/htdocs/langs/fr_FR/donations.lang index a2625c9c0fa..3dbb4cc5f76 100644 --- a/htdocs/langs/fr_FR/donations.lang +++ b/htdocs/langs/fr_FR/donations.lang @@ -6,8 +6,8 @@ Donor=Donateur Donors=Donateurs AddDonation=Créer un don NewDonation=Nouveau don -DeleteADonation=Delete a donation -ConfirmDeleteADonation=Are you sure you want to delete this donation ? +DeleteADonation=Effacer le don +ConfirmDeleteADonation=Êtes-vous sûr de vouloir supprimer ce don ? ShowDonation=Montrer don DonationPromise=Promesse de don PromisesNotValid=Promesses non validées @@ -23,8 +23,8 @@ DonationStatusPaid=Don payé DonationStatusPromiseNotValidatedShort=Non validée DonationStatusPromiseValidatedShort=Validée DonationStatusPaidShort=Payé -DonationTitle=Donation receipt -DonationDatePayment=Payment date +DonationTitle=Reçu de dons +DonationDatePayment=Date paiement ValidPromess=Valider promesse DonationReceipt=Reçu de dons BuildDonationReceipt=Créer reçu @@ -40,4 +40,4 @@ FrenchOptions=Options propres à la france DONATION_ART200=Afficher article 200 du CGI si vous êtes concernés DONATION_ART238=Afficher article 238 du CGI si vous êtes concernés DONATION_ART885=Afficher article 885 du CGI si vous êtes concernés -DonationPayment=Donation payment +DonationPayment=Paiement du don diff --git a/htdocs/langs/fr_FR/errors.lang b/htdocs/langs/fr_FR/errors.lang index d784017964d..dd92729aa4d 100644 --- a/htdocs/langs/fr_FR/errors.lang +++ b/htdocs/langs/fr_FR/errors.lang @@ -25,7 +25,7 @@ ErrorFromToAccountsMustDiffers=Les comptes source et destination doivent être d ErrorBadThirdPartyName=Nom de tiers incorrect ErrorProdIdIsMandatory=Le %s est obligatoire ErrorBadCustomerCodeSyntax=La syntaxe du code client est incorrecte -ErrorBadBarCodeSyntax=Bad syntax for bar code. May be you set a bad barcode type or you defined a barcode mask for numbering that does not match value scanned. +ErrorBadBarCodeSyntax=Mauvaise syntaxe pour le code barre. Peut être que vous avez défini un mauvais type de code-barres ou que vous avez défini un masque de code à barres pour la numérotation qui ne correspond pas à la valeur scannée. ErrorCustomerCodeRequired=Code client obligatoire ErrorBarCodeRequired=Code-barre requis ErrorCustomerCodeAlreadyUsed=Code client déjà utilisé @@ -160,13 +160,13 @@ ErrorPriceExpressionInternal=Erreur interne '%s' ErrorPriceExpressionUnknown=Erreur inconnue '%s' ErrorSrcAndTargetWarehouseMustDiffers=Les entrepôts source et destination doivent être différents ErrorTryToMakeMoveOnProductRequiringBatchData=Erreur, vous essayez de faire un mouvement sans lot/numéro de série, sur un produit qui exige un lot/numéro de série. -ErrorCantSetReceptionToTotalDoneWithReceptionToApprove=All recorded receptions must first be verified before being allowed to do this action -ErrorGlobalVariableUpdater0=HTTP request failed with error '%s' -ErrorGlobalVariableUpdater1=Invalid JSON format '%s' -ErrorGlobalVariableUpdater2=Missing parameter '%s' -ErrorGlobalVariableUpdater3=The requested data was not found in result -ErrorGlobalVariableUpdater4=SOAP client failed with error '%s' -ErrorGlobalVariableUpdater5=No global variable selected +ErrorCantSetReceptionToTotalDoneWithReceptionToApprove=Toutes les réceptions enregistrées doivent d'abord être vérifiées avant d'être autorisés à faire cette action +ErrorGlobalVariableUpdater0=La requête HTTP a échoué avec l'erreur '%s' +ErrorGlobalVariableUpdater1=Format JSON invalide '%s' +ErrorGlobalVariableUpdater2=Paramètre manquant '%s' +ErrorGlobalVariableUpdater3=La donnée recherché n'a pas été trouvée +ErrorGlobalVariableUpdater4=Le client SOAP a échoué avec l'erreur '%s' +ErrorGlobalVariableUpdater5=Pas de variable globale # Warnings WarningMandatorySetupNotComplete=Les informations de configuration obligatoire doivent être renseignées diff --git a/htdocs/langs/fr_FR/main.lang b/htdocs/langs/fr_FR/main.lang index 0883a410e7d..b1fe2e89036 100644 --- a/htdocs/langs/fr_FR/main.lang +++ b/htdocs/langs/fr_FR/main.lang @@ -141,7 +141,7 @@ Cancel=Annuler Modify=Modifier Edit=Éditer Validate=Valider -ValidateAndApprove=Validate and Approve +ValidateAndApprove=Valider et Approuver ToValidate=À valider Save=Enregistrer SaveAs=Enregistrer sous @@ -159,7 +159,7 @@ Search=Rechercher SearchOf=Recherche de Valid=Valider Approve=Approuver -Disapprove=Disapprove +Disapprove=Désapprouver ReOpen=Réouvrir Upload=Envoyer fichier ToLink=Lier @@ -221,7 +221,7 @@ Cards=Fiches Card=Fiche Now=Maintenant Date=Date -DateAndHour=Date and hour +DateAndHour=Date et heure DateStart=Date début DateEnd=Date fin DateCreation=Date création @@ -395,8 +395,8 @@ Available=Disponible NotYetAvailable=Pas encore disponible NotAvailable=Non disponible Popularity=Popularité -Categories=Tags/categories -Category=Tag/category +Categories=Tags/catégories +Category=Tag/catégorie By=Par From=Du to=au diff --git a/htdocs/livraison/card.php b/htdocs/livraison/card.php index e50fb9c8ea8..f4f46e263c2 100644 --- a/htdocs/livraison/card.php +++ b/htdocs/livraison/card.php @@ -394,7 +394,7 @@ if ($action == 'create') */ print ''; $quantite_livree = $commande->livraisons[$line->id]; - print $quantite_livree;; + print $quantite_livree; print ''; $quantite_commandee = $line->qty; diff --git a/htdocs/livraison/class/livraison.class.php b/htdocs/livraison/class/livraison.class.php index 027f7ab3b89..52db876fbf0 100644 --- a/htdocs/livraison/class/livraison.class.php +++ b/htdocs/livraison/class/livraison.class.php @@ -5,7 +5,7 @@ * Copyright (C) 2007 Franky Van Liedekerke * Copyright (C) 2011-2012 Philippe Grand * Copyright (C) 2013 Florian Henry - * Copyright (C) 2014 Marcos García + * Copyright (C) 2014-2015 Marcos García * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -990,6 +990,23 @@ class Livraison extends CommonObject return $this->commonGenerateDocument($modelpath, $modele, $outputlangs, 0, 0, 0); } + /** + * Function used to replace a thirdparty id with another one. + * + * @param DoliDB $db Database handler + * @param int $origin_id Old thirdparty id + * @param int $dest_id New thirdparty id + * @return bool + */ + public static function replaceThirdparty(DoliDB $db, $origin_id, $dest_id) + { + $tables = array( + 'livraison' + ); + + return CommonObject::commonReplaceThirdparty($db, $origin_id, $dest_id, $tables); + } + } diff --git a/htdocs/loan/card.php b/htdocs/loan/card.php index 8e280b2da75..670f2180bf0 100644 --- a/htdocs/loan/card.php +++ b/htdocs/loan/card.php @@ -425,15 +425,18 @@ if ($id > 0) if ($resql) { $num = $db->num_rows($resql); - $i = 0; $total = 0; + $i = 0; + $total_insurance = 0; + $total_interest = 0; + $total_capital = 0; echo ''; print ''; print ''; print ''; print ''; - print ''; - print ''; - print ''; + print ''; + print ''; + print ''; print ''; print ''; @@ -442,27 +445,31 @@ if ($id > 0) { $objp = $db->fetch_object($resql); $var=!$var; - print "'; + print ""; + print ''; print '\n"; print "\n"; - print '\n"; - print '\n"; - print '\n"; + print '\n"; + print '\n"; + print '\n"; print ""; - $totalpaid += $objp->amount_capital; + $total_insurance += $objp->amount_insurance; + $total_interest += $objp->amount_interest; + $total_capital += $objp->amount_capital; $i++; } + $totalpaid = $total_insurance + $total_interest + $total_capital; + if ($object->paid == 0) { - print ''; - print ''; + print ''; + print ''; $staytopay = $object->capital - $totalpaid; - print ''; - print ''; + print ''; + print ''; } print "
'.$langs->trans("RefPayment").''.$langs->trans("Date").''.$langs->trans("Type").''.$langs->trans("Insurance").''.$langs->trans("Interest").''.$langs->trans("Capital").''.$langs->trans("Insurance").''.$langs->trans("Interest").''.$langs->trans("Capital").' 
"; - print ''.img_object($langs->trans("Payment"),"payment").' '.$objp->rowid.'
'.img_object($langs->trans("Payment"),"payment").' '.$objp->rowid.''.dol_print_date($db->jdate($objp->dp),'day')."".$objp->paiement_type.' '.$objp->num_payment."'.price($objp->amount_insurance)." ".$langs->trans("Currency".$conf->currency)."'.price($objp->amount_interest)." ".$langs->trans("Currency".$conf->currency)."'.price($objp->amount_capital)." ".$langs->trans("Currency".$conf->currency)."'.price($objp->amount_insurance, 0, $langs, 0, 0, -1, $conf->currency)."'.price($objp->amount_interest, 0, $langs, 0, 0, -1, $conf->currency)."'.price($objp->amount_capital, 0, $langs, 0, 0, -1, $conf->currency)."
'.$langs->trans("AlreadyPaid").' :'.price($totalpaid).' '.$langs->trans("Currency".$conf->currency).'
'.$langs->trans("AmountExpected").' :'.price($object->capital).' '.$langs->trans("Currency".$conf->currency).'
'.$langs->trans("AlreadyPaid").' :'.price($totalpaid, 0, $langs, 0, 0, -1, $conf->currency).'
'.$langs->trans("AmountExpected").' :'.price($object->capital, 0, $langs, 0, 0, -1, $conf->currency).'
'.$langs->trans("RemainderToPay").' :'.price($staytopay).' '.$langs->trans("Currency".$conf->currency).'
'.$langs->trans("RemainderToPay").' :'.price($staytopay, 0, $langs, 0, 0, -1, $conf->currency).'
"; $db->free($resql); diff --git a/htdocs/loan/class/loan.class.php b/htdocs/loan/class/loan.class.php index c2c0bba6381..85d0694b725 100644 --- a/htdocs/loan/class/loan.class.php +++ b/htdocs/loan/class/loan.class.php @@ -321,7 +321,7 @@ class Loan extends CommonObject * Return label of loan status (unpaid, paid) * * @param int $mode 0=label, 1=short label, 2=Picto + Short label, 3=Picto, 4=Picto + Label - * @param double $alreadypaid 0=No payment already done, >0=Some payments were already done (we recommand to put here amount payed if you have it, 1 otherwise) + * @param integer $alreadypaid 0=No payment already done, >0=Some payments were already done (we recommand to put here amount payed if you have it, 1 otherwise) * @return string Label */ function getLibStatut($mode=0,$alreadypaid=-1) @@ -334,7 +334,7 @@ class Loan extends CommonObject * * @param int $statut Id statut * @param int $mode 0=Label, 1=Short label, 2=Picto + Short label, 3=Picto, 4=Picto + Label, 5=Short label + Picto - * @param double $alreadypaid 0=No payment already done, >0=Some payments were already done (we recommand to put here amount payed if you have it, 1 otherwise) + * @param integer $alreadypaid 0=No payment already done, >0=Some payments were already done (we recommand to put here amount payed if you have it, 1 otherwise) * @return string Label */ function LibStatut($statut,$mode=0,$alreadypaid=-1) @@ -447,7 +447,7 @@ class Loan extends CommonObject * Information on record * * @param int $id Id of record - * @return void + * @return integer|null */ function info($id) { diff --git a/htdocs/loan/document.php b/htdocs/loan/document.php index 788048a215b..3831f73a7ea 100644 --- a/htdocs/loan/document.php +++ b/htdocs/loan/document.php @@ -81,8 +81,8 @@ llxHeader("",$langs->trans("Loan"),$help_url); if ($object->id) { $alreadypayed=$object->getSumPayment(); - - $head = loan_prepare_head($object, $user); + + $head = loan_prepare_head($object); dol_fiche_head($head, 'documents', $langs->trans("Loan"), 0, 'bill'); diff --git a/htdocs/main.inc.php b/htdocs/main.inc.php index da0296e4b00..d0b80db1190 100644 --- a/htdocs/main.inc.php +++ b/htdocs/main.inc.php @@ -111,17 +111,17 @@ function test_sql_and_script_inject($val, $type) /** * Security: Return true if OK, false otherwise. * - * @param string $var Variable name - * @param string $type 1=GET, 0=POST, 2=PHP_SELF - * @return boolean true if there is an injection + * @param string $var Variable name + * @param string $type 1=GET, 0=POST, 2=PHP_SELF + * @return boolean||null true if there is an injection. Stop code if injection found. */ -function analyse_sql_and_script(&$var, $type) +function analyseVarsForSqlAndScriptsInjection(&$var, $type) { if (is_array($var)) { foreach ($var as $key => $value) { - if (analyse_sql_and_script($value,$type)) + if (analyseVarsForSqlAndScriptsInjection($value,$type)) { $var[$key] = $value; } @@ -147,16 +147,16 @@ if ((defined('NOREQUIREDB') || defined('NOREQUIRETRAN')) && ! defined('NOREQUIRE if (! empty($_SERVER["PHP_SELF"])) { $morevaltochecklikepost=array($_SERVER["PHP_SELF"]); - analyse_sql_and_script($morevaltochecklikepost,2); + analyseVarsForSqlAndScriptsInjection($morevaltochecklikepost,2); } // Sanity check on GET parameters if (! empty($_SERVER["QUERY_STRING"])) { $morevaltochecklikeget=array($_SERVER["QUERY_STRING"]); - analyse_sql_and_script($morevaltochecklikeget,1); + analyseVarsForSqlAndScriptsInjection($morevaltochecklikeget,1); } // Sanity check on POST -analyse_sql_and_script($_POST,0); +analyseVarsForSqlAndScriptsInjection($_POST,0); // This is to make Dolibarr working with Plesk if (! empty($_SERVER['DOCUMENT_ROOT'])) set_include_path($_SERVER['DOCUMENT_ROOT'].'/htdocs'); @@ -975,7 +975,8 @@ function top_htmlhead($head, $title='', $disablejs=0, $disablehead=0, $arrayofjs print "\n"; if (GETPOST('dol_basehref')) print ''."\n"; // Displays meta - print ''."\n"; // Evite indexation par robots + print ''."\n"; // Do not index + print ''; // Scale for mobile device print ''."\n"; if (! empty($conf->global->MAIN_ACTIVATE_HTML5)) print ''."\n"; // Needed for Responsive Web Design $favicon=dol_buildpath('/theme/'.$conf->theme.'/img/favicon.ico',1); diff --git a/htdocs/margin/tabs/productMargins.php b/htdocs/margin/tabs/productMargins.php index 2123f683c21..eb3ac32c424 100644 --- a/htdocs/margin/tabs/productMargins.php +++ b/htdocs/margin/tabs/productMargins.php @@ -77,7 +77,7 @@ if ($id > 0 || ! empty($ref)) */ if ($result > 0) { - $head=product_prepare_head($object, $user); + $head=product_prepare_head($object); $titre=$langs->trans("CardProduct".$object->type); $picto=($object->type== Product::TYPE_SERVICE?'service':'product'); dol_fiche_head($head, 'margin', $titre, 0, $picto); diff --git a/htdocs/opensurvey/card.php b/htdocs/opensurvey/card.php index 70e1b49ad48..a217f34d939 100644 --- a/htdocs/opensurvey/card.php +++ b/htdocs/opensurvey/card.php @@ -309,7 +309,7 @@ $urlwithouturlroot=preg_replace('/'.preg_quote(DOL_URL_ROOT,'/').'$/i','',trim($ $urlwithroot=$urlwithouturlroot.DOL_URL_ROOT; // This is to use external domain name found into config file //$urlwithroot=DOL_MAIN_URL_ROOT; // This is to use same domain name than current -$url=$urlwithouturlroot.dol_buildpath('/opensurvey/public/studs.php',1).'?sondage='.$object->id_sondage; +$url=$urlwithouturlroot.dol_buildpath('/public/opensurvey/studs.php',1).'?sondage='.$object->id_sondage; $urllink=''.$url.''; print $urllink; @@ -367,7 +367,7 @@ if ($comments) { } else { - print $langs->trans("NoCommentYet").'
';; + print $langs->trans("NoCommentYet").'
'; } print '
'; diff --git a/htdocs/opensurvey/results.php b/htdocs/opensurvey/results.php index 226bc0c0465..63242cb341c 100644 --- a/htdocs/opensurvey/results.php +++ b/htdocs/opensurvey/results.php @@ -480,7 +480,7 @@ $urlwithouturlroot=preg_replace('/'.preg_quote(DOL_URL_ROOT,'/').'$/i','',trim($ $urlwithroot=$urlwithouturlroot.DOL_URL_ROOT; // This is to use external domain name found into config file //$urlwithroot=DOL_MAIN_URL_ROOT; // This is to use same domain name than current -$url=$urlwithouturlroot.dol_buildpath('/opensurvey/public/studs.php',1).'?sondage='.$numsondage; +$url=$urlwithouturlroot.dol_buildpath('/public/opensurvey/studs.php',1).'?sondage='.$numsondage; $urlvcal=''.$url.''; print $urlvcal; diff --git a/htdocs/opensurvey/wizard/create_survey.php b/htdocs/opensurvey/wizard/create_survey.php index cacc0ad8155..ec2568c3858 100644 --- a/htdocs/opensurvey/wizard/create_survey.php +++ b/htdocs/opensurvey/wizard/create_survey.php @@ -79,7 +79,7 @@ if (GETPOST("creation_sondage_date") || GETPOST("creation_sondage_autre")) $testdate = false; $champdatefin = dol_mktime(0,0,0,GETPOST('champdatefinmonth'),GETPOST('champdatefinday'),GETPOST('champdatefinyear')); - if (GETPOST('champdatefin') && ($champdatefin > 0)) // A date was provided + if ($champdatefin && ($champdatefin > 0)) // A date was provided { // Expire date is not before today if ($champdatefin >= dol_now()) @@ -90,16 +90,17 @@ if (GETPOST("creation_sondage_date") || GETPOST("creation_sondage_autre")) else { $testdate = true; + $_SESSION['champdatefin'] = dol_print_date($champdatefin,'dayrfc'); //$testdate = false; //$_SESSION['champdatefin'] = dol_print_date($champdatefin,'dayrfc'); - //setEventMessage($langs->trans('ExpiredDate'),'errors'); + setEventMessage($langs->trans('ExpiredDate'),'warnings'); } } if (! $testdate) { setEventMessage($langs->trans('ErrorFieldRequired',$langs->transnoentitiesnoconv("ExpireDate")), 'errors'); } - + if ($titre && $testdate) { if (! empty($creation_sondage_date)) diff --git a/htdocs/paypal/lib/paypal.lib.php b/htdocs/paypal/lib/paypal.lib.php index 2e8ab4bf0b8..5eb4549f0fa 100644 --- a/htdocs/paypal/lib/paypal.lib.php +++ b/htdocs/paypal/lib/paypal.lib.php @@ -415,26 +415,45 @@ function print_paypal_redirect($paymentAmount,$currencyCodeType,$paymentType,$re } -/* - '------------------------------------------------------------------------------------------------------------------------------------------- - ' Purpose: Prepares the parameters for the SetExpressCheckout API Call. - ' Inputs: - ' paymentAmount: Total value of the shopping cart - ' currencyCodeType: Currency code value the PayPal API - ' paymentType: paymentType has to be one of the following values: Sale or Order or Authorization - ' returnURL: the page where buyers return to after they are done with the payment review on PayPal - ' cancelURL: the page where buyers return to when they cancel the payment review on PayPal - ' shipToName: the Ship to name entered on the merchant's site - ' shipToStreet: the Ship to Street entered on the merchant's site - ' shipToCity: the Ship to City entered on the merchant's site - ' shipToState: the Ship to State entered on the merchant's site - ' shipToCountryCode: the Code for Ship to Country entered on the merchant's site - ' shipToZip: the Ship to ZipCode entered on the merchant's site - ' shipToStreet2: the Ship to Street2 entered on the merchant's site - ' phoneNum: the phoneNum entered on the merchant's site - ' email: the buyer email - ' desc: Product description - '-------------------------------------------------------------------------------------------------------------------------------------------- +/** + *------------------------------------------------------------------------------------------------------------------------------------------- + * Purpose: Prepares the parameters for the SetExpressCheckout API Call. + * Inputs: + * paymentAmount: Total value of the shopping cart + * currencyCodeType: Currency code value the PayPal API + * paymentType: paymentType has to be one of the following values: Sale or Order or Authorization + * returnURL: the page where buyers return to after they are done with the payment review on PayPal + * cancelURL: the page where buyers return to when they cancel the payment review on PayPal + * shipToName: the Ship to name entered on the merchant's site + * shipToStreet: the Ship to Street entered on the merchant's site + * shipToCity: the Ship to City entered on the merchant's site + * shipToState: the Ship to State entered on the merchant's site + * shipToCountryCode: the Code for Ship to Country entered on the merchant's site + * shipToZip: the Ship to ZipCode entered on the merchant's site + * shipToStreet2: the Ship to Street2 entered on the merchant's site + * phoneNum: the phoneNum entered on the merchant's site + * email: the buyer email + * desc: Product description + * + * @param double $paymentAmount Payment amount + * @param string $currencyCodeType Currency + * @param string $paymentType Payment type + * @param string $returnURL Return Url + * @param string $cancelURL Cancel Url + * @param string $tag Tag + * @param string $solutionType Type + * @param string $landingPage Landing page + * @param string $shipToName Ship to name + * @param string $shipToStreet Ship to street + * @param string $shipToCity Ship to city + * @param string $shipToState Ship to state + * @param string $shipToCountryCode Ship to country code + * @param string $shipToZip Ship to zip + * @param string $shipToStreet2 Ship to street2 + * @param string $phoneNum Phone + * @param string $email Email + * @param string $desc Description + * @return array Array */ function callSetExpressCheckout($paymentAmount, $currencyCodeType, $paymentType, $returnURL, $cancelURL, $tag, $solutionType, $landingPage, $shipToName, $shipToStreet, $shipToCity, $shipToState, $shipToCountryCode, $shipToZip, $shipToStreet2, $phoneNum, $email='', $desc='') { diff --git a/htdocs/printing/index.php b/htdocs/printing/index.php index e8669f44585..48795fbab4c 100644 --- a/htdocs/printing/index.php +++ b/htdocs/printing/index.php @@ -30,8 +30,8 @@ llxHeader("",$langs->trans("Printing")); print_fiche_titre($langs->trans("Printing")); // List Jobs from printing modules -//$printer = new dolPrintIPP($db,$conf->global->PRINTIPP_HOST,$conf->global->PRINTIPP_PORT,$user->login,$conf->global->PRINTIPP_USER,$conf->global->PRINTIPP_PASSWORD); -//$printer->list_jobs('commande'); +$printer = new dolPrintIPP($db,$conf->global->PRINTIPP_HOST,$conf->global->PRINTIPP_PORT,$user->login,$conf->global->PRINTIPP_USER,$conf->global->PRINTIPP_PASSWORD); +$printer->list_jobs('commande'); llxFooter(); diff --git a/htdocs/product/admin/product.php b/htdocs/product/admin/product.php index b46cfc79b1b..866262f9e45 100644 --- a/htdocs/product/admin/product.php +++ b/htdocs/product/admin/product.php @@ -160,6 +160,10 @@ else if ($action == 'viewProdTextsInThirdpartyLanguage') $view = GETPOST('activate_viewProdTextsInThirdpartyLanguage','alpha'); $res = dolibarr_set_const($db, "PRODUIT_TEXTS_IN_THIRDPARTY_LANGUAGE", $view,'chaine',0,'',$conf->entity); } +elseif ($action == 'mergePropalProductCard') { + $view = GETPOST('activate_mergePropalProductCard','alpha'); + $res = dolibarr_set_const($db, "PRODUIT_PDF_MERGE_PROPAL", $view,'chaine',0,'',$conf->entity); +} else if ($action == 'usesearchtoselectproduct') { $usesearch = GETPOST('activate_usesearchtoselectproduct','alpha'); @@ -435,6 +439,21 @@ print ''; print ''; print ''; +// Activate propal merge produt card +$var=!$var; +print '
'; +print ''; +print ''; +print ''; +print ''.$langs->trans("MergePropalProductCard").''; +print ''; +print $form->selectyesno("activate_mergePropalProductCard",$conf->global->PRODUIT_PDF_MERGE_PROPAL,1); +print ''; +print ''; +print ''; +print ''; +print '
'; + // Use units $var=!$var; print '
'; diff --git a/htdocs/product/canvas/product/actions_card_product.class.php b/htdocs/product/canvas/product/actions_card_product.class.php index 84140ee3f6a..260c8996fc4 100644 --- a/htdocs/product/canvas/product/actions_card_product.class.php +++ b/htdocs/product/canvas/product/actions_card_product.class.php @@ -138,7 +138,7 @@ class ActionsCardProduct if ($action == 'view') { - $head = product_prepare_head($this->object,$user); + $head = product_prepare_head($this->object); $this->tpl['showrefnav'] = $form->showrefnav($this->object,'ref','',1,'ref'); diff --git a/htdocs/product/canvas/service/actions_card_service.class.php b/htdocs/product/canvas/service/actions_card_service.class.php index b36e7b317c6..f7de783cd99 100644 --- a/htdocs/product/canvas/service/actions_card_service.class.php +++ b/htdocs/product/canvas/service/actions_card_service.class.php @@ -67,7 +67,7 @@ class ActionsCardService * Assign custom values for canvas (for example into this->tpl to be used by templates) * * @param string $action Type of action - * @param string $id Id of object + * @param integer $id Id of object * @param string $ref Ref of object * @return void */ @@ -137,7 +137,7 @@ class ActionsCardService if ($action == 'view') { - $head = product_prepare_head($this->object,$user); + $head = product_prepare_head($this->object); $this->tpl['showrefnav'] = $form->showrefnav($this->object,'ref','',1,'ref'); diff --git a/htdocs/product/card.php b/htdocs/product/card.php index 0a78fc98d5a..c5995425778 100644 --- a/htdocs/product/card.php +++ b/htdocs/product/card.php @@ -1,6 +1,6 @@ - * Copyright (C) 2004-2014 Laurent Destailleur + * Copyright (C) 2004-2015 Laurent Destailleur * Copyright (C) 2005 Eric Seigne * Copyright (C) 2005-2014 Regis Houssin * Copyright (C) 2006 Andre Cianfarani @@ -40,6 +40,7 @@ require_once DOL_DOCUMENT_ROOT.'/core/class/extrafields.class.php'; require_once DOL_DOCUMENT_ROOT.'/core/class/genericobject.class.php'; require_once DOL_DOCUMENT_ROOT.'/core/lib/product.lib.php'; require_once DOL_DOCUMENT_ROOT.'/core/lib/company.lib.php'; +require_once DOL_DOCUMENT_ROOT.'/categories/class/categorie.class.php'; if (! empty($conf->propal->enabled)) require_once DOL_DOCUMENT_ROOT.'/comm/propal/class/propal.class.php'; if (! empty($conf->facture->enabled)) require_once DOL_DOCUMENT_ROOT.'/compta/facture/class/facture.class.php'; if (! empty($conf->commande->enabled)) require_once DOL_DOCUMENT_ROOT.'/commande/class/commande.class.php'; @@ -276,6 +277,16 @@ if (empty($reshook)) if ($id > 0) { + // Category association + $categories = GETPOST('categories'); + if(!empty($categories)) { + $cat = new Categorie($db); + foreach($categories as $id_category) { + $cat->fetch($id_category); + $cat->add_type($object, 'product'); + } + } + header("Location: ".$_SERVER['PHP_SELF']."?id=".$id); exit; } @@ -362,6 +373,23 @@ if (empty($reshook)) { if ($object->update($object->id, $user) > 0) { + // Category association + // First we delete all categories association + $sql = "DELETE FROM ".MAIN_DB_PREFIX."categorie_product"; + $sql .= " WHERE fk_product = ".$object->id; + $db->query($sql); + + // Then we add the associated categories + $categories = GETPOST('categories'); + if(!empty($categories)) { + $cat = new Categorie($db); + + foreach($categories as $id_category) { + $cat->fetch($id_category); + $cat->add_type($object, 'product'); + } + } + $action = 'view'; } else @@ -889,6 +917,8 @@ else else $title=$langs->trans("NewProduct"); print_fiche_titre($title); + dol_fiche_head(''); + print ''; print ''; $tmpcode=''; @@ -1049,7 +1079,13 @@ else $doleditor = new DolEditor('note', GETPOST('note'), '', 140, 'dolibarr_details', '', false, true, $conf->global->FCKEDITOR_ENABLE_PRODUCTDESC, 8, 70); $doleditor->Create(); - print ""; + print ""; + + // Categories + print '"; // Units if($conf->global->PRODUCT_USE_UNITS) @@ -1057,10 +1093,10 @@ else print ''; print ''; } - print '>
'.$langs->trans("Categories").''; + $cate_arbo = $form->select_all_categories(0, '', 'parent', 64, 0, 1); + print $form->multiselectarray('categories', $cate_arbo, $arrayselected, '', 0, '', 0, 250); + print "
'.$langs->trans('Unit').''; $form->select_units("units"); - print '
'; + print ''; print '
'; @@ -1117,6 +1153,8 @@ else print '
'; //} + dol_fiche_end(); + print '
'; print ''; @@ -1326,18 +1364,29 @@ else $doleditor = new DolEditor('note', $object->note, '', 140, 'dolibarr_notes', '', false, true, $conf->global->FCKEDITOR_ENABLE_PRODUCTDESC, 4, 80); $doleditor->Create(); - print ""; + print ""; + // Categories + print ''.$langs->trans("Categories").''; + $cate_arbo = $form->select_all_categories(0, '', 'parent', 64, 0, 1); + $c = new Categorie($db); + $cats = $c->containing($object->id,0); + foreach($cats as $cat) { + $arrayselected[] = $cat->id; + } + print $form->multiselectarray('categories', $cate_arbo, $arrayselected, '', 0, '', 0, 250); + print ""; + // Units if($conf->global->PRODUCT_USE_UNITS) { print ''.$langs->trans('Unit').''; print ''; $form->select_units($object->fk_unit); - print ''; + print ''; } - print ''; + print ''; print '
'; @@ -1375,7 +1424,7 @@ else // Fiche en mode visu else { - $head=product_prepare_head($object, $user); + $head=product_prepare_head($object); $titre=$langs->trans("CardProduct".$object->type); $picto=($object->type== Product::TYPE_SERVICE?'service':'product'); dol_fiche_head($head, 'card', $titre, 0, $picto); @@ -1638,6 +1687,19 @@ else print ''.$langs->trans("Note").''.(dol_textishtml($object->note)?$object->note:dol_nl2br($object->note,1,true)).''."\n"; print ' '."\n"; + // Categories + print ''.$langs->trans("Categories").''; + $cat = new Categorie($db); + $categories = $cat->containing($object->id,0); + $catarray = $form->select_all_categories(0, '', 'parent', 64, 0, 1); + + $toprint = array(); + foreach($categories as $c) { + $toprint[] = $catarray[$c->id]; + } + print implode('
', $toprint); + print ""; + print "\n"; dol_fiche_end(); diff --git a/htdocs/product/class/product.class.php b/htdocs/product/class/product.class.php index b8694e44ad4..ce07c25a515 100755 --- a/htdocs/product/class/product.class.php +++ b/htdocs/product/class/product.class.php @@ -7,7 +7,7 @@ * Copyright (C) 2010-2013 Juanjo Menent * Copyright (C) 2012 Cedric Salvador * Copyright (C) 2013-2014 Cedric GROSS - * Copyright (C) 2013-2014 Marcos García + * Copyright (C) 2013-2015 Marcos García * Copyright (C) 2011-2014 Alexandre Spangaro * Copyright (C) 2014 Henry Florian * Copyright (C) 2014 Philippe Grand @@ -3157,6 +3157,8 @@ class Product extends CommonObject else { $this->error=$movementstock->error; + $this->errors=$movementstock->errors; + $this->db->rollback(); return -1; } @@ -3209,9 +3211,10 @@ class Product extends CommonObject } /** - * Load information about stock of a product into stock_warehouse[] and stock_reel + * Load information about stock of a product into stock_reel, stock_warehouse[] (including stock_warehouse[idwarehouse]->detail_batch for batch products) * - * @return int < 0 if KO, > 0 if OK + * @return int < 0 if KO, > 0 if OK + * @see load_virtual_stock, getBatchInfo */ function load_stock() { @@ -3259,9 +3262,10 @@ class Product extends CommonObject } /** - * Load information about virtual stock of a product + * Load information about objects that are delat between physical and virtual stock of a product * - * @return int < 0 if KO, > 0 if OK + * @return int < 0 if KO, > 0 if OK + * @see load_stock, getBatchInfo */ function load_virtual_stock() { @@ -3317,6 +3321,44 @@ class Product extends CommonObject } } + + /** + * Load existing information about a serial + * + * @param string $batch Lot/serial number + * @return array Array with record into product_batch + * @see load_stock, load_virtual_stock + */ + function loadBatchInfo($batch) + { + $result=array(); + + $sql = "SELECT pb.batch, pb.eatby, pb.sellby, SUM(pb.qty) FROM ".MAIN_DB_PREFIX."product_batch as pb, ".MAIN_DB_PREFIX."product_stock as ps"; + $sql.= " WHERE pb.fk_product_stock = ps.rowid AND ps.fk_product = ".$this->id." AND pb.batch = '".$this->db->escape($batch)."'"; + $sql.= " GROUP BY pb.batch, pb.eatby, pb.sellby"; + dol_syslog(get_class($this)."::loadBatchInfo load first entry found for lot/serial = ".$batch, LOG_DEBUG); + $resql = $this->db->query($sql); + if ($resql) + { + $num = $this->db->num_rows($resql); + $i=0; + while ($i < $num) + { + $obj = $this->db->fetch_object($resql); + $result[]=array('batch'=>$batch, 'eatby'=>$this->db->jdate($obj->eatby), 'sellby'=>$this->db->jdate($obj->sellby), 'qty'=>$obj->qty); + $i++; + } + return $result; + } + else + { + dol_print_error($this->db); + $this->db->rollback(); + return array(); + } + } + + /** * Move an uploaded file described into $file array into target directory $sdir. * @@ -3700,7 +3742,7 @@ class Product extends CommonObject */ function isproduct() { - return ($this->type != Product::TYPE_PRODUCT ? true : false); + return ($this->type == Product::TYPE_PRODUCT ? true : false); } /** @@ -3858,4 +3900,22 @@ class Product extends CommonObject return $maxpricesupplier; } + + /** + * Function used to replace a thirdparty id with another one. + * + * @param DoliDB $db Database handler + * @param int $origin_id Old thirdparty id + * @param int $dest_id New thirdparty id + * @return bool + */ + public static function replaceThirdparty(DoliDB $db, $origin_id, $dest_id) + { + $tables = array( + 'product_customer_price', + 'product_customer_price_log' + ); + + return CommonObject::commonReplaceThirdparty($db, $origin_id, $dest_id, $tables); + } } diff --git a/htdocs/product/class/productbatch.class.php b/htdocs/product/class/productbatch.class.php index d6d848b8ef1..ee49302407d 100644 --- a/htdocs/product/class/productbatch.class.php +++ b/htdocs/product/class/productbatch.class.php @@ -462,7 +462,7 @@ class Productbatch extends CommonObject /** * Return all batch detail records for given product and warehouse * - * @param obj $db database object + * @param DoliDB $db database object * @param int $fk_product_stock id product_stock for objet * @param int $with_qty doesn't return line with 0 quantity * @return int <0 if KO, >0 if OK diff --git a/htdocs/product/class/propalmergepdfproduct.class.php b/htdocs/product/class/propalmergepdfproduct.class.php new file mode 100644 index 00000000000..b2b7296d311 --- /dev/null +++ b/htdocs/product/class/propalmergepdfproduct.class.php @@ -0,0 +1,656 @@ + + * Copyright (C) 2015 Florian HENRY + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/** + * \file htdocs/product/class/propalmergepdfproduct.class.php + * \ingroup product + * \brief This file is an CRUD class file (Create/Read/Update/Delete) + */ + +require_once(DOL_DOCUMENT_ROOT."/core/class/commonobject.class.php"); + + + +/** + * Put here description of your class + */ +class Propalmergepdfproduct extends CommonObject +{ + var $db; //!< To store db handler + var $error; //!< To return error code (or message) + var $errors=array(); //!< To return several error codes (or messages) + var $element='propal_merge_pdf_product'; //!< Id that identify managed objects + var $table_element='propal_merge_pdf_product'; //!< Name of table without prefix where object is stored + + var $id; + + var $fk_product; + var $file_name; + var $fk_user_author; + var $fk_user_mod; + var $datec=''; + var $tms=''; + var $import_key; + var $lang; + + var $lines=array(); + + + + + /** + * Constructor + * + * @param DoliDb $db Database handler + */ + function __construct($db) + { + $this->db = $db; + return 1; + } + + + /** + * Create object into database + * + * @param User $user User that creates + * @param int $notrigger 0=launch triggers after, 1=disable triggers + * @return int <0 if KO, Id of created object if OK + */ + function create($user, $notrigger=0) + { + global $conf, $langs; + $error=0; + + // Clean parameters + + if (isset($this->fk_product)) $this->fk_product=trim($this->fk_product); + if (isset($this->file_name)) $this->file_name=trim($this->file_name); + if (isset($this->fk_user_author)) $this->fk_user_author=trim($this->fk_user_author); + if (isset($this->fk_user_mod)) $this->fk_user_mod=trim($this->fk_user_mod); + if (isset($this->lang)) $this->lang=trim($this->lang); + if (isset($this->import_key)) $this->import_key=trim($this->import_key); + + + + // Check parameters + // Put here code to add control on parameters values + + // Insert request + $sql = "INSERT INTO ".MAIN_DB_PREFIX."propal_merge_pdf_product("; + + $sql.= "fk_product,"; + $sql.= "file_name,"; + if ($conf->global->MAIN_MULTILANGS) { + $sql.= "lang,"; + } + $sql.= "fk_user_author,"; + $sql.= "fk_user_mod,"; + $sql.= "datec"; + + + $sql.= ") VALUES ("; + + $sql.= " ".(! isset($this->fk_product)?'NULL':"'".$this->fk_product."'").","; + $sql.= " ".(! isset($this->file_name)?'NULL':"'".$this->db->escape($this->file_name)."'").","; + if ($conf->global->MAIN_MULTILANGS) { + $sql.= " ".(! isset($this->lang)?'NULL':"'".$this->db->escape($this->lang)."'").","; + } + $sql.= " ".$user->id.","; + $sql.= " ".$user->id.","; + $sql.= " '".$this->db->idate(dol_now())."'"; + + + $sql.= ")"; + + $this->db->begin(); + + dol_syslog(get_class($this)."::".__METHOD__, LOG_DEBUG); + $resql=$this->db->query($sql); + if (! $resql) { $error++; $this->errors[]="Error ".$this->db->lasterror(); } + + if (! $error) + { + $this->id = $this->db->last_insert_id(MAIN_DB_PREFIX."propal_merge_pdf_product"); + + if (! $notrigger) + { + // Uncomment this and change MYOBJECT to your own tag if you + // want this action calls a trigger. + + //// Call triggers + //include_once DOL_DOCUMENT_ROOT . '/core/class/interfaces.class.php'; + //$interface=new Interfaces($this->db); + //$result=$interface->run_triggers('MYOBJECT_CREATE',$this,$user,$langs,$conf); + //if ($result < 0) { $error++; $this->errors=$interface->errors; } + //// End call triggers + } + } + + // Commit or rollback + if ($error) + { + foreach($this->errors as $errmsg) + { + dol_syslog(get_class($this)."::create ".$errmsg, LOG_ERR); + $this->error.=($this->error?', '.$errmsg:$errmsg); + } + $this->db->rollback(); + return -1*$error; + } + else + { + $this->db->commit(); + return $this->id; + } + } + + + /** + * Load object in memory from the database + * + * @param int $id Id object + * @return int <0 if KO, >0 if OK + */ + function fetch($id) + { + global $langs,$conf; + + $sql = "SELECT"; + $sql.= " t.rowid,"; + + $sql.= " t.fk_product,"; + $sql.= " t.file_name,"; + $sql.= " t.lang,"; + $sql.= " t.fk_user_author,"; + $sql.= " t.fk_user_mod,"; + $sql.= " t.datec,"; + $sql.= " t.tms,"; + $sql.= " t.import_key"; + + + $sql.= " FROM ".MAIN_DB_PREFIX."propal_merge_pdf_product as t"; + $sql.= " WHERE t.rowid = ".$id; + + dol_syslog(get_class($this)."::".__METHOD__, LOG_DEBUG); + $resql=$this->db->query($sql); + if ($resql) + { + if ($this->db->num_rows($resql)) + { + $obj = $this->db->fetch_object($resql); + + $this->id = $obj->rowid; + + $this->fk_product = $obj->fk_product; + $this->file_name = $obj->file_name; + if ($conf->global->MAIN_MULTILANGS) { + $this->lang = $obj->lang; + } + $this->fk_user_author = $obj->fk_user_author; + $this->fk_user_mod = $obj->fk_user_mod; + $this->datec = $this->db->jdate($obj->datec); + $this->tms = $this->db->jdate($obj->tms); + $this->import_key = $obj->import_key; + + + } + $this->db->free($resql); + + return 1; + } + else + { + $this->error="Error ".$this->db->lasterror(); + dol_syslog(get_class($this)."::fetch ".$this->error, LOG_ERR); + return -1; + } + } + + /** + * Load object in memory from the database + * + * @param int $id Id object + * @param string $lang lang string id + * @return int <0 if KO, >0 if OK + */ + function fetch_by_product($product_id, $lang='') + { + global $langs,$conf; + + $sql = "SELECT"; + $sql.= " t.rowid,"; + + $sql.= " t.fk_product,"; + $sql.= " t.file_name,"; + $sql.= " t.lang,"; + $sql.= " t.fk_user_author,"; + $sql.= " t.fk_user_mod,"; + $sql.= " t.datec,"; + $sql.= " t.tms,"; + $sql.= " t.import_key"; + + + $sql.= " FROM ".MAIN_DB_PREFIX."propal_merge_pdf_product as t"; + $sql.= " WHERE t.fk_product = ".$product_id; + if ($conf->global->MAIN_MULTILANGS && !empty($lang)) { + $sql.= " AND t.lang = '".$lang."'"; + } + + dol_syslog(get_class($this)."::".__METHOD__, LOG_DEBUG); + $resql=$this->db->query($sql); + if ($resql) + { + if ($this->db->num_rows($resql)) + { + while($obj = $this->db->fetch_object($resql)) { + + $line = new PropalmergepdfproductLine(); + + $line->id = $obj->rowid; + + $line->fk_product = $obj->fk_product; + $line->file_name = $obj->file_name; + if ($conf->global->MAIN_MULTILANGS) { + $line->lang = $obj->lang; + } + $line->fk_user_author = $obj->fk_user_author; + $line->fk_user_mod = $obj->fk_user_mod; + $line->datec = $this->db->jdate($obj->datec); + $line->tms = $this->db->jdate($obj->tms); + $line->import_key = $obj->import_key; + + + if ($conf->global->MAIN_MULTILANGS) { + $this->lines[$obj->file_name.'_'.$obj->lang]=$line; + }else { + $this->lines[$obj->file_name]=$line; + } + + + } + + + } + $this->db->free($resql); + + return 1; + } + else + { + $this->error="Error ".$this->db->lasterror(); + dol_syslog(get_class($this)."::fetch_by_product ".$this->error, LOG_ERR); + return -1; + } + } + + + /** + * Update object into database + * + * @param User $user User that modifies + * @param int $notrigger 0=launch triggers after, 1=disable triggers + * @return int <0 if KO, >0 if OK + */ + function update($user=0, $notrigger=0) + { + global $conf, $langs; + $error=0; + + // Clean parameters + + if (isset($this->fk_product)) $this->fk_product=trim($this->fk_product); + if (isset($this->file_name)) $this->file_name=trim($this->file_name); + if (isset($this->fk_user_mod)) $this->fk_user_mod=trim($this->fk_user_mod); + if (isset($this->lang)) $this->lang=trim($this->lang); + + + + + // Check parameters + // Put here code to add a control on parameters values + + // Update request + $sql = "UPDATE ".MAIN_DB_PREFIX."propal_merge_pdf_product SET"; + + $sql.= " fk_product=".(isset($this->fk_product)?$this->fk_product:"null").","; + $sql.= " file_name=".(isset($this->file_name)?"'".$this->db->escape($this->file_name)."'":"null").","; + if ($conf->global->MAIN_MULTILANGS) { + $sql.= " lang=".(isset($this->lang)?"'".$this->db->escape($this->lang)."'":"null").","; + } + $sql.= " fk_user_mod=".$user->id; + + + $sql.= " WHERE rowid=".$this->id; + + $this->db->begin(); + + dol_syslog(get_class($this)."::".__METHOD__, LOG_DEBUG); + $resql = $this->db->query($sql); + if (! $resql) { $error++; $this->errors[]="Error ".$this->db->lasterror(); } + + if (! $error) + { + if (! $notrigger) + { + // Uncomment this and change MYOBJECT to your own tag if you + // want this action calls a trigger. + + //// Call triggers + //include_once DOL_DOCUMENT_ROOT . '/core/class/interfaces.class.php'; + //$interface=new Interfaces($this->db); + //$result=$interface->run_triggers('MYOBJECT_MODIFY',$this,$user,$langs,$conf); + //if ($result < 0) { $error++; $this->errors=$interface->errors; } + //// End call triggers + } + } + + // Commit or rollback + if ($error) + { + foreach($this->errors as $errmsg) + { + dol_syslog(get_class($this)."::update ".$errmsg, LOG_ERR); + $this->error.=($this->error?', '.$errmsg:$errmsg); + } + $this->db->rollback(); + return -1*$error; + } + else + { + $this->db->commit(); + return 1; + } + } + + + /** + * Delete object in database + * + * @param User $user User that deletes + * @param int $notrigger 0=launch triggers after, 1=disable triggers + * @return int <0 if KO, >0 if OK + */ + function delete($user, $notrigger=0) + { + global $conf, $langs; + $error=0; + + $this->db->begin(); + + if (! $error) + { + if (! $notrigger) + { + // Uncomment this and change MYOBJECT to your own tag if you + // want this action calls a trigger. + + //// Call triggers + //include_once DOL_DOCUMENT_ROOT . '/core/class/interfaces.class.php'; + //$interface=new Interfaces($this->db); + //$result=$interface->run_triggers('MYOBJECT_DELETE',$this,$user,$langs,$conf); + //if ($result < 0) { $error++; $this->errors=$interface->errors; } + //// End call triggers + } + } + + if (! $error) + { + $sql = "DELETE FROM ".MAIN_DB_PREFIX."propal_merge_pdf_product"; + $sql.= " WHERE rowid=".$this->id; + + dol_syslog(get_class($this)."::".__METHOD__, LOG_DEBUG); + $resql = $this->db->query($sql); + if (! $resql) { $error++; $this->errors[]="Error ".$this->db->lasterror(); } + } + + // Commit or rollback + if ($error) + { + foreach($this->errors as $errmsg) + { + dol_syslog(get_class($this)."::delete ".$errmsg, LOG_ERR); + $this->error.=($this->error?', '.$errmsg:$errmsg); + } + $this->db->rollback(); + return -1*$error; + } + else + { + $this->db->commit(); + return 1; + } + } + + /** + * Delete object in database + * + * @param User $user User that deletes + * @param int $product_id product_id + * @param string $lang_id language + * @param int $notrigger 0=launch triggers after, 1=disable triggers + * @return int <0 if KO, >0 if OK + */ + function delete_by_product($user, $product_id, $lang_id='', $notrigger=0) + { + global $conf, $langs; + $error=0; + + $this->db->begin(); + + if (! $error) + { + if (! $notrigger) + { + // Uncomment this and change MYOBJECT to your own tag if you + // want this action calls a trigger. + + //// Call triggers + //include_once DOL_DOCUMENT_ROOT . '/core/class/interfaces.class.php'; + //$interface=new Interfaces($this->db); + //$result=$interface->run_triggers('MYOBJECT_DELETE',$this,$user,$langs,$conf); + //if ($result < 0) { $error++; $this->errors=$interface->errors; } + //// End call triggers + } + } + + if (! $error) + { + $sql = "DELETE FROM ".MAIN_DB_PREFIX."propal_merge_pdf_product"; + $sql.= " WHERE fk_product=".$product_id; + + if ($conf->global->MAIN_MULTILANGS && !empty($lang_id)) { + $sql.= " AND lang='".$lang_id."'"; + } + + dol_syslog(get_class($this)."::".__METHOD__, LOG_DEBUG); + $resql = $this->db->query($sql); + if (! $resql) { $error++; $this->errors[]="Error ".$this->db->lasterror(); } + } + + // Commit or rollback + if ($error) + { + foreach($this->errors as $errmsg) + { + dol_syslog(get_class($this)."::delete ".$errmsg, LOG_ERR); + $this->error.=($this->error?', '.$errmsg:$errmsg); + } + $this->db->rollback(); + return -1*$error; + } + else + { + $this->db->commit(); + return 1; + } + } + + /** + * Delete object in database + * + * @param User $user User that deletes + * @return int <0 if KO, >0 if OK + */ + function delete_by_file($user) + { + global $conf, $langs; + $error=0; + + $this->db->begin(); + + if (! $error) + { + if (! $notrigger) + { + // Uncomment this and change MYOBJECT to your own tag if you + // want this action calls a trigger. + + //// Call triggers + //include_once DOL_DOCUMENT_ROOT . '/core/class/interfaces.class.php'; + //$interface=new Interfaces($this->db); + //$result=$interface->run_triggers('MYOBJECT_DELETE',$this,$user,$langs,$conf); + //if ($result < 0) { $error++; $this->errors=$interface->errors; } + //// End call triggers + } + } + + if (! $error) + { + $sql = "DELETE FROM ".MAIN_DB_PREFIX."propal_merge_pdf_product"; + $sql.= " WHERE fk_product=".$this->fk_product." AND file_name='".$this->db->escape($this->file_name)."'"; + + dol_syslog(get_class($this)."::".__METHOD__, LOG_DEBUG); + $resql = $this->db->query($sql); + if (! $resql) { $error++; $this->errors[]="Error ".$this->db->lasterror(); } + } + + // Commit or rollback + if ($error) + { + foreach($this->errors as $errmsg) + { + dol_syslog(get_class($this)."::delete ".$errmsg, LOG_ERR); + $this->error.=($this->error?', '.$errmsg:$errmsg); + } + $this->db->rollback(); + return -1*$error; + } + else + { + $this->db->commit(); + return 1; + } + } + + + + /** + * Load an object from its id and create a new one in database + * + * @param int $fromid Id of object to clone + * @return int New id of clone + */ + function createFromClone($fromid) + { + global $user,$langs; + + $error=0; + + $object=new Propalmergepdfproduct($this->db); + + $this->db->begin(); + + // Load source object + $object->fetch($fromid); + $object->id=0; + $object->statut=0; + + // Clear fields + // ... + + // Create clone + $result=$object->create($user); + + // Other options + if ($result < 0) + { + $this->error=$object->error; + $error++; + } + + if (! $error) + { + + + } + + // End + if (! $error) + { + $this->db->commit(); + return $object->id; + } + else + { + $this->db->rollback(); + return -1; + } + } + + + /** + * Initialise object with example values + * Id must be 0 if object instance is a specimen + * + * @return void + */ + function initAsSpecimen() + { + $this->id=0; + + $this->fk_product=''; + $this->file_name=''; + $this->fk_user_author=''; + $this->fk_user_mod=''; + $this->datec=''; + $this->tms=''; + $this->import_key=''; + + + } + +} + +class PropalmergepdfproductLine{ + var $id; + + var $fk_product; + var $file_name; + var $lang; + var $fk_user_author; + var $fk_user_mod; + var $datec=''; + var $tms=''; + var $import_key; + + function __construct() { + return 1; + } + +} diff --git a/htdocs/product/composition/card.php b/htdocs/product/composition/card.php index 96f2a589429..773d08fae72 100644 --- a/htdocs/product/composition/card.php +++ b/htdocs/product/composition/card.php @@ -174,7 +174,7 @@ if ($action == 'search') llxHeader("","",$langs->trans("CardProduct".$object->type)); -$head=product_prepare_head($object, $user); +$head=product_prepare_head($object); $titre=$langs->trans("CardProduct".$object->type); $picto=($object->type==Product::TYPE_SERVICE?'service':'product'); dol_fiche_head($head, 'subproduct', $titre, 0, $picto); @@ -268,7 +268,7 @@ if ($id > 0 || ! empty($ref)) $productstatic->type=$value["fk_product_type"]; $productstatic->ref=$value['label']; print ''; - print ''.$productstatic->getNomUrl(1,'composition').'';; + print ''.$productstatic->getNomUrl(1,'composition').''; print ''; } print ''; diff --git a/htdocs/product/document.php b/htdocs/product/document.php index 9a71eac4f55..615f4accf70 100644 --- a/htdocs/product/document.php +++ b/htdocs/product/document.php @@ -33,6 +33,8 @@ require_once DOL_DOCUMENT_ROOT.'/product/class/product.class.php'; require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php'; require_once DOL_DOCUMENT_ROOT.'/core/lib/images.lib.php'; require_once DOL_DOCUMENT_ROOT.'/core/class/html.formfile.class.php'; +if (!empty($conf->global->PRODUIT_PDF_MERGE_PROPAL)) + require_once DOL_DOCUMENT_ROOT.'/product/class/propalmergepdfproduct.class.php'; $langs->load("other"); $langs->load("products"); @@ -84,8 +86,70 @@ if ($reshook < 0) setEventMessages($hookmanager->error, $hookmanager->errors, 'e if (empty($reshook)) { + //Delete line if product propal merge is linked to a file + if (!empty($conf->global->PRODUIT_PDF_MERGE_PROPAL)) { + if ($action == 'confirm_deletefile' && $confirm == 'yes') + { + print 'toto'; + //extract file name + $urlfile = GETPOST('urlfile', 'alpha'); + $filename = basename($urlfile); + $filetomerge = new Propalmergepdfproduct($db); + $filetomerge->fk_product=$object->id; + $filetomerge->file_name=$filename; + $result=$filetomerge->delete_by_file($user); + if ($result<0) { + setEventMessage($filetomerge->error,'errors'); + } + } + } + // Action sending file include_once DOL_DOCUMENT_ROOT.'/core/tpl/document_actions_pre_headers.tpl.php'; + +} + +if ($action=='filemerge') { + $is_refresh = GETPOST('refresh'); + if (empty($is_refresh)) { + + $filetomerge_file_array = GETPOST('filetoadd'); + + $filetomerge_file_array = GETPOST('filetoadd'); + + if ($conf->global->MAIN_MULTILANGS) { + $lang_id = GETPOST('lang_id'); + } + + // Delete all file already associated + $filetomerge = new Propalmergepdfproduct($db); + + if ($conf->global->MAIN_MULTILANGS) { + $result=$filetomerge->delete_by_product($user, $object->id, $lang_id); + } else { + $result=$filetomerge->delete_by_product($user, $object->id); + } + if ($result<0) { + setEventMessage($filetomerge->error,'errors'); + } + + // for each file checked add it to the product + if (is_array($filetomerge_file_array)) { + foreach ( $filetomerge_file_array as $filetomerge_file ) { + $filetomerge->fk_product = $object->id; + $filetomerge->file_name = $filetomerge_file; + + if ($conf->global->MAIN_MULTILANGS) { + $filetomerge->lang = $lang_id; + } + + $result=$filetomerge->create($user); + if ($result<0) { + setEventMessage($filetomerge->error,'errors'); + } + } + } + } } @@ -100,7 +164,7 @@ llxHeader("","",$langs->trans("CardProduct".$object->type)); if ($object->id) { - $head=product_prepare_head($object, $user); + $head=product_prepare_head($object); $titre=$langs->trans("CardProduct".$object->type); $picto=($object->type== Product::TYPE_SERVICE?'service':'product'); dol_fiche_head($head, 'documents', $titre, 0, $picto); @@ -142,13 +206,139 @@ if ($object->id) print ''.$langs->trans("NbOfAttachedFiles").''.count($filearray).''; print ''.$langs->trans("TotalSizeOfAttachedFiles").''.$totalsize.' '.$langs->trans("bytes").''; print ''; - + print '
'; $modulepart = 'produit'; $permission = (($object->type == Product::TYPE_PRODUCT && $user->rights->produit->creer) || ($object->type == Product::TYPE_SERVICE && $user->rights->service->creer)); $param = '&id=' . $object->id; include_once DOL_DOCUMENT_ROOT . '/core/tpl/document_actions_post_headers.tpl.php'; + + + //Merge propal PDF docuemnt PDF files + if (!empty($conf->global->PRODUIT_PDF_MERGE_PROPAL)) + { + $filetomerge = new Propalmergepdfproduct($db); + + if ($conf->global->MAIN_MULTILANGS) { + $lang_id = GETPOST('lang_id'); + $result = $filetomerge->fetch_by_product($object->id, $lang_id); + } else { + $result = $filetomerge->fetch_by_product($object->id); + } + + $form = new Form($db); + + $filearray = dol_dir_list($upload_dir, "files", 0, '', '\.meta$', 'name', SORT_ASC, 1); + + // For each file build select list with PDF extention + if (count($filearray) > 0) { + print '
'; + // Actual file to merge is : + if (count($filetomerge->lines) > 0) { + print $langs->trans('PropalMergePdfProductActualFile'); + } + + print '
'; + print ''; + print ''; + if (count($filetomerge->lines) == 0) { + print $langs->trans('PropalMergePdfProductChooseFile'); + } + + print ''; + + // Get language + if ($conf->global->MAIN_MULTILANGS) { + + $langs->load("languages"); + + print ''; + } + + $style = 'impair'; + foreach ( $filearray as $filetoadd ) { + + if ($ext = pathinfo($filetoadd['name'], PATHINFO_EXTENSION) == 'pdf') { + + if ($style == 'pair') { + $style = 'impair'; + } else { + $style = 'pair'; + } + + $checked = ''; + $filename = $filetoadd['name']; + + if ($conf->global->MAIN_MULTILANGS) { + if (array_key_exists($filetoadd['name'] . '_' . $delauft_lang, $filetomerge->lines)) { + $filename = $filetoadd['name'] . ' - ' . $langs->trans('Language_' . $delauft_lang); + $checked = ' checked="checked" '; + } + } else { + if (array_key_exists($filetoadd['name'], $filetomerge->lines)) { + $checked = ' checked="checked" '; + } + } + + print ''; + } + } + print ''; + print '
'; + + $delauft_lang = (empty($lang_id)) ? $langs->getDefaultLang() : $lang_id; + + $langs_available = $langs->get_available_languages(DOL_DOCUMENT_ROOT, 12); + + print ''; + + if ($conf->global->MAIN_MULTILANGS) { + print ''; + } + + print '
'; + + print '' . $filename . ''; + print '
'; + + print ''; + print '
'; + + print '
'; + } + } + } else { @@ -157,4 +347,4 @@ else llxFooter(); -$db->close(); +$db->close(); \ No newline at end of file diff --git a/htdocs/product/fournisseurs.php b/htdocs/product/fournisseurs.php index c2196aba00b..9d7a9215ef1 100644 --- a/htdocs/product/fournisseurs.php +++ b/htdocs/product/fournisseurs.php @@ -43,6 +43,7 @@ $id = GETPOST('id', 'int'); $ref = GETPOST('ref', 'alpha'); $rowid=GETPOST('rowid','int'); $action=GETPOST('action', 'alpha'); +$cancel=GETPOST('cancel', 'alpha'); $socid=GETPOST('socid', 'int'); $backtopage=GETPOST('backtopage','alpha'); $error=0; @@ -77,6 +78,8 @@ if (! $sortorder) $sortorder="ASC"; * Actions */ +if ($cancel) $action=''; + $parameters=array('socid'=>$socid, 'id_prod'=>$id); $reshook=$hookmanager->executeHooks('doActions',$parameters,$product,$action); // Note that $action and $object may have been modified by some hooks if ($reshook < 0) setEventMessages($hookmanager->error, $hookmanager->errors, 'errors'); @@ -97,59 +100,70 @@ if (empty($reshook)) } } -if ($action == 'updateprice' && GETPOST('cancel') <> $langs->trans("Cancel")) -{ - $id_fourn=GETPOST("id_fourn"); - if (empty($id_fourn)) $id_fourn=GETPOST("search_id_fourn"); - $ref_fourn=GETPOST("ref_fourn"); - if (empty($ref_fourn)) $ref_fourn=GETPOST("search_ref_fourn"); - $quantity=GETPOST("qty"); - $remise_percent=price2num(GETPOST('remise_percent','alpha')); - $npr = preg_match('/\*/', $_POST['tva_tx']) ? 1 : 0 ; - $tva_tx = str_replace('*','', GETPOST('tva_tx','alpha')); - $tva_tx = price2num($tva_tx); - $price_expression = GETPOST('eid', 'int') ? GETPOST('eid', 'int') : ''; // Discard expression if not in expression mode - $delivery_time_days = GETPOST('delivery_time_days', 'int') ? GETPOST('delivery_time_days', 'int') : ''; + if ($action == 'updateprice') + { + $id_fourn=GETPOST("id_fourn"); + if (empty($id_fourn)) $id_fourn=GETPOST("search_id_fourn"); + $ref_fourn=GETPOST("ref_fourn"); + if (empty($ref_fourn)) $ref_fourn=GETPOST("search_ref_fourn"); + $quantity=GETPOST("qty"); + $remise_percent=price2num(GETPOST('remise_percent','alpha')); + $npr = preg_match('/\*/', $_POST['tva_tx']) ? 1 : 0 ; + $tva_tx = str_replace('*','', GETPOST('tva_tx','alpha')); + $tva_tx = price2num($tva_tx); + $price_expression = GETPOST('eid', 'int') ? GETPOST('eid', 'int') : ''; // Discard expression if not in expression mode + $delivery_time_days = GETPOST('delivery_time_days', 'int') ? GETPOST('delivery_time_days', 'int') : ''; - if ($tva_tx == '') - { - $error++; - setEventMessage($langs->trans("ErrorFieldRequired",$langs->transnoentities("VATRateForSupplierProduct")), 'errors'); - } - if (empty($quantity)) - { - $error++; - setEventMessage($langs->trans("ErrorFieldRequired",$langs->transnoentities("Qty")), 'errors'); - } - if (empty($ref_fourn)) - { - $error++; - setEventMessage($langs->trans("ErrorFieldRequired",$langs->transnoentities("RefSupplier")), 'errors'); - } - if ($id_fourn <= 0) - { - $error++; - setEventMessage($langs->trans("ErrorFieldRequired",$langs->transnoentities("Supplier")), 'errors'); - } - if ($_POST["price"] < 0 || $_POST["price"] == '') - { - if ($price_expression === '') // Return error of missing price only if price_expression not set + if ($tva_tx == '') { $error++; - setEventMessage($langs->trans("ErrorFieldRequired",$langs->transnoentities("Price")), 'errors'); + $langs->load("errors"); + setEventMessage($langs->trans("ErrorFieldRequired",$langs->transnoentities("VATRateForSupplierProduct")), 'errors'); } - else + if (! is_numeric($tva_tx)) { - $_POST["price"] = 0; + $error++; + $langs->load("errors"); + setEventMessage($langs->trans("ErrorFieldMustBeANumeric",'eeee'), 'errors'); } - } - + if (empty($quantity)) + { + $error++; + $langs->load("errors"); + setEventMessage($langs->trans("ErrorFieldRequired",$langs->transnoentities("Qty")), 'errors'); + } + if (empty($ref_fourn)) + { + $error++; + $langs->load("errors"); + setEventMessage($langs->trans("ErrorFieldRequired",$langs->transnoentities("RefSupplier")), 'errors'); + } + if ($id_fourn <= 0) + { + $error++; + $langs->load("errors"); + setEventMessage($langs->trans("ErrorFieldRequired",$langs->transnoentities("Supplier")), 'errors'); + } + if ($_POST["price"] < 0 || $_POST["price"] == '') + { + if ($price_expression === '') // Return error of missing price only if price_expression not set + { + $error++; + $langs->load("errors"); + setEventMessage($langs->trans("ErrorFieldRequired",$langs->transnoentities("Price")), 'errors'); + } + else + { + $_POST["price"] = 0; + } + } + $product = new ProductFournisseur($db); $result=$product->fetch($id); if ($result <= 0) { $error++; - setEventMessage($product->error, 'errors'); + setEventMessages($product->error, $product->errors, 'errors'); } if (! $error) @@ -187,11 +201,11 @@ if ($action == 'updateprice' && GETPOST('cancel') <> $langs->trans("Cancel")) { $error++; - setEventMessage($product->error, 'errors'); + setEventMessage($product->error, $product->errors, 'errors'); } else { - if ($price_expression !== '') + if ($price_expression !== '') { //Check the expression validity by parsing it $priceparser = new PriceParser($db); @@ -222,13 +236,10 @@ if ($action == 'updateprice' && GETPOST('cancel') <> $langs->trans("Cancel")) $db->rollback(); } } - } - - if (GETPOST('cancel') == $langs->trans("Cancel")) - { - $action = ''; - header("Location: fournisseurs.php?id=".$_GET["id"]); - exit; + else + { + $action = 'add_price'; + } } } @@ -253,11 +264,7 @@ if ($id || $ref) { if ($action <> 'edit' && $action <> 're-edit') { - /* - * En mode visu - */ - - $head=product_prepare_head($product, $user); + $head=product_prepare_head($product); $titre=$langs->trans("CardProduct".$product->type); $picto=($product->type== Product::TYPE_SERVICE?'service':'product'); dol_fiche_head($head, 'suppliers', $titre, 0, $picto); @@ -323,8 +330,10 @@ if ($id || $ref) $supplier->fetch($socid); print $supplier->getNomUrl(1); print ''; - print ''; + print ''; print ''; + print ''; + print ''; } else { @@ -380,7 +389,7 @@ if ($id || $ref) { print ''; } - print ''; + print ''; // Vat rate $default_vat=''; @@ -450,7 +459,7 @@ if ($id || $ref) print ''; print ''; - + // Delai livraison jours print ''; print ''.$langs->trans('NbDaysToDelivery').''; @@ -487,11 +496,7 @@ if ($id || $ref) print ''; } - /* ************************************************************************** */ - /* */ - /* Barre d'action */ - /* */ - /* ************************************************************************** */ + // Actions buttons print "\n
\n"; @@ -523,13 +528,9 @@ if ($id || $ref) print_liste_field_titre($langs->trans("QtyMin"),$_SERVER["PHP_SELF"],"pfp.quantity","",$param,'align="right"',$sortfield,$sortorder); print ''.$langs->trans("VATRate").''; print ''.$langs->trans("PriceQtyMinHT").''; - // Charges ???? - if ($conf->global->PRODUCT_CHARGES) - { - if (! empty($conf->margin->enabled)) print ''.$langs->trans("Charges").''; - } print_liste_field_titre($langs->trans("UnitPriceHT"),$_SERVER["PHP_SELF"],"pfp.unitprice","",$param,'align="right"',$sortfield,$sortorder); print ''.$langs->trans("DiscountQtyMin").''; + print_liste_field_titre($langs->trans("NbDaysToDelivery"),$_SERVER["PHP_SELF"],"pfp.delivery_time_days","",$param,'align="right"',$sortfield,$sortorder); // Charges ???? if ($conf->global->PRODUCT_CHARGES) { @@ -601,6 +602,11 @@ if ($id || $ref) print price2num($productfourn->fourn_remise_percent).'%'; print ''; + // Delivery delay + print ''; + print $productfourn->delivery_time_days; + print ''; + // Charges ???? if ($conf->global->PRODUCT_CHARGES) { diff --git a/htdocs/product/index.php b/htdocs/product/index.php index 90ec2e76fd1..b98470b272d 100644 --- a/htdocs/product/index.php +++ b/htdocs/product/index.php @@ -1,6 +1,6 @@ - * Copyright (C) 2004-2011 Laurent Destailleur + * Copyright (C) 2004-2015 Laurent Destailleur * Copyright (C) 2005-2014 Regis Houssin * Copyright (C) 2014 Charles-Fr BENKE * @@ -383,7 +383,6 @@ function activitytrim($product_type) $result = $db->query($sql); if ($result) { - //$tmpyear=$beginyear; // FIXME $beginyear is not defined $tmpyear=0; $trim1=0; $trim2=0; diff --git a/htdocs/product/list.php b/htdocs/product/list.php index f9503778411..ededdbaff01 100644 --- a/htdocs/product/list.php +++ b/htdocs/product/list.php @@ -476,8 +476,11 @@ else { if ($product_fourn->product_fourn_price_id > 0) { - $htmltext=$product_fourn->display_price_product_fournisseur(); - if (! empty($conf->fournisseur->enabled) && $user->rights->fournisseur->lire) print $form->textwithpicto(price($product_fourn->fourn_unitprice).' '.$langs->trans("HT"),$htmltext); + if (! empty($conf->fournisseur->enabled) && $user->rights->fournisseur->lire) + { + $htmltext=$product_fourn->display_price_product_fournisseur(1, 1, 0, 1); + print $form->textwithpicto(price($product_fourn->fourn_unitprice).' '.$langs->trans("HT"),$htmltext); + } else print price($product_fourn->fourn_unitprice).' '.$langs->trans("HT"); } } diff --git a/htdocs/product/photos.php b/htdocs/product/photos.php index 8a6e2ddbd6b..c6245cf203c 100644 --- a/htdocs/product/photos.php +++ b/htdocs/product/photos.php @@ -100,7 +100,7 @@ if ($object->id) /* * En mode visu */ - $head=product_prepare_head($object, $user); + $head=product_prepare_head($object); $titre=$langs->trans("CardProduct".$object->type); $picto=($object->type== Product::TYPE_SERVICE?'service':'product'); dol_fiche_head($head, 'photos', $titre, 0, $picto); diff --git a/htdocs/product/price.php b/htdocs/product/price.php index 3e7ba24d3dd..2c9ab9a7794 100644 --- a/htdocs/product/price.php +++ b/htdocs/product/price.php @@ -353,7 +353,7 @@ if (! empty($id) || ! empty($ref)) llxHeader("", "", $langs->trans("CardProduct" . $object->type)); -$head = product_prepare_head($object, $user); +$head = product_prepare_head($object); $titre = $langs->trans("CardProduct" . $object->type); $picto = ($object->type == Product::TYPE_SERVICE ? 'service' : 'product'); dol_fiche_head($head, 'price', $titre, 0, $picto); diff --git a/htdocs/product/reassort.php b/htdocs/product/reassort.php index ab184cdf943..be38eda6b2d 100644 --- a/htdocs/product/reassort.php +++ b/htdocs/product/reassort.php @@ -1,6 +1,6 @@ - * Copyright (C) 2004-2011 Laurent Destailleur + * Copyright (C) 2004-2015 Laurent Destailleur * Copyright (C) 2005-2012 Regis Houssin * Copyright (C) 2013 Cédric Salvador * @@ -102,13 +102,12 @@ $title=$langs->trans("ProductsAndServices"); $sql = 'SELECT p.rowid, p.ref, p.label, p.barcode, p.price, p.price_ttc, p.price_base_type,'; $sql.= ' p.fk_product_type, p.tms as datem,'; -$sql.= ' p.duration, p.tosell as statut, p.tobuy, p.seuil_stock_alerte,'; +$sql.= ' p.duration, p.tosell as statut, p.tobuy, p.seuil_stock_alerte, p.desiredstock,'; $sql.= ' SUM(s.reel) as stock_physique'; -$sql .= ', p.desiredstock'; -$sql.= ' FROM ('.MAIN_DB_PREFIX.'product as p'; +$sql.= ' FROM '.MAIN_DB_PREFIX.'product as p'; +$sql.= ' LEFT JOIN '.MAIN_DB_PREFIX.'product_stock as s on p.rowid = s.fk_product'; // We'll need this table joined to the select in order to filter by categ if ($search_categ) $sql.= ", ".MAIN_DB_PREFIX."categorie_product as cp"; -$sql.= ') LEFT JOIN '.MAIN_DB_PREFIX.'product_stock as s on p.rowid = s.fk_product'; $sql.= " WHERE p.entity IN (".getEntity('product', 1).")"; if ($search_categ) $sql.= " AND p.rowid = cp.fk_product"; // Join for the needed table to filter by categ if ($sall) @@ -156,10 +155,8 @@ if ($search_categ) $sql .= " AND cp.fk_categorie = ".$db->escape($search_categ); } $sql.= " GROUP BY p.rowid, p.ref, p.label, p.barcode, p.price, p.price_ttc, p.price_base_type,"; -$sql.= " p.fk_product_type, p.tms,"; -$sql.= " p.duration, p.tosell, p.tobuy, p.seuil_stock_alerte"; -$sql .= ", p.desiredstock"; -if ($toolowstock) $sql.= " HAVING SUM(s.reel) < p.seuil_stock_alerte"; // Not used yet +$sql.= " p.fk_product_type, p.tms, p.duration, p.tosell, p.tobuy, p.seuil_stock_alerte, p.desiredstock"; +if ($toolowstock) $sql.= " HAVING SUM(".$db->ifsql('s.reel IS NULL', '0', 's.reel').") < p.seuil_stock_alerte"; // Not used yet $sql.= $db->order($sortfield,$sortorder); $sql.= $db->plimit($limit + 1, $offset); $resql = $db->query($sql); @@ -247,19 +244,19 @@ if ($resql) print_liste_field_titre($langs->trans("DesiredStock"), $_SERVER["PHP_SELF"], "p.desiredstock",$param,"",'align="right"',$sortfield,$sortorder); print_liste_field_titre($langs->trans("PhysicalStock"), $_SERVER["PHP_SELF"], "stock_physique",$param,"",'align="right"',$sortfield,$sortorder); // TODO Add info of running suppliers/customers orders - //print_liste_field_titre($langs->trans("TheoreticalStock"),"reassort.php", "stock_theorique",$param,"",'align="right"',$sortfield,$sortorder); + //print_liste_field_titre($langs->trans("TheoreticalStock"),$_SERVER["PHP_SELF"], "stock_theorique",$param,"",'align="right"',$sortfield,$sortorder); print ' '; - print_liste_field_titre($langs->trans("Sell"),"reassort.php", "p.tosell",$param,"",'align="right"',$sortfield,$sortorder); - print_liste_field_titre($langs->trans("Buy"),"reassort.php", "p.tobuy",$param,"",'align="right"',$sortfield,$sortorder); + print_liste_field_titre($langs->trans("Sell"),$_SERVER["PHP_SELF"], "p.tosell",$param,"",'align="right"',$sortfield,$sortorder); + print_liste_field_titre($langs->trans("Buy"),$_SERVER["PHP_SELF"], "p.tobuy",$param,"",'align="right"',$sortfield,$sortorder); print "\n"; // Lignes des champs de filtre print ''; print ''; - print ''; + print ''; print ''; print ''; - print ''; + print ''; print ''; if (! empty($conf->service->enabled) && $type == 1) { @@ -267,6 +264,7 @@ if ($resql) print ' '; print ''; } + // Lot/Serial print ' '; print ' '; print ' '; diff --git a/htdocs/product/reassortlot.php b/htdocs/product/reassortlot.php new file mode 100644 index 00000000000..451e4302f05 --- /dev/null +++ b/htdocs/product/reassortlot.php @@ -0,0 +1,388 @@ + + * Copyright (C) 2004-2015 Laurent Destailleur + * Copyright (C) 2005-2012 Regis Houssin + * Copyright (C) 2013 Cédric Salvador + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/** + * \file htdocs/product/reassortlot.php + * \ingroup produit + * \brief Page to list stocks + */ + +require '../main.inc.php'; +require_once DOL_DOCUMENT_ROOT.'/product/class/product.class.php'; +require_once DOL_DOCUMENT_ROOT.'/core/class/html.formother.class.php'; +require_once DOL_DOCUMENT_ROOT.'/categories/class/categorie.class.php'; +require_once DOL_DOCUMENT_ROOT.'/product/stock/class/entrepot.class.php'; + +$langs->load("products"); +$langs->load("stocks"); +$langs->load("productbatch"); + +// Security check +if ($user->societe_id) $socid=$user->societe_id; +$result=restrictedArea($user,'produit|service'); + + +$action=GETPOST('action','alpha'); +$sref=GETPOST("sref"); +$snom=GETPOST("snom"); +$sall=GETPOST("sall"); +$type=GETPOST("type","int"); +$sbarcode=GETPOST("sbarcode"); +$search_batch=GETPOST('search_batch'); +$catid=GETPOST('catid','int'); +$toolowstock=GETPOST('toolowstock'); +$tosell = GETPOST("tosell"); +$tobuy = GETPOST("tobuy"); +$fourn_id = GETPOST("fourn_id",'int'); + +$sortfield = GETPOST("sortfield",'alpha'); +$sortorder = GETPOST("sortorder",'alpha'); +$page = GETPOST("page",'int'); +if (! $sortfield) $sortfield="stock_physique"; +if (! $sortorder) $sortorder="ASC"; +$limit = $conf->liste_limit; +$offset = $limit * $page ; + +// Load sale and categ filters +$search_sale = GETPOST("search_sale"); +$search_categ = GETPOST("search_categ"); + +// Get object canvas (By default, this is not defined, so standard usage of dolibarr) +$canvas=GETPOST("canvas"); +$objcanvas=null; +if (! empty($canvas)) +{ + require_once DOL_DOCUMENT_ROOT.'/core/class/canvas.class.php'; + $objcanvas = new Canvas($db,$action); + $objcanvas->getCanvas('product','list',$canvas); +} + +if (! empty($_POST["button_removefilter_x"])) +{ + $sref=""; + $snom=""; + $sall=""; + $search_sale=""; + $search_categ=""; + $type=""; + $catid=''; + $toolowstock=''; +} + + + +/* + * Actions + */ + +// None + + +/* + * View + */ + +$htmlother=new FormOther($db); + +$title=$langs->trans("ProductsAndServices"); + +$sql = 'SELECT p.rowid, p.ref, p.label, p.barcode, p.price, p.price_ttc, p.price_base_type,'; +$sql.= ' p.fk_product_type, p.tms as datem,'; +$sql.= ' p.duration, p.tosell as statut, p.tobuy, p.seuil_stock_alerte, p.desiredstock,'; +$sql.= ' s.fk_entrepot,'; +$sql.= ' pb.batch, pb.eatby, pb.sellby,'; +$sql.= ' SUM(pb.qty) as stock_physique'; +$sql.= ' FROM '.MAIN_DB_PREFIX.'product as p'; +$sql.= ' LEFT JOIN '.MAIN_DB_PREFIX.'product_stock as s on p.rowid = s.fk_product'; +$sql.= ' LEFT JOIN '.MAIN_DB_PREFIX.'product_batch as pb on pb.fk_product_stock = s.rowid'; +// We'll need this table joined to the select in order to filter by categ +if ($search_categ) $sql.= ", ".MAIN_DB_PREFIX."categorie_product as cp"; +$sql.= " WHERE p.entity IN (".getEntity('product', 1).")"; +if ($search_categ) $sql.= " AND p.rowid = cp.fk_product"; // Join for the needed table to filter by categ +if ($sall) +{ + $sql.= " AND (p.ref LIKE '%".$db->escape($sall)."%' OR p.label LIKE '%".$db->escape($sall)."%' OR p.description LIKE '%".$db->escape($sall)."%' OR p.note LIKE '%".$db->escape($sall)."%')"; +} +// if the type is not 1, we show all products (type = 0,2,3) +if (dol_strlen($type)) +{ + if ($type==1) + { + $sql.= " AND p.fk_product_type = '1'"; + } + else + { + $sql.= " AND p.fk_product_type <> '1'"; + } +} +if ($sref) $sql.= " AND p.ref LIKE '%".$sref."%'"; +if ($sbarcode) $sql.= " AND p.barcode LIKE '%".$sbarcode."%'"; +if ($snom) $sql.= " AND p.label LIKE '%".$db->escape($snom)."%'"; +if (! empty($tosell)) +{ + $sql.= " AND p.tosell = ".$tosell; +} +if (! empty($tobuy)) +{ + $sql.= " AND p.tobuy = ".$tobuy; +} +if (! empty($canvas)) +{ + $sql.= " AND p.canvas = '".$db->escape($canvas)."'"; +} +if($catid) +{ + $sql.= " AND cp.fk_categorie = ".$catid; +} +if ($fourn_id > 0) +{ + $sql.= " AND p.rowid = pf.fk_product AND pf.fk_soc = ".$fourn_id; +} +// Insert categ filter +if ($search_categ) +{ + $sql .= " AND cp.fk_categorie = ".$db->escape($search_categ); +} +if ($search_batch) +{ + $sql .= " AND pb.batch LIKE '%".$db->escape($search_batch)."%'"; +} +$sql.= " GROUP BY p.rowid, p.ref, p.label, p.barcode, p.price, p.price_ttc, p.price_base_type,"; +$sql.= " p.fk_product_type, p.tms, p.duration, p.tosell, p.tobuy, p.seuil_stock_alerte, p.desiredstock,"; +$sql.= " s.fk_entrepot,"; +$sql.= " pb.batch, pb.eatby, pb.sellby"; +if ($toolowstock) $sql.= " HAVING SUM(".$db->ifsql('s.reel IS NULL', '0', 's.reel').") < p.seuil_stock_alerte"; // Not used yet +$sql.= $db->order($sortfield,$sortorder); +$sql.= $db->plimit($limit + 1, $offset); +$resql = $db->query($sql); + +if ($resql) +{ + $num = $db->num_rows($resql); + + $i = 0; + + if ($num == 1 && ($sall or $snom or $sref)) + { + $objp = $db->fetch_object($resql); + header("Location: card.php?id=$objp->rowid"); + exit; + } + + $helpurl=''; + $helpurl='EN:Module_Stocks_En|FR:Module_Stock|ES:Módulo_Stocks'; + + if (isset($type)) + { + if ($type==1) { $texte = $langs->trans("Services"); } + else { $texte = $langs->trans("Products"); } + } else { + $texte = $langs->trans("ProductsAndServices"); + } + $texte.=' ('.$langs->trans("StocksByLotSerial").')'; + + + llxHeader("",$title,$helpurl,$texte); + + if ($sref || $snom || $sall || GETPOST('search')) + { + print_barre_liste($texte, $page, $_SERVER["PHP_SELF"], "&sref=".$sref."&snom=".$snom."&sall=".$sall."&tosell=".$tosell."&tobuy=".$tobuy, $sortfield, $sortorder,'',$num); + } + else + { + print_barre_liste($texte, $page, $_SERVER["PHP_SELF"], "&sref=$sref&snom=$snom&fourn_id=$fourn_id".(isset($type)?"&type=$type":""), $sortfield, $sortorder,'',$num); + } + + if (! empty($catid)) + { + print "
"; + $c = new Categorie($db); + $c->fetch($catid); + $ways = $c->print_all_ways(' > ','product/reassortlot.php'); + print " > ".$ways[0]."
\n"; + print "

"; + } + + print '
'; + print ''; + print ''; + print ''; + print ''; + + print ''; + + // Filter on categories + $moreforfilter=''; + if (! empty($conf->categorie->enabled)) + { + $moreforfilter.=$langs->trans('Categories'). ': '; + $moreforfilter.=$htmlother->select_categories(0,$search_categ,'search_categ'); + $moreforfilter.='           '; + } + //$moreforfilter.=$langs->trans("StockTooLow").' '; + if ($moreforfilter) + { + print ''; + print ''; + } + + $param="&tosell=$tosell&tobuy=$tobuy".(isset($type)?"&type=$type":"")."&fourn_id=$fourn_id&snom=$snom&sref=$sref&batch=$batch&eatby=$eatby&sellby=$sellby"; + + // Lignes des titres + print ""; + print_liste_field_titre($langs->trans("Ref"), $_SERVER["PHP_SELF"], "p.ref",$param,"","",$sortfield,$sortorder); + print_liste_field_titre($langs->trans("Label"), $_SERVER["PHP_SELF"], "p.label",$param,"","",$sortfield,$sortorder); + if (! empty($conf->service->enabled) && $type == 1) print_liste_field_titre($langs->trans("Duration"), $_SERVER["PHP_SELF"], "p.duration",$param,"",'align="center"',$sortfield,$sortorder); + print_liste_field_titre($langs->trans("Warehouse"), $_SERVER["PHP_SELF"], "",$param,"",'',$sortfield,$sortorder); + //print_liste_field_titre($langs->trans("DesiredStock"), $_SERVER["PHP_SELF"], "p.desiredstock",$param,"",'align="right"',$sortfield,$sortorder); + print_liste_field_titre($langs->trans("Batch"), $_SERVER["PHP_SELF"], "pb.batch",$param,"",'align="center"',$sortfield,$sortorder); + print_liste_field_titre($langs->trans("l_eatby"), $_SERVER["PHP_SELF"], "pb.eatby",$param,"",'align="center"',$sortfield,$sortorder); + print_liste_field_titre($langs->trans("l_sellby"), $_SERVER["PHP_SELF"], "pb.sellby",$param,"",'align="center"',$sortfield,$sortorder); + print_liste_field_titre($langs->trans("PhysicalStock"), $_SERVER["PHP_SELF"], "stock_physique",$param,"",'align="right"',$sortfield,$sortorder); + // TODO Add info of running suppliers/customers orders + //print_liste_field_titre($langs->trans("TheoreticalStock"),$_SERVER["PHP_SELF"], "stock_theorique",$param,"",'align="right"',$sortfield,$sortorder); + print ''; + print_liste_field_titre($langs->trans("Sell"),$_SERVER["PHP_SELF"], "p.tosell",$param,"",'align="right"',$sortfield,$sortorder); + print_liste_field_titre($langs->trans("Buy"),$_SERVER["PHP_SELF"], "p.tobuy",$param,"",'align="right"',$sortfield,$sortorder); + print "\n"; + + // Lignes des champs de filtre + print ''; + print ''; + print ''; + if (! empty($conf->service->enabled) && $type == 1) + { + print ''; + } + print ''; + print ''; + print ''; + print ''; + print ''; + print ''; + print ''; + print ''; + print ''; + + $product_static=new Product($db); + $warehousetmp=new Entrepot($db); + + $var=True; + while ($i < min($num,$limit)) + { + $objp = $db->fetch_object($resql); + + // Multilangs + if (! empty($conf->global->MAIN_MULTILANGS)) // si l'option est active + { + $sql = "SELECT label"; + $sql.= " FROM ".MAIN_DB_PREFIX."product_lang"; + $sql.= " WHERE fk_product=".$objp->rowid; + $sql.= " AND lang='". $langs->getDefaultLang() ."'"; + $sql.= " LIMIT 1"; + + $result = $db->query($sql); + if ($result) + { + $objtp = $db->fetch_object($result); + if (! empty($objtp->label)) $objp->label = $objtp->label; + } + } + + $var=!$var; + print ''; + print ''; + + if (! empty($conf->service->enabled) && $type == 1) + { + print ''; + } + //print ''; + //print ''; + //print ''; + + // Warehouse + print ''; + print ''; + print ''; + print ''; + print ''; + print ''; + print ''; + print ''; + print "\n"; + $i++; + } + + print "
'; + print $moreforfilter; + print '
 
'; + print ''; + print ''; + print ''; + print ''; + print ' '; + print '      '; + print ''; + print ''; + print '
'; + $product_static->ref=$objp->ref; + $product_static->id=$objp->rowid; + $product_static->label = $objp->label; + $product_static->type=$objp->fk_product_type; + print $product_static->getNomUrl(1,'',16); + //if ($objp->stock_theorique < $objp->seuil_stock_alerte) print ' '.img_warning($langs->trans("StockTooLow")); + print ''.$objp->label.''; + if (preg_match('/([0-9]+)y/i',$objp->duration,$regs)) print $regs[1].' '.$langs->trans("DurationYear"); + elseif (preg_match('/([0-9]+)m/i',$objp->duration,$regs)) print $regs[1].' '.$langs->trans("DurationMonth"); + elseif (preg_match('/([0-9]+)d/i',$objp->duration,$regs)) print $regs[1].' '.$langs->trans("DurationDay"); + else print $objp->duration; + print ''.$objp->stock_theorique.''.$objp->seuil_stock_alerte.''.$objp->desiredstock.''; + $warehousetmp->fetch($obj->fk_entrepot); + print $warehousetmp->getNomUrl(1); + print ''.$objp->batch.''.dol_print_date($db->jdate($objp->eatby), 'day').''.dol_print_date($db->jdate($objp->sellby), 'day').''; + //if ($objp->seuil_stock_alerte && ($objp->stock_physique < $objp->seuil_stock_alerte)) print img_warning($langs->trans("StockTooLow")).' '; + print $objp->stock_physique; + print ''.$langs->trans("Movements").''.$product_static->LibStatut($objp->statut,5,0).''.$product_static->LibStatut($objp->tobuy,5,1).'
"; + print '
'; + + if ($num > $conf->liste_limit) + { + if ($sref || $snom || $sall || GETPOST('search')) + { + print_barre_liste('', $page, "reassort.php", "&sref=".$sref."&snom=".$snom."&sall=".$sall."&tosell=".$tosell."&tobuy=".$tobuy, $sortfield, $sortorder,'',$num, 0, ''); + } + else + { + print_barre_liste('', $page, "reassort.php", "&sref=$sref&snom=$snom&fourn_id=$fourn_id".(isset($type)?"&type=$type":"")."&tosell=".$tosell."&tobuy=".$tobuy, $sortfield, $sortorder,'',$num, 0, ''); + } + } + + $db->free($resql); + +} +else +{ + dol_print_error($db); +} + + +llxFooter(); +$db->close(); diff --git a/htdocs/product/stats/card.php b/htdocs/product/stats/card.php index 788068ea5ec..ce161a1af60 100644 --- a/htdocs/product/stats/card.php +++ b/htdocs/product/stats/card.php @@ -67,7 +67,7 @@ if (! empty($id) || ! empty($ref)) if ($result) { - $head=product_prepare_head($object, $user); + $head=product_prepare_head($object); $titre=$langs->trans("CardProduct".$object->type); $picto=($object->type==Product::TYPE_SERVICE?'service':'product'); diff --git a/htdocs/product/stats/commande.php b/htdocs/product/stats/commande.php index 81b251d795b..7dcf6139534 100644 --- a/htdocs/product/stats/commande.php +++ b/htdocs/product/stats/commande.php @@ -89,7 +89,7 @@ if ($id > 0 || ! empty($ref)) if ($result > 0) { - $head=product_prepare_head($product, $user); + $head=product_prepare_head($product); $titre=$langs->trans("CardProduct".$product->type); $picto=($product->type==Product::TYPE_SERVICE?'service':'product'); dol_fiche_head($head, 'referers', $titre, 0, $picto); diff --git a/htdocs/product/stats/commande_fournisseur.php b/htdocs/product/stats/commande_fournisseur.php index f0444356bcc..e6ced5ad905 100644 --- a/htdocs/product/stats/commande_fournisseur.php +++ b/htdocs/product/stats/commande_fournisseur.php @@ -96,7 +96,7 @@ if ($id > 0 || ! empty($ref)) { llxHeader("", "", $langs->trans("CardProduct" . $product->type)); if ($result > 0) { - $head = product_prepare_head($product, $user); + $head = product_prepare_head($product); $titre = $langs->trans("CardProduct" . $product->type); $picto = ($product->type == Product::TYPE_SERVICE ? 'service' : 'product'); dol_fiche_head($head, 'referers', $titre, 0, $picto); diff --git a/htdocs/product/stats/contrat.php b/htdocs/product/stats/contrat.php index aa535f02575..d098ca3399b 100644 --- a/htdocs/product/stats/contrat.php +++ b/htdocs/product/stats/contrat.php @@ -79,7 +79,7 @@ if ($id > 0 || ! empty($ref)) if ($result > 0) { - $head=product_prepare_head($product,$user); + $head=product_prepare_head($product); $titre=$langs->trans("CardProduct".$product->type); $picto=($product->type==Product::TYPE_SERVICE?'service':'product'); dol_fiche_head($head, 'referers', $titre, 0, $picto); diff --git a/htdocs/product/stats/facture.php b/htdocs/product/stats/facture.php index c0fa1481269..1f4e9b985e5 100644 --- a/htdocs/product/stats/facture.php +++ b/htdocs/product/stats/facture.php @@ -90,7 +90,7 @@ if ($id > 0 || ! empty($ref)) if ($result > 0) { - $head=product_prepare_head($product, $user); + $head=product_prepare_head($product); $titre=$langs->trans("CardProduct".$product->type); $picto=($product->type==Product::TYPE_SERVICE?'service':'product'); dol_fiche_head($head, 'referers', $titre, 0, $picto); @@ -148,7 +148,7 @@ if ($id > 0 || ! empty($ref)) if (!$user->rights->societe->client->voir && !$socid) $sql.= " AND s.rowid = sc.fk_soc AND sc.fk_user = " .$user->id; if ($socid) $sql.= " AND f.fk_soc = ".$socid; $sql.= " ORDER BY $sortfield $sortorder "; - + //Calcul total qty and amount for global if full scan list $total_ht=0; $total_qty=0; @@ -163,21 +163,21 @@ if ($id > 0 || ! empty($ref)) } } } - + $sql.= $db->plimit($conf->liste_limit +1, $offset); $result = $db->query($sql); - if ($result) + if ($result) { $num = $db->num_rows($result); - + if (! empty($id)) $option .= '&id='.$product->id; if (! empty($search_month)) $option .= '&search_month='.$search_month; if (! empty($search_year)) $option .= '&search_year='.$search_year; - + print '
' . "\n"; if (! empty($sortfield)) print ''; @@ -187,7 +187,7 @@ if ($id > 0 || ! empty($ref)) print ''; $option .= '&page=' . $page; } - + print_barre_liste($langs->trans("CustomersInvoices"),$page,$_SERVER["PHP_SELF"],"&id=".$product->id,$sortfield,$sortorder,'',$num,$totalrecords,''); print '
'; print $langs->trans('Period').' ('.$langs->trans("DateInvoice") .') - '; @@ -235,7 +235,7 @@ if ($id > 0 || ! empty($ref)) print ''.$invoicestatic->LibStatut($objp->paye,$objp->statut,5).''; print "\n"; $i++; - + if (!empty($conf->global->MAIN_DISABLE_FULL_SCANLIST)) { $total_ht+=$objp->total_ht; $total_qty+=$objp->qty; diff --git a/htdocs/product/stats/facture_fournisseur.php b/htdocs/product/stats/facture_fournisseur.php index 275a2ff8604..debb0698c44 100644 --- a/htdocs/product/stats/facture_fournisseur.php +++ b/htdocs/product/stats/facture_fournisseur.php @@ -82,52 +82,52 @@ if ($id > 0 || ! empty($ref)) { $product = new Product($db); $result = $product->fetch($id, $ref); - + $parameters = array('id' => $id); $reshook = $hookmanager->executeHooks('doActions', $parameters, $product, $action); // Note that $action and $object may have been modified by some hooks if ($reshook < 0) setEventMessages($hookmanager->error, $hookmanager->errors, 'errors'); - + llxHeader("", "", $langs->trans("CardProduct" . $product->type)); - + if ($result > 0) { - $head = product_prepare_head($product, $user); + $head = product_prepare_head($product); $titre = $langs->trans("CardProduct" . $product->type); $picto = ($product->type == Product::TYPE_SERVICE ? 'service' : 'product'); dol_fiche_head($head, 'referers', $titre, 0, $picto); - + $reshook = $hookmanager->executeHooks('formObjectOptions', $parameters, $product, $action); // Note that $action and $object may have been modified by hook if ($reshook < 0) setEventMessages($hookmanager->error, $hookmanager->errors, 'errors'); - + print ''; - + // Reference print ''; print ''; print ''; - + // Libelle print ''; print ''; - + // Status (to sell) print ''; - + // Status (to buy) print ''; - + show_stats_for_company($product, $socid); - + print "
' . $langs->trans("Ref") . ''; print $form->showrefnav($product, 'ref', '', 1, 'ref'); print '
' . $langs->trans("Label") . '' . $product->libelle . '
' . $langs->trans("Status") . ' (' . $langs->trans("Sell") . ')'; print $product->getLibStatut(2, 0); print '
' . $langs->trans("Status") . ' (' . $langs->trans("Buy") . ')'; print $product->getLibStatut(2, 1); print '
"; - + print '
'; - + if ($user->rights->fournisseur->facture->lire) { $sql = "SELECT distinct s.nom as name, s.rowid as socid, s.code_client, f.ref, d.total_ht as total_ht,"; @@ -142,14 +142,14 @@ if ($id > 0 || ! empty($ref)) $sql .= " AND f.entity = " . $conf->entity; $sql .= " AND d.fk_facture_fourn = f.rowid"; $sql .= " AND d.fk_product =" . $product->id; - if (! empty($search_month)) + if (! empty($search_month)) $sql .= ' AND MONTH(f.datef) IN (' . $search_month . ')'; - if (! empty($search_year)) + if (! empty($search_year)) $sql .= ' AND YEAR(f.datef) IN (' . $search_year . ')'; if (! $user->rights->societe->client->voir && ! $socid) $sql .= " AND s.rowid = sc.fk_soc AND sc.fk_user = " . $user->id; if ($socid) $sql .= " AND f.fk_soc = " . $socid; $sql .= " ORDER BY $sortfield $sortorder "; - + // Calcul total qty and amount for global if full scan list $total_ht = 0; $total_qty = 0; @@ -164,21 +164,21 @@ if ($id > 0 || ! empty($ref)) } } } - + $sql .= $db->plimit($conf->liste_limit + 1, $offset); - + $result = $db->query($sql); if ($result) { $num = $db->num_rows($result); - + if (! empty($id)) $option .= '&id=' . $product->id; if (! empty($search_month)) $option .= '&search_month=' . $search_month; if (! empty($search_year)) $option .= '&search_year=' . $search_year; - + print '' . "\n"; if (! empty($sortfield)) print ''; @@ -199,7 +199,7 @@ if ($id > 0 || ! empty($ref)) print ''; print '
'; print '
'; - + $i = 0; print ''; print ''; @@ -211,7 +211,7 @@ if ($id > 0 || ! empty($ref)) print_liste_field_titre($langs->trans("AmountHT"), $_SERVER["PHP_SELF"], "f.total_ht", "", $option, 'align="right"', $sortfield, $sortorder); print_liste_field_titre($langs->trans("Status"), $_SERVER["PHP_SELF"], "f.paye,f.fk_statut", "", $option, 'align="right"', $sortfield, $sortorder); print "\n"; - + if ($num > 0) { $var = True; @@ -219,7 +219,7 @@ if ($id > 0 || ! empty($ref)) { $objp = $db->fetch_object($result); $var = ! $var; - + print ''; print ''; print "\n"; $i ++; - + if (! empty($conf->global->MAIN_DISABLE_FULL_SCANLIST)) { $total_ht += $objp->total_ht; $total_qty += $objp->qty; diff --git a/htdocs/product/stats/propal.php b/htdocs/product/stats/propal.php index 4eae4c238e1..1776ba571e0 100644 --- a/htdocs/product/stats/propal.php +++ b/htdocs/product/stats/propal.php @@ -80,52 +80,52 @@ if ($id > 0 || ! empty($ref)) { $product = new Product($db); $result = $product->fetch($id, $ref); - + $parameters = array ('id' => $id); $reshook = $hookmanager->executeHooks('doActions', $parameters, $product, $action); // Note that $action and $object may have been modified by some hooks if ($reshook < 0) setEventMessages($hookmanager->error, $hookmanager->errors, 'errors'); - + llxHeader("", "", $langs->trans("CardProduct" . $product->type)); - + if ($result > 0) { - $head = product_prepare_head($product, $user); + $head = product_prepare_head($product); $titre = $langs->trans("CardProduct" . $product->type); $picto = ($product->type == Product::TYPE_SERVICE ? 'service' : 'product'); dol_fiche_head($head, 'referers', $titre, 0, $picto); - + $reshook = $hookmanager->executeHooks('formObjectOptions', $parameters, $product, $action); // Note that $action and $object may have been modified by hook if ($reshook < 0) setEventMessages($hookmanager->error, $hookmanager->errors, 'errors'); - + print '
'; $supplierinvoicestatic->id = $objp->facid; @@ -236,7 +236,7 @@ if ($id > 0 || ! empty($ref)) print '' . $supplierinvoicestatic->LibStatut($objp->paye, $objp->statut, 5) . '
'; - + // Reference print ''; print ''; print ''; - + // Libelle print ''; print ''; - + // Status (to sell) print ''; - + // Status (to buy) print ''; - + show_stats_for_company($product, $socid); - + print "
' . $langs->trans("Ref") . ''; print $form->showrefnav($product, 'ref', '', 1, 'ref'); print '
' . $langs->trans("Label") . '' . $product->libelle . '
' . $langs->trans("Status") . ' (' . $langs->trans("Sell") . ')'; print $product->getLibStatut(2, 0); print '
' . $langs->trans("Status") . ' (' . $langs->trans("Buy") . ')'; print $product->getLibStatut(2, 1); print '
"; - + print ''; - + if ($user->rights->propale->lire) { $sql = "SELECT DISTINCT s.nom as name, s.rowid as socid, p.rowid as propalid, p.ref, d.total_ht as amount,"; $sql .= " p.ref_client,"; @@ -150,7 +150,7 @@ if ($id > 0 || ! empty($ref)) if ($socid) $sql .= " AND p.fk_soc = " . $socid; $sql .= " ORDER BY $sortfield $sortorder "; - + // Calcul total qty and amount for global if full scan list $total_ht = 0; $total_qty = 0; @@ -165,21 +165,21 @@ if ($id > 0 || ! empty($ref)) } } } - + $sql .= $db->plimit($conf->liste_limit + 1, $offset); - + $result = $db->query($sql); if ($result) { $num = $db->num_rows($result); - + if (! empty($id)) $option .= '&id=' . $product->id; if (! empty($search_month)) $option .= '&search_month=' . $search_month; if (! empty($search_year)) $option .= '&search_year=' . $search_year; - + print '' . "\n"; if (! empty($sortfield)) print ''; @@ -189,7 +189,7 @@ if ($id > 0 || ! empty($ref)) print ''; $option .= '&page=' . $page; } - + print_barre_liste($langs->trans("Proposals"), $page, $_SERVER["PHP_SELF"], "&id=$product->id", $sortfield, $sortorder, '', $num, $totalrecords, ''); print '
'; print $langs->trans('Period') . ' (' . $langs->trans("DatePropal") . ') - '; @@ -200,7 +200,7 @@ if ($id > 0 || ! empty($ref)) print ''; print '
'; print ''; - + $i = 0; print ''; print ''; @@ -211,7 +211,7 @@ if ($id > 0 || ! empty($ref)) print_liste_field_titre($langs->trans("AmountHT"), $_SERVER["PHP_SELF"], "p.total", "", $option, 'align="right"', $sortfield, $sortorder); print_liste_field_titre($langs->trans("Status"), $_SERVER["PHP_SELF"], "p.fk_statut", "", $option, 'align="right"', $sortfield, $sortorder); print "\n"; - + if ($num > 0) { $var = True; @@ -219,7 +219,7 @@ if ($id > 0 || ! empty($ref)) { $objp = $db->fetch_object($result); $var = ! $var; - + print ''; print ''; print "\n"; $i ++; - + if (! empty($conf->global->MAIN_DISABLE_FULL_SCANLIST)) { $total_ht += $objp->total_ht; $total_qty += $objp->qty; } } - } + } print ''; print ''; print ''; @@ -251,12 +251,12 @@ if ($id > 0 || ! empty($ref)) print ''; print "
'; $propalstatic->id=$objp->propalid; @@ -236,13 +236,13 @@ if ($id > 0 || ! empty($ref)) print '' . $propalstatic->LibStatut($objp->statut, 5) . '
' . $langs->trans('Total') . '
"; print ''; - print '
'; + print '
'; } else { dol_print_error($db); } $db->free($result); - } + } } } else { dol_print_error(); diff --git a/htdocs/product/stock/class/mouvementstock.class.php b/htdocs/product/stock/class/mouvementstock.class.php index c41fe590d18..2e9fcfab68e 100644 --- a/htdocs/product/stock/class/mouvementstock.class.php +++ b/htdocs/product/stock/class/mouvementstock.class.php @@ -67,16 +67,16 @@ class MouvementStock extends CommonObject * @param date $eatby eat-by date * @param date $sellby sell-by date * @param string $batch batch number - * @param boolean $skip_sellby If set to true, stock mouvement is done without impacting batch record + * @param boolean $skip_batch If set to true, stock movement is done without impacting batch record * @return int <0 if KO, 0 if fk_product is null, >0 if OK */ - function _create($user, $fk_product, $entrepot_id, $qty, $type, $price=0, $label='', $inventorycode='', $datem='',$eatby='',$sellby='',$batch='',$skip_sellby=false) + function _create($user, $fk_product, $entrepot_id, $qty, $type, $price=0, $label='', $inventorycode='', $datem='',$eatby='',$sellby='',$batch='',$skip_batch=false) { global $conf, $langs; require_once DOL_DOCUMENT_ROOT.'/product/class/product.class.php'; $error = 0; - dol_syslog(get_class($this)."::_create start userid=$user->id, fk_product=$fk_product, warehouse=$entrepot_id, qty=$qty, type=$type, price=$price, label=$label, inventorycode=$inventorycode"); + dol_syslog(get_class($this)."::_create start userid=$user->id, fk_product=$fk_product, warehouse=$entrepot_id, qty=$qty, type=$type, price=$price, label=$label, inventorycode=$inventorycode, datem=".$datem.", eatby=".$eatby.", sellby=".$sellby.", batch=".$batch.", skip_batch=".$skip_batch); // Clean parameters if (empty($price)) $price=0; @@ -84,6 +84,16 @@ class MouvementStock extends CommonObject // Check parameters if (empty($fk_product)) return 0; + if ($eatby < 0) + { + $this->errors[]='ErrorBadValueForParameterEatBy'; + return -1; + } + if ($sellby < 0) + { + $this->errors[]='ErrorBadValueForParameterEatBy'; + return -1; + } // Set properties of movement $this->product_id = $fk_product; @@ -91,7 +101,7 @@ class MouvementStock extends CommonObject $this->qty = $qty; $this->type = $type; - $this->db->begin(); + $mvid = 0; $product = new Product($this->db); $result=$product->fetch($fk_product); @@ -100,19 +110,69 @@ class MouvementStock extends CommonObject dol_print_error('',"Failed to fetch product"); return -1; } + + $this->db->begin(); + $product->load_stock(); // Test if product require batch data. If yes, and there is not, we throw an error. - if ($product->hasbatch() && ! $skip_sellby) + if (! empty($conf->productbatch->enabled) && $product->hasbatch() && ! $skip_batch) { - if (empty($batch) && empty($eatby) && empty($sellby)) + //if (empty($batch) && empty($eatby) && empty($sellby)) + if (empty($batch)) { - $this->errors[]="ErrorTryToMakeMoveOnProductRequiringBatchData"; + $this->errors[]=$langs->trans("ErrorTryToMakeMoveOnProductRequiringBatchData", $product->name); dol_syslog("Try to make a movement of a product with status_batch on without any batch data"); $this->db->rollback(); return -2; } + + // If a serial number is provided, we check that sellby and eatby match already existing serial + $sql = "SELECT pb.rowid, pb.batch, pb.eatby, pb.sellby FROM ".MAIN_DB_PREFIX."product_batch as pb, ".MAIN_DB_PREFIX."product_stock as ps"; + $sql.= " WHERE pb.fk_product_stock = ps.rowid AND ps.fk_product = ".$fk_product." AND pb.batch = '".$this->db->escape($batch)."'"; + dol_syslog(get_class($this)."::_create scan serial for this product to check if eatby and sellby match", LOG_DEBUG); + $resql = $this->db->query($sql); + if ($resql) + { + $num = $this->db->num_rows($resql); + $i=0; + while ($i < $num) + { + $obj = $this->db->fetch_object($resql); + if ($this->db->jdate($obj->eatby) != $eatby) + { + $this->errors[]=$langs->trans("ThisSerialAlreadyExistWithDifferentDate", $batch, $this->db->jdate($obj->eatby), $eatby); + dol_syslog($langs->trans("ThisSerialAlreadyExistWithDifferentDate", $batch, $this->db->jdate($obj->eatby), $eatby)); + $this->db->rollback(); + return -3; + } + if ($this->db->jdate($obj->sellby) != $sellby) + { + $this->errors[]=$langs->trans("ThisSerialAlreadyExistWithDifferentDate", $batch, $this->db->jdate($obj->sellby), $sellby); + dol_syslog($langs->trans("ThisSerialAlreadyExistWithDifferentDate", $batch, $this->db->jdate($obj->sellby), $sellby)); + $this->db->rollback(); + return -3; + } + $i++; + } + } + else + { + dol_print_error($this->db); + $this->db->rollback(); + return -1; + } + } + + // TODO Check qty is ok for stock move. + if (! empty($conf->productbatch->enabled) && $product->hasbatch() && ! $skip_batch) + { + + } + else + { + } // Define if we must make the stock change (If product type is a service or if stock is used also for services) @@ -129,8 +189,6 @@ class MouvementStock extends CommonObject $fk_origin = 0; } - $mvid = 0; - $sql = "INSERT INTO ".MAIN_DB_PREFIX."stock_mouvement("; $sql.= " datem, fk_product, batch, eatby, sellby,"; $sql.= " fk_entrepot, value, type_mouvement, fk_user_author, label, inventorycode, price, fk_origin, origintype"; @@ -157,7 +215,7 @@ class MouvementStock extends CommonObject } else { - $this->error=$this->db->lasterror(); + $this->errors[]=$this->db->lasterror(); $error = -1; } @@ -190,7 +248,7 @@ class MouvementStock extends CommonObject } else { - $this->error=$this->db->lasterror(); + $this->errors[]=$this->db->lasterror(); $error = -2; } } @@ -212,7 +270,7 @@ class MouvementStock extends CommonObject $resql=$this->db->query($sql); if (! $resql) { - $this->error=$this->db->lasterror(); + $this->errors[]=$this->db->lasterror(); $error = -4; } */ @@ -266,7 +324,7 @@ class MouvementStock extends CommonObject $resql=$this->db->query($sql); if (! $resql) { - $this->error=$this->db->lasterror(); + $this->errors[]=$this->db->lasterror(); $error = -3; } else if(empty($fk_product_stock)) @@ -276,8 +334,8 @@ class MouvementStock extends CommonObject } - // Update detail stock for sell-by date - if (($product->hasbatch()) && (! $error) && (! $skip_sellby)) + // Update detail stock for batch product + if (! $error && ! empty($conf->productbatch->enabled) && $product->hasbatch() && ! $skip_batch) { $param_batch=array('fk_product_stock' =>$fk_product_stock, 'eatby'=>$eatby, 'sellby'=>$sellby, 'batchnumber'=>$batch); $result=$this->_create_batch($param_batch, $qty); @@ -296,7 +354,7 @@ class MouvementStock extends CommonObject $resql=$this->db->query($sql); if (! $resql) { - $this->error=$this->db->lasterror(); + $this->errors[]=$this->db->lasterror(); $error = -4; } } diff --git a/htdocs/product/stock/index.php b/htdocs/product/stock/index.php index dc394f898dc..aacdedc3668 100644 --- a/htdocs/product/stock/index.php +++ b/htdocs/product/stock/index.php @@ -27,6 +27,7 @@ require '../../main.inc.php'; require_once DOL_DOCUMENT_ROOT.'/product/stock/class/entrepot.class.php'; $langs->load("stocks"); +$langs->load("productbatch"); // Security check $result=restrictedArea($user,'stock'); @@ -112,7 +113,7 @@ print '
'; $max=10; $sql = "SELECT p.rowid, p.label as produit,"; $sql.= " e.label as stock, e.rowid as entrepot_id,"; -$sql.= " m.value, m.datem"; +$sql.= " m.value as qty, m.datem, m.batch, m.eatby, m.sellby"; $sql.= " FROM ".MAIN_DB_PREFIX."entrepot as e"; $sql.= ", ".MAIN_DB_PREFIX."stock_mouvement as m"; $sql.= ", ".MAIN_DB_PREFIX."product as p"; @@ -133,6 +134,12 @@ if ($resql) print ""; print ''.$langs->trans("LastMovements",min($num,$max)).''; print ''.$langs->trans("Product").''; + if (! empty($conf->productbatch->enabled)) + { + print ''.$langs->trans("Batch").''; + print ''.$langs->trans("l_eatby").''; + print ''.$langs->trans("l_sellby").''; + } print ''.$langs->trans("Warehouse").''; print ''.$langs->trans("FullList").''; print "\n"; @@ -148,12 +155,18 @@ if ($resql) print "rowid\">"; print img_object($langs->trans("ShowProduct"),"product").' '.$objp->produit; print "\n"; + if (! empty($conf->productbatch->enabled)) + { + print ''.$objp->batch.''; + print ''.dol_print_date($db->jdate($objp->eatby),'day').''; + print ''.dol_print_date($db->jdate($objp->sellby),'day').''; + } print ''; print img_object($langs->trans("ShowWarehouse"),"stock").' '.$objp->stock; print "\n"; print ''; - if ($objp->value > 0) print '+'; - print $objp->value.''; + if ($objp->qty > 0) print '+'; + print $objp->qty.''; print "\n"; $i++; } diff --git a/htdocs/product/stock/list.php b/htdocs/product/stock/list.php index f6417b389e1..fcc7412c061 100644 --- a/htdocs/product/stock/list.php +++ b/htdocs/product/stock/list.php @@ -1,6 +1,6 @@ - * Copyright (C) 2004-2014 Laurent Destailleur + * Copyright (C) 2004-2015 Laurent Destailleur * Copyright (C) 2005-2014 Regis Houssin * * This program is free software; you can redistribute it and/or modify @@ -51,6 +51,8 @@ $year = strftime("%Y",time()); * View */ +$form=new Form($db); + $sql = "SELECT e.rowid, e.label as ref, e.statut, e.lieu, e.address, e.zip, e.town, e.fk_pays,"; $sql.= " SUM(p.pmp * ps.reel) as estimatedvalue, SUM(p.price * ps.reel) as sellvalue"; $sql.= " FROM ".MAIN_DB_PREFIX."entrepot as e"; @@ -118,7 +120,11 @@ if ($result) // Selling value print ''; if (empty($conf->global->PRODUIT_MULTIPRICES)) print price(price2num($objp->sellvalue,'MT'),1); - else print $langs->trans("Variable"); + else + { + $htmltext=$langs->trans("OptionMULTIPRICESIsOn"); + print $form->textwithtooltip($langs->trans("Variable"),$htmltext); + } print ''; // Status print ''.$entrepot->LibStatut($objp->statut,5).''; @@ -134,7 +140,14 @@ if ($result) print ''; print ''.$langs->trans("Total").''; print ''.price(price2num($total,'MT'),1,$langs,0,0,-1,$conf->currency).''; - print ''.price(price2num($totalsell,'MT'),1,$langs,0,0,-1,$conf->currency).''; + print ''; + if (empty($conf->global->PRODUIT_MULTIPRICES)) print price(price2num($totalsell,'MT'),1,$langs,0,0,-1,$conf->currency); + else + { + $htmltext=$langs->trans("OptionMULTIPRICESIsOn"); + print $form->textwithtooltip($langs->trans("Variable"),$htmltext); + } + print ''; print ' '; print "\n"; } diff --git a/htdocs/product/stock/massstockmove.php b/htdocs/product/stock/massstockmove.php index 8a0b7297e2f..7b3d41c9911 100644 --- a/htdocs/product/stock/massstockmove.php +++ b/htdocs/product/stock/massstockmove.php @@ -1,6 +1,6 @@ - * Copyright (C) 2014 Regis Houssin +/* Copyright (C) 2013-2015 Laurent Destaileur + * Copyright (C) 2014 Regis Houssin * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -47,6 +47,7 @@ $action = GETPOST('action','alpha'); $id_product = GETPOST('productid', 'int'); $id_sw = GETPOST('id_sw', 'int'); $id_tw = GETPOST('id_tw', 'int'); +$batch = GETPOST('batch'); $qty = GETPOST('qty'); $idline = GETPOST('idline'); @@ -79,11 +80,6 @@ if ($action == 'addline') $error++; setEventMessage($langs->trans("ErrorFieldRequired",$langs->transnoentitiesnoconv("Product")),'errors'); } - if (! $qty) - { - $error++; - setEventMessage($langs->trans("ErrorFieldRequired",$langs->transnoentitiesnoconv("Qty")),'errors'); - } if (! ($id_sw > 0)) { $error++; @@ -100,12 +96,47 @@ if ($action == 'addline') $langs->load("errors"); setEventMessage($langs->trans("ErrorWarehouseMustDiffers"),'errors'); } + if (! $qty) + { + $error++; + setEventMessage($langs->trans("ErrorFieldRequired",$langs->transnoentitiesnoconv("Qty")),'errors'); + } + + // Check a batch number is provided if product need it + if (! $error) + { + $producttmp=new Product($db); + $producttmp->fetch($id_product); + if ($producttmp->hasbatch()) + { + if (empty($batch)) + { + $error++; + setEventMessage($langs->trans("ErrorTryToMakeMoveOnProductRequiringBatchData"), 'errors'); + } + } + } + + // TODO Check qty is ok for stock move. Note qty may not be enough yet, but we make a check now to report a warning. + // What is important is to have qty when doing action 'createmovements' + if (! $error) + { + // Warning, don't forget lines already added into the $_SESSION['massstockmove'] + if ($producttmp->hasbatch()) + { + + } + else + { + + } + } if (! $error) { if (count(array_keys($listofdata)) > 0) $id=max(array_keys($listofdata)) + 1; else $id=1; - $listofdata[$id]=array('id'=>$id, 'id_product'=>$id_product, 'qty'=>$qty, 'id_sw'=>$id_sw, 'id_tw'=>$id_tw); + $listofdata[$id]=array('id'=>$id, 'id_product'=>$id_product, 'qty'=>$qty, 'id_sw'=>$id_sw, 'id_tw'=>$id_tw, 'batch'=>$batch); $_SESSION['massstockmove']=json_encode($listofdata); unset($id_product); @@ -145,6 +176,9 @@ if ($action == 'createmovements') $id_sw=$val['id_sw']; $id_tw=$val['id_tw']; $qty=price2num($val['qty']); + $batch=$val['batch']; + $dlc=-1; // They are loaded later from serial + $dluo=-1; // They are loaded later from serial if (! $error && $id_sw <> $id_tw && is_numeric($qty) && $id_product) { @@ -154,39 +188,98 @@ if ($action == 'createmovements') // Define value of products moved $pricesrc=0; - if (isset($product->stock_warehouse[$id_sw]->pmp)) $pricesrc=$product->stock_warehouse[$id_sw]->pmp; + if (! empty($product->pmp)) $pricesrc=$product->pmp; $pricedest=$pricesrc; //print 'price src='.$pricesrc.', price dest='.$pricedest;exit; - // Remove stock - $result1=$product->correct_stock( - $user, - $id_sw, - $qty, - 1, - GETPOST("label"), - $pricesrc - ); - if ($result1 < 0) + if (empty($conf->productbatch->enabled) || ! $product->hasbatch()) // If product does not need lot/serial { - $error++; - setEventMessage($product->errors,'errors'); - } + // Remove stock + $result1=$product->correct_stock( + $user, + $id_sw, + $qty, + 1, + GETPOST("label"), + $pricesrc, + GETPOST("codemove") + ); + if ($result1 < 0) + { + $error++; + setEventMessage($product->errors,'errors'); + } - // Add stock - $result2=$product->correct_stock( - $user, - $id_tw, - $qty, - 0, - GETPOST("label"), - $pricedest - ); - if ($result2 < 0) + // Add stock + $result2=$product->correct_stock( + $user, + $id_tw, + $qty, + 0, + GETPOST("label"), + $pricedest, + GETPOST("codemove") + ); + if ($result2 < 0) + { + $error++; + setEventMessage($product->errors,'errors'); + } + } + else { - $error++; - setEventMessage($product->errors,'errors'); + $arraybatchinfo=$product->loadBatchInfo($batch); + if (count($arraybatchinfo) > 0) + { + $firstrecord = array_shift($arraybatchinfo); + $dlc=$firstrecord['eatby']; + $dluo=$firstrecord['sellby']; + //var_dump($batch); var_dump($arraybatchinfo); var_dump($firstrecord); var_dump($dlc); var_dump($dluo); exit; + } + else + { + $dlc=''; + $dluo=''; + } + + // Remove stock + $result1=$product->correct_stock_batch( + $user, + $id_sw, + $qty, + 1, + GETPOST("label"), + $pricesrc, + $dlc, + $dluo, + $batch, + GETPOST("codemove") + ); + if ($result1 < 0) + { + $error++; + setEventMessage($product->errors,'errors'); + } + + // Add stock + $result2=$product->correct_stock_batch( + $user, + $id_tw, + $qty, + 0, + GETPOST("label"), + $pricedest, + $dlc, + $dluo, + $batch, + GETPOST("codemove") + ); + if ($result2 < 0) + { + $error++; + setEventMessage($product->errors,'errors'); + } } } else @@ -254,6 +347,10 @@ $param=''; print ''; print getTitleFieldOfList($langs->trans('ProductRef'),0,$_SERVER["PHP_SELF"],'',$param,'','class="tagtd"',$sortfield,$sortorder); +if ($conf->productbatch->enabled) +{ + print getTitleFieldOfList($langs->trans('Batch'),0,$_SERVER["PHP_SELF"],'',$param,'','class="tagtd"',$sortfield,$sortorder); +} print getTitleFieldOfList($langs->trans('WarehouseSource'),0,$_SERVER["PHP_SELF"],'',$param,'','class="tagtd"',$sortfield,$sortorder); print getTitleFieldOfList($langs->trans('WarehouseTarget'),0,$_SERVER["PHP_SELF"],'',$param,'','class="tagtd"',$sortfield,$sortorder); print getTitleFieldOfList($langs->trans('Qty'),0,$_SERVER["PHP_SELF"],'',$param,'','align="center" class="tagtd"',$sortfield,$sortorder); @@ -276,6 +373,13 @@ else } print $form->select_produits($id_product,'productid',$filtertype,$limit); print ''; +// Batch number +if ($conf->productbatch->enabled) +{ + print ''; + print ''; + print ''; +} // In warehouse print ''; print $formproduct->selectWarehouses($id_sw,'id_sw','',1); @@ -301,13 +405,16 @@ foreach($listofdata as $key => $val) $warehousestatict->fetch($val['id_tw']); print ''; - print ''.$productstatic->getNomUrl(1).''; print ''; - $oldref=$productstatic->ref; - $productstatic->ref=$productstatic->label; print $productstatic->getNomUrl(1); - $productstatic->ref=$oldref; + print ' - '.$productstatic->label; print ''; + if ($conf->productbatch->enabled) + { + print ''; + print $val['batch']; + print ''; + } print ''; print $warehousestatics->getNomUrl(1); print ''; @@ -333,9 +440,16 @@ print ''; print ''; // Button to record mass movement +$codemove=GETPOST('codemove'); $labelmovement=GETPOST("label")?GETPOST('label'):$langs->trans("StockTransfer").' '.dol_print_date($now,'%Y-%m-%d %H:%M'); print ''; + print ''; + print ''; + print ''; + print ''; print ''; print ''; print ''; - print ''; - print ''; + print_liste_field_titre($langs->trans("BatchNumberShort"),$_SERVER["PHP_SELF"],'m.batch','',$param,'align="center"',$sortfield,$sortorder); + print_liste_field_titre($langs->trans("l_eatby"),$_SERVER["PHP_SELF"],'m.eatby','',$param,'align="center"',$sortfield,$sortorder); + print_liste_field_titre($langs->trans("l_sellby"),$_SERVER["PHP_SELF"],'m.sellby','',$param,'align="center"',$sortfield,$sortorder); } print_liste_field_titre($langs->trans("Warehouse"),$_SERVER["PHP_SELF"], "","",$param,"",$sortfield,$sortorder); // We are on a specific warehouse card, no filter on other should be possible print_liste_field_titre($langs->trans("Author"),$_SERVER["PHP_SELF"], "m.fk_user_author","",$param,"",$sortfield,$sortorder); - print_liste_field_titre($langs->trans("InventoryCode"),$_SERVER["PHP_SELF"], "m.inventorycode","",$param,"",$sortfield,$sortorder); + print_liste_field_titre($langs->trans("InventoryCodeShort"),$_SERVER["PHP_SELF"], "m.inventorycode","",$param,"",$sortfield,$sortorder); print_liste_field_titre($langs->trans("LabelMovement"),$_SERVER["PHP_SELF"], "m.label","",$param,"",$sortfield,$sortorder); print_liste_field_titre($langs->trans("Source"),$_SERVER["PHP_SELF"], "m.label","",$param,"",$sortfield,$sortorder); print_liste_field_titre($langs->trans("Units"),$_SERVER["PHP_SELF"], "m.value","",$param,'align="right"',$sortfield,$sortorder); @@ -473,13 +459,13 @@ if ($resql) // Batch if (! empty($conf->productbatch->enabled)) { - print ''; + print ''; print ''; print ''; } // Warehouse print ''; // Author print ''; // Label of movement print ''; // Origin of movement print ''; + print ''; print ''; print ''; } diff --git a/htdocs/product/stock/product.php b/htdocs/product/stock/product.php index d4a190a482a..40d9ef7e060 100644 --- a/htdocs/product/stock/product.php +++ b/htdocs/product/stock/product.php @@ -5,7 +5,7 @@ * Copyright (C) 2005 Simon TOSSER * Copyright (C) 2005-2009 Regis Houssin * Copyright (C) 2013 Cédric Salvador - * Copyright (C) 2013 Juanjo Menent + * Copyright (C) 2013-2015 Juanjo Menent * Copyright (C) 2014-2015 Cédric Gross * Copyright (C) 2015 Marcos García * @@ -384,7 +384,7 @@ if ($id > 0 || $ref) if ($result > 0) { - $head=product_prepare_head($product, $user); + $head=product_prepare_head($product); $titre=$langs->trans("CardProduct".$product->type); $picto=($product->type==Product::TYPE_SERVICE?'service':'product'); dol_fiche_head($head, 'stock', $titre, 0, $picto); @@ -432,7 +432,9 @@ if ($id > 0 || $ref) // PMP print ''; - print ''; + print ''; print ''; // Minimum Price @@ -803,7 +805,7 @@ if (empty($action) && $product->id) { print "
\n"; - if ($user->rights->stock->creer) + if ($user->rights->stock->mouvement->creer) { print ''.$langs->trans("StockCorrection").''; } @@ -821,8 +823,9 @@ if (empty($action) && $product->id) /* - * Stock detail + * Stock detail (by warehouse). Do not go down into batch. */ + print '
'.$langs->trans("InventoryCode").''; + print ''; + print '
'.$langs->trans("LabelMovement").''; diff --git a/htdocs/product/stock/mouvement.php b/htdocs/product/stock/mouvement.php index 44cf9df493f..a27713d8b0f 100644 --- a/htdocs/product/stock/mouvement.php +++ b/htdocs/product/stock/mouvement.php @@ -1,7 +1,8 @@ - * Copyright (C) 2004-2013 Laurent Destailleur + * Copyright (C) 2004-2015 Laurent Destailleur * Copyright (C) 2005-2014 Regis Houssin + * Copyright (C) 2015 Juanjo Menent * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -52,6 +53,7 @@ $search_product = trim(GETPOST("search_product")); $search_warehouse = trim(GETPOST("search_warehouse")); $search_inventorycode = trim(GETPOST("search_inventorycode")); $search_user = trim(GETPOST("search_user")); +$search_batch = trim(GETPOST("search_batch")); $page = GETPOST("page",'int'); $sortfield = GETPOST("sortfield",'alpha'); $sortorder = GETPOST("sortorder",'alpha'); @@ -70,6 +72,7 @@ if (GETPOST("button_removefilter_x") || GETPOST("button_removefilter")) // Both $search_product=""; $search_warehouse=""; $search_user=""; + $search_batch=""; $sall=""; } @@ -147,34 +150,17 @@ else if ($year > 0) { $sql.= " AND m.datem BETWEEN '".$db->idate(dol_get_first_day($year,1,false))."' AND '".$db->idate(dol_get_last_day($year,12,false))."'"; } -if (! empty($search_movement)) -{ - $sql.= " AND m.label LIKE '%".$db->escape($search_movement)."%'"; -} -if (! empty($search_inventorycode)) -{ - $sql.= " AND m.inventorycode LIKE '%".$db->escape($search_inventorycode)."%'"; -} -if (! empty($search_product_ref)) -{ - $sql.= " AND p.ref LIKE '%".$db->escape($search_product_ref)."%'"; -} -if (! empty($search_product)) -{ - $sql.= " AND p.label LIKE '%".$db->escape($search_product)."%'"; -} -if (! empty($search_warehouse)) -{ - $sql.= " AND e.label LIKE '%".$db->escape($search_warehouse)."%'"; -} -if (! empty($search_user)) -{ - $sql.= " AND u.login LIKE '%".$db->escape($search_user)."%'"; -} if ($idproduct > 0) { $sql.= " AND p.rowid = '".$idproduct."'"; } +if (! empty($search_movement)) $sql.= " AND m.label LIKE '%".$db->escape($search_movement)."%'"; +if (! empty($search_inventorycode)) $sql.= " AND m.inventorycode LIKE '%".$db->escape($search_inventorycode)."%'"; +if (! empty($search_product_ref)) $sql.= " AND p.ref LIKE '%".$db->escape($search_product_ref)."%'"; +if (! empty($search_product)) $sql.= " AND p.label LIKE '%".$db->escape($search_product)."%'"; +if (! empty($search_warehouse)) $sql.= " AND e.label LIKE '%".$db->escape($search_warehouse)."%'"; +if (! empty($search_user)) $sql.= " AND u.login LIKE '%".$db->escape($search_user)."%'"; +if (! empty($search_batch)) $sql.= " AND m.batch LIKE '%".$db->escape($search_batch)."%'"; $sql.= $db->order($sortfield,$sortorder); $sql.= $db->plimit($conf->liste_limit+1, $offset); @@ -400,7 +386,7 @@ if ($resql) { print "
\n"; - if ($user->rights->stock->creer) + if ($user->rights->stock->mouvement->creer) { print ''.$langs->trans("StockCorrection").''; } @@ -439,13 +425,13 @@ if ($resql) if (! empty($conf->productbatch->enabled)) { $langs->load("productbatch"); - print '
'.$langs->trans("batch_number").''.$langs->trans("l_eatby").''.$langs->trans("l_sellby").''; - print ''; + print ''; print ''; @@ -491,7 +477,7 @@ if ($resql) print ''; - print ''; + print ''; print ''; @@ -543,7 +529,7 @@ if ($resql) // Batch if (! empty($conf->productbatch->enabled)) { - print ''.$objp->batch.''.$objp->batch.''. dol_print_date($objp->eatby,'day') .''. dol_print_date($objp->sellby,'day') .'
'.$langs->trans("AverageUnitPricePMP").''.price($product->pmp).' '.$langs->trans("HT").''; + if ($product->pmp > 0) print price($product->pmp).' '.$langs->trans("HT"); + print '
'; print ''; print ''; @@ -870,9 +873,9 @@ if ($resql) print ''; print ''; // PMP - print ''; // Ditto : Show PMP from movement or from product + print ''; // Value purchase - print ''; // Ditto : Show PMP from movement or from product + print ''; // Sell price print ''; // Value sell print ''; // Ditto : Show PMP from movement or from product + if (empty($conf->global->PRODUIT_MULTI_PRICES)) print price(price2num($product->price*$obj->reel,'MT'),1).''; else print $langs->trans("Variable"); print ''; ; $total += $obj->reel; if (price2num($product->pmp)) $totalwithpmp += $obj->reel; - $totalvalue = $totalvalue + ($product->pmp*$obj->reel); // Ditto : Show PMP from movement or from product - $totalvaluesell = $totalvaluesell + ($product->price*$obj->reel); // Ditto : Show PMP from movement or from product + $totalvalue = $totalvalue + ($product->pmp*$obj->reel); + $totalvaluesell = $totalvaluesell + ($product->price*$obj->reel); //Batch Detail if ((! empty($conf->productbatch->enabled)) && $product->hasbatch()) { diff --git a/htdocs/product/stock/replenish.php b/htdocs/product/stock/replenish.php index 289c3c31457..0f935c0154c 100644 --- a/htdocs/product/stock/replenish.php +++ b/htdocs/product/stock/replenish.php @@ -536,9 +536,11 @@ while ($i < ($limit ? min($num, $limit) : $num)) //virtual stock to compute the stock to buy value $stocktobuy = max(max($objp->desiredstock, $objp->alertstock) - $stock - $ordered, 0); $disabled = ''; - if($ordered > 0) { - $compare = $usevirtualstock ? $stock : $stock + $ordered; - if($compare >= $objp->desiredstock) { + if ($ordered > 0) + { + $stockforcompare = $usevirtualstock ? $stock : $stock + $ordered; + if ($stockforcompare >= $objp->desiredstock) + { $picto = img_picto('', './img/yes', '', 1); $disabled = 'disabled="disabled"'; } @@ -546,7 +548,8 @@ while ($i < ($limit ? min($num, $limit) : $num)) $picto = img_picto('', './img/no', '', 1); } } else { - $picto = img_picto('', './img/no', '', 1); + //$picto = img_help('',$langs->trans("NoPendingReceptionOnSupplierOrder")); + $picto = img_picto($langs->trans("NoPendingReceptionOnSupplierOrder"), './img/no', '', 1); } print ''; diff --git a/htdocs/product/stock/valo.php b/htdocs/product/stock/valo.php index 6f5cb7ae578..871ec4d30f1 100644 --- a/htdocs/product/stock/valo.php +++ b/htdocs/product/stock/valo.php @@ -31,7 +31,7 @@ $langs->load("stocks"); // Security check $result=restrictedArea($user,'stock'); -$sref=GETPOST("sref");; +$sref=GETPOST("sref"); $snom=GETPOST("snom"); $sall=GETPOST("sall"); diff --git a/htdocs/product/traduction.php b/htdocs/product/traduction.php index 480f739285d..413cb589dff 100644 --- a/htdocs/product/traduction.php +++ b/htdocs/product/traduction.php @@ -143,7 +143,7 @@ $cancel != $langs->trans("Cancel") && $product->fetch($id); $langtodelete=GETPOST('langdel','alpha'); - + if ( $product->delMultiLangs($langtodelete) > 0 ) { $action = ''; @@ -168,7 +168,7 @@ llxHeader("","",$langs->trans("Translation")); $form = new Form($db); $formadmin=new FormAdmin($db); -$head=product_prepare_head($product, $user); +$head=product_prepare_head($product); $titre=$langs->trans("CardProduct".$product->type); $picto=($product->type==Product::TYPE_SERVICE?'service':'product'); dol_fiche_head($head, 'translation', $titre, 0, $picto); diff --git a/htdocs/projet/activity/perday.php b/htdocs/projet/activity/perday.php index 9c55874a762..1df9359dfa5 100644 --- a/htdocs/projet/activity/perday.php +++ b/htdocs/projet/activity/perday.php @@ -48,11 +48,33 @@ $socid=0; if ($user->societe_id > 0) $socid=$user->societe_id; $result = restrictedArea($user, 'projet', $projectid); +$now=dol_now(); +$nowtmp=dol_getdate($now); +$nowday=$nowtmp['mday']; +$nowmonth=$nowtmp['mon']; +$nowyear=$nowtmp['year']; + +$year=GETPOST('reyear')?GETPOST('reyear'):(GETPOST("year","int")?GETPOST("year","int"):date("Y")); +$month=GETPOST('remonth')?GETPOST('remonth'):(GETPOST("month","int")?GETPOST("month","int"):date("m")); +$day=GETPOST('reday')?GETPOST('reday'):(GETPOST("day","int")?GETPOST("day","int"):date("d")); +$day = (int) $day; +$week=GETPOST("week","int")?GETPOST("week","int"):date("W"); + +$daytoparse = $now; +if ($year && $month && $day) $daytoparse=dol_mktime(0, 0, 0, $month, $day, $year); + /* * Actions */ +if (GETPOST('submitdateselect')) +{ + $daytoparse = dol_mktime(0, 0, 0, GETPOST('remonth'), GETPOST('reday'), GETPOST('reyear')); + + $action = ''; +} + if ($action == 'addtime' && $user->rights->projet->creer) { $task = new Task($db); @@ -133,6 +155,16 @@ $projectstatic=new Project($db); $project = new Project($db); $taskstatic = new Task($db); +$prev = dol_getdate($daytoparse - (24 * 3600)); +$prev_year = $prev['year']; +$prev_month = $prev['mon']; +$prev_day = $prev['mday']; + +$next = dol_getdate($daytoparse + (24 * 3600)); +$next_year = $next['year']; +$next_month = $next['mon']; +$next_day = $next['mday']; + $title=$langs->trans("TimeSpent"); if ($mine) $title=$langs->trans("MyTimeSpent"); @@ -160,7 +192,18 @@ llxHeader("",$title,""); print_barre_liste($title, $page, $_SERVER["PHP_SELF"], "", $sortfield, $sortorder, "", $num); -print ''; +// Show navigation bar +$nav ="".img_previous($langs->trans("Previous"))."\n"; +$nav.=" ".dol_print_date(dol_mktime(0,0,0,$month,$day,$year),"day")." \n"; +$nav.="".img_next($langs->trans("Next"))."\n"; +$nav.="   (".$langs->trans("Today").")"; +$nav.='
'.$form->select_date(-1,'',0,0,2,"addtime",1,0,1).' '; +$nav.=' '; + +$picto='calendarweek'; + + +print 'id > 0 ? '?id='.$project->id : '').'">'; print ''; print ''; print ''; @@ -169,13 +212,15 @@ $head=project_timesheet_prepare_head($mode); dol_fiche_head($head, 'inputperday', '', 0, 'task'); // Show description of content -if ($mine) print $langs->trans("MyTasksDesc").($onlyopened?' '.$langs->trans("OnlyOpenedProject"):'').'

'; +if ($mine) print $langs->trans("MyTasksDesc").($onlyopened?' '.$langs->trans("OnlyOpenedProject"):'').'
'; else { - if ($user->rights->projet->all->lire && ! $socid) print $langs->trans("ProjectsDesc").($onlyopened?' '.$langs->trans("OnlyOpenedProject"):'').'

'; - else print $langs->trans("ProjectsPublicTaskDesc").($onlyopened?' '.$langs->trans("AlsoOnlyOpenedProject"):'').'

'; + if ($user->rights->projet->all->lire && ! $socid) print $langs->trans("ProjectsDesc").($onlyopened?' '.$langs->trans("OnlyOpenedProject"):'').'
'; + else print $langs->trans("ProjectsPublicTaskDesc").($onlyopened?' '.$langs->trans("AlsoOnlyOpenedProject"):'').'
'; } - +print $langs->trans("AllTaskVisibleButEditIfYouAreAssigned").'
'; +print '
'; +print "\n"; // Filter on user /* dol_fiche_head(''); @@ -197,6 +242,10 @@ else dol_fiche_end(); */ + +print '
'.$nav.'
'; + + print '
'.$langs->trans("Warehouse").''.$langs->trans("NumberOfUnit").''.$entrepotstatic->getNomUrl(1).''.$obj->reel.($obj->reel<0?' '.img_warning():'').''.(price2num($product->pmp)?price2num($product->pmp,'MU'):'').''.(price2num($product->pmp)?price2num($product->pmp,'MU'):'').''.(price2num($product->pmp)?price(price2num($product->pmp*$obj->reel,'MT')):'').''.(price2num($product->pmp)?price(price2num($product->pmp*$obj->reel,'MT')):'').''; if (empty($conf->global->PRODUIT_MULTI_PRICES)) print price(price2num($product->price,'MU'),1); @@ -880,13 +883,13 @@ if ($resql) print ''; - if (empty($conf->global->PRODUIT_MULTI_PRICES)) print price(price2num($product->price*$obj->reel,'MT'),1).'
'; print ''; print ''; @@ -207,7 +256,7 @@ print ''; print ''; if ($usertoprocess->id == $user->id) print ''; else print ''; -print ''; +print ''; print ''; print "\n"; @@ -217,7 +266,7 @@ $restricteditformytask=(empty($conf->global->PROJECT_TIME_ON_ALL_TASKS_MY_PROJEC if (count($tasksarray) > 0) { $j=0; - projectLinesPerDay($j, 0, $tasksarray, $level, $projectsrole, $tasksrole, $mine, $restricteditformytask); + projectLinesPerDay($j, 0, $tasksarray, $level, $projectsrole, $tasksrole, $mine, $restricteditformytask, $daytoparse); } else { @@ -234,6 +283,13 @@ print ''; print ''; +print ''; + + llxFooter(); $db->close(); diff --git a/htdocs/projet/activity/perweek.php b/htdocs/projet/activity/perweek.php index b7ab0a8bd71..77b65a19c6b 100644 --- a/htdocs/projet/activity/perweek.php +++ b/htdocs/projet/activity/perweek.php @@ -49,12 +49,15 @@ if ($user->societe_id > 0) $socid=$user->societe_id; $result = restrictedArea($user, 'projet', $projectid); $now=dol_now(); - -$year=GETPOST("year","int")?GETPOST("year","int"):date("Y"); -$month=GETPOST("month","int")?GETPOST("month","int"):date("m"); -$week=GETPOST("week","int")?GETPOST("week","int"):date("W"); -$day=GETPOST("day","int")?GETPOST("day","int"):date("d"); +$nowtmp=dol_getdate($now); +$nowday=$nowtmp['mday']; +$nowmonth=$nowtmp['mon']; +$nowyear=$nowtmp['year']; +$year=GETPOST('reyear')?GETPOST('reyear'):(GETPOST("year","int")?GETPOST("year","int"):date("Y")); +$month=GETPOST('remonth')?GETPOST('remonth'):(GETPOST("month","int")?GETPOST("month","int"):date("m")); +$day=GETPOST('reday')?GETPOST('reday'):(GETPOST("day","int")?GETPOST("day","int"):date("d")); $day = (int) $day; +$week=GETPOST("week","int")?GETPOST("week","int"):date("W"); $startdayarray=dol_get_first_day_week($day, $month, $year); @@ -83,6 +86,13 @@ $usertoprocess=$user; * Actions */ +if (GETPOST('submitdateselect')) +{ + $daytoparse = dol_mktime(0, 0, 0, GETPOST('remonth'), GETPOST('reday'), GETPOST('reyear')); + + $action = ''; +} + if ($action == 'addtime' && $user->rights->projet->creer) { $task = new Task($db); @@ -176,16 +186,15 @@ llxHeader("",$title,"",'','','',array('/core/js/timesheet.js')); print_barre_liste($title, $page, $_SERVER["PHP_SELF"], "", $sortfield, $sortorder, "", $num); -$tmpday = $first_day; - // Show navigation bar $nav ="".img_previous($langs->trans("Previous"))."\n"; -$nav.=" ".dol_print_date(dol_mktime(0,0,0,$first_month,$first_day,$first_year),"%Y").", ".$langs->trans("Week")." ".$week; -$nav.=" \n"; +$nav.=" ".dol_print_date(dol_mktime(0,0,0,$first_month,$first_day,$first_year),"%Y").", ".$langs->trans("Week")." ".$week." \n"; $nav.="".img_next($langs->trans("Next"))."\n"; $nav.="   (".$langs->trans("Today").")"; -$picto='calendarweek'; +$nav.='
'.$form->select_date(-1,'',0,0,2,"addtime",1,0,1).' '; +$nav.=' '; +$picto='calendarweek'; print ''; print ''; @@ -199,12 +208,14 @@ $head=project_timesheet_prepare_head($mode); dol_fiche_head($head, 'inputperweek', '', 0, 'task'); // Show description of content -if ($mine) print $langs->trans("MyTasksDesc").($onlyopened?' '.$langs->trans("OnlyOpenedProject"):'').'

'; +if ($mine) print $langs->trans("MyTasksDesc").($onlyopened?' '.$langs->trans("OnlyOpenedProject"):'').'
'; else { - if ($user->rights->projet->all->lire && ! $socid) print $langs->trans("ProjectsDesc").($onlyopened?' '.$langs->trans("OnlyOpenedProject"):'').'

'; - else print $langs->trans("ProjectsPublicTaskDesc").($onlyopened?' '.$langs->trans("AlsoOnlyOpenedProject"):'').'

'; + if ($user->rights->projet->all->lire && ! $socid) print $langs->trans("ProjectsDesc").($onlyopened?' '.$langs->trans("OnlyOpenedProject"):'').'
'; + else print $langs->trans("ProjectsPublicTaskDesc").($onlyopened?' '.$langs->trans("AlsoOnlyOpenedProject"):'').'
'; } +print $langs->trans("AllTaskVisibleButEditIfYouAreAssigned").'
'; +print '
'; print "\n"; // Filter on user @@ -248,6 +259,7 @@ for($i=0;$i<7;$i++) { print ''; } +print ''; print "\n"; @@ -268,11 +280,12 @@ if (count($tasksarray) > 0) + '; } else { - print ''; + print ''; } print "
'.$langs->trans("Project").''.$langs->trans("ProgressDeclared").''.$langs->trans("TimeSpent").''.$langs->trans("TimeSpentByYou").''.$langs->trans("TimeSpentByUser").''.$langs->trans("DateAndHour").''.$langs->trans("HourStart").''.$langs->trans("Duration").'
'.dol_print_date($startday + ($i * 3600 * 24), '%a').'
'.dol_print_date($startday + ($i * 3600 * 24), 'day').'
 
 
 
'.$langs->trans("NoTasks").'
'.$langs->trans("NoTasks").'
"; @@ -287,6 +300,7 @@ print '
'; print ''."\n\n"; + $modeinput='hours'; print '