From ae180f06a03572412189f94445a5bead7d1135cf Mon Sep 17 00:00:00 2001 From: jfefe Date: Sat, 16 Mar 2013 00:53:46 +0100 Subject: [PATCH 01/40] Fix : document module option was not saved --- htdocs/admin/propal.php | 30 +++++++++++++++++++++++++++--- 1 file changed, 27 insertions(+), 3 deletions(-) diff --git a/htdocs/admin/propal.php b/htdocs/admin/propal.php index 6c18da0e240..755ca681c73 100644 --- a/htdocs/admin/propal.php +++ b/htdocs/admin/propal.php @@ -162,10 +162,34 @@ if ($action == 'setdefaultduration') } } -/*if ($action == 'setusecustomercontactasrecipient') +// Define constants for submodules that contains parameters (forms with param1, param2, ... and value1, value2, ...) +if ($action == 'setModuleOptions') { - dolibarr_set_const($db, "PROPALE_USE_CUSTOMER_CONTACT_AS_RECIPIENT",$_POST["value"],'chaine',0,'',$conf->entity); -}*/ + $post_size=count($_POST); + + $db->begin(); + + for($i=0;$i < $post_size;$i++) + { + if (array_key_exists('param'.$i,$_POST)) + { + $param=GETPOST("param".$i,'alpha'); + $value=GETPOST("value".$i,'alpha'); + if ($param) $res = dolibarr_set_const($db,$param,$value,'chaine',0,'',$conf->entity); + if (! $res > 0) $error++; + } + } + if (! $error) + { + $db->commit(); + $mesg = "".$langs->trans("SetupSaved").""; + } + else + { + $db->rollback(); + $mesg = "".$langs->trans("Error").""; + } +} From 5f1141675c4347562c39db9423d88d99cd21aae8 Mon Sep 17 00:00:00 2001 From: jfefe Date: Sat, 16 Mar 2013 01:10:21 +0100 Subject: [PATCH 02/40] Add constants into config of ODT document for propal : can choose wich ODT will be used on creation and when close to bill or not. --- .../doc/doc_generic_proposal_odt.modules.php | 32 ++++++++++++++++++- htdocs/langs/fr_FR/propal.lang | 3 ++ 2 files changed, 34 insertions(+), 1 deletion(-) diff --git a/htdocs/core/modules/propale/doc/doc_generic_proposal_odt.modules.php b/htdocs/core/modules/propale/doc/doc_generic_proposal_odt.modules.php index 0f9e64c1fe2..54cf9efb2cc 100644 --- a/htdocs/core/modules/propale/doc/doc_generic_proposal_odt.modules.php +++ b/htdocs/core/modules/propale/doc/doc_generic_proposal_odt.modules.php @@ -106,6 +106,9 @@ class doc_generic_proposal_odt extends ModelePDFPropales $texte.= ''; $texte.= ''; $texte.= ''; + $texte.= ''; + $texte.= ''; + $texte.= ''; $texte.= ''; // List of directories area @@ -143,8 +146,35 @@ class doc_generic_proposal_odt extends ModelePDFPropales $texte.= '
'; // Scan directories - if (count($listofdir)) $texte.=$langs->trans("NumberOfModelFilesFound").': '.count($listoffiles).''; + if (count($listofdir)) + { + $texte.=$langs->trans("NumberOfModelFilesFound").': '.count($listoffiles).''; + + // Model for creation + $liste=ModelePDFPropales::liste_modeles($this->db); + $texte.= ''; + $texte.= ''; + $texte.= ''; + $texte.= '"; + + $texte.= ''; + $texte.= ''; + $texte.= '"; + $texte.= ''; + + $texte.= ''; + $texte.= '"; + $texte.= '
'.$langs->trans("DefaultModelPropalCreate").''; + $texte.= $form->selectarray('value2',$liste,$conf->global->PROPALE_ADDON_PDF_ODT_DEFAULT); + $texte.= "
'.$langs->trans("DefaultModelPropalToBill").''; + $texte.= $form->selectarray('value3',$liste,$conf->global->PROPALE_ADDON_PDF_ODT_TOBILL); + $texte.= "
'.$langs->trans("DefaultModelPropalCreate").''; + $texte.= $form->selectarray('value4',$liste,$conf->global->PROPALE_ADDON_PDF_ODT_CLOSED); + $texte.= "
'; + } + + $texte.= ''; diff --git a/htdocs/langs/fr_FR/propal.lang b/htdocs/langs/fr_FR/propal.lang index 5a4c05f0d6d..5d5d1b2043c 100644 --- a/htdocs/langs/fr_FR/propal.lang +++ b/htdocs/langs/fr_FR/propal.lang @@ -97,4 +97,7 @@ TypeContact_propal_external_CUSTOMER=Contact client suivi propale DocModelAzurDescription=Modèle de propositions commerciales complet (logo...) DocModelJauneDescription=Modèle de proposition Jaune Numbershort=N° +DefaultModelPropalCreate=Modèle par défaut à la création +DefaultModelPropalToBill=Modèle lors de la cloture d'une proposition commerciale (à facturer) +DefaultModelPropalClosed=Modèle lors de la cloture d'une proposition commerciale (non facturée) From 8a3fae31e1850e9c3120f0715cfc5f1c9cc5fb01 Mon Sep 17 00:00:00 2001 From: jfefe Date: Sat, 16 Mar 2013 01:13:44 +0100 Subject: [PATCH 03/40] When create a propal, select model document chosen by defaut in module config --- htdocs/comm/propal.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/htdocs/comm/propal.php b/htdocs/comm/propal.php index e17940379bf..11a78523189 100644 --- a/htdocs/comm/propal.php +++ b/htdocs/comm/propal.php @@ -1331,7 +1331,7 @@ if ($action == 'create') print ''.$langs->trans("DefaultModel").''; print ''; $liste=ModelePDFPropales::liste_modeles($db); - print $form->selectarray('model',$liste,$conf->global->PROPALE_ADDON_PDF); + print $form->selectarray('model',$liste,($conf->global->PROPALE_ADDON_PDF_ODT_DEFAULT?$conf->global->PROPALE_ADDON_PDF_ODT_DEFAULT:$conf->global->PROPALE_ADDON_PDF)); print ""; // Project From 65a9edd5a7795642a120c8827daa53e40ba7379b Mon Sep 17 00:00:00 2001 From: jfefe Date: Sat, 16 Mar 2013 01:52:56 +0100 Subject: [PATCH 04/40] Fix : lang --- .../modules/propale/doc/doc_generic_proposal_odt.modules.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/htdocs/core/modules/propale/doc/doc_generic_proposal_odt.modules.php b/htdocs/core/modules/propale/doc/doc_generic_proposal_odt.modules.php index 54cf9efb2cc..959d9b29cd9 100644 --- a/htdocs/core/modules/propale/doc/doc_generic_proposal_odt.modules.php +++ b/htdocs/core/modules/propale/doc/doc_generic_proposal_odt.modules.php @@ -166,7 +166,7 @@ class doc_generic_proposal_odt extends ModelePDFPropales $texte.= ""; $texte.= ''; - $texte.= ''.$langs->trans("DefaultModelPropalCreate").''; + $texte.= ''.$langs->trans("DefaultModelPropalClosed").''; $texte.= ''; $texte.= $form->selectarray('value4',$liste,$conf->global->PROPALE_ADDON_PDF_ODT_CLOSED); $texte.= ""; From 71bb4149cc250800623a32bd910088123796d1e2 Mon Sep 17 00:00:00 2001 From: jfefe Date: Sat, 16 Mar 2013 02:08:07 +0100 Subject: [PATCH 05/40] New : Automatic creation of the document to the closing of the propale depending on the model selected in the configuration --- htdocs/comm/propal/class/propal.class.php | 29 +++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/htdocs/comm/propal/class/propal.class.php b/htdocs/comm/propal/class/propal.class.php index 66f6bb3874d..a7cc2f71c2b 100644 --- a/htdocs/comm/propal/class/propal.class.php +++ b/htdocs/comm/propal/class/propal.class.php @@ -1634,6 +1634,20 @@ class Propal extends CommonObject $this->db->rollback(); return -2; } + + if (empty($conf->global->MAIN_DISABLE_PDF_AUTOUPDATE)) + { + // Define output language + $outputlangs = $langs; + if (! empty($conf->global->MAIN_MULTILANGS)) + { + $outputlangs = new Translate("",$conf); + $newlang=(GETPOST('lang_id') ? GETPOST('lang_id') : $this->client->default_lang); + $outputlangs->setDefaultLang($newlang); + } + //$ret=$object->fetch($id); // Reload to get new records + propale_pdf_create($this->db, $this, $conf->global->PROPALE_ADDON_PDF_ODT_TOBILL?$conf->global->PROPALE_ADDON_PDF_ODT_TOBILL:$this->modelpdf, $outputlangs, $hidedetails, $hidedesc, $hideref); + } // Appel des triggers include_once DOL_DOCUMENT_ROOT . '/core/class/interfaces.class.php'; @@ -1646,6 +1660,21 @@ class Propal extends CommonObject } else { + + if (empty($conf->global->MAIN_DISABLE_PDF_AUTOUPDATE)) + { + // Define output language + $outputlangs = $langs; + if (! empty($conf->global->MAIN_MULTILANGS)) + { + $outputlangs = new Translate("",$conf); + $newlang=(GETPOST('lang_id') ? GETPOST('lang_id') : $this->client->default_lang); + $outputlangs->setDefaultLang($newlang); + } + //$ret=$object->fetch($id); // Reload to get new records + propale_pdf_create($this->db, $this, $conf->global->PROPALE_ADDON_PDF_ODT_CLOSED?$conf->global->PROPALE_ADDON_PDF_ODT_CLOSED:$this->modelpdf, $outputlangs, $hidedetails, $hidedesc, $hideref); + } + // Appel des triggers include_once DOL_DOCUMENT_ROOT . '/core/class/interfaces.class.php'; $interface=new Interfaces($this->db); From 83def2cd57f6bc3c791a387b0cd9355fec58557d Mon Sep 17 00:00:00 2001 From: Maxime Kohlhaas Date: Mon, 25 Mar 2013 18:03:42 +0100 Subject: [PATCH 06/40] Fix : on a new trigger, using $this but not in a class... --- htdocs/fourn/commande/dispatch.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/htdocs/fourn/commande/dispatch.php b/htdocs/fourn/commande/dispatch.php index 1a41324479c..4c5dc82bcec 100644 --- a/htdocs/fourn/commande/dispatch.php +++ b/htdocs/fourn/commande/dispatch.php @@ -90,12 +90,12 @@ if ($_POST["action"] == 'dispatch' && $user->rights->fournisseur->commande->rece global $conf, $langs, $user; // Appel des triggers include_once DOL_DOCUMENT_ROOT . '/core/class/interfaces.class.php'; - $interface=new Interfaces($this->db); - $result_trigger=$interface->run_triggers('ORDER_SUPPLIER_DISPATCH',$this,$user,$langs,$conf); - if ($result_trigger < 0) { $error++; $this->errors=$interface->errors; } + $interface=new Interfaces($db); + $result_trigger=$interface->run_triggers('ORDER_SUPPLIER_DISPATCH',$commande,$user,$langs,$conf); + if ($result_trigger < 0) { $error++; $commande->errors=$interface->errors; } // Fin appel triggers - $this->db->commit(); + $db->commit(); } if ($result > 0) From 8b160ac71291f50c9a7ac7326655354a39bf9dfa Mon Sep 17 00:00:00 2001 From: BENKE Charles Date: Mon, 25 Mar 2013 18:26:35 +0100 Subject: [PATCH 07/40] Update modAgenda.class.php Add export feature of calendar module --- htdocs/core/modules/modAgenda.class.php | 36 ++++++++++++++++++++----- 1 file changed, 30 insertions(+), 6 deletions(-) diff --git a/htdocs/core/modules/modAgenda.class.php b/htdocs/core/modules/modAgenda.class.php index d02be9ebf06..89c92a14c69 100644 --- a/htdocs/core/modules/modAgenda.class.php +++ b/htdocs/core/modules/modAgenda.class.php @@ -159,6 +159,12 @@ class modAgenda extends DolibarrModules $this->rights[$r][5] = 'delete'; $r++; + $this->rights[$r][0] = 2414; + $this->rights[$r][1] = 'Export actions/tasks of others'; + $this->rights[$r][2] = 'w'; + $this->rights[$r][3] = 0; + $this->rights[$r][4] = 'export'; + // Main menu entries $this->menu = array(); // List of menus to add $r=0; @@ -355,12 +361,30 @@ class modAgenda extends DolibarrModules //-------- $r=0; - // $this->export_code[$r] Code unique identifiant l'export (tous modules confondus) - // $this->export_label[$r] Libelle par defaut si traduction de cle "ExportXXX" non trouvee (XXX = Code) - // $this->export_permission[$r] Liste des codes permissions requis pour faire l'export - // $this->export_fields_sql[$r] Liste des champs exportables en codif sql - // $this->export_fields_name[$r] Liste des champs exportables en codif traduction - // $this->export_sql[$r] Requete sql qui offre les donnees a l'export + $r++; + $this->export_code[$r]=$this->rights_class.'_'.$r; + $this->export_label[$r]="Liste des action commerciales de l'agenda"; + $this->export_permission[$r]=array(array("agenda","export")); + $this->export_fields_array[$r]=array('a.id'=>'IdAgenda','a.label'=>'Actions','a.datep'=>'DateActionStart', + 'a.datea'=>'DateActionEnd','a.percent'=>'PercentDone','a.fk_user_author'=>'ActionAskedBy','a.fk_user_action'=>'ActionAffectedTo', + 'a.fk_user_done'=>"ActionDoneBy","a.priority"=>"Priority","a.fulldayevent"=>"EventOnFullDay","a.location"=>"Location", + "a.fk_soc"=>"Company","a.fk_contact"=>"contact","a.fk_action"=>"Action"); + + $this->export_TypeFields_array[$r]=array('a.id'=>'Numeric','a.label'=>'Text','a.datep'=>'Date','a.datep2'=>'Date', + 'a.datea'=>'Date','a.datea2'=>'Date','a.percent'=>'Numeric','a.fk_user_author'=>'List:user:name','a.fk_user_action'=>'List:user:name', + 'a.fk_user_done'=>"List:user:name","a.priority"=>"Numeric","a.fulldayevent"=>"Boolean","a.location"=>"Text", + "a.fk_soc"=>"List:Societe:nom","a.fk_contact"=>"List:socpeople:name","a.fk_action"=>"List:c_actioncomm:libelle:code"); + + $this->export_entities_array[$r]=array('a.id'=>'action','a.label'=>'action','a.datep'=>'action','a.datep2'=>'action', + 'a.datea'=>'action','a.datea2'=>'action','a.percent'=>'action','a.fk_user_author'=>'action','a.fk_user_action'=>'action', + 'a.fk_user_done'=>"action","a.priority"=>"action","a.fulldayevent"=>"action","a.location"=>"action", + "a.fk_soc"=>"action","a.fk_contact"=>"action","a.fk_action"=>"action"); + + $this->export_sql_start[$r]='SELECT DISTINCT '; + $this->export_sql_end[$r] =' FROM '.MAIN_DB_PREFIX.'actioncomm as a'; + $this->export_sql_end[$r] .=' Where a.entity = '.$conf->entity; + $this->export_sql_end[$r] .=' ORDER BY datep'; + } From 9dd4ed9cb8e9c5564efd43b3cbe7f32e3b8d94eb Mon Sep 17 00:00:00 2001 From: fhenry Date: Mon, 25 Mar 2013 19:28:34 +0100 Subject: [PATCH 08/40] [ task #770 ] Add ODT document generation for Projects module --- .../doctemplates/project/template_project.odt | Bin 0 -> 25790 bytes .../project/template_task_summary.odt | Bin 0 -> 15625 bytes htdocs/admin/project.php | 185 ++++--- htdocs/core/modules/modProjet.class.php | 7 + .../pdf/doc_generic_project_odt.modules.php | 481 ++++++++++++++++++ htdocs/projet/class/project.class.php | 3 +- 6 files changed, 593 insertions(+), 83 deletions(-) create mode 100755 documents/doctemplates/project/template_project.odt create mode 100755 documents/doctemplates/project/template_task_summary.odt create mode 100644 htdocs/core/modules/project/pdf/doc_generic_project_odt.modules.php diff --git a/documents/doctemplates/project/template_project.odt b/documents/doctemplates/project/template_project.odt new file mode 100755 index 0000000000000000000000000000000000000000..fcf5f52d80126f4af6bd2ecb629f5721a5b606f1 GIT binary patch literal 25790 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 literal 0 HcmV?d00001 diff --git a/documents/doctemplates/project/template_task_summary.odt b/documents/doctemplates/project/template_task_summary.odt new file mode 100755 index 0000000000000000000000000000000000000000..67c43a785d2dbac54867ce9f13a7565ed4acdeac GIT binary patch literal 15625 zcmeHubyS@>*DuB0DNx+4xVsm3cR3u~5AIT+I23m%T8g`Cf#U8~Xn{g;cP@0MGoATn z-u1orzq{7WS`Xw&_WorjPx4DncA_W)0f`9)1`7t}9_ucm-^+qX1qKH8^gJek*;v>B zo!sq#M)vmB762nB3p-mz7h4ksJ0p+-Pu7%hhj z2KMyeJc6m3JKGrB8d+F_7@dAb8SHJ%LKWpDklB!^M;m6IOLg-^+k=Q&C&!TlK8Avq`OylW|Sm$D~%I#-x|=X9+;0Cg$-g%Jv&9 zvObQC%3b9ex#SK&KrYH9-T6d~d_&1pB`RE3l_+j*RbL~QmNy^Qzd|X8Vk2plad5}4 z5Vx2H8fmS+y4cLRXxYLqn6`w1w1C+h^#+%WhCcI;5%MM`S0sXkn}QJm|8HL3om^MY zx|GkEp<7~@jtqR|xu9>j0(y3Q}RxyAM32aQGZ0gDCJYFa^+>!bW1l+D%&YZ}zaI{qR^R}1vOM+9Bwy6#4mK%DcJ@X5@ByeW( z8CMQB?Tlwq1iWV2$Hn|S6)&dcq$5|%zlseMrCLThotkj@inBA&4$Z&WnG2x`^aM&W zeQOb*_DN5t`t%KZ?Y(p;!u^)`;>i^0MP`FVT}Xfm3XiYnhSJTKZ#~iViv`nTL(-ue zYauexWPUd=2Kq4=U#qj{s-8hrMJ3I4Ci-@UMH}w3GFgDnAw}W}q$Ax4`U&$joYBa- zV`qB3=pFIX-_u>~#Qq$YWq1uQxd^Xw^X%rqPwAW93L+6dIE1<=GLqeJ&=HXk&tfGA znXOOsy4q0h5sK-XM$E^??(l>0TNc67MkXUZuSTfe2Y6)qz%Ie=4_n!s9l>hEI0x|6te(i;I!{_8E-#fFPI` z<*qy2z2dXG(h6I`CClJTPvH^&6$|@w3F@~UI$2%&jKrZ(TQ7vVAbfDrX@cVIKg(o? z2GbHmOa-hH!me6iuYR3JJwdnyJb)|A`zygYJC9`tRnH2++kbuenzQTdPVpL+{4{_F zMK}ViMD~qoryNAYh@&1=k6#O1%py$0V)pyzZ!t)ipN|v^mqM40G`B!aNptBVSkvKj z`O`uA!?CbtThOT{i8_)@z3xf}=kkIrp31KFi-%E1R^=4UvPI8|CD}kJ=Ty8ts6r>#Ht6O_UE%Ix3aM`+WGk=owBMazQ15 zXPci4uOBx28d>%d_(ge0V=2Nxz%bB$G>Iu`d9!0AOj$D7=)q>8TA#6P!W1IHJ{b<- z6_~d~(oOY|%rwk1Vd#kC`JP}SjFt<<7=e|_@z^dOIv3REh|Tq^8=g21LDxb7usaYW z{?|g1kYf+;ZtrUo^4E;EC$nBK6j(!-TzlnHvu4_%*y37B<8^;cU+2`&*eN+Ymu6v+#%iXh;ThZ?4zgnt(zu^22y%KIAFqYN7?_n^)kUahELVhAU;3Wd>BD3u z@X#2iI-hak$>w;Q@^Q+lc&VhP(ROiJMw9s6gtS$TFIY)tes%&#LZ(%*aO027o+xh^ zpQ*_tM_4iArtW+%g%0aX5@%Ha53JLs30tJ2f9tJ69PS@XMw_p0glaDbUz>;?@)}J1 zgcKNGH9rA08?uD^Y)P=|Ra?VQTjj0MVxYLU#U%Dyn8a0z%DYKMuZ62=MvHOdo5{EC z7>PsGc0*cR9#MCV2NN*X(HHdIjmy0-g)Y}#F=b!n?_lU<2~$U1Jz+y0Btw}DuKU_$ zF$yox6bsT;OWqUK6H9#gqNGf!$$;<XL}KFxXGtlT0_$y?U88HK=`er{Ni)E83b! zM8?@l(=a_KJF+OV~aJ7hgUndFNBM3&GfjKwIueYJ1Awqng>!TwrxZBjcYa4iY zNXRcjUTt@1p6q=<(Ya2Z(z>g!wssZ;2Jh^c46dvP&x?v?P%)Wxe&a^ao#r<)F9xZP zY8~s6OgiiGRBd-OO$eYMA&I8AfeMe9wUh6^yKlGg_TWN%+)FZ&u0B3qtPz9T2n?#* zx)&w=6mqDttmiuSEiVVt#xq(cqhqg__q%o+A$*|{z76b9R+}C-@q6hMPTyByu8tAi zr@+C~g;4M97B4IJhkyq2B%9aIx6Df)?(ZCwq!jKunQDXz+P!;H_VGFmhLik-ie5` zDz+EWiEpv`xe7U%xYo^?zp-1E&QqOle9;l5K+lvKl&PBUwbGzYI%3;q(~irLvcf!* z2}MgY9BwLhP`PGl7q*zz$-fj}oPz{Uu(VGg>c2n=a4$A6Q_xiZssJS)xcx;&I}M%O9(*Ds=hj5+ z_%x;abz<=_V;P?*^M`@y*e_I+dNz|A=T6t5wQ2QUhx9T-1ezYgM3$zfDQvk+?{*rZ zu`L*b)f=t$?xpF?1@!N4up%0xdqI2C0Ikj9Rx8d0g3;ntoOZ4HJrmKz-0!LzQ;2L7 zuF^u+hJBm884Lo#<4$i<@Dj}19HeoKZ4MVVOebgt8CERc&d%$z)2asGyW@1Pi1itp z*K|jjTaJ967jbrOrKMk0TefuKCcHM!?frW2Z6XVKDttVCiN@c%4faOh(9a4a^t{o0 z_oRH~=JrF>u*m2LmmMSc9!%%)mf-FwX?POvdD_kh5q~MbrgohqozKz^UxkLw$7_Ss3s` z+W^|FVHj!N`}g$p4U6>>^^R8335ju8)+F-?t{)K_S-~e@DBgtA`1&g3&naI6l)J_6 z4X+wA9&C53cO$(#PrGIr=9YTp9LjWE7X?_O7cZ@Wa8y+1Rg2{j*)F#mt)+tf2e^61 z_*Ua5bMI#eAoEbdUp=F0Ad5DJkIFgK|ejD9FWpRSH#UhrOU?Oj>gkOC$!y`)PbNC`W z%e^Dc)te~BgkaXwrZFdl_925h?~C!Bq{Zv#FubHu+nej6Hj0Ju%!k8Jmt;?Z`d1L&rMIA@cfqr5iKLth>Hc47zxQ0r;0?lpbI*8_miX|Hxu>FzYFfDnbPK| z)#UO&tXUZhHJSSJ>CA*HQ{(q_MP%BNRosMJ?r)qkB;OpIFA&U5FtWPLyj8!+xF@sd z+6}<~t-HrlEsVE4m5yj|+eLmLOZsA1q8?T9zVBYc$AE9g=%xg80ff^gCCY5s=!+Y) z?9x7FU4mNT<}DNY)Z!GjbOJu2o2k2)iCRAC$2fRuO4B3id#DK}5(=|~8#qb5lwjG? z<<9Izi+xIs<=ux6Q05D?$(Q-!U*PE-UzFC)G`-68x$~UuK`eF|b;b6L`FJ`Q%D&BGDc@-%Lh&+V zMEiDg}3kg5rf73Uv zOpPye6mm|k52cXb;y`+p>4S1*`(*G$GFsnBSNdvL2;zNW#T@85$dKD>G956UN-s7> zNK-@9A%m`yH0)f;$`su?8~1UHiF7y*p(ZwgppRK3)4Ph@F!PZnI{8>#_XYdq3xtYO z*Gvwki$a)jwIk*x46<+DLLuXU9ajoy=tU^6As^T4Xnq0<$Rp=O;1)so_aDo4BHkei z8&X-6T>6v?*y$cT>?EXmP-e`AnAz7gdVSF`u=WD<%>jIYUX3zDR2!O3Vc(r!HF+Eq zO2D)|B$Z&8k!B`mx}8ut*tRIsz~>HL*j(PHgPTBHJ0RQgPwVE6!Jg5sOl|GYdf#+5 zS;Sx$!_ky@;fMeB6fR3O9xDvT`Z zZCHeJ(u-kf854sAj*O5dtxY(n3fEGuaJ5*POK zN&fWb-Snhht|nbWRq5~O7xX@z_wgy#zE0#+)n5RzC7173ha3}d;@Ma1y-(D?B==jK z+iQn$6*rV|)~`*Z>?Fs=g|A;u9WHHWZYsy^lqXgnc5iHDr`^&}(ef{tVK-lV?9Z%z z^9k27tCq2?u|nieqnQc8*)f9*}FQOrl4iz zdRt3=a20FZ*D_F#F4Ay?P)Ipms`0#f3m!K_e3zHvY(&jA$TJf8N>-L{U&%?IsN~yH z%g`My+{GA-9X=6tyYu0coci+0M;bC9X^xshIJdRe-blURy+`wXY`OCG7hsugjx}@I zFIyIC>^Q7c!#F)lYt^q{3ZTxIz^}ZRKUi7P?TmgOqV#7ji{8GIgBMv`Zv1rbIL;syCCz z^2POJ=IX0`m(g97!!FXrTyN41<~!{q*RSwFUtjvPY_z&6AbxHBt^9y*f;;DJAinSY zM=ar>&y$8ZX3=CCpZbDo@?hP=CEuN)sA3Oj#bwRK>fRs1@KfJ@+7PjkihE`8Ri=b9Nka%~#>?|b;t4%S?)x>f`!4k_ z@2gm~6_R&TGZkHrS_`q$Q`!&95X;Bjkjc!O@pLC@=$Mhu*CnXl)d9H7n-O45Z*w!Q z5OQx7>TYMmPNYH@-*XgFPH3F(Gn}(foLeBcdM~)_!7Sc~4Rd8Ux}ptThCEy$EM{2a z;x~rY5D#ge$BCdrt>mEL?UmdK9Xar9*pd|;MZ0V=TD$TkOeT>>WVC){FV8`^s0q3n zbt}L7yb?W02r`fxRd(N{W(}5)uM(7qN;J88(eSI?l_PhKd38t^>>f2aA2r!L zCA%VXHB{NcH<_sY74>HGkg?x9>gDHXx0clNa+#jwQPTA}<;pJF@_rL-_GdUQY!u%w zElj+&>dKFgB`@~-@CV@0JakG?6@Qaiid zp@&wMKtT1fd-D!{{v*YSghYznB)3`F+~H2Dvu`ug-K7E9x$Wxd_}W+(b3f&(3w$~P z_s3w0!7o#sqw!K-^5xLZ8H~x@Ajf^*;NcN`56`eg3^i1F9$t6a;eIqnl3pZ6nGugp z#sODHpq$nC?giF{ET?TdXr%HDjzW424PY9qlyTXB#U-Fcj<>sufLoZ2mqt#T%tVjR zdCyW*UmKRU$T#cZ0CLhd!l`Vv;@0RUx6$K)^PS`efveeQ3f}fz%J#!GNR56j$E|cN z6;s@b^>+ZY$`lN(Tg{9t7wzYchOZEZqWx~~pXtIo;x+A_q>?myYNIv6l2Fc6z0qvm zGsG|96%q{jzut5HuQsUvzwrN)?R<&C#27b(Jj$s0=q3S^5|@Gs3;V;L z^OW;5AU;N{joj^=o#+8Z0COO~#L$HLGr-Ug_OpqhVJsL6n4$~}EX7nZFZ!e8)AR3G z2#>h{J6oqG$B&zh^@g^N-6993&uaOYs`Z>7?Q#A#dZ~jy`@CW{Qdln(G@_`GOnhk~ zDf`>1FIZOxym^nCu`)StO)X*t$k9f*iP}LFz>A*25Aj?wL*iZELV5Xc8juS}!qIsI z9Ry{4FQS%`;tupHxa39f#a<4n$mV0S(5}@(%&0;JoqinVM#4c4g{79Rgf+pbK%5+) zWvYc})u<%>nyQ&*1)S7gr?apsal)%JH*K$0=O`tMQm^Zk#tyJd?Hii8ltyJVMLlB^ zWtlg25J$h>{-`IJ0@c>8U5c#!1)_KB{_yg0ZgwKoUh_MUn@XDw-dna}LH4pcFvnoK zK$BF*M|w6-?8GU!(b+skj8_Y5u+drkK*k&q z(xy;E4Jq@p)3GfsfbNWc=pGEEiIply=Tm%5ee+xOVi2LYr<(uBT*ypF?@1z@KEDHA zTuU=?R6V>%bWfUWjq-A0%<=Hp=E=2gsFu7xX1X{~=uj=#{hinw^XhE>vE%|cO10)0 z$n#DxHAbu${vzc>s9|A}sWE4v zH)I3Jm(DWfnob$eH4_(`$s)wr?e3xVr0honvb|3XhM54O#+r+j0N*ZRX8cK4;j zb5XXA@xx$aYG*prQ5ZnJ@Z+A>tYxx;&VGJ*>~| zF>8G=;sTI2oi#S_!lzA^fF0n7Yj+Ar^*tzXFR$Ag9(3E=<54kuzT*(#+v&a+2>yDg zUO$gF@5>(2@fiC|@UQ^g5dk>uPcw3(=z;fG8DBAwkuBh*Nm||9*dJeBFXZjHjWpdK z*J~`~Juoof00owlg91HAmV9nKhnGeMmCZJ_`=&;MeZEsEq$~k5goF7Ei~&i>eiybR3?f&ls0~=4JDSsb0uMjA4+`h|!S5X1HDV^$ z5hOF#&x?RTq3*+ev+w&2Ry{LM7Uzk|M+s^J?fDK4&?&!H@HtYckPC2UC5%(_9XVf7 z3A4(UWrXv|p&959BUwFMNJ;E}B`_m$pw5_8osJmE#Nc}VDa00Q4sl$M+etn0E@gP? zKqf^ppxn2ZFu_1ju=HG+DNZ_GY*xWW62Cc4Mc1pLJXGU+-1Mj^iSa&CzBM3oDotF{ z7*?&7f=@p<|8T)+U?e&fOjn_CDV!nxV=ocLe#EPhZ9*nlGMOR}^vr=WVhWqaDqZ5xO%cJidM+ZkgKhnI&gXL{cwC|=Z2_JA%0o95 zgb-GD8~l0(#rbV{eHnRK2@v1-qfo#Bh+1G81sX6F^gtwAdaw9Zngbmtv7`6A)%cP&l}jCAuq`i$7HF?cO@A z_HW{0rwyw(Y`xE{dr+DBD)=-9A+p;H%0PpGsZso=Iq2!U0LaPR8VGutf|j+lqQ7vU z`>YxmQA@6v_q!0;n(;kz3FP;a1vl}?gwTFxV@j?>Oha_?y*><+LOO9N)rki-J%oIi zNAq@ve8W{Ry~@eaP}w22JaC>3p7Le1c-P4?&*kZ@T@|8_+e5Ugaq|YV4h1O#YogV= zQ*NLocvqvg);bS0unk?+p?1KccS^dCPN`xEuGDKkVSb1HA{udlM}6GHO!x(>7YWu9^s7Ws26VfF(}2Wj_vcY@to26ZDhKElGj9@S5J zT%H~t@JO{BTxC~b$_2r6p`wW_OR_=L+b^A3a3`Hgygz+Ui%*&l?jIjhlw)iuMs6NQ zbC^RC!Z>)3Pk30aEOH&eiRF@7W=OuI$ z{-P^^_!3m**uJ%1GcD_*}d`7&Ww8&MxGNi%p|$EV(uYQNBK%%2juAUMC8MYVvm zqF0S8Uh{?fC^)>r0)XG=so9poXGcKY^T-Ln9@rO_5gtEj( z1XjJ1Cp?!?&qcgf*Q&!i^YUL@^+#>kYr`sNZCi1{mjNU{LnJH_!TdNVoYmUB)0bUnl*(0&Xd(J^qW1ozD`>%BO{Frytc7OQO|unshd(0 zS2K6QW#2Nrniqq*s|-3kP%nw9kQU34)7=R8yxIxLyC=P8K^g_gp)MOY$@8Wloa;M9 zCa)Nhji1o0i5M1JaHib3$T1^02wZDx@WT*H4P%>05DTmNcPOjq5%_Y<5r?lH3cHwj z!0jGkVG8z7R}EU|RT$cq{yIYThp*uVr6-LIU;-0F+Xa|-qDJAcHV{Mr~u78aMMUT(h~(gnO^Xo zc0XXXd(N=7^ogF7YsJUoj)8>6#LssML^_GN`2Li_ASyj0B^rA+b&Uw=II`32?kjR& z;j>8gGi5V5@KPkP(k0wDMfQTuENp!7l)fgmz3x0hHV7`%%S)@=LNLVCB7!wzlx6>! z!v$iY+L5fgp1VEp-d(+$)#7FKu4SCbQWFujk`H6Y$(m<6+Q5 zWegkTV{l~Q(!F`kTX5lq*ZIcB0^lo(r%l8jgeyhaY50oUOQjey8D?z}@+7~FXs@n) zICnKOww9Dq7mJ2J?)l`$Ew{bi2OwK#<1Lg;g`&Y>zgpY}ZzJ)E@4z12=DqweHi(TT zzx-sLwf%^3pw%}9E}5Y9x(miaSB1d>x*gCn^*(z6lofAq~^08M`HftaV%%PbfE!gKxQiwC(PKuDw! zDN^u&e5GG<`lus7cOC+=eE1y?T8oVv^zb^0g1%2kB>Wu=ek6N89?tdclF=0{CrZzx zhWnhnD9!4Iv)ucsTYcK$dNV(;?hyQ(`C2`e1+Cd&qQK)=BW`UNyjaRotq$}ha%QnI z&o(2Ry~2kz3y`T}PaE0!RlkFrS7MXS&Gcr_xGk=8a1CRjil_9TxPIY#C1~NHyjFwH zq(eBQ8~tE|u~e6|W}ALKQ3Ed^GOiwSv_>>%c!#bi^`ij%j_kvdQRl-nP}hWJVZYDMrWkUFA9{LQ5R)mFJ1@#OA&?(bL)OAQ5soM7anA+j zB=_yJ^~@^%W;0&km5&dnA4qf?%m&Ub>hvy>iQEFt-aIA&)Fzw}L00EugR9 zZ)-WJC^8m|>-h>kB0LT%cEx%rf&0cW*-n1`)nh%HVVH6$IpS%+ggR`b??t1rdd8d& zgTPpg$>k0JJ0ts;n91Oy7w(Pf>#QNgteZRNOxKp6mkPm%U+Af=j_dn~wzRl{+#)ynd3okb zM+j*e6u)eS1g+?M{piiu8|}}qH#;`A_iWw`j=h!`eu@|*-1of&j&(8G%4Mw;(7-(= z&V#`W_KUV9!TK6(An@J8ThInXTcqUMaTRYKFGx!tLuF>_O@TtyZ({a^XKf$JV}jU1 zl&g&VUav`HYO#G^%h5sFKL8vNUEbDHrGCaJK|;WL>7pm1&g;7DyU5p2+eUgby5b$> z8nT>rVCr%+CefkOqB`~Z8&FpLbwshYM5|8io76I&;8UA(<9V6LsOyRcs+NNXl&6JA zva#B}(&ITu@R$E-A@cOY8U%E5vamJ#u@tG*UUXdNLiJuPm%QR%OT<%sOGDg^h=EQ` z9Jk<(;R3Pn$ufx?=JLj3K4v%|g`(F(x+lrj`NK{6BnziOVh)!(L_YU`PPwD{xxCOd zjy-qtS!Q3xq}9RTvH|Dg-YL{{R7O?lg#RvUOaO2dh|u#{fHxR}4}@wMux z*XSsdo$-6?L)%GQrX8&zAfjcMpgQbZlo0pHe)06l!nB;l?9f_)Clh;0-C*Cm_nLo- z*^4s0_;SW*)_a0W>&({O0r7m@Q8RD0z8+NYVpj9flyv`7~ZPM!85&Azmi8sgbL_;_q@mpjM7Cph4O5ZTGJcsbqUF8`$+wVOF*p{#+M z7KBNAHU|%we1#U`*jyc6wIbq0UsCOQGGWvvoX~nM&AqkL>;Vbx1tBak9)vG5+Hi?x zbiS+~sD2Ld@omV7r3Z=n5UPxCupta2Koz}49@BGtrHE@QlVVdR;HsS9cr8F49Yv02 zoV?O(YQ-TxV~(f-w}$#nN|&asim;N!i|z?TYBeSav<{b8?8FZTe6T{=W@UU{NMzMj zG$1uah#;PK!OmDhUAXcPhG<1mUG|WaE2eFvU2cgO%Aw^Ek~=iWRN3fU_VEmgDMn04 zNn7*`DcbJ&5Q=V;O2Q#@HXh_c&95UToHlNb2}&}H6e}b}l`CvejXN;ud z46+ZuPn`Ne*{Jaj=*f>!W4YXa)0ymn@Y5o;}YoqxNOO_mM?*NDzXjR;hai{IAaJ z+ZYVr@}g9H*^H~WDam0BV2=_6XOBHF*-;o<-gi@hCWqblP;g%@v})QFEl#?!G^LrP z?Lce4*5RS7BTC$A<6mbHQKf_i)T;d+FvG4nbzRR(#wj*|2#z;KZ7jfz0|?+wBqo4; zN76Zr>cFd~8qGGLR;;0s)JN^A_*`Q*l-gg0=iNSce@fgpUbSoszPj3ER)+w1dWTyG zDjP~~)E=`Edbg>mJ?=eJq|#yJ~}oi}PMJx%88m~^_dRa?}C&?PK{qBv-@ zyHMM=+qvuVEK^zX?;V!$9nilfKc`(EcSdQ1gfM0^hFCYZMVPH*MVQ|=UQqTpKY#^n z91NYpgtwx32HJsB$u5<*hblsrGq|)8;mM5fzx7$SLna+#;O*%>W4)uDOtSG`2ukmN zzJePP2dBODaod%c>;&yu1=9P&lToEluZgjWV1%Y0kMy(;%1BJ!y>Zb6L-Px#B|CkG ziym*X?hD<2tK@VB!Toq><|}bxTd3aqYI42RU9W4H=@h}JsJ$*zYo>fG?9iP`xE8YT z4~X-zE8`BTDu*fL?wl+*HaH*05zonHf)z9pg-#JTPb4S-l-lR%1IztWll%VnX2|fn zl_k?{$Sih7qYW=dYTqc#w43f0;Nl)@x0FkmZqggW%J@l1aa+RhzBEx%s8uhUE-#Cw z#`0u4EEJs}&yQ2@KqsT8-;{iUkAH|=fR3QY zbMO45%nVGV#6VksoyjB9^OLHnzM|(M6%>Hyvokfd004P@9)+iWJTq@Z{HSUR;`uF$ zpVZmWmgmQzc^+FM8z6|s3BdE~>3N=CrFni7^jnIXwS}z}KdHHslRXb3qpPbcgDWe8 zoue5eGdDLk}dT%$^^g&v<5z%&j&FwGcYs$lzp=Be{0l}?5`%- z+1dS3&{G|LtKyI1SeTgD7=L^JS(2HfiHY?e^1oEzQI?g_jM2o%$%x*?0_aLcO8k2} z{?gzqqyj%%_sI+acw#;i0MDZiP=JMrnU$W2m7axNm6@A|nVE;3nUC>jCf^UEfhHDD zlQO-Dv*VAe3j&JFVyeuN>@0E|DtwIpEb>=PfIHxEe?fqg{cqyGr~f8w2DAk}7GUQn zAZual2vqpd8yHy`ILKu!Y@OWPoETX-m~5EIMVu|HP3T#E zFXKTJ&@C5RY6V`0OB9@b22iv2GRrU zoNb->NguoKk3(z}{lH~~TSMu10){w~SR#zo2~@LLU?L5~O~KvN4_ zpviC5cp6Fkq*At~c8)ei0E_NwTVm$_PMqbx6KDPJ#Mz$2e;*D!PYwU)+aI6nNAkb> zS)P`bHb%Axq>eb&UnmkzcHp&BAbyj)Ob=_~i4u2b&fa>TVe4ez zJ3hlhx~S2)l{bh58~UGHEB18*SG^LX4f%WHOEA166H^1UUOkS0rd zXm4llZ2!oJ&WwM(t@MY|V}$4*^nMH)5Tl5NlZ}x*=szgq|AX@5csFwdf5|mn&2_S~v;NOo|5V8*Eqfzdp!I)QnyIzjBe(vyHa@lHpEmxJ@A2tA+23ns1OPnF zO+Sc}5#a3T_`5F=;)fgZQ6B8+`qxwV_wV#iRevHt=U*E7pUlB}M3oa)6{eSxf5rI6 z_IpFr&uRHlQ_!5 zWHvkk=sb?(-B`_sl39s@YF7$F5_N^?pz>yB^Uc;M2?+}Nx=BHe1<^3)pAOx|4w55mT>I{&r%$Y- zE`&1nKzt&3LEwNfBL`7c%D&4B$A>=Wt#FwXN;noBi!wCIC_lgTuTJbI3jH&T zJ>Et9)d~K0&0k#)PfqSX1O8)Y`^Dw`cg0_~3Z6U@e}-)0U;Pw+*ZXx<`d3qFX#Tpb z@Kf{OR;_=Qc+T)RYdp?3PixqpT0fiSSK|C@d9PXjI@kQv{8`?g_+Vg91Mkn!&GtV> z_pdbj*N*Y0-fu+v=ljh+;QSBT{dce@;{7vlvHycnf1%-jM|vXSKZD~xApJ?p|Bmw4 zMk@Ljl%F*H?>K+8=JP+`{7KvYTa@P<|Fd=er19TSes-CsmiWoVPelG_ko^agf1&mN xeQ(PB2hd+h{jbLTN * Copyright (C) 2011 Laurent Destailleur - * Copyright (C) 2011-2012 Juanjo Menent - * Copyright (C) 2011-2013 Philippe Grand - * - * 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 . - */ +* Copyright (C) 2011-2012 Juanjo Menent +* Copyright (C) 2011-2013 Philippe Grand +* +* 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/admin/project.php * \ingroup project * \brief Page to setup project module - */ +*/ require '../main.inc.php'; require_once DOL_DOCUMENT_ROOT.'/core/lib/admin.lib.php'; @@ -45,7 +45,7 @@ $type='project'; /* * Actions - */ +*/ if ($action == 'updateMask') { @@ -56,14 +56,14 @@ if ($action == 'updateMask') if (! $res > 0) $error++; - if (! $error) - { - $mesg = "".$langs->trans("SetupSaved").""; - } - else - { - $mesg = "".$langs->trans("Error").""; - } + if (! $error) + { + $mesg = "".$langs->trans("SetupSaved").""; + } + else + { + $mesg = "".$langs->trans("Error").""; + } } else if ($action == 'specimen') @@ -78,7 +78,7 @@ else if ($action == 'specimen') $dirmodels=array_merge(array('/'),(array) $conf->modules_parts['models']); foreach($dirmodels as $reldir) { - $file=dol_buildpath($reldir."core/modules/project/pdf/pdf_".$modele.".modules.php",0); + $file=dol_buildpath($reldir."core/modules/project/pdf/pdf_".$modele.".modules.php",0); if (file_exists($file)) { $filefound=1; @@ -95,8 +95,8 @@ else if ($action == 'specimen') if ($module->write_file($project,$langs) > 0) { - header("Location: ".DOL_URL_ROOT."/document.php?modulepart=project&file=SPECIMEN.pdf"); - return; + header("Location: ".DOL_URL_ROOT."/document.php?modulepart=project&file=SPECIMEN.pdf"); + return; } else { @@ -122,7 +122,7 @@ else if ($action == 'del') $ret = delDocumentModel($value, $type); if ($ret > 0) { - if ($conf->global->PROJECT_ADDON_PDF == "$value") dolibarr_del_const($db, 'PROJECT_ADDON_PDF',$conf->entity); + if ($conf->global->PROJECT_ADDON_PDF == "$value") dolibarr_del_const($db, 'PROJECT_ADDON_PDF',$conf->entity); } } @@ -154,7 +154,7 @@ else if ($action == 'setmod') /* * View - */ +*/ $dirmodels=array_merge(array('/'),(array) $conf->modules_parts['models']); @@ -179,8 +179,8 @@ dol_fiche_head($head, $hselected, $langs->trans("ModuleSetup")); /* * Projects Numbering model - */ - +*/ + print_titre($langs->trans("ProjectsNumberingModules")); print ''; @@ -284,7 +284,7 @@ print '

'; /* * Document templates generators - */ +*/ print_titre($langs->trans("ProjectsModelModule")); @@ -337,59 +337,80 @@ foreach ($dirmodels as $reldir) { while (($file = readdir($handle))!==false) { - if (substr($file, dol_strlen($file) -12) == '.modules.php' && substr($file,0,4) == 'pdf_') + if (preg_match('/\.modules\.php$/i',$file) && preg_match('/^(pdf_|doc_)/',$file)) { - $name = substr($file, 4, dol_strlen($file) -16); - $classname = substr($file, 0, dol_strlen($file) -12); - - $var=!$var; - print "\n $name"; - print "\n \n"; - require_once $dir.$file; - $module = new $classname($db); - print $module->description; - print "\n"; - - // Active - if (in_array($name, $def)) + if (file_exists($dir.'/'.$file)) { - print "\n"; - print 'scandir.'&label='.urlencode($module->name).'">'; - print img_picto($langs->trans("Enabled"),'switch_on'); - print ''; - print ""; - } - else - { - print "\n"; - print 'scandir.'&label='.urlencode($module->name).'">'.img_picto($langs->trans("Disabled"),'switch_off').''; - print ""; - } + $name = substr($file, 4, dol_strlen($file) -16); + $classname = substr($file, 0, dol_strlen($file) -12); - // Default - print ""; - if ($conf->global->PROJECT_ADDON_PDF == "$name") - { - print img_picto($langs->trans("Default"),'on'); - } - else - { - print 'scandir.'&label='.urlencode($module->name).'" alt="'.$langs->trans("Default").'">'.img_picto($langs->trans("Disabled"),'off').''; - } - print ''; + require_once $dir.'/'.$file; + $module = new $classname($db); - // Info - $htmltooltip = ''.$langs->trans("Name").': '.$module->name; - $htmltooltip.='
'.$langs->trans("Type").': '.($module->type?$module->type:$langs->trans("Unknown")); - $htmltooltip.='
'.$langs->trans("Width").'/'.$langs->trans("Height").': '.$module->page_largeur.'/'.$module->page_hauteur; - $htmltooltip.='

'.$langs->trans("FeaturesSupported").':'; - $htmltooltip.='
'.$langs->trans("Logo").': '.yn($module->option_logo,1,1); - print ''; - $link=''.img_object($langs->trans("Preview"),'project').''; - print $form->textwithpicto('     '.$link,$htmltooltip,-1,0); - print ''; + $modulequalified=1; + if ($module->version == 'development' && $conf->global->MAIN_FEATURES_LEVEL < 2) $modulequalified=0; + if ($module->version == 'experimental' && $conf->global->MAIN_FEATURES_LEVEL < 1) $modulequalified=0; - print "\n"; + if ($modulequalified) + { + $var=!$var; + print ''; + print (empty($module->name)?$name:$module->name); + print "\n"; + if (method_exists($module,'info')) print $module->info($langs); + else print $module->description; + print "\n"; + + // Active + if (in_array($name, $def)) + { + print "\n"; + print 'scandir.'&label='.urlencode($module->name).'">'; + print img_picto($langs->trans("Enabled"),'switch_on'); + print ''; + print ""; + } + else + { + print "\n"; + print 'scandir.'&label='.urlencode($module->name).'">'.img_picto($langs->trans("Disabled"),'switch_off').''; + print ""; + } + + // Default + print ""; + if ($conf->global->PROJECT_ADDON_PDF == "$name") + { + print img_picto($langs->trans("Default"),'on'); + } + else + { + print 'scandir.'&label='.urlencode($module->name).'" alt="'.$langs->trans("Default").'">'.img_picto($langs->trans("Disabled"),'off').''; + } + print ''; + + // Info + $htmltooltip = ''.$langs->trans("Name").': '.$module->name; + $htmltooltip.='
'.$langs->trans("Type").': '.($module->type?$module->type:$langs->trans("Unknown")); + $htmltooltip.='
'.$langs->trans("Width").'/'.$langs->trans("Height").': '.$module->page_largeur.'/'.$module->page_hauteur; + $htmltooltip.='

'.$langs->trans("FeaturesSupported").':'; + $htmltooltip.='
'.$langs->trans("Logo").': '.yn($module->option_logo,1,1); + + // Preview + print ''; + if ($module->type == 'pdf') + { + print ''.img_object($langs->trans("Preview"),'bill').''; + } + else + { + print img_object($langs->trans("PreviewNotAvailable"),'generic'); + } + print ''; + + print "\n"; + } + } } } closedir($handle); diff --git a/htdocs/core/modules/modProjet.class.php b/htdocs/core/modules/modProjet.class.php index 877bea83b22..a17835ddcc6 100644 --- a/htdocs/core/modules/modProjet.class.php +++ b/htdocs/core/modules/modProjet.class.php @@ -86,6 +86,13 @@ class modProjet extends DolibarrModules $this->const[$r][4] = 0; $r++; + $r++; + $this->const[$r][0] = "PROJECT_ADDON_PDF_ODT_PATH"; + $this->const[$r][1] = "chaine"; + $this->const[$r][2] = "DOL_DATA_ROOT/doctemplates/project"; + $this->const[$r][3] = ""; + $this->const[$r][4] = 0; + // Boxes $this->boxes = array(); diff --git a/htdocs/core/modules/project/pdf/doc_generic_project_odt.modules.php b/htdocs/core/modules/project/pdf/doc_generic_project_odt.modules.php new file mode 100644 index 00000000000..7ba6defaa3b --- /dev/null +++ b/htdocs/core/modules/project/pdf/doc_generic_project_odt.modules.php @@ -0,0 +1,481 @@ + + * Copyright (C) 2012 Juanjo Menent + * 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 . + * or see http://www.gnu.org/ + */ + +/** + * \file htdocs/core/modules/project/doc/doc_generic_project_odt.modules.php + * \ingroup commande + * \brief File of class to build ODT documents for third parties + */ + +require_once DOL_DOCUMENT_ROOT.'/core/modules/project/modules_project.php'; +require_once DOL_DOCUMENT_ROOT.'/projet/class/project.class.php'; +require_once DOL_DOCUMENT_ROOT.'/projet/class/task.class.php'; +require_once DOL_DOCUMENT_ROOT.'/core/lib/company.lib.php'; +require_once DOL_DOCUMENT_ROOT.'/core/lib/functions2.lib.php'; +require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php'; +require_once DOL_DOCUMENT_ROOT.'/core/lib/doc.lib.php'; + + +/** + * Class to build documents using ODF templates generator + */ +class doc_generic_project_odt extends ModelePDFProjects +{ + var $emetteur; // Objet societe qui emet + + var $phpmin = array(5,2,0); // Minimum version of PHP required by module + var $version = 'dolibarr'; + + + /** + * Constructor + * + * @param DoliDB $db Database handler + */ + function __construct($db) + { + global $conf,$langs,$mysoc; + + $langs->load("main"); + $langs->load("companies"); + + $this->db = $db; + $this->name = "ODT templates"; + $this->description = $langs->trans("DocumentModelOdt"); + $this->scandir = 'PROJECT_ADDON_PDF_ODT_PATH'; // Name of constant that is used to save list of directories to scan + + // Dimension page pour format A4 + $this->type = 'odt'; + $this->page_largeur = 0; + $this->page_hauteur = 0; + $this->format = array($this->page_largeur,$this->page_hauteur); + $this->marge_gauche=0; + $this->marge_droite=0; + $this->marge_haute=0; + $this->marge_basse=0; + + $this->option_logo = 1; // Affiche logo + $this->option_tva = 0; // Gere option tva COMMANDE_TVAOPTION + $this->option_modereg = 0; // Affiche mode reglement + $this->option_condreg = 0; // Affiche conditions reglement + $this->option_codeproduitservice = 0; // Affiche code produit-service + $this->option_multilang = 0; // Dispo en plusieurs langues + $this->option_escompte = 0; // Affiche si il y a eu escompte + $this->option_credit_note = 0; // Support credit notes + $this->option_freetext = 1; // Support add of a personalised text + $this->option_draft_watermark = 0; // Support add of a watermark on drafts + + // Recupere emetteur + $this->emetteur=$mysoc; + if (! $this->emetteur->pays_code) $this->emetteur->pays_code=substr($langs->defaultlang,-2); // Par defaut, si n'etait pas defini + } + + + /** + * Define array with couple substitution key => substitution value + * + * @param Object $object Main object to use as data source + * @param Translate $outputlangs Lang object to use for output + * @return array Array of substitution + */ + function get_substitutionarray_object($object,$outputlangs) + { + global $conf; + dol_syslog(get_class($this)."::get_substitutionarray_object object=".var_export($object,true), LOG_DEBUG); + return array( + 'object_id'=>$object->id, + 'object_ref'=>$object->ref, + 'object_title'=>$object->title, + 'object_description'=>$object->description, + 'object_date_creation'=>dol_print_date($object->date_c,'day'), + 'object_date_modification'=>dol_print_date($object->date_m,'day'), + 'object_date_start'=>dol_print_date($object->date_start,'day'), + 'object_date_end'=>dol_print_date($object->date_end,'day'), + 'object_note_private'=>$object->note_private, + 'object_note_public'=>$object->note_public, + 'object_public'=>$object->public, + 'object_statut'=>$object->getLibStatut() + ); + } + + /** + * Define array with couple substitution key => substitution value + * + * @param array $line Array of lines + * @param Translate $outputlangs Lang object to use for output + * @return array Return a substitution array + */ + function get_substitutionarray_lines($line,$outputlangs) + { + global $conf; + + return array( + 'line_ref'=>$line->ref, + 'line_fk_project'=>$line->fk_project, + 'line_projectref'=>$line->projectref, + 'line_projectlabel'=>$line->projectlabel, + 'line_label'=>$line->label, + 'line_description'=>$line->description, + 'line_fk_parent'=>$line->fk_parent, + 'line_duration'=>$line->duration, + 'line_progress'=>$line->progress, + 'line_public'=>$line->public, + 'line_date_start'=>dol_print_date($line->date_start,'day'), + 'line_date_end'=>dol_print_date($line->date_end,'day') + ); + } + + /** + * Return description of a module + * + * @param Translate $langs Lang object to use for output + * @return string Description + */ + function info($langs) + { + global $conf,$langs; + + $langs->load("companies"); + $langs->load("errors"); + + $form = new Form($this->db); + + $texte = $this->description.".
\n"; + $texte.= '
'; + $texte.= ''; + $texte.= ''; + $texte.= ''; + $texte.= ''; + + // List of directories area + $texte.= ''; + + + $texte.= ''; + $texte.= ''; + + /*$texte.= ''; + $texte.= ''; + $texte.= '';*/ + + $texte.= '
'; + $texttitle=$langs->trans("ListOfDirectories"); + $listofdir=explode(',',preg_replace('/[\r\n]+/',',',trim($conf->global->PROJECT_ADDON_PDF_ODT_PATH))); + $listoffiles=array(); + foreach($listofdir as $key=>$tmpdir) + { + $tmpdir=trim($tmpdir); + $tmpdir=preg_replace('/DOL_DATA_ROOT/',DOL_DATA_ROOT,$tmpdir); + if (! $tmpdir) { unset($listofdir[$key]); continue; } + if (! is_dir($tmpdir)) $texttitle.=img_warning($langs->trans("ErrorDirNotFound",$tmpdir),0); + else + { + $tmpfiles=dol_dir_list($tmpdir,'files',0,'\.odt'); + if (count($tmpfiles)) $listoffiles=array_merge($listoffiles,$tmpfiles); + } + } + $texthelp=$langs->trans("ListOfDirectoriesForModelGenODT"); + // Add list of substitution keys + $texthelp.='
'.$langs->trans("FollowingSubstitutionKeysCanBeUsed").'
'; + $texthelp.=$langs->transnoentitiesnoconv("FullListOnOnlineDocumentation"); // This contains an url, we don't modify it + + $texte.= $form->textwithpicto($texttitle,$texthelp,1,'help','',1); + $texte.= ''; + $texte.= ''; + $texte.= ''; + $texte.= '
'; + $texte.= ''; + $texte.= '  '; + $texte.= ''; + $texte.= '
'; + + // Scan directories + if (count($listofdir)) $texte.=$langs->trans("NumberOfModelFilesFound").': '.count($listoffiles).''; + + $texte.= '
'; + $texte.= $langs->trans("ExampleOfDirectoriesForModelGen"); + $texte.= '
'; + $texte.= ''; + $texte.= '
'; + $texte.= '
'; + + return $texte; + } + + /** + * Function to build a document on disk using the generic odt module. + * + * @param Commande $object Object source to build document + * @param Translate $outputlangs Lang output object + * @param string $srctemplatepath Full path of source filename for generator using a template file + * @return int 1 if OK, <=0 if KO + */ + function write_file($object,$outputlangs,$srctemplatepath) + { + global $user,$langs,$conf,$mysoc; + + if (empty($srctemplatepath)) + { + dol_syslog("doc_generic_odt::write_file parameter srctemplatepath empty", LOG_WARNING); + return -1; + } + + if (! is_object($outputlangs)) $outputlangs=$langs; + $sav_charset_output=$outputlangs->charset_output; + $outputlangs->charset_output='UTF-8'; + + $outputlangs->load("main"); + $outputlangs->load("dict"); + $outputlangs->load("companies"); + $outputlangs->load("projects"); + + if ($conf->projet->dir_output) + { + // If $object is id instead of object + if (! is_object($object)) + { + $id = $object; + $object = new Project($this->db); + $result=$object->fetch($id); + if ($result < 0) + { + dol_print_error($this->db,$object->error); + return -1; + } + } + + $dir = $conf->projet->dir_output; + $objectref = dol_sanitizeFileName($object->ref); + if (! preg_match('/specimen/i',$objectref)) $dir.= "/" . $objectref; + $file = $dir . "/" . $objectref . ".odt"; + + if (! file_exists($dir)) + { + if (dol_mkdir($dir) < 0) + { + $this->error=$langs->transnoentities("ErrorCanNotCreateDir",$dir); + return -1; + } + } + + if (file_exists($dir)) + { + //print "srctemplatepath=".$srctemplatepath; // Src filename + $newfile=basename($srctemplatepath); + $newfiletmp=preg_replace('/\.odt/i','',$newfile); + $newfiletmp=preg_replace('/template_/i','',$newfiletmp); + $newfiletmp=preg_replace('/modele_/i','',$newfiletmp); + $newfiletmp=$objectref.'_'.$newfiletmp; + //$file=$dir.'/'.$newfiletmp.'.'.dol_print_date(dol_now(),'%Y%m%d%H%M%S').'.odt'; + $file=$dir.'/'.$newfiletmp.'.odt'; + //print "newdir=".$dir; + //print "newfile=".$newfile; + //print "file=".$file; + //print "conf->societe->dir_temp=".$conf->societe->dir_temp; + + dol_mkdir($conf->projet->dir_temp); + + + // List of all contact + $usecontact=false; + $arrayidcontact=$object->liste_contact(-1,'internal'); + if (count($arrayidcontact) > 0) + { + $usecontact=true; + $result=$object->fetch_contact($arrayidcontact[0]['id']); + } + + $socobject=$object->thirdparty; + + // Make substitution + $substitutionarray=array( + '__FROM_NAME__' => $this->emetteur->nom, + '__FROM_EMAIL__' => $this->emetteur->email, + ); + complete_substitutions_array($substitutionarray, $langs, $object); + + // Open and load template + require_once ODTPHP_PATH.'odf.php'; + $odfHandler = new odf( + $srctemplatepath, + array( + 'PATH_TO_TMP' => $conf->projet->dir_temp, + 'ZIP_PROXY' => 'PclZipProxy', // PhpZipProxy or PclZipProxy. Got "bad compression method" error when using PhpZipProxy. + 'DELIMITER_LEFT' => '{', + 'DELIMITER_RIGHT' => '}' + ) + ); + // After construction $odfHandler->contentXml contains content and + // [!-- BEGIN row.lines --]*[!-- END row.lines --] has been replaced by + // [!-- BEGIN lines --]*[!-- END lines --] + //print html_entity_decode($odfHandler->__toString()); + //print exit; + + // Make substitutions into odt of user info + $tmparray=$this->get_substitutionarray_user($user,$outputlangs); + //var_dump($tmparray); exit; + foreach($tmparray as $key=>$value) + { + try { + if (preg_match('/logo$/',$key)) // Image + { + //var_dump($value);exit; + if (file_exists($value)) $odfHandler->setImage($key, $value); + else $odfHandler->setVars($key, 'ErrorFileNotFound', true, 'UTF-8'); + } + else // Text + { + $odfHandler->setVars($key, $value, true, 'UTF-8'); + } + } + catch(OdfException $e) + { + } + } + // Make substitutions into odt of mysoc + $tmparray=$this->get_substitutionarray_mysoc($mysoc,$outputlangs); + //var_dump($tmparray); exit; + foreach($tmparray as $key=>$value) + { + try { + if (preg_match('/logo$/',$key)) // Image + { + //var_dump($value);exit; + if (file_exists($value)) $odfHandler->setImage($key, $value); + else $odfHandler->setVars($key, 'ErrorFileNotFound', true, 'UTF-8'); + } + else // Text + { + $odfHandler->setVars($key, $value, true, 'UTF-8'); + } + } + catch(OdfException $e) + { + } + } + + // Make substitutions into odt of thirdparty + $tmparray=$this->get_substitutionarray_thirdparty($socobject,$outputlangs); + foreach($tmparray as $key=>$value) + { + try { + if (preg_match('/logo$/',$key)) // Image + { + if (file_exists($value)) $odfHandler->setImage($key, $value); + else $odfHandler->setVars($key, 'ErrorFileNotFound', true, 'UTF-8'); + } + else // Text + { + $odfHandler->setVars($key, $value, true, 'UTF-8'); + } + } + catch(OdfException $e) + { + } + } + + // Replace tags of object + external modules + $tmparray=$this->get_substitutionarray_object($object,$outputlangs); + complete_substitutions_array($tmparray, $outputlangs, $object); + foreach($tmparray as $key=>$value) + { + try { + if (preg_match('/logo$/',$key)) // Image + { + if (file_exists($value)) $odfHandler->setImage($key, $value); + else $odfHandler->setVars($key, 'ErrorFileNotFound', true, 'UTF-8'); + } + else // Text + { + $odfHandler->setVars($key, $value, true, 'UTF-8'); + } + } + catch(OdfException $e) + { + } + } + + // Replace tags of lines + try + { + $listlines = $odfHandler->setSegment('lines'); + + $taskstatic = new Task($this->db); + + // Security check + $socid=0; + if (!empty($object->fk_soc)) $socid = $object->fk_soc; + + $tasksarray=$taskstatic->getTasksArray(0, 0, $object->id, $socid, 0); + + foreach ($tasksarray as $task) + { + $tmparray=$this->get_substitutionarray_lines($task,$outputlangs); + complete_substitutions_array($tmparray, $outputlangs, $object, $task, "completesubstitutionarray_lines"); + foreach($tmparray as $key => $val) + { + try + { + $listlines->setVars($key, $val, true, 'UTF-8'); + } + catch(OdfException $e) + { + } + catch(SegmentException $e) + { + } + } + $listlines->merge(); + } + $odfHandler->mergeSegment($listlines); + } + catch(OdfException $e) + { + $this->error=$e->getMessage(); + dol_syslog($this->error, LOG_WARNING); + return -1; + } + + // Write new file + //$result=$odfHandler->exportAsAttachedFile('toto'); + $odfHandler->saveToDisk($file); + + if (! empty($conf->global->MAIN_UMASK)) + @chmod($file, octdec($conf->global->MAIN_UMASK)); + + $odfHandler=null; // Destroy object + + return 1; // Success + } + else + { + $this->error=$langs->transnoentities("ErrorCanNotCreateDir",$dir); + return -1; + } + } + + return -1; + } + +} + +?> diff --git a/htdocs/projet/class/project.class.php b/htdocs/projet/class/project.class.php index 97eb27745a8..226d7246e9b 100644 --- a/htdocs/projet/class/project.class.php +++ b/htdocs/projet/class/project.class.php @@ -260,7 +260,7 @@ class Project extends CommonObject if (empty($id) && empty($ref)) return -1; $sql = "SELECT rowid, ref, title, description, public, datec"; - $sql.= ", tms, dateo, datee, fk_soc, fk_user_creat, fk_statut, note_private, note_public"; + $sql.= ", tms, dateo, datee, fk_soc, fk_user_creat, fk_statut, note_private, note_public,model_pdf"; $sql.= " FROM " . MAIN_DB_PREFIX . "projet"; if (! empty($id)) { @@ -298,6 +298,7 @@ class Project extends CommonObject $this->user_author_id = $obj->fk_user_creat; $this->public = $obj->public; $this->statut = $obj->fk_statut; + $this->modelpdf = $obj->model_pdf; $this->db->free($resql); From b5751ab6586a497332b5113e07a9b1843f129a3a Mon Sep 17 00:00:00 2001 From: fhenry Date: Mon, 25 Mar 2013 19:31:17 +0100 Subject: [PATCH 09/40] Add copyright --- htdocs/admin/project.php | 31 ++++++++++++++------------- htdocs/projet/class/project.class.php | 1 + 2 files changed, 17 insertions(+), 15 deletions(-) diff --git a/htdocs/admin/project.php b/htdocs/admin/project.php index e971eb92e51..8bb1baae575 100644 --- a/htdocs/admin/project.php +++ b/htdocs/admin/project.php @@ -1,21 +1,22 @@ * Copyright (C) 2011 Laurent Destailleur -* Copyright (C) 2011-2012 Juanjo Menent -* Copyright (C) 2011-2013 Philippe Grand -* -* 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 . + * Copyright (C) 2011-2012 Juanjo Menent + * Copyright (C) 2011-2013 Philippe Grand + * 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 . */ /** diff --git a/htdocs/projet/class/project.class.php b/htdocs/projet/class/project.class.php index 226d7246e9b..d2864b08c11 100644 --- a/htdocs/projet/class/project.class.php +++ b/htdocs/projet/class/project.class.php @@ -3,6 +3,7 @@ /* Copyright (C) 2002-2005 Rodolphe Quiedeville * Copyright (C) 2005-2012 Laurent Destailleur * Copyright (C) 2005-2010 Regis Houssin + * 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 From 48e4ffb4b58995c4eb6ea8bbc1eae1604ee3b527 Mon Sep 17 00:00:00 2001 From: fhenry Date: Mon, 25 Mar 2013 19:32:30 +0100 Subject: [PATCH 10/40] Change-Id: I1aca3849ce75a7aea527a3897e4fcd0e70ccb428 --- .gitignore | 1 - 1 file changed, 1 deletion(-) diff --git a/.gitignore b/.gitignore index bc2110ab7ae..2d8658b869e 100755 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,5 @@ htdocs/conf/conf.php htdocs/conf/conf.php.old -documents/ custom/ custom2/ test/report/ From 26f120cbc7cf01c4a0efb72b592d6905069b9778 Mon Sep 17 00:00:00 2001 From: Regis Houssin Date: Tue, 26 Mar 2013 08:57:37 +0100 Subject: [PATCH 11/40] Fix: move doctemplates in install directory --- .gitignore | 1 + .../doctemplates/project/template_project.odt | Bin .../doctemplates/project/template_task_summary.odt | Bin 3 files changed, 1 insertion(+) rename {documents => htdocs/install}/doctemplates/project/template_project.odt (100%) rename {documents => htdocs/install}/doctemplates/project/template_task_summary.odt (100%) diff --git a/.gitignore b/.gitignore index 2d8658b869e..bc2110ab7ae 100755 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,6 @@ htdocs/conf/conf.php htdocs/conf/conf.php.old +documents/ custom/ custom2/ test/report/ diff --git a/documents/doctemplates/project/template_project.odt b/htdocs/install/doctemplates/project/template_project.odt similarity index 100% rename from documents/doctemplates/project/template_project.odt rename to htdocs/install/doctemplates/project/template_project.odt diff --git a/documents/doctemplates/project/template_task_summary.odt b/htdocs/install/doctemplates/project/template_task_summary.odt similarity index 100% rename from documents/doctemplates/project/template_task_summary.odt rename to htdocs/install/doctemplates/project/template_task_summary.odt From c97d712e50cdbed8bd2bdce34b51976e2d2f6465 Mon Sep 17 00:00:00 2001 From: fhenry Date: Tue, 26 Mar 2013 09:17:24 +0100 Subject: [PATCH 12/40] move doctemplate into install --- .gitignore | 1 + .../doctemplates/project/template_project.odt | Bin 0 -> 25790 bytes .../project/template_task_summary.odt | Bin 0 -> 15625 bytes 3 files changed, 1 insertion(+) create mode 100755 htdocs/install/doctemplates/project/template_project.odt create mode 100755 htdocs/install/doctemplates/project/template_task_summary.odt diff --git a/.gitignore b/.gitignore index 2d8658b869e..bc2110ab7ae 100755 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,6 @@ htdocs/conf/conf.php htdocs/conf/conf.php.old +documents/ custom/ custom2/ test/report/ diff --git a/htdocs/install/doctemplates/project/template_project.odt b/htdocs/install/doctemplates/project/template_project.odt new file mode 100755 index 0000000000000000000000000000000000000000..fcf5f52d80126f4af6bd2ecb629f5721a5b606f1 GIT binary patch literal 25790 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 literal 0 HcmV?d00001 diff --git a/htdocs/install/doctemplates/project/template_task_summary.odt b/htdocs/install/doctemplates/project/template_task_summary.odt new file mode 100755 index 0000000000000000000000000000000000000000..67c43a785d2dbac54867ce9f13a7565ed4acdeac GIT binary patch literal 15625 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 xeQ(PB2hd+h{jbLTN Date: Tue, 26 Mar 2013 15:48:12 +0100 Subject: [PATCH 13/40] Fix: [ bug #777 ] Withdrawal receipt set Credited --- htdocs/compta/paiement/class/paiement.class.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/htdocs/compta/paiement/class/paiement.class.php b/htdocs/compta/paiement/class/paiement.class.php index abf8e76f988..00741aad4d4 100644 --- a/htdocs/compta/paiement/class/paiement.class.php +++ b/htdocs/compta/paiement/class/paiement.class.php @@ -442,7 +442,7 @@ class Paiement extends CommonObject } // Add link 'company' in bank_url between invoice and bank transaction (for each invoice concerned by payment) - if (! $error) + if (! $error && $label != '(WithdrawalPayment)') { $linkaddedforthirdparty=array(); foreach ($this->amounts as $key => $value) // We should have always same third party but we loop in case of. From 2c56a1c8dc4e63e2cb6ca08971c16791badd561e Mon Sep 17 00:00:00 2001 From: BENKE Charles Date: Tue, 26 Mar 2013 16:49:02 +0100 Subject: [PATCH 14/40] Update mysql.class.php MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Create Table 'type' not supported on recent mysql databases, need to use 'engine' instead  --- htdocs/core/db/mysql.class.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/htdocs/core/db/mysql.class.php b/htdocs/core/db/mysql.class.php index 386624132f7..1143372bb98 100644 --- a/htdocs/core/db/mysql.class.php +++ b/htdocs/core/db/mysql.class.php @@ -931,7 +931,7 @@ class DoliDBMysql $sql .= ",".implode(',',$sqluq); if($keys != "") $sql .= ",".implode(',',$sqlk); - $sql .=") type=".$type; + $sql .=") engine=".$type; dol_syslog($sql,LOG_DEBUG); if(! $this -> query($sql)) From 33a82c396eca23d4ebc236fd914188b32f0b212a Mon Sep 17 00:00:00 2001 From: Regis Houssin Date: Tue, 26 Mar 2013 17:12:00 +0100 Subject: [PATCH 15/40] Fix: broken feature for use hooks with dol_move_uploaded_file method --- htdocs/core/class/fileupload.class.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/htdocs/core/class/fileupload.class.php b/htdocs/core/class/fileupload.class.php index 8afb5f39f42..c5e83017940 100644 --- a/htdocs/core/class/fileupload.class.php +++ b/htdocs/core/class/fileupload.class.php @@ -436,7 +436,7 @@ class FileUpload { file_put_contents($file_path, fopen($uploaded_file, 'r'), FILE_APPEND); } else { - dol_move_uploaded_file($uploaded_file, $file_path, 1); + dol_move_uploaded_file($uploaded_file, $file_path, 1, 0, 0, 0, 'userfile'); } } else From dff74667c275e24669f031e3d4a986a5e5dbd848 Mon Sep 17 00:00:00 2001 From: Regis Houssin Date: Tue, 26 Mar 2013 17:29:40 +0100 Subject: [PATCH 16/40] Fix: broken features due to the removal of the trigger FILE_UPLOAD ! --- htdocs/core/lib/files.lib.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/htdocs/core/lib/files.lib.php b/htdocs/core/lib/files.lib.php index c257b00e56d..d95bd707868 100644 --- a/htdocs/core/lib/files.lib.php +++ b/htdocs/core/lib/files.lib.php @@ -663,7 +663,7 @@ function dol_move_uploaded_file($src_file, $dest_file, $allowoverwrite, $disable } $hookmanager->initHooks(array('fileslib')); - $parameters=array('filename' => $file_name, 'varfiles' => $varfiles, 'allowoverwrite' => $allowoverwrite); + $parameters=array('src_file' => $src_file, 'file_name' => $file_name, 'varfiles' => $varfiles, 'allowoverwrite' => $allowoverwrite); $reshook=$hookmanager->executeHooks('moveUploadedFile', $parameters, $object); } From 4fe94b800bea6baa9dfe57e0cb635030e3275705 Mon Sep 17 00:00:00 2001 From: Regis Houssin Date: Tue, 26 Mar 2013 17:43:48 +0100 Subject: [PATCH 17/40] Fix: missing parameter --- htdocs/core/lib/files.lib.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/htdocs/core/lib/files.lib.php b/htdocs/core/lib/files.lib.php index d95bd707868..7557fa8322d 100644 --- a/htdocs/core/lib/files.lib.php +++ b/htdocs/core/lib/files.lib.php @@ -663,7 +663,7 @@ function dol_move_uploaded_file($src_file, $dest_file, $allowoverwrite, $disable } $hookmanager->initHooks(array('fileslib')); - $parameters=array('src_file' => $src_file, 'file_name' => $file_name, 'varfiles' => $varfiles, 'allowoverwrite' => $allowoverwrite); + $parameters=array('dest_files' => $dest_files, 'src_file' => $src_file, 'file_name' => $file_name, 'varfiles' => $varfiles, 'allowoverwrite' => $allowoverwrite); $reshook=$hookmanager->executeHooks('moveUploadedFile', $parameters, $object); } From b694451ab28e287fd7b46bf0856233407301f252 Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Tue, 26 Mar 2013 17:45:07 +0100 Subject: [PATCH 18/40] Use engine instead of type --- htdocs/core/db/mysqli.class.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/htdocs/core/db/mysqli.class.php b/htdocs/core/db/mysqli.class.php index 7d9d67f839c..2180546dc39 100644 --- a/htdocs/core/db/mysqli.class.php +++ b/htdocs/core/db/mysqli.class.php @@ -925,7 +925,7 @@ class DoliDBMysqli $sql .= ",".implode(',',$sqluq); if($keys != "") $sql .= ",".implode(',',$sqlk); - $sql .=") type=".$type; + $sql .=") engine=".$type; dol_syslog($sql,LOG_DEBUG); if(! $this -> query($sql)) From a701cbd77c97745ad540fcb2f724fca1f90d1503 Mon Sep 17 00:00:00 2001 From: Regis Houssin Date: Tue, 26 Mar 2013 17:47:37 +0100 Subject: [PATCH 19/40] Fix: wrong var name --- htdocs/core/lib/files.lib.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/htdocs/core/lib/files.lib.php b/htdocs/core/lib/files.lib.php index 7557fa8322d..d083751d819 100644 --- a/htdocs/core/lib/files.lib.php +++ b/htdocs/core/lib/files.lib.php @@ -663,7 +663,7 @@ function dol_move_uploaded_file($src_file, $dest_file, $allowoverwrite, $disable } $hookmanager->initHooks(array('fileslib')); - $parameters=array('dest_files' => $dest_files, 'src_file' => $src_file, 'file_name' => $file_name, 'varfiles' => $varfiles, 'allowoverwrite' => $allowoverwrite); + $parameters=array('dest_file' => $dest_file, 'src_file' => $src_file, 'file_name' => $file_name, 'varfiles' => $varfiles, 'allowoverwrite' => $allowoverwrite); $reshook=$hookmanager->executeHooks('moveUploadedFile', $parameters, $object); } From 61826b04d80b531b80d0901a66649d8057937486 Mon Sep 17 00:00:00 2001 From: Regis Houssin Date: Tue, 26 Mar 2013 17:12:00 +0100 Subject: [PATCH 20/40] Fix: broken feature for use hooks with dol_move_uploaded_file method --- htdocs/core/class/fileupload.class.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/htdocs/core/class/fileupload.class.php b/htdocs/core/class/fileupload.class.php index 8afb5f39f42..c5e83017940 100644 --- a/htdocs/core/class/fileupload.class.php +++ b/htdocs/core/class/fileupload.class.php @@ -436,7 +436,7 @@ class FileUpload { file_put_contents($file_path, fopen($uploaded_file, 'r'), FILE_APPEND); } else { - dol_move_uploaded_file($uploaded_file, $file_path, 1); + dol_move_uploaded_file($uploaded_file, $file_path, 1, 0, 0, 0, 'userfile'); } } else From e9a8457d7ed2b75f7801cb4b9699dd2e5a506d13 Mon Sep 17 00:00:00 2001 From: Regis Houssin Date: Tue, 26 Mar 2013 17:29:40 +0100 Subject: [PATCH 21/40] Fix: broken features due to the removal of the trigger FILE_UPLOAD ! --- htdocs/core/lib/files.lib.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/htdocs/core/lib/files.lib.php b/htdocs/core/lib/files.lib.php index 351b3fed386..cc756621172 100644 --- a/htdocs/core/lib/files.lib.php +++ b/htdocs/core/lib/files.lib.php @@ -649,7 +649,7 @@ function dol_move_uploaded_file($src_file, $dest_file, $allowoverwrite, $disable $hookmanager->initHooks(array('fileslib')); - $parameters=array('filename' => $file_name, 'varfiles' => $varfiles, 'allowoverwrite' => $allowoverwrite); + $parameters=array('src_file' => $src_file, 'file_name' => $file_name, 'varfiles' => $varfiles, 'allowoverwrite' => $allowoverwrite); $reshook=$hookmanager->executeHooks('moveUploadedFile', $parameters, $object); } From b5d13dc6e6938554c43265de5899cc97fd5aca00 Mon Sep 17 00:00:00 2001 From: Regis Houssin Date: Tue, 26 Mar 2013 17:43:48 +0100 Subject: [PATCH 22/40] Fix: missing parameter --- htdocs/core/lib/files.lib.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/htdocs/core/lib/files.lib.php b/htdocs/core/lib/files.lib.php index cc756621172..34fb66fb5ea 100644 --- a/htdocs/core/lib/files.lib.php +++ b/htdocs/core/lib/files.lib.php @@ -649,7 +649,7 @@ function dol_move_uploaded_file($src_file, $dest_file, $allowoverwrite, $disable $hookmanager->initHooks(array('fileslib')); - $parameters=array('src_file' => $src_file, 'file_name' => $file_name, 'varfiles' => $varfiles, 'allowoverwrite' => $allowoverwrite); + $parameters=array('dest_files' => $dest_files, 'src_file' => $src_file, 'file_name' => $file_name, 'varfiles' => $varfiles, 'allowoverwrite' => $allowoverwrite); $reshook=$hookmanager->executeHooks('moveUploadedFile', $parameters, $object); } From e75c609a0a80451530ba217c933baa8214c548d1 Mon Sep 17 00:00:00 2001 From: Regis Houssin Date: Tue, 26 Mar 2013 17:47:37 +0100 Subject: [PATCH 23/40] Fix: wrong var name --- htdocs/core/lib/files.lib.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/htdocs/core/lib/files.lib.php b/htdocs/core/lib/files.lib.php index 34fb66fb5ea..23bf990ae69 100644 --- a/htdocs/core/lib/files.lib.php +++ b/htdocs/core/lib/files.lib.php @@ -649,7 +649,7 @@ function dol_move_uploaded_file($src_file, $dest_file, $allowoverwrite, $disable $hookmanager->initHooks(array('fileslib')); - $parameters=array('dest_files' => $dest_files, 'src_file' => $src_file, 'file_name' => $file_name, 'varfiles' => $varfiles, 'allowoverwrite' => $allowoverwrite); + $parameters=array('dest_file' => $dest_file, 'src_file' => $src_file, 'file_name' => $file_name, 'varfiles' => $varfiles, 'allowoverwrite' => $allowoverwrite); $reshook=$hookmanager->executeHooks('moveUploadedFile', $parameters, $object); } From 19ae4a75d62767c3566853eee88ee76a1afb5e70 Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Tue, 26 Mar 2013 20:57:24 +0100 Subject: [PATCH 24/40] Qual: More robust function to run jobs --- htdocs/cron/card.php | 6 +- htdocs/cron/class/cronjob.class.php | 169 +++++++++++++++++++--------- 2 files changed, 117 insertions(+), 58 deletions(-) diff --git a/htdocs/cron/card.php b/htdocs/cron/card.php index fb936b58f3f..13ccb27cb0b 100644 --- a/htdocs/cron/card.php +++ b/htdocs/cron/card.php @@ -123,9 +123,9 @@ if ($action=='add') { // Save parameters if ($action=='update') { $object->id=$id; - $object->jobtype=GETPOST('jobtype','alpha'); - $object->label=GETPOST('label','alpha'); - $object->command=GETPOST('command','alpha'); + $object->jobtype=GETPOST('jobtype'); + $object->label=GETPOST('label'); + $object->command=GETPOST('command'); $object->classesname=GETPOST('classesname','alpha'); $object->priority=GETPOST('priority','int'); $object->objectname=GETPOST('objectname','alpha'); diff --git a/htdocs/cron/class/cronjob.class.php b/htdocs/cron/class/cronjob.class.php index 078ee98ad8e..b43f4ed9bd4 100644 --- a/htdocs/cron/class/cronjob.class.php +++ b/htdocs/cron/class/cronjob.class.php @@ -834,9 +834,12 @@ class Cronjob extends CommonObject { global $langs, $conf; + $error=0; + $now=dol_now(); + $langs->load('cron'); - if (empty($userlogin)) { + if (empty($userlogin)) { $this->error="User login is mandatory"; dol_syslog(get_class($this)."::run_jobs ".$this->error, LOG_ERR); return -1; @@ -845,27 +848,59 @@ class Cronjob extends CommonObject require_once DOL_DOCUMENT_ROOT.'/user/class/user.class.php'; $user=new User($this->db); $result=$user->fetch('',$userlogin); - if ($result<0) { + if ($result<0) + { $this->error="User Error:".$user->error; dol_syslog(get_class($this)."::run_jobs ".$this->error, LOG_ERR); return -1; - }else { - if (empty($user->id)) { + } + else + { + if (empty($user->id)) + { $this->error=" User user login:".$userlogin." do not exists"; dol_syslog(get_class($this)."::run_jobs ".$this->error, LOG_ERR); return -1; } } - dol_syslog(get_class($this)."::run_jobs userlogin:$userlogin", LOG_DEBUG); + dol_syslog(get_class($this)."::run_jobs jobtype=".$this->jobtype." userlogin=".$userlogin, LOG_DEBUG); - $error=0; - $now=dol_now(); - if ($this->jobtype=='method') { + // Increase limit of time. Works only if we are not in safe mode + $ExecTimeLimit=600; + if (!empty($ExecTimeLimit)) + { + $err=error_reporting(); + error_reporting(0); // Disable all errors + //error_reporting(E_ALL); + @set_time_limit($ExecTimeLimit); // Need more than 240 on Windows 7/64 + error_reporting($err); + } + if (!empty($MemoryLimit)) + { + @ini_set('memory_limit', $MemoryLimit); + } + + + // Update last run date (to track launch) + $this->datelastrun=$now; + $this->lastoutput=''; + $this->lastresult=''; + $this->nbrun=$this->nbrun+1; + $result = $this->update($user); + if ($result<0) { + dol_syslog(get_class($this)."::run_jobs ".$this->error, LOG_ERR); + return -1; + } + + // Run a method + if ($this->jobtype=='method') + { // load classes $ret=dol_include_once("/".$this->module_name."/class/".$this->classesname,$this->objectname); - if ($ret===false) { + if ($ret===false) + { $this->error=$langs->trans('CronCannotLoadClass',$file,$this->objectname); dol_syslog(get_class($this)."::run_jobs ".$this->error, LOG_ERR); return -1; @@ -873,7 +908,8 @@ class Cronjob extends CommonObject // Load langs $result=$langs->load($this->module_name.'@'.$this->module_name); - if ($result<0) { + if ($result<0) + { dol_syslog(get_class($this)."::run_jobs Cannot load module langs".$langs->error, LOG_ERR); return -1; } @@ -883,66 +919,89 @@ class Cronjob extends CommonObject // Create Object for the call module $object = new $this->objectname($this->db); - - //Update launch start date - $this->datelastrun=$now; - $this->nbrun=$this->nbrun+1; - $result = $this->update($user); - if ($result<0) { - dol_syslog(get_class($this)."::run_jobs ".$this->error, LOG_ERR); - return -1; - } - - $params_arr = array(); - $params_arr=explode(", ",$this->params); - if (!is_array($params_arr)) { + $params_arr = explode(", ",$this->params); + if (!is_array($params_arr)) + { $result = call_user_func(array($object, $this->methodename), $this->params); - }else { + } + else + { $result = call_user_func_array(array($object, $this->methodename), $params_arr); } - if ($result===false) { + if ($result===false) + { dol_syslog(get_class($this)."::run_jobs ".$object->error, LOG_ERR); return -1; - }else { + } + else + { $this->lastoutput=var_export($result,true); $this->lastresult=var_export($result,true); } - } elseif ($this->jobtype=='command') { - dol_syslog(get_class($this)."::run_jobs system:".$this->command, LOG_DEBUG); - $output_arr=array(); - - //Update launch start date - $this->datelastrun=$now; - $this->nbrun=$this->nbrun+1; - $result = $this->update($user); - if ($result<0) { - dol_syslog(get_class($this)."::run_jobs ".$this->error, LOG_ERR); - return -1; - } - - exec($this->command, $output_arr,$retval); - - dol_syslog(get_class($this)."::run_jobs output_arr:".var_export($output_arr,true), LOG_DEBUG); - - $this->lastoutput=''; - if (is_array($output_arr) && count($output_arr)>0) { - foreach($output_arr as $val) { - $this->lastoutput.=$val."\n"; - } - } - $this->lastresult=$retval; } - - //Update result date - $this->datelastresult=$now; + + // Run a command line + if ($this->jobtype=='command') + { + $command=escapeshellcmd($this->command); + $command.=" 2>&1"; + dol_mkdir($conf->cronjob->dir_temp); + $outputfile=$conf->cronjob->dir_temp.'/cronjob.'.$userlogin.'.out'; + + dol_syslog(get_class($this)."::run_jobs system:".$command, LOG_DEBUG); + $output_arr=array(); + + $execmethod=(empty($conf->global->MAIN_EXEC_USE_POPEN)?1:2); // 1 or 2 + if ($execmethod == 1) + { + exec($command, $output_arr, $retval); + } + if ($execmethod == 2) + { + $ok=0; + $handle = fopen($outputfile, 'w'); + if ($handle) + { + dol_syslog("Run command ".$command); + $handlein = popen($command, 'r'); + while (!feof($handlein)) + { + $read = fgets($handlein); + fwrite($handle,$read); + $output_arr[]=$read; + } + pclose($handlein); + fclose($handle); + } + if (! empty($conf->global->MAIN_UMASK)) @chmod($outputfile, octdec($conf->global->MAIN_UMASK)); + } + } + + dol_syslog(get_class($this)."::run_jobs output_arr:".var_export($output_arr,true), LOG_DEBUG); + + + // Update with result + $this->lastoutput=''; + if (is_array($output_arr) && count($output_arr)>0) + { + foreach($output_arr as $val) + { + $this->lastoutput.=$val."\n"; + } + } + $this->lastresult=$retval; + $this->datelastresult=dol_now(); $result = $this->update($user); - if ($result<0) { + if ($result < 0) + { dol_syslog(get_class($this)."::run_jobs ".$this->error, LOG_ERR); return -1; - }else { + } + else + { return 1; } From 8c053b2f8d254ac13fccb79b5a3c701517134511 Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Tue, 26 Mar 2013 21:18:01 +0100 Subject: [PATCH 25/40] Debug module cron --- htdocs/cron/list.php | 62 +++++++++++++------------- htdocs/langs/en_US/cron.lang | 25 +++++++++++ htdocs/theme/amarok/img/play.png | Bin 0 -> 836 bytes htdocs/theme/auguria/img/play.png | Bin 0 -> 836 bytes htdocs/theme/bureau2crea/img/play.png | Bin 0 -> 836 bytes htdocs/theme/cameleo/img/play.png | Bin 0 -> 836 bytes htdocs/theme/eldy/img/play.png | Bin 0 -> 836 bytes 7 files changed, 56 insertions(+), 31 deletions(-) create mode 100644 htdocs/theme/amarok/img/play.png create mode 100644 htdocs/theme/auguria/img/play.png create mode 100644 htdocs/theme/bureau2crea/img/play.png create mode 100644 htdocs/theme/cameleo/img/play.png create mode 100644 htdocs/theme/eldy/img/play.png diff --git a/htdocs/cron/list.php b/htdocs/cron/list.php index 5e972f0e55b..db36cc5d59b 100644 --- a/htdocs/cron/list.php +++ b/htdocs/cron/list.php @@ -146,9 +146,9 @@ print $langs->trans('CronWaitingJobs'); print "

"; if (count($object->lines)>0) { - + print ''; - print ''; + print ''; $arg_url='&page='.$page.'&status='.$status.'&search_label='.$search_label; print_liste_field_titre($langs->trans("CronLabel"),$_SERVEUR['PHP_SELF'],"t.label","",$arg_url,'',$sortfield,$sortorder); print_liste_field_titre($langs->trans("CronTask"),'','',"",$arg_url,'',$sortfield,$sortorder); @@ -161,15 +161,15 @@ if (count($object->lines)>0) { print_liste_field_titre($langs->trans("CronLastResult"),$_SERVEUR['PHP_SELF'],"t.lastresult","",$arg_url,'',$sortfield,$sortorder); print_liste_field_titre($langs->trans("CronLastOutput"),$_SERVEUR['PHP_SELF'],"t.lastoutput","",$arg_url,'',$sortfield,$sortorder); print ''; - + print ''; - + print ''."\n"; print ''; print ''; - - - + + + print ''; @@ -186,30 +186,30 @@ if (count($object->lines)>0) { print '  '; print ''; print ''; - + print ''; print ''; - - - + + + // Boucler sur chaque job $style='impair'; foreach($object->lines as $line){ // title profil if ($style=='pair') {$style='impair';} else {$style='pair';} - + print ''; - + print ''; - + print ''; - + print ''; - + print ''; - + print ''; - + print ''; - + print ''; - + print ''; - + print ''; - + print ''; - - print ''; - + print ''; } print '
'; print ''; print '
'; if(!empty($line->label)) { print ''.$line->label.''; - } + } else { print $langs->trans('CronNone'); } print ''; if ($line->jobtype=='method') { print $langs->trans('CronModule').':'.$line->module_name.'
'; @@ -219,7 +219,7 @@ if (count($object->lines)>0) { if(!empty($line->params)) { print '
'.$langs->trans('CronArgs').':'. $line->params; } - + }elseif ($line->jobtype=='command') { print $langs->trans('CronCommand').':'. dol_trunc($line->command); if(!empty($line->params)) { @@ -227,55 +227,55 @@ if (count($object->lines)>0) { } } print '
'; if(!empty($line->datestart)) {print dol_print_date($line->datestart,'dayhourtext');} else {print $langs->trans('CronNone');} print ''; if(!empty($line->dateend)) {print dol_print_date($line->dateend,'dayhourtext');} else {print $langs->trans('CronNone');} print ''; if(!empty($line->datelastrun)) {print dol_print_date($line->datelastrun,'dayhourtext');} else {print $langs->trans('CronNone');} print ''; if(!empty($line->datenextrun)) {print dol_print_date($line->datenextrun,'dayhourtext');} else {print $langs->trans('CronNone');} print ''; if($line->unitfrequency == "60") print $langs->trans('CronEach')." ".($line->frequency/$line->unitfrequency)." ".$langs->trans('Minutes'); if($line->unitfrequency == "3600") print $langs->trans('CronEach')." ".($line->frequency/$line->unitfrequency)." ".$langs->trans('Hours'); if($line->unitfrequency == "86400") print $langs->trans('CronEach')." ".($line->frequency/$line->unitfrequency)." ".$langs->trans('Days'); if($line->unitfrequency == "604800") print $langs->trans('CronEach')." ".($line->frequency/$line->unitfrequency)." ".$langs->trans('Weeks'); print ''; if(!empty($line->nbrun)) {print $line->nbrun;} else {print '0';} print ''; if(!empty($line->lastresult)) {print dol_trunc($line->lastresult);} else {print $langs->trans('CronNone');} print ''; if(!empty($line->lastoutput)) {print dol_trunc(nl2br($line->lastoutput),100);} else {print $langs->trans('CronNone');} print ''; + + print ''; if ($user->rights->cron->delete) { - print "id."&status=".$status."&action=delete\" title=\"".$langs->trans('CronDelete')."\">\"".$langs-trans('CronDelete')."\" />"; + print "id."&status=".$status."&action=delete\" title=\"".$langs->trans('CronDelete')."\">".img_delete()."  "; } else { - print "trans('NotEnoughPermissions')."\">\"".$langs-trans('NotEnoughPermissions')."\" />"; + print "trans('NotEnoughPermissions')."\">".img_delete()."   "; } if ($user->rights->cron->execute) { - print "id."&status=".$status."&action=execute\" title=\"".$langs->trans('CronExecute')."\">\"".$langs-trans('CronExecute')."\" />"; + print "id."&status=".$status."&action=execute\" title=\"".$langs->trans('CronExecute')."\">".img_picto('',"play").""; } else { - print "trans('NotEnoughPermissions')."\">\"".$langs-trans('NotEnoughPermissions')."\" />"; + print "trans('NotEnoughPermissions')."\">".img_picto('',"execute").""; } print '
'; diff --git a/htdocs/langs/en_US/cron.lang b/htdocs/langs/en_US/cron.lang index c64c74f1f58..e6930cd0b08 100644 --- a/htdocs/langs/en_US/cron.lang +++ b/htdocs/langs/en_US/cron.lang @@ -1,5 +1,22 @@ # Dolibarr language file - en_US - cron CHARSET=UTF-8 +Module2310Name=Cron +Module2310Desc=Scheduled task management + +# +# About page +# +About = About +CronAbout = About Cron +CronAboutPage = Cron about page + +# +# Right +# +Permission23101 = Read Scheduled task +Permission23102 = Create/update Scheduled task +Permission23103 = Delete Scheduled task +Permission23104 = Execute Scheduled task # # Admin @@ -12,6 +29,14 @@ FileToLaunchCronJobs=Command to launch cron jobs CronExplainHowToRunUnix=On Unix environement you should use crontab to run Command line each minutes CronExplainHowToRunWin=On Microsoft(tm) Windows environement you can use Scheduled task tools to run Command line each minutes + +# +# Menu +# +CronListActive= List of active jobs +CronListInactive= List of disabled jobs + + # # Page list # diff --git a/htdocs/theme/amarok/img/play.png b/htdocs/theme/amarok/img/play.png new file mode 100644 index 0000000000000000000000000000000000000000..6de3e256ba63c72c88e3ad9929da735574d84ee1 GIT binary patch literal 836 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 Date: Tue, 26 Mar 2013 23:32:22 +0100 Subject: [PATCH 26/40] Add inforamtion on Project into ODT project --- .../pdf/doc_generic_project_odt.modules.php | 707 +++++++++++++----- .../doctemplates/project/template_project.odt | Bin 25790 -> 28586 bytes 2 files changed, 508 insertions(+), 199 deletions(-) diff --git a/htdocs/core/modules/project/pdf/doc_generic_project_odt.modules.php b/htdocs/core/modules/project/pdf/doc_generic_project_odt.modules.php index 7ba6defaa3b..a1aa87366d9 100644 --- a/htdocs/core/modules/project/pdf/doc_generic_project_odt.modules.php +++ b/htdocs/core/modules/project/pdf/doc_generic_project_odt.modules.php @@ -1,36 +1,49 @@ * Copyright (C) 2012 Juanjo Menent - * 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 . - * or see http://www.gnu.org/ - */ +* 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 . +* or see http://www.gnu.org/ +*/ /** * \file htdocs/core/modules/project/doc/doc_generic_project_odt.modules.php - * \ingroup commande + * \ingroup project * \brief File of class to build ODT documents for third parties - */ +*/ require_once DOL_DOCUMENT_ROOT.'/core/modules/project/modules_project.php'; require_once DOL_DOCUMENT_ROOT.'/projet/class/project.class.php'; require_once DOL_DOCUMENT_ROOT.'/projet/class/task.class.php'; +require_once DOL_DOCUMENT_ROOT.'/contact/class/contact.class.php'; +require_once DOL_DOCUMENT_ROOT.'/user/class/user.class.php'; +require_once DOL_DOCUMENT_ROOT.'/societe/class/societe.class.php'; require_once DOL_DOCUMENT_ROOT.'/core/lib/company.lib.php'; require_once DOL_DOCUMENT_ROOT.'/core/lib/functions2.lib.php'; require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php'; require_once DOL_DOCUMENT_ROOT.'/core/lib/doc.lib.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->facture->enabled)) require_once DOL_DOCUMENT_ROOT.'/compta/facture/class/facture-rec.class.php'; +if (! empty($conf->commande->enabled)) require_once DOL_DOCUMENT_ROOT.'/commande/class/commande.class.php'; +if (! empty($conf->fournisseur->enabled)) require_once DOL_DOCUMENT_ROOT.'/fourn/class/fournisseur.facture.class.php'; +if (! empty($conf->fournisseur->enabled)) require_once DOL_DOCUMENT_ROOT.'/fourn/class/fournisseur.commande.class.php'; +if (! empty($conf->contrat->enabled)) require_once DOL_DOCUMENT_ROOT.'/contrat/class/contrat.class.php'; +if (! empty($conf->ficheinter->enabled)) require_once DOL_DOCUMENT_ROOT.'/fichinter/class/fichinter.class.php'; +if (! empty($conf->deplacement->enabled)) require_once DOL_DOCUMENT_ROOT.'/compta/deplacement/class/deplacement.class.php'; +if (! empty($conf->agenda->enabled)) require_once DOL_DOCUMENT_ROOT.'/comm/action/class/actioncomm.class.php'; /** @@ -88,64 +101,129 @@ 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 Translate $outputlangs Lang object to use for output - * @return array Array of substitution - */ - function get_substitutionarray_object($object,$outputlangs) - { - global $conf; - dol_syslog(get_class($this)."::get_substitutionarray_object object=".var_export($object,true), LOG_DEBUG); - return array( - 'object_id'=>$object->id, - 'object_ref'=>$object->ref, - 'object_title'=>$object->title, - 'object_description'=>$object->description, - 'object_date_creation'=>dol_print_date($object->date_c,'day'), - 'object_date_modification'=>dol_print_date($object->date_m,'day'), - 'object_date_start'=>dol_print_date($object->date_start,'day'), - 'object_date_end'=>dol_print_date($object->date_end,'day'), - 'object_note_private'=>$object->note_private, - 'object_note_public'=>$object->note_public, - 'object_public'=>$object->public, - 'object_statut'=>$object->getLibStatut() - ); - } + /** + * Define array with couple substitution key => substitution value + * + * @param Object $object Main object to use as data source + * @param Translate $outputlangs Lang object to use for output + * @return array Array of substitution + */ + function get_substitutionarray_object($object,$outputlangs) + { + global $conf; - /** - * Define array with couple substitution key => substitution value - * - * @param array $line Array of lines - * @param Translate $outputlangs Lang object to use for output - * @return array Return a substitution array - */ - function get_substitutionarray_lines($line,$outputlangs) - { - global $conf; + return array( + 'object_id'=>$object->id, + 'object_ref'=>$object->ref, + 'object_title'=>$object->title, + 'object_description'=>$object->description, + 'object_date_creation'=>dol_print_date($object->date_c,'day'), + 'object_date_modification'=>dol_print_date($object->date_m,'day'), + 'object_date_start'=>dol_print_date($object->date_start,'day'), + 'object_date_end'=>dol_print_date($object->date_end,'day'), + 'object_note_private'=>$object->note_private, + 'object_note_public'=>$object->note_public, + 'object_public'=>$object->public, + 'object_statut'=>html_entity_decode($object->getLibStatut()) + ); + } + + /** + * Define array with couple substitution key => substitution value + * + * @param array $task Task Object + * @param Translate $outputlangs Lang object to use for output + * @return array Return a substitution array + */ + function get_substitutionarray_tasks($task,$outputlangs) + { + global $conf; + + return array( + 'task_ref'=>$task->ref, + 'task_fk_project'=>$task->fk_project, + 'task_projectref'=>$task->projectref, + 'task_projectlabel'=>$task->projectlabel, + 'task_label'=>$task->label, + 'task_description'=>$task->description, + 'task_fk_parent'=>$task->fk_parent, + 'task_duration'=>$task->duration, + 'task_progress'=>$task->progress, + 'task_public'=>$task->public, + 'task_date_start'=>dol_print_date($task->date_start,'day'), + 'task_date_end'=>dol_print_date($task->date_end,'day') + ); + } + + /** + * Define array with couple substitution key => substitution value + * + * @param array $contact Contact array + * @param Translate $outputlangs Lang object to use for output + * @return array Return a substitution array + */ + function get_substitutionarray_project_contacts($contact,$outputlangs) + { + global $conf; + + return array( + 'projcontacts_id'=>$contact['id'], + 'projcontacts_rowid'=>$contact['rowid'], + 'projcontacts_role'=>$contact['libelle'], + 'projcontacts_lastname'=>$contact['lastname'], + 'projcontacts_firstname'=>$contact['firstname'], + 'projcontacts_fullcivname'=>$contact['fullname'], + 'projcontacts_socname'=>$contact['socname'], + 'projcontacts_email'=>$contact['email'] + ); + } + + /** + * Define array with couple substitution key => substitution value + * + * @param array $file file array + * @param Translate $outputlangs Lang object to use for output + * @return array Return a substitution array + */ + function get_substitutionarray_project_file($file,$outputlangs) + { + global $conf; + + return array( + 'projfile_name'=>$file['name'], + 'projfile_date'=>dol_print_date($file['date'],'day'), + 'projfile_size'=>$file['size'] + ); + } + + /** + * Define array with couple substitution key => substitution value + * + * @param array $refdetail Reference array + * @param Translate $outputlangs Lang object to use for output + * @return array Return a substitution array + */ + function get_substitutionarray_project_reference($refdetail,$outputlangs) + { + global $conf; + + return array( + 'projref_type'=>$refdetail['type'], + 'projref_ref'=>$refdetail['ref'], + 'projref_date'=>dol_print_date($refdetail['date'],'day'), + 'projref_socname'=>$refdetail['socname'], + 'projref_amountht'=>price($refdetail['amountht'],0,$outputlangs), + 'projref_amountttc'=>price($refdetail['amountttc'],0,$outputlangs), + 'projref_status'=>$refdetail['status'] + ); + } + - return array( - 'line_ref'=>$line->ref, - 'line_fk_project'=>$line->fk_project, - 'line_projectref'=>$line->projectref, - 'line_projectlabel'=>$line->projectlabel, - 'line_label'=>$line->label, - 'line_description'=>$line->description, - 'line_fk_parent'=>$line->fk_parent, - 'line_duration'=>$line->duration, - 'line_progress'=>$line->progress, - 'line_public'=>$line->public, - 'line_date_start'=>dol_print_date($line->date_start,'day'), - 'line_date_end'=>dol_print_date($line->date_end,'day') - ); - } /** * Return description of a module * - * @param Translate $langs Lang object to use for output + * @param Translate $langs Lang object to use for output * @return string Description */ function info($langs) @@ -173,7 +251,9 @@ class doc_generic_project_odt extends ModelePDFProjects { $tmpdir=trim($tmpdir); $tmpdir=preg_replace('/DOL_DATA_ROOT/',DOL_DATA_ROOT,$tmpdir); - if (! $tmpdir) { unset($listofdir[$key]); continue; } + if (! $tmpdir) { + unset($listofdir[$key]); continue; + } if (! is_dir($tmpdir)) $texttitle.=img_warning($langs->trans("ErrorDirNotFound",$tmpdir),0); else { @@ -184,19 +264,19 @@ class doc_generic_project_odt extends ModelePDFProjects $texthelp=$langs->trans("ListOfDirectoriesForModelGenODT"); // Add list of substitution keys $texthelp.='
'.$langs->trans("FollowingSubstitutionKeysCanBeUsed").'
'; - $texthelp.=$langs->transnoentitiesnoconv("FullListOnOnlineDocumentation"); // This contains an url, we don't modify it + $texthelp.=$langs->transnoentitiesnoconv("FullListOnOnlineDocumentation"); // This contains an url, we don't modify it $texte.= $form->textwithpicto($texttitle,$texthelp,1,'help','',1); $texte.= ''; + $texte.= ''; $texte.= ''; + $texte.= ''; + $texte.= ''; $texte.= ''; - $texte.= '
'; $texte.= ''; - $texte.= '  '; - $texte.= ''; - $texte.= '
'; + $texte.= ''; // Scan directories if (count($listofdir)) $texte.=$langs->trans("NumberOfModelFilesFound").': '.count($listoffiles).''; @@ -210,7 +290,7 @@ class doc_generic_project_odt extends ModelePDFProjects $texte.= ''; /*$texte.= ''; - $texte.= ''; + $texte.= ''; $texte.= ''; $texte.= ''; $texte.= '';*/ @@ -232,7 +312,7 @@ class doc_generic_project_odt extends ModelePDFProjects function write_file($object,$outputlangs,$srctemplatepath) { global $user,$langs,$conf,$mysoc; - + if (empty($srctemplatepath)) { dol_syslog("doc_generic_odt::write_file parameter srctemplatepath empty", LOG_WARNING); @@ -247,7 +327,7 @@ class doc_generic_project_odt extends ModelePDFProjects $outputlangs->load("dict"); $outputlangs->load("companies"); $outputlangs->load("projects"); - + if ($conf->projet->dir_output) { // If $object is id instead of object @@ -284,7 +364,7 @@ class doc_generic_project_odt extends ModelePDFProjects $newfiletmp=preg_replace('/\.odt/i','',$newfile); $newfiletmp=preg_replace('/template_/i','',$newfiletmp); $newfiletmp=preg_replace('/modele_/i','',$newfiletmp); - $newfiletmp=$objectref.'_'.$newfiletmp; + $newfiletmp=$objectref.'_'.$newfiletmp; //$file=$dir.'/'.$newfiletmp.'.'.dol_print_date(dol_now(),'%Y%m%d%H%M%S').'.odt'; $file=$dir.'/'.$newfiletmp.'.odt'; //print "newdir=".$dir; @@ -293,66 +373,59 @@ class doc_generic_project_odt extends ModelePDFProjects //print "conf->societe->dir_temp=".$conf->societe->dir_temp; dol_mkdir($conf->projet->dir_temp); - - - // List of all contact - $usecontact=false; - $arrayidcontact=$object->liste_contact(-1,'internal'); - if (count($arrayidcontact) > 0) - { - $usecontact=true; - $result=$object->fetch_contact($arrayidcontact[0]['id']); - } - - $socobject=$object->thirdparty; - - // Make substitution - $substitutionarray=array( - '__FROM_NAME__' => $this->emetteur->nom, - '__FROM_EMAIL__' => $this->emetteur->email, - ); - complete_substitutions_array($substitutionarray, $langs, $object); - - // Open and load template + + $socobject=$object->thirdparty; + + // Make substitution + $substitutionarray=array( + '__FROM_NAME__' => $this->emetteur->nom, + '__FROM_EMAIL__' => $this->emetteur->email, + ); + complete_substitutions_array($substitutionarray, $langs, $object); + + // Open and load template require_once ODTPHP_PATH.'odf.php'; $odfHandler = new odf( - $srctemplatepath, - array( - 'PATH_TO_TMP' => $conf->projet->dir_temp, - 'ZIP_PROXY' => 'PclZipProxy', // PhpZipProxy or PclZipProxy. Got "bad compression method" error when using PhpZipProxy. - 'DELIMITER_LEFT' => '{', - 'DELIMITER_RIGHT' => '}' + $srctemplatepath, + array( + 'PATH_TO_TMP' => $conf->projet->dir_temp, + 'ZIP_PROXY' => 'PclZipProxy', // PhpZipProxy or PclZipProxy. Got "bad compression method" error when using PhpZipProxy. + 'DELIMITER_LEFT' => '{', + 'DELIMITER_RIGHT' => '}' ) ); // After construction $odfHandler->contentXml contains content and // [!-- BEGIN row.lines --]*[!-- END row.lines --] has been replaced by // [!-- BEGIN lines --]*[!-- END lines --] - //print html_entity_decode($odfHandler->__toString()); - //print exit; + //print html_entity_decode($odfHandler->__toString()); + //print exit; - // Make substitutions into odt of user info + + + + // Make substitutions into odt of user info $tmparray=$this->get_substitutionarray_user($user,$outputlangs); - //var_dump($tmparray); exit; - foreach($tmparray as $key=>$value) - { - try { - if (preg_match('/logo$/',$key)) // Image - { - //var_dump($value);exit; - if (file_exists($value)) $odfHandler->setImage($key, $value); - else $odfHandler->setVars($key, 'ErrorFileNotFound', true, 'UTF-8'); - } - else // Text - { - $odfHandler->setVars($key, $value, true, 'UTF-8'); - } - } - catch(OdfException $e) - { - } - } - // Make substitutions into odt of mysoc - $tmparray=$this->get_substitutionarray_mysoc($mysoc,$outputlangs); + //var_dump($tmparray); exit; + foreach($tmparray as $key=>$value) + { + try { + if (preg_match('/logo$/',$key)) // Image + { + //var_dump($value);exit; + if (file_exists($value)) $odfHandler->setImage($key, $value); + else $odfHandler->setVars($key, 'ErrorFileNotFound', true, 'UTF-8'); + } + else // Text + { + $odfHandler->setVars($key, $value, true, 'UTF-8'); + } + } + catch(OdfException $e) + { + } + } + // Make substitutions into odt of mysoc + $tmparray=$this->get_substitutionarray_mysoc($mysoc,$outputlangs); //var_dump($tmparray); exit; foreach($tmparray as $key=>$value) { @@ -372,8 +445,8 @@ class doc_generic_project_odt extends ModelePDFProjects { } } - - // Make substitutions into odt of thirdparty + + // Make substitutions into odt of thirdparty $tmparray=$this->get_substitutionarray_thirdparty($socobject,$outputlangs); foreach($tmparray as $key=>$value) { @@ -392,75 +465,312 @@ class doc_generic_project_odt extends ModelePDFProjects { } } - - // Replace tags of object + external modules - $tmparray=$this->get_substitutionarray_object($object,$outputlangs); - complete_substitutions_array($tmparray, $outputlangs, $object); - foreach($tmparray as $key=>$value) - { - try { - if (preg_match('/logo$/',$key)) // Image - { - if (file_exists($value)) $odfHandler->setImage($key, $value); - else $odfHandler->setVars($key, 'ErrorFileNotFound', true, 'UTF-8'); - } - else // Text - { - $odfHandler->setVars($key, $value, true, 'UTF-8'); - } - } - catch(OdfException $e) - { - } - } - - // Replace tags of lines - try - { - $listlines = $odfHandler->setSegment('lines'); - - $taskstatic = new Task($this->db); - - // Security check - $socid=0; - if (!empty($object->fk_soc)) $socid = $object->fk_soc; - - $tasksarray=$taskstatic->getTasksArray(0, 0, $object->id, $socid, 0); - - foreach ($tasksarray as $task) - { - $tmparray=$this->get_substitutionarray_lines($task,$outputlangs); - complete_substitutions_array($tmparray, $outputlangs, $object, $task, "completesubstitutionarray_lines"); - foreach($tmparray as $key => $val) - { - try - { - $listlines->setVars($key, $val, true, 'UTF-8'); - } - catch(OdfException $e) - { - } - catch(SegmentException $e) - { - } - } - $listlines->merge(); - } - $odfHandler->mergeSegment($listlines); - } - catch(OdfException $e) - { - $this->error=$e->getMessage(); - dol_syslog($this->error, LOG_WARNING); - return -1; - } - // Write new file + // Replace tags of object + external modules + $tmparray=$this->get_substitutionarray_object($object,$outputlangs); + complete_substitutions_array($tmparray, $outputlangs, $object); + foreach($tmparray as $key=>$value) + { + try { + if (preg_match('/logo$/',$key)) // Image + { + if (file_exists($value)) $odfHandler->setImage($key, $value); + else $odfHandler->setVars($key, 'ErrorFileNotFound', true, 'UTF-8'); + } + else // Text + { + $odfHandler->setVars($key, $value, true, 'UTF-8'); + } + } + catch(OdfException $e) + { + } + } + + // Replace tags of lines for tasks + try + { + $listlines = $odfHandler->setSegment('tasks'); + + $taskstatic = new Task($this->db); + + // Security check + $socid=0; + if (!empty($object->fk_soc)) $socid = $object->fk_soc; + + $tasksarray=$taskstatic->getTasksArray(0, 0, $object->id, $socid, 0); + + + + foreach ($tasksarray as $task) + { + $tmparray=$this->get_substitutionarray_tasks($task,$outputlangs); + //complete_substitutions_array($tmparray, $outputlangs, $object, $task, "completesubstitutionarray_lines"); + foreach($tmparray as $key => $val) + { + try + { + $listlines->setVars($key, $val, true, 'UTF-8'); + } + catch(OdfException $e) + { + } + catch(SegmentException $e) + { + } + } + $listlines->merge(); + } + $odfHandler->mergeSegment($listlines); + } + catch(OdfException $e) + { + $this->error=$e->getMessage(); + dol_syslog($this->error, LOG_WARNING); + return -1; + } + + // Replace tags of project files + try + { + $listlines = $odfHandler->setSegment('projectfiles'); + + $upload_dir = $conf->projet->dir_output.'/'.dol_sanitizeFileName($object->ref); + $filearray=dol_dir_list($upload_dir,"files",0,'','\.meta$','name',SORT_ASC,1); + + + foreach ($filearray as $filedetail) + { + //dol_syslog(get_class($this).'::ee $filedetail'.var_export($filedetail,true)); + $tmparray=$this->get_substitutionarray_project_file($filedetail,$outputlangs); + + foreach($tmparray as $key => $val) + { + try + { + $listlines->setVars($key, $val, true, 'UTF-8'); + } + catch(OdfException $e) + { + } + catch(SegmentException $e) + { + } + } + $listlines->merge(); + } + $odfHandler->mergeSegment($listlines); + } + catch(OdfException $e) + { + $this->error=$e->getMessage(); + dol_syslog($this->error, LOG_WARNING); + return -1; + } + + // Replace tags of lines for contacts + $sourcearray=array('internal','external'); + $contact_arrray=array(); + foreach ($sourcearray as $source) { + $contact_temp=$object->liste_contact(-1,$source); + if ((is_array($contact_temp) && count($contact_temp) > 0)) + { + $contact_arrray=array_merge($contact_arrray,$contact_temp); + } + } + if ((is_array($contact_arrray) && count($contact_arrray) > 0)) + { + try + { + $listlines = $odfHandler->setSegment('projectcontacts'); + + foreach ($contact_arrray as $contact) + { + if ($contact['source']=='internal') { + $objectdetail=new User($this->db); + $objectdetail->fetch($contact['id']); + $contact['socname']=$mysoc->name; + } elseif ($contact['source']=='external') { + $objectdetail=new Contact($this->db); + $objectdetail->fetch($contact['id']); + + $soc=new Societe($this->db); + $soc->fetch($contact['socid']); + $contact['socname']=$soc->name; + } + $contact['fullname']=$objectdetail->getFullName($outputlangs,1); + + $tmparray=$this->get_substitutionarray_project_contacts($contact,$outputlangs); + complete_substitutions_array($tmparray, $outputlangs, $contact, $contact, "completesubstitutionarray_lines"); + foreach($tmparray as $key => $val) + { + try + { + $listlines->setVars($key, $val, true, 'UTF-8'); + } + catch(OdfException $e) + { + } + catch(SegmentException $e) + { + } + } + $listlines->merge(); + } + $odfHandler->mergeSegment($listlines); + } + catch(OdfException $e) + { + $this->error=$e->getMessage(); + dol_syslog($this->error, LOG_WARNING); + return -1; + } + } + + //List of referent + + $listofreferent=array( + 'propal'=>array( + 'title'=>"ListProposalsAssociatedProject", + 'class'=>'Propal', + 'test'=>$conf->propal->enabled), + 'order'=>array( + 'title'=>"ListOrdersAssociatedProject", + 'class'=>'Commande', + 'test'=>$conf->commande->enabled), + 'invoice'=>array( + 'title'=>"ListInvoicesAssociatedProject", + 'class'=>'Facture', + 'test'=>$conf->facture->enabled), + 'invoice_predefined'=>array( + 'title'=>"ListPredefinedInvoicesAssociatedProject", + 'class'=>'FactureRec', + 'test'=>$conf->facture->enabled), + 'order_supplier'=>array( + 'title'=>"ListSupplierOrdersAssociatedProject", + 'class'=>'CommandeFournisseur', + 'test'=>$conf->fournisseur->enabled), + 'invoice_supplier'=>array( + 'title'=>"ListSupplierInvoicesAssociatedProject", + 'class'=>'FactureFournisseur', + 'test'=>$conf->fournisseur->enabled), + 'contract'=>array( + 'title'=>"ListContractAssociatedProject", + 'class'=>'Contrat', + 'test'=>$conf->contrat->enabled), + 'intervention'=>array( + 'title'=>"ListFichinterAssociatedProject", + 'class'=>'Fichinter', + 'disableamount'=>1, + 'test'=>$conf->ficheinter->enabled), + 'trip'=>array( + 'title'=>"ListTripAssociatedProject", + 'class'=>'Deplacement', + 'disableamount'=>1, + 'test'=>$conf->deplacement->enabled), + 'agenda'=>array( + 'title'=>"ListActionsAssociatedProject", + 'class'=>'ActionComm', + 'disableamount'=>1, + 'test'=>$conf->agenda->enabled) + ); + + //Inser refenrence + try + { + $listlines = $odfHandler->setSegment('projectrefs'); + + foreach ($listofreferent as $keyref => $valueref) + { + $title=$valueref['title']; + $classname=$valueref['class']; + $qualified=$valueref['test']; + if ($qualified) + { + $elementarray = $object->get_element_list($keyref); + if (count($elementarray)>0 && is_array($elementarray)) + { + $var=true; + $total_ht = 0; + $total_ttc = 0; + $num=count($elementarray); + for ($i = 0; $i < $num; $i++) + { + $ref_array=array(); + $ref_array['type']=$langs->trans($classname); + + $element = new $classname($this->db); + $element->fetch($elementarray[$i]); + $element->fetch_thirdparty(); + + //Ref object + $ref_array['ref']=$element->ref; + + //Date object + $dateref=$element->date; + if (empty($dateref)) $dateref=$element->datep; + if (empty($dateref)) $dateref=$element->date_contrat; + $ref_array['date']=$dateref; + + //Soc object + if (is_object($element->thirdparty)) { + $ref_array['socname']=$element->thirdparty->name; + } else { + $ref_array['socname']=''; + } + + //Amount object + if (empty($valueref['disableamount'])) { + if (!empty($element->total_ht)) { + $ref_array['amountht']=$element->total_ht; + $ref_array['amountttc']=$element->total_ttc; + }else { + $ref_array['amountht']=0; + $ref_array['amountttc']=0; + } + }else { + $ref_array['amountht']=''; + $ref_array['amountttc']=''; + } + + $ref_array['status']=html_entity_decode($element->getLibStatut(0)); + + $tmparray=$this->get_substitutionarray_project_reference($ref_array,$outputlangs); + + foreach($tmparray as $key => $val) + { + try + { + $listlines->setVars($key, $val, true, 'UTF-8'); + } + catch(OdfException $e) + { + } + catch(SegmentException $e) + { + } + } + $listlines->merge(); + } + + } + } + $odfHandler->mergeSegment($listlines); + } + } + catch(OdfException $e) + { + $this->error=$e->getMessage(); + dol_syslog($this->error, LOG_WARNING); + return -1; + } + + // Write new file //$result=$odfHandler->exportAsAttachedFile('toto'); $odfHandler->saveToDisk($file); if (! empty($conf->global->MAIN_UMASK)) - @chmod($file, octdec($conf->global->MAIN_UMASK)); + @chmod($file, octdec($conf->global->MAIN_UMASK)); $odfHandler=null; // Destroy object @@ -477,5 +787,4 @@ class doc_generic_project_odt extends ModelePDFProjects } } - -?> +?> \ No newline at end of file diff --git a/htdocs/install/doctemplates/project/template_project.odt b/htdocs/install/doctemplates/project/template_project.odt index fcf5f52d80126f4af6bd2ecb629f5721a5b606f1..ff34277a48c52325be4902df3ed9b9a9bf6056ad 100755 GIT binary patch delta 25734 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 YEBHMoc>k&wU=K;QqC+@z_*44-0RNeJwg3PC delta 22888 zcmbTd1#nzVlcp0a)|DA}BMQG^ip7bp* z70-vwgy&zn-_AjL0hUZJK6bEJBxuuLz%}R=yc`cnsRS#9xu`2<&8p2AqlCplSiIAc8NrK9DiIVDznsh!nNlm6`8_n$lxY=CPmWFAmfsTW6QnuX9LclgsTIy)LWEo9}W>@QIP26+bi2m@Z4e z%aA~lcoVBJwP3-5T>bMVK-59h6yb)6`B#)HkN7VSOZ3XI|EPc{Ab0Nl!a|w+-Wd;6 zbmdI^f^Y=g^ZC%e2;KMuLgsV8zO;jbm!P7IjA(JwXJT@}0_-=W-~Kwg#X zy7{3?m47($-SQKr!c9sNPCRQnBy~~(VBM??oKRZth)#ch6{0+vfXI>)LjHO+J28f( zd_p$jvZ0a_1hGQAWb=!ln^c0r_dv>306qNj60r#L@p8o(g#>cTM2O*Q!O=OzZ%jp4 z(&eY7w-2fhbvX(SDx7&u!ypf$07gCmp_u^*OZ+#RkES6(G%xd-eRI!uiIS2UfZXyT zHG0qt7{n}^T!LuCCe#I!knxRY-&8~_ zY|7jvgpU2rO;_ZuAxiAxqNQZ17blAU#vnO`5&tjpgV22o)9?L7q% zv;+5v5Ypezu&tb8C32slEQsJ6@KB)111q~!;RhV*;tMi?;9}ltwcB#$-jg{gJ#ELN zM@s^=_}P44?w7_YNA0f-Cye8BI*Cs+!WlY(3N{aaExg$FU5M}yp2Pk3ziUqdlJ`np zw;-qFU2eTS@cu(od%Y_duD02txjy|yhhb#I1BN*_5* zoxN=>;?Ly?>?`1D!@4n|Q<&+)J}_px9E+aOl+3};*a~-?rcJ9XR*mCHtv_D!W(Q@+ z#$gVY;QKu~lYwz^jBTT0pd?VCT3=Vk_%x6CaB6o^AGSS=JG|Mb_sso0tg@w&wi>99iLJdH4z&(jjFWwi z3-ybaf<`9z>AwR-VKiaT4zOCCKX%ep*FPqtsiq*E2~$kKXGe``phuk@4E6h0+vG*-pr5GC@0F*J?&`d>AlAXxn(CJ}v28!l=o;)k1 zFH(>4G}B&oBg&}XqjBoGN)B-Dy{g_&C^&zT4^P^AJkXmFM#8fz&P$apz2DrK1nk&b zPUyVFHo>eb74cZ0?5x^`$No;^q>9fUkj;+QQgEQ;Q+*i$?asd-Q1O0{hT-w}GC^qm z7r;^TMSjK2ARynx{Zak=yQa6bH`!pSQAx+rxp&32TOuE z?jn3}HXv50<0OIJ*|{%p<~!mVyDCk%cw%w;_v2mB=sP^v<;H-&gc!j>78O%Wg@92_ zb6z>DtN|q_X~-Z{_fI#%sp21yX~R}VD8Awaj5ULJWlTs+b1NCe6q~r;bA1%M-KVL$ zqGsW=JwPabC{i8d#Wlkn7Li~z@(&WIW=t2 z$Am7Z14*23p=@Cx#;&Lp=v*gR!biD=r&9DafHb;!)eJa2vw&wr zQ>+0M&AoY3TO0i*e$=>hq^(+M+Y6_r6Ss{yMDQd#Dz*!D(eOwB96OrU@A=HF>IEb_AIXDE8WVr$-a=<>L)(a@hDy^mD5@@7r|7G*Kxi$O#> z?gsDFvT75Jin<;a#dlWZ_kgX%s(|QFX9C;L<>SKSMzeNo1kK0go?RU+ppJp-E+mJy zll}qO6JT(g@ZK3*<&o}q)TjuxI(ZyYl=pwQj&sd#n{Mc#4|3tHeZ6DSJ;Kgp{8MqH zxStyVH}dCDl=&u@!qg?h@T0n4pWuY;-q?qGbQ|8@U%g^Ttb>@1*?u$7n%_Ew&Quh zPENX`HVnZ&-1co^VA-BUd<2ICZ|#h)7f4xw{X_#L;aANV!5Tq5x7^r7hA#eczmI1n zS_gz$V69dj*6L~#fS5zN!yf@F3|>#2jt1BGkzF$6wy`M;p+x7SANPw0E{jT=r&Y(K zz1}^PJ|B2E&+SL%&X; zb70&p_aN{3pw~(pE0;MugO`pj-ePxqWBGn`0}&H^JU{h!J%4yVDOD}_s}JuOi@K`R z=8eMJ*tS1izfMF1dO4YSukbeLFx08e{xxa8s{V)!3M}oM1_L}!5)Y~qGIV=-B6a_E zI(3ckh5h_ZPasm~7sG>3UxMP17o?p4$*{*!7TgQ2O_?qLO3oaC9)mBmENh@p8>eck z2q?5%UO7237f)eJL#s&Tvv@LUT@rt#>-sd%n=v<+IrTFYRlr0Wb7n6xU@_5$`9#rv z*u-(Q1eXCof=CU&cy>XbDq0&(v1!UCeL)s}rj`|jrbhQ+ToTx z{iqkwV72CjV!4q~&^FyCq(8`mP-KMt31zU69qxyt1ue(s5=q&UwtEgTT}iM2l}ok0 z$KU$Xf|xjGjdTiCMYsLKErAYnxG3%ea9J7jGkPm#EQGY>L4@3koA=UWPHL9q94j;V z6MjM!#>Sma&Y(UNU41mgbxIZ-E^=PBx~CI?p9#M!Uz=!Eg}`~x8L@Ul95Za_4ib|Q z6w_DH6zO{T(YcWF%c+b~EK$`gb2BrY654C)M-iw4q$pdD6 zk{{Z;MzlN17i~-CA@_t#{tVx<)bOy;#UMP!1N2w~NEjeeB^z=I!UmA{%zE}b@*6gN zOTjg+7{BoRpb{cd+5%e=>IJ_Psc6hya!XY&5Sp7qKp~swMr!2;jAwCuVY>V~9~WU7 zaC*NpUf#Zg!9Za}d2O<*SG<>9lwmJ+h-clSGT7X~?L702VMTh6ZV-YTU!M&m8EG7^ zKWk-L(r~yJ;fs%@q9U^td12Bs&L}{VF2ztApL25n zf%ISu{km)QzD6*!jj!eQQ1HR~Y3C;A2o|q<(5({`*zEg(Xt(LI>1&zIv_w9hn;Z1H zN=4jgCcwpQXYF}tyQ9w`aFnF?J)d)}S;^Ray zaKhq$g%SWvUM}sp+J%Pq6nhiGe=v2ym$D^!*mDOP#Mc*w;}GMTZj0RP5!>Q01f#*$ z`RYZ-Z%ostSog1LrkXAvOPepscJ)~V4pD8<7GaUOn2$>7IEATopP7&t(p9UwZp+zJ4kQCXrw=iP*G_doz`U$%aBeQCdM%@h z2&#Uwvd0=5x#O6Z(8l&q8(oj5takJC*4(x_|2w3>X0DoTS0kzQo;LIi2`yvj&LWRm zDB4jOH9~5sd6Mssu*=a=gp;SE8dS6D<0~H{?~x-#vt=pvFy7x-X+BqckjI$zgjJ#) zt5(3k?FgyuR##*@&tj*>yHxvDC#EfaT=Cz<*P#3@xQ7iGjarM4a(PM~?b{4i!G!Bx z!teQ;A%dpLDMFkS8cI@x2q*nrw7LYP(SMH;=--CZtGyz&TG~1zPZ8=y6T4}jA-bZ> z#8Q-I@)#Mb4B%^X;!Y;6Fw~UbAxUPySeO8Bw^>hn1rozS6?DU+-*JlhcUx{(k48#4 zY+G(Vq};PihHz|03F?t;aSw@gYED8rfCv{gjiJ0kEd7>FYP|>}x}rwT&3T`>pwOS( z<|OF2kwk;sciJvXgJ%%k3^We<4%;LuZsXDF=(V~kYC&7Qj1rU=si`RMY%gDN1r0zX zIAd?hHdxGvM(9sBf6XSzb$$P&939-1lKhHCjORMt4DVSW| zS&?A#9YM6z* zl4<@6Q<2#BrabkOeOYU(`SHq^W>aewXg-8iEPC~#Q~?SS6Y#%WUT$8HA={Mf;cBJ^ z8)@nVbD$Nw?DXk=M7ApPb0J_o{eoLq=&MEmjpsQ*(w#=dS41Mu?QfnCQb5+X3$;tL zTJONH9@s23>UvsF4+XS*OYjn%G!tC4fx)-=b06YpgZbLI9}R~wNth35nGmA%-mcjD zCmIq`wO(pBlD<&7;t-H#5n=c?SGI4H)p!|bPSRgDHSUUPvTZQc)-;fkCX40Z*NTfv zTWd;#j?DmN;o&54Mu`!ZC7_7($NaAF&{b*6o50t`EkF4;Yr@rB-O*?hWL(o()Fvga zC2H$No3l+Nqf}q$Hg(k=>1X5jn+cjq?(ma)t>35fh%$LYkvYs+&vuNf+Z)O9;z7}8 zYY#`0YZ{Xq%8)`IP)xU07wc1|lPS(HpA8`E(BCwqdzDXlWhaJv0oQpmcK68ANcjXW zUWJBv5wYl^9`b5>T?-%OT!^2aOT9~%;qUFtJ;mx0?oai{reU76sj^_uacM^K ze0zQw`pz8rbHkPZWv^kWS}B?-m5i$j<6C0}qun-hU~%JSTNoenq6&{QK9*H5tI0VT z1T$kxKN7rey1OPMYTDoIyaP;o9yDdu3jQzn0(R@fk0 z-frWxu+b!UfSB$!tb2{kyw?R5wa?OiQZMB^jsUJE<;a6T9J$NpZ4x$vjhT~OBtR`P zH*Ww9v#^v;9Jm!Ggwe;$8iINrNd?zjqecW<9+}N=?`;rBGfE!H(~XR*AF7nH+lQbB z=j`S)4A#h$$0qEG+K&(pYcoyHyufAj5g*MnSeNjy3n3D8F9f+_5C};G^xn5NWFJMK zH?MCcq~idi`7kOxyw-VjYARakWk-_c$nZ5$Z0kth6XZL!ZyKKacPQZ1YdqDzaKq30 z-XE$@VYs@Q?XICV!3^(EER%qF;$pd^^o)Z9$%#TWJT`RUz3_faq{CYHA8bz+gXv-> z<#V?$R=hGfibSvkSP97wV;!gtG%Gl~7I*kOPRIjKPcf7Svcb$I2DJ(8X*d&{2IoSsdKsBgg`**_6g%F;c=;v?Zs8}_ygjwV5Lf^VbT#oS{ zH{Y~mM;b6pUA34ENb?443@ieDR7Y}<%D5$xWS*<0GichJk5-M9M`49guO~A)8q5=R zuT+3#Gj?mv-*%w@ZgCunEhcbxA7}Dj8-61e2=zR=u`D9f@xE(F))y%_P>92T>H4eq z`|CBui2@E&mZaBK3oS-5uk>aE0p4bNxA{s{faWb6pFQ7P7HhKEG9rYh`Nxyyz#tWh zR1eo&mg10;-BM`D7Ws$Eb^hI(>O3MmbTtr>iWoFZSoHh6#B!_saTj0hOK0-A5{}}5 zs3x99%VF5Vx|6$2YoZ8>-q)2MR}bwg~PclqDob_Rhj zLy&v97Ma3K`F1gHjIKS9BMHCfF;XcGM4nMe{7aorNeZ$^U`cE2G@xq^MAuni`~+xI z6NS6?1ooI*K9}u;n)`lE_Uv0)w)kT4m6>Uodde?EXvA#oItZvh1qmo{D7>~sYIaKQ z$Hn??P3gT3ynLC|1dCE`d#o(!dQkw9|G*_|3*$|IP%Ya{gPRMBM~OVb@9jO3oV_q5 z{OIU{e_BC|odsUW1^v@3ZDTBDyFKdMYw;(#Ii@uspa6IqiI=Q7vCmN0V^I5(+1Bc<2&Sa!YQZM~G(*>QRPaN*3hU zloOb88d-F*F|KV(i-8U-sw@N+Fwa*kq<%CpUuBsqg(i5G_OM2A5{oVfw5zDt%U9Vw z{D`iqdu2MCbIk~^Iz(#(cdfNk^}6oLakatFmH(Z$Hv!Y4z5eTFvt%M3oBYHDg9QPH zU{>Y+Ow|}{$3Noj1l`l?FG!p-_M>^$v^TIeODdLv=YFQEtX>0vI`=!+(tBgVuB}!1 zwrt0=a2ShxvmlkfG-<=nis4AvEjD2x+pCiPNfL@wElj>+#5UV0Aek-4GIl3n%bO=b zHVq}1#w7C3d<1b#m(pdRbEGQs7*rk*28d zr!lG6O}v)X=KwO@a4=~Nax*FvcSgEzyGoDDp9j zF2nK8D+N|Q%U#DfjTA8Lvt4CeI9a! z$$J6fKvyws0XL+MiRu`L!vUCFr#cD{ z7&LCft6jR1I6zAqRW%ju=u2Nl0VZfVG|ufGK}aZ%#MYp?h4?)Cvf2 z;lQ;dRm8?FWRc||)0ZtcCk2=4)3gVsUv7RLh$XX@aTYn)P=C?P`qf@bSDuK**+A$QzKPOvC42ffC@%ZE)ShVLE zZ=f7-54D#GvcouzFFoU_UsPqo@gJ7n4+9zNd1=7TEX;r~jEAXr%8G>9IlyDD>`&GC z0aN^aP`LYYtjvFY3GMa-BN3{uP<^vfRnJ>G%6@Iv&r1k7;9bib8&3Q?{)mxq?f&o# z375HehX2K|_VXCrLdA(o;|z?5bqS=C3aiq9`59x7d=)TlV(2=`WT1qz6JI*9i!ktR z*KcLf@fk=Hr0~vs0Gf?tJ~VvVuRVDRZ*w8T%NO)0cp9CKYhS)C=_*y<{E_Y`46hxw zUFS5Pp-+hXkW*NY?SPN``3D89r+hvI6#YFQ?AwEEM5ib_k9<9;ma(=7Q9wWTAAtD2PB? z;a03})9@8<2!eRn{rLKcKKaGVoUWe()*{bkpDvdM^FvrWDCgZvL)6MCY+k4yixM3B zcoPn(9Fz~mytPZ?Y)7DvP!IbuPUVbDcYHW=r3O>t%xob7>J^#2%L%@t^_Qg>2V@xt z256ol5mUv_0BWQAL(XWj_)v%T?DC;xjUx(unPvi4M(wFs+wWs?w-+_0Rmi3pHCBxaIg1yDM1LYmL3u` z)#I1H?AC01x){lXR4tP^Ar)%3K%0r8VL>v{fA8avz{g5Du5>2l3XOdHmw^?HkSdb4dP3)?zduh>u>|bKc=W*_ z!SlLAf8=-?&(A{vaipZ#MlWJs z+x~$1q>|*qYu3TYoL!9IQCyU|fEE15OCKX3n4Ls-2-6FYY<>Wr`Pl!;wCX=z>&K_Q zU#>(P1|Q8-gNZNJ)gMU|JoJK0Lvu0&9Gms+cc}K63>56$COfi-SER;A44fw}Beglx z9M=VrJcj{hDZ|AYd$%w@?UG%Tu-d&cr7>3w2t55B&PqNM3F6TdRNWL$(Sgyk*)jF; zrMfe}to%wQ{hP>0r`J7tPpKq=kAtJD&F3K5wz~)GURmn*fy<+s3Z2W*P?$|qBM6&Q@GM5%zR=} zuzX4;A77CKDA>HIDo%9?be<0(Acsl^+{sPBkwd@!=9OF}dblM<0qkx!L71atOg*X- z-Ap`Vy3Lr9>`N1GzfO#l-jlN=WhH=d4+&*QOIyTsWiFV9-+tw+iOdz(XF9GWM?rNm zN9H330lz?w;a7yQx5%q4YXs5 zjP{3eTGyRJK&|L9^ol%r4xv8g+@L@IEyXr+Bs{d1YtE?_z;1iBvNv3g4{?!jV~ET> zGi!7%hVHPl=BjH^$%t;Vxu;udfuFZ=-wRY^(eToHH(d2^xeZ%?D-hm&c(+mqZhuAGa)zx7wIWJG{~0andKOJ;+MldHpI zLY<)e^O!guP=J?Flgym%4ww*#5)#Dz!qTn(&h@^Z#hh_oTtHI@l`d2{!4E$OYKoFKS26&j)YR8+2?%C#MpV|qWFEJz5hY}Tq=Us?vd z6J+*%TFaIt<;y~4|0dv?N)6yqM?>1(l}X4zYc5S@1M~iTl6Ns>&vbnQD;5y&?m4q& zmx-^dv-=frd!Oj}{A3Ew@DO?|(ytzRj*VwcYn+hQXy{%~V^bvs)!tY49nsT_VEtHbrJV@}NZ7H=3*&Ka zlk=N_5LoYL$rA30v*%0Ao1P0AzHt>{p17IEyQ%8vl-S2a2HEDrk{%7Ds>R&GnLaWz z8^WiXs2pj7r@MX4gqPNl;k+MN&E50jZ;zCHX)at7E26GPn`8?2-BKb~Efs6y?k-Eo z2TUop5TwS*AZ{=t4L#y0>99$=8q_UC%hKc=U zzlj=OU;o3w@sV{HSmf2k`{jMp{aKV&h*<-Trf_V*P(f{X2c)5)NBb6iK)a5R-@k~w z8JB`teL0w3cpWqX6DDK9MnFh75eJkYDJ+GtwwA-0$MDkOky2GwKeRQ-h`7_>t$zOL z_grh5Qdz)>ZM2V2y_4~pjwu2Nl=%{{+n| zt#r5me~`kF1_IOQVE&jGgZ{UBKNbh8VxVnRV?^{FE`i9BEUf0emD+~QDB$2c5g2E^w}aiSNc1G>_tJLI+tIqD9lJJmQ%york|T-Ab{ioA zQu2Pyrn$<$tr(AatMPVJKBxB;oIA-#Wu0~Ik|1@c3&ATvN8CO=1VqmznIvsF7vLS> zz|ZtWZIp0Op{dG?V05js(Wt_yPh+Vq+Q>Rx+F zOj*q8U2x_y&~%hP^lN5JaC7a9?vXrPljQd_?-EiJu3fcWl{j&7(_SMJ|{JPRzk51x2 zfA)r6#<1V&g}n^EO@D1Hc&a6x#bGp^=ac`y)850AtU9X)SI(&1JqFmd0Wok}OfMw= z8^}7wX<-t5IXHx&W%j}uLbrU_K?fl`km3%f$MIw!AD@U%6J_T@d6~7 zq`Y_WFoAzw=qbyXlZWasnXt1CI94t2lKXvbj*94Ej?8!5}hp?Uyt591OFQm-I~8ImQn1H!he9FyRjXM zS0b>w@JZoBm?}HT|!?zCI?QX0e@+H;%q{DyoC$plk&?^qPtO%0NPx z!vCim!qM*bLUb5=<{B5s{U~R=qAW`y-PqWwBF6%9-#S8JCh3>T6Y=IqKD^jxs z5>WhsR9gEznLoim*Lu%%_mg4JZ2$d)q21e;CV1kxr8|XkM~$$b&*4oP$a~g+kZ+1|;sr3_)A z&nKxSnmeT9)zx$#$9J`x)!PJ8D((~qXdLfAUkN25)iO;9LHo^&q7EJtn{f?NE_H+% zi{kunHDe=SVFbTaY}UMz7ya+V6F21_+R4#L=L>f?GRlIq)KQg-&hnjZVm>u+%qrlCR|`yad;>Vfjm%&$8auZ{Uz~Ac z*IGS)CGbaaId~P5!{?pC$6ibswsBmn`Q1sRw9x5%W%z%>n>DWcRldv(Jy~CTc8Nry z_`|TuLkUO}#7K!_LNh&>{l2PmeJh^Xc{ag!G;m){2{{m*7EI}xvjdX;9bd9xnNCo| zBa={ZyUZ{-c+ijZRF6&EeYXMcl9*dR`Z(sq%^qqi%HFCi!`)>1OpQ>Jt<$|9pHYv! zn&Tcs!6My`Zm@osNFY_)daZIhXiQ0L3+c_lb-WH`D|XkhO{hphE5{!L8VyD|J0K6} zGAqqs0No5dNFS(j(6U*!IVaj_UfY2!r?fw5)ojwDYYE*ACKY5C^q96I=k@Xz4u1Vc^T*1cl z$_58h&z`kgo4=Y*wwOLt2&o=T28K9L!w1rVY6r%=&6_XE4LYQSITg_K@GTi9|H~|YY$Vx;g)KfB5O8X>(I&D+~-AtWdn@$kr{jV8VCW-Cg zKCQ&)T4mQYgvP_Z`t4}T$eHtLGFfc~(RS*9fM4iwqqWED+8#!lpE{`)of2Jn5HRwp zse4pa;bU=dh$h{w5-!SVIkpTwi~lXx$t>Rc!>#>-2O&4O&Ch?@Khm1Ibx!GhMgO?h zy{LZ~H3)gx$kXVnlg%1?^Sy1r1qv!|{!jtmYxaEG;6E^?P0;70Mhz&B*HJ2=Ow@2iqRZ`Eco3V;rHxQk{csjpDb7!w4K9wAg@9HWlv{a{`;AP{}FXkX^2j-fHsi zQLZ!EvHJU68^je^>Y&awjMT==OY&j0FBusLUd2jodw8##a-HM`KN^jY!MX~d;7 zXA2R^Ky$Z>8JQ(Fexa-7%`XQyUEAu^l?KkSLCX*@9F6oFOAA?Cgo%6j|B#a) zR1ffI$#lT!I|(8A22SGCN(qqRts#&2cg9;8C=+8tG9%&9h0CtHN{ejw3o(y`q#Wsg z>7LVO1#DfOz6o|c1k$E9UWIkV$+YY4Or3a(sM7K>iwI5E6Og!q6dc!NZ&9juh3l(s!NZDJ}!`B0D zP@umYHY1u!m{QKPf@x+YpW%HTuL!FF4E(YHb)if_ps#R`KlM(GYFRA+qqr_s_idl< zbo?H3ilS>PQ^HhirgeeyHJ>KY{KogJjGcqE@_@>I9&8kf5x&v#9m7A%{$hVWY2sF# z`Lq(oqafWu>P+E$eR9o9&s5qe1<&r(8OzSt>w2NX#ofW4A9?gl9F>Fj$>$DD1Kx8AmYH< z2Tiy3-~~3M493hQ45VBW7`ZQK*eF$u)6 z6M5?^?1tnVvBpQbni^zGmFQ-euz7qAkJ32Z!R>Y{BOR(YMI(4n2ZxYVD*$lode@J( zGE6Q0jHN-sY@u*~Acd@I%AXNzzIelv_N!frT9BzXiqceiAMtLz)!zT>{uHkp=o2gg z*-rI?Qv^iyxk3A1P}JWrdeDtI!sgs6x+Hl{f`rG!O&y;`(p}mq_4GGRrU*))P?kmV zN!+@RM4Ut}((ms*advqC@G{x2-dU_`L;JeRSfUFXZ*@p?Tm#-8pXqZMtTh@eEsL-} z4KB;Y-?JiUD@%0wUpY|ctS~vBf^5n{IbY0Qs)07-9 zj;7nKatJ7!(&wC%Hl{T#jc;j-KGy0=zmeu)(Jdj=1QIkWFy1TxiF6xFh?bePzyHCm z8GRCIjIcf(ga65{4N{oIJ}w$;cH1%{@t>Qq!fh8lBt}DmmGD;!29xm0Pp(7t*3Bff zcLqyJPjML9dDOmq*Q8dJZvuY2Y-b5l^i@@eD(f~nJ~dZkGkagpjC-kWr=?W`#%uRf zDH*I8C4HziR@8`|u6W4%n)t+@CdD%I?;yK=Xms+}4@z|MG?^S_iCMJNQk5)=cvNzT z(Bs%_a)d4`zF(EX$4O|yZIdyo?td6f>Q#j56l?-87ZP%dXY|TTMat%vqzITs>{|Gd zbNJ+o;?abN3x&Sp6c(Wmbb5^df&nF`k(Tf~czFk{b0e{JRgR}UIUZS&nJ3qMgQD*? zNr@2dinJa9NmDU0O`c)iosZ4xGb+v}egnOMxTf@>ChSuGNvn&~evlaJXn0Znhp4r;F%GXdQW2NN;pFlH92u^&hlR(d z!g-lWYz$s*Lohg1APdJstL}U(BIL@);_Mv&)8ZqW$xMpB_F29Y`ny#OZi)V zXVGWoaKe9jG0Mkv5_MByU_!8dX2N6Je5iWx%qmO$zh{n|paZ3hJ)j(+ z3x~rt|6u8Rrs(_yK-#nxIs@OW$D7Ii&_#{U$jXN0lJ@I$oZZB$f4^Jyu^y}%R>k2i z7#oMlC0bM*3Zci3td(7thWgL@2@(B=FT!(#2MAR8fv{Ou(1&m3IEhFLV*yn`tX zp6!axe6B@#0^>`5B92o!Yw)s41gyD!CihL^hOm=Y+h65^*bNj7|kQK$i*V zd{fRMe{h z;#>tV2MTMf6@GmE>fdb)Tp5BMZxhhP9apF*&HDgRhm-W_Cm5T9{QLNC1_pI#A1YI- z9azbL+x3yob00HcqL6zSRP84s)j=wc+o67E*5Ff=8z|?OBL>-qy=wg-@JGJ0?YS@4 z%+iWb#@KZ~HrLR~wNsn-hxv&|zxgityUN*A1eJ8&-6BrLz=ZLi>NNX}jFDdx{ z^}M$|9Ctf%!c)4~|E4K+H#%@{@H<5!97Zc)L&0m87lN#AdMJ`!E~A8hMHWwie0NO3 zC~ctl&mLiITJn+On_L#d`4J`s0=)^m;d_19Umjnb*C9k<7uNHJ7RHKC@@;RB6EN~0 zsqHo0XxJNdViF!Go2+?7Xpid71B=oe}L^a7szHZ^qk)IssSu8q=K0g z-=(m>MWpHUs8e%2wL><6pHV}ps18u`u}N_Ui{(;Hq3@%cajy{s$h^}?+C-|I-iN#~ z(|iXz7d+HyWc&yM+a)>|U!-sN7uL4vFZ{&XNa3H_(q)e}1c*dbiTm&%-h034+WfaMUw+ZaWm6bKeLP!U$Pn^gxl`z zga~?+SCmxdz8A<2`oFn=na?a)|L1`J(oJkJ8pL`?RnsX5ly`#jyN4j-5PulVs5 z!k-V;&vCzs0KZJ{j*4^5Y_1sft^Pn|&5)3D|Ebk2V2Mi1lni}p1OK(jZNOyqok*rE zwqDtl&`rrd8wYRPh!yNxQs5wq2xcpMZ=xaiJrwQUo-5u#i_dGf$7`i*uw_#)H>PHT z8q&eL`+&#m0>ymKf!8iSGda!Ik2S1dZ;!}}x%fLvAK=Fv@`iH*0^9RxG?xG?7U{mm z=e(Tmpz2@kgje!rrBkceAzcfq$LRgs_p*Ce-9=FzZmAt#eM_wdRODY{_H|``%s`}1 zN24N??oI4kBA(WqHu?7M^ZqEKh^v?LYCdecKp-(qi5K%%uh9-dUL=^ucK;ShALZb^ zbX_w)3+Tr_GX-~|!2iA~TDGkl!KP%6Cn^^5_b&WT&78HTO|8RA?({uhxD)}tbFY;Z zJ<1o;SM8v!5h%ug6BE{F3>Z$RIe1FDuS83%5H=}$h#%m6G|mwY`iQHx{S7WOs^-B z54m2i&jFzsXQlc#PgW!Q@)Q%yErvsvJ0yj7P&_p#>6OKaxT5u`#ADJ|5y^4i+rNu@ zEZUtMI53v9mu6)-TgUo)9U?ivKkEnSkynbOax%n^1%) zD{Bs8Iv1iGtmZ5v?NI0d#R_ZWF{-4=vE*Y)h>1<{Oz&>>rGpMbf}TEej>b1$A{p;j z_s*x6K57x-){%GW96dMob zg)21%S%;F(;Bmin2)NgdX0C1)Cx0Lgus5db5j)WRCa>dd>yQ)Ogb{fw=RZfnk_nlX zi(O~hQlHr&xPmG;d;p7yC7o#j0MWWqn?@?tS zk*fdK&)PoyjJ6DocEbYWpXbz6f7**SQvf`b-*9=NO-Gjbu64-nT1v3oY7IRQ&%&nD zJ5O2sZrtxOM|fv$ffB^g$EVK_@JuElKWj6~)su{LBRJXp)r#(dzW2Y`1^Xnm=nH1p zUh6qjz)AHP(MW_`lfm1Wu~{{8_JAk$UblBbyq~pgUYZB>fp9OrfMEf!TkxMW6Nt$^ zukS^93p9i#c9&~^U;I=BQ!$e!yI&Z51)w`WKK`xF;y)@j|0_fIe_OEm-^=90{(see zen6Gq?%dQ4cyfb$zQl!Pgvtf<{QjfJ6&f1)pCZ?oT@K>!n}&LN(3?hjdQ}iiAaasW z&{UyLr6`|W{<;2pb1qIiK-)8NrylvEBSS#>S2pN&P;1Nm@>p}@$^c7Wn_UA`EoBG< ztvst^bz$_aM;aj?uQab3uXxaGkH-=@nXL`m0%4<2&z9|P=G|8@jeGBpgCJwQHN$=w z1bVB2l?K{x&9fw1uifuXo-;oiKDgf29%dhcLn-i`RVBZLL`VvP0v~mmu7eczCxLAS zTLHu}kEBA9qZHj~lh8rt72-Oc*;aihbgaHEu6d~!w3q&qXEe@m-cwQ=)e7Se_gESy zF7eG@XT4lAj$M2<`3DNV-WdmgQ@LM#{d;*6*!Gn;`PSp)uDONhNP+d@=gw7Qfd+HX zniRc86`#4g4HA?Z4zR;raB{1#Mus7_z+05!N~J|>nrI#b38OUhy(7bN;?K)d#AG8} zZ|%Wv1-kr)-Wl18;Dn17A%iLsii0+`$-;NH8xKy*MTLd`55+B%b~S%yjI}5ECV(Sf5vYw3^JHl+Z0Po! zo=i+O)8W+>n70PD3f^Y8Rv}Ge2el?a0Xn(HaQGPU#h=qP_&vzR#BgC1x(q~`{-X_n zYLG1nEmqRX2ctI@%3WzO_%z;XZfTx=3mc1p677IMm?Ww|T%VwJtU^5v(cVh-*gkf} zqZ7KHVyCb;A8;ucfE^`GDYr%r5g@=q#x9m%xzC3O-?*&qFo-{@fFteD7TT9YOK`in zJDQuWD?(GIkZ^-4pAfc!#Jw~hwF*ARRu#Lm>&q<-!>-fXngHWPxE&FxwR%;FdwKL= zPc+u6@=Ej8UTNE9YSY$dc><=LJz1aWkY6l`Vnuh#3uOMe=8d~G$g)Py%=0mg5QGLV zwT<7jW+5ilD*W~E2RZI}-Dg4PmxkPq-1iOZkwY z(5R;`vjRBVt!k5pb{p8}0yYtrchgaOkbLoG5e=ZFcs1_D9a3%`mxa3U%VE#<1=8w` zfNS!P&AbZN!vx)n$%^*%EM1^Yu;a-i=>6Cn{_XEF$?t9Nz$KF2$fDAr$m>#rq2 zGOH)BFJ|a}TKGTCF?j!27j9-X4=GZNyqfE7v`F|YyCvMw?#a8SrBZ2sE9M++9EhZ* z`_pk`C&t`aL3E8-ANeJnvms#s{?`$mD3IU%aAtw^{ef{(oTb8^i^Sx|CG6YwZ^Uiz zz?PIfW4B)fC=hQ98L!1LnOq*;ys{mI8S3$|`+?HnQaBBNgBER~^U}`LlTi@fKvKD* zK>lWAE**(xvvYhc@UO5P6)8`?8{qcx*rB6e`dgjXT2;z@3H@6Dzon3%YCBo>>H!FH z(v=tcdYi-J;UPbv&+oejw6GmH0Afub&$3TDE6G=Alv-1vEY+Lpa~2Dj7OQu*RNfX9(; zyKR+YnAu))CgE+qW-Xc?zF;54TkUL+o$)FdXv2$KTk791Hv#c5S7#yiybc`M1t7qy z&|8hcb0A)O8R=Cj9EKwl=bqq}DiJIC*GzRXV(aI9Ic0eil69HT-*D2T(w$(Op2KFt z@+h~Jt7$hw{O+ppd&JUid)qg-Ygjt0sB0#Q6CVq!bQSTG#Vzs1LL%%U@~sL+S}9^Y zUwG^es)rdh)H-SCs-GmMSsUO+OCo>%=5Cn7SbvZoQ^OoHAziX!q!`*WGjlcBn~lvm zH${YxXt{4;dvH=F-V^4La>~D4HS79E4Bcq(Vp>W5B7(xY^MIJ4i)y*_GnG?ei`=wQBYvn=}@B30Dsf- zTj$|fu{6zoLfI6I!faYxxyO4T4ckR&WmJK$k?Go9k?Lqh#yW7>{=Px=x4t z$8+CVo%7xK^-Ri1L&N-73zEvVTtK%4ebZ_F1#j!i$=#l{#aA@Nohf`ziY2uZ4YG5e z9>m8M!c{*&zUy{f#~bj(IkxmiI9Z!3GY+6<_{)g0n2EV4{{M7w)nQdOO&{SP(%s!C zc_`^FX#o+WIl!R~AR+BdNymXhBhnx#-5nyGN~d(Gr1XcrKJV-E?LV_STeJ7zgGb>DzOenf-;naK-OeSlYU+&%>Sd86Gs`Qzi?DN3@0Sru%cnS*V6fRX@f9QcZbI|BZP9Or{b6bY#0=&S3f; zE;$&W*3E#UJ1i|RRt_5Ge7u9{y|TfT>0)c7CrQfOmfWeNkFTH{X$Ic}4|?K1#HR?n zmdj?qdk`rNG76C=dI%1Fx&4U9URzE%=%eXaKyaQldn_0pLle$J$8*0!MJ|9Ll7Jkg z^he196l4gT-2Bi$T0T?G`keq#pSx`MlL$-Tqn>0L*^f|6N=$!{z4T#no*=}2wPRzz zJv>l72)pCHn`vOMDXW_)D|UzaZo7I^$3bjp8;eoUK=%eSJlq)_6vm=jH}_eS>R`Pp zR=h>k^GFmkyOVJ*oZ-zzpG*k5t$tWIYS2F39@?co545OM-t{nXaNK2M> z=o6!gd?mqvwPyppMPujy+_RxD37kSq#lKodjg^RIuizjs`6Y7N*1D9u@U!L%KAGaI zDk}?J70akl`(*Yi^r)0LGO4SxrCS@o_v${uWjB~_y|BWw8q-z@a zJm?vmH-(&ts!%D}T}dKMdhONB9F+Qjr=H};19L~a^MvqgsqL8t4`6CSm^lW=Xn1_Z4vPw;3{hFvq0n{VCA?ZD;bi>6Id`(3pR?|)(2NDX&e`m1lDRcwGVt;yu zBfts^i~_Z~m{lf>9Ua#GRN29&{aH4w&{|qbovF>ze?PvQlNYCjmn-x|rZP@L1X+V3 zgXFWr)h}Dc`cm^4^>MZBW$m>JI!&2Ai{}0;Jv+}1Ct6TFfZYahUp1K%`etj+liXe!y%@O#0MrO=6A(z*gCpGp%X+w>mVCL8}>_i|us_*R-@!8Eq2@H9`CJ zdAbtO+}a70Qe>KIFJJM&==JbhIeyA@yDb(-ORaBGhvTb$^P-+^zW#ca9({6n@fp{V zQ($}BLiSHMqLg$eNMBjy=oBCPl zK^1dRJXJaPcE;7hygCl_Xv&hg7;QEnWu67us09WuYl3ZM;%5E4_Sj6`MkZaK%&||% z1DUp>(YCs61GzVg> zGl}wu>qEa030dK{j0pj5K+rE26z%VG%G@<`@QO?CO6K?=3}w*Ay)MH< zdL8BThzd=-l6;Q+^1NCM;8Z#1JGsUPA5hdU;muGHjf5`Wx^0O+|5n#sdfjo`{!U_Q zj3v#Fm1pvKjM(Jaop(iS@C&>`Wn(y1#TIUAPvJ%}S(7@WTR~VNFyref_F?z&F6VWV z{npZ}x_W5w%y?ZfR zQ`}*;QW{L*RHyXi1+72C(3rP4s|4*=u9a&JuAB|ukeKvVUMVU-us zz@nU?ozFt|wm5;gEKqBMU7GlL@mnj^QrBhz)PeNT{!QbQ(!KDfg1YlOm*c7F$9iUK zu)gu3pXu0D-04bQRP2$>eudnv#E>@{kC+Xl&0~pmj-rVR;x|pEI*fPCiGzE;zVtFw zeKY^2Dk&*xRMRf-Ybx-8&C<3$PRQb6*N~1-+OSM-8d$A&Hl(@riDwEdnF<^G^KobK zPB|qte#in6|BrY5V-;q}a|cFDUl*E`d}bnduKhF;S6Jy%0pE*;Fw~T&1x!x^&7L^Y zoEV!1Ur%~D*dvT-kif=p&K7+&;62}4yrSw!9Kn6@ke&uaP!)COT;N4)uP^2XL-WSo?P{S{xjWZpMTX?Tv$b z-dN7NT?WOB&vz0_0WQe9(LQKuabMC~*Oo&ukCl9Vh9Mb}luPF5d(@1Aa^7w(J1XnZ_4%`yM6g%|A+rtJ+;ePxr z4Sx4=Vv+=8MTlEP5x=lZh6GiV)+>rpJ#B8cFHEDeQj`7ZVDx7YimS7L9JV99qdKVuU1|o$u1?QT>57;gB~%1hS3taCNa-WD>I6?8S7)8*Ym<#w z5MWuwcRkKi_V>hVRpT+)xh!5do$@^1Wv|rj4k~8IgN~c0{-mmNxFXC!H%4C^y^nb^ zhumQ6T*F#XI$ldx!QNg zqVH{DFU7wTS6d+&BTn+En=-EV_+q%PofUFh&WESieKf)#{1uRt)ygfAB!jyLL?Q&I zIJug4xRlZ(mEW(y#WX)N2IcF|Jt+MV{vhX*{bDAGtR?agvszQB1Qj;M1~~O6=_Fvu zmD1utH2MrfNZgp*y^%=Or>}4(iMu(=)u{&{g%IQ6cKjJ1w%(UULUQk zyHCF#ZR;4*Lp1wmjf_wyesez36!T3A+2@ZxG%}uwR~~9p$vZ#A!ZZB|XXJ0HRZ$S# zo&65cl;Gu1+%;t!&lSMb3rJ%M{sg#;ZG1SXSh_|Kt){`@g3_m%Cdj;glH4blzA0&XSiFo5Lrqiep# zricE)7zZRhsM4!@?y(<+PNtM=wFh!ub#o)}7U1VOWM{saXyahs;>q7@9}i!!V&amb zcOj8-Ch%FygS!bNKYZRuu)n&EC>jfBU$fp3bD6SeyjNMs{IhwgptehETQI^Pw$m+x z*#bpE8lP?7zpkP9IF}rjy$u{qH18<0Og1#cen45(E_$6%S?VB1@zxs`dy-yEkwLtT zJr_D*eL5LYtzkpI|KMBn@#--Aog^-j5uu1s+KGF}`O2{A>$j3v%k!EdQU;w(jMpAe zB}qwcG`IsBbuQ=1LhS2C_T0@0>#-#qUu8@iMGyDfjBi-m=ap^L7x4hjc;fd1CGI;$ z?+x!hzKD?IjYjzKKzhg36>pG>>^2e%{ccWttryestnbAh43dIPK1vX;u<}iA zz7`4Cq;{kqK+vOj0&V{4;tb<@qjf{evPsvUqNn=NZlhXo)0LkDB45;I{}4;uID08{ zbPM{Stay7eIO~& zFqWSnyROdr5k^Vy&%;JBZH_eaFHB;uq2DBWo4O8$-1(Y(w-}c>jUU;{9P_fU%P2f6 z%~>pcA*c3SQkL^V(7R$UPeIXl`gV6E=0A588e69}^Sii(z8wF$tK2>Cju<=w;$xWj z&Ej1B;uC{G_m%kS96ODr9#?*0?7Mg4`@FVq2z5dw@+3Y?@>NZ7)#hHmA)xWw}i2gQFFLuuBv#p2UvHroEluo zzvSU-s4ecD@!jy(U*o>W_L>nI{^`DaB!5$BM_RM<47~dll}iy1Z#c8c)EUQXpo{1! z5@K;b5*@qe?XiWyidGlOea-Om3AlWL;r;Re)5iwqY$}Uc7n-|W&Wo6}iA7PXf^#IJ zC#&8Kq&_uXr7uB9XP*bo*MW6;vn?A5V$IhLOjhYc9_F6abz1h+?`SQXqCT1?+g+_T zFR~?Xn}n_eslsF({QIfoReWndPP=M$XU%i%SC-V_n<%sIFEqQRIBKqcXwl`Yzj#Lz zh_oa%`ph+}ecXkswIJEIj_*r9;Ae5@WTwX59Znv%9mBQ<_lTsE-UZ|;k`AK6F%R_3 zTRD?&$C+ulj+uUp#u2Cyc;lQ#2fi`~K5dNV(`{ft8cIc|%G>D?r)^7ULKZd& zp;DJ-c3oyO%5?5Br2r^4VO%LMyc1CLJh+}pC$YmWCjC!CDf71b>efZ|#GhoD#s-7R zsqxG|5wQaU8EZum{UIiq-*@|u{ZSoOQ_5`yrg1pcXoPF-4G~9>G_qbAiWVoU$w#yJ zl3o(A%m0`McX1SnkOkX^1Xm?qA?1#lW0xk3S1mLp^wOCs-g!H+6ZgV+-D>Ka(VRM{ zCNZtm4z&O!t11|N` zv8}1V8C0q~D^%=o9ExoGv7rYqMU8?KDYk7-MlvF3f-I72o6Te7!VJgp-A0}c2c))Y zqo#g@MDzrN5rV3_f8f4-m3%B6pHUIL{8YuAq*|80`tFK#Y}4t#tUs1h#Qvp^Xg51l zyUb}OR$TrbpQ-3q^dS6-PUASPcM{0%aakSq3U78dA`xu8)lXxitpwKMu$0D>u$6Ke zP|G0D#L9)9>d)IVZIH->Hoghk`Mszab{|3^%T=yRHW~cp`sovC`x2qE!V^Nk1<(JL z{zJjCjBNm#;=lJ`l4~~Q>Z9nU6R+8BfY`Nyg@ptIaxHzr>l^3Y4fX`2(**YgVdii1DrmhgSXj zlEZ4n3!L3~PwKrhZ({?Iy*cc>P0&*6s-cDfe0Hmd6KMDXFGSXO;OwM*Fk21743)<} zKF7JdOXeWcY398yB~($WhX(s<8-A>$wpIE0spjB}Dq3h5Lq)#2hJFY4QZuYstNh!o zvbM136^g;3e@W$$L41F!$@cus{a^U9%oO8IJSq~>CgVT<>_3rbWzO`{#bF>MBv{pZ zvzmJt0ymr#K}lpfI!CHkFTfr|X5G}e57C_RG80RsV8KlpFC*qY#X zzTNuqZ+c;^^P4`k`8{4$m<{Yd6P(-fVgD=kE<)H&nD!UvZ`0%*HvcQ_BVz3+f4BJ? zxMTj+0trbNap&=*_iLQL56oW({(nhA>2Ex*sd5jQ2#E;kkG)jpZ>9Zv{%K8wxIKmN zufhMTzdIe?9m;>DeBC>(-s$MqQ^Efm8UeSbL>4wcl-g7L{wV!-MGr%SACw0BKO+3u z9f)5Q<%S4u7~Ai5FJP3&TZV}5P)0;54C6Oz|Bl6Mgy6KMLM;EqGB845II#S;MXV7* z^H0&!ffBjb2r*(!_vqit{Uti`ANg7TS_cx+J!8bO!+*BHFM;%o5vDf(NcxX)+0>B| R8E%a5b!5GNWAdx_{{g*SHGBX7 From 6494764e764f1d589e2146ed10bae5e3c3d02c48 Mon Sep 17 00:00:00 2001 From: fhenry Date: Wed, 27 Mar 2013 11:24:57 +0100 Subject: [PATCH 27/40] Add copy files ODT project on install --- htdocs/install/etape1.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/htdocs/install/etape1.php b/htdocs/install/etape1.php index 009d953e73d..1f48bf8efc0 100644 --- a/htdocs/install/etape1.php +++ b/htdocs/install/etape1.php @@ -400,7 +400,7 @@ if (! $error && $db->connected && $action == "set") require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php'; $srcroot=$main_dir.'/install/doctemplates'; $destroot=$main_data_dir.'/doctemplates'; - $docs=array('thirdparties' => 'thirdparty', 'proposals' => 'proposal', 'orders' => 'order', 'invoices' => 'invoice'); + $docs=array('thirdparties' => 'thirdparty', 'proposals' => 'proposal', 'orders' => 'order', 'invoices' => 'invoice', 'projects' => 'project'); foreach($docs as $cursordir => $cursorfile) { $src=$srcroot.'/'.$cursordir.'/template_'.$cursorfile.'.odt'; From c36f52c47a08a6ed5019fa4f53ec0371f554e8df Mon Sep 17 00:00:00 2001 From: Regis Houssin Date: Wed, 27 Mar 2013 11:54:10 +0100 Subject: [PATCH 28/40] Fix: avoid errors due to BROKEN FEATURES !!! --- htdocs/main.inc.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/htdocs/main.inc.php b/htdocs/main.inc.php index cd5e3e32770..39acc88fd5c 100644 --- a/htdocs/main.inc.php +++ b/htdocs/main.inc.php @@ -1020,6 +1020,7 @@ function top_htmlhead($head, $title='', $disablejs=0, $disablehead=0, $arrayofjs print ''."\n"; } // jQuery File Upload + /* if (! empty($conf->global->MAIN_USE_JQUERY_FILEUPLOAD) || (defined('REQUIRE_JQUERY_FILEUPLOAD') && constant('REQUIRE_JQUERY_FILEUPLOAD'))) { print ''."\n"; @@ -1031,6 +1032,7 @@ function top_htmlhead($head, $title='', $disablejs=0, $disablehead=0, $arrayofjs print ''."\n"; print ''."\n"; } + */ // jQuery DataTables if (! empty($conf->global->MAIN_USE_JQUERY_DATATABLES) || (defined('REQUIRE_JQUERY_DATATABLES') && constant('REQUIRE_JQUERY_DATATABLES'))) { From ce8631619a2114238bba3d9b3c202584d146feee Mon Sep 17 00:00:00 2001 From: Regis Houssin Date: Wed, 27 Mar 2013 11:54:10 +0100 Subject: [PATCH 29/40] Fix: avoid errors due to BROKEN FEATURES !!! --- htdocs/main.inc.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/htdocs/main.inc.php b/htdocs/main.inc.php index dd6ac430fee..88efcfd76b5 100644 --- a/htdocs/main.inc.php +++ b/htdocs/main.inc.php @@ -1075,6 +1075,7 @@ function top_htmlhead($head, $title='', $disablejs=0, $disablehead=0, $arrayofjs print ''."\n"; } // jQuery File Upload + /* if (! empty($conf->global->MAIN_USE_JQUERY_FILEUPLOAD) || (defined('REQUIRE_JQUERY_FILEUPLOAD') && constant('REQUIRE_JQUERY_FILEUPLOAD'))) { print ''."\n"; @@ -1086,6 +1087,7 @@ function top_htmlhead($head, $title='', $disablejs=0, $disablehead=0, $arrayofjs print ''."\n"; print ''."\n"; } + */ // jQuery DataTables if (! empty($conf->global->MAIN_USE_JQUERY_DATATABLES) || (defined('REQUIRE_JQUERY_DATATABLES') && constant('REQUIRE_JQUERY_DATATABLES'))) { From da8932f9877fbc1755704ec71415fed19a2807e5 Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Wed, 27 Mar 2013 13:24:26 +0100 Subject: [PATCH 30/40] Some fix for cron module --- htdocs/cron/card.php | 27 +++++++++++++++++++++------ htdocs/cron/list.php | 31 ++++++++++++++++++++----------- 2 files changed, 41 insertions(+), 17 deletions(-) diff --git a/htdocs/cron/card.php b/htdocs/cron/card.php index 13ccb27cb0b..6148ed5d5f7 100644 --- a/htdocs/cron/card.php +++ b/htdocs/cron/card.php @@ -82,6 +82,8 @@ if ($action == 'confirm_execute' && $confirm == "yes" && $user->rights->cron->ex setEventMessage($object->error,'errors'); $action=''; }else { + if ($object->lastresult > 0) setEventMessage($langs->trans("JobFinished"),'warnings'); + else setEventMessage($langs->trans("JobFinished"),'mesgs'); $action=''; } @@ -194,10 +196,13 @@ if ($action=='inactive') { llxHeader('',$langs->trans("CronAdd")); -if ($action=='edit' || empty($action) || $action=='delete' || $action=='execute') { +if ($action=='edit' || empty($action) || $action=='delete' || $action=='execute') +{ $head=cron_prepare_head($object); dol_fiche_head($head, 'card', $langs->trans("CronTask"), 0, 'bill'); -} elseif ($action=='create') { +} +elseif ($action=='create') +{ print_fiche_titre($langs->trans("CronTask"),'','setup'); } @@ -251,8 +256,8 @@ if (empty($object->status) && $action != 'create') dol_htmloutput_mesg($langs->trans("CronTaskInactive"),'','warning',1); } -if (($action=="create") || ($action=="edit")) { - +if (($action=="create") || ($action=="edit")) +{ print ''; print ''."\n"; if (!empty($object->id)) { @@ -565,6 +570,10 @@ if (($action=="create") || ($action=="edit")) { print ''; + + dol_fiche_end(); + + print "\n\n

\n"; if (! $user->rights->cron->create) { print ''.$langs->trans("Edit").''; @@ -585,9 +594,15 @@ if (($action=="create") || ($action=="edit")) { print ''.$langs->trans("CronStatusInactiveBtn").''; } } - if ((! $user->rights->cron->execute) || (empty($object->status))) { + if ((empty($user->rights->cron->execute))) + { print ''.$langs->trans("CronExecute").''; - } else { + } + else if (empty($object->status)) + { + print ''.$langs->trans("CronExecute").''; + } + else { print ''.$langs->trans("CronExecute").''; } print '

'; diff --git a/htdocs/cron/list.php b/htdocs/cron/list.php index db36cc5d59b..efed9579d1f 100644 --- a/htdocs/cron/list.php +++ b/htdocs/cron/list.php @@ -203,7 +203,7 @@ if (count($object->lines)>0) { print ''; if(!empty($line->label)) { - print ''.$line->label.''; + print ''.$line->label.''; } else { print $langs->trans('CronNone'); @@ -229,19 +229,19 @@ if (count($object->lines)>0) { print ''; print ''; - if(!empty($line->datestart)) {print dol_print_date($line->datestart,'dayhourtext');} else {print $langs->trans('CronNone');} + if(!empty($line->datestart)) {print dol_print_date($line->datestart,'dayhour');} else {print $langs->trans('CronNone');} print ''; print ''; - if(!empty($line->dateend)) {print dol_print_date($line->dateend,'dayhourtext');} else {print $langs->trans('CronNone');} + if(!empty($line->dateend)) {print dol_print_date($line->dateend,'dayhour');} else {print $langs->trans('CronNone');} print ''; print ''; - if(!empty($line->datelastrun)) {print dol_print_date($line->datelastrun,'dayhourtext');} else {print $langs->trans('CronNone');} + if(!empty($line->datelastrun)) {print dol_print_date($line->datelastrun,'dayhour');} else {print $langs->trans('CronNone');} print ''; print ''; - if(!empty($line->datenextrun)) {print dol_print_date($line->datenextrun,'dayhourtext');} else {print $langs->trans('CronNone');} + if(!empty($line->datenextrun)) {print dol_print_date($line->datenextrun,'dayhour');} else {print $langs->trans('CronNone');} print ''; print ''; @@ -283,13 +283,22 @@ if (count($object->lines)>0) { print $langs->trans('CronNoJobs'); } -print "\n\n
\n"; -if (! $user->rights->cron->create) { +print "\n
\n"; + +if (! $user->rights->cron->create) +{ print ''.$langs->trans("New").''; -} else { - print ''.$langs->trans("New").''; } -print '

'; +else +{ + print ''.$langs->trans("New").''; +} + +print '
'; + +print '
'; llxFooter(); -$db->close(); \ No newline at end of file + +$db->close(); +?> \ No newline at end of file From 982b3e9d66fdde2594e4aa245aaf103881824cdf Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Wed, 27 Mar 2013 13:59:45 +0100 Subject: [PATCH 31/40] Add trigger into delete line for supplier invoice --- .../fourn/class/fournisseur.facture.class.php | 70 +++++++++++++++---- 1 file changed, 56 insertions(+), 14 deletions(-) diff --git a/htdocs/fourn/class/fournisseur.facture.class.php b/htdocs/fourn/class/fournisseur.facture.class.php index 60bdf26a8ab..840c4cecb94 100644 --- a/htdocs/fourn/class/fournisseur.facture.class.php +++ b/htdocs/fourn/class/fournisseur.facture.class.php @@ -1166,24 +1166,66 @@ class FactureFournisseur extends CommonInvoice } /** - * Delete a detail line from database + * Delete a detail line from database * - * @param int $rowid Id of line to delete - * @return void + * @param int $rowid Id of line to delete + * @param int $notrigger 1=Does not execute triggers, 0= execute triggers + * @return void */ - function deleteline($rowid) + function deleteline($rowid, $notrigger=0) { - // Supprime ligne - $sql = 'DELETE FROM '.MAIN_DB_PREFIX.'facture_fourn_det '; - $sql .= ' WHERE rowid = '.$rowid.';'; - $resql = $this->db->query($sql); - if (! $resql) + global $user, $langs, $conf; + + if (! $rowid) $rowid=$this->id; + + dol_syslog(get_class($this)."::delete rowid=".$rowid, LOG_DEBUG); + + $error=0; + $this->db->begin(); + + if (! $error && ! $notrigger) { - dol_print_error($this->db); + // Appel des triggers + include_once(DOL_DOCUMENT_ROOT . "/core/class/interfaces.class.php"); + $interface=new Interfaces($this->db); + $result=$interface->run_triggers('LINEBILL_SUPPLIER_DELETE',$this,$user,$langs,$conf); + if ($result < 0) { + $error++; $this->errors=$interface->errors; + } + // Fin appel triggers } - // Mise a jour prix facture - $this->update_price(); - return 1; + + if (! $error) + { + // Supprime ligne + $sql = 'DELETE FROM '.MAIN_DB_PREFIX.'facture_fourn_det '; + $sql.= ' WHERE rowid = '.$rowid; + dol_syslog(get_class($this)."::delete sql=".$sql, LOG_DEBUG); + $resql = $this->db->query($sql); + if (! $resql) + { + $error++; + $this->error=$this->db->lasterror(); + dol_syslog(get_class($this)."::delete ".$this->error, LOG_ERR); + } + } + + if (! $error) + { + // Mise a jour prix facture + $this->update_price(); + } + + if (! $error) + { + $this->db->commit(); + return 1; + } + else + { + $this->db->rollback(); + return -1; + } } @@ -1305,7 +1347,7 @@ class FactureFournisseur extends CommonInvoice $result.=$lien.($max?dol_trunc($this->ref,$max):$this->ref).$lienfin; return $result; } - + /** * Renvoie la reference de facture suivante non utilisee en fonction du modele * de numerotation actif defini dans INVOICE_SUPPLIER_ADDON_NUMBER From 393cecb1c23c67d7e32410e77ca03730a60fe374 Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Wed, 27 Mar 2013 14:08:15 +0100 Subject: [PATCH 32/40] New: Add hook --- htdocs/fourn/facture/paiement.php | 177 ++++++++++++++++-------------- 1 file changed, 92 insertions(+), 85 deletions(-) diff --git a/htdocs/fourn/facture/paiement.php b/htdocs/fourn/facture/paiement.php index e9358624fe2..51b9972260e 100644 --- a/htdocs/fourn/facture/paiement.php +++ b/htdocs/fourn/facture/paiement.php @@ -185,8 +185,8 @@ $form=new Form($db); if ($action == 'create' || $action == 'add_paiement') { - $facture = new FactureFournisseur($db); - $facture->fetch($facid); + $object = new FactureFournisseur($db); + $object->fetch($facid); $datefacture=dol_mktime(12, 0, 0, GETPOST('remonth'), GETPOST('reday'), GETPOST('reyear')); $dateinvoice=($datefacture==''?(empty($conf->global->MAIN_AUTOFILL_DATE)?-1:0):$datefacture); @@ -248,91 +248,98 @@ if ($action == 'create' || $action == 'add_paiement') } print ''; - /* - * Autres factures impayees - */ - $sql = 'SELECT f.rowid as facid, f.rowid as ref, f.facnumber, f.total_ht, f.total_ttc, f.datef as df'; - $sql.= ', SUM(pf.amount) as am'; - $sql.= ' FROM '.MAIN_DB_PREFIX.'facture_fourn as f'; - $sql.= ' LEFT JOIN '.MAIN_DB_PREFIX.'paiementfourn_facturefourn as pf ON pf.fk_facturefourn = f.rowid'; - $sql.= " WHERE f.entity = ".$conf->entity; - $sql.= ' AND f.fk_soc = '.$facture->socid; - $sql.= ' AND f.paye = 0'; - $sql.= ' AND f.fk_statut = 1'; // Statut=0 => non validee, Statut=2 => annulee - $sql.= ' GROUP BY f.rowid, f.facnumber, f.total_ht, f.total_ttc, f.datef'; - $resql = $db->query($sql); - if ($resql) - { - $num = $db->num_rows($resql); - if ($num > 0) - { - $i = 0; - print '
'; - print $langs->trans('Invoices').'
'; - print ''; - print ''; - print ''; - print ''; - print ''; - print ''; - print ''; - print ''; - print ''; - print ''; + $parameters=array('facid'=>$facid, 'ref'=>$ref, 'objcanvas'=>$objcanvas); + $reshook=$hookmanager->executeHooks('paymentsupplierinvoices',$parameters,$object,$action); // Note that $action and $object may have been modified by some hooks + $error=$hookmanager->error; $errors=$hookmanager->errors; + if (empty($reshook)) + { + /* + * Autres factures impayees + */ + $sql = 'SELECT f.rowid as facid, f.rowid as ref, f.facnumber, f.total_ht, f.total_ttc, f.datef as df'; + $sql.= ', SUM(pf.amount) as am'; + $sql.= ' FROM '.MAIN_DB_PREFIX.'facture_fourn as f'; + $sql.= ' LEFT JOIN '.MAIN_DB_PREFIX.'paiementfourn_facturefourn as pf ON pf.fk_facturefourn = f.rowid'; + $sql.= " WHERE f.entity = ".$conf->entity; + $sql.= ' AND f.fk_soc = '.$object->socid; + $sql.= ' AND f.paye = 0'; + $sql.= ' AND f.fk_statut = 1'; // Statut=0 => non validee, Statut=2 => annulee + $sql.= ' GROUP BY f.rowid, f.facnumber, f.total_ht, f.total_ttc, f.datef'; + $resql = $db->query($sql); + if ($resql) + { + $num = $db->num_rows($resql); + if ($num > 0) + { + $i = 0; + print '
'; - $var=True; - $total=0; - $total_ttc=0; - $totalrecu=0; - while ($i < $num) - { - $objp = $db->fetch_object($resql); - $var=!$var; - print ''; - print ''; - print ''; - if ($objp->df > 0 ) - { - print ''; - } - else - { - print ''; - } - print ''; - print ''; - print ''; - print '\n"; - $total+=$objp->total_ht; - $total_ttc+=$objp->total_ttc; - $totalrecu+=$objp->am; - $i++; - } - if ($i > 1) - { - // Print total - print ''; - print ''; - print ''; - print ''; - print ''; - print ''; - print "\n"; - } - print "
'.$langs->trans('Ref').''.$langs->trans('RefSupplier').''.$langs->trans('Date').''.$langs->trans('AmountTTC').''.$langs->trans('AlreadyPaid').''.$langs->trans('RemainderToPay').''.$langs->trans('Amount').'
'.img_object($langs->trans('ShowBill'),'bill').' '.$objp->ref; - print ''.$objp->facnumber.''; - print dol_print_date($db->jdate($objp->df)).'!!!'.price($objp->total_ttc).''.price($objp->am).''.price($objp->total_ttc - $objp->am).''; - $namef = 'amount_'.$objp->facid; - print ''; - print "
'.$langs->trans('TotalTTC').':'.price($total_ttc).''.price($totalrecu).''.price($total_ttc - $totalrecu).' 
\n"; - } - $db->free($resql); - } - else - { - dol_print_error($db); - } + print $langs->trans('Invoices').'
'; + print ''; + print ''; + print ''; + print ''; + print ''; + print ''; + print ''; + print ''; + print ''; + print ''; + + $var=True; + $total=0; + $total_ttc=0; + $totalrecu=0; + while ($i < $num) + { + $objp = $db->fetch_object($resql); + $var=!$var; + print ''; + print ''; + print ''; + if ($objp->df > 0 ) + { + print ''; + } + else + { + print ''; + } + print ''; + print ''; + print ''; + print '\n"; + $total+=$objp->total_ht; + $total_ttc+=$objp->total_ttc; + $totalrecu+=$objp->am; + $i++; + } + if ($i > 1) + { + // Print total + print ''; + print ''; + print ''; + print ''; + print ''; + print ''; + print "\n"; + } + print "
'.$langs->trans('Ref').''.$langs->trans('RefSupplier').''.$langs->trans('Date').''.$langs->trans('AmountTTC').''.$langs->trans('AlreadyPaid').''.$langs->trans('RemainderToPay').''.$langs->trans('Amount').'
'.img_object($langs->trans('ShowBill'),'bill').' '.$objp->ref; + print ''.$objp->facnumber.''; + print dol_print_date($db->jdate($objp->df)).'!!!'.price($objp->total_ttc).''.price($objp->am).''.price($objp->total_ttc - $objp->am).''; + $namef = 'amount_'.$objp->facid; + print ''; + print "
'.$langs->trans('TotalTTC').':'.price($total_ttc).''.price($totalrecu).''.price($total_ttc - $totalrecu).' 
\n"; + } + $db->free($resql); + } + else + { + dol_print_error($db); + } + } // print ''; print '

'.$langs->trans("ClosePaidInvoicesAutomatically"); From a22d39adfb789fd54b6cfcca3779ff85705cc10d Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Wed, 27 Mar 2013 14:11:15 +0100 Subject: [PATCH 33/40] Fix: Hook is a replaceadd hook. --- htdocs/core/class/hookmanager.class.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/htdocs/core/class/hookmanager.class.php b/htdocs/core/class/hookmanager.class.php index 9154aaa2fdd..72b49af418e 100755 --- a/htdocs/core/class/hookmanager.class.php +++ b/htdocs/core/class/hookmanager.class.php @@ -131,7 +131,7 @@ class HookManager // Define type of hook ('output', 'returnvalue' or 'addreplace') $hooktype='output'; if (preg_match('/^pdf_/',$method)) $hooktype='returnvalue'; // pdf_xxx except pdf_writelinedesc are returnvalue hooks. When there is 2 hooks of this type, only last one win. - if ($method == 'doActions' || $method == 'formObjectOptions' || $method == 'pdf_writelinedesc') $hooktype='addreplace'; + if (in_array($method,array('doActions','formObjectOptions','pdf_writelinedesc','paymentsupplierinvoices'))) $hooktype='addreplace'; // Loop on each hook to qualify modules that declared context $modulealreadyexecuted=array(); @@ -150,7 +150,7 @@ class HookManager // test to avoid to run twice a hook, when a module implements several active contexts if (in_array($module,$modulealreadyexecuted)) continue; $modulealreadyexecuted[$module]=$module; - // Hooks that return int + // Hooks that return int (doActions, formObjectOptions, pdf_writelinedesc, paymentsupplierinvoices) if ($hooktype == 'addreplace') { $resaction += $actionclassinstance->$method($parameters, $object, $action, $this); // $object and $action can be changed by method ($object->id during creation for example or $action to go back to other action for example) @@ -159,7 +159,7 @@ class HookManager $error++; $this->error=$actionclassinstance->error; $this->errors=array_merge($this->errors, (array) $actionclassinstance->errors); - // TODO remove this. Change must be inside the method if required + // TODO remove this. Change must be inside the method of hook if required if ($method == 'doActions') { if ($action=='add') $action='create'; @@ -170,7 +170,7 @@ class HookManager // Generic hooks that return a string (printSearchForm, printLeftBlock, printTopRightMenu, formAddObjectLine, formBuilddocOptions, ...) else { - // TODO. this should be done into the method by returning nothing + // TODO. this should be done into the method of hook by returning nothing if (is_array($parameters) && ! empty($parameters['special_code']) && $parameters['special_code'] > 3 && $parameters['special_code'] != $actionclassinstance->module_number) continue; $result = $actionclassinstance->$method($parameters, $object, $action, $this); // $object and $action can be changed by method ($object->id during creation for example or $action to go back to other action for example) From 6c1bbd3aebed5e0121c4b484dfadefb593956de0 Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Wed, 27 Mar 2013 14:24:33 +0100 Subject: [PATCH 34/40] New: Uniformize hooks. --- htdocs/fourn/facture/fiche.php | 27 +++++++++++++++++---------- 1 file changed, 17 insertions(+), 10 deletions(-) diff --git a/htdocs/fourn/facture/fiche.php b/htdocs/fourn/facture/fiche.php index b726d39231a..b8b4c209cb3 100644 --- a/htdocs/fourn/facture/fiche.php +++ b/htdocs/fourn/facture/fiche.php @@ -749,7 +749,7 @@ if ($action == 'send' && ! $_POST['addfile'] && ! $_POST['removedfile'] && ! $_P { $mesg=$langs->trans('MailSuccessfulySent',$mailfile->getValidAddress($from,2),$mailfile->getValidAddress($sendto,2)); // Must not contain " setEventMessage($mesg); - + $error=0; // Initialisation donnees @@ -1177,7 +1177,8 @@ if ($action == 'create') if (1==2 && ! empty($conf->global->PRODUCT_SHOW_WHEN_CREATE)) { print ''; - print ' '.$langs->trans('Label').''; + print ' '; + print ''.$langs->trans('Label').''; print ''.$langs->trans('PriceUHT').''; print ''.$langs->trans('VAT').''; print ''.$langs->trans('Qty').''; @@ -1201,7 +1202,7 @@ if ($action == 'create') } // Other options - $parameters=array(); + $parameters=array('colspan' => ' colspan="6"'); $reshook=$hookmanager->executeHooks('formObjectOptions',$parameters,$object,$action); // Note that $action and $object may have been modified by hook // Bouton "Create Draft" @@ -1571,7 +1572,7 @@ else } // Other options - $parameters=array('colspan' => ' colspan="3"'); + $parameters=array('colspan' => ' colspan="4"'); $reshook=$hookmanager->executeHooks('formObjectOptions',$parameters,$object,$action); // Note that $action and $object may have been modified by hook print ''; @@ -1736,6 +1737,12 @@ else // Show range print_date_range($date_start,$date_end); } + + if (is_object($hookmanager)) + { + $parameters=array('fk_parent_line'=>$line->fk_parent_line, 'line'=>$object->lines[$i],'var'=>$var,'num'=>$num,'i'=>$i); + $reshook=$hookmanager->executeHooks('formViewProductSupplierOptions',$parameters,$object,$action); + } print ''; // VAT @@ -1808,7 +1815,7 @@ else if (is_object($hookmanager)) { $parameters=array(); - $reshook=$hookmanager->executeHooks('formCreateProductOptions',$parameters,$object,$action); + $reshook=$hookmanager->executeHooks('formCreateSupplierProductOptions',$parameters,$object,$action); } // Editor wysiwyg @@ -2036,7 +2043,7 @@ else * Show mail form */ if ($action == 'presend') - { + { $ref = dol_sanitizeFileName($object->ref); include_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php'; $fileparams = dol_most_recent_file($conf->fournisseur->facture->dir_output.'/'.get_exdir($object->id,2).$ref, preg_quote($object->ref,'/')); @@ -2092,12 +2099,12 @@ else $formmail->substit['__SIGNATURE__']=$user->signature; $formmail->substit['__PERSONALIZED__']=''; $formmail->substit['__CONTACTCIVNAME__']=''; - + //Find the good contact adress $custcontact=''; $contactarr=array(); $contactarr=$object->liste_contact(-1,'external'); - + if (is_array($contactarr) && count($contactarr)>0) { foreach($contactarr as $contact) { if ($contact['libelle']==$langs->trans('TypeContact_invoice_supplier_external_BILLING')) { @@ -2107,12 +2114,12 @@ else $custcontact=$contactstatic->getFullName($langs,1); } } - + if (!empty($custcontact)) { $formmail->substit['__CONTACTCIVNAME__']=$custcontact; } } - + // Tableau des parametres complementaires $formmail->param['action']='send'; $formmail->param['models']='invoice_supplier_send'; From 47b6829e177e6228924d858159f87bbc0569b347 Mon Sep 17 00:00:00 2001 From: jfefe Date: Wed, 27 Mar 2013 14:39:41 +0100 Subject: [PATCH 35/40] Remove DOS EOF (dos2unix utility used) --- htdocs/comm/propal.php | 4540 ++++++++++++++++++++-------------------- 1 file changed, 2270 insertions(+), 2270 deletions(-) diff --git a/htdocs/comm/propal.php b/htdocs/comm/propal.php index de1a87ffe7e..c3a908fcea4 100644 --- a/htdocs/comm/propal.php +++ b/htdocs/comm/propal.php @@ -1,2250 +1,2250 @@ - - * Copyright (C) 2004-2013 Laurent Destailleur - * Copyright (C) 2004 Eric Seigne - * 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-2011 Philippe Grand - * Copyright (C) 2012 Christophe Battarel -* - * 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/comm/propal.php - * \ingroup propale - * \brief Page of commercial proposals card and list - */ - -require '../main.inc.php'; -require_once DOL_DOCUMENT_ROOT.'/core/class/html.formother.class.php'; -require_once DOL_DOCUMENT_ROOT.'/core/class/html.formfile.class.php'; -require_once DOL_DOCUMENT_ROOT.'/core/class/html.formpropal.class.php'; -require_once DOL_DOCUMENT_ROOT.'/comm/propal/class/propal.class.php'; -require_once DOL_DOCUMENT_ROOT.'/comm/action/class/actioncomm.class.php'; -require_once DOL_DOCUMENT_ROOT.'/core/modules/propale/modules_propale.php'; -require_once DOL_DOCUMENT_ROOT.'/core/lib/propal.lib.php'; -require_once DOL_DOCUMENT_ROOT.'/core/lib/functions2.lib.php'; -require_once DOL_DOCUMENT_ROOT.'/core/class/extrafields.class.php'; -if (! empty($conf->projet->enabled)) -{ - require_once DOL_DOCUMENT_ROOT.'/projet/class/project.class.php'; - require_once DOL_DOCUMENT_ROOT.'/core/lib/project.lib.php'; -} - -$langs->load('companies'); -$langs->load('propal'); -$langs->load('compta'); -$langs->load('bills'); -$langs->load('orders'); -$langs->load('products'); -$langs->load("deliveries"); -if (! empty($conf->margin->enabled)) - $langs->load('margins'); - -$error=0; - -$id=GETPOST('id','int'); -$ref=GETPOST('ref','alpha'); -$socid=GETPOST('socid','int'); -$action=GETPOST('action','alpha'); -$origin=GETPOST('origin','alpha'); -$originid=GETPOST('originid','int'); -$confirm=GETPOST('confirm','alpha'); -$lineid=GETPOST('lineid','int'); - -//PDF -$hidedetails = (GETPOST('hidedetails','int') ? GETPOST('hidedetails','int') : (! empty($conf->global->MAIN_GENERATE_DOCUMENTS_HIDE_DETAILS) ? 1 : 0)); -$hidedesc = (GETPOST('hidedesc','int') ? GETPOST('hidedesc','int') : (! empty($conf->global->MAIN_GENERATE_DOCUMENTS_HIDE_DESC) ? 1 : 0)); -$hideref = (GETPOST('hideref','int') ? GETPOST('hideref','int') : (! empty($conf->global->MAIN_GENERATE_DOCUMENTS_HIDE_REF) ? 1 : 0)); - -// Nombre de ligne pour choix de produit/service predefinis -$NBLINES=4; - -// Security check -if (! empty($user->societe_id)) $socid=$user->societe_id; -$result = restrictedArea($user, 'propal', $id); - -$object = new Propal($db); -$extrafields = new ExtraFields($db); - -// Load object -if ($id > 0 || ! empty($ref)) -{ - $ret=$object->fetch($id, $ref); - if ($ret > 0) $ret=$object->fetch_thirdparty(); - if ($ret < 0) dol_print_error('',$object->error); -} - -// Initialize technical object to manage hooks of thirdparties. Note that conf->hooks_modules contains array array -$hookmanager->initHooks(array('propalcard')); - - - -/* - * Actions - */ - -$parameters=array('socid'=>$socid); -$reshook=$hookmanager->executeHooks('doActions',$parameters,$object,$action); // Note that $action and $object may have been modified by some hooks - -// Action clone object -if ($action == 'confirm_clone' && $confirm == 'yes') -{ - if (1==0 && ! GETPOST('clone_content') && ! GETPOST('clone_receivers')) - { - setEventMessage($langs->trans("NoCloneOptionsSpecified"), 'errors'); - } - else - { - if ($object->id > 0) - { - $result=$object->createFromClone($socid); - if ($result > 0) - { - header("Location: ".$_SERVER['PHP_SELF'].'?id='.$result); - exit; - } - else - { - setEventMessage($object->error, 'errors'); - $action=''; - } - } - } -} - -// Suppression de la propale -else if ($action == 'confirm_delete' && $confirm == 'yes' && $user->rights->propal->supprimer) -{ - $result=$object->delete($user); - if ($result > 0) - { - header('Location: '.DOL_URL_ROOT.'/comm/propal/list.php'); - exit; - } - else - { - $langs->load("errors"); - setEventMessage($langs->trans($object->error), 'errors'); - } -} - -// Remove line -else if ($action == 'confirm_deleteline' && $confirm == 'yes' && $user->rights->propal->creer) -{ - $result = $object->deleteline($lineid); - // reorder lines - if ($result) $object->line_order(true); - - if (empty($conf->global->MAIN_DISABLE_PDF_AUTOUPDATE)) - { - // Define output language - $outputlangs = $langs; - if (! empty($conf->global->MAIN_MULTILANGS)) - { - $outputlangs = new Translate("",$conf); - $newlang=(GETPOST('lang_id') ? GETPOST('lang_id') : $object->client->default_lang); - $outputlangs->setDefaultLang($newlang); - } - $ret=$object->fetch($id); // Reload to get new records - propale_pdf_create($db, $object, $object->modelpdf, $outputlangs, $hidedetails, $hidedesc, $hideref); - } - - header('Location: '.$_SERVER["PHP_SELF"].'?id='.$object->id); - exit; -} - -// Validation -else if ($action == 'confirm_validate' && $confirm == 'yes' && $user->rights->propal->valider) -{ - $result=$object->valid($user); - if ($result >= 0) - { - if (empty($conf->global->MAIN_DISABLE_PDF_AUTOUPDATE)) - { - // Define output language - $outputlangs = $langs; - if (! empty($conf->global->MAIN_MULTILANGS)) - { - $outputlangs = new Translate("",$conf); - $newlang=(GETPOST('lang_id') ? GETPOST('lang_id') : $object->client->default_lang); - $outputlangs->setDefaultLang($newlang); - } - $ret=$object->fetch($id); // Reload to get new records - propale_pdf_create($db, $object, $object->modelpdf, $outputlangs, $hidedetails, $hidedesc, $hideref); - } - } - else - { - $langs->load("errors"); - setEventMessage($langs->trans($object->error), 'errors'); - } -} - -else if ($action == 'setdate' && $user->rights->propal->creer) -{ - $datep=dol_mktime(12, 0, 0, $_POST['remonth'], $_POST['reday'], $_POST['reyear']); - - if (empty($datep)) - { - $error++; - setEventMessage($langs->trans("ErrorFieldRequired",$langs->transnoentitiesnoconv("Date")), 'errors'); - } - - if (! $error) - { - $result=$object->set_date($user,$datep); - if ($result < 0) dol_print_error($db,$object->error); - } -} -else if ($action == 'setecheance' && $user->rights->propal->creer) -{ - $result=$object->set_echeance($user,dol_mktime(12, 0, 0, $_POST['echmonth'], $_POST['echday'], $_POST['echyear'])); - if ($result < 0) dol_print_error($db,$object->error); -} -else if ($action == 'setdate_livraison' && $user->rights->propal->creer) -{ - $result=$object->set_date_livraison($user,dol_mktime(12, 0, 0, $_POST['liv_month'], $_POST['liv_day'], $_POST['liv_year'])); - if ($result < 0) dol_print_error($db,$object->error); -} - -// Positionne ref client -else if ($action == 'set_ref_client' && $user->rights->propal->creer) -{ - $object->set_ref_client($user, $_POST['ref_client']); -} - -else if ($action == 'setnote_public' && $user->rights->propal->creer) -{ - $result=$object->update_note_public(dol_html_entity_decode(GETPOST('note_public'), ENT_QUOTES)); - if ($result < 0) dol_print_error($db,$object->error); -} - -else if ($action == 'setnote' && $user->rights->propal->creer) -{ - $result=$object->update_note(dol_html_entity_decode(GETPOST('note'), ENT_QUOTES)); - if ($result < 0) dol_print_error($db,$object->error); -} - -// Create proposal -else if ($action == 'add' && $user->rights->propal->creer) -{ - $object->socid=$socid; - $object->fetch_thirdparty(); - - $datep=dol_mktime(12, 0, 0, GETPOST('remonth'), GETPOST('reday'), GETPOST('reyear')); - $date_delivery=dol_mktime(12, 0, 0, GETPOST('liv_month'), GETPOST('liv_day'), GETPOST('liv_year')); - $duration=GETPOST('duree_validite'); - - if (empty($datep)) - { - setEventMessage($langs->trans("ErrorFieldRequired",$langs->transnoentitiesnoconv("Date")), 'errors'); - $action='create'; - $error++; - } - if (empty($duration)) - { - setEventMessage($langs->trans("ErrorFieldRequired",$langs->transnoentitiesnoconv("ValidityDuration")), 'errors'); - $action='create'; - $error++; - } - - if ($socid<1) - { - setEventMessage($langs->trans("ErrorFieldRequired",$langs->transnoentitiesnoconv("Customer")),'errors'); - $action='create'; - $error++; - } - - if (! $error) - { - $db->begin(); - - // Si on a selectionne une propal a copier, on realise la copie - if (GETPOST('createmode')=='copy' && GETPOST('copie_propal')) - { - if ($object->fetch(GETPOST('copie_propal')) > 0) - { - $object->ref = GETPOST('ref'); - $object->datep = $datep; - $object->date_livraison = $date_delivery; - $object->availability_id = GETPOST('availability_id'); - $object->demand_reason_id = GETPOST('demand_reason_id'); - $object->fk_delivery_address = GETPOST('fk_address'); - $object->duree_validite = $duration; - $object->cond_reglement_id = GETPOST('cond_reglement_id'); - $object->mode_reglement_id = GETPOST('mode_reglement_id'); - $object->remise_percent = GETPOST('remise_percent'); - $object->remise_absolue = GETPOST('remise_absolue'); - $object->socid = GETPOST('socid'); - $object->contactid = GETPOST('contactidp'); - $object->fk_project = GETPOST('projectid'); - $object->modelpdf = GETPOST('model'); - $object->author = $user->id; // deprecated - $object->note = GETPOST('note'); - $object->statut = 0; - - $id = $object->create_from($user); - } - else - { - setEventMessage($langs->trans("ErrorFailedToCopyProposal",GETPOST('copie_propal')), 'errors'); - } - } - else - { - $object->ref = GETPOST('ref'); - $object->ref_client = GETPOST('ref_client'); - $object->datep = $datep; - $object->date_livraison = $date_delivery; - $object->availability_id = GETPOST('availability_id'); - $object->demand_reason_id = GETPOST('demand_reason_id'); - $object->fk_delivery_address = GETPOST('fk_address'); - $object->duree_validite = GETPOST('duree_validite'); - $object->cond_reglement_id = GETPOST('cond_reglement_id'); - $object->mode_reglement_id = GETPOST('mode_reglement_id'); - - $object->contactid = GETPOST('contactidp'); - $object->fk_project = GETPOST('projectid'); - $object->modelpdf = GETPOST('model'); - $object->author = $user->id; // deprecated - $object->note = GETPOST('note'); - - $object->origin = GETPOST('origin'); - $object->origin_id = GETPOST('originid'); - - for ($i = 1 ; $i <= $conf->global->PRODUCT_SHOW_WHEN_CREATE; $i++) - { - if ($_POST['idprod'.$i]) - { - $xid = 'idprod'.$i; - $xqty = 'qty'.$i; - $xremise = 'remise'.$i; - $object->add_product($_POST[$xid],$_POST[$xqty],$_POST[$xremise]); - } - } - - // Get extra fields - foreach($_POST as $key => $value) - { - if (preg_match("/^options_/",$key)) - { - $object->array_options[$key]=GETPOST($key); - } - } - - $id = $object->create($user); - } - - if ($id > 0) - { - // Insertion contact par defaut si defini - if (GETPOST('contactidp')) - { - $result=$object->add_contact(GETPOST('contactidp'),'CUSTOMER','external'); - if ($result < 0) - { - $error++; - setEventMessage($langs->trans("ErrorFailedToAddContact"), 'errors'); - } - } - - if (! $error) - { - $db->commit(); - - if (empty($conf->global->MAIN_DISABLE_PDF_AUTOUPDATE)) - { - // Define output language - $outputlangs = $langs; - if (! empty($conf->global->MAIN_MULTILANGS)) - { - $outputlangs = new Translate("",$conf); - $newlang=(GETPOST('lang_id') ? GETPOST('lang_id') : $object->client->default_lang); - $outputlangs->setDefaultLang($newlang); - } - $ret=$object->fetch($id); // Reload to get new records - propale_pdf_create($db, $object, $object->modelpdf, $outputlangs, $hidedetails, $hidedesc, $hideref); - } - - header('Location: '.$_SERVER["PHP_SELF"].'?id='.$id); - exit; - } - else - { - $db->rollback(); - } - } - else - { - dol_print_error($db,$object->error); - $db->rollback(); - exit; - } - } -} - -// Classify billed -else if ($action == 'classifybilled' && $user->rights->propal->cloturer) -{ - $object->cloture($user, 4, ''); -} - -// Reopen proposal -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->setStatut(1); - } -} - -// Close proposal -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')); - } - } -} - -/* - * Add file in email form - */ -if (GETPOST('addfile')) -{ - require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php'; - - // Set tmp user directory TODO Use a dedicated directory for temp mails files - $vardir=$conf->user->dir_output."/".$user->id; - $upload_dir_tmp = $vardir.'/temp'; - - dol_add_file_process($upload_dir_tmp,0,0); - $action='presend'; -} - -/* - * Remove file in email form - */ -if (GETPOST('removedfile')) -{ - require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php'; - - // Set tmp user directory - $vardir=$conf->user->dir_output."/".$user->id; - $upload_dir_tmp = $vardir.'/temp'; - - // TODO Delete only files that was uploaded from email form - dol_remove_file_process($_POST['removedfile'],0); - $action='presend'; -} - -/* - * Send mail - */ -if ($action == 'send' && ! GETPOST('addfile') && ! GETPOST('removedfile') && ! GETPOST('cancel')) -{ - $langs->load('mails'); - - if ($object->id > 0) - { - if ($_POST['sendto']) - { - // Le destinataire a ete fourni via le champ libre - $sendto = $_POST['sendto']; - $sendtoid = 0; - } - elseif ($_POST['receiver'] != '-1') - { - // Recipient was provided from combo list - if ($_POST['receiver'] == 'thirdparty') // Id of third party - { - $sendto = $object->client->email; - $sendtoid = 0; - } - else // Id du contact - { - $sendto = $object->client->contact_get_property($_POST['receiver'],'email'); - $sendtoid = $_POST['receiver']; - } - } - - if (dol_strlen($sendto)) - { - $langs->load("commercial"); - - $from = $_POST['fromname'] . ' <' . $_POST['frommail'] .'>'; - $replyto = $_POST['replytoname']. ' <' . $_POST['replytomail'].'>'; - $message = $_POST['message']; - $sendtocc = $_POST['sendtocc']; - $deliveryreceipt = $_POST['deliveryreceipt']; - - if (dol_strlen($_POST['subject'])) $subject = $_POST['subject']; - else $subject = $langs->transnoentities('Propal').' '.$object->ref; - $actiontypecode='AC_PROP'; - $actionmsg = $langs->transnoentities('MailSentBy').' '.$from.' '.$langs->transnoentities('To').' '.$sendto.".\n"; - if ($message) - { - $actionmsg.=$langs->transnoentities('MailTopic').": ".$subject."\n"; - $actionmsg.=$langs->transnoentities('TextUsedInTheMessageBody').":\n"; - $actionmsg.=$message; - } - $actionmsg2=$langs->transnoentities('Action'.$actiontypecode); - - // Create form object - include_once DOL_DOCUMENT_ROOT.'/core/class/html.formmail.class.php'; - $formmail = new FormMail($db); - - $attachedfiles=$formmail->get_attached_files(); - $filepath = $attachedfiles['paths']; - $filename = $attachedfiles['names']; - $mimetype = $attachedfiles['mimes']; - - // Envoi de la propal - require_once DOL_DOCUMENT_ROOT.'/core/class/CMailFile.class.php'; - $mailfile = new CMailFile($subject,$sendto,$from,$message,$filepath,$mimetype,$filename,$sendtocc,'',$deliveryreceipt,-1); - if ($mailfile->error) - { - setEventMessage($mailfile->error, 'errors'); - } - else - { - $result=$mailfile->sendfile(); - if ($result) - { - // Initialisation donnees - $object->sendtoid = $sendtoid; - $object->actiontypecode = $actiontypecode; - $object->actionmsg = $actionmsg; - $object->actionmsg2 = $actionmsg2; - $object->fk_element = $object->id; - $object->elementtype = $object->element; - - // Appel des triggers - include_once DOL_DOCUMENT_ROOT . '/core/class/interfaces.class.php'; - $interface=new Interfaces($db); - $result=$interface->run_triggers('PROPAL_SENTBYMAIL',$object,$user,$langs,$conf); - if ($result < 0) { - $error++; $this->errors=$interface->errors; - } - // Fin appel triggers - - if (! $error) - { - // Redirect here - // This avoid sending mail twice if going out and then back to page - $mesg=$langs->trans('MailSuccessfulySent',$mailfile->getValidAddress($from,2),$mailfile->getValidAddress($sendto,2)); - setEventMessage($mesg); - header('Location: '.$_SERVER["PHP_SELF"].'?id='.$object->id); - exit; - } - else - { - dol_print_error($db); - } - } - else - { - $langs->load("other"); - if ($mailfile->error) - { - $mesg.=$langs->trans('ErrorFailedToSendMail',$from,$sendto); - $mesg.='
'.$mailfile->error; - } - else - { - $mesg.='No mail sent. Feature is disabled by option MAIN_DISABLE_ALL_MAILS'; - } - setEventMessage($mesg, 'errors'); - } - } - } - else - { - $langs->load("other"); - setEventMessage($langs->trans('ErrorMailRecipientIsEmpty').'!', 'errors'); - dol_syslog($langs->trans('ErrorMailRecipientIsEmpty')); - } - } - else - { - $langs->load("other"); - setEventMessage($langs->trans('ErrorFailedToReadEntity',$langs->trans("Proposal")), 'errors'); - dol_syslog($langs->trans('ErrorFailedToReadEntity',$langs->trans("Proposal"))); - } -} - -// Go back to draft -if ($action == 'modif' && $user->rights->propal->creer) -{ - $object->set_draft($user); - - if (empty($conf->global->MAIN_DISABLE_PDF_AUTOUPDATE)) - { - // Define output language - $outputlangs = $langs; - if (! empty($conf->global->MAIN_MULTILANGS)) - { - $outputlangs = new Translate("",$conf); - $newlang=(GETPOST('lang_id') ? GETPOST('lang_id') : $object->client->default_lang); - $outputlangs->setDefaultLang($newlang); - } - $ret=$object->fetch($id); // Reload to get new records - propale_pdf_create($db, $object, $object->modelpdf, $outputlangs, $hidedetails, $hidedesc, $hideref); - } -} - -else if ($action == "setabsolutediscount" && $user->rights->propal->creer) -{ - if ($_POST["remise_id"]) - { - if ($object->id > 0) - { - $result=$object->insert_discount($_POST["remise_id"]); - if ($result < 0) - { - setEventMessage($object->error, 'errors'); - } - } - } -} - -//Ajout d'une ligne produit dans la propale -else if ($action == "addline" && $user->rights->propal->creer) -{ - $idprod=GETPOST('idprod', 'int'); - $product_desc = (GETPOST('product_desc')?GETPOST('product_desc'):(GETPOST('np_desc')?GETPOST('np_desc'):(GETPOST('dp_desc')?GETPOST('dp_desc'):''))); - $price_ht = GETPOST('price_ht'); - $tva_tx = (GETPOST('tva_tx')?GETPOST('tva_tx'):0); - - if (empty($idprod) && GETPOST('type') < 0) - { - setEventMessage($langs->trans("ErrorFieldRequired",$langs->transnoentitiesnoconv("Type")), 'errors'); - $error++; - } - if ((empty($idprod) || GETPOST('usenewaddlineform')) && (!($price_ht != 0) || $price_ht == '')) // Unit price can be 0 but not ''. Also price can be negative for proposal. - { - setEventMessage($langs->trans("ErrorFieldRequired",$langs->transnoentitiesnoconv("UnitPriceHT")), 'errors'); - $error++; - } - if (empty($idprod) && empty($product_desc)) - { - setEventMessage($langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("Description")), 'errors'); - $error++; - } - - if (! $error && (GETPOST('qty') >= 0) && (! empty($product_desc) || ! empty($idprod))) - { - $pu_ht=0; - $pu_ttc=0; - $price_min=0; - $price_base_type = (GETPOST('price_base_type', 'alpha')?GETPOST('price_base_type', 'alpha'):'HT'); - - // Ecrase $pu par celui du produit - // Ecrase $desc par celui du produit - // Ecrase $txtva par celui du produit - if (! empty($idprod)) - { - $prod = new Product($db); - $prod->fetch($idprod); - - $label = ((GETPOST('product_label') && GETPOST('product_label')!=$prod->label)?GETPOST('product_label'):''); - - // If prices fields are update - if (GETPOST('usenewaddlineform')) - { - $pu_ht=price2num($price_ht, 'MU'); - $pu_ttc=price2num(GETPOST('price_ttc'), 'MU'); - $tva_npr=(preg_match('/\*/', $tva_tx)?1:0); - $tva_tx=str_replace('*','', $tva_tx); - $desc = $product_desc; - } - else - { - $tva_tx = get_default_tva($mysoc,$object->client,$prod->id); - $tva_npr = get_default_npr($mysoc,$object->client,$prod->id); - - // On defini prix unitaire - if (! empty($conf->global->PRODUIT_MULTIPRICES) && $object->client->price_level) - { - $pu_ht = $prod->multiprices[$object->client->price_level]; - $pu_ttc = $prod->multiprices_ttc[$object->client->price_level]; - $price_min = $prod->multiprices_min[$object->client->price_level]; - $price_base_type = $prod->multiprices_base_type[$object->client->price_level]; - } - else - { - $pu_ht = $prod->price; - $pu_ttc = $prod->price_ttc; - $price_min = $prod->price_min; - $price_base_type = $prod->price_base_type; - } - - // On reevalue prix selon taux tva car taux tva transaction peut etre different - // de ceux du produit par defaut (par exemple si pays different entre vendeur et acheteur). - if ($tva_tx != $prod->tva_tx) - { - if ($price_base_type != 'HT') - { - $pu_ht = price2num($pu_ttc / (1 + ($tva_tx/100)), 'MU'); - } - else - { - $pu_ttc = price2num($pu_ht * (1 + ($tva_tx/100)), 'MU'); - } - } - - $desc=''; - - // Define output language - if (! empty($conf->global->MAIN_MULTILANGS) && ! empty($conf->global->PRODUIT_TEXTS_IN_THIRDPARTY_LANGUAGE)) - { - $outputlangs = $langs; - $newlang=''; - if (empty($newlang) && GETPOST('lang_id')) $newlang=GETPOST('lang_id'); - if (empty($newlang)) $newlang=$object->client->default_lang; - if (! empty($newlang)) - { - $outputlangs = new Translate("",$conf); - $outputlangs->setDefaultLang($newlang); - } - - $desc = (! empty($prod->multilangs[$outputlangs->defaultlang]["description"])) ? $prod->multilangs[$outputlangs->defaultlang]["description"] : $prod->description; - } - else - { - $desc = $prod->description; - } - - $desc=dol_concatdesc($desc,$product_desc); - - // Add custom code and origin country into description - if (empty($conf->global->MAIN_PRODUCT_DISABLE_CUSTOMCOUNTRYCODE) && (! empty($prod->customcode) || ! empty($prod->country_code))) - { - $tmptxt='('; - if (! empty($prod->customcode)) $tmptxt.=$langs->transnoentitiesnoconv("CustomCode").': '.$prod->customcode; - if (! empty($prod->customcode) && ! empty($prod->country_code)) $tmptxt.=' - '; - if (! empty($prod->country_code)) $tmptxt.=$langs->transnoentitiesnoconv("CountryOrigin").': '.getCountry($prod->country_code,0,$db,$langs,0); - $tmptxt.=')'; - $desc= dol_concatdesc($desc, $tmptxt); - } - } - - $type = $prod->type; - } - else - { - $pu_ht = price2num($price_ht, 'MU'); - $pu_ttc = price2num(GETPOST('price_ttc'), 'MU'); - $tva_npr = (preg_match('/\*/', $tva_tx)?1:0); - $tva_tx = str_replace('*', '', $tva_tx); - $label = (GETPOST('product_label')?GETPOST('product_label'):''); - $desc = $product_desc; - $type = GETPOST('type'); - } - - // Margin - $fournprice=(GETPOST('fournprice')?GETPOST('fournprice'):''); - $buyingprice=(GETPOST('buying_price')?GETPOST('buying_price'):''); - - // Local Taxes - $localtax1_tx= get_localtax($tva_tx, 1, $object->client); - $localtax2_tx= get_localtax($tva_tx, 2, $object->client); - - $info_bits=0; - if ($tva_npr) $info_bits |= 0x01; - - if (! empty($price_min) && (price2num($pu_ht)*(1-price2num(GETPOST('remise_percent'))/100) < price2num($price_min))) - { - $mesg = $langs->trans("CantBeLessThanMinPrice",price2num($price_min,'MU').$langs->getCurrencySymbol($conf->currency)); - setEventMessage($mesg, 'errors'); - } - else - { - // Insert line - $result=$object->addline( - $id, - $desc, - $pu_ht, - GETPOST('qty'), - $tva_tx, - $localtax1_tx, - $localtax2_tx, - $idprod, - GETPOST('remise_percent'), - $price_base_type, - $pu_ttc, - $info_bits, - $type, - -1, - 0, - GETPOST('fk_parent_line'), - $fournprice, - $buyingprice, - $label - ); - - if ($result > 0) - { - if (empty($conf->global->MAIN_DISABLE_PDF_AUTOUPDATE)) - { - // Define output language - $outputlangs = $langs; - if (! empty($conf->global->MAIN_MULTILANGS)) - { - $outputlangs = new Translate("",$conf); - $newlang=(GETPOST('lang_id') ? GETPOST('lang_id') : $object->client->default_lang); - $outputlangs->setDefaultLang($newlang); - } - $ret=$object->fetch($id); // Reload to get new records - propale_pdf_create($db, $object, $object->modelpdf, $outputlangs, $hidedetails, $hidedesc, $hideref); - } - - unset($_POST['qty']); - unset($_POST['type']); - unset($_POST['idprod']); - unset($_POST['remise_percent']); - unset($_POST['price_ht']); - unset($_POST['price_ttc']); - unset($_POST['tva_tx']); - unset($_POST['product_ref']); - unset($_POST['product_label']); - unset($_POST['product_desc']); - unset($_POST['fournprice']); - unset($_POST['buying_price']); - - // old method - unset($_POST['np_desc']); - unset($_POST['dp_desc']); - } - else - { - setEventMessage($object->error, 'errors'); - } - } - } -} - -// Mise a jour d'une ligne dans la propale -else if ($action == 'updateligne' && $user->rights->propal->creer && GETPOST('save') == $langs->trans("Save")) -{ - // Define info_bits - $info_bits=0; - if (preg_match('/\*/', GETPOST('tva_tx'))) $info_bits |= 0x01; - - // Clean parameters - $description=dol_htmlcleanlastbr(GETPOST('product_desc')); - - // Define vat_rate - $vat_rate=(GETPOST('tva_tx')?GETPOST('tva_tx'):0); - $vat_rate=str_replace('*','',$vat_rate); - $localtax1_rate=get_localtax($vat_rate,1,$object->client); - $localtax2_rate=get_localtax($vat_rate,2,$object->client); - $pu_ht=GETPOST('price_ht'); - - // Add buying price - $fournprice=(GETPOST('fournprice')?GETPOST('fournprice'):''); - $buyingprice=(GETPOST('buying_price')?GETPOST('buying_price'):''); - - // Define special_code for special lines - $special_code=0; - if (! GETPOST('qty')) $special_code=3; - - // Check minimum price - $productid = GETPOST('productid', 'int'); - if (! empty($productid)) - { - $product = new Product($db); - $res=$product->fetch($productid); - - $type=$product->type; - - $price_min = $product->price_min; - if (! empty($conf->global->PRODUIT_MULTIPRICES) && ! empty($object->client->price_level)) - $price_min = $product->multiprices_min[$object->client->price_level]; - - $label = ((GETPOST('update_label') && GETPOST('product_label')) ? GETPOST('product_label'):''); - - if ($price_min && (price2num($pu_ht)*(1-price2num(GETPOST('remise_percent'))/100) < price2num($price_min))) - { - setEventMessage($langs->trans("CantBeLessThanMinPrice", price2num($price_min,'MU')).$langs->getCurrencySymbol($conf->currency), 'errors'); - $error++; - } - } - else - { - $type = GETPOST('type'); - $label = (GETPOST('product_label') ? GETPOST('product_label'):''); - - // Check parameters - if (GETPOST('type') < 0) { - setEventMessage($langs->trans("ErrorFieldRequired",$langs->transnoentitiesnoconv("Type")), 'errors'); - $error++; - } - } - - if (! $error) - { - $result = $object->updateline( - GETPOST('lineid'), - $pu_ht, - GETPOST('qty'), - GETPOST('remise_percent'), - $vat_rate, - $localtax1_rate, - $localtax2_rate, - $description, - 'HT', - $info_bits, - $special_code, - GETPOST('fk_parent_line'), - 0, - $fournprice, - $buyingprice, - $label, - $type - ); - - if ($result >= 0) - { - if (empty($conf->global->MAIN_DISABLE_PDF_AUTOUPDATE)) - { - // Define output language - $outputlangs = $langs; - if (! empty($conf->global->MAIN_MULTILANGS)) - { - $outputlangs = new Translate("",$conf); - $newlang=(GETPOST('lang_id') ? GETPOST('lang_id') : $object->client->default_lang); - $outputlangs->setDefaultLang($newlang); - } - $ret=$object->fetch($id); // Reload to get new records - propale_pdf_create($db, $object, $object->modelpdf, $outputlangs, $hidedetails, $hidedesc, $hideref); - } - - unset($_POST['qty']); - unset($_POST['type']); - unset($_POST['productid']); - unset($_POST['remise_percent']); - unset($_POST['price_ht']); - unset($_POST['price_ttc']); - unset($_POST['tva_tx']); - unset($_POST['product_ref']); - unset($_POST['product_label']); - unset($_POST['product_desc']); - unset($_POST['fournprice']); - unset($_POST['buying_price']); - } - else - { - setEventMessage($object->error, 'errors'); - } - } -} - -else if ($action == 'updateligne' && $user->rights->propal->creer && GETPOST('cancel') == $langs->trans('Cancel')) -{ - header('Location: '.$_SERVER['PHP_SELF'].'?id='.$object->id); // Pour reaffichage de la fiche en cours d'edition - exit; -} - -// Generation doc (depuis lien ou depuis cartouche doc) -else if ($action == 'builddoc' && $user->rights->propal->creer) -{ - if (GETPOST('model')) - { - $object->setDocModel($user, GETPOST('model')); - } - - // Define output language - $outputlangs = $langs; - if (! empty($conf->global->MAIN_MULTILANGS)) - { - $outputlangs = new Translate("",$conf); - $newlang=(GETPOST('lang_id') ? GETPOST('lang_id') : $object->client->default_lang); - $outputlangs->setDefaultLang($newlang); - } - $ret=$object->fetch($id); // Reload to get new records - $result=propale_pdf_create($db, $object, $object->modelpdf, $outputlangs, $hidedetails, $hidedesc, $hideref); - - if ($result <= 0) - { - dol_print_error($db,$result); - exit; - } - else - { - header('Location: '.$_SERVER["PHP_SELF"].'?id='.$object->id.(empty($conf->global->MAIN_JUMP_TAG)?'':'#builddoc')); - exit; - } -} - -// Remove file in doc form -else if ($action == 'remove_file' && $user->rights->propal->creer) -{ - if ($object->id > 0) - { - require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php'; - - $langs->load("other"); - $upload_dir = $conf->propal->dir_output; - $file = $upload_dir . '/' . GETPOST('file'); - $ret=dol_delete_file($file,0,0,0,$object); - if ($ret) setEventMessage($langs->trans("FileWasRemoved", GETPOST('file'))); - else setEventMessage($langs->trans("ErrorFailToDeleteFile", GETPOST('file')), 'errors'); - } -} - -// Set project -else if ($action == 'classin' && $user->rights->propal->creer) -{ - $object->setProject($_POST['projectid']); -} - -// Delai de livraison -else if ($action == 'setavailability' && $user->rights->propal->creer) -{ - $result = $object->availability($_POST['availability_id']); -} - -// Origine de la propale -else if ($action == 'setdemandreason' && $user->rights->propal->creer) -{ - $result = $object->demand_reason($_POST['demand_reason_id']); -} - -// Conditions de reglement -else if ($action == 'setconditions' && $user->rights->propal->creer) -{ - $result = $object->setPaymentTerms(GETPOST('cond_reglement_id','int')); -} - -else if ($action == 'setremisepercent' && $user->rights->propal->creer) -{ - $result = $object->set_remise_percent($user, $_POST['remise_percent']); -} - -else if ($action == 'setremiseabsolue' && $user->rights->propal->creer) -{ - $result = $object->set_remise_absolue($user, $_POST['remise_absolue']); -} - -// Mode de reglement -else if ($action == 'setmode' && $user->rights->propal->creer) -{ - $result = $object->setPaymentMethods(GETPOST('mode_reglement_id','int')); -} - -/* - * Ordonnancement des lignes - */ - -else if ($action == 'up' && $user->rights->propal->creer) -{ - $object->line_up(GETPOST('rowid')); - - if (empty($conf->global->MAIN_DISABLE_PDF_AUTOUPDATE)) - { - // Define output language - $outputlangs = $langs; - if (! empty($conf->global->MAIN_MULTILANGS)) - { - $outputlangs = new Translate("",$conf); - $newlang=(GETPOST('lang_id') ? GETPOST('lang_id') : $object->client->default_lang); - $outputlangs->setDefaultLang($newlang); - } - $ret=$object->fetch($id); // Reload to get new records - propale_pdf_create($db, $object, $object->modelpdf, $outputlangs, $hidedetails, $hidedesc, $hideref); - } - - header('Location: '.$_SERVER["PHP_SELF"].'?id='.$id.'#'.GETPOST('rowid')); - exit; -} - -else if ($action == 'down' && $user->rights->propal->creer) -{ - $object->line_down(GETPOST('rowid')); - - if (empty($conf->global->MAIN_DISABLE_PDF_AUTOUPDATE)) - { - // Define output language - $outputlangs = $langs; - if (! empty($conf->global->MAIN_MULTILANGS)) - { - $outputlangs = new Translate("",$conf); - $newlang=(GETPOST('lang_id') ? GETPOST('lang_id') : $object->client->default_lang); - $outputlangs->setDefaultLang($newlang); - } - $ret=$object->fetch($id); // Reload to get new records - propale_pdf_create($db, $object, $object->modelpdf, $outputlangs, $hidedetails, $hidedesc, $hideref); - } - - header('Location: '.$_SERVER["PHP_SELF"].'?id='.$id.'#'.GETPOST('rowid')); - exit; -} -else if ($action == 'update_extras') -{ - // Get extra fields - foreach($_POST as $key => $value) - { - if (preg_match("/^options_/",$key)) - { - $object->array_options[$key]=$_POST[$key]; - } - } - // Actions on extra fields (by external module or standard code) - // FIXME 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 modified by some hooks - if (empty($reshook)) - { - if (empty($conf->global->MAIN_EXTRAFIELDS_DISABLED)) // For avoid conflicts if trigger used - { - $result=$object->insertExtraFields(); - if ($result < 0) - { - $error++; - } - } - } - else if ($reshook < 0) $error++; - -} - -if (! empty($conf->global->MAIN_DISABLE_CONTACTS_TAB) && $user->rights->propal->creer) -{ - if ($action == 'addcontact') - { - if ($object->id > 0) - { - $contactid = (GETPOST('userid') ? GETPOST('userid') : GETPOST('contactid')); - $result = $object->add_contact($contactid, $_POST["type"], $_POST["source"]); - } - - if ($result >= 0) - { - header("Location: ".$_SERVER['PHP_SELF']."?id=".$object->id); - exit; - } - else - { - if ($object->error == 'DB_ERROR_RECORD_ALREADY_EXISTS') - { - $langs->load("errors"); - setEventMessage($langs->trans("ErrorThisContactIsAlreadyDefinedAsThisType"), 'errors'); - } - else - { - setEventMessage($object->error, 'errors'); - } - } - } - - // Bascule du statut d'un contact - else if ($action == 'swapstatut') - { - if ($object->fetch($id) > 0) - { - $result=$object->swapContactStatus(GETPOST('ligne')); - } - else - { - dol_print_error($db); - } - } - - // Efface un contact - else if ($action == 'deletecontact') - { - $object->fetch($id); - $result = $object->delete_contact($lineid); - - if ($result >= 0) - { - header("Location: ".$_SERVER['PHP_SELF']."?id=".$object->id); - exit; - } - else - { - dol_print_error($db); - } - } -} - - -/* - * View - */ - -llxHeader('',$langs->trans('Proposal'),'EN:Commercial_Proposals|FR:Proposition_commerciale|ES:Presupuestos'); - -$form = new Form($db); -$formother = new FormOther($db); -$formfile = new FormFile($db); -$formpropal = new FormPropal($db); -$companystatic=new Societe($db); - -// fetch optionals attributes and labels -$extralabels=$extrafields->fetch_name_optionals_label('propal'); - -$now=dol_now(); - -// Add new proposal -if ($action == 'create') -{ - print_fiche_titre($langs->trans("NewProp")); - - $soc = new Societe($db); - if ($socid>0) $res=$soc->fetch($socid); - - $object = new Propal($db); - - print ''; - print ''; - print ''; - - if ($origin != 'project' && $originid) - { - print ''; - print ''; - } - - print ''; - - // Reference - print ''; - - // Ref customer - print ''; - print ''; - - // Third party - print ''; - print ''; - if($socid>0) - { - print ''; - } - else - { - print ''; - } - print ''."\n"; - - // Contacts - if($socid>0) - { - print "'; - - // Ligne info remises tiers - print ''; - } - - // Date - print ''; - - // Validaty duration - print ''; - - // Terms of payment - print ''; - - // Mode of payment - print ''; - - // What trigger creation - print ''; - - // Delivery delay - print ''; - - // Delivery date (or manufacturing) - print ''; - print ''; - - // Model - print ''; - print ''; - print '"; - - // Project - if (! empty($conf->projet->enabled) && $socid>0) - { - $projectid = 0; - if ($origin == 'project') $projectid = ($originid?$originid:0); - - print ''; - print ''; - print ''; - } - - // Other attributes - $parameters=array('colspan' => ' colspan="3"'); - $reshook=$hookmanager->executeHooks('formObjectOptions',$parameters,$object,$action); // Note that $action and $object may have been modified by hook - if (empty($reshook) && ! empty($extrafields->attribute_label)) - { - foreach($extrafields->attribute_label as $key=>$label) - { - $value=(isset($_POST["options_".$key])?$_POST["options_".$key]:$object->array_options["options_".$key]); - - // Show separator only - if ($extrafields->attribute_type[$key] == 'separate') - { - print $extrafields->showSeparator($key); - } - else - { - print 'attribute_required[$key])) print ' class="fieldrequired"'; - print '>'.$label.''."\n"; - } - } - } - - print "
'.$langs->trans('Ref').''.$langs->trans("Draft").'
'.$langs->trans('RefCustomer').''; - print '
'.$langs->trans('Customer').''; - print $soc->getNomUrl(1); - print ''; - print ''; - print $form->select_company('','socid','s.client = 1 OR s.client = 2 OR s.client = 3',1); - print '
".$langs->trans("DefaultContact").''; - $form->select_contacts($soc->id,$setcontact,'contactidp',1,$srccontactslist); - print '
'.$langs->trans('Discounts').''; - if ($soc->remise_client) print $langs->trans("CompanyHasRelativeDiscount",$soc->remise_client); - else print $langs->trans("CompanyHasNoRelativeDiscount"); - $absolute_discount=$soc->getAvailableDiscounts(); - print '. '; - if ($absolute_discount) print $langs->trans("CompanyHasAbsoluteDiscount",price($absolute_discount),$langs->trans("Currency".$conf->currency)); - else print $langs->trans("CompanyHasNoAbsoluteDiscount"); - print '.'; - print '
'.$langs->trans('Date').''; - $form->select_date('','','','','',"addprop"); - print '
'.$langs->trans("ValidityDuration").' '.$langs->trans("days").'
'.$langs->trans('PaymentConditionsShort').''; - $form->select_conditions_paiements($soc->cond_reglement,'cond_reglement_id'); - print '
'.$langs->trans('PaymentMode').''; - $form->select_types_paiements($soc->mode_reglement,'mode_reglement_id'); - print '
'.$langs->trans('Source').''; - $form->select_demand_reason('','demand_reason_id',"SRC_PROP",1); - print '
'.$langs->trans('AvailabilityPeriod').''; - $form->select_availability('','availability_id','',1); - print '
'.$langs->trans("DeliveryDate").''; - if ($conf->global->DATE_LIVRAISON_WEEK_DELAY != "") - { - $tmpdte = time() + ((7 * $conf->global->DATE_LIVRAISON_WEEK_DELAY) * 24 * 60 * 60); - $syear = date("Y", $tmpdte); - $smonth = date("m", $tmpdte); - $sday = date("d", $tmpdte); - $form->select_date($syear."-".$smonth."-".$sday,'liv_','','','',"addprop"); - } - else - { - $datepropal=empty($conf->global->MAIN_AUTOFILL_DATE)?-1:0; - $form->select_date($datepropal,'liv_','','','',"addprop"); - } - print '
'.$langs->trans("DefaultModel").''; - $liste=ModelePDFPropales::liste_modeles($db); - print $form->selectarray('model',$liste,$conf->global->PROPALE_ADDON_PDF); - print "
'.$langs->trans("Project").''; - - $numprojet=select_projects($soc->id,$projectid); - if ($numprojet==0) - { - print '   '.$langs->trans("AddProject").''; - } - print '
'; - print $extrafields->showInputField($key,$value); - print '
"; - print '
'; - - /* - * Combobox pour la fonction de copie - */ - - if (empty($conf->global->PROPAL_CLONE_ON_CREATE_PAGE)) - { - print ''; - } - - print ''; - if (! empty($conf->global->PROPAL_CLONE_ON_CREATE_PAGE)) - { - // For backward compatibility - print ''; - print ''; - print ''; - print ''; - - if (! empty($conf->global->PRODUCT_SHOW_WHEN_CREATE)) print ''; - - print ''; - print ''; - } - - if (! empty($conf->global->PRODUCT_SHOW_WHEN_CREATE)) - { - print ''; - } - print '
'.$langs->trans("CopyPropalFrom").' '; - $liste_propal = array(); - $liste_propal[0] = ''; - - $sql ="SELECT p.rowid as id, p.ref, s.nom"; - $sql.=" FROM ".MAIN_DB_PREFIX."propal p"; - $sql.= ", ".MAIN_DB_PREFIX."societe s"; - $sql.= " WHERE s.rowid = p.fk_soc"; - $sql.= " AND p.entity = ".$conf->entity; - $sql.= " AND p.fk_statut <> 0"; - $sql.= " ORDER BY Id"; - - $resql = $db->query($sql); - if ($resql) - { - $num = $db->num_rows($resql); - $i = 0; - while ($i < $num) - { - $row = $db->fetch_row($resql); - $propalRefAndSocName = $row[1]." - ".$row[2]; - $liste_propal[$row[0]]=$propalRefAndSocName; - $i++; - } - print $form->selectarray("copie_propal",$liste_propal, 0); - } - else - { - dol_print_error($db); - } - print '
 
'.$langs->trans("CreateEmptyPropal").'
'; - if (! empty($conf->product->enabled) || ! empty($conf->service->enabled)) - { - $lib=$langs->trans("ProductsAndServices"); - - print ''; - print ''; - print ''; - print ''; - print ''; - print ''; - for ($i = 1 ; $i <= $conf->global->PRODUCT_SHOW_WHEN_CREATE; $i++) - { - print ''; - print ''; - print ''; - print ''; - } - - print "
'.$lib.''.$langs->trans("Qty").''.$langs->trans("ReductionShort").'
'; - // multiprix - if($conf->global->PRODUIT_MULTIPRICES && $soc->price_level) - $form->select_produits('',"idprod".$i,'',$conf->product->limit_size,$soc->price_level); - else - $form->select_produits('',"idprod".$i,'',$conf->product->limit_size); - print '%
"; - - } - print '
'; - print '
'; - - $langs->load("bills"); - print '
'; - print ''; - print ' '; - print '
'; - - print ""; -} -else -{ - /* - * Show object in view mode - */ - - $soc = new Societe($db); - $soc->fetch($object->socid); - - $head = propal_prepare_head($object); - dol_fiche_head($head, 'comm', $langs->trans('Proposal'), 0, 'propal'); - - $formconfirm=''; - - // Clone confirmation - if ($action == 'clone') - { - // Create an array for form - $formquestion=array( - //'text' => $langs->trans("ConfirmClone"), - //array('type' => 'checkbox', 'name' => 'clone_content', 'label' => $langs->trans("CloneMainAttributes"), 'value' => 1), - //array('type' => 'checkbox', 'name' => 'update_prices', 'label' => $langs->trans("PuttingPricesUpToDate"), 'value' => 1), - array('type' => 'other', 'name' => 'socid', 'label' => $langs->trans("SelectThirdParty"), 'value' => $form->select_company(GETPOST('socid','int'),'socid','(s.client=1 OR s.client=2 OR s.client=3)')) - ); - // Paiement incomplet. On demande si motif = escompte ou autre - $formconfirm=$form->formconfirm($_SERVER["PHP_SELF"].'?id='.$object->id,$langs->trans('ClonePropal'),$langs->trans('ConfirmClonePropal',$object->ref),'confirm_clone',$formquestion,'yes',1); - } - - // Confirm delete - else if ($action == 'delete') - { - $formconfirm=$form->formconfirm($_SERVER["PHP_SELF"].'?id='.$object->id, $langs->trans('DeleteProp'), $langs->trans('ConfirmDeleteProp',$object->ref), 'confirm_delete','',0,1); - } - - // Confirm reopen - else if ($action == 'reopen') - { - $formconfirm=$form->formconfirm($_SERVER["PHP_SELF"].'?id='.$object->id, $langs->trans('ReOpen'), $langs->trans('ConfirmReOpenProp',$object->ref), 'confirm_reopen','',0,1); - } - - // Confirmation delete product/service line - else if ($action == 'ask_deleteline') - { - $formconfirm=$form->formconfirm($_SERVER["PHP_SELF"].'?id='.$object->id.'&lineid='.$lineid, $langs->trans('DeleteProductLine'), $langs->trans('ConfirmDeleteProductLine'), 'confirm_deleteline','',0,1); - } - - // Confirm validate proposal - else if ($action == 'validate') - { - $error=0; - - // on verifie si l'objet est en numerotation provisoire - $ref = substr($object->ref, 1, 4); - if ($ref == 'PROV') - { - $numref = $object->getNextNumRef($soc); - if (empty($numref)) - { - $error++; - dol_htmloutput_errors($object->error); - } - } - else - { - $numref = $object->ref; - } - - $text=$langs->trans('ConfirmValidateProp',$numref); - if (! empty($conf->notification->enabled)) - { - require_once DOL_DOCUMENT_ROOT .'/core/class/notify.class.php'; - $notify=new Notify($db); - $text.='
'; - $text.=$notify->confirmMessage('NOTIFY_VAL_PROPAL',$object->socid); - } - - if (! $error) $formconfirm=$form->formconfirm($_SERVER["PHP_SELF"].'?id='.$object->id, $langs->trans('ValidateProp'), $text, 'confirm_validate','',0,1); - } - - if (! $formconfirm) - { - $parameters=array('lineid'=>$lineid); - $formconfirm=$hookmanager->executeHooks('formConfirm',$parameters,$object,$action); // Note that $action and $object may have been modified by hook - } - - // Print form confirm - print $formconfirm; - - - print ''; - - $linkback = ''.$langs->trans("BackToList").''; - - // Ref - print ''; - - // Ref client - print ''; - print ''; - - // Company - print ''; - print ''; - - // Ligne info remises tiers - print ''; - - // Date of proposal - print ''; - print ''; - - // Date end proposal - print ''; - print ''; - print ''; - - // Payment term - print ''; - print ''; - - // Delivery date - $langs->load('deliveries'); - print ''; - print ''; - - // Delivery delay - print ''; - print ''; - - // Origin of demand - print ''; - print ''; - - // Payment mode - print ''; - print ''; - - // Project - if (! empty($conf->projet->enabled)) - { - $langs->load("projects"); - print ''; - } - else - { - print '
'.$langs->trans('Ref').''; - print $form->showrefnav($object, 'ref', $linkback, 1, 'ref', 'ref', ''); - print '
'; - print ''; - if ($action != 'refclient' && ! empty($object->brouillon)) print ''; - print '
'; - print $langs->trans('RefCustomer').''; - print ''.img_edit($langs->trans('Modify')).'
'; - print '
'; - if ($user->rights->propal->creer && $action == 'refclient') - { - print '
'; - print ''; - print ''; - print ''; - print ' '; - print '
'; - } - else - { - print $object->ref_client; - } - print '
'.$langs->trans('Company').''.$soc->getNomUrl(1).'
'.$langs->trans('Discounts').''; - if ($soc->remise_client) print $langs->trans("CompanyHasRelativeDiscount",$soc->remise_client); - else print $langs->trans("CompanyHasNoRelativeDiscount"); - print '. '; - $absolute_discount=$soc->getAvailableDiscounts('','fk_facture_source IS NULL'); - $absolute_creditnote=$soc->getAvailableDiscounts('','fk_facture_source IS NOT NULL'); - $absolute_discount=price2num($absolute_discount,'MT'); - $absolute_creditnote=price2num($absolute_creditnote,'MT'); - if ($absolute_discount) - { - if ($object->statut > 0) - { - print $langs->trans("CompanyHasAbsoluteDiscount",price($absolute_discount),$langs->transnoentities("Currency".$conf->currency)); - } - else - { - // Remise dispo de type non avoir - $filter='fk_facture_source IS NULL'; - print '
'; - $form->form_remise_dispo($_SERVER["PHP_SELF"].'?id='.$object->id,0,'remise_id',$soc->id,$absolute_discount,$filter); - } - } - if ($absolute_creditnote) - { - print $langs->trans("CompanyHasCreditNote",price($absolute_creditnote),$langs->transnoentities("Currency".$conf->currency)).'. '; - } - if (! $absolute_discount && ! $absolute_creditnote) print $langs->trans("CompanyHasNoAbsoluteDiscount").'.'; - print '
'; - print ''; - if ($action != 'editdate' && ! empty($object->brouillon)) print ''; - print '
'; - print $langs->trans('Date'); - print 'id.'">'.img_edit($langs->trans('SetDate'),1).'
'; - print '
'; - if (! empty($object->brouillon) && $action == 'editdate') - { - print '
'; - print ''; - print ''; - $form->select_date($object->date,'re','','',0,"editdate"); - print ''; - print '
'; - } - else - { - if ($object->date) - { - print dol_print_date($object->date,'daytext'); - } - else - { - print ' '; - } - } - print '
'; - print ''; - if ($action != 'editecheance' && ! empty($object->brouillon)) print ''; - print '
'; - print $langs->trans('DateEndPropal'); - print 'id.'">'.img_edit($langs->trans('SetConditions'),1).'
'; - print '
'; - if (! empty($object->brouillon) && $action == 'editecheance') - { - print '
'; - print ''; - print ''; - $form->select_date($object->fin_validite,'ech','','','',"editecheance"); - print ''; - print '
'; - } - 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)) print img_warning($langs->trans("Late")); - } - else - { - print ' '; - } - } - print '
'; - print ''; - if ($action != 'editconditions' && ! empty($object->brouillon)) print ''; - print '
'; - print $langs->trans('PaymentConditionsShort'); - print 'id.'">'.img_edit($langs->transnoentitiesnoconv('SetConditions'),1).'
'; - print '
'; - if ($action == 'editconditions') - { - $form->form_conditions_reglement($_SERVER['PHP_SELF'].'?id='.$object->id,$object->cond_reglement_id,'cond_reglement_id'); - } - else - { - $form->form_conditions_reglement($_SERVER['PHP_SELF'].'?id='.$object->id,$object->cond_reglement_id,'none'); - } - print '
'; - print ''; - if ($action != 'editdate_livraison' && ! empty($object->brouillon)) print ''; - print '
'; - print $langs->trans('DeliveryDate'); - print 'id.'">'.img_edit($langs->transnoentitiesnoconv('SetDeliveryDate'),1).'
'; - print '
'; - if ($action == 'editdate_livraison') - { - print '
'; - print ''; - print ''; - $form->select_date($object->date_livraison,'liv_','','','',"editdate_livraison"); - print ''; - print '
'; - } - else - { - print dol_print_date($object->date_livraison,'daytext'); - } - print '
'; - print ''; - if ($action != 'editavailability' && ! empty($object->brouillon)) print ''; - print '
'; - print $langs->trans('AvailabilityPeriod'); - if (! empty($conf->commande->enabled)) print ' ('.$langs->trans('AfterOrder').')'; - print 'id.'">'.img_edit($langs->transnoentitiesnoconv('SetAvailability'),1).'
'; - print '
'; - if ($action == 'editavailability') - { - $form->form_availability($_SERVER['PHP_SELF'].'?id='.$object->id,$object->availability_id,'availability_id',1); - } - else - { - $form->form_availability($_SERVER['PHP_SELF'].'?id='.$object->id,$object->availability_id,'none',1); - } - - print '
'; - print ''; - if ($action != 'editdemandreason' && ! empty($object->brouillon)) print ''; - print '
'; - print $langs->trans('Source'); - print 'id.'">'.img_edit($langs->transnoentitiesnoconv('SetDemandReason'),1).'
'; - print '
'; - //print $object->demand_reason_id; - if ($action == 'editdemandreason') - { - $form->form_demand_reason($_SERVER['PHP_SELF'].'?id='.$object->id,$object->demand_reason_id,'demand_reason_id',1); - } - else - { - $form->form_demand_reason($_SERVER['PHP_SELF'].'?id='.$object->id,$object->demand_reason_id,'none'); - } - - print '
'; - print ''; - if ($action != 'editmode' && ! empty($object->brouillon)) print ''; - print '
'; - print $langs->trans('PaymentMode'); - print 'id.'">'.img_edit($langs->transnoentitiesnoconv('SetMode'),1).'
'; - print '
'; - if ($action == 'editmode') - { - $form->form_modes_reglement($_SERVER['PHP_SELF'].'?id='.$object->id,$object->mode_reglement_id,'mode_reglement_id'); - } - else - { - $form->form_modes_reglement($_SERVER['PHP_SELF'].'?id='.$object->id,$object->mode_reglement_id,'none'); - } - print '
'; - print ''; - if ($user->rights->propal->creer) - { - if ($action != 'classify') print ''; - print '
'; - print $langs->trans('Project').''.img_edit($langs->transnoentitiesnoconv('SetProject')).'
'; - print '
'; - if ($action == 'classify') - { - $form->form_project($_SERVER['PHP_SELF'].'?id='.$object->id, $object->socid, $object->fk_project, 'projectid'); - } - else - { - $form->form_project($_SERVER['PHP_SELF'].'?id='.$object->id, $object->socid, $object->fk_project, 'none'); - } - print '
'; - if (! empty($object->fk_project)) - { - print ''; - $proj = new Project($db); - $proj->fetch($object->fk_project); - print ''; - print $proj->ref; - print ''; - print ''; - } - else { - print ' '; - } - } - print ''; - } - - // Other attributes - $res=$object->fetch_optionals($object->id,$extralabels); - $parameters=array('colspan' => ' colspan="3"'); - $reshook=$hookmanager->executeHooks('formObjectOptions',$parameters,$object,$action); // Note that $action and $object may have been modified by hook - if (empty($reshook) && ! empty($extrafields->attribute_label)) - { - - if ($action == 'edit_extras') - { - print '
'; - print ''; - print ''; - print ''; - } - - - foreach($extrafields->attribute_label as $key=>$label) - { - $value=(isset($_POST["options_".$key])?$_POST["options_".$key]:$object->array_options["options_".$key]); - if ($extrafields->attribute_type[$key] == 'separate') - { - print $extrafields->showSeparator($key); - } - else - { - print 'attribute_required[$key])) print ' class="fieldrequired"'; - print '>'.$label.''; - if ($action == 'edit_extras' && $user->rights->propal->creer) - { - print $extrafields->showInputField($key,$value); - } - else - { - print $extrafields->showOutputField($key,$value); - } - print ''."\n"; - } - } - - if(count($extrafields->attribute_label) > 0) { - - if ($action == 'edit_extras' && $user->rights->propal->creer) - { - print ''; - print ''; - print ''; - print ''; - - } - else { - if ($object->statut == 0 && $user->rights->propal->creer) - { - print ''.img_picto('','edit').' '.$langs->trans('Modify').''; - } - } - } - } - - // Amount HT - print ''.$langs->trans('AmountHT').''; - print ''.price($object->total_ht).''; - print ''.$langs->trans("Currency".$conf->currency).''; - - // Margin Infos - if (! empty($conf->margin->enabled)) { - print ''; - $object->displayMarginInfos(); - print ''; - } - print ''; - - // Amount VAT - print ''.$langs->trans('AmountVAT').''; - print ''.price($object->total_tva).''; - print ''.$langs->trans("Currency".$conf->currency).''; - - // Amount Local Taxes - if ($mysoc->localtax1_assuj=="1") //Localtax1 - { - print ''.$langs->transcountry("AmountLT1",$mysoc->country_code).''; - print ''.price($object->total_localtax1).''; - print ''.$langs->trans("Currency".$conf->currency).''; - } - if ($mysoc->localtax2_assuj=="1") //Localtax2 - { - print ''.$langs->transcountry("AmountLT2",$mysoc->country_code).''; - print ''.price($object->total_localtax2).''; - print ''.$langs->trans("Currency".$conf->currency).''; - } - - - // Amount TTC - print ''.$langs->trans('AmountTTC').''; - print ''.price($object->total_ttc).''; - print ''.$langs->trans("Currency".$conf->currency).''; - - // Statut - print ''.$langs->trans('Status').''.$object->getLibStatut(4).''; - - print '
'; - - if (! empty($conf->global->MAIN_DISABLE_CONTACTS_TAB)) - { - $blocname = 'contacts'; - $title = $langs->trans('ContactsAddresses'); - include DOL_DOCUMENT_ROOT.'/core/tpl/bloc_showhide.tpl.php'; - } - - if (! empty($conf->global->MAIN_DISABLE_NOTES_TAB)) - { - $blocname = 'notes'; - $title = $langs->trans('Notes'); - include DOL_DOCUMENT_ROOT.'/core/tpl/bloc_showhide.tpl.php'; - } - - /* - * Lines - */ - - if (! empty($conf->use_javascript_ajax) && $object->statut == 0) - { - include DOL_DOCUMENT_ROOT.'/core/tpl/ajaxrow.tpl.php'; - } - - print ''; - - // Show object lines - $result = $object->getLinesArray(); - if (! empty($object->lines)) - $ret=$object->printObjectLines($action,$mysoc,$soc,$lineid); - - // Form to add new line - if ($object->statut == 0 && $user->rights->propal->creer) - { - if ($action != 'editline') - { - $var=true; - - if ($conf->global->MAIN_FEATURES_LEVEL > 1) - { - // Add free or predefined products/services - $object->formAddObjectLine(0,$mysoc,$soc); - } - else - { - // Add free products/services - $object->formAddFreeProduct(0,$mysoc,$soc); - - // Add predefined products/services - if (! empty($conf->product->enabled) || ! empty($conf->service->enabled)) - { - $var=!$var; - $object->formAddPredefinedProduct(0,$mysoc,$soc); - } - } - - $parameters=array(); - $reshook=$hookmanager->executeHooks('formAddObjectLine',$parameters,$object,$action); // Note that $action and $object may have been modified by hook - } - } - - print '
'; - - print ''; - print "\n"; - - if ($action == 'statut') - { - /* - * Formulaire cloture (signe ou non) - */ - $form_close = '
'; - $form_close.= ''; - $form_close.= ''; - $form_close.= ''; - $form_close.= ''; - $form_close.= ''; - $form_close.= '
'.$langs->trans("CloseAs").''; - $form_close.= ''; - $form_close.= ''; - $form_close.= '
'.$langs->trans('Note').'
'; - $form_close.= ''; - $form_close.= '   '; - $form_close.= ' '; - $form_close.= '
'; - - print $form_close; - } - - - /* - * Boutons Actions - */ - if ($action != 'presend') - { - print '
'; - - if ($action != 'statut' && $action <> 'editline') - { - // Validate - if ($object->statut == 0 && $object->total_ttc >= 0 && count($object->lines) > 0 && $user->rights->propal->valider) - { - if (count($object->lines) > 0) print ''.$langs->trans('Validate').''; - //else print ''.$langs->trans('Validate').''; - } - - // Edit - if ($object->statut == 1 && $user->rights->propal->creer) - { - print ''.$langs->trans('Modify').''; - } - - // ReOpen - if (($object->statut == 2 || $object->statut == 3) && $user->rights->propal->cloturer) - { - print 'global->MAIN_JUMP_TAG)?'':'#reopen').'"'; - print '>'.$langs->trans('ReOpen').''; - } - - // Send - if ($object->statut == 1 || $object->statut == 2) - { - if (empty($conf->global->MAIN_USE_ADVANCED_PERMS) || $user->rights->propal->propal_advance->send) - { - print ''.$langs->trans('SendByMail').''; - } - else print ''.$langs->trans('SendByMail').''; - } - - // Create an order - if (! empty($conf->commande->enabled) && $object->statut == 2 && $user->societe_id == 0) - { - if ($user->rights->commande->creer) - { - print ''.$langs->trans("AddOrder").''; - } - } - - // Create contract - if ($conf->contrat->enabled && $object->statut == 2 && $user->societe_id == 0) - { - $langs->load("contracts"); - - if ($user->rights->contrat->creer) - { - print ''.$langs->trans('AddContract').''; - } - } - - // Create an invoice and classify billed - if ($object->statut == 2 && $user->societe_id == 0) - { - if (! empty($conf->facture->enabled) && $user->rights->facture->creer) - { - print ''.$langs->trans("AddBill").''; - } - - $arraypropal=$object->getInvoiceArrayList(); - if (is_array($arraypropal) && count($arraypropal) > 0) - { - print 'socid.'">'.$langs->trans("ClassifyBilled").''; - } - } - - // Close - if ($object->statut == 1 && $user->rights->propal->cloturer) - { - print 'global->MAIN_JUMP_TAG)?'':'#close').'"'; - print '>'.$langs->trans('Close').''; - } - - // Clone - if ($user->rights->propal->creer) - { - print ''.$langs->trans("ToClone").''; - } - - // Delete - if ($user->rights->propal->supprimer) - { - print ''.$langs->trans('Delete').''; - } - - } - - print '
'; - print "
\n"; - } - - if ($action != 'presend') - { - print '
'; - print ''; // ancre - - - /* - * Documents generes - */ - $filename=dol_sanitizeFileName($object->ref); - $filedir=$conf->propal->dir_output . "/" . dol_sanitizeFileName($object->ref); - $urlsource=$_SERVER["PHP_SELF"]."?id=".$object->id; - $genallowed=$user->rights->propal->creer; - $delallowed=$user->rights->propal->supprimer; - - $var=true; - - $somethingshown=$formfile->show_documents('propal',$filename,$filedir,$urlsource,$genallowed,$delallowed,$object->modelpdf,1,0,0,28,0,'',0,'',$soc->default_lang); - - - /* - * Linked object block - */ - $somethingshown=$object->showLinkedObjectBlock(); - - print ''; - - // List of actions on element - include_once DOL_DOCUMENT_ROOT.'/core/class/html.formactions.class.php'; - $formactions=new FormActions($db); - $somethingshown=$formactions->showactions($object,'propal',$socid); - - print '
'; - } - - - /* - * Action presend - * - */ - if ($action == 'presend') - { - $ref = dol_sanitizeFileName($object->ref); - include_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php'; - $fileparams = dol_most_recent_file($conf->propal->dir_output . '/' . $ref, preg_quote($object->ref,'/')); - $file=$fileparams['fullname']; - - // Build document if it not exists - if (! $file || ! is_readable($file)) - { - // Define output language - $outputlangs = $langs; - $newlang=''; - if ($conf->global->MAIN_MULTILANGS && empty($newlang) && ! empty($_REQUEST['lang_id'])) $newlang=$_REQUEST['lang_id']; - if ($conf->global->MAIN_MULTILANGS && empty($newlang)) $newlang=$object->client->default_lang; - if (! empty($newlang)) - { - $outputlangs = new Translate("",$conf); - $outputlangs->setDefaultLang($newlang); - } - - $result=propale_pdf_create($db, $object, GETPOST('model')?GETPOST('model'):$object->modelpdf, $outputlangs, $hidedetails, $hidedesc, $hideref); - if ($result <= 0) - { - dol_print_error($db,$result); - exit; - } - $fileparams = dol_most_recent_file($conf->propal->dir_output . '/' . $ref, preg_quote($object->ref,'/')); - $file=$fileparams['fullname']; - } - - print '
'; - print_titre($langs->trans('SendPropalByMail')); - - // Create form object - include_once DOL_DOCUMENT_ROOT.'/core/class/html.formmail.class.php'; - $formmail = new FormMail($db); - $formmail->fromtype = 'user'; - $formmail->fromid = $user->id; - $formmail->fromname = $user->getFullName($langs); - $formmail->frommail = $user->email; - $formmail->withfrom=1; - $liste=array(); - foreach ($object->thirdparty->thirdparty_and_contact_email_array(1) as $key=>$value) $liste[$key]=$value; - $formmail->withto=GETPOST("sendto")?GETPOST("sendto"):$liste; - $formmail->withtocc=$liste; - $formmail->withtoccc=(! empty($conf->global->MAIN_EMAIL_USECCC)?$conf->global->MAIN_EMAIL_USECCC:false); - $formmail->withtopic=$langs->trans('SendPropalRef','__PROPREF__'); - $formmail->withfile=2; - $formmail->withbody=1; - $formmail->withdeliveryreceipt=1; - $formmail->withcancel=1; - - // Tableau des substitutions - $formmail->substit['__PROPREF__']=$object->ref; - $formmail->substit['__SIGNATURE__']=$user->signature; - $formmail->substit['__PERSONALIZED__']=''; - $formmail->substit['__CONTACTCIVNAME__']=''; - + + * Copyright (C) 2004-2013 Laurent Destailleur + * Copyright (C) 2004 Eric Seigne + * 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-2011 Philippe Grand + * Copyright (C) 2012 Christophe Battarel +* + * 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/comm/propal.php + * \ingroup propale + * \brief Page of commercial proposals card and list + */ + +require '../main.inc.php'; +require_once DOL_DOCUMENT_ROOT.'/core/class/html.formother.class.php'; +require_once DOL_DOCUMENT_ROOT.'/core/class/html.formfile.class.php'; +require_once DOL_DOCUMENT_ROOT.'/core/class/html.formpropal.class.php'; +require_once DOL_DOCUMENT_ROOT.'/comm/propal/class/propal.class.php'; +require_once DOL_DOCUMENT_ROOT.'/comm/action/class/actioncomm.class.php'; +require_once DOL_DOCUMENT_ROOT.'/core/modules/propale/modules_propale.php'; +require_once DOL_DOCUMENT_ROOT.'/core/lib/propal.lib.php'; +require_once DOL_DOCUMENT_ROOT.'/core/lib/functions2.lib.php'; +require_once DOL_DOCUMENT_ROOT.'/core/class/extrafields.class.php'; +if (! empty($conf->projet->enabled)) +{ + require_once DOL_DOCUMENT_ROOT.'/projet/class/project.class.php'; + require_once DOL_DOCUMENT_ROOT.'/core/lib/project.lib.php'; +} + +$langs->load('companies'); +$langs->load('propal'); +$langs->load('compta'); +$langs->load('bills'); +$langs->load('orders'); +$langs->load('products'); +$langs->load("deliveries"); +if (! empty($conf->margin->enabled)) + $langs->load('margins'); + +$error=0; + +$id=GETPOST('id','int'); +$ref=GETPOST('ref','alpha'); +$socid=GETPOST('socid','int'); +$action=GETPOST('action','alpha'); +$origin=GETPOST('origin','alpha'); +$originid=GETPOST('originid','int'); +$confirm=GETPOST('confirm','alpha'); +$lineid=GETPOST('lineid','int'); + +//PDF +$hidedetails = (GETPOST('hidedetails','int') ? GETPOST('hidedetails','int') : (! empty($conf->global->MAIN_GENERATE_DOCUMENTS_HIDE_DETAILS) ? 1 : 0)); +$hidedesc = (GETPOST('hidedesc','int') ? GETPOST('hidedesc','int') : (! empty($conf->global->MAIN_GENERATE_DOCUMENTS_HIDE_DESC) ? 1 : 0)); +$hideref = (GETPOST('hideref','int') ? GETPOST('hideref','int') : (! empty($conf->global->MAIN_GENERATE_DOCUMENTS_HIDE_REF) ? 1 : 0)); + +// Nombre de ligne pour choix de produit/service predefinis +$NBLINES=4; + +// Security check +if (! empty($user->societe_id)) $socid=$user->societe_id; +$result = restrictedArea($user, 'propal', $id); + +$object = new Propal($db); +$extrafields = new ExtraFields($db); + +// Load object +if ($id > 0 || ! empty($ref)) +{ + $ret=$object->fetch($id, $ref); + if ($ret > 0) $ret=$object->fetch_thirdparty(); + if ($ret < 0) dol_print_error('',$object->error); +} + +// Initialize technical object to manage hooks of thirdparties. Note that conf->hooks_modules contains array array +$hookmanager->initHooks(array('propalcard')); + + + +/* + * Actions + */ + +$parameters=array('socid'=>$socid); +$reshook=$hookmanager->executeHooks('doActions',$parameters,$object,$action); // Note that $action and $object may have been modified by some hooks + +// Action clone object +if ($action == 'confirm_clone' && $confirm == 'yes') +{ + if (1==0 && ! GETPOST('clone_content') && ! GETPOST('clone_receivers')) + { + setEventMessage($langs->trans("NoCloneOptionsSpecified"), 'errors'); + } + else + { + if ($object->id > 0) + { + $result=$object->createFromClone($socid); + if ($result > 0) + { + header("Location: ".$_SERVER['PHP_SELF'].'?id='.$result); + exit; + } + else + { + setEventMessage($object->error, 'errors'); + $action=''; + } + } + } +} + +// Suppression de la propale +else if ($action == 'confirm_delete' && $confirm == 'yes' && $user->rights->propal->supprimer) +{ + $result=$object->delete($user); + if ($result > 0) + { + header('Location: '.DOL_URL_ROOT.'/comm/propal/list.php'); + exit; + } + else + { + $langs->load("errors"); + setEventMessage($langs->trans($object->error), 'errors'); + } +} + +// Remove line +else if ($action == 'confirm_deleteline' && $confirm == 'yes' && $user->rights->propal->creer) +{ + $result = $object->deleteline($lineid); + // reorder lines + if ($result) $object->line_order(true); + + if (empty($conf->global->MAIN_DISABLE_PDF_AUTOUPDATE)) + { + // Define output language + $outputlangs = $langs; + if (! empty($conf->global->MAIN_MULTILANGS)) + { + $outputlangs = new Translate("",$conf); + $newlang=(GETPOST('lang_id') ? GETPOST('lang_id') : $object->client->default_lang); + $outputlangs->setDefaultLang($newlang); + } + $ret=$object->fetch($id); // Reload to get new records + propale_pdf_create($db, $object, $object->modelpdf, $outputlangs, $hidedetails, $hidedesc, $hideref); + } + + header('Location: '.$_SERVER["PHP_SELF"].'?id='.$object->id); + exit; +} + +// Validation +else if ($action == 'confirm_validate' && $confirm == 'yes' && $user->rights->propal->valider) +{ + $result=$object->valid($user); + if ($result >= 0) + { + if (empty($conf->global->MAIN_DISABLE_PDF_AUTOUPDATE)) + { + // Define output language + $outputlangs = $langs; + if (! empty($conf->global->MAIN_MULTILANGS)) + { + $outputlangs = new Translate("",$conf); + $newlang=(GETPOST('lang_id') ? GETPOST('lang_id') : $object->client->default_lang); + $outputlangs->setDefaultLang($newlang); + } + $ret=$object->fetch($id); // Reload to get new records + propale_pdf_create($db, $object, $object->modelpdf, $outputlangs, $hidedetails, $hidedesc, $hideref); + } + } + else + { + $langs->load("errors"); + setEventMessage($langs->trans($object->error), 'errors'); + } +} + +else if ($action == 'setdate' && $user->rights->propal->creer) +{ + $datep=dol_mktime(12, 0, 0, $_POST['remonth'], $_POST['reday'], $_POST['reyear']); + + if (empty($datep)) + { + $error++; + setEventMessage($langs->trans("ErrorFieldRequired",$langs->transnoentitiesnoconv("Date")), 'errors'); + } + + if (! $error) + { + $result=$object->set_date($user,$datep); + if ($result < 0) dol_print_error($db,$object->error); + } +} +else if ($action == 'setecheance' && $user->rights->propal->creer) +{ + $result=$object->set_echeance($user,dol_mktime(12, 0, 0, $_POST['echmonth'], $_POST['echday'], $_POST['echyear'])); + if ($result < 0) dol_print_error($db,$object->error); +} +else if ($action == 'setdate_livraison' && $user->rights->propal->creer) +{ + $result=$object->set_date_livraison($user,dol_mktime(12, 0, 0, $_POST['liv_month'], $_POST['liv_day'], $_POST['liv_year'])); + if ($result < 0) dol_print_error($db,$object->error); +} + +// Positionne ref client +else if ($action == 'set_ref_client' && $user->rights->propal->creer) +{ + $object->set_ref_client($user, $_POST['ref_client']); +} + +else if ($action == 'setnote_public' && $user->rights->propal->creer) +{ + $result=$object->update_note_public(dol_html_entity_decode(GETPOST('note_public'), ENT_QUOTES)); + if ($result < 0) dol_print_error($db,$object->error); +} + +else if ($action == 'setnote' && $user->rights->propal->creer) +{ + $result=$object->update_note(dol_html_entity_decode(GETPOST('note'), ENT_QUOTES)); + if ($result < 0) dol_print_error($db,$object->error); +} + +// Create proposal +else if ($action == 'add' && $user->rights->propal->creer) +{ + $object->socid=$socid; + $object->fetch_thirdparty(); + + $datep=dol_mktime(12, 0, 0, GETPOST('remonth'), GETPOST('reday'), GETPOST('reyear')); + $date_delivery=dol_mktime(12, 0, 0, GETPOST('liv_month'), GETPOST('liv_day'), GETPOST('liv_year')); + $duration=GETPOST('duree_validite'); + + if (empty($datep)) + { + setEventMessage($langs->trans("ErrorFieldRequired",$langs->transnoentitiesnoconv("Date")), 'errors'); + $action='create'; + $error++; + } + if (empty($duration)) + { + setEventMessage($langs->trans("ErrorFieldRequired",$langs->transnoentitiesnoconv("ValidityDuration")), 'errors'); + $action='create'; + $error++; + } + + if ($socid<1) + { + setEventMessage($langs->trans("ErrorFieldRequired",$langs->transnoentitiesnoconv("Customer")),'errors'); + $action='create'; + $error++; + } + + if (! $error) + { + $db->begin(); + + // Si on a selectionne une propal a copier, on realise la copie + if (GETPOST('createmode')=='copy' && GETPOST('copie_propal')) + { + if ($object->fetch(GETPOST('copie_propal')) > 0) + { + $object->ref = GETPOST('ref'); + $object->datep = $datep; + $object->date_livraison = $date_delivery; + $object->availability_id = GETPOST('availability_id'); + $object->demand_reason_id = GETPOST('demand_reason_id'); + $object->fk_delivery_address = GETPOST('fk_address'); + $object->duree_validite = $duration; + $object->cond_reglement_id = GETPOST('cond_reglement_id'); + $object->mode_reglement_id = GETPOST('mode_reglement_id'); + $object->remise_percent = GETPOST('remise_percent'); + $object->remise_absolue = GETPOST('remise_absolue'); + $object->socid = GETPOST('socid'); + $object->contactid = GETPOST('contactidp'); + $object->fk_project = GETPOST('projectid'); + $object->modelpdf = GETPOST('model'); + $object->author = $user->id; // deprecated + $object->note = GETPOST('note'); + $object->statut = 0; + + $id = $object->create_from($user); + } + else + { + setEventMessage($langs->trans("ErrorFailedToCopyProposal",GETPOST('copie_propal')), 'errors'); + } + } + else + { + $object->ref = GETPOST('ref'); + $object->ref_client = GETPOST('ref_client'); + $object->datep = $datep; + $object->date_livraison = $date_delivery; + $object->availability_id = GETPOST('availability_id'); + $object->demand_reason_id = GETPOST('demand_reason_id'); + $object->fk_delivery_address = GETPOST('fk_address'); + $object->duree_validite = GETPOST('duree_validite'); + $object->cond_reglement_id = GETPOST('cond_reglement_id'); + $object->mode_reglement_id = GETPOST('mode_reglement_id'); + + $object->contactid = GETPOST('contactidp'); + $object->fk_project = GETPOST('projectid'); + $object->modelpdf = GETPOST('model'); + $object->author = $user->id; // deprecated + $object->note = GETPOST('note'); + + $object->origin = GETPOST('origin'); + $object->origin_id = GETPOST('originid'); + + for ($i = 1 ; $i <= $conf->global->PRODUCT_SHOW_WHEN_CREATE; $i++) + { + if ($_POST['idprod'.$i]) + { + $xid = 'idprod'.$i; + $xqty = 'qty'.$i; + $xremise = 'remise'.$i; + $object->add_product($_POST[$xid],$_POST[$xqty],$_POST[$xremise]); + } + } + + // Get extra fields + foreach($_POST as $key => $value) + { + if (preg_match("/^options_/",$key)) + { + $object->array_options[$key]=GETPOST($key); + } + } + + $id = $object->create($user); + } + + if ($id > 0) + { + // Insertion contact par defaut si defini + if (GETPOST('contactidp')) + { + $result=$object->add_contact(GETPOST('contactidp'),'CUSTOMER','external'); + if ($result < 0) + { + $error++; + setEventMessage($langs->trans("ErrorFailedToAddContact"), 'errors'); + } + } + + if (! $error) + { + $db->commit(); + + if (empty($conf->global->MAIN_DISABLE_PDF_AUTOUPDATE)) + { + // Define output language + $outputlangs = $langs; + if (! empty($conf->global->MAIN_MULTILANGS)) + { + $outputlangs = new Translate("",$conf); + $newlang=(GETPOST('lang_id') ? GETPOST('lang_id') : $object->client->default_lang); + $outputlangs->setDefaultLang($newlang); + } + $ret=$object->fetch($id); // Reload to get new records + propale_pdf_create($db, $object, $object->modelpdf, $outputlangs, $hidedetails, $hidedesc, $hideref); + } + + header('Location: '.$_SERVER["PHP_SELF"].'?id='.$id); + exit; + } + else + { + $db->rollback(); + } + } + else + { + dol_print_error($db,$object->error); + $db->rollback(); + exit; + } + } +} + +// Classify billed +else if ($action == 'classifybilled' && $user->rights->propal->cloturer) +{ + $object->cloture($user, 4, ''); +} + +// Reopen proposal +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->setStatut(1); + } +} + +// Close proposal +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')); + } + } +} + +/* + * Add file in email form + */ +if (GETPOST('addfile')) +{ + require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php'; + + // Set tmp user directory TODO Use a dedicated directory for temp mails files + $vardir=$conf->user->dir_output."/".$user->id; + $upload_dir_tmp = $vardir.'/temp'; + + dol_add_file_process($upload_dir_tmp,0,0); + $action='presend'; +} + +/* + * Remove file in email form + */ +if (GETPOST('removedfile')) +{ + require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php'; + + // Set tmp user directory + $vardir=$conf->user->dir_output."/".$user->id; + $upload_dir_tmp = $vardir.'/temp'; + + // TODO Delete only files that was uploaded from email form + dol_remove_file_process($_POST['removedfile'],0); + $action='presend'; +} + +/* + * Send mail + */ +if ($action == 'send' && ! GETPOST('addfile') && ! GETPOST('removedfile') && ! GETPOST('cancel')) +{ + $langs->load('mails'); + + if ($object->id > 0) + { + if ($_POST['sendto']) + { + // Le destinataire a ete fourni via le champ libre + $sendto = $_POST['sendto']; + $sendtoid = 0; + } + elseif ($_POST['receiver'] != '-1') + { + // Recipient was provided from combo list + if ($_POST['receiver'] == 'thirdparty') // Id of third party + { + $sendto = $object->client->email; + $sendtoid = 0; + } + else // Id du contact + { + $sendto = $object->client->contact_get_property($_POST['receiver'],'email'); + $sendtoid = $_POST['receiver']; + } + } + + if (dol_strlen($sendto)) + { + $langs->load("commercial"); + + $from = $_POST['fromname'] . ' <' . $_POST['frommail'] .'>'; + $replyto = $_POST['replytoname']. ' <' . $_POST['replytomail'].'>'; + $message = $_POST['message']; + $sendtocc = $_POST['sendtocc']; + $deliveryreceipt = $_POST['deliveryreceipt']; + + if (dol_strlen($_POST['subject'])) $subject = $_POST['subject']; + else $subject = $langs->transnoentities('Propal').' '.$object->ref; + $actiontypecode='AC_PROP'; + $actionmsg = $langs->transnoentities('MailSentBy').' '.$from.' '.$langs->transnoentities('To').' '.$sendto.".\n"; + if ($message) + { + $actionmsg.=$langs->transnoentities('MailTopic').": ".$subject."\n"; + $actionmsg.=$langs->transnoentities('TextUsedInTheMessageBody').":\n"; + $actionmsg.=$message; + } + $actionmsg2=$langs->transnoentities('Action'.$actiontypecode); + + // Create form object + include_once DOL_DOCUMENT_ROOT.'/core/class/html.formmail.class.php'; + $formmail = new FormMail($db); + + $attachedfiles=$formmail->get_attached_files(); + $filepath = $attachedfiles['paths']; + $filename = $attachedfiles['names']; + $mimetype = $attachedfiles['mimes']; + + // Envoi de la propal + require_once DOL_DOCUMENT_ROOT.'/core/class/CMailFile.class.php'; + $mailfile = new CMailFile($subject,$sendto,$from,$message,$filepath,$mimetype,$filename,$sendtocc,'',$deliveryreceipt,-1); + if ($mailfile->error) + { + setEventMessage($mailfile->error, 'errors'); + } + else + { + $result=$mailfile->sendfile(); + if ($result) + { + // Initialisation donnees + $object->sendtoid = $sendtoid; + $object->actiontypecode = $actiontypecode; + $object->actionmsg = $actionmsg; + $object->actionmsg2 = $actionmsg2; + $object->fk_element = $object->id; + $object->elementtype = $object->element; + + // Appel des triggers + include_once DOL_DOCUMENT_ROOT . '/core/class/interfaces.class.php'; + $interface=new Interfaces($db); + $result=$interface->run_triggers('PROPAL_SENTBYMAIL',$object,$user,$langs,$conf); + if ($result < 0) { + $error++; $this->errors=$interface->errors; + } + // Fin appel triggers + + if (! $error) + { + // Redirect here + // This avoid sending mail twice if going out and then back to page + $mesg=$langs->trans('MailSuccessfulySent',$mailfile->getValidAddress($from,2),$mailfile->getValidAddress($sendto,2)); + setEventMessage($mesg); + header('Location: '.$_SERVER["PHP_SELF"].'?id='.$object->id); + exit; + } + else + { + dol_print_error($db); + } + } + else + { + $langs->load("other"); + if ($mailfile->error) + { + $mesg.=$langs->trans('ErrorFailedToSendMail',$from,$sendto); + $mesg.='
'.$mailfile->error; + } + else + { + $mesg.='No mail sent. Feature is disabled by option MAIN_DISABLE_ALL_MAILS'; + } + setEventMessage($mesg, 'errors'); + } + } + } + else + { + $langs->load("other"); + setEventMessage($langs->trans('ErrorMailRecipientIsEmpty').'!', 'errors'); + dol_syslog($langs->trans('ErrorMailRecipientIsEmpty')); + } + } + else + { + $langs->load("other"); + setEventMessage($langs->trans('ErrorFailedToReadEntity',$langs->trans("Proposal")), 'errors'); + dol_syslog($langs->trans('ErrorFailedToReadEntity',$langs->trans("Proposal"))); + } +} + +// Go back to draft +if ($action == 'modif' && $user->rights->propal->creer) +{ + $object->set_draft($user); + + if (empty($conf->global->MAIN_DISABLE_PDF_AUTOUPDATE)) + { + // Define output language + $outputlangs = $langs; + if (! empty($conf->global->MAIN_MULTILANGS)) + { + $outputlangs = new Translate("",$conf); + $newlang=(GETPOST('lang_id') ? GETPOST('lang_id') : $object->client->default_lang); + $outputlangs->setDefaultLang($newlang); + } + $ret=$object->fetch($id); // Reload to get new records + propale_pdf_create($db, $object, $object->modelpdf, $outputlangs, $hidedetails, $hidedesc, $hideref); + } +} + +else if ($action == "setabsolutediscount" && $user->rights->propal->creer) +{ + if ($_POST["remise_id"]) + { + if ($object->id > 0) + { + $result=$object->insert_discount($_POST["remise_id"]); + if ($result < 0) + { + setEventMessage($object->error, 'errors'); + } + } + } +} + +//Ajout d'une ligne produit dans la propale +else if ($action == "addline" && $user->rights->propal->creer) +{ + $idprod=GETPOST('idprod', 'int'); + $product_desc = (GETPOST('product_desc')?GETPOST('product_desc'):(GETPOST('np_desc')?GETPOST('np_desc'):(GETPOST('dp_desc')?GETPOST('dp_desc'):''))); + $price_ht = GETPOST('price_ht'); + $tva_tx = (GETPOST('tva_tx')?GETPOST('tva_tx'):0); + + if (empty($idprod) && GETPOST('type') < 0) + { + setEventMessage($langs->trans("ErrorFieldRequired",$langs->transnoentitiesnoconv("Type")), 'errors'); + $error++; + } + if ((empty($idprod) || GETPOST('usenewaddlineform')) && (!($price_ht != 0) || $price_ht == '')) // Unit price can be 0 but not ''. Also price can be negative for proposal. + { + setEventMessage($langs->trans("ErrorFieldRequired",$langs->transnoentitiesnoconv("UnitPriceHT")), 'errors'); + $error++; + } + if (empty($idprod) && empty($product_desc)) + { + setEventMessage($langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("Description")), 'errors'); + $error++; + } + + if (! $error && (GETPOST('qty') >= 0) && (! empty($product_desc) || ! empty($idprod))) + { + $pu_ht=0; + $pu_ttc=0; + $price_min=0; + $price_base_type = (GETPOST('price_base_type', 'alpha')?GETPOST('price_base_type', 'alpha'):'HT'); + + // Ecrase $pu par celui du produit + // Ecrase $desc par celui du produit + // Ecrase $txtva par celui du produit + if (! empty($idprod)) + { + $prod = new Product($db); + $prod->fetch($idprod); + + $label = ((GETPOST('product_label') && GETPOST('product_label')!=$prod->label)?GETPOST('product_label'):''); + + // If prices fields are update + if (GETPOST('usenewaddlineform')) + { + $pu_ht=price2num($price_ht, 'MU'); + $pu_ttc=price2num(GETPOST('price_ttc'), 'MU'); + $tva_npr=(preg_match('/\*/', $tva_tx)?1:0); + $tva_tx=str_replace('*','', $tva_tx); + $desc = $product_desc; + } + else + { + $tva_tx = get_default_tva($mysoc,$object->client,$prod->id); + $tva_npr = get_default_npr($mysoc,$object->client,$prod->id); + + // On defini prix unitaire + if (! empty($conf->global->PRODUIT_MULTIPRICES) && $object->client->price_level) + { + $pu_ht = $prod->multiprices[$object->client->price_level]; + $pu_ttc = $prod->multiprices_ttc[$object->client->price_level]; + $price_min = $prod->multiprices_min[$object->client->price_level]; + $price_base_type = $prod->multiprices_base_type[$object->client->price_level]; + } + else + { + $pu_ht = $prod->price; + $pu_ttc = $prod->price_ttc; + $price_min = $prod->price_min; + $price_base_type = $prod->price_base_type; + } + + // On reevalue prix selon taux tva car taux tva transaction peut etre different + // de ceux du produit par defaut (par exemple si pays different entre vendeur et acheteur). + if ($tva_tx != $prod->tva_tx) + { + if ($price_base_type != 'HT') + { + $pu_ht = price2num($pu_ttc / (1 + ($tva_tx/100)), 'MU'); + } + else + { + $pu_ttc = price2num($pu_ht * (1 + ($tva_tx/100)), 'MU'); + } + } + + $desc=''; + + // Define output language + if (! empty($conf->global->MAIN_MULTILANGS) && ! empty($conf->global->PRODUIT_TEXTS_IN_THIRDPARTY_LANGUAGE)) + { + $outputlangs = $langs; + $newlang=''; + if (empty($newlang) && GETPOST('lang_id')) $newlang=GETPOST('lang_id'); + if (empty($newlang)) $newlang=$object->client->default_lang; + if (! empty($newlang)) + { + $outputlangs = new Translate("",$conf); + $outputlangs->setDefaultLang($newlang); + } + + $desc = (! empty($prod->multilangs[$outputlangs->defaultlang]["description"])) ? $prod->multilangs[$outputlangs->defaultlang]["description"] : $prod->description; + } + else + { + $desc = $prod->description; + } + + $desc=dol_concatdesc($desc,$product_desc); + + // Add custom code and origin country into description + if (empty($conf->global->MAIN_PRODUCT_DISABLE_CUSTOMCOUNTRYCODE) && (! empty($prod->customcode) || ! empty($prod->country_code))) + { + $tmptxt='('; + if (! empty($prod->customcode)) $tmptxt.=$langs->transnoentitiesnoconv("CustomCode").': '.$prod->customcode; + if (! empty($prod->customcode) && ! empty($prod->country_code)) $tmptxt.=' - '; + if (! empty($prod->country_code)) $tmptxt.=$langs->transnoentitiesnoconv("CountryOrigin").': '.getCountry($prod->country_code,0,$db,$langs,0); + $tmptxt.=')'; + $desc= dol_concatdesc($desc, $tmptxt); + } + } + + $type = $prod->type; + } + else + { + $pu_ht = price2num($price_ht, 'MU'); + $pu_ttc = price2num(GETPOST('price_ttc'), 'MU'); + $tva_npr = (preg_match('/\*/', $tva_tx)?1:0); + $tva_tx = str_replace('*', '', $tva_tx); + $label = (GETPOST('product_label')?GETPOST('product_label'):''); + $desc = $product_desc; + $type = GETPOST('type'); + } + + // Margin + $fournprice=(GETPOST('fournprice')?GETPOST('fournprice'):''); + $buyingprice=(GETPOST('buying_price')?GETPOST('buying_price'):''); + + // Local Taxes + $localtax1_tx= get_localtax($tva_tx, 1, $object->client); + $localtax2_tx= get_localtax($tva_tx, 2, $object->client); + + $info_bits=0; + if ($tva_npr) $info_bits |= 0x01; + + if (! empty($price_min) && (price2num($pu_ht)*(1-price2num(GETPOST('remise_percent'))/100) < price2num($price_min))) + { + $mesg = $langs->trans("CantBeLessThanMinPrice",price2num($price_min,'MU').$langs->getCurrencySymbol($conf->currency)); + setEventMessage($mesg, 'errors'); + } + else + { + // Insert line + $result=$object->addline( + $id, + $desc, + $pu_ht, + GETPOST('qty'), + $tva_tx, + $localtax1_tx, + $localtax2_tx, + $idprod, + GETPOST('remise_percent'), + $price_base_type, + $pu_ttc, + $info_bits, + $type, + -1, + 0, + GETPOST('fk_parent_line'), + $fournprice, + $buyingprice, + $label + ); + + if ($result > 0) + { + if (empty($conf->global->MAIN_DISABLE_PDF_AUTOUPDATE)) + { + // Define output language + $outputlangs = $langs; + if (! empty($conf->global->MAIN_MULTILANGS)) + { + $outputlangs = new Translate("",$conf); + $newlang=(GETPOST('lang_id') ? GETPOST('lang_id') : $object->client->default_lang); + $outputlangs->setDefaultLang($newlang); + } + $ret=$object->fetch($id); // Reload to get new records + propale_pdf_create($db, $object, $object->modelpdf, $outputlangs, $hidedetails, $hidedesc, $hideref); + } + + unset($_POST['qty']); + unset($_POST['type']); + unset($_POST['idprod']); + unset($_POST['remise_percent']); + unset($_POST['price_ht']); + unset($_POST['price_ttc']); + unset($_POST['tva_tx']); + unset($_POST['product_ref']); + unset($_POST['product_label']); + unset($_POST['product_desc']); + unset($_POST['fournprice']); + unset($_POST['buying_price']); + + // old method + unset($_POST['np_desc']); + unset($_POST['dp_desc']); + } + else + { + setEventMessage($object->error, 'errors'); + } + } + } +} + +// Mise a jour d'une ligne dans la propale +else if ($action == 'updateligne' && $user->rights->propal->creer && GETPOST('save') == $langs->trans("Save")) +{ + // Define info_bits + $info_bits=0; + if (preg_match('/\*/', GETPOST('tva_tx'))) $info_bits |= 0x01; + + // Clean parameters + $description=dol_htmlcleanlastbr(GETPOST('product_desc')); + + // Define vat_rate + $vat_rate=(GETPOST('tva_tx')?GETPOST('tva_tx'):0); + $vat_rate=str_replace('*','',$vat_rate); + $localtax1_rate=get_localtax($vat_rate,1,$object->client); + $localtax2_rate=get_localtax($vat_rate,2,$object->client); + $pu_ht=GETPOST('price_ht'); + + // Add buying price + $fournprice=(GETPOST('fournprice')?GETPOST('fournprice'):''); + $buyingprice=(GETPOST('buying_price')?GETPOST('buying_price'):''); + + // Define special_code for special lines + $special_code=0; + if (! GETPOST('qty')) $special_code=3; + + // Check minimum price + $productid = GETPOST('productid', 'int'); + if (! empty($productid)) + { + $product = new Product($db); + $res=$product->fetch($productid); + + $type=$product->type; + + $price_min = $product->price_min; + if (! empty($conf->global->PRODUIT_MULTIPRICES) && ! empty($object->client->price_level)) + $price_min = $product->multiprices_min[$object->client->price_level]; + + $label = ((GETPOST('update_label') && GETPOST('product_label')) ? GETPOST('product_label'):''); + + if ($price_min && (price2num($pu_ht)*(1-price2num(GETPOST('remise_percent'))/100) < price2num($price_min))) + { + setEventMessage($langs->trans("CantBeLessThanMinPrice", price2num($price_min,'MU')).$langs->getCurrencySymbol($conf->currency), 'errors'); + $error++; + } + } + else + { + $type = GETPOST('type'); + $label = (GETPOST('product_label') ? GETPOST('product_label'):''); + + // Check parameters + if (GETPOST('type') < 0) { + setEventMessage($langs->trans("ErrorFieldRequired",$langs->transnoentitiesnoconv("Type")), 'errors'); + $error++; + } + } + + if (! $error) + { + $result = $object->updateline( + GETPOST('lineid'), + $pu_ht, + GETPOST('qty'), + GETPOST('remise_percent'), + $vat_rate, + $localtax1_rate, + $localtax2_rate, + $description, + 'HT', + $info_bits, + $special_code, + GETPOST('fk_parent_line'), + 0, + $fournprice, + $buyingprice, + $label, + $type + ); + + if ($result >= 0) + { + if (empty($conf->global->MAIN_DISABLE_PDF_AUTOUPDATE)) + { + // Define output language + $outputlangs = $langs; + if (! empty($conf->global->MAIN_MULTILANGS)) + { + $outputlangs = new Translate("",$conf); + $newlang=(GETPOST('lang_id') ? GETPOST('lang_id') : $object->client->default_lang); + $outputlangs->setDefaultLang($newlang); + } + $ret=$object->fetch($id); // Reload to get new records + propale_pdf_create($db, $object, $object->modelpdf, $outputlangs, $hidedetails, $hidedesc, $hideref); + } + + unset($_POST['qty']); + unset($_POST['type']); + unset($_POST['productid']); + unset($_POST['remise_percent']); + unset($_POST['price_ht']); + unset($_POST['price_ttc']); + unset($_POST['tva_tx']); + unset($_POST['product_ref']); + unset($_POST['product_label']); + unset($_POST['product_desc']); + unset($_POST['fournprice']); + unset($_POST['buying_price']); + } + else + { + setEventMessage($object->error, 'errors'); + } + } +} + +else if ($action == 'updateligne' && $user->rights->propal->creer && GETPOST('cancel') == $langs->trans('Cancel')) +{ + header('Location: '.$_SERVER['PHP_SELF'].'?id='.$object->id); // Pour reaffichage de la fiche en cours d'edition + exit; +} + +// Generation doc (depuis lien ou depuis cartouche doc) +else if ($action == 'builddoc' && $user->rights->propal->creer) +{ + if (GETPOST('model')) + { + $object->setDocModel($user, GETPOST('model')); + } + + // Define output language + $outputlangs = $langs; + if (! empty($conf->global->MAIN_MULTILANGS)) + { + $outputlangs = new Translate("",$conf); + $newlang=(GETPOST('lang_id') ? GETPOST('lang_id') : $object->client->default_lang); + $outputlangs->setDefaultLang($newlang); + } + $ret=$object->fetch($id); // Reload to get new records + $result=propale_pdf_create($db, $object, $object->modelpdf, $outputlangs, $hidedetails, $hidedesc, $hideref); + + if ($result <= 0) + { + dol_print_error($db,$result); + exit; + } + else + { + header('Location: '.$_SERVER["PHP_SELF"].'?id='.$object->id.(empty($conf->global->MAIN_JUMP_TAG)?'':'#builddoc')); + exit; + } +} + +// Remove file in doc form +else if ($action == 'remove_file' && $user->rights->propal->creer) +{ + if ($object->id > 0) + { + require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php'; + + $langs->load("other"); + $upload_dir = $conf->propal->dir_output; + $file = $upload_dir . '/' . GETPOST('file'); + $ret=dol_delete_file($file,0,0,0,$object); + if ($ret) setEventMessage($langs->trans("FileWasRemoved", GETPOST('file'))); + else setEventMessage($langs->trans("ErrorFailToDeleteFile", GETPOST('file')), 'errors'); + } +} + +// Set project +else if ($action == 'classin' && $user->rights->propal->creer) +{ + $object->setProject($_POST['projectid']); +} + +// Delai de livraison +else if ($action == 'setavailability' && $user->rights->propal->creer) +{ + $result = $object->availability($_POST['availability_id']); +} + +// Origine de la propale +else if ($action == 'setdemandreason' && $user->rights->propal->creer) +{ + $result = $object->demand_reason($_POST['demand_reason_id']); +} + +// Conditions de reglement +else if ($action == 'setconditions' && $user->rights->propal->creer) +{ + $result = $object->setPaymentTerms(GETPOST('cond_reglement_id','int')); +} + +else if ($action == 'setremisepercent' && $user->rights->propal->creer) +{ + $result = $object->set_remise_percent($user, $_POST['remise_percent']); +} + +else if ($action == 'setremiseabsolue' && $user->rights->propal->creer) +{ + $result = $object->set_remise_absolue($user, $_POST['remise_absolue']); +} + +// Mode de reglement +else if ($action == 'setmode' && $user->rights->propal->creer) +{ + $result = $object->setPaymentMethods(GETPOST('mode_reglement_id','int')); +} + +/* + * Ordonnancement des lignes + */ + +else if ($action == 'up' && $user->rights->propal->creer) +{ + $object->line_up(GETPOST('rowid')); + + if (empty($conf->global->MAIN_DISABLE_PDF_AUTOUPDATE)) + { + // Define output language + $outputlangs = $langs; + if (! empty($conf->global->MAIN_MULTILANGS)) + { + $outputlangs = new Translate("",$conf); + $newlang=(GETPOST('lang_id') ? GETPOST('lang_id') : $object->client->default_lang); + $outputlangs->setDefaultLang($newlang); + } + $ret=$object->fetch($id); // Reload to get new records + propale_pdf_create($db, $object, $object->modelpdf, $outputlangs, $hidedetails, $hidedesc, $hideref); + } + + header('Location: '.$_SERVER["PHP_SELF"].'?id='.$id.'#'.GETPOST('rowid')); + exit; +} + +else if ($action == 'down' && $user->rights->propal->creer) +{ + $object->line_down(GETPOST('rowid')); + + if (empty($conf->global->MAIN_DISABLE_PDF_AUTOUPDATE)) + { + // Define output language + $outputlangs = $langs; + if (! empty($conf->global->MAIN_MULTILANGS)) + { + $outputlangs = new Translate("",$conf); + $newlang=(GETPOST('lang_id') ? GETPOST('lang_id') : $object->client->default_lang); + $outputlangs->setDefaultLang($newlang); + } + $ret=$object->fetch($id); // Reload to get new records + propale_pdf_create($db, $object, $object->modelpdf, $outputlangs, $hidedetails, $hidedesc, $hideref); + } + + header('Location: '.$_SERVER["PHP_SELF"].'?id='.$id.'#'.GETPOST('rowid')); + exit; +} +else if ($action == 'update_extras') +{ + // Get extra fields + foreach($_POST as $key => $value) + { + if (preg_match("/^options_/",$key)) + { + $object->array_options[$key]=$_POST[$key]; + } + } + // Actions on extra fields (by external module or standard code) + // FIXME 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 modified by some hooks + if (empty($reshook)) + { + if (empty($conf->global->MAIN_EXTRAFIELDS_DISABLED)) // For avoid conflicts if trigger used + { + $result=$object->insertExtraFields(); + if ($result < 0) + { + $error++; + } + } + } + else if ($reshook < 0) $error++; + +} + +if (! empty($conf->global->MAIN_DISABLE_CONTACTS_TAB) && $user->rights->propal->creer) +{ + if ($action == 'addcontact') + { + if ($object->id > 0) + { + $contactid = (GETPOST('userid') ? GETPOST('userid') : GETPOST('contactid')); + $result = $object->add_contact($contactid, $_POST["type"], $_POST["source"]); + } + + if ($result >= 0) + { + header("Location: ".$_SERVER['PHP_SELF']."?id=".$object->id); + exit; + } + else + { + if ($object->error == 'DB_ERROR_RECORD_ALREADY_EXISTS') + { + $langs->load("errors"); + setEventMessage($langs->trans("ErrorThisContactIsAlreadyDefinedAsThisType"), 'errors'); + } + else + { + setEventMessage($object->error, 'errors'); + } + } + } + + // Bascule du statut d'un contact + else if ($action == 'swapstatut') + { + if ($object->fetch($id) > 0) + { + $result=$object->swapContactStatus(GETPOST('ligne')); + } + else + { + dol_print_error($db); + } + } + + // Efface un contact + else if ($action == 'deletecontact') + { + $object->fetch($id); + $result = $object->delete_contact($lineid); + + if ($result >= 0) + { + header("Location: ".$_SERVER['PHP_SELF']."?id=".$object->id); + exit; + } + else + { + dol_print_error($db); + } + } +} + + +/* + * View + */ + +llxHeader('',$langs->trans('Proposal'),'EN:Commercial_Proposals|FR:Proposition_commerciale|ES:Presupuestos'); + +$form = new Form($db); +$formother = new FormOther($db); +$formfile = new FormFile($db); +$formpropal = new FormPropal($db); +$companystatic=new Societe($db); + +// fetch optionals attributes and labels +$extralabels=$extrafields->fetch_name_optionals_label('propal'); + +$now=dol_now(); + +// Add new proposal +if ($action == 'create') +{ + print_fiche_titre($langs->trans("NewProp")); + + $soc = new Societe($db); + if ($socid>0) $res=$soc->fetch($socid); + + $object = new Propal($db); + + print '
'; + print ''; + print ''; + + if ($origin != 'project' && $originid) + { + print ''; + print ''; + } + + print ''; + + // Reference + print ''; + + // Ref customer + print ''; + print ''; + + // Third party + print ''; + print ''; + if($socid>0) + { + print ''; + } + else + { + print ''; + } + print ''."\n"; + + // Contacts + if($socid>0) + { + print "'; + + // Ligne info remises tiers + print ''; + } + + // Date + print ''; + + // Validaty duration + print ''; + + // Terms of payment + print ''; + + // Mode of payment + print ''; + + // What trigger creation + print ''; + + // Delivery delay + print ''; + + // Delivery date (or manufacturing) + print ''; + print ''; + + // Model + print ''; + print ''; + print '"; + + // Project + if (! empty($conf->projet->enabled) && $socid>0) + { + $projectid = 0; + if ($origin == 'project') $projectid = ($originid?$originid:0); + + print ''; + print ''; + print ''; + } + + // Other attributes + $parameters=array('colspan' => ' colspan="3"'); + $reshook=$hookmanager->executeHooks('formObjectOptions',$parameters,$object,$action); // Note that $action and $object may have been modified by hook + if (empty($reshook) && ! empty($extrafields->attribute_label)) + { + foreach($extrafields->attribute_label as $key=>$label) + { + $value=(isset($_POST["options_".$key])?$_POST["options_".$key]:$object->array_options["options_".$key]); + + // Show separator only + if ($extrafields->attribute_type[$key] == 'separate') + { + print $extrafields->showSeparator($key); + } + else + { + print 'attribute_required[$key])) print ' class="fieldrequired"'; + print '>'.$label.''."\n"; + } + } + } + + print "
'.$langs->trans('Ref').''.$langs->trans("Draft").'
'.$langs->trans('RefCustomer').''; + print '
'.$langs->trans('Customer').''; + print $soc->getNomUrl(1); + print ''; + print ''; + print $form->select_company('','socid','s.client = 1 OR s.client = 2 OR s.client = 3',1); + print '
".$langs->trans("DefaultContact").''; + $form->select_contacts($soc->id,$setcontact,'contactidp',1,$srccontactslist); + print '
'.$langs->trans('Discounts').''; + if ($soc->remise_client) print $langs->trans("CompanyHasRelativeDiscount",$soc->remise_client); + else print $langs->trans("CompanyHasNoRelativeDiscount"); + $absolute_discount=$soc->getAvailableDiscounts(); + print '. '; + if ($absolute_discount) print $langs->trans("CompanyHasAbsoluteDiscount",price($absolute_discount),$langs->trans("Currency".$conf->currency)); + else print $langs->trans("CompanyHasNoAbsoluteDiscount"); + print '.'; + print '
'.$langs->trans('Date').''; + $form->select_date('','','','','',"addprop"); + print '
'.$langs->trans("ValidityDuration").' '.$langs->trans("days").'
'.$langs->trans('PaymentConditionsShort').''; + $form->select_conditions_paiements($soc->cond_reglement,'cond_reglement_id'); + print '
'.$langs->trans('PaymentMode').''; + $form->select_types_paiements($soc->mode_reglement,'mode_reglement_id'); + print '
'.$langs->trans('Source').''; + $form->select_demand_reason('','demand_reason_id',"SRC_PROP",1); + print '
'.$langs->trans('AvailabilityPeriod').''; + $form->select_availability('','availability_id','',1); + print '
'.$langs->trans("DeliveryDate").''; + if ($conf->global->DATE_LIVRAISON_WEEK_DELAY != "") + { + $tmpdte = time() + ((7 * $conf->global->DATE_LIVRAISON_WEEK_DELAY) * 24 * 60 * 60); + $syear = date("Y", $tmpdte); + $smonth = date("m", $tmpdte); + $sday = date("d", $tmpdte); + $form->select_date($syear."-".$smonth."-".$sday,'liv_','','','',"addprop"); + } + else + { + $datepropal=empty($conf->global->MAIN_AUTOFILL_DATE)?-1:0; + $form->select_date($datepropal,'liv_','','','',"addprop"); + } + print '
'.$langs->trans("DefaultModel").''; + $liste=ModelePDFPropales::liste_modeles($db); + print $form->selectarray('model',$liste,$conf->global->PROPALE_ADDON_PDF); + print "
'.$langs->trans("Project").''; + + $numprojet=select_projects($soc->id,$projectid); + if ($numprojet==0) + { + print '   '.$langs->trans("AddProject").''; + } + print '
'; + print $extrafields->showInputField($key,$value); + print '
"; + print '
'; + + /* + * Combobox pour la fonction de copie + */ + + if (empty($conf->global->PROPAL_CLONE_ON_CREATE_PAGE)) + { + print ''; + } + + print ''; + if (! empty($conf->global->PROPAL_CLONE_ON_CREATE_PAGE)) + { + // For backward compatibility + print ''; + print ''; + print ''; + print ''; + + if (! empty($conf->global->PRODUCT_SHOW_WHEN_CREATE)) print ''; + + print ''; + print ''; + } + + if (! empty($conf->global->PRODUCT_SHOW_WHEN_CREATE)) + { + print ''; + } + print '
'.$langs->trans("CopyPropalFrom").' '; + $liste_propal = array(); + $liste_propal[0] = ''; + + $sql ="SELECT p.rowid as id, p.ref, s.nom"; + $sql.=" FROM ".MAIN_DB_PREFIX."propal p"; + $sql.= ", ".MAIN_DB_PREFIX."societe s"; + $sql.= " WHERE s.rowid = p.fk_soc"; + $sql.= " AND p.entity = ".$conf->entity; + $sql.= " AND p.fk_statut <> 0"; + $sql.= " ORDER BY Id"; + + $resql = $db->query($sql); + if ($resql) + { + $num = $db->num_rows($resql); + $i = 0; + while ($i < $num) + { + $row = $db->fetch_row($resql); + $propalRefAndSocName = $row[1]." - ".$row[2]; + $liste_propal[$row[0]]=$propalRefAndSocName; + $i++; + } + print $form->selectarray("copie_propal",$liste_propal, 0); + } + else + { + dol_print_error($db); + } + print '
 
'.$langs->trans("CreateEmptyPropal").'
'; + if (! empty($conf->product->enabled) || ! empty($conf->service->enabled)) + { + $lib=$langs->trans("ProductsAndServices"); + + print ''; + print ''; + print ''; + print ''; + print ''; + print ''; + for ($i = 1 ; $i <= $conf->global->PRODUCT_SHOW_WHEN_CREATE; $i++) + { + print ''; + print ''; + print ''; + print ''; + } + + print "
'.$lib.''.$langs->trans("Qty").''.$langs->trans("ReductionShort").'
'; + // multiprix + if($conf->global->PRODUIT_MULTIPRICES && $soc->price_level) + $form->select_produits('',"idprod".$i,'',$conf->product->limit_size,$soc->price_level); + else + $form->select_produits('',"idprod".$i,'',$conf->product->limit_size); + print '%
"; + + } + print '
'; + print '
'; + + $langs->load("bills"); + print '
'; + print ''; + print ' '; + print '
'; + + print "
"; +} +else +{ + /* + * Show object in view mode + */ + + $soc = new Societe($db); + $soc->fetch($object->socid); + + $head = propal_prepare_head($object); + dol_fiche_head($head, 'comm', $langs->trans('Proposal'), 0, 'propal'); + + $formconfirm=''; + + // Clone confirmation + if ($action == 'clone') + { + // Create an array for form + $formquestion=array( + //'text' => $langs->trans("ConfirmClone"), + //array('type' => 'checkbox', 'name' => 'clone_content', 'label' => $langs->trans("CloneMainAttributes"), 'value' => 1), + //array('type' => 'checkbox', 'name' => 'update_prices', 'label' => $langs->trans("PuttingPricesUpToDate"), 'value' => 1), + array('type' => 'other', 'name' => 'socid', 'label' => $langs->trans("SelectThirdParty"), 'value' => $form->select_company(GETPOST('socid','int'),'socid','(s.client=1 OR s.client=2 OR s.client=3)')) + ); + // Paiement incomplet. On demande si motif = escompte ou autre + $formconfirm=$form->formconfirm($_SERVER["PHP_SELF"].'?id='.$object->id,$langs->trans('ClonePropal'),$langs->trans('ConfirmClonePropal',$object->ref),'confirm_clone',$formquestion,'yes',1); + } + + // Confirm delete + else if ($action == 'delete') + { + $formconfirm=$form->formconfirm($_SERVER["PHP_SELF"].'?id='.$object->id, $langs->trans('DeleteProp'), $langs->trans('ConfirmDeleteProp',$object->ref), 'confirm_delete','',0,1); + } + + // Confirm reopen + else if ($action == 'reopen') + { + $formconfirm=$form->formconfirm($_SERVER["PHP_SELF"].'?id='.$object->id, $langs->trans('ReOpen'), $langs->trans('ConfirmReOpenProp',$object->ref), 'confirm_reopen','',0,1); + } + + // Confirmation delete product/service line + else if ($action == 'ask_deleteline') + { + $formconfirm=$form->formconfirm($_SERVER["PHP_SELF"].'?id='.$object->id.'&lineid='.$lineid, $langs->trans('DeleteProductLine'), $langs->trans('ConfirmDeleteProductLine'), 'confirm_deleteline','',0,1); + } + + // Confirm validate proposal + else if ($action == 'validate') + { + $error=0; + + // on verifie si l'objet est en numerotation provisoire + $ref = substr($object->ref, 1, 4); + if ($ref == 'PROV') + { + $numref = $object->getNextNumRef($soc); + if (empty($numref)) + { + $error++; + dol_htmloutput_errors($object->error); + } + } + else + { + $numref = $object->ref; + } + + $text=$langs->trans('ConfirmValidateProp',$numref); + if (! empty($conf->notification->enabled)) + { + require_once DOL_DOCUMENT_ROOT .'/core/class/notify.class.php'; + $notify=new Notify($db); + $text.='
'; + $text.=$notify->confirmMessage('NOTIFY_VAL_PROPAL',$object->socid); + } + + if (! $error) $formconfirm=$form->formconfirm($_SERVER["PHP_SELF"].'?id='.$object->id, $langs->trans('ValidateProp'), $text, 'confirm_validate','',0,1); + } + + if (! $formconfirm) + { + $parameters=array('lineid'=>$lineid); + $formconfirm=$hookmanager->executeHooks('formConfirm',$parameters,$object,$action); // Note that $action and $object may have been modified by hook + } + + // Print form confirm + print $formconfirm; + + + print ''; + + $linkback = ''.$langs->trans("BackToList").''; + + // Ref + print ''; + + // Ref client + print ''; + print ''; + + // Company + print ''; + print ''; + + // Ligne info remises tiers + print ''; + + // Date of proposal + print ''; + print ''; + + // Date end proposal + print ''; + print ''; + print ''; + + // Payment term + print ''; + print ''; + + // Delivery date + $langs->load('deliveries'); + print ''; + print ''; + + // Delivery delay + print ''; + print ''; + + // Origin of demand + print ''; + print ''; + + // Payment mode + print ''; + print ''; + + // Project + if (! empty($conf->projet->enabled)) + { + $langs->load("projects"); + print ''; + } + else + { + print '
'.$langs->trans('Ref').''; + print $form->showrefnav($object, 'ref', $linkback, 1, 'ref', 'ref', ''); + print '
'; + print ''; + if ($action != 'refclient' && ! empty($object->brouillon)) print ''; + print '
'; + print $langs->trans('RefCustomer').''; + print ''.img_edit($langs->trans('Modify')).'
'; + print '
'; + if ($user->rights->propal->creer && $action == 'refclient') + { + print '
'; + print ''; + print ''; + print ''; + print ' '; + print '
'; + } + else + { + print $object->ref_client; + } + print '
'.$langs->trans('Company').''.$soc->getNomUrl(1).'
'.$langs->trans('Discounts').''; + if ($soc->remise_client) print $langs->trans("CompanyHasRelativeDiscount",$soc->remise_client); + else print $langs->trans("CompanyHasNoRelativeDiscount"); + print '. '; + $absolute_discount=$soc->getAvailableDiscounts('','fk_facture_source IS NULL'); + $absolute_creditnote=$soc->getAvailableDiscounts('','fk_facture_source IS NOT NULL'); + $absolute_discount=price2num($absolute_discount,'MT'); + $absolute_creditnote=price2num($absolute_creditnote,'MT'); + if ($absolute_discount) + { + if ($object->statut > 0) + { + print $langs->trans("CompanyHasAbsoluteDiscount",price($absolute_discount),$langs->transnoentities("Currency".$conf->currency)); + } + else + { + // Remise dispo de type non avoir + $filter='fk_facture_source IS NULL'; + print '
'; + $form->form_remise_dispo($_SERVER["PHP_SELF"].'?id='.$object->id,0,'remise_id',$soc->id,$absolute_discount,$filter); + } + } + if ($absolute_creditnote) + { + print $langs->trans("CompanyHasCreditNote",price($absolute_creditnote),$langs->transnoentities("Currency".$conf->currency)).'. '; + } + if (! $absolute_discount && ! $absolute_creditnote) print $langs->trans("CompanyHasNoAbsoluteDiscount").'.'; + print '
'; + print ''; + if ($action != 'editdate' && ! empty($object->brouillon)) print ''; + print '
'; + print $langs->trans('Date'); + print 'id.'">'.img_edit($langs->trans('SetDate'),1).'
'; + print '
'; + if (! empty($object->brouillon) && $action == 'editdate') + { + print '
'; + print ''; + print ''; + $form->select_date($object->date,'re','','',0,"editdate"); + print ''; + print '
'; + } + else + { + if ($object->date) + { + print dol_print_date($object->date,'daytext'); + } + else + { + print ' '; + } + } + print '
'; + print ''; + if ($action != 'editecheance' && ! empty($object->brouillon)) print ''; + print '
'; + print $langs->trans('DateEndPropal'); + print 'id.'">'.img_edit($langs->trans('SetConditions'),1).'
'; + print '
'; + if (! empty($object->brouillon) && $action == 'editecheance') + { + print '
'; + print ''; + print ''; + $form->select_date($object->fin_validite,'ech','','','',"editecheance"); + print ''; + print '
'; + } + 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)) print img_warning($langs->trans("Late")); + } + else + { + print ' '; + } + } + print '
'; + print ''; + if ($action != 'editconditions' && ! empty($object->brouillon)) print ''; + print '
'; + print $langs->trans('PaymentConditionsShort'); + print 'id.'">'.img_edit($langs->transnoentitiesnoconv('SetConditions'),1).'
'; + print '
'; + if ($action == 'editconditions') + { + $form->form_conditions_reglement($_SERVER['PHP_SELF'].'?id='.$object->id,$object->cond_reglement_id,'cond_reglement_id'); + } + else + { + $form->form_conditions_reglement($_SERVER['PHP_SELF'].'?id='.$object->id,$object->cond_reglement_id,'none'); + } + print '
'; + print ''; + if ($action != 'editdate_livraison' && ! empty($object->brouillon)) print ''; + print '
'; + print $langs->trans('DeliveryDate'); + print 'id.'">'.img_edit($langs->transnoentitiesnoconv('SetDeliveryDate'),1).'
'; + print '
'; + if ($action == 'editdate_livraison') + { + print '
'; + print ''; + print ''; + $form->select_date($object->date_livraison,'liv_','','','',"editdate_livraison"); + print ''; + print '
'; + } + else + { + print dol_print_date($object->date_livraison,'daytext'); + } + print '
'; + print ''; + if ($action != 'editavailability' && ! empty($object->brouillon)) print ''; + print '
'; + print $langs->trans('AvailabilityPeriod'); + if (! empty($conf->commande->enabled)) print ' ('.$langs->trans('AfterOrder').')'; + print 'id.'">'.img_edit($langs->transnoentitiesnoconv('SetAvailability'),1).'
'; + print '
'; + if ($action == 'editavailability') + { + $form->form_availability($_SERVER['PHP_SELF'].'?id='.$object->id,$object->availability_id,'availability_id',1); + } + else + { + $form->form_availability($_SERVER['PHP_SELF'].'?id='.$object->id,$object->availability_id,'none',1); + } + + print '
'; + print ''; + if ($action != 'editdemandreason' && ! empty($object->brouillon)) print ''; + print '
'; + print $langs->trans('Source'); + print 'id.'">'.img_edit($langs->transnoentitiesnoconv('SetDemandReason'),1).'
'; + print '
'; + //print $object->demand_reason_id; + if ($action == 'editdemandreason') + { + $form->form_demand_reason($_SERVER['PHP_SELF'].'?id='.$object->id,$object->demand_reason_id,'demand_reason_id',1); + } + else + { + $form->form_demand_reason($_SERVER['PHP_SELF'].'?id='.$object->id,$object->demand_reason_id,'none'); + } + + print '
'; + print ''; + if ($action != 'editmode' && ! empty($object->brouillon)) print ''; + print '
'; + print $langs->trans('PaymentMode'); + print 'id.'">'.img_edit($langs->transnoentitiesnoconv('SetMode'),1).'
'; + print '
'; + if ($action == 'editmode') + { + $form->form_modes_reglement($_SERVER['PHP_SELF'].'?id='.$object->id,$object->mode_reglement_id,'mode_reglement_id'); + } + else + { + $form->form_modes_reglement($_SERVER['PHP_SELF'].'?id='.$object->id,$object->mode_reglement_id,'none'); + } + print '
'; + print ''; + if ($user->rights->propal->creer) + { + if ($action != 'classify') print ''; + print '
'; + print $langs->trans('Project').''.img_edit($langs->transnoentitiesnoconv('SetProject')).'
'; + print '
'; + if ($action == 'classify') + { + $form->form_project($_SERVER['PHP_SELF'].'?id='.$object->id, $object->socid, $object->fk_project, 'projectid'); + } + else + { + $form->form_project($_SERVER['PHP_SELF'].'?id='.$object->id, $object->socid, $object->fk_project, 'none'); + } + print '
'; + if (! empty($object->fk_project)) + { + print ''; + $proj = new Project($db); + $proj->fetch($object->fk_project); + print ''; + print $proj->ref; + print ''; + print ''; + } + else { + print ' '; + } + } + print ''; + } + + // Other attributes + $res=$object->fetch_optionals($object->id,$extralabels); + $parameters=array('colspan' => ' colspan="3"'); + $reshook=$hookmanager->executeHooks('formObjectOptions',$parameters,$object,$action); // Note that $action and $object may have been modified by hook + if (empty($reshook) && ! empty($extrafields->attribute_label)) + { + + if ($action == 'edit_extras') + { + print '
'; + print ''; + print ''; + print ''; + } + + + foreach($extrafields->attribute_label as $key=>$label) + { + $value=(isset($_POST["options_".$key])?$_POST["options_".$key]:$object->array_options["options_".$key]); + if ($extrafields->attribute_type[$key] == 'separate') + { + print $extrafields->showSeparator($key); + } + else + { + print 'attribute_required[$key])) print ' class="fieldrequired"'; + print '>'.$label.''; + if ($action == 'edit_extras' && $user->rights->propal->creer) + { + print $extrafields->showInputField($key,$value); + } + else + { + print $extrafields->showOutputField($key,$value); + } + print ''."\n"; + } + } + + if(count($extrafields->attribute_label) > 0) { + + if ($action == 'edit_extras' && $user->rights->propal->creer) + { + print ''; + print ''; + print ''; + print ''; + + } + else { + if ($object->statut == 0 && $user->rights->propal->creer) + { + print ''.img_picto('','edit').' '.$langs->trans('Modify').''; + } + } + } + } + + // Amount HT + print ''.$langs->trans('AmountHT').''; + print ''.price($object->total_ht).''; + print ''.$langs->trans("Currency".$conf->currency).''; + + // Margin Infos + if (! empty($conf->margin->enabled)) { + print ''; + $object->displayMarginInfos(); + print ''; + } + print ''; + + // Amount VAT + print ''.$langs->trans('AmountVAT').''; + print ''.price($object->total_tva).''; + print ''.$langs->trans("Currency".$conf->currency).''; + + // Amount Local Taxes + if ($mysoc->localtax1_assuj=="1") //Localtax1 + { + print ''.$langs->transcountry("AmountLT1",$mysoc->country_code).''; + print ''.price($object->total_localtax1).''; + print ''.$langs->trans("Currency".$conf->currency).''; + } + if ($mysoc->localtax2_assuj=="1") //Localtax2 + { + print ''.$langs->transcountry("AmountLT2",$mysoc->country_code).''; + print ''.price($object->total_localtax2).''; + print ''.$langs->trans("Currency".$conf->currency).''; + } + + + // Amount TTC + print ''.$langs->trans('AmountTTC').''; + print ''.price($object->total_ttc).''; + print ''.$langs->trans("Currency".$conf->currency).''; + + // Statut + print ''.$langs->trans('Status').''.$object->getLibStatut(4).''; + + print '
'; + + if (! empty($conf->global->MAIN_DISABLE_CONTACTS_TAB)) + { + $blocname = 'contacts'; + $title = $langs->trans('ContactsAddresses'); + include DOL_DOCUMENT_ROOT.'/core/tpl/bloc_showhide.tpl.php'; + } + + if (! empty($conf->global->MAIN_DISABLE_NOTES_TAB)) + { + $blocname = 'notes'; + $title = $langs->trans('Notes'); + include DOL_DOCUMENT_ROOT.'/core/tpl/bloc_showhide.tpl.php'; + } + + /* + * Lines + */ + + if (! empty($conf->use_javascript_ajax) && $object->statut == 0) + { + include DOL_DOCUMENT_ROOT.'/core/tpl/ajaxrow.tpl.php'; + } + + print ''; + + // Show object lines + $result = $object->getLinesArray(); + if (! empty($object->lines)) + $ret=$object->printObjectLines($action,$mysoc,$soc,$lineid); + + // Form to add new line + if ($object->statut == 0 && $user->rights->propal->creer) + { + if ($action != 'editline') + { + $var=true; + + if ($conf->global->MAIN_FEATURES_LEVEL > 1) + { + // Add free or predefined products/services + $object->formAddObjectLine(0,$mysoc,$soc); + } + else + { + // Add free products/services + $object->formAddFreeProduct(0,$mysoc,$soc); + + // Add predefined products/services + if (! empty($conf->product->enabled) || ! empty($conf->service->enabled)) + { + $var=!$var; + $object->formAddPredefinedProduct(0,$mysoc,$soc); + } + } + + $parameters=array(); + $reshook=$hookmanager->executeHooks('formAddObjectLine',$parameters,$object,$action); // Note that $action and $object may have been modified by hook + } + } + + print '
'; + + print ''; + print "\n"; + + if ($action == 'statut') + { + /* + * Formulaire cloture (signe ou non) + */ + $form_close = '
'; + $form_close.= ''; + $form_close.= ''; + $form_close.= ''; + $form_close.= ''; + $form_close.= ''; + $form_close.= '
'.$langs->trans("CloseAs").''; + $form_close.= ''; + $form_close.= ''; + $form_close.= '
'.$langs->trans('Note').'
'; + $form_close.= ''; + $form_close.= '   '; + $form_close.= ' '; + $form_close.= '
'; + + print $form_close; + } + + + /* + * Boutons Actions + */ + if ($action != 'presend') + { + print '
'; + + if ($action != 'statut' && $action <> 'editline') + { + // Validate + if ($object->statut == 0 && $object->total_ttc >= 0 && count($object->lines) > 0 && $user->rights->propal->valider) + { + if (count($object->lines) > 0) print ''.$langs->trans('Validate').''; + //else print ''.$langs->trans('Validate').''; + } + + // Edit + if ($object->statut == 1 && $user->rights->propal->creer) + { + print ''.$langs->trans('Modify').''; + } + + // ReOpen + if (($object->statut == 2 || $object->statut == 3) && $user->rights->propal->cloturer) + { + print 'global->MAIN_JUMP_TAG)?'':'#reopen').'"'; + print '>'.$langs->trans('ReOpen').''; + } + + // Send + if ($object->statut == 1 || $object->statut == 2) + { + if (empty($conf->global->MAIN_USE_ADVANCED_PERMS) || $user->rights->propal->propal_advance->send) + { + print ''.$langs->trans('SendByMail').''; + } + else print ''.$langs->trans('SendByMail').''; + } + + // Create an order + if (! empty($conf->commande->enabled) && $object->statut == 2 && $user->societe_id == 0) + { + if ($user->rights->commande->creer) + { + print ''.$langs->trans("AddOrder").''; + } + } + + // Create contract + if ($conf->contrat->enabled && $object->statut == 2 && $user->societe_id == 0) + { + $langs->load("contracts"); + + if ($user->rights->contrat->creer) + { + print ''.$langs->trans('AddContract').''; + } + } + + // Create an invoice and classify billed + if ($object->statut == 2 && $user->societe_id == 0) + { + if (! empty($conf->facture->enabled) && $user->rights->facture->creer) + { + print ''.$langs->trans("AddBill").''; + } + + $arraypropal=$object->getInvoiceArrayList(); + if (is_array($arraypropal) && count($arraypropal) > 0) + { + print 'socid.'">'.$langs->trans("ClassifyBilled").''; + } + } + + // Close + if ($object->statut == 1 && $user->rights->propal->cloturer) + { + print 'global->MAIN_JUMP_TAG)?'':'#close').'"'; + print '>'.$langs->trans('Close').''; + } + + // Clone + if ($user->rights->propal->creer) + { + print ''.$langs->trans("ToClone").''; + } + + // Delete + if ($user->rights->propal->supprimer) + { + print ''.$langs->trans('Delete').''; + } + + } + + print '
'; + print "
\n"; + } + + if ($action != 'presend') + { + print '
'; + print ''; // ancre + + + /* + * Documents generes + */ + $filename=dol_sanitizeFileName($object->ref); + $filedir=$conf->propal->dir_output . "/" . dol_sanitizeFileName($object->ref); + $urlsource=$_SERVER["PHP_SELF"]."?id=".$object->id; + $genallowed=$user->rights->propal->creer; + $delallowed=$user->rights->propal->supprimer; + + $var=true; + + $somethingshown=$formfile->show_documents('propal',$filename,$filedir,$urlsource,$genallowed,$delallowed,$object->modelpdf,1,0,0,28,0,'',0,'',$soc->default_lang); + + + /* + * Linked object block + */ + $somethingshown=$object->showLinkedObjectBlock(); + + print ''; + + // List of actions on element + include_once DOL_DOCUMENT_ROOT.'/core/class/html.formactions.class.php'; + $formactions=new FormActions($db); + $somethingshown=$formactions->showactions($object,'propal',$socid); + + print '
'; + } + + + /* + * Action presend + * + */ + if ($action == 'presend') + { + $ref = dol_sanitizeFileName($object->ref); + include_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php'; + $fileparams = dol_most_recent_file($conf->propal->dir_output . '/' . $ref, preg_quote($object->ref,'/')); + $file=$fileparams['fullname']; + + // Build document if it not exists + if (! $file || ! is_readable($file)) + { + // Define output language + $outputlangs = $langs; + $newlang=''; + if ($conf->global->MAIN_MULTILANGS && empty($newlang) && ! empty($_REQUEST['lang_id'])) $newlang=$_REQUEST['lang_id']; + if ($conf->global->MAIN_MULTILANGS && empty($newlang)) $newlang=$object->client->default_lang; + if (! empty($newlang)) + { + $outputlangs = new Translate("",$conf); + $outputlangs->setDefaultLang($newlang); + } + + $result=propale_pdf_create($db, $object, GETPOST('model')?GETPOST('model'):$object->modelpdf, $outputlangs, $hidedetails, $hidedesc, $hideref); + if ($result <= 0) + { + dol_print_error($db,$result); + exit; + } + $fileparams = dol_most_recent_file($conf->propal->dir_output . '/' . $ref, preg_quote($object->ref,'/')); + $file=$fileparams['fullname']; + } + + print '
'; + print_titre($langs->trans('SendPropalByMail')); + + // Create form object + include_once DOL_DOCUMENT_ROOT.'/core/class/html.formmail.class.php'; + $formmail = new FormMail($db); + $formmail->fromtype = 'user'; + $formmail->fromid = $user->id; + $formmail->fromname = $user->getFullName($langs); + $formmail->frommail = $user->email; + $formmail->withfrom=1; + $liste=array(); + foreach ($object->thirdparty->thirdparty_and_contact_email_array(1) as $key=>$value) $liste[$key]=$value; + $formmail->withto=GETPOST("sendto")?GETPOST("sendto"):$liste; + $formmail->withtocc=$liste; + $formmail->withtoccc=(! empty($conf->global->MAIN_EMAIL_USECCC)?$conf->global->MAIN_EMAIL_USECCC:false); + $formmail->withtopic=$langs->trans('SendPropalRef','__PROPREF__'); + $formmail->withfile=2; + $formmail->withbody=1; + $formmail->withdeliveryreceipt=1; + $formmail->withcancel=1; + + // Tableau des substitutions + $formmail->substit['__PROPREF__']=$object->ref; + $formmail->substit['__SIGNATURE__']=$user->signature; + $formmail->substit['__PERSONALIZED__']=''; + $formmail->substit['__CONTACTCIVNAME__']=''; + //Find the good contact adress $custcontact=''; $contactarr=array(); - $contactarr=$object->liste_contact(-1,'external'); - + $contactarr=$object->liste_contact(-1,'external'); + if (is_array($contactarr) && count($contactarr)>0) { foreach($contactarr as $contact) { if ($contact['libelle']==$langs->trans('TypeContact_propal_external_CUSTOMER')) { @@ -2257,29 +2257,29 @@ else if (!empty($custcontact)) { $formmail->substit['__CONTACTCIVNAME__']=$custcontact; } - } - - // Tableau des parametres complementaires - $formmail->param['action']='send'; - $formmail->param['models']='propal_send'; - $formmail->param['id']=$object->id; - $formmail->param['returnurl']=$_SERVER["PHP_SELF"].'?id='.$object->id; - - - // Init list of files - if (GETPOST("mode")=='init') - { - $formmail->clear_attached_files(); - $formmail->add_attached_files($file,basename($file),dol_mimetype($file)); - } - - $formmail->show_form(); - - print '
'; - } -} - -// End of page -llxFooter(); -$db->close(); -?> + } + + // Tableau des parametres complementaires + $formmail->param['action']='send'; + $formmail->param['models']='propal_send'; + $formmail->param['id']=$object->id; + $formmail->param['returnurl']=$_SERVER["PHP_SELF"].'?id='.$object->id; + + + // Init list of files + if (GETPOST("mode")=='init') + { + $formmail->clear_attached_files(); + $formmail->add_attached_files($file,basename($file),dol_mimetype($file)); + } + + $formmail->show_form(); + + print '
'; + } +} + +// End of page +llxFooter(); +$db->close(); +?> From 1f537300ea11e8c85a2c3d89015cd75834d53179 Mon Sep 17 00:00:00 2001 From: jfefe Date: Wed, 27 Mar 2013 19:11:42 +0100 Subject: [PATCH 36/40] Add hidden option MAIN_PROPAL_CHOOSE_ODT_DOCUMENT to enable choice of ODT document to use according to his status --- .../doc/doc_generic_proposal_odt.modules.php | 54 ++++++++++--------- 1 file changed, 30 insertions(+), 24 deletions(-) diff --git a/htdocs/core/modules/propale/doc/doc_generic_proposal_odt.modules.php b/htdocs/core/modules/propale/doc/doc_generic_proposal_odt.modules.php index 959d9b29cd9..0878e4da181 100644 --- a/htdocs/core/modules/propale/doc/doc_generic_proposal_odt.modules.php +++ b/htdocs/core/modules/propale/doc/doc_generic_proposal_odt.modules.php @@ -106,9 +106,12 @@ class doc_generic_proposal_odt extends ModelePDFPropales $texte.= ''; $texte.= ''; $texte.= ''; - $texte.= ''; - $texte.= ''; - $texte.= ''; + if ($conf->global->MAIN_PROPAL_CHOOSE_ODT_DOCUMENT > 0) + { + $texte.= ''; + $texte.= ''; + $texte.= ''; + } $texte.= ''; // List of directories area @@ -150,27 +153,30 @@ class doc_generic_proposal_odt extends ModelePDFPropales { $texte.=$langs->trans("NumberOfModelFilesFound").': '.count($listoffiles).''; - // Model for creation - $liste=ModelePDFPropales::liste_modeles($this->db); - $texte.= '
'; - $texte.= ''; - $texte.= ''; - $texte.= '"; - - $texte.= ''; - $texte.= ''; - $texte.= '"; - $texte.= ''; - - $texte.= ''; - $texte.= '"; - $texte.= '
'.$langs->trans("DefaultModelPropalCreate").''; - $texte.= $form->selectarray('value2',$liste,$conf->global->PROPALE_ADDON_PDF_ODT_DEFAULT); - $texte.= "
'.$langs->trans("DefaultModelPropalToBill").''; - $texte.= $form->selectarray('value3',$liste,$conf->global->PROPALE_ADDON_PDF_ODT_TOBILL); - $texte.= "
'.$langs->trans("DefaultModelPropalClosed").''; - $texte.= $form->selectarray('value4',$liste,$conf->global->PROPALE_ADDON_PDF_ODT_CLOSED); - $texte.= "
'; + if ($conf->global->MAIN_PROPAL_CHOOSE_ODT_DOCUMENT > 0) + { + // Model for creation + $liste=ModelePDFPropales::liste_modeles($this->db); + $texte.= ''; + $texte.= ''; + $texte.= ''; + $texte.= '"; + + $texte.= ''; + $texte.= ''; + $texte.= '"; + $texte.= ''; + + $texte.= ''; + $texte.= '"; + $texte.= '
'.$langs->trans("DefaultModelPropalCreate").''; + $texte.= $form->selectarray('value2',$liste,$conf->global->PROPALE_ADDON_PDF_ODT_DEFAULT); + $texte.= "
'.$langs->trans("DefaultModelPropalToBill").''; + $texte.= $form->selectarray('value3',$liste,$conf->global->PROPALE_ADDON_PDF_ODT_TOBILL); + $texte.= "
'.$langs->trans("DefaultModelPropalClosed").''; + $texte.= $form->selectarray('value4',$liste,$conf->global->PROPALE_ADDON_PDF_ODT_CLOSED); + $texte.= "
'; + } } From 1f5987b379a232498f504f1fc8cd8f7c4692dc77 Mon Sep 17 00:00:00 2001 From: jfefe Date: Wed, 27 Mar 2013 19:13:50 +0100 Subject: [PATCH 37/40] Fix trad & add english --- htdocs/langs/en_US/propal.lang | 3 +++ htdocs/langs/fr_FR/propal.lang | 4 ++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/htdocs/langs/en_US/propal.lang b/htdocs/langs/en_US/propal.lang index 197a9f52146..a5f01c3e884 100644 --- a/htdocs/langs/en_US/propal.lang +++ b/htdocs/langs/en_US/propal.lang @@ -96,3 +96,6 @@ TypeContact_propal_external_CUSTOMER=Customer contact following-up proposal # Document models DocModelAzurDescription=A complete proposal model (logo...) DocModelJauneDescription=Jaune proposal model +DefaultModelPropalCreate=Default model creation +DefaultModelPropalToBill=Default template when closing a business proposal (to be invoiced) +DefaultModelPropalClosed=Default template when closing a business proposal (unbilled) diff --git a/htdocs/langs/fr_FR/propal.lang b/htdocs/langs/fr_FR/propal.lang index 5d5d1b2043c..5a52f3b442b 100644 --- a/htdocs/langs/fr_FR/propal.lang +++ b/htdocs/langs/fr_FR/propal.lang @@ -98,6 +98,6 @@ DocModelAzurDescription=Modèle de propositions commerciales complet (logo...) DocModelJauneDescription=Modèle de proposition Jaune Numbershort=N° DefaultModelPropalCreate=Modèle par défaut à la création -DefaultModelPropalToBill=Modèle lors de la cloture d'une proposition commerciale (à facturer) -DefaultModelPropalClosed=Modèle lors de la cloture d'une proposition commerciale (non facturée) +DefaultModelPropalToBill=Modèle par défaut lors de la cloture d'une proposition commerciale (à facturer) +DefaultModelPropalClosed=Modèle par défaut lors de la cloture d'une proposition commerciale (non facturée) From 55757a6b82ef5578d53dbc337e47c6544d05bf62 Mon Sep 17 00:00:00 2001 From: Regis Houssin Date: Wed, 27 Mar 2013 20:42:55 +0100 Subject: [PATCH 38/40] Fix: $i is global --- htdocs/core/boxes/box_activity.php | 23 +++++++---------------- htdocs/core/boxes/modules_boxes.php | 2 +- 2 files changed, 8 insertions(+), 17 deletions(-) diff --git a/htdocs/core/boxes/box_activity.php b/htdocs/core/boxes/box_activity.php index 1977e41970a..87e555958e8 100644 --- a/htdocs/core/boxes/box_activity.php +++ b/htdocs/core/boxes/box_activity.php @@ -41,18 +41,9 @@ class box_activity extends ModeleBoxes var $info_box_head = array(); var $info_box_contents = array(); - /** - * Constructor - */ - function __construct($db) - { - $this->db = $db; - - $this->enabled = 1; - // FIXME: Use a cache to save data because this slow down too much main home page. This box slow down too seriously software. - // FIXME: Removed number_format (not compatible with all languages) - // FIXME: Pb into some status - } + // FIXME: Use a cache to save data because this slow down too much main home page. This box slow down too seriously software. + // FIXME: Removed number_format (not compatible with all languages) + // FIXME: Pb into some status /** * Charge les donnees en memoire pour affichage ulterieur @@ -66,6 +57,7 @@ class box_activity extends ModeleBoxes $totalMnt = 0; $totalnb = 0; + $i = 0; include_once DOL_DOCUMENT_ROOT.'/core/lib/date.lib.php'; @@ -99,7 +91,6 @@ class box_activity extends ModeleBoxes if ($result) { $num = $db->num_rows($result); - $i = 0; while ($i < $num) { $this->info_box_contents[$i][0] = array('td' => 'align="left" width="16"', 'logo' => 'bill'); @@ -140,7 +131,7 @@ class box_activity extends ModeleBoxes $result = $db->query($sql); if ($result) { - $num = $db->num_rows($result)+$i; + $num = $db->num_rows($result) + $i; $now=dol_now(); while ($i < $num) @@ -195,7 +186,7 @@ class box_activity extends ModeleBoxes if ($result) { - $num = $db->num_rows($result)+$i; + $num = $db->num_rows($result) + $i; while ($i < $num) { $this->info_box_contents[$i][0] = array('td' => 'align="left" width="16"','logo' => 'object_order'); @@ -246,7 +237,7 @@ class box_activity extends ModeleBoxes if ($result) { - $num = $db->num_rows($result)+$i; + $num = $db->num_rows($result) + $i; while ($i < $num) { $this->info_box_contents[$i][0] = array('td' => 'align="left" width="16"','logo' => 'object_propal'); diff --git a/htdocs/core/boxes/modules_boxes.php b/htdocs/core/boxes/modules_boxes.php index ad901b42ca9..7ca1b1dd4a2 100644 --- a/htdocs/core/boxes/modules_boxes.php +++ b/htdocs/core/boxes/modules_boxes.php @@ -33,7 +33,7 @@ class ModeleBoxes // Can't be abtract as it is instanciated to build "empty" var $error=''; var $max=5; var $enabled=1; - + var $rowid; var $id; var $position; From 0a3b7e79940bbffe556946d0198aab863a8944f3 Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Wed, 27 Mar 2013 20:43:28 +0100 Subject: [PATCH 39/40] New: Be able to get path of image without tag img --- htdocs/core/lib/functions.lib.php | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/htdocs/core/lib/functions.lib.php b/htdocs/core/lib/functions.lib.php index 835e5a36ee1..edc39c6d164 100644 --- a/htdocs/core/lib/functions.lib.php +++ b/htdocs/core/lib/functions.lib.php @@ -1640,10 +1640,11 @@ function dol_trunc($string,$size=40,$trunc='right',$stringencoding='UTF-8',$nodo * Example: /mydir/mysubdir/picto.png if picto.png is stored into htdocs/mydir/mysubdir (pictoisfullpath must be set to 1) * @param string $options Add more attribute on img tag (For example 'style="float: right"') * @param int $pictoisfullpath If 1, image path is a full path + * @param int $srconly Return only content of the src attribute of img. * @return string Return img tag * @see #img_object, #img_picto_common */ -function img_picto($alt, $picto, $options = '', $pictoisfullpath = false) +function img_picto($alt, $picto, $options = '', $pictoisfullpath = false, $srconly=0) { global $conf; @@ -1678,7 +1679,8 @@ function img_picto($alt, $picto, $options = '', $pictoisfullpath = false) $fullpathpicto = $url.'/'.$path.'/img/'.$picto; } - return ''.dol_escape_htmltag($alt).''; + if ($srconly) return $fullpathpicto; + else return ''.dol_escape_htmltag($alt).''; } /** From 0108ee2bd8e66f2d4f6af20ad45eb51837fb0554 Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Wed, 27 Mar 2013 20:48:57 +0100 Subject: [PATCH 40/40] Fix: Bad name of function --- htdocs/install/etape5.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/htdocs/install/etape5.php b/htdocs/install/etape5.php index 4f7803c9786..499cc844db9 100644 --- a/htdocs/install/etape5.php +++ b/htdocs/install/etape5.php @@ -233,7 +233,7 @@ if ($action == "set" || empty($action) || preg_match('/upgrade/i',$action)) dolibarr_install_syslog('install/etape5.php Activate module file='.$file); $res=dol_include_once("/core/modules/".$file); - $res=Activate($modtoactivatenew,1); + $res=activateModule($modtoactivatenew,1); if (! $result) print 'ERROR in activating module file='.$file; } }