diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index e2282654fc9fb110d65451a393d7b215c9f80e50..ef6dd3a834ad50f0cb19e94013eb4759795b83fe 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -47,8 +47,8 @@ Long description (Can span accross multiple lines). Where KEYWORD is one of: -- "FIXED:" for bug fixes (May be followed by the bug number i.e: #456) -- "NEW:" for new features (May be followed by the task number i.e: #123) +- "FIXED:" for bug fixes. In upper case to appear into ChangeLog. (May be followed by the bug number i.e: #456) +- "NEW:" for new features. In upper case to appear into ChangeLog. (May be followed by the task number i.e: #123) - void, don't put a keyword if the commit is not introducing feature or closing a bug. ### Resources diff --git a/ChangeLog b/ChangeLog index ebf41dd05168d23c4d5240397fa323c6716ba0f7..e384f3ade7cec640215e06dc5caec2aa1b6f54a6 100644 --- a/ChangeLog +++ b/ChangeLog @@ -14,8 +14,10 @@ For users: MARGIN_PMP_AS_DEFAULT_BUY_PRICE to replace with first supplier price. - Introduce option MAIN_HTML_TITLE to start to control format of html title content. - Add extrafields on bank account cards. -- Added delay between mails in Newsletter module -- [ task #1793 ] Create new permission to restrict commercial agent margin to logged user +- Added delay between mails in Newsletter module. +- [ task #1793 ] Create new permission to restrict commercial agent margin to logged user. +- Add experimental module ask supplier price to request supplier quotation. +- Add experimental module batch management. For translators: - Update language files. @@ -25,6 +27,12 @@ For developers: - New: Function yn can show a visual checkbox. - New: Introduced select2 jquery plugin. +WARNING: Following changes may create regression for some external modules, but was necessary to make +Dolibarr better: +- Removed hoo supplierorderdao into supplier order creation. This is a business event, so we must use the + trigger ORDER_SUPPLIER_CREATE instead. + + ***** ChangeLog for 3.7 compared to 3.6.* ***** For users: diff --git a/htdocs/admin/askpricesupplier.php b/htdocs/admin/askpricesupplier.php new file mode 100644 index 0000000000000000000000000000000000000000..6307e81042cf03d2e1b0c3db14842ea92b8471f4 --- /dev/null +++ b/htdocs/admin/askpricesupplier.php @@ -0,0 +1,599 @@ +<?php +/* Copyright (C) 2003-2004 Rodolphe Quiedeville <rodolphe@quiedeville.org> + * Copyright (C) 2004-2011 Laurent Destailleur <eldy@users.sourceforge.net> + * Copyright (C) 2004 Sebastien Di Cintio <sdicintio@ressource-toi.org> + * Copyright (C) 2004 Benoit Mortier <benoit.mortier@opensides.be> + * Copyright (C) 2004 Eric Seigne <eric.seigne@ryxeo.com> + * Copyright (C) 2005-2012 Regis Houssin <regis.houssin@capnetworks.com> + * Copyright (C) 2008 Raphael Bertrand (Resultic) <raphael.bertrand@resultic.fr> + * Copyright (C) 2011-2013 Juanjo Menent <jmenent@2byte.es> + * + * 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 <http://www.gnu.org/licenses/>. + */ + +require '../main.inc.php'; +require_once DOL_DOCUMENT_ROOT.'/core/lib/admin.lib.php'; +require_once DOL_DOCUMENT_ROOT.'/comm/askpricesupplier/class/askpricesupplier.class.php'; +require_once DOL_DOCUMENT_ROOT.'/core/lib/askpricesupplier.lib.php'; +$langs->load("admin"); +$langs->load("errors"); +$langs->load('other'); +$langs->load('askpricesupplier'); + +if (! $user->admin) accessforbidden(); + +$action = GETPOST('action','alpha'); +$value = GETPOST('value','alpha'); +$label = GETPOST('label','alpha'); +$scandir = GETPOST('scandir','alpha'); +$type='askpricesupplier'; + +/* + * Actions + */ +$error=0; +if ($action == 'updateMask') +{ + $maskconstaskpricesupplier=GETPOST('maskconstaskpricesupplier','alpha'); + $maskaskpricesupplier=GETPOST('maskaskpricesupplier','alpha'); + if ($maskconstaskpricesupplier) $res = dolibarr_set_const($db,$maskconstaskpricesupplier,$maskaskpricesupplier,'chaine',0,'',$conf->entity); + + if (! $res > 0) $error++; + + if (! $error) + { + setEventMessage($langs->trans("SetupSaved")); + } + else + { + setEventMessage($langs->trans("Error"),'errors'); + } +} + +if ($action == 'specimen') +{ + $modele=GETPOST('module','alpha'); + + $askpricesupplier = new AskPriceSupplier($db); + $askpricesupplier->initAsSpecimen(); + + // Search template files + $file=''; $classname=''; $filefound=0; + $dirmodels=array_merge(array('/'),(array) $conf->modules_parts['models']); + foreach($dirmodels as $reldir) + { + $file=dol_buildpath($reldir."core/modules/askpricesupplier/doc/pdf_".$modele.".modules.php"); + if (file_exists($file)) + { + $filefound=1; + $classname = "pdf_".$modele; + break; + } + } + + if ($filefound) + { + require_once $file; + + $module = new $classname($db); + + if ($module->write_file($askpricesupplier,$langs) > 0) + { + header("Location: ".DOL_URL_ROOT."/document.php?modulepart=askpricesupplier&file=SPECIMEN.pdf"); + return; + } + else + { + setEventMessage($module->error,'errors'); + dol_syslog($module->error, LOG_ERR); + } + } + else + { + setEventMessage($langs->trans("ErrorModuleNotFound"),'errors'); + dol_syslog($langs->trans("ErrorModuleNotFound"), LOG_ERR); + } +} + +if ($action == 'set_ASKPRICESUPPLIER_DRAFT_WATERMARK') +{ + $draft = GETPOST('ASKPRICESUPPLIER_DRAFT_WATERMARK','alpha'); + + $res = dolibarr_set_const($db, "ASKPRICESUPPLIER_DRAFT_WATERMARK",trim($draft),'chaine',0,'',$conf->entity); + if (! $res > 0) $error++; + + if (! $error) + { + setEventMessage($langs->trans("SetupSaved")); + } + else + { + setEventMessage($langs->trans("Error"),'errors'); + } +} + +if ($action == 'set_ASKPRICESUPPLIER_FREE_TEXT') +{ + $freetext = GETPOST('ASKPRICESUPPLIER_FREE_TEXT'); // No alpha here, we want exact string + + $res = dolibarr_set_const($db, "ASKPRICESUPPLIER_FREE_TEXT",$freetext,'chaine',0,'',$conf->entity); + + if (! $res > 0) $error++; + + if (! $error) + { + setEventMessage($langs->trans("SetupSaved")); + } + else + { + setEventMessage($langs->trans("Error"),'errors'); + } +} + +if ($action == 'set_BANK_ASK_PAYMENT_BANK_DURING_ASKPRICESUPPLIER') +{ + $res = dolibarr_set_const($db, "BANK_ASK_PAYMENT_BANK_DURING_ASKPRICESUPPLIER",$value,'chaine',0,'',$conf->entity); + + if (! $res > 0) $error++; + + if (! $error) + { + setEventMessage($langs->trans("SetupSaved")); + } + else + { + setEventMessage($langs->trans("Error"),'errors'); + } +} + +// Define constants for submodules that contains parameters (forms with param1, param2, ... and value1, value2, ...) +if ($action == 'setModuleOptions') +{ + $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(); + setEventMessage($langs->trans("SetupSaved")); + } + else + { + $db->rollback(); + setEventMessage($langs->trans("Error"),'errors'); + } +} + +// Activate a model +if ($action == 'set') +{ + $ret = addDocumentModel($value, $type, $label, $scandir); +} + +else if ($action == 'del') +{ + $ret = delDocumentModel($value, $type); + if ($ret > 0) + { + if ($conf->global->ASKPRICESUPPLIER_ADDON_PDF == "$value") dolibarr_del_const($db, 'ASKPRICESUPPLIER_ADDON_PDF',$conf->entity); + } +} + +else if ($action == 'setdoc') +{ + if (dolibarr_set_const($db, "ASKPRICESUPPLIER_ADDON_PDF",$value,'chaine',0,'',$conf->entity)) + { + $conf->global->ASKPRICESUPPLIER_ADDON_PDF = $value; + } + + // On active le modele + $ret = delDocumentModel($value, $type); + if ($ret > 0) + { + $ret = addDocumentModel($value, $type, $label, $scandir); + } +} + +else if ($action == 'setmod') +{ + // TODO Verifier si module numerotation choisi peut etre active + // par appel methode canBeActivated + + dolibarr_set_const($db, "ASKPRICESUPPLIER_ADDON",$value,'chaine',0,'',$conf->entity); +} + + +/* + * Affiche page + */ + +$dirmodels=array_merge(array('/'),(array) $conf->modules_parts['models']); + + +llxHeader('',$langs->trans("AskPriceSupplierSetup")); + +$form=new Form($db); + +//if ($mesg) print $mesg; + +$linkback='<a href="'.DOL_URL_ROOT.'/admin/modules.php">'.$langs->trans("BackToModuleList").'</a>'; +print_fiche_titre($langs->trans("AskPriceSupplierSetup"),$linkback,'setup'); + +$head = askpricesupplier_admin_prepare_head(); + +dol_fiche_head($head, 'general', $langs->trans("CommRequests"), 0, 'askpricesupplier'); + +/* + * Module numerotation + */ +print_titre($langs->trans("AskPriceSupplierNumberingModules")); + +print '<table class="noborder" width="100%">'; +print '<tr class="liste_titre">'; +print '<td>'.$langs->trans("Name")."</td>\n"; +print '<td>'.$langs->trans("Description")."</td>\n"; +print '<td class="nowrap">'.$langs->trans("Example")."</td>\n"; +print '<td align="center" width="60">'.$langs->trans("Status").'</td>'; +print '<td align="center" width="16">'.$langs->trans("ShortInfo").'</td>'; +print '</tr>'."\n"; + +clearstatcache(); +foreach ($dirmodels as $reldir) +{ + $dir = dol_buildpath($reldir."core/modules/askpricesupplier/"); + + if (is_dir($dir)) + { + $handle = opendir($dir); + if (is_resource($handle)) + { + $var=true; + + while (($file = readdir($handle))!==false) + { + if (substr($file, 0, 21) == 'mod_askpricesupplier_' && substr($file, dol_strlen($file)-3, 3) == 'php') + { + $file = substr($file, 0, dol_strlen($file)-4); + + require_once $dir.$file.'.php'; + + $module = new $file; + + // Show modules according to features level + if ($module->version == 'development' && $conf->global->MAIN_FEATURES_LEVEL < 2) continue; + if ($module->version == 'experimental' && $conf->global->MAIN_FEATURES_LEVEL < 1) continue; + + if ($module->isEnabled()) + { + $var=!$var; + print '<tr '.$bc[$var].'><td>'.$module->nom."</td><td>\n"; + print $module->info(); + print '</td>'; + + // Show example of numbering module + print '<td class="nowrap">'; + $tmp=$module->getExample(); + if (preg_match('/^Error/',$tmp)) print '<div class="error">'.$langs->trans($tmp).'</div>'; + elseif ($tmp=='NotConfigured') print $langs->trans($tmp); + else print $tmp; + print '</td>'."\n"; + + print '<td align="center">'; + if ($conf->global->ASKPRICESUPPLIER_ADDON == "$file") + { + print img_picto($langs->trans("Activated"),'switch_on'); + } + else + { + print '<a href="'.$_SERVER["PHP_SELF"].'?action=setmod&value='.$file.'">'; + print img_picto($langs->trans("Disabled"),'switch_off'); + print '</a>'; + } + print '</td>'; + + $askpricesupplier=new AskPriceSupplier($db); + $askpricesupplier->initAsSpecimen(); + + // Info + $htmltooltip=''; + $htmltooltip.=''.$langs->trans("Version").': <b>'.$module->getVersion().'</b><br>'; + $askpricesupplier->type=0; + $nextval=$module->getNextValue($mysoc,$askpricesupplier); + if ("$nextval" != $langs->trans("NotAvailable")) { // Keep " on nextval + $htmltooltip.=''.$langs->trans("NextValue").': '; + if ($nextval) { + if (preg_match('/^Error/',$nextval) || $nextval=='NotConfigured') + $nextval = $langs->trans($nextval); + $htmltooltip.=$nextval.'<br>'; + } else { + $htmltooltip.=$langs->trans($module->error).'<br>'; + } + } + + print '<td align="center">'; + print $form->textwithpicto('',$htmltooltip,1,0); + print '</td>'; + + print "</tr>\n"; + } + } + } + closedir($handle); + } + } +} +print "</table><br>\n"; + + +/* + * Document templates generators + */ + +print_titre($langs->trans("AskPriceSupplierPDFModules")); + +// Load array def with activated templates +$def = array(); +$sql = "SELECT nom"; +$sql.= " FROM ".MAIN_DB_PREFIX."document_model"; +$sql.= " WHERE type = '".$type."'"; +$sql.= " AND entity = ".$conf->entity; +$resql=$db->query($sql); +if ($resql) +{ + $i = 0; + $num_rows=$db->num_rows($resql); + while ($i < $num_rows) + { + $array = $db->fetch_array($resql); + array_push($def, $array[0]); + $i++; + } +} +else +{ + dol_print_error($db); +} + + +print "<table class=\"noborder\" width=\"100%\">\n"; +print "<tr class=\"liste_titre\">\n"; +print " <td>".$langs->trans("Name")."</td>\n"; +print " <td>".$langs->trans("Description")."</td>\n"; +print '<td align="center" width="40">'.$langs->trans("Status")."</td>\n"; +print '<td align="center" width="40">'.$langs->trans("Default")."</td>\n"; +print '<td align="center" width="40">'.$langs->trans("ShortInfo").'</td>'; +print '<td align="center" width="40">'.$langs->trans("Preview").'</td>'; +print "</tr>\n"; + +clearstatcache(); + +$var=true; +foreach ($dirmodels as $reldir) +{ + foreach (array('','/doc') as $valdir) + { + $dir = dol_buildpath($reldir."core/modules/askpricesupplier".$valdir); + + if (is_dir($dir)) + { + $handle=opendir($dir); + if (is_resource($handle)) + { + while (($file = readdir($handle))!==false) + { + $filelist[]=$file; + } + closedir($handle); + arsort($filelist); + + foreach($filelist as $file) + { + if (preg_match('/\.modules\.php$/i',$file) && preg_match('/^(pdf_|doc_)/',$file)) + { + if (file_exists($dir.'/'.$file)) + { + $name = substr($file, 4, dol_strlen($file) -16); + $classname = substr($file, 0, dol_strlen($file) -12); + + require_once $dir.'/'.$file; + $module = new $classname($db); + + $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; + + if ($modulequalified) + { + $var = !$var; + print '<tr '.$bc[$var].'><td width="100">'; + print (empty($module->name)?$name:$module->name); + print "</td><td>\n"; + if (method_exists($module,'info')) print $module->info($langs); + else print $module->description; + print '</td>'; + + // Active + if (in_array($name, $def)) + { + print '<td align="center">'."\n"; + print '<a href="'.$_SERVER["PHP_SELF"].'?action=del&value='.$name.'">'; + print img_picto($langs->trans("Enabled"),'switch_on'); + print '</a>'; + print '</td>'; + } + else + { + print "<td align=\"center\">\n"; + print '<a href="'.$_SERVER["PHP_SELF"].'?action=set&value='.$name.'&scandir='.$module->scandir.'&label='.urlencode($module->name).'">'.img_picto($langs->trans("Disabled"),'switch_off').'</a>'; + print "</td>"; + } + + // Defaut + print "<td align=\"center\">"; + if ($conf->global->ASKPRICESUPPLIER_ADDON_PDF == "$name") + { + print img_picto($langs->trans("Default"),'on'); + } + else + { + print '<a href="'.$_SERVER["PHP_SELF"].'?action=setdoc&value='.$name.'&scandir='.$module->scandir.'&label='.urlencode($module->name).'" alt="'.$langs->trans("Default").'">'.img_picto($langs->trans("Disabled"),'off').'</a>'; + } + print '</td>'; + + // Info + $htmltooltip = ''.$langs->trans("Name").': '.$module->name; + $htmltooltip.='<br>'.$langs->trans("Type").': '.($module->type?$module->type:$langs->trans("Unknown")); + if ($module->type == 'pdf') + { + $htmltooltip.='<br>'.$langs->trans("Width").'/'.$langs->trans("Height").': '.$module->page_largeur.'/'.$module->page_hauteur; + } + $htmltooltip.='<br><br><u>'.$langs->trans("FeaturesSupported").':</u>'; + $htmltooltip.='<br>'.$langs->trans("Logo").': '.yn($module->option_logo,1,1); + $htmltooltip.='<br>'.$langs->trans("PaymentMode").': '.yn($module->option_modereg,1,1); + $htmltooltip.='<br>'.$langs->trans("PaymentConditions").': '.yn($module->option_condreg,1,1); + $htmltooltip.='<br>'.$langs->trans("MultiLanguage").': '.yn($module->option_multilang,1,1); + //$htmltooltip.='<br>'.$langs->trans("Discounts").': '.yn($module->option_escompte,1,1); + //$htmltooltip.='<br>'.$langs->trans("CreditNote").': '.yn($module->option_credit_note,1,1); + $htmltooltip.='<br>'.$langs->trans("WatermarkOnDraftProposal").': '.yn($module->option_draft_watermark,1,1); + + + print '<td align="center">'; + print $form->textwithpicto('',$htmltooltip,1,0); + print '</td>'; + + // Preview + print '<td align="center">'; + if ($module->type == 'pdf') + { + print '<a href="'.$_SERVER["PHP_SELF"].'?action=specimen&module='.$name.'">'.img_object($langs->trans("Preview"),'bill').'</a>'; + } + else + { + print img_object($langs->trans("PreviewNotAvailable"),'generic'); + } + print '</td>'; + + print "</tr>\n"; + } + } + } + } + } + } + } +} + +print '</table>'; +print '<br>'; + + +/* + * Other options + * + */ +print_titre($langs->trans("OtherOptions")); + +$var=true; +print "<table class=\"noborder\" width=\"100%\">"; +print "<tr class=\"liste_titre\">"; +print "<td>".$langs->trans("Parameter")."</td>\n"; +print '<td width="60" align="center">'.$langs->trans("Value")."</td>\n"; +print "<td> </td>\n"; +print "</tr>"; + +$var=! $var; +print '<form action="'.$_SERVER["PHP_SELF"].'" method="post">'; +print '<input type="hidden" name="token" value="'.$_SESSION['newtoken'].'">'; +print '<input type="hidden" name="action" value="set_ASKPRICESUPPLIER_FREE_TEXT">'; +print '<tr '.$bc[$var].'><td colspan="2">'; +print $langs->trans("FreeLegalTextOnAskPriceSupplier").' ('.$langs->trans("AddCRIfTooLong").')<br>'; +print '<textarea name="ASKPRICESUPPLIER_FREE_TEXT" class="flat" cols="120">'.$conf->global->ASKPRICESUPPLIER_FREE_TEXT.'</textarea>'; +print '</td><td align="right">'; +print '<input type="submit" class="button" value="'.$langs->trans("Modify").'">'; +print "</td></tr>\n"; +print '</form>'; + +$var=!$var; +print "<form method=\"post\" action=\"".$_SERVER["PHP_SELF"]."\">"; +print '<input type="hidden" name="token" value="'.$_SESSION['newtoken'].'">'; +print "<input type=\"hidden\" name=\"action\" value=\"set_ASKPRICESUPPLIER_DRAFT_WATERMARK\">"; +print '<tr '.$bc[$var].'><td colspan="2">'; +print $langs->trans("WatermarkOnDraftAskPriceSupplier").'<br>'; +print '<input size="50" class="flat" type="text" name="ASKPRICESUPPLIER_DRAFT_WATERMARK" value="'.$conf->global->ASKPRICESUPPLIER_DRAFT_WATERMARK.'">'; +print '</td><td align="right">'; +print '<input type="submit" class="button" value="'.$langs->trans("Modify").'">'; +print "</td></tr>\n"; +print '</form>'; + +if ($conf->banque->enabled) +{ + $var=!$var; + print '<tr '.$bc[$var].'><td>'; + print $langs->trans("BANK_ASK_PAYMENT_BANK_DURING_ASKPRICESUPPLIER").'</td><td> </td><td align="right">'; + if (! empty($conf->use_javascript_ajax)) + { + print ajax_constantonoff('BANK_ASK_PAYMENT_BANK_DURING_ASKPRICESUPPLIER'); + } + else + { + if (empty($conf->global->BANK_ASK_PAYMENT_BANK_DURING_ASKPRICESUPPLIER)) + { + print '<a href="'.$_SERVER['PHP_SELF'].'?action=set_BANK_ASK_PAYMENT_BANK_DURING_ASKPRICESUPPLIER&value=1">'.img_picto($langs->trans("Disabled"),'switch_off').'</a>'; + } + else + { + print '<a href="'.$_SERVER['PHP_SELF'].'?action=set_BANK_ASK_PAYMENT_BANK_DURING_ASKPRICESUPPLIER&value=0">'.img_picto($langs->trans("Enabled"),'switch_on').'</a>'; + } + } + print '</td></tr>'; +} +else +{ + $var=!$var; + print '<tr '.$bc[$var].'><td>'; + print $langs->trans("BANK_ASK_PAYMENT_BANK_DURING_ASKPRICESUPPLIER").'</td><td> </td><td align="center">'.$langs->trans('NotAvailable').'</td></tr>'; +} + +print '</table>'; + + + +/* + * Directory + */ +print '<br>'; +print_titre($langs->trans("PathToDocuments")); + +print "<table class=\"noborder\" width=\"100%\">\n"; +print "<tr class=\"liste_titre\">\n"; +print " <td>".$langs->trans("Name")."</td>\n"; +print " <td>".$langs->trans("Value")."</td>\n"; +print "</tr>\n"; +print "<tr ".$bc[false].">\n <td width=\"140\">".$langs->trans("PathDirectory")."</td>\n <td>".$conf->askpricesupplier->dir_output."</td>\n</tr>\n"; +print "</table>\n<br>"; + +$db->close(); + +llxFooter(); diff --git a/htdocs/comm/admin/askpricesupplier_extrafields.php b/htdocs/comm/admin/askpricesupplier_extrafields.php new file mode 100644 index 0000000000000000000000000000000000000000..0e74ca265e9a6e71312a1c675c9b8c428da125ea --- /dev/null +++ b/htdocs/comm/admin/askpricesupplier_extrafields.php @@ -0,0 +1,151 @@ +<?php +/* Copyright (C) 2001-2002 Rodolphe Quiedeville <rodolphe@quiedeville.org> + * Copyright (C) 2003 Jean-Louis Bergamo <jlb@j1b.org> + * Copyright (C) 2004-2011 Laurent Destailleur <eldy@users.sourceforge.net> + * Copyright (C) 2012 Regis Houssin <regis.houssin@capnetworks.com> + * + * 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 <http://www.gnu.org/licenses/>. + */ + +require '../../main.inc.php'; +require_once DOL_DOCUMENT_ROOT.'/core/lib/askpricesupplier.lib.php'; +require_once DOL_DOCUMENT_ROOT.'/core/class/extrafields.class.php'; + +$langs->load("companies"); +$langs->load("admin"); +$langs->load('askpricesupplier'); + +$extrafields = new ExtraFields($db); +$form = new Form($db); + +// List of supported format +$tmptype2label=ExtraFields::$type2label; +$type2label=array(''); +foreach ($tmptype2label as $key => $val) $type2label[$key]=$langs->trans($val); + +$action=GETPOST('action', 'alpha'); +$attrname=GETPOST('attrname', 'alpha'); +$elementtype='askpricesupplier'; //Must be the $table_element of the class that manage extrafield + +if (!$user->admin) accessforbidden(); + + +/* + * Actions + */ + +require DOL_DOCUMENT_ROOT.'/core/actions_extrafields.inc.php'; + + + +/* + * View + */ + +$textobject=$langs->transnoentitiesnoconv("CommRequests"); + + +llxHeader('',$langs->trans("AskPriceSupplierSetup")); + + +$linkback='<a href="'.DOL_URL_ROOT.'/admin/modules.php">'.$langs->trans("BackToModuleList").'</a>'; +print_fiche_titre($langs->trans("AskPriceSupplierSetup"),$linkback,'setup'); + + +$head = askpricesupplier_admin_prepare_head(); + +dol_fiche_head($head, 'attributes', $langs->trans("CommRequests"), 0, 'askpricesupplier'); + + +print $langs->trans("DefineHereComplementaryAttributes",$textobject).'<br>'."\n"; +print '<br>'; + +// Load attribute_label +$extrafields->fetch_name_optionals_label($elementtype); + +print "<table summary=\"listofattributes\" class=\"noborder\" width=\"100%\">"; + +print '<tr class="liste_titre">'; +print '<td align="center">'.$langs->trans("Position").'</td>'; +print '<td>'.$langs->trans("Label").'</td>'; +print '<td>'.$langs->trans("AttributeCode").'</td>'; +print '<td>'.$langs->trans("Type").'</td>'; +print '<td align="right">'.$langs->trans("Size").'</td>'; +print '<td align="center">'.$langs->trans("Unique").'</td>'; +print '<td align="center">'.$langs->trans("Required").'</td>'; +print '<td width="80"> </td>'; +print "</tr>\n"; + +$var=True; +foreach($extrafields->attribute_type as $key => $value) +{ + $var=!$var; + print "<tr ".$bc[$var].">"; + print "<td>".$extrafields->attribute_pos[$key]."</td>\n"; + print "<td>".$extrafields->attribute_label[$key]."</td>\n"; + print "<td>".$key."</td>\n"; + print "<td>".$type2label[$extrafields->attribute_type[$key]]."</td>\n"; + print '<td align="right">'.$extrafields->attribute_size[$key]."</td>\n"; + print '<td align="center">'.yn($extrafields->attribute_unique[$key])."</td>\n"; + print '<td align="center">'.yn($extrafields->attribute_required[$key])."</td>\n"; + print '<td align="right"><a href="'.$_SERVER["PHP_SELF"].'?action=edit&attrname='.$key.'">'.img_edit().'</a>'; + print " <a href=\"".$_SERVER["PHP_SELF"]."?action=delete&attrname=$key\">".img_delete()."</a></td>\n"; + print "</tr>"; + // $i++; +} + +print "</table>"; + +dol_fiche_end(); + + +// Buttons +if ($action != 'create' && $action != 'edit') +{ + print '<div class="tabsAction">'; + print '<div class="inline-block divButAction"><a class="butAction" href="'.$_SERVER["PHP_SELF"].'?action=create">'.$langs->trans("NewAttribute").'</a></div>'; + print "</div>"; +} + + +/* ************************************************************************** */ +/* */ +/* Creation d'un champ optionnel + /* */ +/* ************************************************************************** */ + +if ($action == 'create') +{ + print "<br>"; + print_titre($langs->trans('NewAttribute')); + + require DOL_DOCUMENT_ROOT.'/core/tpl/admin_extrafields_add.tpl.php'; +} + +/* ************************************************************************** */ +/* */ +/* Edition d'un champ optionnel */ +/* */ +/* ************************************************************************** */ +if ($action == 'edit' && ! empty($attrname)) +{ + print "<br>"; + print_titre($langs->trans("FieldEdition", $attrname)); + + require DOL_DOCUMENT_ROOT.'/core/tpl/admin_extrafields_edit.tpl.php'; +} + +llxFooter(); + +$db->close(); diff --git a/htdocs/comm/admin/askpricesupplierdet_extrafields.php b/htdocs/comm/admin/askpricesupplierdet_extrafields.php new file mode 100644 index 0000000000000000000000000000000000000000..a58164b63dda6a8af39b07c2ddbc74e914c7ce74 --- /dev/null +++ b/htdocs/comm/admin/askpricesupplierdet_extrafields.php @@ -0,0 +1,153 @@ +<?php +/* Copyright (C) 2001-2002 Rodolphe Quiedeville <rodolphe@quiedeville.org> + * Copyright (C) 2003 Jean-Louis Bergamo <jlb@j1b.org> + * Copyright (C) 2004-2013 Laurent Destailleur <eldy@users.sourceforge.net> + * Copyright (C) 2012 Regis Houssin <regis.houssin@capnetworks.com> + * Copyright (C) 2012 Florian Henry <florian.henry@open-concept.pro> + * Copyright (C) 2013 Philippe Grand <philippe.grand@atoo-net.com> + * Copyright (C) 2013 Florian Henry <florian.henry@open-concept.pro> + * + * 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 <http://www.gnu.org/licenses/>. + */ + +require '../../main.inc.php'; +require_once DOL_DOCUMENT_ROOT.'/core/lib/askpricesupplier.lib.php'; +require_once DOL_DOCUMENT_ROOT.'/core/class/extrafields.class.php'; + + +if (!$user->admin) + accessforbidden(); + +$langs->load("admin"); +$langs->load("other"); +$langs->load("askpricesupplier"); + +$extrafields = new ExtraFields($db); +$form = new Form($db); + +// List of supported format +$tmptype2label=ExtraFields::$type2label; +$type2label=array(''); +foreach ($tmptype2label as $key => $val) $type2label[$key]=$langs->trans($val); + +$action=GETPOST('action', 'alpha'); +$attrname=GETPOST('attrname', 'alpha'); + +$elementtype='askpricesupplierdet'; //Must be the $table_element of the class that manage extrafield + +if (!$user->admin) accessforbidden(); + + +/* + * Actions + */ + +require DOL_DOCUMENT_ROOT.'/core/actions_extrafields.inc.php'; + + + +/* + * View + */ + +$textobject=$langs->transnoentitiesnoconv("CommRequests"); + +llxHeader('',$langs->trans("AskPriceSupplierSetup")); + +$linkback='<a href="'.DOL_URL_ROOT.'/admin/modules.php">'.$langs->trans("BackToModuleList").'</a>'; +print_fiche_titre($langs->trans("AskPriceSupplierSetup"),$linkback,'setup'); + +$head = askpricesupplier_admin_prepare_head(); + +dol_fiche_head($head, 'attributeslines', $langs->trans("CommRequests"), 0, 'askpricesupplier'); + + +print $langs->trans("DefineHereComplementaryAttributes",$textobject).'<br>'."\n"; +print '<br>'; + +// Load attribute_label +$extrafields->fetch_name_optionals_label($elementtype); + +print "<table summary=\"listofattributes\" class=\"noborder\" width=\"100%\">"; + +print '<tr class="liste_titre">'; +print '<td>'.$langs->trans("Label").'</td>'; +print '<td>'.$langs->trans("AttributeCode").'</td>'; +print '<td>'.$langs->trans("Type").'</td>'; +print '<td align="right">'.$langs->trans("Size").'</td>'; +print '<td align="center">'.$langs->trans("Unique").'</td>'; +print '<td align="center">'.$langs->trans("Required").'</td>'; +print '<td width="80"> </td>'; +print "</tr>\n"; + +$var=True; +foreach($extrafields->attribute_type as $key => $value) +{ + $var=!$var; + print "<tr ".$bc[$var].">"; + print "<td>".$extrafields->attribute_label[$key]."</td>\n"; + print "<td>".$key."</td>\n"; + print "<td>".$type2label[$extrafields->attribute_type[$key]]."</td>\n"; + print '<td align="right">'.$extrafields->attribute_size[$key]."</td>\n"; + print '<td align="center">'.yn($extrafields->attribute_unique[$key])."</td>\n"; + print '<td align="center">'.yn($extrafields->attribute_required[$key])."</td>\n"; + print '<td align="right"><a href="'.$_SERVER["PHP_SELF"].'?action=edit&attrname='.$key.'">'.img_edit().'</a>'; + print " <a href=\"".$_SERVER["PHP_SELF"]."?action=delete&attrname=$key\">".img_delete()."</a></td>\n"; + print "</tr>"; +} + +print "</table>"; + +dol_fiche_end(); + + +// Buttons +if ($action != 'create' && $action != 'edit') +{ + print '<div class="tabsAction">'; + print "<a class=\"butAction\" href=\"".$_SERVER["PHP_SELF"]."?action=create\">".$langs->trans("NewAttribute")."</a>"; + print "</div>"; +} + + +/* ************************************************************************** */ +/* */ +/* Creation d'un champ optionnel */ +/* */ +/* ************************************************************************** */ + +if ($action == 'create') +{ + print "<br>"; + print_titre($langs->trans('NewAttribute')); + + require DOL_DOCUMENT_ROOT.'/core/tpl/admin_extrafields_add.tpl.php'; +} + +/* ************************************************************************** */ +/* */ +/* Edition d'un champ optionnel */ +/* */ +/* ************************************************************************** */ +if ($action == 'edit' && ! empty($attrname)) +{ + print "<br>"; + print_titre($langs->trans("FieldEdition", $attrname)); + + require DOL_DOCUMENT_ROOT.'/core/tpl/admin_extrafields_edit.tpl.php'; +} + +llxFooter(); + +$db->close(); diff --git a/htdocs/comm/askpricesupplier/card.php b/htdocs/comm/askpricesupplier/card.php new file mode 100644 index 0000000000000000000000000000000000000000..f2ca52f1f898436f66f89b1510aeb463470b0e80 --- /dev/null +++ b/htdocs/comm/askpricesupplier/card.php @@ -0,0 +1,1821 @@ +<?php +/* Copyright (C) 2001-2007 Rodolphe Quiedeville <rodolphe@quiedeville.org> + * Copyright (C) 2004-2014 Laurent Destailleur <eldy@users.sourceforge.net> + * Copyright (C) 2004 Eric Seigne <eric.seigne@ryxeo.com> + * Copyright (C) 2005 Marc Barilley / Ocebo <marc@ocebo.com> + * Copyright (C) 2005-2012 Regis Houssin <regis.houssin@capnetworks.com> + * Copyright (C) 2006 Andre Cianfarani <acianfa@free.fr> + * Copyright (C) 2010-2014 Juanjo Menent <jmenent@2byte.es> + * Copyright (C) 2010-2011 Philippe Grand <philippe.grand@atoo-net.com> + * Copyright (C) 2012-2013 Christophe Battarel <christophe.battarel@altairis.fr> + * Copyright (C) 2013-2014 Florian Henry <florian.henry@open-concept.pro> + * Copyright (C) 2014 Ferran Marcet <fmarcet@2byte.es> + * + * 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 <http://www.gnu.org/licenses/>. + */ + +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.formaskpricesupplier.class.php'; +require_once DOL_DOCUMENT_ROOT . '/comm/askpricesupplier/class/askpricesupplier.class.php'; +require_once DOL_DOCUMENT_ROOT . '/comm/action/class/actioncomm.class.php'; +require_once DOL_DOCUMENT_ROOT . '/core/modules/askpricesupplier/modules_askpricesupplier.php'; +require_once DOL_DOCUMENT_ROOT . '/core/lib/askpricesupplier.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/class/html.formprojet.class.php'; +} + +$langs->load('companies'); +$langs->load('askpricesupplier'); +$langs->load('compta'); +$langs->load('bills'); +$langs->load('orders'); +$langs->load('products'); +$langs->load("deliveries"); +$langs->load('sendings'); +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'); +$contactid = GETPOST('contactid','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, 'askpricesupplier', $id); + +$object = new AskPriceSupplier($db); +$extrafields = new ExtraFields($db); + +// fetch optionals attributes and labels +$extralabels = $extrafields->fetch_name_optionals_label($object->table_element); + +// 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('askpricesuppliercard','globalcard')); + +$permissionnote = $user->rights->askpricesupplier->creer; // Used by the include of actions_setnotes.inc.php + + +/* + * Actions + */ + +$parameters = array('socid' => $socid); +$reshook = $hookmanager->executeHooks('doActions', $parameters, $object, $action); // Note that $action and $object may have been modified by some hooks +if ($reshook < 0) setEventMessages($hookmanager->error, $hookmanager->errors, 'errors'); + +if (empty($reshook)) +{ + include DOL_DOCUMENT_ROOT . '/core/actions_setnotes.inc.php'; // Must be include, not includ_once + + // 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 = ''; + } + } + } + } + + // Delete askprice + else if ($action == 'confirm_delete' && $confirm == 'yes' && $user->rights->askpricesupplier->supprimer) + { + $result = $object->delete($user); + if ($result > 0) { + header('Location: ' . DOL_URL_ROOT . '/comm/askpricesupplier/list.php'); + exit(); + } else { + $langs->load("errors"); + setEventMessage($langs->trans($object->error), 'errors'); + } + } + + // Remove line + else if ($action == 'confirm_deleteline' && $confirm == 'yes' && $user->rights->askpricesupplier->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->thirdparty->default_lang); + $outputlangs->setDefaultLang($newlang); + } + $ret = $object->fetch($id); // Reload to get new records + $object->generateDocument($object->modelpdf, $outputlangs, $hidedetails, $hidedesc, $hideref); + } + + header('Location: ' . $_SERVER["PHP_SELF"] . '?id=' . $object->id); + exit(); + } + + // Validation + else if ($action == 'confirm_validate' && $confirm == 'yes' && + ((empty($conf->global->MAIN_USE_ADVANCED_PERMS) && ! empty($user->rights->askpricesupplier->creer)) + || (! empty($conf->global->MAIN_USE_ADVANCED_PERMS) && ! empty($user->rights->askpricesupplier->validate))) + ) + { + $result = $object->valid($user); + if ($result >= 0) + { + if (empty($conf->global->MAIN_DISABLE_PDF_AUTOUPDATE)) + { + // Define output language + if (empty($conf->global->MAIN_DISABLE_PDF_AUTOUPDATE)) + { + $outputlangs = $langs; + $newlang = ''; + if ($conf->global->MAIN_MULTILANGS && empty($newlang) && GETPOST('lang_id')) $newlang = GETPOST('lang_id','alpha'); + if ($conf->global->MAIN_MULTILANGS && empty($newlang)) $newlang = $object->thirdparty->default_lang; + if (! empty($newlang)) { + $outputlangs = new Translate("", $conf); + $outputlangs->setDefaultLang($newlang); + } + $model=$object->modelpdf; + $ret = $object->fetch($id); // Reload to get new records + + $object->generateDocument($model, $outputlangs, $hidedetails, $hidedesc, $hideref); + } + } + } else { + $langs->load("errors"); + if (count($object->errors) > 0) setEventMessage($object->errors, 'errors'); + else setEventMessage($langs->trans($object->error), 'errors'); + } + } + + else if ($action == 'setdate_livraison' && $user->rights->askpricesupplier->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); + } + + // Create askprice + else if ($action == 'add' && $user->rights->askpricesupplier->creer) + { + $object->socid = $socid; + $object->fetch_thirdparty(); + + $date_delivery = dol_mktime(12, 0, 0, GETPOST('liv_month'), GETPOST('liv_day'), GETPOST('liv_year')); + + if ($socid < 1) { + setEventMessage($langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("Customer")), 'errors'); + $action = 'create'; + $error ++; + } + + if (! $error) + { + $db->begin(); + + // Si on a selectionne une demande a copier, on realise la copie + if (GETPOST('createmode') == 'copy' && GETPOST('copie_askpricesupplier')) + { + if ($object->fetch(GETPOST('copie_askpricesupplier')) > 0) { + $object->ref = GETPOST('ref'); + $object->date_livraison = $date_delivery; + $object->shipping_method_id = GETPOST('shipping_method_id', 'int'); + $object->cond_reglement_id = GETPOST('cond_reglement_id'); + $object->mode_reglement_id = GETPOST('mode_reglement_id'); + $object->fk_account = GETPOST('fk_account', 'int'); + $object->remise_percent = GETPOST('remise_percent'); + $object->remise_absolue = GETPOST('remise_absolue'); + $object->socid = GETPOST('socid'); + $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_askpricesupplier')), 'errors'); + } + } else { + $object->ref = GETPOST('ref'); + $object->date_livraison = $date_delivery; + $object->demand_reason_id = GETPOST('demand_reason_id'); + $object->shipping_method_id = GETPOST('shipping_method_id', 'int'); + $object->cond_reglement_id = GETPOST('cond_reglement_id'); + $object->mode_reglement_id = GETPOST('mode_reglement_id'); + $object->fk_account = GETPOST('fk_account', 'int'); + $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]); + } + } + + // Fill array 'array_options' with data from add form + $ret = $extrafields->setOptionalsFromPost($extralabels, $object); + if ($ret < 0) { + $error ++; + $action = 'create'; + } + } + + if (! $error) + { + if ($origin && $originid) + { + $element = 'comm/askpricesupplier'; + $subelement = 'askpricesupplier'; + + $object->origin = $origin; + $object->origin_id = $originid; + + // Possibility to add external linked objects with hooks + $object->linked_objects [$object->origin] = $object->origin_id; + if (is_array($_POST['other_linked_objects']) && ! empty($_POST['other_linked_objects'])) { + $object->linked_objects = array_merge($object->linked_objects, $_POST['other_linked_objects']); + } + + $id = $object->create($user); + if ($id > 0) + { + dol_include_once('/' . $element . '/class/' . $subelement . '.class.php'); + + $classname = ucfirst($subelement); + $srcobject = new $classname($db); + + dol_syslog("Try to find source object origin=" . $object->origin . " originid=" . $object->origin_id . " to add lines"); + $result = $srcobject->fetch($object->origin_id); + + if ($result > 0) + { + $lines = $srcobject->lines; + if (empty($lines) && method_exists($srcobject, 'fetch_lines')) + { + $srcobject->fetch_lines(); + $lines = $srcobject->lines; + } + + $fk_parent_line=0; + $num=count($lines); + for ($i=0;$i<$num;$i++) + { + $label=(! empty($lines[$i]->label)?$lines[$i]->label:''); + $desc=(! empty($lines[$i]->desc)?$lines[$i]->desc:$lines[$i]->libelle); + + // Positive line + $product_type = ($lines[$i]->product_type ? $lines[$i]->product_type : 0); + + // Reset fk_parent_line for no child products and special product + if (($lines[$i]->product_type != 9 && empty($lines[$i]->fk_parent_line)) || $lines[$i]->product_type == 9) { + $fk_parent_line = 0; + } + + // Extrafields + if (empty($conf->global->MAIN_EXTRAFIELDS_DISABLED) && method_exists($lines[$i], 'fetch_optionals')) { + $lines[$i]->fetch_optionals($lines[$i]->rowid); + $array_option = $lines[$i]->array_options; + } + + $tva_tx=get_default_tva($mysoc, $object->thirdparty); + + $result = $object->addline($desc, $lines[$i]->subprice, $lines[$i]->qty, $tva_tx, $lines[$i]->localtax1_tx, $lines[$i]->localtax2_tx, $lines[$i]->fk_product, $lines[$i]->remise_percent, 'HT', 0, $lines[$i]->info_bits, $product_type, $lines[$i]->rang, $lines[$i]->special_code, $fk_parent_line, $lines[$i]->fk_fournprice, $lines[$i]->pa_ht, $label, $array_option); + + if ($result > 0) { + $lineid = $result; + } else { + $lineid = 0; + $error ++; + break; + } + + // Defined the new fk_parent_line + if ($result > 0 && $lines[$i]->product_type == 9) { + $fk_parent_line = $result; + } + } + + // Hooks + $parameters = array('objFrom' => $srcobject); + $reshook = $hookmanager->executeHooks('createFrom', $parameters, $object, $action); // Note that $action and $object may have been + // modified by hook + if ($reshook < 0) + $error ++; + } else { + setEventMessages($srcobject->error, $srcobject->errors, 'errors'); + $error ++; + } + } else { + setEventMessages($object->error, $object->errors, 'errors'); + $error ++; + } + } // Standard creation + else + { + $id = $object->create($user); + } + + if ($id > 0) + { + if (! $error) + { + $db->commit(); + + // Define output language + if (empty($conf->global->MAIN_DISABLE_PDF_AUTOUPDATE)) + { + $outputlangs = $langs; + $newlang = ''; + if ($conf->global->MAIN_MULTILANGS && empty($newlang) && GETPOST('lang_id')) $newlang = GETPOST('lang_id','alpha'); + if ($conf->global->MAIN_MULTILANGS && empty($newlang)) $newlang = $object->thirdparty->default_lang; + if (! empty($newlang)) { + $outputlangs = new Translate("", $conf); + $outputlangs->setDefaultLang($newlang); + } + $model=$object->modelpdf; + + $ret = $object->fetch($id); // Reload to get new records + $result=$object->generateDocument($model, $outputlangs, $hidedetails, $hidedesc, $hideref); + if ($result < 0) dol_print_error($db,$result); + } + + header('Location: ' . $_SERVER["PHP_SELF"] . '?id=' . $id); + exit(); + } + else + { + $db->rollback(); + $action='create'; + } + } + else + { + setEventMessages($object->error, $object->errors, 'errors'); + $db->rollback(); + $action='create'; + } + } + } + } + + // Reopen proposal + else if ($action == 'confirm_reopen' && $user->rights->askpricesupplier->cloturer && ! GETPOST('cancel')) { + // prevent browser refresh from reopening proposal several times + if ($object->statut == 2 || $object->statut == 3 || $object->statut == 4) { + $object->reopen($user, 1); + } + } + + // Close proposal + else if ($action == 'setstatut' && $user->rights->askpricesupplier->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')); + } + } + } + + include DOL_DOCUMENT_ROOT.'/core/actions_printing.inc.php'; + + + /* + * Send mail + */ + + // Actions to send emails + $actiontypecode='AC_ASKPRICE'; + $trigger_name='ASKPRICESUPPLIER_SENTBYMAIL'; + $paramname='id'; + $mode='emailfromaskpricesupplier'; + include DOL_DOCUMENT_ROOT.'/core/actions_sendmails.inc.php'; + + + + // Go back to draft + if ($action == 'modif' && $user->rights->askpricesupplier->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->thirdparty->default_lang); + $outputlangs->setDefaultLang($newlang); + } + $ret = $object->fetch($id); // Reload to get new records + $object->generateDocument($object->modelpdf, $outputlangs, $hidedetails, $hidedesc, $hideref); + } + } + + else if ($action == "setabsolutediscount" && $user->rights->askpricesupplier->creer) { + if ($_POST["remise_id"]) { + if ($object->id > 0) { + $result = $object->insert_discount($_POST["remise_id"]); + if ($result < 0) { + setEventMessage($object->error, 'errors'); + } + } + } + } + + // Add line + else if ($action == 'addline' && $user->rights->askpricesupplier->creer) { + + // Set if we used free entry or predefined product + $predef=''; + $product_desc=(GETPOST('dp_desc')?GETPOST('dp_desc'):''); + $price_ht = GETPOST('price_ht'); + + if (GETPOST('prod_entry_mode') == 'free') + { + $idprod=0; + $tva_tx = (GETPOST('tva_tx') ? GETPOST('tva_tx') : 0); + } + else + { + $idprod=GETPOST('idprod', 'int'); + $tva_tx = ''; + } + + $qty = GETPOST('qty' . $predef); + $remise_percent = GETPOST('remise_percent' . $predef); + + // Extrafields + $extrafieldsline = new ExtraFields($db); + $extralabelsline = $extrafieldsline->fetch_name_optionals_label($object->table_element_line); + $array_option = $extrafieldsline->getOptionalsFromPost($extralabelsline, $predef); + // Unset extrafield + if (is_array($extralabelsline)) { + // Get extra fields + foreach ($extralabelsline as $key => $value) { + unset($_POST["options_" . $key]); + } + } + + if (GETPOST('prod_entry_mode') == 'free' && empty($idprod) && GETPOST('type') < 0) { + setEventMessage($langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("Type")), 'errors'); + $error ++; + } + + if (GETPOST('prod_entry_mode') == 'free' && empty($idprod) && $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 (GETPOST('prod_entry_mode') == 'free' && empty($idprod) && empty($product_desc)) { + setEventMessage($langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("Description")), 'errors'); + $error ++; + } + + if (! $error && ($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'); + + $db->begin(); + + // 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 + $tva_tx = get_default_tva($mysoc, $object->thirdparty, $prod->id); + $tva_npr = get_default_npr($mysoc, $object->thirdparty, $prod->id); + + //On garde le prix indiqué dans l'input pour la demande de prix fournisseur + //$pu_ht = $prod->price; + $pu_ht = price2num($price_ht, 'MU'); + //$pu_ttc = $prod->price_ttc; + $pu_ttc = price2num($pu_ht * (1 + ($tva_tx / 100)), 'MU'); + + $price_min = $prod->price_min; + $price_base_type = $prod->price_base_type; + + // On defini prix unitaire + if (! empty($conf->global->PRODUIT_MULTIPRICES) && $object->thirdparty->price_level) + { + $pu_ht = $prod->multiprices[$object->thirdparty->price_level]; + $pu_ttc = $prod->multiprices_ttc[$object->thirdparty->price_level]; + $price_min = $prod->multiprices_min[$object->thirdparty->price_level]; + $price_base_type = $prod->multiprices_base_type[$object->thirdparty->price_level]; + if (isset($prod->multiprices_tva_tx[$object->thirdparty->price_level])) $tva_tx=$prod->multiprices_tva_tx[$object->thirdparty->price_level]; + if (isset($prod->multiprices_recuperableonly[$object->thirdparty->price_level])) $tva_npr=$prod->multiprices_recuperableonly[$object->thirdparty->price_level]; + } + elseif (! empty($conf->global->PRODUIT_CUSTOMER_PRICES)) + { + require_once DOL_DOCUMENT_ROOT . '/product/class/productcustomerprice.class.php'; + + $prodcustprice = new Productcustomerprice($db); + + $filter = array('t.fk_product' => $prod->id,'t.fk_soc' => $object->thirdparty->id); + + $result = $prodcustprice->fetch_all('', '', 0, 0, $filter); + if ($result) { + if (count($prodcustprice->lines) > 0) { + $pu_ht = price($prodcustprice->lines [0]->price); + $pu_ttc = price($prodcustprice->lines [0]->price_ttc); + $price_base_type = $prodcustprice->lines [0]->price_base_type; + $prod->tva_tx = $prodcustprice->lines [0]->tva_tx; + } + } + } + + // if price ht is forced (ie: calculated by margin rate and cost price) + if (! empty($price_ht)) { + $pu_ht = price2num($price_ht, 'MU'); + $pu_ttc = price2num($pu_ht * (1 + ($tva_tx / 100)), 'MU'); + } + + // 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). + elseif ($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->thirdparty->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' . $predef) ? GETPOST('fournprice' . $predef) : ''); + $buyingprice = (GETPOST('buying_price' . $predef) ? GETPOST('buying_price' . $predef) : ''); + + // Local Taxes + $localtax1_tx = get_localtax($tva_tx, 1, $object->thirdparty); + $localtax2_tx = get_localtax($tva_tx, 2, $object->thirdparty); + + $info_bits = 0; + if ($tva_npr) + $info_bits |= 0x01; + + if (! empty($price_min) && (price2num($pu_ht) * (1 - price2num($remise_percent) / 100) < price2num($price_min))) { + $mesg = $langs->trans("CantBeLessThanMinPrice", price(price2num($price_min, 'MU'), 0, $langs, 0, 0, - 1, $conf->currency)); + setEventMessage($mesg, 'errors'); + } else { + // Insert line + $ref_fourn = GETPOST('fourn_ref'); + $result = $object->addline($desc, $pu_ht, $qty, $tva_tx, $localtax1_tx, $localtax2_tx, $idprod, $remise_percent, $price_base_type, $pu_ttc, $info_bits, $type, - 1, 0, GETPOST('fk_parent_line'), $fournprice, $buyingprice, $label, $array_option, $ref_fourn); + + if ($result > 0) { + $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->thirdparty->default_lang); + $outputlangs->setDefaultLang($newlang); + } + $ret = $object->fetch($id); // Reload to get new records + $object->generateDocument($object->modelpdf, $outputlangs, $hidedetails, $hidedesc, $hideref); + } + + unset($_POST['prod_entry_mode']); + + unset($_POST['qty']); + unset($_POST['type']); + 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']); + unset($_POST['np_marginRate']); + unset($_POST['np_markRate']); + unset($_POST['dp_desc']); + unset($_POST['idprod']); + + } else { + $db->rollback(); + + setEventMessage($object->error, 'errors'); + } + } + } + } + + // Mise a jour d'une ligne dans la demande de prix + else if ($action == 'updateligne' && $user->rights->askpricesupplier->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->thirdparty); + $localtax2_rate = get_localtax($vat_rate, 2, $object->thirdparty); + $pu_ht = GETPOST('price_ht') ? GETPOST('price_ht') : 0; + + // Add buying price + $fournprice = (GETPOST('fournprice') ? GETPOST('fournprice') : ''); + $buyingprice = (GETPOST('buying_price') ? GETPOST('buying_price') : ''); + + // Extrafields + $extrafieldsline = new ExtraFields($db); + $extralabelsline = $extrafieldsline->fetch_name_optionals_label($object->table_element_line); + $array_option = $extrafieldsline->getOptionalsFromPost($extralabelsline); + // Unset extrafield + if (is_array($extralabelsline)) { + // Get extra fields + foreach ($extralabelsline as $key => $value) { + unset($_POST["options_" . $key]); + } + } + + // Define special_code for special lines + $special_code=GETPOST('special_code'); + 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->thirdparty->price_level)) + $price_min = $product->multiprices_min [$object->thirdparty->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", price(price2num($price_min, 'MU'), 0, $langs, 0, 0, - 1, $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) { + $db->begin(); + $ref_fourn = GETPOST('fourn_ref'); + $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, $array_option, $ref_fourn); + + if ($result >= 0) { + $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->thirdparty->default_lang); + $outputlangs->setDefaultLang($newlang); + } + $ret = $object->fetch($id); // Reload to get new records + $object->generateDocument($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 { + $db->rollback(); + + setEventMessage($object->error, 'errors'); + } + } + } + + else if ($action == 'updateligne' && $user->rights->askpricesupplier->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->askpricesupplier->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->thirdparty->default_lang); + $outputlangs->setDefaultLang($newlang); + } + $ret = $object->fetch($id); // Reload to get new records + $result = $object->generateDocument($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->askpricesupplier->creer) { + if ($object->id > 0) { + require_once DOL_DOCUMENT_ROOT . '/core/lib/files.lib.php'; + + $langs->load("other"); + $upload_dir = $conf->askpricesupplier->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->askpricesupplier->creer) { + $object->setProject($_POST['projectid']); + } + + // Delai de livraison + else if ($action == 'setavailability' && $user->rights->askpricesupplier->creer) { + $result = $object->availability($_POST['availability_id']); + } + + // Conditions de reglement + else if ($action == 'setconditions' && $user->rights->askpricesupplier->creer) { + $result = $object->setPaymentTerms(GETPOST('cond_reglement_id', 'int')); + } + + else if ($action == 'setremisepercent' && $user->rights->askpricesupplier->creer) { + $result = $object->set_remise_percent($user, $_POST['remise_percent']); + } + + else if ($action == 'setremiseabsolue' && $user->rights->askpricesupplier->creer) { + $result = $object->set_remise_absolue($user, $_POST['remise_absolue']); + } + + // Mode de reglement + else if ($action == 'setmode' && $user->rights->askpricesupplier->creer) { + $result = $object->setPaymentMethods(GETPOST('mode_reglement_id', 'int')); + } + + /* + * Ordonnancement des lignes + */ + + else if ($action == 'up' && $user->rights->askpricesupplier->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->thirdparty->default_lang); + $outputlangs->setDefaultLang($newlang); + } + $ret = $object->fetch($id); // Reload to get new records + $object->generateDocument($object->modelpdf, $outputlangs, $hidedetails, $hidedesc, $hideref); + } + + header('Location: ' . $_SERVER["PHP_SELF"] . '?id=' . $id . '#' . GETPOST('rowid')); + exit(); + } + + else if ($action == 'down' && $user->rights->askpricesupplier->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->thirdparty->default_lang); + $outputlangs->setDefaultLang($newlang); + } + $ret = $object->fetch($id); // Reload to get new records + $object->generateDocument($object->modelpdf, $outputlangs, $hidedetails, $hidedesc, $hideref); + } + + header('Location: ' . $_SERVER["PHP_SELF"] . '?id=' . $id . '#' . GETPOST('rowid')); + exit(); + } else if ($action == 'update_extras') { + // Fill array 'array_options' with data from update form + $extralabels = $extrafields->fetch_name_optionals_label($object->table_element); + $ret = $extrafields->setOptionalsFromPost($extralabels, $object, GETPOST('attribute')); + if ($ret < 0) + $error ++; + + if (! $error) { + // Actions on extra fields (by external module or standard code) + $hookmanager->initHooks(array('askpricesupplierdao')); + $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)) { + $result = $object->insertExtraFields(); + if ($result < 0) { + $error ++; + } + } else if ($reshook < 0) + $error ++; + } + + if ($error) + $action = 'edit_extras'; + } +} + + +/* + * View + */ + +llxHeader('', $langs->trans('CommRequests'), 'EN:Ask_Price_Supplier|FR:Demande_de_prix_fournisseur'); + +$form = new Form($db); +$formother = new FormOther($db); +$formfile = new FormFile($db); +$formaskpricesupplier = new FormAskPriceSupplier($db); +$companystatic = new Societe($db); + +$now = dol_now(); + +// Add new askprice +if ($action == 'create') +{ + print_fiche_titre($langs->trans("NewAskPrice")); + + $soc = new Societe($db); + if ($socid > 0) + $res = $soc->fetch($socid); + + // Load objectsrc + if (! empty($origin) && ! empty($originid)) + { + $element = 'comm/askpricesupplier'; + $subelement = 'askpricesupplier'; + + dol_include_once('/' . $element . '/class/' . $subelement . '.class.php'); + + $classname = ucfirst($subelement); + $objectsrc = new $classname($db); + $objectsrc->fetch($originid); + if (empty($objectsrc->lines) && method_exists($objectsrc, 'fetch_lines')) + { + $objectsrc->fetch_lines(); + } + $objectsrc->fetch_thirdparty(); + + $projectid = (! empty($objectsrc->fk_project) ? $objectsrc->fk_project : ''); + $soc = $objectsrc->thirdparty; + + $cond_reglement_id = (! empty($objectsrc->cond_reglement_id)?$objectsrc->cond_reglement_id:(! empty($soc->cond_reglement_id)?$soc->cond_reglement_id:1)); + $mode_reglement_id = (! empty($objectsrc->mode_reglement_id)?$objectsrc->mode_reglement_id:(! empty($soc->mode_reglement_id)?$soc->mode_reglement_id:0)); + $remise_percent = (! empty($objectsrc->remise_percent)?$objectsrc->remise_percent:(! empty($soc->remise_percent)?$soc->remise_percent:0)); + $remise_absolue = (! empty($objectsrc->remise_absolue)?$objectsrc->remise_absolue:(! empty($soc->remise_absolue)?$soc->remise_absolue:0)); + + // Replicate extrafields + $objectsrc->fetch_optionals($originid); + $object->array_options = $objectsrc->array_options; + + } + + $object = new AskPriceSupplier($db); + + print '<form name="addprop" action="' . $_SERVER["PHP_SELF"] . '" method="POST">'; + print '<input type="hidden" name="token" value="' . $_SESSION ['newtoken'] . '">'; + print '<input type="hidden" name="action" value="add">'; + if ($origin != 'project' && $originid) { + print '<input type="hidden" name="origin" value="' . $origin . '">'; + print '<input type="hidden" name="originid" value="' . $originid . '">'; + } + + dol_fiche_head(); + + print '<table class="border" width="100%">'; + + // Reference + print '<tr><td class="fieldrequired">' . $langs->trans('Ref') . '</td><td colspan="2">' . $langs->trans("Draft") . '</td></tr>'; + + // Third party + print '<tr>'; + print '<td class="fieldrequired">' . $langs->trans('Supplier') . '</td>'; + if ($socid > 0) { + print '<td colspan="2">'; + print $soc->getNomUrl(1); + print '<input type="hidden" name="socid" value="' . $soc->id . '">'; + print '</td>'; + } else { + print '<td colspan="2">'; + print $form->select_company('', 'socid', 's.fournisseur = 1', 1); + print '</td>'; + } + print '</tr>' . "\n"; + + // Terms of payment + print '<tr><td class="nowrap">' . $langs->trans('PaymentConditionsShort') . '</td><td colspan="2">'; + $form->select_conditions_paiements($soc->cond_reglement_id, 'cond_reglement_id', -1, 1); + print '</td></tr>'; + + // Mode of payment + print '<tr><td>' . $langs->trans('PaymentMode') . '</td><td colspan="2">'; + $form->select_types_paiements($soc->mode_reglement_id, 'mode_reglement_id'); + print '</td></tr>'; + + // Bank Account + if (! empty($conf->global->BANK_ASK_PAYMENT_BANK_DURING_PROPOSAL) && $conf->banque->enabled) { + print '<tr><td>' . $langs->trans('BankAccount') . '</td><td colspan="2">'; + $form->select_comptes($fk_account, 'fk_account', 0, '', 1); + print '</td></tr>'; + } + + // Shipping Method + if (! empty($conf->expedition->enabled)) { + print '<tr><td>' . $langs->trans('SendingMethod') . '</td><td colspan="2">'; + print $form->selectShippingMethod($shipping_method_id, 'shipping_method_id', '', 1); + print '</td></tr>'; + } + + // Delivery date (or manufacturing) + print '<tr><td>' . $langs->trans("DeliveryDate") . '</td>'; + print '<td colspan="2">'; + 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_', '', '', '', "addask"); + } else { + $form->select_date(-1, 'liv_', '', '', '', "addask", 1, 1); + } + print '</td></tr>'; + + + // Model + print '<tr>'; + print '<td>' . $langs->trans("DefaultModel") . '</td>'; + print '<td colspan="2">'; + $liste = ModelePDFAskPriceSupplier::liste_modeles($db); + print $form->selectarray('model', $liste, ($conf->global->ASKPRICESUPPLIER_ADDON_PDF_ODT_DEFAULT ? $conf->global->ASKPRICESUPPLIER_ADDON_PDF_ODT_DEFAULT : $conf->global->ASKPRICESUPPLIER_ADDON_PDF)); + print "</td></tr>"; + + // Project + if (! empty($conf->projet->enabled) && $socid > 0) { + + $formproject = new FormProjets($db); + + $projectid = 0; + if ($origin == 'project') + $projectid = ($originid ? $originid : 0); + + print '<tr>'; + print '<td valign="top">' . $langs->trans("Project") . '</td><td colspan="2">'; + + $numprojet = $formproject->select_projects($soc->id, $projectid); + if ($numprojet == 0) { + $langs->load("projects"); + print ' <a href="../projet/card.php?socid=' . $soc->id . '&action=create">' . $langs->trans("AddProject") . '</a>'; + } + print '</td>'; + print '</tr>'; + } + + + // 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)) { + print $object->showOptionals($extrafields, 'edit'); + } + + + // Lines from source + if (! empty($origin) && ! empty($originid) && is_object($objectsrc)) + { + // TODO for compatibility + if ($origin == 'contrat') { + // Calcul contrat->price (HT), contrat->total (TTC), contrat->tva + $objectsrc->remise_absolue = $remise_absolue; + $objectsrc->remise_percent = $remise_percent; + $objectsrc->update_price(1, - 1, 1); + } + + print "\n<!-- " . $classname . " info -->"; + print "\n"; + print '<input type="hidden" name="amount" value="' . $objectsrc->total_ht . '">' . "\n"; + print '<input type="hidden" name="total" value="' . $objectsrc->total_ttc . '">' . "\n"; + print '<input type="hidden" name="tva" value="' . $objectsrc->total_tva . '">' . "\n"; + print '<input type="hidden" name="origin" value="' . $objectsrc->element . '">'; + print '<input type="hidden" name="originid" value="' . $objectsrc->id . '">'; + + print '<tr><td>' . $langs->trans('CommRequest') . '</td><td colspan="2">' . $objectsrc->getNomUrl(1) . '</td></tr>'; + print '<tr><td>' . $langs->trans('TotalHT') . '</td><td colspan="2">' . price($objectsrc->total_ht) . '</td></tr>'; + print '<tr><td>' . $langs->trans('TotalVAT') . '</td><td colspan="2">' . price($objectsrc->total_tva) . "</td></tr>"; + if ($mysoc->localtax1_assuj == "1" || $objectsrc->total_localtax1 != 0 ) // Localtax1 + { + print '<tr><td>' . $langs->transcountry("AmountLT1", $mysoc->country_code) . '</td><td colspan="2">' . price($objectsrc->total_localtax1) . "</td></tr>"; + } + + if ($mysoc->localtax2_assuj == "1" || $objectsrc->total_localtax2 != 0) // Localtax2 + { + print '<tr><td>' . $langs->transcountry("AmountLT2", $mysoc->country_code) . '</td><td colspan="2">' . price($objectsrc->total_localtax2) . "</td></tr>"; + } + print '<tr><td>' . $langs->trans('TotalTTC') . '</td><td colspan="2">' . price($objectsrc->total_ttc) . "</td></tr>"; + } + + print "</table>\n"; + + + /* + * Combobox pour la fonction de copie + */ + + if (empty($conf->global->ASKPRICESUPPLIER_CLONE_ON_CREATE_PAGE)) print '<input type="hidden" name="createmode" value="empty">'; + + if (! empty($conf->global->ASKPRICESUPPLIER_CLONE_ON_CREATE_PAGE) || ! empty($conf->global->PRODUCT_SHOW_WHEN_CREATE)) print '<br><table>'; + if (! empty($conf->global->ASKPRICESUPPLIER_CLONE_ON_CREATE_PAGE)) + { + // For backward compatibility + print '<tr>'; + print '<td><input type="radio" name="createmode" value="copy"></td>'; + print '<td>' . $langs->trans("CopyAskFrom") . ' </td>'; + print '<td>'; + $liste_ask = array(); + $liste_ask [0] = ''; + + $sql = "SELECT p.rowid as id, p.ref, s.nom"; + $sql .= " FROM " . MAIN_DB_PREFIX . "askpricesupplier 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); + $askPriceSupplierRefAndSocName = $row [1] . " - " . $row [2]; + $liste_ask [$row [0]] = $askPriceSupplierRefAndSocName; + $i ++; + } + print $form->selectarray("copie_askpricesupplier", $liste_ask, 0); + } else { + dol_print_error($db); + } + print '</td></tr>'; + + if (! empty($conf->global->PRODUCT_SHOW_WHEN_CREATE)) + print '<tr><td colspan="3"> </td></tr>'; + + print '<tr><td valign="top"><input type="radio" name="createmode" value="empty" checked="checked"></td>'; + print '<td valign="top" colspan="2">' . $langs->trans("CreateEmptyAsk") . '</td></tr>'; + } + + if (! empty($conf->global->PRODUCT_SHOW_WHEN_CREATE)) + { + print '<tr><td colspan="3">'; + if (! empty($conf->product->enabled) || ! empty($conf->service->enabled)) { + $lib = $langs->trans("ProductsAndServices"); + + print '<table class="border" width="100%">'; + print '<tr>'; + print '<td>' . $lib . '</td>'; + print '<td>' . $langs->trans("Qty") . '</td>'; + print '<td>' . $langs->trans("ReductionShort") . '</td>'; + print '</tr>'; + for($i = 1; $i <= $conf->global->PRODUCT_SHOW_WHEN_CREATE; $i ++) { + print '<tr><td>'; + // 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 '</td>'; + print '<td><input type="text" size="2" name="qty' . $i . '" value="1"></td>'; + print '<td><input type="text" size="2" name="remise' . $i . '" value="' . $soc->remise_percent . '">%</td>'; + print '</tr>'; + } + print "</table>"; + } + print '</td></tr>'; + } + if (! empty($conf->global->ASKPRICESUPPLIER_CLONE_ON_CREATE_PAGE) || ! empty($conf->global->PRODUCT_SHOW_WHEN_CREATE)) print '</table>'; + + dol_fiche_end(); + + print '<div class="center">'; + print '<input type="submit" class="button" value="' . $langs->trans("CreateDraft") . '">'; + print ' '; + print '<input type="button" class="button" value="' . $langs->trans("Cancel") . '" onClick="javascript:history.go(-1)">'; + print '</div>'; + + print "</form>"; + + + // Show origin lines + if (! empty($origin) && ! empty($originid) && is_object($objectsrc)) { + print '<br>'; + + $title = $langs->trans('ProductsAndServices'); + print_titre($title); + + print '<table class="noborder" width="100%">'; + + $objectsrc->printOriginLinesList(); + + print '</table>'; + } + +} else { + /* + * Show object in view mode + */ + + $soc = new Societe($db); + $soc->fetch($object->socid); + + $head = askpricesupplier_prepare_head($object); + dol_fiche_head($head, 'comm', $langs->trans('CommRequest'), 0, 'askpricesupplier'); + + $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.fournisseur=1'))); + // Paiement incomplet. On demande si motif = escompte ou autre + $formconfirm = $form->formconfirm($_SERVER["PHP_SELF"] . '?id=' . $object->id, $langs->trans('CloneAsk'), $langs->trans('ConfirmCloneAsk', $object->ref), 'confirm_clone', $formquestion, 'yes', 1); + } + + // Confirm delete + else if ($action == 'delete') { + $formconfirm = $form->formconfirm($_SERVER["PHP_SELF"] . '?id=' . $object->id, $langs->trans('DeleteAsk'), $langs->trans('ConfirmDeleteAsk', $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('ConfirmReOpenAsk', $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 askprice + 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 ++; + setEventMessage($object->error, 'errors'); + } + } else { + $numref = $object->ref; + } + + $text = $langs->trans('ConfirmValidateAsk', $numref); + if (! empty($conf->notification->enabled)) { + require_once DOL_DOCUMENT_ROOT . '/core/class/notify.class.php'; + $notify = new Notify($db); + $text .= '<br>'; + $text .= $notify->confirmMessage('ASKPRICESUPPLIER_VALIDATE', $object->socid); + } + + if (! $error) + $formconfirm = $form->formconfirm($_SERVER["PHP_SELF"] . '?id=' . $object->id, $langs->trans('ValidateAsk'), $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 '<table class="border" width="100%">'; + + $linkback = '<a href="' . DOL_URL_ROOT . '/comm/askpricesupplier/list.php' . (! empty($socid) ? '?socid=' . $socid : '') . '">' . $langs->trans("BackToList") . '</a>'; + + // Ref + print '<tr><td>' . $langs->trans('Ref') . '</td><td colspan="5">'; + print $form->showrefnav($object, 'ref', $linkback, 1, 'ref', 'ref', ''); + print '</td></tr>'; + + // Company + print '<tr><td>' . $langs->trans('Supplier') . '</td><td colspan="5">' . $soc->getNomUrl(1) . '</td>'; + print '</tr>'; + + // Payment term + print '<tr><td>'; + print '<table class="nobordernopadding" width="100%"><tr><td>'; + print $langs->trans('PaymentConditionsShort'); + print '</td>'; + if ($action != 'editconditions' && ! empty($object->brouillon)) + print '<td align="right"><a href="' . $_SERVER["PHP_SELF"] . '?action=editconditions&id=' . $object->id . '">' . img_edit($langs->transnoentitiesnoconv('SetConditions'), 1) . '</a></td>'; + print '</tr></table>'; + print '</td><td colspan="3">'; + if ($action == 'editconditions') { + $form->form_conditions_reglement($_SERVER['PHP_SELF'] . '?id=' . $object->id, $object->cond_reglement_id, 'cond_reglement_id', 1); + } else { + $form->form_conditions_reglement($_SERVER['PHP_SELF'] . '?id=' . $object->id, $object->cond_reglement_id, 'none', 1); + } + print '</td>'; + print '</tr>'; + + // Delivery date + $langs->load('deliveries'); + print '<tr><td>'; + print '<table class="nobordernopadding" width="100%"><tr><td>'; + print $langs->trans('DeliveryDate'); + print '</td>'; + if ($action != 'editdate_livraison' && ! empty($object->brouillon)) + print '<td align="right"><a href="' . $_SERVER["PHP_SELF"] . '?action=editdate_livraison&id=' . $object->id . '">' . img_edit($langs->transnoentitiesnoconv('SetDeliveryDate'), 1) . '</a></td>'; + print '</tr></table>'; + print '</td><td colspan="3">'; + if ($action == 'editdate_livraison') { + print '<form name="editdate_livraison" action="' . $_SERVER["PHP_SELF"] . '?id=' . $object->id . '" method="post">'; + print '<input type="hidden" name="token" value="' . $_SESSION ['newtoken'] . '">'; + print '<input type="hidden" name="action" value="setdate_livraison">'; + $form->select_date($object->date_livraison, 'liv_', '', '', '', "editdate_livraison"); + print '<input type="submit" class="button" value="' . $langs->trans('Modify') . '">'; + print '</form>'; + } else { + print dol_print_date($object->date_livraison, 'daytext'); + } + print '</td>'; + print '</tr>'; + + // Payment mode + print '<tr>'; + print '<td width="25%">'; + print '<table class="nobordernopadding" width="100%"><tr><td>'; + print $langs->trans('PaymentMode'); + print '</td>'; + if ($action != 'editmode' && ! empty($object->brouillon)) + print '<td align="right"><a href="' . $_SERVER["PHP_SELF"] . '?action=editmode&id=' . $object->id . '">' . img_edit($langs->transnoentitiesnoconv('SetMode'), 1) . '</a></td>'; + print '</tr></table>'; + print '</td><td colspan="3">'; + 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 '</td></tr>'; + + // Project + if (! empty($conf->projet->enabled)) { + $langs->load("projects"); + print '<tr><td>'; + print '<table class="nobordernopadding" width="100%"><tr><td>'; + print $langs->trans('Project') . '</td>'; + if ($user->rights->askpricesupplier->creer) { + if ($action != 'classify') + print '<td align="right"><a href="' . $_SERVER['PHP_SELF'] . '?action=classify&id=' . $object->id . '">' . img_edit($langs->transnoentitiesnoconv('SetProject')) . '</a></td>'; + print '</tr></table>'; + print '</td><td colspan="3">'; + 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 '</td></tr>'; + } else { + print '</td></tr></table>'; + if (! empty($object->fk_project)) { + print '<td colspan="3">'; + $proj = new Project($db); + $proj->fetch($object->fk_project); + print '<a href="../projet/card.php?id=' . $object->fk_project . '" title="' . $langs->trans('ShowProject') . '">'; + print $proj->ref; + print '</a>'; + print '</td>'; + } else { + print '<td colspan="3"> </td>'; + } + } + print '</tr>'; + } + + + if ($soc->outstanding_limit) + { + // Outstanding Bill + print '<tr><td>'; + print $langs->trans('OutstandingBill'); + print '</td><td align=right colspan=3>'; + print price($soc->get_OutstandingBill()) . ' / '; + print price($soc->outstanding_limit, 0, '', 1, - 1, - 1, $conf->currency); + print '</td>'; + print '</tr>'; + } + + if (! empty($conf->global->BANK_ASK_PAYMENT_BANK_DURING_PROPOSAL) && $conf->banque->enabled) + { + // Bank Account + print '<tr><td>'; + print '<table width="100%" class="nobordernopadding"><tr><td>'; + print $langs->trans('BankAccount'); + print '</td>'; + if ($action != 'editbankaccount' && $user->rights->askpricesupplier->creer) + print '<td align="right"><a href="'.$_SERVER["PHP_SELF"].'?action=editbankaccount&id='.$object->id.'">'.img_edit($langs->trans('SetBankAccount'),1).'</a></td>'; + print '</tr></table>'; + print '</td><td colspan="3">'; + if ($action == 'editbankaccount') { + $form->formSelectAccount($_SERVER['PHP_SELF'].'?id='.$object->id, $object->fk_account, 'fk_account', 1); + } else { + $form->formSelectAccount($_SERVER['PHP_SELF'].'?id='.$object->id, $object->fk_account, 'none'); + } + print '</td>'; + print '</tr>'; + } + + // Other attributes + $cols = 3; + include DOL_DOCUMENT_ROOT . '/core/tpl/extrafields_view.tpl.php'; + + // Amount HT + print '<tr><td height="10" width="25%">' . $langs->trans('AmountHT') . '</td>'; + print '<td align="right" class="nowrap"><b>' . price($object->total_ht, '', $langs, 0, - 1, - 1, $conf->currency) . '</b></td>'; + print '<td></td>'; + + // Margin Infos + if (! empty($conf->margin->enabled)) { + print '<td valign="top" width="50%" rowspan="4">'; + $object->displayMarginInfos(); + print '</td>'; + } + print '</tr>'; + + // Amount VAT + print '<tr><td height="10">' . $langs->trans('AmountVAT') . '</td>'; + print '<td align="right" class="nowrap">' . price($object->total_tva, '', $langs, 0, - 1, - 1, $conf->currency) . '</td>'; + print '<td></td></tr>'; + + // Amount Local Taxes + if ($mysoc->localtax1_assuj == "1" || $object->total_localtax1 != 0) // Localtax1 + { + print '<tr><td height="10">' . $langs->transcountry("AmountLT1", $mysoc->country_code) . '</td>'; + print '<td align="right" class="nowrap">' . price($object->total_localtax1, '', $langs, 0, - 1, - 1, $conf->currency) . '</td>'; + print '<td></td></tr>'; + } + if ($mysoc->localtax2_assuj == "1" || $object->total_localtax2 != 0) // Localtax2 + { + print '<tr><td height="10">' . $langs->transcountry("AmountLT2", $mysoc->country_code) . '</td>'; + print '<td align="right" class="nowrap">' . price($object->total_localtax2, '', $langs, 0, - 1, - 1, $conf->currency) . '</td>'; + print '<td></td></tr>'; + } + + // Amount TTC + print '<tr><td height="10">' . $langs->trans('AmountTTC') . '</td>'; + print '<td align="right" class="nowrap">' . price($object->total_ttc, '', $langs, 0, - 1, - 1, $conf->currency) . '</td>'; + print '<td></td></tr>'; + + // Statut + print '<tr><td height="10">' . $langs->trans('Status') . '</td><td align="left" colspan="2">' . $object->getLibStatut(4) . '</td></tr>'; + + print '</table><br>'; + + 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 + */ + + // Show object lines + $result = $object->getLinesArray(); + + print ' <form name="addproduct" id="addproduct" action="' . $_SERVER["PHP_SELF"] . '?id=' . $object->id . (($action != 'editline') ? '#add' : '#line_' . GETPOST('lineid')) . '" method="POST"> + <input type="hidden" name="token" value="' . $_SESSION ['newtoken'] . '"> + <input type="hidden" name="action" value="' . (($action != 'editline') ? 'addline' : 'updateligne') . '"> + <input type="hidden" name="mode" value=""> + <input type="hidden" name="id" value="' . $object->id . '"> + '; + + if (! empty($conf->use_javascript_ajax) && $object->statut == 0) { + include DOL_DOCUMENT_ROOT . '/core/tpl/ajaxrow.tpl.php'; + } + + print '<table id="tablelines" class="noborder noshadow" width="100%">'; + + if (! empty($object->lines)) + $ret = $object->printObjectLines($action, $mysoc, $soc, $lineid, 1); + + // Form to add new line + if ($object->statut == 0 && $user->rights->askpricesupplier->creer) + { + if ($action != 'editline') + { + $var = true; + + // Add products/services form + $object->formAddObjectLine(1, $mysoc, $soc); + + $parameters = array(); + $reshook = $hookmanager->executeHooks('formAddObjectLine', $parameters, $object, $action); // Note that $action and $object may have been modified by hook + } + } + + print '</table>'; + + print "</form>\n"; + + dol_fiche_end(); + + if ($action == 'statut') + { + /* + * Form to close proposal (signed or not) + */ + $form_close = '<form action="' . $_SERVER["PHP_SELF"] . '?id=' . $object->id . '" method="post">'; + $form_close .= '<p class="notice">'.$langs->trans('AskPriceSupplierRefFournNotice').'</p>'; + $form_close .= '<input type="hidden" name="token" value="' . $_SESSION ['newtoken'] . '">'; + $form_close .= '<table class="border" width="100%">'; + $form_close .= '<tr><td width="150" align="left">' . $langs->trans("CloseAs") . '</td><td align="left">'; + $form_close .= '<input type="hidden" name="action" value="setstatut">'; + $form_close .= '<select id="statut" name="statut" class="flat">'; + $form_close .= '<option value="0"> </option>'; + $form_close .= '<option value="2">' . $langs->trans('AskpricesupplierStatusSigned') . '</option>'; + $form_close .= '<option value="3">' . $langs->trans('AskpricesupplierStatusNotSigned') . '</option>'; + $form_close .= '</select>'; + $form_close .= '</td></tr>'; + $form_close .= '<tr><td width="150" align="left">' . $langs->trans('Note') . '</td><td align="left"><textarea cols="70" rows="' . ROWS_3 . '" wrap="soft" name="note">'; + $form_close .= $object->note; + $form_close .= '</textarea></td></tr>'; + $form_close .= '<tr><td align="center" colspan="2">'; + $form_close .= '<input type="submit" class="button" name="validate" value="' . $langs->trans('Validate') . '">'; + $form_close .= ' <input type="submit" class="button" name="cancel" value="' . $langs->trans('Cancel') . '">'; + $form_close .= '<a name="close"> </a>'; + $form_close .= '</td>'; + $form_close .= '</tr></table></form>'; + + print $form_close; + } + + /* + * Boutons Actions + */ + if ($action != 'presend') { + print '<div class="tabsAction">'; + + $parameters = array(); + $reshook = $hookmanager->executeHooks('addMoreActionsButtons', $parameters, $object, $action); // Note that $action and $object may have been + // modified by hook + if (empty($reshook)) + { + if ($action != 'statut' && $action != 'editline') + { + // Validate + if ($object->statut == 0 && $object->total_ttc >= 0 && count($object->lines) > 0 && + ((empty($conf->global->MAIN_USE_ADVANCED_PERMS) && ! empty($user->rights->askpricesupplier->creer)) + || (! empty($conf->global->MAIN_USE_ADVANCED_PERMS) && ! empty($user->rights->askpricesupplier->validate))) + ) { + if (count($object->lines) > 0) + print '<div class="inline-block divButAction"><a class="butAction" href="' . $_SERVER["PHP_SELF"] . '?id=' . $object->id . '&action=validate">' . $langs->trans('Validate') . '</a></div>'; + // else print '<a class="butActionRefused" href="#">'.$langs->trans('Validate').'</a>'; + } + + // Edit + if ($object->statut == 1 && $user->rights->askpricesupplier->creer) { + print '<div class="inline-block divButAction"><a class="butAction" href="' . $_SERVER["PHP_SELF"] . '?id=' . $object->id . '&action=modif">' . $langs->trans('Modify') . '</a></div>'; + } + + // ReOpen + if (($object->statut == 2 || $object->statut == 3 || $object->statut == 4) && $user->rights->askpricesupplier->cloturer) { + print '<div class="inline-block divButAction"><a class="butAction" href="' . $_SERVER["PHP_SELF"] . '?id=' . $object->id . '&action=reopen' . (empty($conf->global->MAIN_JUMP_TAG) ? '' : '#reopen') . '"'; + print '>' . $langs->trans('ReOpen') . '</a></div>'; + } + + // Send + if ($object->statut == 1 || $object->statut == 2) { + if (empty($conf->global->MAIN_USE_ADVANCED_PERMS) || $user->rights->askpricesupplier->send) { + print '<div class="inline-block divButAction"><a class="butAction" href="' . $_SERVER["PHP_SELF"] . '?id=' . $object->id . '&action=presend&mode=init">' . $langs->trans('SendByMail') . '</a></div>'; + } else + print '<div class="inline-block divButAction"><a class="butActionRefused" href="#">' . $langs->trans('SendByMail') . '</a></div>'; + } + + // Create an order + if (! empty($conf->commande->enabled) && $object->statut == 2) { + if ($user->rights->commande->creer) { + print '<div class="inline-block divButAction"><a class="butAction" href="' . DOL_URL_ROOT . '/fourn/commande/card.php?action=create&origin=' . $object->element . '&originid=' . $object->id . '&socid=' . $object->socid . '">' . $langs->trans("AddOrder") . '</a></div>'; + } + } + + // Close + if ($object->statut == 1 && $user->rights->askpricesupplier->cloturer) { + print '<div class="inline-block divButAction"><a class="butAction" href="' . $_SERVER["PHP_SELF"] . '?id=' . $object->id . '&action=statut' . (empty($conf->global->MAIN_JUMP_TAG) ? '' : '#close') . '"'; + print '>' . $langs->trans('Close') . '</a></div>'; + } + + // Clone + if ($user->rights->askpricesupplier->creer) { + print '<div class="inline-block divButAction"><a class="butAction" href="' . $_SERVER['PHP_SELF'] . '?id=' . $object->id . '&socid=' . $object->socid . '&action=clone&object=' . $object->element . '">' . $langs->trans("ToClone") . '</a></div>'; + } + + // Delete + if ($user->rights->askpricesupplier->supprimer) { + print '<div class="inline-block divButAction"><a class="butActionDelete" href="' . $_SERVER["PHP_SELF"] . '?id=' . $object->id . '&action=delete"'; + print '>' . $langs->trans('Delete') . '</a></div>'; + } + } + } + + print '</div>'; + } + print "<br>\n"; + + if ($action != 'presend') + { + print '<div class="fichecenter"><div class="fichehalfleft">'; + + /* + * Documents generes + */ + $filename = dol_sanitizeFileName($object->ref); + $filedir = $conf->askpricesupplier->dir_output . "/" . dol_sanitizeFileName($object->ref); + $urlsource = $_SERVER["PHP_SELF"] . "?id=" . $object->id; + $genallowed = $user->rights->askpricesupplier->creer; + $delallowed = $user->rights->askpricesupplier->supprimer; + + $var = true; + + $somethingshown = $formfile->show_documents('askpricesupplier', $filename, $filedir, $urlsource, $genallowed, $delallowed, $object->modelpdf, 1, 0, 0, 28, 0, '', 0, '', $soc->default_lang); + + /* + * Linked object block + */ + $somethingshown = $object->showLinkedObjectBlock(); + + print '</div><div class="fichehalfright"><div class="ficheaddleft">'; + + // List of actions on element + include_once DOL_DOCUMENT_ROOT . '/core/class/html.formactions.class.php'; + $formactions = new FormActions($db); + $somethingshown = $formactions->showactions($object, 'askpricesupplier', $socid); + + print '</div></div></div>'; + } + + /* + * Action presend + */ + if ($action == 'presend') + { + $object->fetch_projet(); + + $ref = dol_sanitizeFileName($object->ref); + include_once DOL_DOCUMENT_ROOT . '/core/lib/files.lib.php'; + $fileparams = dol_most_recent_file($conf->askpricesupplier->dir_output . '/' . $ref, preg_quote($ref, '/')); + $file = $fileparams ['fullname']; + + // 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->thirdparty->default_lang; + + if (!empty($newlang)) + { + $outputlangs = new Translate('', $conf); + $outputlangs->setDefaultLang($newlang); + $outputlangs->load('commercial'); + } + + // Build document if it not exists + if (! $file || ! is_readable($file)) { + $result = $object->generateDocument(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->askpricesupplier->dir_output . '/' . $ref, preg_quote($ref, '/')); + $file = $fileparams ['fullname']; + } + + print '<br>'; + print_titre($langs->trans('SendAskByMail')); + + // Create form object + include_once DOL_DOCUMENT_ROOT . '/core/class/html.formmail.class.php'; + $formmail = new FormMail($db); + $formmail->param['langsmodels']=(empty($newlang)?$langs->defaultlang:$newlang); + $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 = $outputlangs->trans('SendAskRef', '__ASKREF__'); + + $formmail->withfile = 2; + $formmail->withbody = 1; + $formmail->withdeliveryreceipt = 1; + $formmail->withcancel = 1; + + // Tableau des substitutions + $formmail->substit['__ASKREF__'] = $object->ref; + $formmail->substit['__SIGNATURE__'] = $user->signature; + $formmail->substit['__THIRPARTY_NAME__'] = $object->thirdparty->name; + $formmail->substit['__PROJECT_REF__'] = (is_object($object->projet)?$object->projet->ref:''); + $formmail->substit['__CONTACTCIVNAME__'] = ''; + $formmail->substit['__PERSONALIZED__'] = ''; + + // Tableau des parametres complementaires + $formmail->param['action'] = 'send'; + $formmail->param['models'] = 'askpricesupplier_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)); + } + + print $formmail->get_form(); + + print '<br>'; + } +} + +// End of page +llxFooter(); +$db->close(); diff --git a/htdocs/comm/askpricesupplier/class/askpricesupplier.class.php b/htdocs/comm/askpricesupplier/class/askpricesupplier.class.php new file mode 100644 index 0000000000000000000000000000000000000000..8740e139235a5fdfbb4be64088f482cbbfd0448d --- /dev/null +++ b/htdocs/comm/askpricesupplier/class/askpricesupplier.class.php @@ -0,0 +1,2872 @@ +<?php +/* Copyright (C) 2002-2004 Rodolphe Quiedeville <rodolphe@quiedeville.org> + * Copyright (C) 2004 Eric Seigne <eric.seigne@ryxeo.com> + * Copyright (C) 2004-2011 Laurent Destailleur <eldy@users.sourceforge.net> + * Copyright (C) 2005 Marc Barilley <marc@ocebo.com> + * Copyright (C) 2005-2013 Regis Houssin <regis.houssin@capnetworks.com> + * Copyright (C) 2006 Andre Cianfarani <acianfa@free.fr> + * Copyright (C) 2008 Raphael Bertrand <raphael.bertrand@resultic.fr> + * Copyright (C) 2010-2014 Juanjo Menent <jmenent@2byte.es> + * Copyright (C) 2010-2011 Philippe Grand <philippe.grand@atoo-net.com> + * Copyright (C) 2012-2014 Christophe Battarel <christophe.battarel@altairis.fr> + * Copyright (C) 2013 Florian Henry <florian.henry@open-concept.pro> + * Copyright (C) 2014 Marcos García <marcosgdf@gmail.com> + * + * 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 <http://www.gnu.org/licenses/>. + */ + +/** + * \file htdocs/comm/propal/class/propal.class.php + * \brief File of class to manage proposals + */ + +require_once DOL_DOCUMENT_ROOT .'/fourn/class/fournisseur.product.class.php'; +require_once DOL_DOCUMENT_ROOT .'/core/class/commonobject.class.php'; +require_once DOL_DOCUMENT_ROOT .'/product/class/product.class.php'; +require_once DOL_DOCUMENT_ROOT .'/contact/class/contact.class.php'; +require_once DOL_DOCUMENT_ROOT .'/margin/lib/margins.lib.php'; + +/** + * Class to manage price ask supplier + */ +class AskPriceSupplier extends CommonObject +{ + public $element='askpricesupplier'; + public $table_element='askpricesupplier'; + public $table_element_line='askpricesupplierdet'; + public $fk_element='fk_askpricesupplier'; + protected $ismultientitymanaged = 1; // 0=No test on entity, 1=Test with field entity, 2=Test with link by societe + + /** + * {@inheritdoc} + */ + protected $table_ref_field = 'ref'; + + var $id; + + var $socid; // Id client + var $client; // Objet societe client (a charger par fetch_client) + + var $fk_project; + var $author; + var $ref; + var $ref_fourn; //Reference saisie lors de l'ajout d'une ligne à la demande + var $statut; // 0 (draft), 1 (validated), 2 (signed), 3 (not signed), 4 (billed) + var $datec; // Date of creation + var $date; // Date of proposal + var $date_livraison; + + var $user_author_id; + var $user_valid_id; + var $user_close_id; + + var $total_ht; // Total net of tax + var $total_tva; // Total VAT + var $total_localtax1; // Total Local Taxes 1 + var $total_localtax2; // Total Local Taxes 2 + var $total_ttc; // Total with tax + var $price; // deprecated (for compatibility) + var $tva; // deprecated (for compatibility) + var $total; // deprecated (for compatibility) + + var $cond_reglement_id; + var $cond_reglement_code; + var $fk_account; // Id of bank account + var $mode_reglement_id; + var $mode_reglement_code; + var $remise; + var $remise_percent; + var $remise_absolue; + var $note; // deprecated (for compatibility) + var $note_private; + var $note_public; + var $shipping_method_id; + + var $products=array(); + var $extraparams=array(); + + var $lines = array(); + var $line; + + var $origin; + var $origin_id; + + var $labelstatut=array(); + var $labelstatut_short=array(); + + var $nbtodo; + var $nbtodolate; + + var $specimen; + + + /** + * Constructor + * + * @param DoliDB $db Database handler + * @param int $socid Id third party + * @param int $askpricesupplierid Id askpricesupplier + */ + function __construct($db, $socid="", $askpricesupplierid=0) + { + global $conf,$langs; + + $this->db = $db; + $this->socid = $socid; + $this->id = $askpricesupplierid; + $this->products = array(); + $this->remise = 0; + $this->remise_percent = 0; + $this->remise_absolue = 0; + + $langs->load("askpricesupplier"); + $this->labelstatut[0]=(! empty($conf->global->ASKPRICESUPPLIER_STATUS_DRAFT_LABEL) ? $conf->global->ASKPRICESUPPLIER_STATUS_DRAFT_LABEL : $langs->trans("AskpricesupplierStatusDraft")); + $this->labelstatut[1]=(! empty($conf->global->ASKPRICESUPPLIER_STATUS_VALIDATED_LABEL) ? $conf->global->ASKPRICESUPPLIER_STATUS_VALIDATED_LABEL : $langs->trans("AskpricesupplierStatusValidated")); + $this->labelstatut[2]=(! empty($conf->global->ASKPRICESUPPLIER_STATUS_SIGNED_LABEL) ? $conf->global->ASKPRICESUPPLIER_STATUS_SIGNED_LABEL : $langs->trans("AskpricesupplierStatusSigned")); + $this->labelstatut[3]=(! empty($conf->global->ASKPRICESUPPLIER_STATUS_NOTSIGNED_LABEL) ? $conf->global->ASKPRICESUPPLIER_STATUS_NOTSIGNED_LABEL : $langs->trans("AskpricesupplierStatusNotSigned")); + $this->labelstatut[4]=(! empty($conf->global->ASKPRICESUPPLIER_STATUS_BILLED_LABEL) ? $conf->global->ASKPRICESUPPLIER_STATUS_BILLED_LABEL : $langs->trans("AskpricesupplierStatusBilled")); + $this->labelstatut_short[0]=(! empty($conf->global->ASKPRICESUPPLIER_STATUS_DRAFTSHORT_LABEL) ? $conf->global->ASKPRICESUPPLIER_STATUS_DRAFTSHORT_LABEL : $langs->trans("AskpricesupplierStatusDraftShort")); + $this->labelstatut_short[1]=(! empty($conf->global->ASKPRICESUPPLIER_STATUS_VALIDATEDSHORT_LABEL) ? $conf->global->ASKPRICESUPPLIER_STATUS_VALIDATEDSHORT_LABEL : $langs->trans("Opened")); + $this->labelstatut_short[2]=(! empty($conf->global->ASKPRICESUPPLIER_STATUS_SIGNEDSHORT_LABEL) ? $conf->global->ASKPRICESUPPLIER_STATUS_SIGNEDSHORT_LABEL : $langs->trans("AskpricesupplierStatusSignedShort")); + $this->labelstatut_short[3]=(! empty($conf->global->ASKPRICESUPPLIER_STATUS_NOTSIGNEDSHORT_LABEL) ? $conf->global->ASKPRICESUPPLIER_STATUS_NOTSIGNEDSHORT_LABEL : $langs->trans("AskpricesupplierStatusNotSignedShort")); + $this->labelstatut_short[4]=(! empty($conf->global->ASKPRICESUPPLIER_STATUS_BILLEDSHORT_LABEL) ? $conf->global->ASKPRICESUPPLIER_STATUS_BILLEDSHORT_LABEL : $langs->trans("AskpricesupplierStatusBilledShort")); + } + + + /** + * Add line into array products + * $this->client doit etre charge + * + * @param int $idproduct Product Id to add + * @param int $qty Quantity + * @param int $remise_percent Discount effected on Product + * @return int <0 if KO, >0 if OK + * + * TODO Remplacer les appels a cette fonction par generation objet Ligne + * insere dans tableau $this->products + */ + function add_product($idproduct, $qty, $remise_percent=0) + { + global $conf, $mysoc; + + if (! $qty) $qty = 1; + + dol_syslog(get_class($this)."::add_product $idproduct, $qty, $remise_percent"); + if ($idproduct > 0) + { + $prod=new Product($this->db); + $prod->fetch($idproduct); + + $productdesc = $prod->description; + + $tva_tx = get_default_tva($mysoc,$this->client,$prod->id); + // local taxes + $localtax1_tx = get_default_localtax($mysoc,$this->client,1,$prod->tva_tx); + $localtax2_tx = get_default_localtax($mysoc,$this->client,2,$prod->tva_tx); + + // multiprix + if($conf->global->PRODUIT_MULTIPRICES && $this->client->price_level) + { + $price = $prod->multiprices[$this->client->price_level]; + } + else + { + $price = $prod->price; + } + + $line = new AskPriceSupplierLigne($this->db); + + $line->fk_product=$idproduct; + $line->desc=$productdesc; + $line->qty=$qty; + $line->subprice=$price; + $line->remise_percent=$remise_percent; + $line->tva_tx=$tva_tx; + + $this->lines[]=$line; + } + } + + /** + * Adding line of fixed discount in the proposal in DB + * + * @param int $idremise Id of fixed discount + * @return int >0 if OK, <0 if KO + */ + function insert_discount($idremise) + { + global $langs; + + include_once DOL_DOCUMENT_ROOT.'/core/lib/price.lib.php'; + include_once DOL_DOCUMENT_ROOT.'/core/class/discount.class.php'; + + $this->db->begin(); + + $remise=new DiscountAbsolute($this->db); + $result=$remise->fetch($idremise); + + if ($result > 0) + { + if ($remise->fk_facture) // Protection against multiple submission + { + $this->error=$langs->trans("ErrorDiscountAlreadyUsed"); + $this->db->rollback(); + return -5; + } + + $askpricesupplierligne=new AskPriceSupplierLigne($this->db); + $askpricesupplierligne->fk_askpricesupplier=$this->id; + $askpricesupplierligne->fk_remise_except=$remise->id; + $askpricesupplierligne->desc=$remise->description; // Description ligne + $askpricesupplierligne->tva_tx=$remise->tva_tx; + $askpricesupplierligne->subprice=-$remise->amount_ht; + $askpricesupplierligne->fk_product=0; // Id produit predefini + $askpricesupplierligne->qty=1; + $askpricesupplierligne->remise=0; + $askpricesupplierligne->remise_percent=0; + $askpricesupplierligne->rang=-1; + $askpricesupplierligne->info_bits=2; + + // TODO deprecated + $askpricesupplierligne->price=-$remise->amount_ht; + + $askpricesupplierligne->total_ht = -$remise->amount_ht; + $askpricesupplierligne->total_tva = -$remise->amount_tva; + $askpricesupplierligne->total_ttc = -$remise->amount_ttc; + + $result=$askpricesupplierligne->insert(); + if ($result > 0) + { + $result=$this->update_price(1); + if ($result > 0) + { + $this->db->commit(); + return 1; + } + else + { + $this->db->rollback(); + return -1; + } + } + else + { + $this->error=$askpricesupplierligne->error; + $this->db->rollback(); + return -2; + } + } + else + { + $this->db->rollback(); + return -2; + } + } + + /** + * Add a proposal line into database (linked to product/service or not) + * Les parametres sont deja cense etre juste et avec valeurs finales a l'appel + * de cette methode. Aussi, pour le taux tva, il doit deja avoir ete defini + * par l'appelant par la methode get_default_tva(societe_vendeuse,societe_acheteuse,'',produit) + * et le desc doit deja avoir la bonne valeur (a l'appelant de gerer le multilangue) + * + * @param string $desc Description de la ligne + * @param double $pu_ht Prix unitaire + * @param double $qty Quantite + * @param double $txtva Taux de tva + * @param double $txlocaltax1 Local tax 1 rate + * @param double $txlocaltax2 Local tax 2 rate + * @param int $fk_product Id du produit/service predefini + * @param double $remise_percent Pourcentage de remise de la ligne + * @param string $price_base_type HT or TTC + * @param double $pu_ttc Prix unitaire TTC + * @param int $info_bits Bits de type de lignes + * @param int $type Type of line (product, service) + * @param int $rang Position of line + * @param int $special_code Special code (also used by externals modules!) + * @param int $fk_parent_line Id of parent line + * @param int $fk_fournprice Id supplier price + * @param int $pa_ht Buying price without tax + * @param string $label ??? + * @param array $array_option extrafields array + * @param string $ref_fourn Supplier price reference + * @return int >0 if OK, <0 if KO + * + * @see add_product + */ + function addline($desc, $pu_ht, $qty, $txtva, $txlocaltax1=0, $txlocaltax2=0, $fk_product=0, $remise_percent=0, $price_base_type='HT', $pu_ttc=0, $info_bits=0, $type=0, $rang=-1, $special_code=0, $fk_parent_line=0, $fk_fournprice=0, $pa_ht=0, $label='',$array_option=0, $ref_fourn='') + { + global $mysoc; + + dol_syslog(get_class($this)."::addline askpricesupplierid=$this->id, desc=$desc, pu_ht=$pu_ht, qty=$qty, txtva=$txtva, fk_product=$fk_product, remise_except=$remise_percent, price_base_type=$price_base_type, pu_ttc=$pu_ttc, info_bits=$info_bits, type=$type"); + include_once DOL_DOCUMENT_ROOT.'/core/lib/price.lib.php'; + + // Clean parameters + if (empty($remise_percent)) $remise_percent=0; + if (empty($qty)) $qty=0; + if (empty($info_bits)) $info_bits=0; + if (empty($rang)) $rang=0; + if (empty($fk_parent_line) || $fk_parent_line < 0) $fk_parent_line=0; + + $remise_percent=price2num($remise_percent); + $qty=price2num($qty); + $pu_ht=price2num($pu_ht); + $pu_ttc=price2num($pu_ttc); + $txtva=price2num($txtva); + $txlocaltax1=price2num($txlocaltax1); + $txlocaltax2=price2num($txlocaltax2); + $pa_ht=price2num($pa_ht); + if ($price_base_type=='HT') + { + $pu=$pu_ht; + } + else + { + $pu=$pu_ttc; + } + + // Check parameters + if ($type < 0) return -1; + + if ($this->statut == 0) + { + $this->db->begin(); + + // Calcul du total TTC et de la TVA pour la ligne a partir de + // qty, pu, remise_percent et txtva + // TRES IMPORTANT: C'est au moment de l'insertion ligne qu'on doit stocker + // la part ht, tva et ttc, et ce au niveau de la ligne qui a son propre taux tva. + + $localtaxes_type=getLocalTaxesFromRate($txtva,0,$this->thirdparty,$mysoc); + + $tabprice=calcul_price_total($qty, $pu, $remise_percent, $txtva, $txlocaltax1, $txlocaltax2, 0, $price_base_type, $info_bits, $type, '', $localtaxes_type); + $total_ht = $tabprice[0]; + $total_tva = $tabprice[1]; + $total_ttc = $tabprice[2]; + $total_localtax1 = $tabprice[9]; + $total_localtax2 = $tabprice[10]; + + // Rang to use + $rangtouse = $rang; + if ($rangtouse == -1) + { + $rangmax = $this->line_max($fk_parent_line); + $rangtouse = $rangmax + 1; + } + + // TODO A virer + // Anciens indicateurs: $price, $remise (a ne plus utiliser) + $price = $pu; + $remise = 0; + if ($remise_percent > 0) + { + $remise = round(($pu * $remise_percent / 100), 2); + $price = $pu - $remise; + } + + // Insert line + $this->line=new AskPriceSupplierLigne($this->db); + + $this->line->fk_askpricesupplier=$this->id; + $this->line->label=$label; + $this->line->desc=$desc; + $this->line->qty=$qty; + $this->line->tva_tx=$txtva; + $this->line->localtax1_tx=$txlocaltax1; + $this->line->localtax2_tx=$txlocaltax2; + $this->line->localtax1_type = $localtaxes_type[0]; + $this->line->localtax2_type = $localtaxes_type[2]; + $this->line->fk_product=$fk_product; + $this->line->remise_percent=$remise_percent; + $this->line->subprice=$pu_ht; + $this->line->rang=$rangtouse; + $this->line->info_bits=$info_bits; + $this->line->total_ht=$total_ht; + $this->line->total_tva=$total_tva; + $this->line->total_localtax1=$total_localtax1; + $this->line->total_localtax2=$total_localtax2; + $this->line->total_ttc=$total_ttc; + $this->line->product_type=$type; + $this->line->special_code=$special_code; + $this->line->fk_parent_line=$fk_parent_line; + + $this->line->ref_fourn = $this->db->escape($ref_fourn); + + // infos marge + if (!empty($fk_product) && empty($fk_fournprice) && empty($pa_ht)) { + // by external module, take lowest buying price + include_once DOL_DOCUMENT_ROOT.'/fourn/class/fournisseur.product.class.php'; + $productFournisseur = new ProductFournisseur($this->db); + $productFournisseur->find_min_price_product_fournisseur($fk_product); + $this->line->fk_fournprice = $productFournisseur->product_fourn_price_id; + } else { + $this->line->fk_fournprice = $fk_fournprice; + } + $this->line->pa_ht = $pa_ht; + + // Mise en option de la ligne + if (empty($qty) && empty($special_code)) $this->line->special_code=3; + + // TODO deprecated + $this->line->price=$price; + $this->line->remise=$remise; + + if (is_array($array_option) && count($array_option)>0) { + $this->line->array_options=$array_option; + } + + $result=$this->line->insert(); + if ($result > 0) + { + // Reorder if child line + if (! empty($fk_parent_line)) $this->line_order(true,'DESC'); + + // Mise a jour informations denormalisees au niveau de la propale meme + $result=$this->update_price(1,'auto'); // This method is designed to add line from user input so total calculation must be done using 'auto' mode. + if ($result > 0) + { + $this->db->commit(); + return $this->line->rowid; + } + else + { + $this->error=$this->db->error(); + $this->db->rollback(); + return -1; + } + } + else + { + $this->error=$this->line->error; + $this->db->rollback(); + return -2; + } + } + } + + + /** + * Update a proposal line + * + * @param int $rowid Id de la ligne + * @param double $pu Prix unitaire (HT ou TTC selon price_base_type) + * @param double $qty Quantity + * @param double $remise_percent Remise effectuee sur le produit + * @param double $txtva Taux de TVA + * @param double $txlocaltax1 Local tax 1 rate + * @param double $txlocaltax2 Local tax 2 rate + * @param string $desc Description + * @param double $price_base_type HT ou TTC + * @param int $info_bits Miscellaneous informations + * @param int $special_code Special code (also used by externals modules!) + * @param int $fk_parent_line Id of parent line (0 in most cases, used by modules adding sublevels into lines). + * @param int $skip_update_total Keep fields total_xxx to 0 (used for special lines by some modules) + * @param int $fk_fournprice Id of origin supplier price + * @param int $pa_ht Price (without tax) of product when it was bought + * @param string $label ??? + * @param int $type 0/1=Product/service + * @param array $array_option extrafields array + * @param string $ref_fourn Supplier price reference + * @return int 0 if OK, <0 if KO + */ + function updateline($rowid, $pu, $qty, $remise_percent, $txtva, $txlocaltax1=0, $txlocaltax2=0, $desc='', $price_base_type='HT', $info_bits=0, $special_code=0, $fk_parent_line=0, $skip_update_total=0, $fk_fournprice=0, $pa_ht=0, $label='', $type=0, $array_option=0, $ref_fourn='') + { + global $conf,$user,$langs, $mysoc; + + dol_syslog(get_class($this)."::updateLine $rowid, $pu, $qty, $remise_percent, $txtva, $desc, $price_base_type, $info_bits"); + include_once DOL_DOCUMENT_ROOT.'/core/lib/price.lib.php'; + + // Clean parameters + $remise_percent=price2num($remise_percent); + $qty=price2num($qty); + $pu = price2num($pu); + $txtva = price2num($txtva); + $txlocaltax1=price2num($txlocaltax1); + $txlocaltax2=price2num($txlocaltax2); + $pa_ht=price2num($pa_ht); + if (empty($qty) && empty($special_code)) $special_code=3; // Set option tag + if (! empty($qty) && $special_code == 3) $special_code=0; // Remove option tag + + if ($this->statut == 0) + { + $this->db->begin(); + + // Calcul du total TTC et de la TVA pour la ligne a partir de + // qty, pu, remise_percent et txtva + // TRES IMPORTANT: C'est au moment de l'insertion ligne qu'on doit stocker + // la part ht, tva et ttc, et ce au niveau de la ligne qui a son propre taux tva. + + $localtaxes_type=getLocalTaxesFromRate($txtva,0,$this->thirdparty,$mysoc); + + $tabprice=calcul_price_total($qty, $pu, $remise_percent, $txtva, $txlocaltax1, $txlocaltax2, 0, $price_base_type, $info_bits, $type,'', $localtaxes_type); + $total_ht = $tabprice[0]; + $total_tva = $tabprice[1]; + $total_ttc = $tabprice[2]; + $total_localtax1 = $tabprice[9]; + $total_localtax2 = $tabprice[10]; + + // Anciens indicateurs: $price, $remise (a ne plus utiliser) + $price = $pu; + if ($remise_percent > 0) + { + $remise = round(($pu * $remise_percent / 100), 2); + $price = $pu - $remise; + } + + // Update line + $this->line=new AskPriceSupplierLigne($this->db); + + // Stock previous line records + $staticline=new AskPriceSupplierLigne($this->db); + $staticline->fetch($rowid); + $this->line->oldline = $staticline; + + // Reorder if fk_parent_line change + if (! empty($fk_parent_line) && ! empty($staticline->fk_parent_line) && $fk_parent_line != $staticline->fk_parent_line) + { + $rangmax = $this->line_max($fk_parent_line); + $this->line->rang = $rangmax + 1; + } + + $this->line->rowid = $rowid; + $this->line->label = $label; + $this->line->desc = $desc; + $this->line->qty = $qty; + $this->line->product_type = $type; + $this->line->tva_tx = $txtva; + $this->line->localtax1_tx = $txlocaltax1; + $this->line->localtax2_tx = $txlocaltax2; + $this->line->localtax1_type = $localtaxes_type[0]; + $this->line->localtax2_type = $localtaxes_type[2]; + $this->line->remise_percent = $remise_percent; + $this->line->subprice = $pu; + $this->line->info_bits = $info_bits; + $this->line->total_ht = $total_ht; + $this->line->total_tva = $total_tva; + $this->line->total_localtax1 = $total_localtax1; + $this->line->total_localtax2 = $total_localtax2; + $this->line->total_ttc = $total_ttc; + $this->line->special_code = $special_code; + $this->line->fk_parent_line = $fk_parent_line; + $this->line->skip_update_total = $skip_update_total; + $this->line->ref_fourn = $ref_fourn; + + // infos marge + if (!empty($fk_product) && empty($fk_fournprice) && empty($pa_ht)) { + // by external module, take lowest buying price + include_once DOL_DOCUMENT_ROOT.'/fourn/class/fournisseur.product.class.php'; + $productFournisseur = new ProductFournisseur($this->db); + $productFournisseur->find_min_price_product_fournisseur($fk_product); + $this->line->fk_fournprice = $productFournisseur->product_fourn_price_id; + } else { + $this->line->fk_fournprice = $fk_fournprice; + } + $this->line->pa_ht = $pa_ht; + + // TODO deprecated + $this->line->price=$price; + $this->line->remise=$remise; + + if (is_array($array_option) && count($array_option)>0) { + $this->line->array_options=$array_option; + } + + $result=$this->line->update(); + if ($result > 0) + { + // Reorder if child line + if (! empty($fk_parent_line)) $this->line_order(true,'DESC'); + + $this->update_price(1); + + $this->fk_askpricesupplier = $this->id; + $this->rowid = $rowid; + + $this->db->commit(); + return $result; + } + else + { + $this->error=$this->db->error(); + $this->db->rollback(); + return -1; + } + } + else + { + dol_syslog(get_class($this)."::updateline Erreur -2 Askpricesupplier en mode incompatible pour cette action"); + return -2; + } + } + + + /** + * Delete detail line + * + * @param int $lineid Id of line to delete + * @return int >0 if OK, <0 if KO + */ + function deleteline($lineid) + { + if ($this->statut == 0) + { + $line=new AskPriceSupplierLigne($this->db); + + // For triggers + $line->fetch($lineid); + + if ($line->delete() > 0) + { + $this->update_price(1); + + return 1; + } + else + { + return -1; + } + } + else + { + return -2; + } + } + + + /** + * Create commercial proposal into database + * this->ref can be set or empty. If empty, we will use "(PROVid)" + * + * @param User $user User that create + * @param int $notrigger 1=Does not execute triggers, 0= execuete triggers + * @return int <0 if KO, >=0 if OK + */ + function create($user, $notrigger=0) + { + global $langs,$conf,$mysoc,$hookmanager; + $error=0; + + $now=dol_now(); + + dol_syslog(get_class($this)."::create"); + + // Check parameters + $result=$this->fetch_thirdparty(); + if ($result < 0) + { + $this->error="Failed to fetch company"; + dol_syslog(get_class($this)."::create ".$this->error, LOG_ERR); + return -3; + } + + // Check parameters + if (! empty($this->ref)) // We check that ref is not already used + { + $result=self::isExistingObject($this->element, 0, $this->ref); // Check ref is not yet used + if ($result > 0) + { + $this->error='ErrorRefAlreadyExists'; + dol_syslog(get_class($this)."::create ".$this->error,LOG_WARNING); + $this->db->rollback(); + return -1; + } + } + + $this->db->begin(); + + // Insert into database + $sql = "INSERT INTO ".MAIN_DB_PREFIX."askpricesupplier ("; + $sql.= "fk_soc"; + $sql.= ", price"; + $sql.= ", remise"; + $sql.= ", remise_percent"; + $sql.= ", remise_absolue"; + $sql.= ", tva"; + $sql.= ", total"; + $sql.= ", datec"; + $sql.= ", ref"; + $sql.= ", fk_user_author"; + $sql.= ", note_private"; + $sql.= ", note_public"; + $sql.= ", model_pdf"; + $sql.= ", fk_cond_reglement"; + $sql.= ", fk_mode_reglement"; + $sql.= ", fk_account"; + $sql.= ", date_livraison"; + $sql.= ", fk_shipping_method"; + $sql.= ", fk_projet"; + $sql.= ", entity"; + $sql.= ") "; + $sql.= " VALUES ("; + $sql.= $this->socid; + $sql.= ", 0"; + $sql.= ", ".$this->remise; + $sql.= ", ".($this->remise_percent?$this->remise_percent:'null'); + $sql.= ", ".($this->remise_absolue?$this->remise_absolue:'null'); + $sql.= ", 0"; + $sql.= ", 0"; + $sql.= ", '".$this->db->idate($now)."'"; + $sql.= ", '(PROV)'"; + $sql.= ", ".($user->id > 0 ? "'".$user->id."'":"null"); + $sql.= ", '".$this->db->escape($this->note_private)."'"; + $sql.= ", '".$this->db->escape($this->note_public)."'"; + $sql.= ", '".$this->modelpdf."'"; + $sql.= ", ".$this->cond_reglement_id; + $sql.= ", ".$this->mode_reglement_id; + $sql.= ", ".($this->fk_account>0?$this->fk_account:'NULL'); + $sql.= ", ".($this->date_livraison!=''?"'".$this->db->idate($this->date_livraison)."'":"null"); + $sql.= ", ".($this->shipping_method_id>0?$this->shipping_method_id:'NULL'); + $sql.= ", ".($this->fk_project?$this->fk_project:"null"); + $sql.= ", ".$conf->entity; + $sql.= ")"; + + dol_syslog(get_class($this)."::create", LOG_DEBUG); + $resql=$this->db->query($sql); + if ($resql) + { + $this->id = $this->db->last_insert_id(MAIN_DB_PREFIX."askpricesupplier"); + + if ($this->id) + { + $this->ref='(PROV'.$this->id.')'; + $sql = 'UPDATE '.MAIN_DB_PREFIX."askpricesupplier SET ref='".$this->ref."' WHERE rowid=".$this->id; + + dol_syslog(get_class($this)."::create", LOG_DEBUG); + $resql=$this->db->query($sql); + if (! $resql) $error++; + + /* + * Insertion du detail des produits dans la base + */ + if (! $error) + { + $fk_parent_line=0; + $num=count($this->lines); + + for ($i=0;$i<$num;$i++) + { + // Reset fk_parent_line for no child products and special product + if (($this->lines[$i]->product_type != 9 && empty($this->lines[$i]->fk_parent_line)) || $this->lines[$i]->product_type == 9) { + $fk_parent_line = 0; + } + + $result = $this->addline( + $this->lines[$i]->desc, + $this->lines[$i]->subprice, + $this->lines[$i]->qty, + $this->lines[$i]->tva_tx, + $this->lines[$i]->localtax1_tx, + $this->lines[$i]->localtax2_tx, + $this->lines[$i]->fk_product, + $this->lines[$i]->remise_percent, + 'HT', + 0, + 0, + $this->lines[$i]->product_type, + $this->lines[$i]->rang, + $this->lines[$i]->special_code, + $fk_parent_line, + $this->lines[$i]->fk_fournprice, + $this->lines[$i]->pa_ht, + $this->lines[$i]->label, + $this->lines[$i]->array_options, + $this->lines[$i]->ref_fourn + ); + + if ($result < 0) + { + $error++; + $this->error=$this->db->error; + dol_print_error($this->db); + break; + } + // Defined the new fk_parent_line + if ($result > 0 && $this->lines[$i]->product_type == 9) { + $fk_parent_line = $result; + } + } + } + + // Add linked object + if (! $error && $this->origin && $this->origin_id) + { + $ret = $this->add_object_linked(); + if (! $ret) dol_print_error($this->db); + } + + if (! $error) + { + // Mise a jour infos denormalisees + $resql=$this->update_price(1); + if ($resql) + { + $action='update'; + + // Actions on extra fields (by external module or standard code) + $hookmanager->initHooks(array('askpricesupplierdao')); + $parameters=array('socid'=>$this->id); + $reshook=$hookmanager->executeHooks('insertExtraFields',$parameters,$this,$action); // Note that $action and $object may have been modified by some hooks + if (empty($reshook)) + { + if (empty($conf->global->MAIN_EXTRAFIELDS_DISABLED)) // For avoid conflicts if trigger used + { + $result=$this->insertExtraFields(); + if ($result < 0) + { + $error++; + } + } + } + else if ($reshook < 0) $error++; + + if (! $notrigger) + { + // Call trigger + $result=$this->call_trigger('ASKPRICESUPPLIER_CREATE',$user); + if ($result < 0) { $error++; } + // End call triggers + } + } + else + { + $this->error=$this->db->lasterror(); + $error++; + } + } + } + else + { + $this->error=$this->db->lasterror(); + $error++; + } + + if (! $error) + { + $this->db->commit(); + dol_syslog(get_class($this)."::create done id=".$this->id); + return $this->id; + } + else + { + $this->db->rollback(); + return -2; + } + } + else + { + $this->error=$this->db->lasterror(); + $this->db->rollback(); + return -1; + } + } + + + /** + * Insert into DB a askpricesupplier object completely defined by its data members (ex, results from copy). + * + * @param User $user User that create + * @return int Id of the new object if ok, <0 if ko + * @see create + */ + function create_from($user) + { + $this->products=$this->lines; + + return $this->create($user); + } + + /** + * Load an object from its id and create a new one in database + * + * @param int $socid Id of thirdparty + * @return int New id of clone + */ + function createFromClone($socid=0) + { + global $user,$langs,$conf,$hookmanager; + + $error=0; + $now=dol_now(); + + $this->db->begin(); + + // get extrafields so they will be clone + foreach($this->lines as $line) + $line->fetch_optionals($line->rowid); + + // Load source object + $objFrom = dol_clone($this); + + $objsoc=new Societe($this->db); + + // Change socid if needed + if (! empty($socid) && $socid != $this->socid) + { + if ($objsoc->fetch($socid) > 0) + { + $this->socid = $objsoc->id; + $this->cond_reglement_id = (! empty($objsoc->cond_reglement_id) ? $objsoc->cond_reglement_id : 0); + $this->mode_reglement_id = (! empty($objsoc->mode_reglement_id) ? $objsoc->mode_reglement_id : 0); + $this->fk_project = ''; + } + + // TODO Change product price if multi-prices + } + else + { + $objsoc->fetch($this->socid); + } + + $this->id=0; + $this->statut=0; + + if (empty($conf->global->ASKPRICESUPPLIER_ADDON) || ! is_readable(DOL_DOCUMENT_ROOT ."/core/modules/askpricesupplier/".$conf->global->ASKPRICESUPPLIER_ADDON.".php")) + { + $this->error='ErrorSetupNotComplete'; + return -1; + } + + // Clear fields + $this->user_author = $user->id; + $this->user_valid = ''; + $this->date = $now; + + // Set ref + require_once DOL_DOCUMENT_ROOT ."/core/modules/askpricesupplier/".$conf->global->ASKPRICESUPPLIER_ADDON.'.php'; + $obj = $conf->global->ASKPRICESUPPLIER_ADDON; + $modAskPriceSupplier = new $obj; + $this->ref = $modAskPriceSupplier->getNextValue($objsoc,$this); + + // Create clone + $result=$this->create($user); + if ($result < 0) $error++; + + if (! $error) + { + // Hook of thirdparty module + if (is_object($hookmanager)) + { + $parameters=array('objFrom'=>$objFrom); + $action=''; + $reshook=$hookmanager->executeHooks('createFrom',$parameters,$this,$action); // Note that $action and $object may have been modified by some hooks + if ($reshook < 0) $error++; + } + + // Call trigger + $result=$this->call_trigger('ASKPRICESUPPLIER_CLONE',$user); + if ($result < 0) { $error++; } + // End call triggers + } + + // End + if (! $error) + { + $this->db->commit(); + return $this->id; + } + else + { + $this->db->rollback(); + return -1; + } + } + + /** + * Load a proposal from database and its ligne array + * + * @param int $rowid id of object to load + * @param string $ref Ref of proposal + * @return int >0 if OK, <0 if KO + */ + function fetch($rowid,$ref='') + { + global $conf; + + $sql = "SELECT p.rowid, p.ref, p.remise, p.remise_percent, p.remise_absolue, p.fk_soc"; + $sql.= ", p.total, p.tva, p.localtax1, p.localtax2, p.total_ht"; + $sql.= ", p.datec"; + $sql.= ", p.date_valid as datev"; + $sql.= ", p.date_livraison as date_livraison"; + $sql.= ", p.model_pdf, p.extraparams"; + $sql.= ", p.note_private, p.note_public"; + $sql.= ", p.fk_projet, p.fk_statut"; + $sql.= ", p.fk_user_author, p.fk_user_valid, p.fk_user_cloture"; + $sql.= ", p.fk_cond_reglement"; + $sql.= ", p.fk_mode_reglement"; + $sql.= ', p.fk_account'; + $sql.= ", p.fk_shipping_method"; + $sql.= ", c.label as statut_label"; + $sql.= ", cr.code as cond_reglement_code, cr.libelle as cond_reglement, cr.libelle_facture as cond_reglement_libelle_doc"; + $sql.= ", cp.code as mode_reglement_code, cp.libelle as mode_reglement"; + $sql.= " FROM ".MAIN_DB_PREFIX."c_propalst as c, ".MAIN_DB_PREFIX."askpricesupplier as p"; + $sql.= ' LEFT JOIN '.MAIN_DB_PREFIX.'c_paiement as cp ON p.fk_mode_reglement = cp.id'; + $sql.= ' LEFT JOIN '.MAIN_DB_PREFIX.'c_payment_term as cr ON p.fk_cond_reglement = cr.rowid'; + $sql.= " WHERE p.fk_statut = c.id"; + $sql.= " AND p.entity = ".$conf->entity; + if ($ref) $sql.= " AND p.ref='".$ref."'"; + else $sql.= " AND p.rowid=".$rowid; + + dol_syslog(get_class($this)."::fetch", LOG_DEBUG); + $resql=$this->db->query($sql); + if ($resql) + { + if ($this->db->num_rows($resql)) + { + $obj = $this->db->fetch_object($resql); + + $this->id = $obj->rowid; + + $this->ref = $obj->ref; + $this->remise = $obj->remise; + $this->remise_percent = $obj->remise_percent; + $this->remise_absolue = $obj->remise_absolue; + $this->total = $obj->total; // TODO obsolete + $this->total_ht = $obj->total_ht; + $this->total_tva = $obj->tva; + $this->total_localtax1 = $obj->localtax1; + $this->total_localtax2 = $obj->localtax2; + $this->total_ttc = $obj->total; + $this->socid = $obj->fk_soc; + $this->fk_project = $obj->fk_projet; + $this->modelpdf = $obj->model_pdf; + $this->note = $obj->note_private; // TODO obsolete + $this->note_private = $obj->note_private; + $this->note_public = $obj->note_public; + $this->statut = $obj->fk_statut; + $this->statut_libelle = $obj->statut_label; + + $this->datec = $this->db->jdate($obj->datec); // TODO obsolete + $this->datev = $this->db->jdate($obj->datev); // TODO obsolete + $this->date_creation = $this->db->jdate($obj->datec); //Creation date + $this->date_validation = $this->db->jdate($obj->datev); //Validation date + $this->date_livraison = $this->db->jdate($obj->date_livraison); + $this->shipping_method_id = ($obj->fk_shipping_method>0)?$obj->fk_shipping_method:null; + + $this->mode_reglement_id = $obj->fk_mode_reglement; + $this->mode_reglement_code = $obj->mode_reglement_code; + $this->mode_reglement = $obj->mode_reglement; + $this->fk_account = ($obj->fk_account>0)?$obj->fk_account:null; + $this->cond_reglement_id = $obj->fk_cond_reglement; + $this->cond_reglement_code = $obj->cond_reglement_code; + $this->cond_reglement = $obj->cond_reglement; + $this->cond_reglement_doc = $obj->cond_reglement_libelle_doc; + + $this->extraparams = (array) json_decode($obj->extraparams, true); + + $this->user_author_id = $obj->fk_user_author; + $this->user_valid_id = $obj->fk_user_valid; + $this->user_close_id = $obj->fk_user_cloture; + + if ($obj->fk_statut == 0) + { + $this->brouillon = 1; + } + + // Retreive all extrafield for invoice + // fetch optionals attributes and labels + require_once DOL_DOCUMENT_ROOT.'/core/class/extrafields.class.php'; + $extrafields=new ExtraFields($this->db); + $extralabels=$extrafields->fetch_name_optionals_label($this->table_element,true); + $this->fetch_optionals($this->id,$extralabels); + + $this->db->free($resql); + + $this->lines = array(); + + /* + * Lignes askprice liees a un produit ou non + */ + $sql = "SELECT d.rowid, d.fk_askpricesupplier, d.fk_parent_line, d.label as custom_label, d.description, d.price, d.tva_tx, d.localtax1_tx, d.localtax2_tx, d.qty, d.fk_remise_except, d.remise_percent, d.subprice, d.fk_product,"; + $sql.= " d.info_bits, d.total_ht, d.total_tva, d.total_localtax1, d.total_localtax2, d.total_ttc, d.fk_product_fournisseur_price as fk_fournprice, d.buy_price_ht as pa_ht, d.special_code, d.rang, d.product_type,"; + $sql.= ' p.ref as product_ref, p.description as product_desc, p.fk_product_type, p.label as product_label,'; + $sql.= ' d.ref_fourn as ref_produit_fourn'; + $sql.= " FROM ".MAIN_DB_PREFIX."askpricesupplierdet as d"; + $sql.= " LEFT JOIN ".MAIN_DB_PREFIX."product as p ON d.fk_product = p.rowid"; + $sql.= " WHERE d.fk_askpricesupplier = ".$this->id; + $sql.= " ORDER by d.rang"; + + $result = $this->db->query($sql); + if ($result) + { + $num = $this->db->num_rows($result); + $i = 0; + + while ($i < $num) + { + $objp = $this->db->fetch_object($result); + + $line = new AskPriceSupplierLigne($this->db); + + $line->rowid = $objp->rowid; + $line->fk_askpricesupplier = $objp->fk_askpricesupplier; + $line->fk_parent_line = $objp->fk_parent_line; + $line->product_type = $objp->product_type; + $line->label = $objp->custom_label; + $line->desc = $objp->description; // Description ligne + $line->qty = $objp->qty; + $line->tva_tx = $objp->tva_tx; + $line->localtax1_tx = $objp->localtax1_tx; + $line->localtax2_tx = $objp->localtax2_tx; + $line->subprice = $objp->subprice; + $line->fk_remise_except = $objp->fk_remise_except; + $line->remise_percent = $objp->remise_percent; + $line->price = $objp->price; // TODO deprecated + + $line->info_bits = $objp->info_bits; + $line->total_ht = $objp->total_ht; + $line->total_tva = $objp->total_tva; + $line->total_localtax1 = $objp->total_localtax1; + $line->total_localtax2 = $objp->total_localtax2; + $line->total_ttc = $objp->total_ttc; + $line->fk_fournprice = $objp->fk_fournprice; + $marginInfos = getMarginInfos($objp->subprice, $objp->remise_percent, $objp->tva_tx, $objp->localtax1_tx, $objp->localtax2_tx, $line->fk_fournprice, $objp->pa_ht); + $line->pa_ht = $marginInfos[0]; + $line->marge_tx = $marginInfos[1]; + $line->marque_tx = $marginInfos[2]; + $line->special_code = $objp->special_code; + $line->rang = $objp->rang; + + $line->fk_product = $objp->fk_product; + + $line->ref = $objp->product_ref; // TODO deprecated + $line->product_ref = $objp->product_ref; + $line->libelle = $objp->product_label; // TODO deprecated + $line->product_label = $objp->product_label; + $line->product_desc = $objp->product_desc; // Description produit + $line->fk_product_type = $objp->fk_product_type; + + $line->ref_fourn = $objp->ref_produit_fourn; + + $this->lines[$i] = $line; + + $i++; + } + $this->db->free($result); + } + else + { + $this->error=$this->db->error(); + return -1; + } + + // Retreive all extrafield for askprice + // fetch optionals attributes and labels + require_once DOL_DOCUMENT_ROOT.'/core/class/extrafields.class.php'; + $extrafields=new ExtraFields($this->db); + $extralabels=$extrafields->fetch_name_optionals_label($this->table_element,true); + $this->fetch_optionals($this->id,$extralabels); + + return 1; + } + + $this->error="Record Not Found"; + return 0; + } + else + { + $this->error=$this->db->error(); + return -1; + } + } + + /** + * Update value of extrafields on the proposal + * + * @param User $user Object user that modify + * @return int <0 if ko, >0 if ok + */ + function update_extrafields($user) + { + $action='update'; + + // Actions on extra fields (by external module or standard code) + $hookmanager->initHooks(array('askpricesupplierdao')); + $parameters=array('id'=>$this->id); + $reshook=$hookmanager->executeHooks('insertExtraFields',$parameters,$this,$action); // Note that $action and $object may have been modified by some hooks + if (empty($reshook)) + { + if (empty($conf->global->MAIN_EXTRAFIELDS_DISABLED)) // For avoid conflicts if trigger used + { + $result=$this->insertExtraFields(); + if ($result < 0) + { + $error++; + } + } + } + else if ($reshook < 0) $error++; + + if (!$error) + { + return 1; + } + else + { + return -1; + } + + } + + /** + * Set status to validated + * + * @param User $user Object user that validate + * @param int $notrigger 1=Does not execute triggers, 0= execuete triggers + * @return int <0 if KO, >=0 if OK + */ + function valid($user, $notrigger=0) + { + require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php'; + + global $conf,$langs; + + $error=0; + $now=dol_now(); + + if ((empty($conf->global->MAIN_USE_ADVANCED_PERMS) && ! empty($user->rights->askpricesupplier->creer)) + || (! empty($conf->global->MAIN_USE_ADVANCED_PERMS) && ! empty($user->rights->askpricesupplier->validate))) + { + $this->db->begin(); + + // Numbering module definition + $soc = new Societe($this->db); + $soc->fetch($this->socid); + + // Define new ref + if (! $error && (preg_match('/^[\(]?PROV/i', $this->ref))) + { + $num = $this->getNextNumRef($soc); + } + else + { + $num = $this->ref; + } + $this->newref = $num; + + $sql = "UPDATE ".MAIN_DB_PREFIX."askpricesupplier"; + $sql.= " SET ref = '".$num."',"; + $sql.= " fk_statut = 1, date_valid='".$this->db->idate($now)."', fk_user_valid=".$user->id; + $sql.= " WHERE rowid = ".$this->id." AND fk_statut = 0"; + + dol_syslog(get_class($this)."::valid", LOG_DEBUG); + $resql=$this->db->query($sql); + if (! $resql) + { + dol_print_error($this->db); + $error++; + } + + // Trigger calls + if (! $error && ! $notrigger) + { + // Call trigger + $result=$this->call_trigger('ASKPRICESUPPLIER_VALIDATE',$user); + if ($result < 0) { $error++; } + // End call triggers + } + + if (! $error) + { + $this->oldref = $this->ref; + + // Rename directory if dir was a temporary ref + if (preg_match('/^[\(]?PROV/i', $this->ref)) + { + // Rename of propal directory ($this->ref = old ref, $num = new ref) + // to not lose the linked files + $oldref = dol_sanitizeFileName($this->ref); + $newref = dol_sanitizeFileName($num); + $dirsource = $conf->askpricesupplier->dir_output.'/'.$oldref; + $dirdest = $conf->askpricesupplier->dir_output.'/'.$newref; + + if (file_exists($dirsource)) + { + dol_syslog(get_class($this)."::validate rename dir ".$dirsource." into ".$dirdest); + if (@rename($dirsource, $dirdest)) + { + dol_syslog("Rename ok"); + // Rename docs starting with $oldref with $newref + $listoffiles=dol_dir_list($conf->askpricesupplier->dir_output.'/'.$newref, 'files', 1, '^'.preg_quote($oldref,'/')); + foreach($listoffiles as $fileentry) + { + $dirsource=$fileentry['name']; + $dirdest=preg_replace('/^'.preg_quote($oldref,'/').'/',$newref, $dirsource); + $dirsource=$fileentry['path'].'/'.$dirsource; + $dirdest=$fileentry['path'].'/'.$dirdest; + @rename($dirsource, $dirdest); + } + } + } + } + + $this->ref=$num; + $this->brouillon=0; + $this->statut = 1; + $this->user_valid_id=$user->id; + $this->datev=$now; + + $this->db->commit(); + return 1; + } + else + { + $this->db->rollback(); + return -1; + } + } + } + + /** + * Set delivery date + * + * @param User $user Object user that modify + * @param int $date_livraison Delivery date + * @return int <0 if ko, >0 if ok + */ + function set_date_livraison($user, $date_livraison) + { + if (! empty($user->rights->askpricesupplier->creer)) + { + $sql = "UPDATE ".MAIN_DB_PREFIX."askpricesupplier "; + $sql.= " SET date_livraison = ".($date_livraison!=''?"'".$this->db->idate($date_livraison)."'":'null'); + $sql.= " WHERE rowid = ".$this->id; + + if ($this->db->query($sql)) + { + $this->date_livraison = $date_livraison; + return 1; + } + else + { + $this->error=$this->db->error(); + dol_syslog(get_class($this)."::set_date_livraison Erreur SQL"); + return -1; + } + } + } + + /** + * Set an overall discount on the proposal + * + * @param User $user Object user that modify + * @param double $remise Amount discount + * @return int <0 if ko, >0 if ok + */ + function set_remise_percent($user, $remise) + { + $remise=trim($remise)?trim($remise):0; + + if (! empty($user->rights->askpricesupplier->creer)) + { + $remise = price2num($remise); + + $sql = "UPDATE ".MAIN_DB_PREFIX."askpricesupplier SET remise_percent = ".$remise; + $sql.= " WHERE rowid = ".$this->id." AND fk_statut = 0"; + + if ($this->db->query($sql) ) + { + $this->remise_percent = $remise; + $this->update_price(1); + return 1; + } + else + { + $this->error=$this->db->error(); + return -1; + } + } + } + + + /** + * Set an absolute overall discount on the proposal + * + * @param User $user Object user that modify + * @param double $remise Amount discount + * @return int <0 if ko, >0 if ok + */ + function set_remise_absolue($user, $remise) + { + $remise=trim($remise)?trim($remise):0; + + if (! empty($user->rights->askpricesupplier->creer)) + { + $remise = price2num($remise); + + $sql = "UPDATE ".MAIN_DB_PREFIX."askpricesupplier "; + $sql.= " SET remise_absolue = ".$remise; + $sql.= " WHERE rowid = ".$this->id." AND fk_statut = 0"; + + if ($this->db->query($sql) ) + { + $this->remise_absolue = $remise; + $this->update_price(1); + return 1; + } + else + { + $this->error=$this->db->error(); + return -1; + } + } + } + + + + /** + * Reopen the commercial proposal + * + * @param User $user Object user that close + * @param int $statut Statut + * @param string $note Comment + * @param int $notrigger 1=Does not execute triggers, 0= execuete triggers + * @return int <0 if KO, >0 if OK + */ + function reopen($user, $statut, $note='', $notrigger=0) + { + global $langs,$conf; + + $this->statut = $statut; + $error=0; + + $sql = "UPDATE ".MAIN_DB_PREFIX."askpricesupplier"; + $sql.= " SET fk_statut = ".$this->statut.","; + if (! empty($note)) $sql.= " note_private = '".$this->db->escape($note)."',"; + $sql.= " date_cloture=NULL, fk_user_cloture=NULL"; + $sql.= " WHERE rowid = ".$this->id; + + $this->db->begin(); + + dol_syslog(get_class($this)."::reopen", LOG_DEBUG); + $resql = $this->db->query($sql); + if (! $resql) { + $error++; $this->errors[]="Error ".$this->db->lasterror(); + } + if (! $error) + { + if (! $notrigger) + { + // Call trigger + $result=$this->call_trigger('ASKPRICESUPPLIER_REOPEN',$user); + if ($result < 0) { $error++; } + // End call triggers + } + } + + // Commit or rollback + if ($error) + { + if (!empty($this->errors)) + { + foreach($this->errors as $errmsg) + { + dol_syslog(get_class($this)."::update ".$errmsg, LOG_ERR); + $this->error.=($this->error?', '.$errmsg:$errmsg); + } + } + $this->db->rollback(); + return -1*$error; + } + else + { + $this->db->commit(); + return 1; + } + } + + + /** + * Close the askprice + * + * @param User $user Object user that close + * @param int $statut Statut + * @param string $note Comment + * @return int <0 if KO, >0 if OK + */ + function cloture($user, $statut, $note) + { + global $langs,$conf; + + $this->statut = $statut; + $error=0; + $now=dol_now(); + + $this->db->begin(); + + $sql = "UPDATE ".MAIN_DB_PREFIX."askpricesupplier"; + $sql.= " SET fk_statut = ".$statut.", note_private = '".$this->db->escape($note)."', date_cloture='".$this->db->idate($now)."', fk_user_cloture=".$user->id; + $sql.= " WHERE rowid = ".$this->id; + + $resql=$this->db->query($sql); + if ($resql) + { + $modelpdf=$conf->global->ASKPRICESUPPLIER_ADDON_PDF_ODT_CLOSED?$conf->global->ASKPRICESUPPLIER_ADDON_PDF_ODT_CLOSED:$this->modelpdf; + $trigger_name='ASKPRICESUPPLIER_CLOSE_REFUSED'; + + if ($statut == 2) + { + $trigger_name='ASKPRICESUPPLIER_CLOSE_SIGNED'; + $modelpdf=$conf->global->ASKPRICESUPPLIER_ADDON_PDF_ODT_TOBILL?$conf->global->ASKPRICESUPPLIER_ADDON_PDF_ODT_TOBILL:$this->modelpdf; + + // The connected company is classified as a client + $soc=new Societe($this->db); + $soc->id = $this->socid; + $result=$soc->set_as_client(); + + if ($result < 0) + { + $this->error=$this->db->error(); + $this->db->rollback(); + return -2; + } + else + { + $this->updateOrCreatePriceFournisseur($user); + } + } + if ($statut == 4) + { + $trigger_name='ASKPRICESUPPLIER_CLASSIFY_BILLED'; + } + + 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 + $this->generateDocument($modelpdf, $outputlangs, $hidedetails, $hidedesc, $hideref); + } + + // Call trigger + $result=$this->call_trigger($trigger_name,$user); + if ($result < 0) { $error++; } + // End call triggers + + if ( ! $error ) + { + $this->db->commit(); + return 1; + } + else + { + $this->db->rollback(); + return -1; + } + } + else + { + $this->error=$this->db->error(); + $this->db->rollback(); + return -1; + } + } + + /** + * Choose between update or create ProductFournisseur + * + * @param User $user Object user + */ + function updateOrCreatePriceFournisseur($user) + { + $productsupplier = new ProductFournisseur($this->db); + + dol_syslog(get_class($this)."::updateOrCreatePriceFournisseur", LOG_DEBUG); + foreach ($this->lines as $product) { + if ($product->subprice <= 0) + continue; + + $idProductFourn = $productsupplier->find_min_price_product_fournisseur($product->fk_product, $product->qty); + $res = $productsupplier->fetch($idProductFourn); + + if ($productsupplier->id) { + if ($productsupplier->fourn_qty == $product->qty) { + $this->updatePriceFournisseur($productsupplier->product_fourn_price_id, $product, $user); + } else { + $this->createPriceFournisseur($product, $user); + } + } else { + $this->createPriceFournisseur($product, $user); + } + } + } + + /** + * Upate ProductFournisseur + * + * @param int $idProductFournPrice id of llx_product_fournisseur_price + * @param int $product contain informations to update + * @param User $user Object user + * @return int <0 if KO, >0 if OK + */ + function updatePriceFournisseur($idProductFournPrice, $product, $user) { + $price=price2num($product->subprice*$product->qty,'MU'); + $unitPrice = price2num($product->subprice,'MU'); + + $sql = 'UPDATE '.MAIN_DB_PREFIX.'product_fournisseur_price SET '.(!empty($product->ref_fourn) ? 'ref_fourn = "'.$product->ref_fourn.'", ' : '').' price ='.$price.', unitprice ='.$unitPrice.' WHERE rowid = '.$idProductFournPrice; + + $resql = $this->db->query($sql); + if (!resql) { + $this->error=$this->db->error(); + $this->db->rollback(); + return -1; + } + } + + /** + * Create ProductFournisseur + * + * @param Product $product Object Product + * @param User $user Object user + * @return int <0 if KO, >0 if OK + */ + function createPriceFournisseur($product, $user) { + $price=price2num($product->subprice*$product->qty,'MU'); + $qty=price2num($product->qty); + $unitPrice = price2num($product->subprice,'MU'); + $now=dol_now(); + + $values = array( + "'".$this->db->idate($now)."'", + $product->fk_product, + $this->client->id, + "'".$product->ref_fourn."'", + $price, + $qty, + $unitPrice, + $product->tva_tx, + $user->id + ); + + $sql = 'INSERT INTO '.MAIN_DB_PREFIX.'product_fournisseur_price '; + $sql .= '(datec, fk_product, fk_soc, ref_fourn, price, quantity, unitprice, tva_tx, fk_user) VALUES ('.implode(',', $values).')'; + + $resql = $this->db->query($sql); + if (!resql) { + $this->error=$this->db->error(); + $this->db->rollback(); + return -1; + } + } + + /** + * Set draft status + * + * @param User $user Object user that modify + * @return int <0 if KO, >0 if OK + */ + function set_draft($user) + { + global $conf,$langs; + + $sql = "UPDATE ".MAIN_DB_PREFIX."askpricesupplier SET fk_statut = 0"; + $sql.= " WHERE rowid = ".$this->id; + + if ($this->db->query($sql)) + { + $this->statut = 0; + $this->brouillon = 1; + return 1; + } + else + { + return -1; + } + } + + + /** + * Return list of askprice (eventually filtered on user) into an array + * + * @param int $shortlist 0=Return array[id]=ref, 1=Return array[](id=>id,ref=>ref,name=>name) + * @param int $draft 0=not draft, 1=draft + * @param int $notcurrentuser 0=all user, 1=not current user + * @param int $socid Id third pary + * @param int $limit For pagination + * @param int $offset For pagination + * @param string $sortfield Sort criteria + * @param string $sortorder Sort order + * @return int -1 if KO, array with result if OK + */ + function liste_array($shortlist=0, $draft=0, $notcurrentuser=0, $socid=0, $limit=0, $offset=0, $sortfield='p.datec', $sortorder='DESC') + { + global $conf,$user; + + $ga = array(); + + $sql = "SELECT s.rowid, s.nom as name, s.client,"; + $sql.= " p.rowid as askpricesupplierid, p.fk_statut, p.total_ht, p.ref, p.remise, "; + $sql.= " p.datep as dp, p.fin_validite as datelimite"; + if (! $user->rights->societe->client->voir && ! $socid) $sql .= ", sc.fk_soc, sc.fk_user"; + $sql.= " FROM ".MAIN_DB_PREFIX."societe as s, ".MAIN_DB_PREFIX."askpricesupplier as p, ".MAIN_DB_PREFIX."c_propalst as c"; + if (! $user->rights->societe->client->voir && ! $socid) $sql .= ", ".MAIN_DB_PREFIX."societe_commerciaux as sc"; + $sql.= " WHERE p.entity = ".$conf->entity; + $sql.= " AND p.fk_soc = s.rowid"; + $sql.= " AND p.fk_statut = c.id"; + if (! $user->rights->societe->client->voir && ! $socid) //restriction + { + $sql.= " AND s.rowid = sc.fk_soc AND sc.fk_user = " .$user->id; + } + if ($socid) $sql.= " AND s.rowid = ".$socid; + if ($draft) $sql.= " AND p.fk_statut = 0"; + if ($notcurrentuser > 0) $sql.= " AND p.fk_user_author <> ".$user->id; + $sql.= $this->db->order($sortfield,$sortorder); + $sql.= $this->db->plimit($limit,$offset); + + $result=$this->db->query($sql); + if ($result) + { + $num = $this->db->num_rows($result); + if ($num) + { + $i = 0; + while ($i < $num) + { + $obj = $this->db->fetch_object($result); + + if ($shortlist == 1) + { + $ga[$obj->askpricesupplierid] = $obj->ref; + } + else if ($shortlist == 2) + { + $ga[$obj->askpricesupplierid] = $obj->ref.' ('.$obj->name.')'; + } + else + { + $ga[$i]['id'] = $obj->askpricesupplierid; + $ga[$i]['ref'] = $obj->ref; + $ga[$i]['name'] = $obj->name; + } + + $i++; + } + } + return $ga; + } + else + { + dol_print_error($this->db); + return -1; + } + } + + /** + * Delete askprice + * + * @param User $user Object user that delete + * @param int $notrigger 1=Does not execute triggers, 0= execuete triggers + * @return int 1 if ok, otherwise if error + */ + function delete($user, $notrigger=0) + { + global $conf,$langs; + require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php'; + + $error=0; + + $this->db->begin(); + + if (! $notrigger) + { + // Call trigger + $result=$this->call_trigger('ASKPRICESUPPLIER_DELETE',$user); + if ($result < 0) { $error++; } + // End call triggers + } + + if (! $error) + { + $sql = "DELETE FROM ".MAIN_DB_PREFIX."askpricesupplierdet WHERE fk_askpricesupplier = ".$this->id; + if ($this->db->query($sql)) + { + $sql = "DELETE FROM ".MAIN_DB_PREFIX."askpricesupplier WHERE rowid = ".$this->id; + if ($this->db->query($sql)) + { + // Delete linked object + $res = $this->deleteObjectLinked(); + if ($res < 0) $error++; + + if (! $error) + { + // We remove directory + $ref = dol_sanitizeFileName($this->ref); + if ($conf->askpricesupplier->dir_output && !empty($this->ref)) + { + $dir = $conf->askpricesupplier->dir_output . "/" . $ref ; + $file = $dir . "/" . $ref . ".pdf"; + if (file_exists($file)) + { + dol_delete_preview($this); + + if (! dol_delete_file($file,0,0,0,$this)) // For triggers + { + $this->error='ErrorFailToDeleteFile'; + $this->errors=array('ErrorFailToDeleteFile'); + $this->db->rollback(); + return 0; + } + } + if (file_exists($dir)) + { + $res=@dol_delete_dir_recursive($dir); + if (! $res) + { + $this->error='ErrorFailToDeleteDir'; + $this->errors=array('ErrorFailToDeleteDir'); + $this->db->rollback(); + return 0; + } + } + } + } + + // Removed extrafields + if (! $error) + { + if (empty($conf->global->MAIN_EXTRAFIELDS_DISABLED)) // For avoid conflicts if trigger used + { + $result=$this->deleteExtraFields(); + if ($result < 0) + { + $error++; + $errorflag=-4; + dol_syslog(get_class($this)."::delete erreur ".$errorflag." ".$this->error, LOG_ERR); + } + } + } + + if (! $error) + { + dol_syslog(get_class($this)."::delete ".$this->id." by ".$user->id, LOG_DEBUG); + $this->db->commit(); + return 1; + } + else + { + $this->error=$this->db->lasterror(); + $this->db->rollback(); + return 0; + } + } + else + { + $this->error=$this->db->lasterror(); + $this->db->rollback(); + return -3; + } + } + else + { + $this->error=$this->db->lasterror(); + $this->db->rollback(); + return -2; + } + } + else + { + $this->db->rollback(); + return -1; + } + } + + /** + * Object AskPriceSupplier Information + * + * @param int $id Proposal id + * @return void + */ + function info($id) + { + $sql = "SELECT c.rowid, "; + $sql.= " c.datec, c.date_valid as datev, c.date_cloture as dateo,"; + $sql.= " c.fk_user_author, c.fk_user_valid, c.fk_user_cloture"; + $sql.= " FROM ".MAIN_DB_PREFIX."askpricesupplier as c"; + $sql.= " WHERE c.rowid = ".$id; + + $result = $this->db->query($sql); + + if ($result) + { + if ($this->db->num_rows($result)) + { + $obj = $this->db->fetch_object($result); + + $this->id = $obj->rowid; + + $this->date_creation = $this->db->jdate($obj->datec); + $this->date_validation = $this->db->jdate($obj->datev); + $this->date_cloture = $this->db->jdate($obj->dateo); + + $cuser = new User($this->db); + $cuser->fetch($obj->fk_user_author); + $this->user_creation = $cuser; + + if ($obj->fk_user_valid) + { + $vuser = new User($this->db); + $vuser->fetch($obj->fk_user_valid); + $this->user_validation = $vuser; + } + + if ($obj->fk_user_cloture) + { + $cluser = new User($this->db); + $cluser->fetch($obj->fk_user_cloture); + $this->user_cloture = $cluser; + } + + + } + $this->db->free($result); + + } + else + { + dol_print_error($this->db); + } + } + + + /** + * Return label of status of proposal (draft, validated, ...) + * + * @param int $mode 0=long label, 1=short label, 2=Picto + short label, 3=Picto, 4=Picto + long label, 5=Short label + Picto + * @return string Label + */ + function getLibStatut($mode=0) + { + return $this->LibStatut($this->statut,$mode); + } + + /** + * Return label of a status (draft, validated, ...) + * + * @param int $statut id statut + * @param int $mode 0=long label, 1=short label, 2=Picto + short label, 3=Picto, 4=Picto + long label, 5=Short label + Picto + * @return string Label + */ + function LibStatut($statut,$mode=1) + { + global $langs; + $langs->load("askpricesupplier"); + + if ($statut==0) $statuttrans='statut0'; + if ($statut==1) $statuttrans='statut1'; + if ($statut==2) $statuttrans='statut3'; + if ($statut==3) $statuttrans='statut5'; + if ($statut==4) $statuttrans='statut6'; + + if ($mode == 0) return $this->labelstatut[$statut]; + if ($mode == 1) return $this->labelstatut_short[$statut]; + if ($mode == 2) return img_picto($this->labelstatut_short[$statut], $statuttrans).' '.$this->labelstatut_short[$statut]; + if ($mode == 3) return img_picto($this->labelstatut[$statut], $statuttrans); + if ($mode == 4) return img_picto($this->labelstatut[$statut],$statuttrans).' '.$this->labelstatut[$statut]; + if ($mode == 5) return '<span class="hideonsmartphone">'.$this->labelstatut_short[$statut].' </span>'.img_picto($this->labelstatut_short[$statut],$statuttrans); + } + + + /** + * Load indicators for dashboard (this->nbtodo and this->nbtodolate) + * + * @param User $user Object user + * @param int $mode "opened" for askprice to close, "signed" for proposal to invoice + * @return int <0 if KO, >0 if OK + */ + function load_board($user,$mode) + { + global $conf, $user; + + $now=dol_now(); + + $this->nbtodo=$this->nbtodolate=0; + $clause = " WHERE"; + + $sql = "SELECT p.rowid, p.ref, p.datec as datec"; + $sql.= " FROM ".MAIN_DB_PREFIX."askpricesupplier as p"; + if (!$user->rights->societe->client->voir && !$user->societe_id) + { + $sql.= " LEFT JOIN ".MAIN_DB_PREFIX."societe_commerciaux as sc ON p.fk_soc = sc.fk_soc"; + $sql.= " WHERE sc.fk_user = " .$user->id; + $clause = " AND"; + } + $sql.= $clause." p.entity = ".$conf->entity; + if ($mode == 'opened') $sql.= " AND p.fk_statut = 1"; + if ($mode == 'signed') $sql.= " AND p.fk_statut = 2"; + if ($user->societe_id) $sql.= " AND p.fk_soc = ".$user->societe_id; + + $resql=$this->db->query($sql); + if ($resql) + { + if ($mode == 'opened') $delay_warning=$conf->askpricesupplier->cloture->warning_delay; + if ($mode == 'signed') $delay_warning=$conf->askpricesupplier->facturation->warning_delay; + + // This assignment in condition is not a bug. It allows walking the results. + while ($obj=$this->db->fetch_object($resql)) + { + $this->nbtodo++; + if ($mode == 'opened') + { + $datelimit = $this->db->jdate($obj->datefin); + if ($datelimit < ($now - $delay_warning)) + { + $this->nbtodolate++; + } + } + // TODO Definir regle des propales a facturer en retard + // if ($mode == 'signed' && ! count($this->FactureListeArray($obj->rowid))) $this->nbtodolate++; + } + return 1; + } + else + { + $this->error=$this->db->error(); + return -1; + } + } + + + /** + * Initialise an instance with random values. + * Used to build previews or test instances. + * id must be 0 if object instance is a specimen. + * + * @return void + */ + function initAsSpecimen() + { + global $user,$langs,$conf; + + // Charge tableau des produits prodids + $prodids = array(); + $sql = "SELECT rowid"; + $sql.= " FROM ".MAIN_DB_PREFIX."product"; + $sql.= " WHERE entity IN (".getEntity('product', 1).")"; + $resql = $this->db->query($sql); + if ($resql) + { + $num_prods = $this->db->num_rows($resql); + $i = 0; + while ($i < $num_prods) + { + $i++; + $row = $this->db->fetch_row($resql); + $prodids[$i] = $row[0]; + } + } + + // Initialise parametres + $this->id=0; + $this->ref = 'SPECIMEN'; + $this->specimen=1; + $this->socid = 1; + $this->date = time(); + $this->cond_reglement_id = 1; + $this->cond_reglement_code = 'RECEP'; + $this->mode_reglement_id = 7; + $this->mode_reglement_code = 'CHQ'; + $this->note_public='This is a comment (public)'; + $this->note_private='This is a comment (private)'; + // Lines + $nbp = 5; + $xnbp = 0; + while ($xnbp < $nbp) + { + $line=new AskPriceSupplierLigne($this->db); + $line->desc=$langs->trans("Description")." ".$xnbp; + $line->qty=1; + $line->subprice=100; + $line->price=100; + $line->tva_tx=19.6; + $line->localtax1_tx=0; + $line->localtax2_tx=0; + if ($xnbp == 2) + { + $line->total_ht=50; + $line->total_ttc=59.8; + $line->total_tva=9.8; + $line->remise_percent=50; + } + else + { + $line->total_ht=100; + $line->total_ttc=119.6; + $line->total_tva=19.6; + $line->remise_percent=00; + } + + $prodid = rand(1, $num_prods); + $line->fk_product=$prodids[$prodid]; + + $this->lines[$xnbp]=$line; + + $this->total_ht += $line->total_ht; + $this->total_tva += $line->total_tva; + $this->total_ttc += $line->total_ttc; + + $xnbp++; + } + } + + /** + * Charge indicateurs this->nb de tableau de bord + * + * @return int <0 if ko, >0 if ok + */ + function load_state_board() + { + global $conf, $user; + + $this->nb=array(); + $clause = "WHERE"; + + $sql = "SELECT count(p.rowid) as nb"; + $sql.= " FROM ".MAIN_DB_PREFIX."askpricesupplier as p"; + $sql.= " LEFT JOIN ".MAIN_DB_PREFIX."societe as s ON p.fk_soc = s.rowid"; + if (!$user->rights->societe->client->voir && !$user->societe_id) + { + $sql.= " LEFT JOIN ".MAIN_DB_PREFIX."societe_commerciaux as sc ON s.rowid = sc.fk_soc"; + $sql.= " WHERE sc.fk_user = " .$user->id; + $clause = "AND"; + } + $sql.= " ".$clause." p.entity = ".$conf->entity; + + $resql=$this->db->query($sql); + if ($resql) + { + // This assignment in condition is not a bug. It allows walking the results. + while ($obj=$this->db->fetch_object($resql)) + { + $this->nb["askprice"]=$obj->nb; + } + $this->db->free($resql); + return 1; + } + else + { + dol_print_error($this->db); + $this->error=$this->db->error(); + return -1; + } + } + + + /** + * Returns the reference to the following non used Proposal used depending on the active numbering module + * defined into ASKPRICESUPPLIER_ADDON + * + * @param Societe $soc Object thirdparty + * @return string Reference libre pour la propale + */ + function getNextNumRef($soc) + { + global $conf, $db, $langs; + $langs->load("askpricesupplier"); + + if (! empty($conf->global->ASKPRICESUPPLIER_ADDON)) + { + $mybool=false; + + $file = $conf->global->ASKPRICESUPPLIER_ADDON.".php"; + $classname = $conf->global->ASKPRICESUPPLIER_ADDON; + + // Include file with class + $dirmodels = array_merge(array('/'), (array) $conf->modules_parts['models']); + foreach ($dirmodels as $reldir) { + + $dir = dol_buildpath($reldir."core/modules/askpricesupplier/"); + + // Load file with numbering class (if found) + $mybool|=@include_once $dir.$file; + } + + if (! $mybool) + { + dol_print_error('',"Failed to include file ".$file); + return ''; + } + + $obj = new $classname(); + $numref = ""; + $numref = $obj->getNextValue($soc,$this); + + if ($numref != "") + { + return $numref; + } + else + { + $this->error=$obj->error; + return ""; + } + } + else + { + $langs->load("errors"); + print $langs->trans("Error")." ".$langs->trans("ErrorModuleSetupNotComplete"); + return ""; + } + } + + /** + * Return clicable link of object (with eventually picto) + * + * @param int $withpicto Add picto into link + * @param string $option Where point the link ('compta', 'expedition', 'document', ...) + * @param string $get_params Parametres added to url + * @return string String with URL + */ + function getNomUrl($withpicto=0,$option='', $get_params='') + { + global $langs; + + $result=''; + $label=$langs->trans("ShowAskpricesupplier").': '.$this->ref; + $linkclose = '" title="'.dol_escape_htmltag($label, 1).'" class="classfortooltip">'; + if ($option == '') { + $lien = '<a href="'.DOL_URL_ROOT.'/comm/askpricesupplier/card.php?id='.$this->id. $get_params .$linkclose; + } + if ($option == 'document') { + $lien = '<a href="'.DOL_URL_ROOT.'/comm/askpricesupplier/document.php?id='.$this->id. $get_params .$linkclose; + } + $lienfin='</a>'; + + $picto='askpricesupplier'; + + + if ($withpicto) + $result.=($lien.img_object($label, $picto, 'class="classfortooltip"').$lienfin); + if ($withpicto && $withpicto != 2) + $result.=' '; + $result.=$lien.$this->ref.$lienfin; + return $result; + } + + /** + * Retrieve an array of askprice lines + * + * @return int <0 if ko, >0 if ok + */ + function getLinesArray() + { + $sql = 'SELECT pt.rowid, pt.label as custom_label, pt.description, pt.fk_product, pt.fk_remise_except,'; + $sql.= ' pt.qty, pt.tva_tx, pt.remise_percent, pt.subprice, pt.info_bits,'; + $sql.= ' pt.total_ht, pt.total_tva, pt.total_ttc, pt.fk_product_fournisseur_price as fk_fournprice, pt.buy_price_ht as pa_ht, pt.special_code, pt.localtax1_tx, pt.localtax2_tx,'; + $sql.= ' pt.product_type, pt.rang, pt.fk_parent_line,'; + $sql.= ' p.label as product_label, p.ref, p.fk_product_type, p.rowid as prodid,'; + $sql.= ' p.description as product_desc, pt.ref_fourn as ref_produit_fourn'; + $sql.= ' FROM '.MAIN_DB_PREFIX.'askpricesupplierdet as pt'; + $sql.= ' LEFT JOIN '.MAIN_DB_PREFIX.'product as p ON pt.fk_product=p.rowid'; + $sql.= ' WHERE pt.fk_askpricesupplier = '.$this->id; + $sql.= ' ORDER BY pt.rang ASC, pt.rowid'; + + dol_syslog(get_class($this).'::getLinesArray', LOG_DEBUG); + $resql = $this->db->query($sql); + if ($resql) + { + $num = $this->db->num_rows($resql); + $i = 0; + + while ($i < $num) + { + $obj = $this->db->fetch_object($resql); + + $this->lines[$i] = new AskPriceSupplierLigne($this->db); + $this->lines[$i]->id = $obj->rowid; // for backward compatibility + $this->lines[$i]->rowid = $obj->rowid; + $this->lines[$i]->label = $obj->custom_label; + $this->lines[$i]->description = $obj->description; + $this->lines[$i]->fk_product = $obj->fk_product; + $this->lines[$i]->ref = $obj->ref; + $this->lines[$i]->product_label = $obj->product_label; + $this->lines[$i]->product_desc = $obj->product_desc; + $this->lines[$i]->fk_product_type = $obj->fk_product_type; // deprecated + $this->lines[$i]->product_type = $obj->product_type; + $this->lines[$i]->qty = $obj->qty; + $this->lines[$i]->subprice = $obj->subprice; + $this->lines[$i]->fk_remise_except = $obj->fk_remise_except; + $this->lines[$i]->remise_percent = $obj->remise_percent; + $this->lines[$i]->tva_tx = $obj->tva_tx; + $this->lines[$i]->info_bits = $obj->info_bits; + $this->lines[$i]->total_ht = $obj->total_ht; + $this->lines[$i]->total_tva = $obj->total_tva; + $this->lines[$i]->total_ttc = $obj->total_ttc; + $this->lines[$i]->fk_fournprice = $obj->fk_fournprice; + $marginInfos = getMarginInfos($obj->subprice, $obj->remise_percent, $obj->tva_tx, $obj->localtax1_tx, $obj->localtax2_tx, $this->lines[$i]->fk_fournprice, $obj->pa_ht); + $this->lines[$i]->pa_ht = $marginInfos[0]; + $this->lines[$i]->marge_tx = $marginInfos[1]; + $this->lines[$i]->marque_tx = $marginInfos[2]; + $this->lines[$i]->fk_parent_line = $obj->fk_parent_line; + $this->lines[$i]->special_code = $obj->special_code; + $this->lines[$i]->rang = $obj->rang; + + $this->lines[$i]->ref_fourn = $obj->ref_produit_fourn; + + $i++; + } + $this->db->free($resql); + + return 1; + } + else + { + $this->error=$this->db->error(); + return -1; + } + } + + /** + * Create a document onto disk according to template module. + * + * @param string $modele Force model to use ('' to not force) + * @param Translate $outputlangs Object langs to use for output + * @param int $hidedetails Hide details of lines + * @param int $hidedesc Hide description + * @param int $hideref Hide ref + * @return int 0 if KO, 1 if OK + */ + public function generateDocument($modele, $outputlangs, $hidedetails=0, $hidedesc=0, $hideref=0) + { + global $conf,$user,$langs; + + $langs->load("askpricesupplier"); + + // Positionne le modele sur le nom du modele a utiliser + if (! dol_strlen($modele)) + { + if (! empty($conf->global->ASKPRICESUPPLIER_ADDON_PDF)) + { + $modele = $conf->global->ASKPRICESUPPLIER_ADDON_PDF; + } + else + { + $modele = 'aurore'; + } + } + + $modelpath = "core/modules/askpricesupplier/doc/"; + + return $this->commonGenerateDocument($modelpath, $modele, $outputlangs, $hidedetails, $hidedesc, $hideref); + } + + + function printOriginLinesList() + { + global $langs, $hookmanager; + + print '<tr class="liste_titre">'; + print '<td>'.$langs->trans('Ref').'</td>'; + print '<td>'.$langs->trans('Description').'</td>'; + print '<td align="right">'.$langs->trans('VAT').'</td>'; + print '<td align="right">'.$langs->trans('PriceUHT').'</td>'; + print '<td align="right">'.$langs->trans('Qty').'</td>'; + print '<td align="right">'.$langs->trans('ReductionShort').'</td></tr>'; + + $num = count($this->lines); + $var = true; + $i = 0; + + foreach ($this->lines as $line) + { + if (empty($line->subprice) || $line->qty <= 0) + continue; + + $var=!$var; + + if (is_object($hookmanager) && (($line->product_type == 9 && ! empty($line->special_code)) || ! empty($line->fk_parent_line))) + { + if (empty($line->fk_parent_line)) + { + $parameters=array('line'=>$line,'var'=>$var,'i'=>$i); + $action=''; + $reshook=$hookmanager->executeHooks('printOriginObjectLine',$parameters,$this,$action); // Note that $action and $object may have been modified by some hooks + } + } + else + { + $this->printOriginLine($line,$var); + } + + $i++; + } + } + + +} + + +/** + * \class AskPriceSupplierLigne + * \brief Class to manage askpricesupplier lines + */ +class AskPriceSupplierLigne extends CommonObject +{ + var $db; + var $error; + + public $element='askpricesupplierdet'; + public $table_element='askpricesupplierdet'; + + var $oldline; + + // From llx_askpricesupplierdet + var $rowid; + var $fk_askpricesupplier; + var $fk_parent_line; + var $desc; // Description ligne + var $fk_product; // Id produit predefini + var $product_type = 0; // Type 0 = product, 1 = Service + + var $qty; + var $tva_tx; + var $subprice; + var $remise_percent; + var $fk_remise_except; + + var $rang = 0; + + var $fk_fournprice; + var $pa_ht; + var $marge_tx; + var $marque_tx; + + var $special_code; // Tag for special lines (exlusive tags) + // 1: frais de port + // 2: ecotaxe + // 3: option line (when qty = 0) + + var $info_bits = 0; // Liste d'options cumulables: + // Bit 0: 0 si TVA normal - 1 si TVA NPR + // Bit 1: 0 ligne normale - 1 si ligne de remise fixe + + var $total_ht; // Total HT de la ligne toute quantite et incluant la remise ligne + var $total_tva; // Total TVA de la ligne toute quantite et incluant la remise ligne + var $total_ttc; // Total TTC de la ligne toute quantite et incluant la remise ligne + + // Ne plus utiliser + var $remise; + var $price; + + // From llx_product + var $ref; // Reference produit + var $libelle; // Label produit + var $product_desc; // Description produit + + var $localtax1_tx; // Local tax 1 + var $localtax2_tx; // Local tax 2 + var $localtax1_type; // Local tax 1 type + var $localtax2_type; // Local tax 2 type + var $total_localtax1; // Line total local tax 1 + var $total_localtax2; // Line total local tax 2 + + var $skip_update_total; // Skip update price total for special lines + + var $ref_fourn; + + /** + * Class line Contructor + * + * @param DoliDB $db Database handler + */ + function __construct($db) + { + $this->db= $db; + } + + /** + * Retrieve the propal line object + * + * @param int $rowid Propal line id + * @return int <0 if KO, >0 if OK + */ + function fetch($rowid) + { + $sql = 'SELECT pd.rowid, pd.fk_askpricesupplier, pd.fk_parent_line, pd.fk_product, pd.label as custom_label, pd.description, pd.price, pd.qty, pd.tva_tx,'; + $sql.= ' pd.remise, pd.remise_percent, pd.fk_remise_except, pd.subprice,'; + $sql.= ' pd.info_bits, pd.total_ht, pd.total_tva, pd.total_ttc, pd.fk_product_fournisseur_price as fk_fournprice, pd.buy_price_ht as pa_ht, pd.special_code, pd.rang,'; + $sql.= ' pd.localtax1_tx, pd.localtax2_tx, pd.total_localtax1, pd.total_localtax2,'; + $sql.= ' p.ref as product_ref, p.label as product_label, p.description as product_desc,'; + $sql.= ' pd.product_type, pd.ref_fourn as ref_produit_fourn'; + $sql.= ' FROM '.MAIN_DB_PREFIX.'askpricesupplierdet as pd'; + $sql.= ' LEFT JOIN '.MAIN_DB_PREFIX.'product as p ON pd.fk_product = p.rowid'; + $sql.= ' WHERE pd.rowid = '.$rowid; + + $result = $this->db->query($sql); + if ($result) + { + $objp = $this->db->fetch_object($result); + + $this->rowid = $objp->rowid; + $this->fk_askpricesupplier = $objp->fk_askpricesupplier; + $this->fk_parent_line = $objp->fk_parent_line; + $this->label = $objp->custom_label; + $this->desc = $objp->description; + $this->qty = $objp->qty; + $this->price = $objp->price; // deprecated + $this->subprice = $objp->subprice; + $this->tva_tx = $objp->tva_tx; + $this->remise = $objp->remise; + $this->remise_percent = $objp->remise_percent; + $this->fk_remise_except = $objp->fk_remise_except; + $this->fk_product = $objp->fk_product; + $this->info_bits = $objp->info_bits; + + $this->total_ht = $objp->total_ht; + $this->total_tva = $objp->total_tva; + $this->total_ttc = $objp->total_ttc; + + $this->fk_fournprice = $objp->fk_fournprice; + + $marginInfos = getMarginInfos($objp->subprice, $objp->remise_percent, $objp->tva_tx, $objp->localtax1_tx, $objp->localtax2_tx, $this->fk_fournprice, $objp->pa_ht); + $this->pa_ht = $marginInfos[0]; + $this->marge_tx = $marginInfos[1]; + $this->marque_tx = $marginInfos[2]; + + $this->special_code = $objp->special_code; + $this->product_type = $objp->product_type; + $this->rang = $objp->rang; + + $this->ref = $objp->product_ref; // deprecated + $this->product_ref = $objp->product_ref; + $this->libelle = $objp->product_label; // deprecated + $this->product_label = $objp->product_label; + $this->product_desc = $objp->product_desc; + + $this->ref_fourn = $objp->ref_produit_forun; + + $this->db->free($result); + } + else + { + dol_print_error($this->db); + } + } + + /** + * Insert object line propal in database + * + * @param int $notrigger 1=Does not execute triggers, 0= execuete triggers + * @return int <0 if KO, >0 if OK + */ + function insert($notrigger=0) + { + global $conf,$langs,$user; + + $error=0; + + dol_syslog(get_class($this)."::insert rang=".$this->rang); + + // Clean parameters + if (empty($this->tva_tx)) $this->tva_tx=0; + if (empty($this->localtax1_tx)) $this->localtax1_tx=0; + if (empty($this->localtax2_tx)) $this->localtax2_tx=0; + if (empty($this->localtax1_type)) $this->localtax1_type=0; + if (empty($this->localtax2_type)) $this->localtax2_type=0; + if (empty($this->total_localtax1)) $this->total_localtax1=0; + if (empty($this->total_localtax2)) $this->total_localtax2=0; + if (empty($this->rang)) $this->rang=0; + if (empty($this->remise)) $this->remise=0; + if (empty($this->remise_percent)) $this->remise_percent=0; + if (empty($this->info_bits)) $this->info_bits=0; + if (empty($this->special_code)) $this->special_code=0; + if (empty($this->fk_parent_line)) $this->fk_parent_line=0; + if (empty($this->fk_fournprice)) $this->fk_fournprice=0; + + if (empty($this->pa_ht)) $this->pa_ht=0; + + // si prix d'achat non renseigne et utilise pour calcul des marges alors prix achat = prix vente + if ($this->pa_ht == 0) { + if ($this->subprice > 0 && (isset($conf->global->ForceBuyingPriceIfNull) && $conf->global->ForceBuyingPriceIfNull == 1)) + $this->pa_ht = $this->subprice * (1 - $this->remise_percent / 100); + } + + // Check parameters + if ($this->product_type < 0) return -1; + + $this->db->begin(); + + // Insert line into database + $sql = 'INSERT INTO '.MAIN_DB_PREFIX.'askpricesupplierdet'; + $sql.= ' (fk_askpricesupplier, fk_parent_line, label, description, fk_product, product_type,'; + $sql.= ' fk_remise_except, qty, tva_tx, localtax1_tx, localtax2_tx, localtax1_type, localtax2_type,'; + $sql.= ' subprice, remise_percent, '; + $sql.= ' info_bits, '; + $sql.= ' total_ht, total_tva, total_localtax1, total_localtax2, total_ttc, fk_product_fournisseur_price, buy_price_ht, special_code, rang,'; + $sql.= ' ref_fourn)'; + $sql.= " VALUES (".$this->fk_askpricesupplier.","; + $sql.= " ".($this->fk_parent_line>0?"'".$this->fk_parent_line."'":"null").","; + $sql.= " ".(! empty($this->label)?"'".$this->db->escape($this->label)."'":"null").","; + $sql.= " '".$this->db->escape($this->desc)."',"; + $sql.= " ".($this->fk_product?"'".$this->fk_product."'":"null").","; + $sql.= " '".$this->product_type."',"; + $sql.= " ".($this->fk_remise_except?"'".$this->fk_remise_except."'":"null").","; + $sql.= " ".price2num($this->qty).","; + $sql.= " ".price2num($this->tva_tx).","; + $sql.= " ".price2num($this->localtax1_tx).","; + $sql.= " ".price2num($this->localtax2_tx).","; + $sql.= " '".$this->localtax1_type."',"; + $sql.= " '".$this->localtax2_type."',"; + $sql.= " ".($this->subprice?price2num($this->subprice):"null").","; + $sql.= " ".price2num($this->remise_percent).","; + $sql.= " ".(isset($this->info_bits)?"'".$this->info_bits."'":"null").","; + $sql.= " ".price2num($this->total_ht).","; + $sql.= " ".price2num($this->total_tva).","; + $sql.= " ".price2num($this->total_localtax1).","; + $sql.= " ".price2num($this->total_localtax2).","; + $sql.= " ".price2num($this->total_ttc).","; + $sql.= " ".(!empty($this->fk_fournprice)?"'".$this->fk_fournprice."'":"null").","; + $sql.= " ".(isset($this->pa_ht)?"'".price2num($this->pa_ht)."'":"null").","; + $sql.= ' '.$this->special_code.','; + $sql.= ' '.$this->rang.','; + $sql.= " '".$this->db->escape($this->ref_fourn)."'"; + $sql.= ')'; + + dol_syslog(get_class($this).'::insert', LOG_DEBUG); + $resql=$this->db->query($sql); + if ($resql) + { + $this->rowid=$this->db->last_insert_id(MAIN_DB_PREFIX.'askpricesupplierdet'); + + if (empty($conf->global->MAIN_EXTRAFIELDS_DISABLED)) // For avoid conflicts if trigger used + { + $this->id=$this->rowid; + $result=$this->insertExtraFields(); + if ($result < 0) + { + $error++; + } + } + + if (! $notrigger) + { + // Call trigger + $result=$this->call_trigger('LINEASKPRICESUPPLIER_INSERT',$user); + if ($result < 0) + { + $this->db->rollback(); + return -1; + } + // End call triggers + } + + $this->db->commit(); + return 1; + } + else + { + $this->error=$this->db->error()." sql=".$sql; + $this->db->rollback(); + return -1; + } + } + + /** + * Delete line in database + * + * @return int <0 if ko, >0 if ok + */ + function delete() + { + global $conf,$langs,$user; + + $error=0; + $this->db->begin(); + + $sql = "DELETE FROM ".MAIN_DB_PREFIX."askpricesupplierdet WHERE rowid = ".$this->rowid; + dol_syslog("AskPriceSupplierLigne::delete", LOG_DEBUG); + if ($this->db->query($sql) ) + { + + // Remove extrafields + if ((! $error) && (empty($conf->global->MAIN_EXTRAFIELDS_DISABLED))) // For avoid conflicts if trigger used + { + $this->id=$this->rowid; + $result=$this->deleteExtraFields(); + if ($result < 0) + { + $error++; + dol_syslog(get_class($this)."::delete error -4 ".$this->error, LOG_ERR); + } + } + + // Call trigger + $result=$this->call_trigger('LINEASKPRICESUPLLIER_DELETE',$user); + if ($result < 0) + { + $this->db->rollback(); + return -1; + } + // End call triggers + + $this->db->commit(); + + return 1; + } + else + { + $this->error=$this->db->error()." sql=".$sql; + $this->db->rollback(); + return -1; + } + } + + /** + * Update propal line object into DB + * + * @param int $notrigger 1=Does not execute triggers, 0= execuete triggers + * @return int <0 if ko, >0 if ok + */ + function update($notrigger=0) + { + global $conf,$langs,$user; + + $error=0; + + // Clean parameters + if (empty($this->tva_tx)) $this->tva_tx=0; + if (empty($this->localtax1_tx)) $this->localtax1_tx=0; + if (empty($this->localtax2_tx)) $this->localtax2_tx=0; + if (empty($this->total_localtax1)) $this->total_localtax1=0; + if (empty($this->total_localtax2)) $this->total_localtax2=0; + if (empty($this->localtax1_type)) $this->localtax1_type=0; + if (empty($this->localtax2_type)) $this->localtax2_type=0; + if (empty($this->marque_tx)) $this->marque_tx=0; + if (empty($this->marge_tx)) $this->marge_tx=0; + if (empty($this->price)) $this->price=0; // TODO A virer + if (empty($this->remise)) $this->remise=0; // TODO A virer + if (empty($this->remise_percent)) $this->remise_percent=0; + if (empty($this->info_bits)) $this->info_bits=0; + if (empty($this->special_code)) $this->special_code=0; + if (empty($this->fk_parent_line)) $this->fk_parent_line=0; + if (empty($this->fk_fournprice)) $this->fk_fournprice=0; + + if (empty($this->pa_ht)) $this->pa_ht=0; + + // si prix d'achat non renseigne et utilise pour calcul des marges alors prix achat = prix vente + if ($this->pa_ht == 0) { + if ($this->subprice > 0 && (isset($conf->global->ForceBuyingPriceIfNull) && $conf->global->ForceBuyingPriceIfNull == 1)) + $this->pa_ht = $this->subprice * (1 - $this->remise_percent / 100); + } + + $this->db->begin(); + + // Mise a jour ligne en base + $sql = "UPDATE ".MAIN_DB_PREFIX."askpricesupplierdet SET"; + $sql.= " description='".$this->db->escape($this->desc)."'"; + $sql.= " , label=".(! empty($this->label)?"'".$this->db->escape($this->label)."'":"null"); + $sql.= " , product_type=".$this->product_type; + $sql.= " , tva_tx='".price2num($this->tva_tx)."'"; + $sql.= " , localtax1_tx=".price2num($this->localtax1_tx); + $sql.= " , localtax2_tx=".price2num($this->localtax2_tx); + $sql.= " , localtax1_type='".$this->localtax1_type."'"; + $sql.= " , localtax2_type='".$this->localtax2_type."'"; + $sql.= " , qty='".price2num($this->qty)."'"; + $sql.= " , subprice=".price2num($this->subprice).""; + $sql.= " , remise_percent=".price2num($this->remise_percent).""; + $sql.= " , price=".price2num($this->price).""; // TODO A virer + $sql.= " , remise=".price2num($this->remise).""; // TODO A virer + $sql.= " , info_bits='".$this->info_bits."'"; + if (empty($this->skip_update_total)) + { + $sql.= " , total_ht=".price2num($this->total_ht).""; + $sql.= " , total_tva=".price2num($this->total_tva).""; + $sql.= " , total_ttc=".price2num($this->total_ttc).""; + $sql.= " , total_localtax1=".price2num($this->total_localtax1).""; + $sql.= " , total_localtax2=".price2num($this->total_localtax2).""; + } + $sql.= " , fk_product_fournisseur_price=".(! empty($this->fk_fournprice)?"'".$this->fk_fournprice."'":"null"); + $sql.= " , buy_price_ht=".price2num($this->pa_ht); + if (strlen($this->special_code)) $sql.= " , special_code=".$this->special_code; + $sql.= " , fk_parent_line=".($this->fk_parent_line>0?$this->fk_parent_line:"null"); + if (! empty($this->rang)) $sql.= ", rang=".$this->rang; + $sql.= " , ref_fourn=".(! empty($this->ref_fourn)?"'".$this->db->escape($this->ref_fourn)."'":"null"); + $sql.= " WHERE rowid = ".$this->rowid; + + dol_syslog(get_class($this)."::update", LOG_DEBUG); + $resql=$this->db->query($sql); + if ($resql) + { + if (empty($conf->global->MAIN_EXTRAFIELDS_DISABLED)) // For avoid conflicts if trigger used + { + $this->id=$this->rowid; + $result=$this->insertExtraFields(); + if ($result < 0) + { + $error++; + } + } + + if (! $notrigger) + { + // Call trigger + $result=$this->call_trigger('LINEASKPRICESUPPLIER_UPDATE',$user); + if ($result < 0) + { + $this->db->rollback(); + return -1; + } + // End call triggers + } + + $this->db->commit(); + return 1; + } + else + { + $this->error=$this->db->error(); + $this->db->rollback(); + return -2; + } + } + + /** + * Update DB line fields total_xxx + * Used by migration + * + * @return int <0 if ko, >0 if ok + */ + function update_total() + { + $this->db->begin(); + + // Mise a jour ligne en base + $sql = "UPDATE ".MAIN_DB_PREFIX."askpricesupplierdet SET"; + $sql.= " total_ht=".price2num($this->total_ht,'MT').""; + $sql.= ",total_tva=".price2num($this->total_tva,'MT').""; + $sql.= ",total_ttc=".price2num($this->total_ttc,'MT').""; + $sql.= " WHERE rowid = ".$this->rowid; + + dol_syslog("AskPriceSupplierLigne::update_total", LOG_DEBUG); + + $resql=$this->db->query($sql); + if ($resql) + { + $this->db->commit(); + return 1; + } + else + { + $this->error=$this->db->error(); + $this->db->rollback(); + return -2; + } + } + +} + diff --git a/htdocs/comm/askpricesupplier/class/index.html b/htdocs/comm/askpricesupplier/class/index.html new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/htdocs/comm/askpricesupplier/document.php b/htdocs/comm/askpricesupplier/document.php new file mode 100644 index 0000000000000000000000000000000000000000..f2558e826dcac4e3a96f5f8db9e9e6c57b1fe500 --- /dev/null +++ b/htdocs/comm/askpricesupplier/document.php @@ -0,0 +1,127 @@ +<?php +/* Copyright (C) 2003-2004 Rodolphe Quiedeville <rodolphe@quiedeville.org> + * Copyright (C) 2004-2009 Laurent Destailleur <eldy@users.sourceforge.net> + * Copyright (C) 2005 Marc Barilley / Ocebo <marc@ocebo.com> + * Copyright (C) 2005-2012 Regis Houssin <regis.houssin@capnetworks.com> + * Copyright (C) 2013 Cédric Salvador <csalvador@gpcsolutions.fr> + * + * 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 <http://www.gnu.org/licenses/>. + */ + +/** + * \file htdocs/comm/propal/document.php + * \ingroup propal + * \brief Management page of documents attached to a business proposal + */ + +require '../../main.inc.php'; +require_once DOL_DOCUMENT_ROOT.'/comm/askpricesupplier/class/askpricesupplier.class.php'; +require_once DOL_DOCUMENT_ROOT.'/core/lib/askpricesupplier.lib.php'; +require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php'; +require_once DOL_DOCUMENT_ROOT.'/core/lib/images.lib.php'; +require_once DOL_DOCUMENT_ROOT.'/core/class/html.formfile.class.php'; + +$langs->load('compta'); +$langs->load('other'); + +$action = GETPOST('action','alpha'); +$confirm = GETPOST('confirm','alpha'); +$id = GETPOST('id','int'); +$ref = GETPOST('ref','alpha'); + +// Security check +$socid=''; +if (! empty($user->societe_id)) +{ + $action=''; + $socid = $user->societe_id; +} +$result = restrictedArea($user, 'askpricesupplier', $id); + +// Get parameters +$sortfield = GETPOST("sortfield",'alpha'); +$sortorder = GETPOST("sortorder",'alpha'); +$page = GETPOST("page",'int'); +if ($page == -1) { $page = 0; } +$offset = $conf->liste_limit * $page; +$pageprev = $page - 1; +$pagenext = $page + 1; +if (! $sortorder) $sortorder="ASC"; +if (! $sortfield) $sortfield="name"; + +$object = new AskPriceSupplier($db); +$object->fetch($id,$ref); +if ($object->id > 0) +{ + $object->fetch_thirdparty(); + $upload_dir = $conf->askpricesupplier->dir_output.'/'.dol_sanitizeFileName($object->ref); + include_once DOL_DOCUMENT_ROOT . '/core/tpl/document_actions_pre_headers.tpl.php'; +} + + +/* + * View + */ + +llxHeader('',$langs->trans('CommRequest'),'EN:Ask_Price_Supplier|FR:Demande_de_prix_fournisseur'); + +$form = new Form($db); + +if ($object->id > 0) +{ + $upload_dir = $conf->askpricesupplier->dir_output.'/'.dol_sanitizeFileName($object->ref); + + $head = askpricesupplier_prepare_head($object); + dol_fiche_head($head, 'document', $langs->trans('CommRequest'), 0, 'askpricesupplier'); + + // Construit liste des fichiers + $filearray=dol_dir_list($upload_dir,"files",0,'','(\.meta|_preview\.png)$',$sortfield,(strtolower($sortorder)=='desc'?SORT_DESC:SORT_ASC),1); + $totalsize=0; + foreach($filearray as $key => $file) + { + $totalsize+=$file['size']; + } + + print '<table class="border"width="100%">'; + + $linkback='<a href="'.DOL_URL_ROOT.'/comm/askpricesupplier/list.php'.(! empty($socid)?'?socid='.$socid:'').'">'.$langs->trans("BackToList").'</a>'; + + // Ref + print '<tr><td width="25%">'.$langs->trans('Ref').'</td><td colspan="3">'; + print $form->showrefnav($object,'ref',$linkback,1,'ref','ref',''); + print '</td></tr>'; + + // Supplier + print "<tr><td>".$langs->trans("Supplier")."</td>"; + print '<td colspan="3">'.$object->thirdparty->getNomUrl(1).'</td></tr>'; + + print '<tr><td>'.$langs->trans("NbOfAttachedFiles").'</td><td colspan="3">'.count($filearray).'</td></tr>'; + print '<tr><td>'.$langs->trans("TotalSizeOfAttachedFiles").'</td><td colspan="3">'.$totalsize.' '.$langs->trans("bytes").'</td></tr>'; + + print '</table>'; + + print '</div>'; + + $modulepart = 'askpricesupplier'; + $permission = $user->rights->askpricesupplier->creer; + $param = '&id=' . $object->id; + include_once DOL_DOCUMENT_ROOT . '/core/tpl/document_actions_post_headers.tpl.php'; +} +else +{ + print $langs->trans("ErrorUnknown"); +} + +llxFooter(); +$db->close(); diff --git a/htdocs/comm/askpricesupplier/index.php b/htdocs/comm/askpricesupplier/index.php new file mode 100644 index 0000000000000000000000000000000000000000..2f943cef083c277fdfcb3d7c3d251aeb271d7d33 --- /dev/null +++ b/htdocs/comm/askpricesupplier/index.php @@ -0,0 +1,377 @@ +<?php +/* Copyright (C) 2003-2004 Rodolphe Quiedeville <rodolphe@quiedeville.org> + * Copyright (C) 2004-2011 Laurent Destailleur <eldy@users.sourceforge.net> + * Copyright (C) 2005-2012 Regis Houssin <regis.houssin@capnetworks.com> + * + * 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 <http://www.gnu.org/licenses/>. + */ + +/** + * \file htdocs/comm/propal/index.php + * \ingroup propal + * \brief Home page of proposal area + */ + +require '../../main.inc.php'; +require_once DOL_DOCUMENT_ROOT.'/core/class/html.formfile.class.php'; +require_once DOL_DOCUMENT_ROOT .'/comm/askpricesupplier/class/askpricesupplier.class.php'; + +$langs->load("askpricesupplier"); +$langs->load("companies"); + +// Security check +$socid=GETPOST('socid','int'); +if (isset($user->societe_id) && $user->societe_id > 0) +{ + $action = ''; + $socid = $user->societe_id; +} +$result = restrictedArea($user, 'askpricesupplier'); + + +/* + * View + */ +$now=dol_now(); +$askpricesupplierstatic=new AskPriceSupplier($db); +$companystatic=new Societe($db); +$form = new Form($db); +$formfile = new FormFile($db); +$help_url="EN:Module_Ask_Price_Supplier|FR:Module_Demande_de_prix_fournisseur"; + +llxHeader("",$langs->trans("AskPriceSupplierArea"),$help_url); + +print_fiche_titre($langs->trans("AskPriceSupplierArea")); + +print '<div class="fichecenter"><div class="fichethirdleft">'; + + +/* + * Search form + */ +$var=false; +print '<table class="noborder nohover" width="100%">'; +print '<form method="post" action="'.DOL_URL_ROOT.'/comm/askpricesupplier/list.php">'; +print '<input type="hidden" name="token" value="'.$_SESSION['newtoken'].'">'; +print '<tr class="liste_titre"><td colspan="3">'.$langs->trans("SearchRequest").'</td></tr>'; +print '<tr '.$bc[$var].'><td>'; +print $langs->trans("Ref").':</td><td><input type="text" class="flat" name="sref" size=18></td><td rowspan="2"><input type="submit" value="'.$langs->trans("Search").'" class="button"></td></tr>'; +print '<tr '.$bc[$var].'><td class="nowrap">'.$langs->trans("Other").':</td><td><input type="text" class="flat" name="sall" size="18"></td>'; +print '</tr>'; +print "</form></table><br>\n"; + + +/* + * Statistics + */ + +$sql = "SELECT count(p.rowid), p.fk_statut"; +$sql.= " FROM ".MAIN_DB_PREFIX."societe as s"; +$sql.= ", ".MAIN_DB_PREFIX."askpricesupplier as p"; +if (!$user->rights->societe->client->voir && !$socid) $sql.= ", ".MAIN_DB_PREFIX."societe_commerciaux as sc"; +$sql.= " WHERE p.fk_soc = s.rowid"; +$sql.= " AND p.entity = ".$conf->entity; +if ($user->societe_id) $sql.=' AND p.fk_soc = '.$user->societe_id; +if (!$user->rights->societe->client->voir && !$socid) $sql.= " AND s.rowid = sc.fk_soc AND sc.fk_user = " .$user->id; +$sql.= " AND p.fk_statut IN (0,1,2,3,4)"; +$sql.= " GROUP BY p.fk_statut"; +$resql = $db->query($sql); +if ($resql) +{ + $num = $db->num_rows($resql); + $i = 0; + + $total=0; + $totalinprocess=0; + $dataseries=array(); + $vals=array(); + // -1=Canceled, 0=Draft, 1=Validated, (2=Accepted/On process not managed for customer orders), 3=Closed (Sent/Received, billed or not) + while ($i < $num) + { + $row = $db->fetch_row($resql); + if ($row) + { + //if ($row[1]!=-1 && ($row[1]!=3 || $row[2]!=1)) + { + $vals[$row[1]]=$row[0]; + $totalinprocess+=$row[0]; + } + $total+=$row[0]; + } + $i++; + } + $db->free($resql); + + print '<table class="noborder" width="100%">'; + print '<tr class="liste_titre"><td colspan="2">'.$langs->trans("Statistics").' - '.$langs->trans("CommRequests").'</td></tr>'."\n"; + $var=true; + $listofstatus=array(0,1,2,3,4); + foreach ($listofstatus as $status) + { + $dataseries[]=array('label'=>$askpricesupplierstatic->LibStatut($status,1),'data'=>(isset($vals[$status])?(int) $vals[$status]:0)); + if (! $conf->use_javascript_ajax) + { + $var=!$var; + print "<tr ".$bc[$var].">"; + print '<td>'.$askpricesupplierstatic->LibStatut($status,0).'</td>'; + print '<td align="right"><a href="list.php?statut='.$status.'">'.(isset($vals[$status])?$vals[$status]:0).'</a></td>'; + print "</tr>\n"; + } + } + if ($conf->use_javascript_ajax) + { + print '<tr><td align="center" colspan="2">'; + $data=array('series'=>$dataseries); + dol_print_graph('stats',300,180,$data,1,'pie',1); + print '</td></tr>'; + } + + print '<tr class="liste_total"><td>'.$langs->trans("Total").'</td><td align="right">'.$total.'</td></tr>'; + print "</table><br>"; +} +else +{ + dol_print_error($db); +} + + +/* + * Draft askprice + */ +if (! empty($conf->askpricesupplier->enabled)) +{ + $sql = "SELECT c.rowid, c.ref, s.nom as socname, s.rowid as socid, s.canvas, s.client"; + $sql.= " FROM ".MAIN_DB_PREFIX."askpricesupplier as c"; + $sql.= ", ".MAIN_DB_PREFIX."societe as s"; + if (!$user->rights->societe->client->voir && !$socid) $sql.= ", ".MAIN_DB_PREFIX."societe_commerciaux as sc"; + $sql.= " WHERE c.fk_soc = s.rowid"; + $sql.= " AND c.entity = ".$conf->entity; + $sql.= " AND c.fk_statut = 0"; + if ($socid) $sql.= " AND c.fk_soc = ".$socid; + if (!$user->rights->societe->client->voir && !$socid) $sql.= " AND s.rowid = sc.fk_soc AND sc.fk_user = " .$user->id; + + $resql=$db->query($sql); + if ($resql) + { + print '<table class="noborder" width="100%">'; + print '<tr class="liste_titre">'; + print '<td colspan="2">'.$langs->trans("DraftRequests").'</td></tr>'; + $langs->load("askpricesupplier"); + $num = $db->num_rows($resql); + if ($num) + { + $i = 0; + $var = True; + while ($i < $num) + { + $var=!$var; + $obj = $db->fetch_object($resql); + print "<tr ".$bc[$var].">"; + + $askpricesupplierstatic->id=$obj->rowid; + $askpricesupplierstatic->ref=$obj->ref; + print '<td class="nowrap">'.$askpricesupplierstatic->getNomUrl(1).'</td>'; + + $companystatic->id=$obj->socid; + $companystatic->name=$obj->socname; + $companystatic->client=$obj->client; + $companystatic->canvas=$obj->canvas; + print '<td>'.$companystatic->getNomUrl(1,'customer',24).'</td>'; + + print '</tr>'; + $i++; + } + } + print "</table><br>"; + } +} + +print '</div><div class="fichetwothirdright"><div class="ficheaddleft">'; + + +$max=5; + +/* + * Last modified askprice + */ + +$sql = "SELECT c.rowid, c.ref, c.fk_statut, s.nom as socname, s.rowid as socid, s.canvas, s.client,"; +$sql.= " date_cloture as datec"; +$sql.= " FROM ".MAIN_DB_PREFIX."askpricesupplier as c"; +$sql.= ", ".MAIN_DB_PREFIX."societe as s"; +if (!$user->rights->societe->client->voir && !$socid) $sql.= ", ".MAIN_DB_PREFIX."societe_commerciaux as sc"; +$sql.= " WHERE c.fk_soc = s.rowid"; +$sql.= " AND c.entity = ".$conf->entity; +//$sql.= " AND c.fk_statut > 2"; +if ($socid) $sql .= " AND c.fk_soc = ".$socid; +if (!$user->rights->societe->client->voir && !$socid) $sql.= " AND s.rowid = sc.fk_soc AND sc.fk_user = " .$user->id; +$sql.= " ORDER BY c.tms DESC"; +$sql.= $db->plimit($max, 0); + +$resql=$db->query($sql); +if ($resql) +{ + print '<table class="noborder" width="100%">'; + print '<tr class="liste_titre">'; + print '<td colspan="4">'.$langs->trans("LastModifiedRequests",$max).'</td></tr>'; + + $num = $db->num_rows($resql); + if ($num) + { + $i = 0; + $var = True; + while ($i < $num) + { + $var=!$var; + $obj = $db->fetch_object($resql); + + print "<tr ".$bc[$var].">"; + print '<td width="20%" class="nowrap">'; + + $askpricesupplierstatic->id=$obj->rowid; + $askpricesupplierstatic->ref=$obj->ref; + + print '<table class="nobordernopadding"><tr class="nocellnopadd">'; + print '<td width="96" class="nobordernopadding nowrap">'; + print $askpricesupplierstatic->getNomUrl(1); + print '</td>'; + + print '<td width="16" class="nobordernopadding nowrap">'; + print ' '; + print '</td>'; + + print '<td width="16" align="right" class="nobordernopadding">'; + $filename=dol_sanitizeFileName($obj->ref); + $filedir=$conf->askpricesupplier->dir_output . '/' . dol_sanitizeFileName($obj->ref); + $urlsource=$_SERVER['PHP_SELF'].'?id='.$obj->rowid; + print $formfile->getDocumentsLink($askpricesupplierstatic->element, $filename, $filedir); + print '</td></tr></table>'; + + print '</td>'; + + $companystatic->id=$obj->socid; + $companystatic->name=$obj->socname; + $companystatic->client=$obj->client; + $companystatic->canvas=$obj->canvas; + print '<td>'.$companystatic->getNomUrl(1,'customer').'</td>'; + + print '<td>'.dol_print_date($db->jdate($obj->datec),'day').'</td>'; + print '<td align="right">'.$askpricesupplierstatic->LibStatut($obj->fk_statut,5).'</td>'; + print '</tr>'; + $i++; + } + } + print "</table><br>"; +} +else dol_print_error($db); + + +/* + * Opened askprice + */ +if (! empty($conf->askpricesupplier->enabled) && $user->rights->askpricesupplier->lire) +{ + $langs->load("askpricesupplier"); + + $now=dol_now(); + + $sql = "SELECT s.nom as socname, s.rowid as socid, s.canvas, s.client, p.rowid as askpricesupplierid, p.total as total_ttc, p.total_ht, p.ref, p.fk_statut, p.datec as dp"; + $sql.= " FROM ".MAIN_DB_PREFIX."societe as s"; + $sql.= ", ".MAIN_DB_PREFIX."askpricesupplier as p"; + if (!$user->rights->societe->client->voir && !$socid) $sql.= ", ".MAIN_DB_PREFIX."societe_commerciaux as sc"; + $sql.= " WHERE p.fk_soc = s.rowid"; + $sql.= " AND p.entity = ".$conf->entity; + $sql.= " AND p.fk_statut = 1"; + if (!$user->rights->societe->client->voir && !$socid) $sql.= " AND s.rowid = sc.fk_soc AND sc.fk_user = " .$user->id; + if ($socid) $sql.= " AND s.rowid = ".$socid; + $sql.= " ORDER BY p.rowid DESC"; + + $result=$db->query($sql); + if ($result) + { + $total = 0; + $num = $db->num_rows($result); + $i = 0; + if ($num > 0) + { + $var=true; + + print '<table class="noborder" width="100%">'; + print '<tr class="liste_titre"><td colspan="5">'.$langs->trans("RequestsOpened").' <a href="'.DOL_URL_ROOT.'/comm/askpricesupplier/list.php?viewstatut=1"><span class="badge">'.$num.'</span></a></td></tr>'; + + $nbofloop=min($num, (empty($conf->global->MAIN_MAXLIST_OVERLOAD)?500:$conf->global->MAIN_MAXLIST_OVERLOAD)); + while ($i < $nbofloop) + { + $obj = $db->fetch_object($result); + $var=!$var; + print '<tr '.$bc[$var].'>'; + + // Ref + print '<td class="nowrap" width="140">'; + + $askpricesupplierstatic->id=$obj->askpricesupplierid; + $askpricesupplierstatic->ref=$obj->ref; + + print '<table class="nobordernopadding"><tr class="nocellnopadd">'; + print '<td class="nobordernopadding nowrap">'; + print $askpricesupplierstatic->getNomUrl(1); + print '</td>'; + print '<td width="18" class="nobordernopadding nowrap">'; + if ($db->jdate($obj->dfv) < ($now - $conf->askpricesupplier->cloture->warning_delay)) print img_warning($langs->trans("Late")); + print '</td>'; + print '<td width="16" align="center" class="nobordernopadding">'; + $filename=dol_sanitizeFileName($obj->ref); + $filedir=$conf->askpricesupplier->dir_output . '/' . dol_sanitizeFileName($obj->ref); + $urlsource=$_SERVER['PHP_SELF'].'?id='.$obj->askpricesupplierid; + print $formfile->getDocumentsLink($askpricesupplierstatic->element, $filename, $filedir); + print '</td></tr></table>'; + + print "</td>"; + + $companystatic->id=$obj->socid; + $companystatic->name=$obj->socname; + $companystatic->client=$obj->client; + $companystatic->canvas=$obj->canvas; + print '<td align="left">'.$companystatic->getNomUrl(1,'customer',44).'</td>'."\n"; + + print '<td align="right">'; + print dol_print_date($db->jdate($obj->dp),'day').'</td>'."\n"; + print '<td align="right">'.price($obj->total_ttc).'</td>'; + print '<td align="center" width="14">'.$askpricesupplierstatic->LibStatut($obj->fk_statut,3).'</td>'."\n"; + print '</tr>'."\n"; + $i++; + $total += $obj->total_ttc; + } + if ($num > $nbofloop) + { + print '<tr class="liste_total"><td colspan="5">'.$langs->trans("XMoreLines", ($num - $nbofloop))."</td></tr>"; + } + else if ($total>0) + { + print '<tr class="liste_total"><td colspan="3">'.$langs->trans("Total")."</td><td align=\"right\">".price($total)."</td><td> </td></tr>"; + } + print "</table><br>"; + } + } + else + { + dol_print_error($db); + } +} + +print '</div></div></div>'; + +llxFooter(); + +$db->close(); diff --git a/htdocs/comm/askpricesupplier/info.php b/htdocs/comm/askpricesupplier/info.php new file mode 100644 index 0000000000000000000000000000000000000000..3b8f95d45fa6b0c8278c2f8b17c03bbeac91b6ac --- /dev/null +++ b/htdocs/comm/askpricesupplier/info.php @@ -0,0 +1,65 @@ +<?php +/* Copyright (C) 2004 Rodolphe Quiedeville <rodolphe@quiedeville.org> + * Copyright (C) 2004-2006 Laurent Destailleur <eldy@users.sourceforge.net> + * Copyright (C) 2005-2012 Regis Houssin <regis.houssin@capnetworks.com> + * + * 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 <http://www.gnu.org/licenses/>. + */ + +/** + * \file htdocs/comm/propal/info.php + * \ingroup propal + * \brief Page d'affichage des infos d'une proposition commerciale + */ + +require '../../main.inc.php'; +require_once DOL_DOCUMENT_ROOT.'/core/lib/functions2.lib.php'; +require_once DOL_DOCUMENT_ROOT.'/comm/askpricesupplier/class/askpricesupplier.class.php'; +require_once DOL_DOCUMENT_ROOT.'/core/lib/askpricesupplier.lib.php'; + +$langs->load('askpricesupplier'); +$langs->load('compta'); + +$id=GETPOST('id','int'); +$socid=GETPOST('socid','int'); + +// Security check +if (! empty($user->societe_id)) $socid=$user->societe_id; +$result = restrictedArea($user, 'askpricesupplier', $id); + + +/* + * View + */ + +llxHeader('',$langs->trans('CommRequest'),'EN:Ask_Price_Supplier|FR:Demande_de_prix_fournisseur'); + +$object = new AskPriceSupplier($db); +$object->fetch($id); +$object->fetch_thirdparty(); + +$head = askpricesupplier_prepare_head($object); +dol_fiche_head($head, 'info', $langs->trans('CommRequest'), 0, 'askpricesupplier'); + +$object->info($object->id); + +print '<table width="100%"><tr><td>'; +dol_print_object_info($object); +print '</td></tr></table>'; + +print '</div>'; + + +llxFooter(); +$db->close(); diff --git a/htdocs/comm/askpricesupplier/list.php b/htdocs/comm/askpricesupplier/list.php new file mode 100644 index 0000000000000000000000000000000000000000..bce521489e0407c4819db9f33297855f5f0974b3 --- /dev/null +++ b/htdocs/comm/askpricesupplier/list.php @@ -0,0 +1,425 @@ +<?php +/* Copyright (C) 2001-2007 Rodolphe Quiedeville <rodolphe@quiedeville.org> + * Copyright (C) 2004-2011 Laurent Destailleur <eldy@users.sourceforge.net> + * Copyright (C) 2004 Eric Seigne <eric.seigne@ryxeo.com> + * Copyright (C) 2005 Marc Barilley / Ocebo <marc@ocebo.com> + * Copyright (C) 2005-2013 Regis Houssin <regis.houssin@capnetworks.com> + * Copyright (C) 2006 Andre Cianfarani <acianfa@free.fr> + * Copyright (C) 2010-2011 Juanjo Menent <jmenent@2byte.es> + * Copyright (C) 2010-2011 Philippe Grand <philippe.grand@atoo-net.com> + * Copyright (C) 2012 Christophe Battarel <christophe.battarel@altairis.fr> + * Copyright (C) 2013 Cédric Salvador <csalvador@gpcsolutions.fr> +* + * 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 <http://www.gnu.org/licenses/>. + */ + +/** + * \file htdocs/comm/propal/list.php + * \ingroup propal + * \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.formaskpricesupplier.class.php'; +require_once DOL_DOCUMENT_ROOT.'/core/lib/date.lib.php'; +require_once DOL_DOCUMENT_ROOT.'/comm/askpricesupplier/class/askpricesupplier.class.php'; +if (! empty($conf->projet->enabled)) + require_once DOL_DOCUMENT_ROOT.'/projet/class/project.class.php'; + +$langs->load('companies'); +$langs->load('askpricesupplier'); +$langs->load('compta'); +$langs->load('bills'); +$langs->load('orders'); +$langs->load('products'); + +$socid=GETPOST('socid','int'); + +$search_user=GETPOST('search_user','int'); +$search_sale=GETPOST('search_sale','int'); +$search_ref=GETPOST('sf_ref')?GETPOST('sf_ref','alpha'):GETPOST('search_ref','alpha'); +$search_societe=GETPOST('search_societe','alpha'); +$search_montant_ht=GETPOST('search_montant_ht','alpha'); +$search_author=GETPOST('search_author','alpha'); +$viewstatut=$db->escape(GETPOST('viewstatut')); +$object_statut=$db->escape(GETPOST('askpricesupplier_statut')); + +$sall=GETPOST("sall"); +$mesg=(GETPOST("msg") ? GETPOST("msg") : GETPOST("mesg")); +$year=GETPOST("year"); +$month=GETPOST("month"); + +// Nombre de ligne pour choix de produit/service predefinis +$NBLINES=4; + +// Security check +$module='askpricesupplier'; +$dbtable=''; +$objectid=''; +if (! empty($user->societe_id)) $socid=$user->societe_id; +if (! empty($socid)) +{ + $objectid=$socid; + $module='societe'; + $dbtable='&societe'; +} +$result = restrictedArea($user, $module, $objectid, $dbtable); + +if (GETPOST("button_removefilter") || GETPOST("button_removefilter_x")) // Both tests are required to be compatible with all browsers +{ + $search_categ=''; + $search_user=''; + $search_sale=''; + $search_ref=''; + $search_societe=''; + $search_montant_ht=''; + $search_author=''; + $year=''; + $month=''; + $viewstatut=''; + $object_statut=''; +} + +if($object_statut != '') +$viewstatut=$object_statut; + + +// Initialize technical object to manage hooks of thirdparties. Note that conf->hooks_modules contains array array +$hookmanager->initHooks(array('askpricesupplierlist')); + + + +/* + * Actions + */ + + +$parameters=array('socid'=>$socid); +$reshook=$hookmanager->executeHooks('doActions',$parameters,$object,$action); // Note that $action and $object may have been modified by some hooks +if ($reshook < 0) setEventMessages($hookmanager->error, $hookmanager->errors, 'errors'); + + + +/* + * View + */ + +llxHeader('',$langs->trans('CommRequest'),'EN:Ask_Price_Supplier|FR:Demande_de_prix_fournisseur'); + +$form = new Form($db); +$formother = new FormOther($db); +$formfile = new FormFile($db); +$formaskpricesupplier = new FormAskPriceSupplier($db); +$companystatic=new Societe($db); + +$now=dol_now(); + +$sortfield = GETPOST("sortfield",'alpha'); +$sortorder = GETPOST("sortorder",'alpha'); +$page = GETPOST("page",'int'); +if ($page == -1) { $page = 0; } +$offset = $conf->liste_limit * $page; +$pageprev = $page - 1; +$pagenext = $page + 1; + +if (! $sortfield) $sortfield='p.date_livraison'; +if (! $sortorder) $sortorder='DESC'; +$limit = $conf->liste_limit; + + +$sql = 'SELECT s.rowid, s.nom as name, s.town, s.client, s.code_client,'; +$sql.= ' p.rowid as askpricesupplierid, p.note_private, p.total_ht, p.ref, p.fk_statut, p.fk_user_author, p.date_livraison as dp,'; +if (! $user->rights->societe->client->voir && ! $socid) $sql .= " sc.fk_soc, sc.fk_user,"; +$sql.= ' u.login'; +$sql.= ' FROM '.MAIN_DB_PREFIX.'societe as s, '.MAIN_DB_PREFIX.'askpricesupplier as p'; +if ($sall) $sql.= ' LEFT JOIN '.MAIN_DB_PREFIX.'askpricesupplierdet as pd ON p.rowid=pd.fk_askpricesupplier'; +$sql.= ' LEFT JOIN '.MAIN_DB_PREFIX.'user as u ON p.fk_user_author = u.rowid'; +// We'll need this table joined to the select in order to filter by sale +if ($search_sale > 0 || (! $user->rights->societe->client->voir && ! $socid)) $sql .= ", ".MAIN_DB_PREFIX."societe_commerciaux as sc"; +if ($search_user > 0) +{ + $sql.=", ".MAIN_DB_PREFIX."element_contact as c"; + $sql.=", ".MAIN_DB_PREFIX."c_type_contact as tc"; +} +$sql.= ' WHERE p.fk_soc = s.rowid'; +$sql.= ' AND p.entity = '.$conf->entity; +if (! $user->rights->societe->client->voir && ! $socid) //restriction +{ + $sql.= " AND s.rowid = sc.fk_soc AND sc.fk_user = " .$user->id; +} +if ($search_ref) { + $sql .= natural_search('p.ref', $search_ref); +} +if ($search_societe) { + $sql .= natural_search('s.nom', $search_societe); +} +if ($search_author) +{ + $sql.= " AND u.login LIKE '%".$db->escape(trim($search_author))."%'"; +} +if ($search_montant_ht) +{ + $sql.= " AND p.total_ht='".$db->escape(price2num(trim($search_montant_ht)))."'"; +} +if ($sall) { + $sql .= natural_search(array('s.nom', 'p.note_private', 'p.note_public', 'pd.description'), $sall); +} +if ($socid) $sql.= ' AND s.rowid = '.$socid; +if ($viewstatut <> '') +{ + $sql.= ' AND p.fk_statut IN ('.$viewstatut.')'; +} +if ($month > 0) +{ + if ($year > 0 && empty($day)) + $sql.= " AND p.date_livraison BETWEEN '".$db->idate(dol_get_first_day($year,$month,false))."' AND '".$db->idate(dol_get_last_day($year,$month,false))."'"; + else if ($year > 0 && ! empty($day)) + $sql.= " AND p.date_livraison BETWEEN '".$db->idate(dol_mktime(0, 0, 0, $month, $day, $year))."' AND '".$db->idate(dol_mktime(23, 59, 59, $month, $day, $year))."'"; + else + $sql.= " AND date_format(p.date_livraison, '%m') = '".$month."'"; +} +else if ($year > 0) +{ + $sql.= " AND p.date_livraison BETWEEN '".$db->idate(dol_get_first_day($year,1,false))."' AND '".$db->idate(dol_get_last_day($year,12,false))."'"; +} +if ($search_sale > 0) $sql.= " AND s.rowid = sc.fk_soc AND sc.fk_user = " .$search_sale; +if ($search_user > 0) +{ + $sql.= " AND c.fk_c_type_contact = tc.rowid AND tc.element='askpricesupplier' AND tc.source='internal' AND c.element_id = p.rowid AND c.fk_socpeople = ".$search_user; +} + + +$sql.= ' ORDER BY '.$sortfield.' '.$sortorder.', p.ref DESC'; + +$nbtotalofrecords = 0; +if (empty($conf->global->MAIN_DISABLE_FULL_SCANLIST)) +{ + $result = $db->query($sql); + $nbtotalofrecords = $db->num_rows($result); +} + + +$sql.= $db->plimit($limit + 1,$offset); +$result=$db->query($sql); + +if ($result) +{ + $objectstatic=new AskPriceSupplier($db); + $userstatic=new User($db); + $num = $db->num_rows($result); + + if ($socid) + { + $soc = new Societe($db); + $soc->fetch($socid); + } + + $param='&socid='.$socid.'&viewstatut='.$viewstatut; + if ($month) $param.='&month='.$month; + if ($year) $param.='&year='.$year; + if ($search_ref) $param.='&search_ref=' .$search_ref; + if ($search_societe) $param.='&search_societe=' .$search_societe; + if ($search_user > 0) $param.='&search_user='.$search_user; + if ($search_sale > 0) $param.='&search_sale='.$search_sale; + if ($search_montant_ht) $param.='&search_montant_ht='.$search_montant_ht; + if ($search_author) $param.='&search_author='.$search_author; + print_barre_liste($langs->trans('ListOfAskPriceSupplier').' '.($socid?'- '.$soc->name:''), $page, $_SERVER["PHP_SELF"],$param,$sortfield,$sortorder,'',$num,$nbtotalofrecords); + + // Lignes des champs de filtre + print '<form method="GET" action="'.$_SERVER["PHP_SELF"].'">'; + + $i = 0; + print '<table class="liste" width="100%">'; + + $moreforfilter=''; + + // If the user can view prospects other than his' + if ($user->rights->societe->client->voir || $socid) + { + $langs->load("commercial"); + $moreforfilter.=$langs->trans('ThirdPartiesOfSaleRepresentative'). ': '; + $moreforfilter.=$formother->select_salesrepresentatives($search_sale,'search_sale',$user); + $moreforfilter.=' '; + } + // If the user can view prospects other than his' + if ($user->rights->societe->client->voir || $socid) + { + $moreforfilter.=$langs->trans('LinkedToSpecificUsers'). ': '; + $moreforfilter.=$form->select_dolusers($search_user,'search_user',1); + } + if (! empty($moreforfilter)) + { + print '<tr class="liste_titre">'; + print '<td class="liste_titre" colspan="10">'; + print $moreforfilter; + print '</td></tr>'; + } + + print '<tr class="liste_titre">'; + print_liste_field_titre($langs->trans('Ref'),$_SERVER["PHP_SELF"],'p.ref','',$param,'',$sortfield,$sortorder); + print_liste_field_titre($langs->trans('Company'),$_SERVER["PHP_SELF"],'s.nom','',$param,'',$sortfield,$sortorder); + print_liste_field_titre($langs->trans('AskPriceSupplierDate'),$_SERVER["PHP_SELF"],'p.date_livraison','',$param, 'align="center"',$sortfield,$sortorder); + print_liste_field_titre($langs->trans('AmountHT'),$_SERVER["PHP_SELF"],'p.total_ht','',$param, 'align="right"',$sortfield,$sortorder); + print_liste_field_titre($langs->trans('Author'),$_SERVER["PHP_SELF"],'u.login','',$param,'align="center"',$sortfield,$sortorder); + print_liste_field_titre($langs->trans('Status'),$_SERVER["PHP_SELF"],'p.fk_statut','',$param,'align="right"',$sortfield,$sortorder); + print_liste_field_titre(''); + print "</tr>\n"; + + print '<tr class="liste_titre">'; + print '<td class="liste_titre">'; + print '<input class="flat" size="6" type="text" name="search_ref" value="'.$search_ref.'">'; + print '</td>'; + print '<td class="liste_titre" align="left">'; + print '<input class="flat" type="text" size="12" name="search_societe" value="'.$search_societe.'">'; + print '</td>'; + + // Date + print '<td class="liste_titre" colspan="1" align="center">'; + //print $langs->trans('Month').': '; + print '<input class="flat" type="text" size="1" maxlength="2" name="month" value="'.$month.'">'; + //print ' '.$langs->trans('Year').': '; + $syear = $year; + $formother->select_year($syear,'year',1, 20, 5); + print '</td>'; + + // Amount + print '<td class="liste_titre" align="right">'; + print '<input class="flat" type="text" size="10" name="search_montant_ht" value="'.$search_montant_ht.'">'; + print '</td>'; + // Author + print '<td class="liste_titre" align="center">'; + print '<input class="flat" size="10" type="text" name="search_author" value="'.$search_author.'">'; + print '</td>'; + print '<td class="liste_titre" align="right">'; + $formaskpricesupplier->selectAskPriceSupplierStatus($viewstatut,1); + print '</td>'; + + print '<td class="liste_titre" align="right">'; + print '<input type="image" name="button_search" class="liste_titre" src="'.img_picto($langs->trans("Search"),'search.png','','',1).'" value="'.dol_escape_htmltag($langs->trans("Search")).'" title="'.dol_escape_htmltag($langs->trans("Search")).'">'; + print '<input type="image" name="button_removefilter" class="liste_titre" src="'.img_picto($langs->trans("RemoveFilter"),'searchclear.png','','',1).'" value="'.dol_escape_htmltag($langs->trans("RemoveFilter")).'" title="'.dol_escape_htmltag($langs->trans("RemoveFilter")).'">'; + print '</td>'; + + print "</tr>\n"; + + $var=true; + $total=0; + $subtotal=0; + + while ($i < min($num,$limit)) + { + $objp = $db->fetch_object($result); + $now = dol_now(); + $var=!$var; + print '<tr '.$bc[$var].'>'; + print '<td class="nowrap">'; + + $objectstatic->id=$objp->askpricesupplierid; + $objectstatic->ref=$objp->ref; + + print '<table class="nobordernopadding"><tr class="nocellnopadd">'; + print '<td class="nobordernopadding nowrap">'; + print $objectstatic->getNomUrl(1); + print '</td>'; + + print '<td style="min-width: 20px" class="nobordernopadding nowrap">'; + if ($objp->fk_statut == 1 && $db->jdate($objp->dfv) < ($now - $conf->askpricesupplier->cloture->warning_delay)) print img_warning($langs->trans("Late")); + if (! empty($objp->note_private)) + { + print ' <span class="note">'; + print '<a href="'.DOL_URL_ROOT.'/comm/askpricesupplier/note.php?id='.$objp->askpricesupplierid.'">'.img_picto($langs->trans("ViewPrivateNote"),'object_generic').'</a>'; + print '</span>'; + } + print '</td>'; + + // Ref + print '<td width="16" align="right" class="nobordernopadding hideonsmartphone">'; + $filename=dol_sanitizeFileName($objp->ref); + $filedir=$conf->askpricesupplier->dir_output . '/' . dol_sanitizeFileName($objp->ref); + $urlsource=$_SERVER['PHP_SELF'].'?id='.$objp->askpricesupplierid; + print $formfile->getDocumentsLink($objectstatic->element, $filename, $filedir); + print '</td></tr></table>'; + + print "</td>\n"; + + $url = DOL_URL_ROOT.'/comm/card.php?socid='.$objp->rowid; + + // Company + $companystatic->id=$objp->rowid; + $companystatic->name=$objp->name; + $companystatic->client=$objp->client; + $companystatic->code_client=$objp->code_client; + print '<td>'; + print $companystatic->getNomUrl(1,'customer'); + print '</td>'; + + // Date askprice + print '<td align="center">'; + print dol_print_date($db->jdate($objp->dp), 'day'); + print "</td>\n"; + + print '<td align="right">'.price($objp->total_ht)."</td>\n"; + + $userstatic->id=$objp->fk_user_author; + $userstatic->login=$objp->login; + print '<td align="center">'; + if ($userstatic->id) print $userstatic->getLoginUrl(1); + else print ' '; + print "</td>\n"; + + print '<td align="right">'.$objectstatic->LibStatut($objp->fk_statut,5)."</td>\n"; + + print '<td> </td>'; + + print "</tr>\n"; + + $total += $objp->total_ht; + $subtotal += $objp->total_ht; + + $i++; + } + + if ($total>0) + { + if($num<$limit){ + $var=!$var; + print '<tr class="liste_total"><td align="left">'.$langs->trans("TotalHT").'</td>'; + print '<td colspan="3" align="right">'.price($total).'</td><td colspan="3"></td>'; + print '</tr>'; + } + else + { + $var=!$var; + print '<tr class="liste_total"><td align="left">'.$langs->trans("TotalHTforthispage").'</td>'; + print '<td colspan="3" align="right">'.price($total).'</td><td colspan="3"></td>'; + print '</tr>'; + } + + } + + print '</table>'; + + print '</form>'; + + $db->free($result); +} +else +{ + dol_print_error($db); +} + +// End of page +llxFooter(); +$db->close(); diff --git a/htdocs/comm/askpricesupplier/note.php b/htdocs/comm/askpricesupplier/note.php new file mode 100644 index 0000000000000000000000000000000000000000..0ce89fe5e8b92cd380f1a313760295d7180f9d83 --- /dev/null +++ b/htdocs/comm/askpricesupplier/note.php @@ -0,0 +1,113 @@ +<?php +/* Copyright (C) 2004 Rodolphe Quiedeville <rodolphe@quiedeville.org> + * Copyright (C) 2004-2012 Laurent Destailleur <eldy@users.sourceforge.net> + * Copyright (C) 2004 Eric Seigne <eric.seigne@ryxeo.com> + * Copyright (C) 2005-2012 Regis Houssin <regis.houssin@capnetworks.com> + * Copyright (C) 2013 Florian Henry <florian.henry@open-concept.pro> + * + * 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 <http://www.gnu.org/licenses/>. + */ + +/** + * \file htdocs/comm/propal/note.php + * \ingroup propal + * \brief Fiche d'information sur une proposition commerciale + */ + +require '../../main.inc.php'; +require_once DOL_DOCUMENT_ROOT.'/comm/askpricesupplier/class/askpricesupplier.class.php'; +require_once DOL_DOCUMENT_ROOT.'/core/lib/askpricesupplier.lib.php'; + +$langs->load('askpricesupplier'); +$langs->load('compta'); +$langs->load('bills'); + +$id = GETPOST('id','int'); +$ref=GETPOST('ref','alpha'); +$action=GETPOST('action','alpha'); + +// Security check +if ($user->societe_id) $socid=$user->societe_id; +$result = restrictedArea($user, 'askpricesupplier', $id, 'askpricesupplier'); + +$object = new AskPriceSupplier($db); + + + +/******************************************************************************/ +/* Actions */ +/******************************************************************************/ + +$permissionnote=$user->rights->askpricesupplier->creer; // Used by the include of actions_setnotes.inc.php + +include DOL_DOCUMENT_ROOT.'/core/actions_setnotes.inc.php'; // Must be include, not includ_once + + + +/******************************************************************************/ +/* Affichage fiche */ +/******************************************************************************/ + +llxHeader('',$langs->trans('CommRequest'),'EN:Ask_Price_Supplier|FR:Demande_de_prix_fournisseur'); + +$form = new Form($db); + +if ($id > 0 || ! empty($ref)) +{ + if ($mesg) print $mesg; + + $now=dol_now(); + + if ($object->fetch($id, $ref)) + { + $societe = new Societe($db); + if ( $societe->fetch($object->socid) ) + { + $head = askpricesupplier_prepare_head($object); + dol_fiche_head($head, 'note', $langs->trans('CommRequest'), 0, 'askpricesupplier'); + + print '<table class="border" width="100%">'; + + $linkback = '<a href="'.DOL_URL_ROOT.'/comm/askpricesupplier/list.php'.(! empty($socid)?'?socid='.$socid:'').'">'.$langs->trans('BackToList').'</a>'; + + // Ref + print '<tr><td width="25%">'.$langs->trans('Ref').'</td><td colspan="3">'; + print $form->showrefnav($object,'ref',$linkback,1,'ref','ref',''); + print '</td></tr>'; + + // Customer + if ( is_null($object->client) ) + $object->fetch_thirdparty(); + print "<tr><td>".$langs->trans("Supplier")."</td>"; + print '<td colspan="3">'.$object->client->getNomUrl(1).'</td></tr>'; + + print '<tr><td>'.$langs->trans('AskPriceSupplierDate').'</td><td colspan="3">'; + print dol_print_date($object->date_livraison,'daytext'); + print '</td>'; + print '</tr>'; + + print "</table>"; + + print '<br>'; + + include DOL_DOCUMENT_ROOT.'/core/tpl/notes.tpl.php'; + + dol_fiche_end(); + } + } +} + + +llxFooter(); +$db->close(); diff --git a/htdocs/comm/askpricesupplier/tpl/index.html b/htdocs/comm/askpricesupplier/tpl/index.html new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/htdocs/comm/askpricesupplier/tpl/linkedobjectblock.tpl.php b/htdocs/comm/askpricesupplier/tpl/linkedobjectblock.tpl.php new file mode 100644 index 0000000000000000000000000000000000000000..a45fac8b3c974b482b5b401377f07da0ac5f2d5c --- /dev/null +++ b/htdocs/comm/askpricesupplier/tpl/linkedobjectblock.tpl.php @@ -0,0 +1,74 @@ +<?php +/* Copyright (C) 2010-2011 Regis Houssin <regis.houssin@capnetworks.com> + * Copyright (C) 2013 Juanjo Menent <jmenent@2byte.es> + * Copyright (C) 2014 Marcos García <marcosgdf@gmail.com> + * + * 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 <http://www.gnu.org/licenses/>. + */ + +?> + +<!-- BEGIN PHP TEMPLATE --> + +<?php + +global $user; + +$langs = $GLOBALS['langs']; +$linkedObjectBlock = $GLOBALS['linkedObjectBlock']; + +echo '<br>'; +print_titre($langs->trans('RelatedAskPriceSupplier')); +?> +<table class="noborder allwidth"> +<tr class="liste_titre"> + <td><?php echo $langs->trans("Ref"); ?></td> + <td></td> + <td align="center"><?php echo $langs->trans("Date"); ?></td> + <td align="right"><?php echo $langs->trans("AmountHTShort"); ?></td> + <td align="right"><?php echo $langs->trans("Status"); ?></td> +</tr> +<?php +$var=true; +$total=0; +foreach($linkedObjectBlock as $object) +{ + $var=!$var; +?> +<tr <?php echo $bc[$var]; ?> ><td> + <a href="<?php echo DOL_URL_ROOT.'/comm/askpricesupplier/card.php?id='.$object->id ?>"><?php echo img_object($langs->trans("ShowAskPriceSupplier"),"askpricesupplier").' '.$object->ref; ?></a></td> + <td></td> + <td align="center"><?php echo dol_print_date($object->datec,'day'); ?></td> + <td align="right"><?php + if ($user->rights->askpricesupplier->lire) { + $total = $total + $object->total_ht; + echo price($object->total_ht); + } ?></td> + <td align="right"><?php echo $object->getLibStatut(3); ?></td> +</tr> +<?php +} + +?> +<tr class="liste_total"> + <td align="left" colspan="3"><?php echo $langs->trans('TotalHT'); ?></td> + <td align="right"><?php + if ($user->rights->askpricesupplier->lire) { + echo price($total); + } ?></td> + <td> </td> +</tr> +</table> + +<!-- END PHP TEMPLATE --> diff --git a/htdocs/comm/propal.php b/htdocs/comm/propal.php index 0fe47b9d8379ab80e7f23bb73f5f36a2634e5b11..49aa8d9fb62e35b548fd6bb677a829744681d0ee 100644 --- a/htdocs/comm/propal.php +++ b/htdocs/comm/propal.php @@ -488,7 +488,7 @@ if (empty($reshook)) setEventMessage($langs->trans("ErrorFailedToAddContact"), 'errors'); } } - + if (! $error) { $db->commit(); diff --git a/htdocs/core/class/commonobject.class.php b/htdocs/core/class/commonobject.class.php index c4b2902113ab72df15def8885b81fa9ebd191b72..884e8a16912c7534a21a5f487ea5575b8d2d594d 100644 --- a/htdocs/core/class/commonobject.class.php +++ b/htdocs/core/class/commonobject.class.php @@ -1776,6 +1776,7 @@ abstract class CommonObject if ($this->element == 'facture_fourn' || $this->element == 'invoice_supplier') $fieldtva='total_tva'; if ($this->element == 'propal') $fieldttc='total'; if ($this->element == 'expensereport') $fieldtva='total_tva'; + if ($this->element == 'askpricesupplier') $fieldttc='total'; if (empty($nodatabaseupdate)) { @@ -1966,6 +1967,9 @@ abstract class CommonObject else if ($objecttype == 'propal') { $classpath = 'comm/propal/class'; } + else if ($objecttype == 'askpricesupplier') { + $classpath = 'comm/askpricesupplier/class'; + } else if ($objecttype == 'shipping') { $classpath = 'expedition/class'; $subelement = 'expedition'; $module = 'expedition_bon'; } @@ -2484,6 +2488,10 @@ abstract class CommonObject $tplpath = 'comm/'.$element; if (empty($conf->propal->enabled)) continue; // Do not show if module disabled } + else if ($objecttype == 'askpricesupplier') { + $tplpath = 'comm/'.$element; + if (empty($conf->askpricesupplier->enabled)) continue; // Do not show if module disabled + } else if ($objecttype == 'shipping' || $objecttype == 'shipment') { $tplpath = 'expedition'; if (empty($conf->expedition->enabled)) continue; // Do not show if module disabled @@ -2586,6 +2594,11 @@ abstract class CommonObject // Description print '<td>'.$langs->trans('Description').'</td>'; + if ($this->element == 'askpricesupplier') + { + print '<td align="right"><span id="title_fourn_ref">'.$langs->trans("AskPriceSupplierRefFourn").'</span></td>'; + } + // VAT print '<td align="right" width="50">'.$langs->trans('VAT').'</td>'; diff --git a/htdocs/core/class/html.formactions.class.php b/htdocs/core/class/html.formactions.class.php index 333969fc3b3a46e6dff7c3a91d8d831dcb93bd59..cfab0e52b7c443355fc830ea483b467253c9edf7 100644 --- a/htdocs/core/class/html.formactions.class.php +++ b/htdocs/core/class/html.formactions.class.php @@ -171,6 +171,7 @@ class FormActions if ($typeelement == 'invoice') $title=$langs->trans('ActionsOnBill'); elseif ($typeelement == 'invoice_supplier' || $typeelement == 'supplier_invoice') $title=$langs->trans('ActionsOnBill'); elseif ($typeelement == 'propal') $title=$langs->trans('ActionsOnPropal'); + elseif ($typeelement == 'askpricesupplier') $title=$langs->trans('ActionsOnAskPriceSupplier'); elseif ($typeelement == 'order') $title=$langs->trans('ActionsOnOrder'); elseif ($typeelement == 'order_supplier' || $typeelement == 'supplier_order') $title=$langs->trans('ActionsOnOrder'); elseif ($typeelement == 'project') $title=$langs->trans('ActionsOnProject'); diff --git a/htdocs/core/class/html.formaskpricesupplier.class.php b/htdocs/core/class/html.formaskpricesupplier.class.php new file mode 100644 index 0000000000000000000000000000000000000000..ba7a6d8fee457244ed6567a62616d10542176bd9 --- /dev/null +++ b/htdocs/core/class/html.formaskpricesupplier.class.php @@ -0,0 +1,104 @@ +<?php +/* Copyright (C) 2012 Laurent Destailleur <eldy@users.sourceforge.net> + * + * 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 <http://www.gnu.org/licenses/>. + */ + +/** + * \file htdocs/core/class/html.formpropal.class.php + * \ingroup core + * \brief File of class with all html predefined components + */ + + +/** + * Class to manage generation of HTML components for proposal management + */ +class FormAskPriceSupplier +{ + var $db; + var $error; + + + /** + * Constructor + * + * @param DoliDB $db Database handler + */ + public function __construct($db) + { + $this->db = $db; + } + + /** + * Return combo list of differents status of a proposal + * Values are id of table c_propalst + * + * @param string $selected Preselected value + * @param int $short Use short labels + * @return void + */ + function selectAskPriceSupplierStatus($selected='',$short=0) + { + global $langs; + + $sql = "SELECT id, code, label, active FROM ".MAIN_DB_PREFIX."c_propalst"; + $sql .= " WHERE active = 1"; + + dol_syslog(get_class($this)."::selectAskPriceSupplierStatus", LOG_DEBUG); + $resql=$this->db->query($sql); + if ($resql) + { + print '<select class="flat" name="askpricesupplier_statut">'; + print '<option value=""> </option>'; + $num = $this->db->num_rows($resql); + $i = 0; + if ($num) + { + while ($i < $num) + { + $obj = $this->db->fetch_object($resql); + if ($selected == $obj->id) + { + print '<option value="'.$obj->id.'" selected="selected">'; + } + else + { + print '<option value="'.$obj->id.'">'; + } + $key=$obj->code; + if ($langs->trans("PropalStatus".$key.($short?'Short':'')) != "PropalStatus".$key.($short?'Short':'')) + { + print $langs->trans("PropalStatus".$key.($short?'Short':'')); + } + else + { + $conv_to_new_code=array('PR_DRAFT'=>'Draft','PR_OPEN'=>'Opened','PR_CLOSED'=>'Closed','PR_SIGNED'=>'Signed','PR_NOTSIGNED'=>'NotSigned','PR_FAC'=>'Billed'); + if (! empty($conv_to_new_code[$obj->code])) $key=$conv_to_new_code[$obj->code]; + print ($langs->trans("PropalStatus".$key.($short?'Short':''))!="PropalStatus".$key.($short?'Short':''))?$langs->trans("PropalStatus".$key.($short?'Short':'')):$obj->label; + } + print '</option>'; + $i++; + } + } + print '</select>'; + } + else + { + dol_print_error($this->db); + } + } + +} + diff --git a/htdocs/core/class/html.formfile.class.php b/htdocs/core/class/html.formfile.class.php index e341a992b6b0f150d8253bf290c4eff46ea88f53..3be937babdf7abafefcf79c5a5a337d637937240 100644 --- a/htdocs/core/class/html.formfile.class.php +++ b/htdocs/core/class/html.formfile.class.php @@ -273,7 +273,7 @@ class FormFile } $printer=0; - if (in_array($modulepart,array('facture','propal','proposal','order','commande','expedition'))) // The direct print feature is implemented only for such elements + if (in_array($modulepart,array('facture','askpricesupplier','propal','proposal','order','commande','expedition'))) // The direct print feature is implemented only for such elements { $printer = (!empty($user->rights->printing->read) && !empty($conf->printing->enabled))?true:false; } @@ -316,6 +316,15 @@ class FormFile include_once DOL_DOCUMENT_ROOT.'/core/modules/propale/modules_propale.php'; $modellist=ModelePDFPropales::liste_modeles($this->db); } + } + else if ($modulepart == 'askpricesupplier') + { + if (is_array($genallowed)) $modellist=$genallowed; + else + { + include_once DOL_DOCUMENT_ROOT.'/core/modules/askpricesupplier/modules_askpricesupplier.php'; + $modellist=ModelePDFAskPriceSupplier::liste_modeles($this->db); + } } else if ($modulepart == 'commande') { @@ -671,7 +680,7 @@ class FormFile $out=''; $this->numoffiles=0; - + $file_list=dol_dir_list($filedir, 'files', 0, preg_quote(basename($modulesubdir).'.pdf','/'), '\.meta$|\.png$'); // For ajax treatment @@ -921,6 +930,11 @@ class FormFile include_once DOL_DOCUMENT_ROOT.'/comm/propal/class/propal.class.php'; $object_instance=new Propal($this->db); } + else if ($modulepart == 'askpricesupplier') + { + include_once DOL_DOCUMENT_ROOT.'/comm/askpricesupplier/class/askpricesupplier.class.php'; + $object_instance=new AskPriceSupplier($this->db); + } else if ($modulepart == 'order') { include_once DOL_DOCUMENT_ROOT.'/commande/class/commande.class.php'; @@ -982,6 +996,7 @@ class FormFile if ($modulepart == 'invoice') { preg_match('/(.*)\/[^\/]+$/',$relativefile,$reg); $ref=(isset($reg[1])?$reg[1]:''); } if ($modulepart == 'invoice_supplier') { preg_match('/([^\/]+)\/[^\/]+$/',$relativefile,$reg); $ref=(isset($reg[1])?$reg[1]:''); if (is_numeric($ref)) { $id=$ref; $ref=''; } } // $ref may be also id with old supplier invoices if ($modulepart == 'propal') { preg_match('/(.*)\/[^\/]+$/',$relativefile,$reg); $ref=(isset($reg[1])?$reg[1]:''); } + if ($modulepart == 'askpricesupplier') { preg_match('/(.*)\/[^\/]+$/',$relativefile,$reg); $ref=(isset($reg[1])?$reg[1]:''); } if ($modulepart == 'order') { preg_match('/(.*)\/[^\/]+$/',$relativefile,$reg); $ref=(isset($reg[1])?$reg[1]:''); } if ($modulepart == 'order_supplier') { preg_match('/(.*)\/[^\/]+$/',$relativefile,$reg); $ref=(isset($reg[1])?$reg[1]:''); } if ($modulepart == 'contract') { preg_match('/(.*)\/[^\/]+$/',$relativefile,$reg); $ref=(isset($reg[1])?$reg[1]:''); } diff --git a/htdocs/core/class/html.formmail.class.php b/htdocs/core/class/html.formmail.class.php index 49c55384a1654f1377a7c5db8d7ebaadb5d01473..9e7686f70ceb2094896daaa77cbf924f73332050 100644 --- a/htdocs/core/class/html.formmail.class.php +++ b/htdocs/core/class/html.formmail.class.php @@ -479,6 +479,7 @@ class FormMail $showinfobcc=''; if (! empty($conf->global->MAIN_MAIL_AUTOCOPY_PROPOSAL_TO) && ! empty($this->param['models']) && $this->param['models'] == 'propal_send') $showinfobcc=$conf->global->MAIN_MAIL_AUTOCOPY_PROPOSAL_TO; + if (! empty($conf->global->MAIN_MAIL_AUTOCOPY_ASKPRICESUPPLIER_TO) && ! empty($this->param['models']) && $this->param['models'] == 'askpricesupplier_send') $showinfobcc=$conf->global->MAIN_MAIL_AUTOCOPY_ASKPRICESUPPLIER_TO; if (! empty($conf->global->MAIN_MAIL_AUTOCOPY_ORDER_TO) && ! empty($this->param['models']) && $this->param['models'] == 'order_send') $showinfobcc=$conf->global->MAIN_MAIL_AUTOCOPY_ORDER_TO; if (! empty($conf->global->MAIN_MAIL_AUTOCOPY_INVOICE_TO) && ! empty($this->param['models']) && $this->param['models'] == 'facture_send') $showinfobcc=$conf->global->MAIN_MAIL_AUTOCOPY_INVOICE_TO; if ($showinfobcc) $out.=' + '.$showinfobcc; @@ -498,6 +499,7 @@ class FormMail { $defaultvaluefordeliveryreceipt=0; if (! empty($conf->global->MAIL_FORCE_DELIVERY_RECEIPT_PROPAL) && ! empty($this->param['models']) && $this->param['models'] == 'propal_send') $defaultvaluefordeliveryreceipt=1; + if (! empty($conf->global->MAIL_FORCE_DELIVERY_RECEIPT_ASKPRICESUPPLIER) && ! empty($this->param['models']) && $this->param['models'] == 'askpricesupplier_send') $defaultvaluefordeliveryreceipt=1; if (! empty($conf->global->MAIL_FORCE_DELIVERY_RECEIPT_ORDER) && ! empty($this->param['models']) && $this->param['models'] == 'order_send') $defaultvaluefordeliveryreceipt=1; if (! empty($conf->global->MAIL_FORCE_DELIVERY_RECEIPT_INVOICE) && ! empty($this->param['models']) && $this->param['models'] == 'facture_send') $defaultvaluefordeliveryreceipt=1; $out.= $form->selectyesno('deliveryreceipt', (isset($_POST["deliveryreceipt"])?$_POST["deliveryreceipt"]:$defaultvaluefordeliveryreceipt), 1); @@ -720,6 +722,7 @@ class FormMail if ($type_template=='facture_send') { $defaultmessage=$outputlangs->transnoentities("PredefinedMailContentSendInvoice"); } elseif ($type_template=='facture_relance') { $defaultmessage=$outputlangs->transnoentities("PredefinedMailContentSendInvoiceReminder"); } elseif ($type_template=='propal_send') { $defaultmessage=$outputlangs->transnoentities("PredefinedMailContentSendProposal"); } + elseif ($type_template=='askpricesupplier_send') { $defaultmessage=$outputlangs->transnoentities("PredefinedMailContentSendAskPriceSupplier"); } elseif ($type_template=='order_send') { $defaultmessage=$outputlangs->transnoentities("PredefinedMailContentSendOrder"); } elseif ($type_template=='order_supplier_send') { $defaultmessage=$outputlangs->transnoentities("PredefinedMailContentSendSupplierOrder"); } elseif ($type_template=='invoice_supplier_send') { $defaultmessage=$outputlangs->transnoentities("PredefinedMailContentSendSupplierInvoice"); } diff --git a/htdocs/core/lib/askpricesupplier.lib.php b/htdocs/core/lib/askpricesupplier.lib.php new file mode 100644 index 0000000000000000000000000000000000000000..eec34ea91330ef777699cc7e473a1df738639164 --- /dev/null +++ b/htdocs/core/lib/askpricesupplier.lib.php @@ -0,0 +1,122 @@ +<?php +/* Copyright (C) 2006-2010 Laurent Destailleur <eldy@users.sourceforge.net> + * Copyright (C) 2005-2012 Regis Houssin <regis.houssin@capnetworks.com> + * + * 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 <http://www.gnu.org/licenses/>. + * or see http://www.gnu.org/ + */ + +/** + * \file htdocs/core/lib/propal.lib.php + * \brief Ensemble de fonctions de base pour le module propal + * \ingroup propal + */ + +/** + * Prepare array with list of tabs + * + * @param object $object Object related to tabs + * @return array Array of tabs to show + */ +function askpricesupplier_prepare_head($object) +{ + global $langs, $conf, $user; + $langs->load("askpricesupplier"); + $langs->load("compta"); + + $h = 0; + $head = array(); + + $head[$h][0] = DOL_URL_ROOT.'/comm/askpricesupplier/card.php?id='.$object->id; + $head[$h][1] = $langs->trans('AskPriceSupplierCard'); + $head[$h][2] = 'comm'; + $h++; + + + // Show more tabs from modules + // Entries must be declared in modules descriptor with line + // $this->tabs = array('entity:+tabname:Title:@mymodule:/mymodule/mypage.php?id=__ID__'); to add new tab + // $this->tabs = array('entity:-tabname); to remove a tab + complete_head_from_modules($conf,$langs,$object,$head,$h,'askpricesupplier'); + + if (empty($conf->global->MAIN_DISABLE_NOTES_TAB)) + { + $nbNote = 0; + if(!empty($object->note_private)) $nbNote++; + if(!empty($object->note_public)) $nbNote++; + $head[$h][0] = DOL_URL_ROOT.'/comm/askpricesupplier/note.php?id='.$object->id; + $head[$h][1] = $langs->trans('Notes'); + if ($nbNote > 0) $head[$h][1].= ' <span class="badge">'.$nbNote.'</span>'; + $head[$h][2] = 'note'; + $h++; + } + + require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php'; + $upload_dir = $conf->askpricesupplier->dir_output . "/" . dol_sanitizeFileName($object->ref); + $nbFiles = count(dol_dir_list($upload_dir,'files',0,'','(\.meta|_preview\.png)$')); + $head[$h][0] = DOL_URL_ROOT.'/comm/askpricesupplier/document.php?id='.$object->id; + $head[$h][1] = $langs->trans('Documents'); + if($nbFiles > 0) $head[$h][1].= ' <span class="badge">'.$nbFiles.'</span>'; + $head[$h][2] = 'document'; + $h++; + + $head[$h][0] = DOL_URL_ROOT.'/comm/askpricesupplier/info.php?id='.$object->id; + $head[$h][1] = $langs->trans('Info'); + $head[$h][2] = 'info'; + $h++; + + complete_head_from_modules($conf,$langs,$object,$head,$h,'askpricesupplier','remove'); + + return $head; +} + +/** + * Return array head with list of tabs to view object informations. + * + * @return array head array with tabs + */ +function askpricesupplier_admin_prepare_head() +{ + global $langs, $conf, $user; + + $h = 0; + $head = array(); + + $head[$h][0] = DOL_URL_ROOT.'/admin/askpricesupplier.php'; + $head[$h][1] = $langs->trans("Miscellaneous"); + $head[$h][2] = 'general'; + $h++; + + // Show more tabs from modules + // Entries must be declared in modules descriptor with line + // $this->tabs = array('entity:+tabname:Title:@mymodule:/mymodule/mypage.php?id=__ID__'); to add new tab + // $this->tabs = array('entity:-tabname:Title:@mymodule:/mymodule/mypage.php?id=__ID__'); to remove a tab + complete_head_from_modules($conf,$langs,null,$head,$h,'askpricesupplier_admin'); + + $head[$h][0] = DOL_URL_ROOT.'/comm/admin/askpricesupplier_extrafields.php'; + $head[$h][1] = $langs->trans("ExtraFields"); + $head[$h][2] = 'attributes'; + $h++; + + $head[$h][0] = DOL_URL_ROOT.'/comm/admin/askpricesupplierdet_extrafields.php'; + $head[$h][1] = $langs->trans("ExtraFieldsLines"); + $head[$h][2] = 'attributeslines'; + $h++; + + complete_head_from_modules($conf,$langs,null,$head,$h,'askpricesupplier_admin','remove'); + + return $head; +} + + diff --git a/htdocs/core/lib/functions2.lib.php b/htdocs/core/lib/functions2.lib.php index 5faf1c1c470001a45d470987c407dc00180c7a43..aaff80233b1ece673e66e2dd774a5d10ae869468 100644 --- a/htdocs/core/lib/functions2.lib.php +++ b/htdocs/core/lib/functions2.lib.php @@ -1549,6 +1549,9 @@ function dolGetElementUrl($objectid,$objecttype,$withpicto=0,$option='') if ($objecttype == 'propal') { $classpath = 'comm/propal/class'; } + if ($objecttype == 'askpricesupplier') { + $classpath = 'comm/askpricesupplier/class'; + } if ($objecttype == 'shipping') { $classpath = 'expedition/class'; $subelement = 'expedition'; @@ -1780,6 +1783,9 @@ function getElementProperties($element_type) if ($element_type == 'propal') { $classpath = 'comm/propal/class'; } + if ($element_type == 'askpricesupplier') { + $classpath = 'comm/askpricesupplier/class'; + } if ($element_type == 'shipping') { $classpath = 'expedition/class'; $subelement = 'expedition'; diff --git a/htdocs/core/modules/askpricesupplier/doc/doc_generic_askpricesupplier_odt.modules.php b/htdocs/core/modules/askpricesupplier/doc/doc_generic_askpricesupplier_odt.modules.php new file mode 100644 index 0000000000000000000000000000000000000000..ddc995cc69a193328aea48aebe00d15522765798 --- /dev/null +++ b/htdocs/core/modules/askpricesupplier/doc/doc_generic_askpricesupplier_odt.modules.php @@ -0,0 +1,484 @@ +<?php +/* Copyright (C) 2010-2012 Laurent Destailleur <eldy@users.sourceforge.net> + * Copyright (C) 2012 Juanjo Menent <jmenent@2byte.es> +* +* 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 <http://www.gnu.org/licenses/>. +* or see http://www.gnu.org/ +*/ + +/** + * \file htdocs/core/modules/propale/doc/doc_generic_proposal_odt.modules.php + * \ingroup societe + * \brief File of class to build ODT documents for third parties + */ + +require_once DOL_DOCUMENT_ROOT.'/core/modules/askpricesupplier/modules_askpricesupplier.php'; +require_once DOL_DOCUMENT_ROOT.'/product/class/product.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_askpricesupplier_odt extends ModelePDFAskPriceSupplier +{ + 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 = 'ASKPRICESUPPLIER_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 PROPALE_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 = 1; // 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->country_code) $this->emetteur->country_code=substr($langs->defaultlang,-2); // By default if not defined + } + + + /** + * 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.".<br>\n"; + $texte.= '<form action="'.$_SERVER["PHP_SELF"].'" method="POST">'; + $texte.= '<input type="hidden" name="token" value="'.$_SESSION['newtoken'].'">'; + $texte.= '<input type="hidden" name="action" value="setModuleOptions">'; + $texte.= '<input type="hidden" name="param1" value="ASKPRICESUPPLIER_ADDON_PDF_ODT_PATH">'; + if ($conf->global->MAIN_ASKPRICESUPPLIER_CHOOSE_ODT_DOCUMENT > 0) + { + $texte.= '<input type="hidden" name="param2" value="ASKPRICESUPPLIER_ADDON_PDF_ODT_DEFAULT">'; + $texte.= '<input type="hidden" name="param3" value="ASKPRICESUPPLIER_ADDON_PDF_ODT_TOBILL">'; + $texte.= '<input type="hidden" name="param4" value="ASKPRICESUPPLIER_ADDON_PDF_ODT_CLOSED">'; + } + $texte.= '<table class="nobordernopadding" width="100%">'; + + // List of directories area + $texte.= '<tr><td>'; + $texttitle=$langs->trans("ListOfDirectories"); + $listofdir=explode(',',preg_replace('/[\r\n]+/',',',trim($conf->global->ASKPRICESUPPLIER_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,'\.(ods|odt)'); + if (count($tmpfiles)) $listoffiles=array_merge($listoffiles,$tmpfiles); + } + } + $texthelp=$langs->trans("ListOfDirectoriesForModelGenODT"); + // Add list of substitution keys + $texthelp.='<br>'.$langs->trans("FollowingSubstitutionKeysCanBeUsed").'<br>'; + $texthelp.=$langs->transnoentitiesnoconv("FullListOnOnlineDocumentation"); // This contains an url, we don't modify it + + $texte.= $form->textwithpicto($texttitle,$texthelp,1,'help','',1); + $texte.= '<div><div style="display: inline-block; min-width: 100px; vertical-align: middle;">'; + $texte.= '<textarea class="flat" cols="60" name="value1">'; + $texte.=$conf->global->ASKPRICESUPPLIER_ADDON_PDF_ODT_PATH; + $texte.= '</textarea>'; + $texte.= '</div><div style="display: inline-block; vertical-align: middle;">'; + $texte.= '<input type="submit" class="button" value="'.$langs->trans("Modify").'" name="Button">'; + $texte.= '<br></div></div>'; + + // Scan directories + if (count($listofdir)) + { + $texte.=$langs->trans("NumberOfModelFilesFound").': <b>'.count($listoffiles).'</b>'; + + if ($conf->global->MAIN_ASKPRICESUPPLIER_CHOOSE_ODT_DOCUMENT > 0) + { + // Model for creation + $liste=ModelePDFAskPriceSupplier::liste_modeles($this->db); + $texte.= '<table width="50%;">'; + $texte.= '<tr>'; + $texte.= '<td width="60%;">'.$langs->trans("DefaultModelAskPriceSupplierCreate").'</td>'; + $texte.= '<td colspan="">'; + $texte.= $form->selectarray('value2',$liste,$conf->global->ASKPRICESUPPLIER_ADDON_PDF_ODT_DEFAULT); + $texte.= "</td></tr>"; + + $texte.= '<tr>'; + $texte.= '<td width="60%;">'.$langs->trans("DefaultModelAskPriceSupplierToBill").'</td>'; + $texte.= '<td colspan="">'; + $texte.= $form->selectarray('value3',$liste,$conf->global->ASKPRICESUPPLIER_ADDON_PDF_ODT_TOBILL); + $texte.= "</td></tr>"; + $texte.= '<tr>'; + + $texte.= '<td width="60%;">'.$langs->trans("DefaultModelAskPriceSupplierClosed").'</td>'; + $texte.= '<td colspan="">'; + $texte.= $form->selectarray('value4',$liste,$conf->global->ASKPRICESUPPLIER_ADDON_PDF_ODT_CLOSED); + $texte.= "</td></tr>"; + $texte.= '</table>'; + } + } + + $texte.= '</td>'; + + $texte.= '<td valign="top" rowspan="2" class="hideonsmartphone">'; + $texte.= $langs->trans("ExampleOfDirectoriesForModelGen"); + $texte.= '</td>'; + $texte.= '</tr>'; + + $texte.= '</table>'; + $texte.= '</form>'; + + return $texte; + } + + /** + * Function to build a document on disk using the generic odt module. + * + * @param Propale $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 + * @param int $hidedetails Do not show line details + * @param int $hidedesc Do not show desc + * @param int $hideref Do not show ref + * @return int 1 if OK, <=0 if KO + */ + function write_file($object,$outputlangs,$srctemplatepath,$hidedetails=0,$hidedesc=0,$hideref=0) + { + global $user,$langs,$conf,$mysoc,$hookmanager; + + if (empty($srctemplatepath)) + { + dol_syslog("doc_generic_odt::write_file parameter srctemplatepath empty", LOG_WARNING); + return -1; + } + + // Add odtgeneration hook + if (! is_object($hookmanager)) + { + include_once DOL_DOCUMENT_ROOT.'/core/class/hookmanager.class.php'; + $hookmanager=new HookManager($this->db); + } + $hookmanager->initHooks(array('odtgeneration')); + global $action; + + 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("bills"); + + if ($conf->askpricesupplier->dir_output) + { + // If $object is id instead of object + if (! is_object($object)) + { + $id = $object; + $object = new AskPriceSupplier($this->db); + $result=$object->fetch($id); + if ($result < 0) + { + dol_print_error($this->db,$object->error); + return -1; + } + } + + $dir = $conf->askpricesupplier->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('/\.od(t|s)/i','',$newfile); + $newfiletmp=preg_replace('/template_/i','',$newfiletmp); + $newfiletmp=preg_replace('/modele_/i','',$newfiletmp); + + $newfiletmp=$objectref.'_'.$newfiletmp; + + // Get extension (ods or odt) + $newfileformat=substr($newfile, strrpos($newfile, '.')+1); + if ( ! empty($conf->global->MAIN_DOC_USE_TIMING)) + { + $filename=$newfiletmp.'.'.dol_print_date(dol_now(),'%Y%m%d%H%M%S').'.'.$newfileformat; + } + else + { + $filename=$newfiletmp.'.'.$newfileformat; + } + $file=$dir.'/'.$filename; + //print "newdir=".$dir; + //print "newfile=".$newfile; + //print "file=".$file; + //print "conf->propal->dir_temp=".$conf->propal->dir_temp; + + dol_mkdir($conf->askpricesupplier->dir_temp); + + + // If BILLING contact defined on invoice, we use it + $usecontact=false; + $arrayidcontact=$object->getIdContact('external','BILLING'); + if (count($arrayidcontact) > 0) + { + $usecontact=true; + $result=$object->fetch_contact($arrayidcontact[0]); + } + + // Recipient name + if (! empty($usecontact)) + { + // On peut utiliser le nom de la societe du contact + if (! empty($conf->global->MAIN_USE_COMPANY_NAME_OF_CONTACT)) $socobject = $object->contact; + else $socobject = $object->client; + } + else + { + $socobject=$object->client; + } + + // Make substitution + $substitutionarray=array( + '__FROM_NAME__' => $this->emetteur->name, + '__FROM_EMAIL__' => $this->emetteur->email, + '__TOTAL_TTC__' => $object->total_ttc, + '__TOTAL_HT__' => $object->total_ht, + '__TOTAL_VAT__' => $object->total_vat + ); + complete_substitutions_array($substitutionarray, $langs, $object); + // Call the ODTSubstitution hook + $parameters=array('file'=>$file,'object'=>$object,'outputlangs'=>$outputlangs,'substitutionarray'=>&$substitutionarray); + $reshook=$hookmanager->executeHooks('ODTSubstitution',$parameters,$this,$action); // Note that $action and $object may have been modified by some hooks + + // Line of free text + $newfreetext=''; + $paramfreetext='ASKPRICESUPPLIER_FREE_TEXT'; + if (! empty($conf->global->$paramfreetext)) + { + $newfreetext=make_substitutions($conf->global->$paramfreetext,$substitutionarray); + } + + // Open and load template + require_once ODTPHP_PATH.'odf.php'; + try { + $odfHandler = new odf( + $srctemplatepath, + array( + 'PATH_TO_TMP' => $conf->askpricesupplier->dir_temp, + 'ZIP_PROXY' => 'PclZipProxy', // PhpZipProxy or PclZipProxy. Got "bad compression method" error when using PhpZipProxy. + 'DELIMITER_LEFT' => '{', + 'DELIMITER_RIGHT' => '}' + ) + ); + } + catch(Exception $e) + { + $this->error=$e->getMessage(); + return -1; + } + // 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 freetext + try { + $odfHandler->setVars('free_text', $newfreetext, true, 'UTF-8'); + } + catch(OdfException $e) + { + } + + // Make substitutions into odt + $array_user=$this->get_substitutionarray_user($user,$outputlangs); + $array_soc=$this->get_substitutionarray_mysoc($mysoc,$outputlangs); + $array_thirdparty=$this->get_substitutionarray_thirdparty($socobject,$outputlangs); + $array_objet=$this->get_substitutionarray_object($object,$outputlangs); + $array_other=$this->get_substitutionarray_other($outputlangs); + + $tmparray = array_merge($array_user,$array_soc,$array_thirdparty,$array_objet,$array_other); + complete_substitutions_array($tmparray, $outputlangs, $object); + // Call the ODTSubstitution hook + $parameters=array('file'=>$file,'object'=>$object,'outputlangs'=>$outputlangs,'substitutionarray'=>&$tmparray); + $reshook=$hookmanager->executeHooks('ODTSubstitution',$parameters,$this,$action); // Note that $action and $object may have been modified by some hooks + 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'); + foreach ($object->lines as $line) + { + $tmparray=$this->get_substitutionarray_lines($line,$outputlangs); + complete_substitutions_array($tmparray, $outputlangs, $object, $line, "completesubstitutionarray_lines"); + // Call the ODTSubstitutionLine hook + $parameters=array('odfHandler'=>&$odfHandler,'file'=>$file,'object'=>$object,'outputlangs'=>$outputlangs,'substitutionarray'=>&$tmparray,'line'=>$line); + $reshook=$hookmanager->executeHooks('ODTSubstitutionLine',$parameters,$this,$action); // Note that $action and $object may have been modified by some hooks + 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 labels translated + $tmparray=$outputlangs->get_translations_for_substitutions(); + foreach($tmparray as $key=>$value) + { + try { + $odfHandler->setVars($key, $value, true, 'UTF-8'); + } + catch(OdfException $e) + { + } + } + + // Call the beforeODTSave hook + $parameters=array('odfHandler'=>&$odfHandler,'file'=>$file,'object'=>$object,'outputlangs'=>$outputlangs); + $reshook=$hookmanager->executeHooks('beforeODTSave',$parameters,$this,$action); // Note that $action and $object may have been modified by some hooks + + // Write new file + if (!empty($conf->global->MAIN_ODT_AS_PDF)) { + try { + $odfHandler->exportAsAttachedPDF($file); + }catch (Exception $e){ + $this->error=$e->getMessage(); + return -1; + } + } + else { + try { + $odfHandler->saveToDisk($file); + }catch (Exception $e){ + $this->error=$e->getMessage(); + return -1; + } + } + + $reshook=$hookmanager->executeHooks('afterODTCreation',$parameters,$this,$action); // Note that $action and $object may have been modified by some hooks + + 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/core/modules/askpricesupplier/doc/index.html b/htdocs/core/modules/askpricesupplier/doc/index.html new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/htdocs/core/modules/askpricesupplier/doc/pdf_aurore.modules.php b/htdocs/core/modules/askpricesupplier/doc/pdf_aurore.modules.php new file mode 100644 index 0000000000000000000000000000000000000000..2c817314ecbc63c775386fa1085fee505d0cf844 --- /dev/null +++ b/htdocs/core/modules/askpricesupplier/doc/pdf_aurore.modules.php @@ -0,0 +1,1396 @@ +<?php +/* Copyright (C) 2004-2014 Laurent Destailleur <eldy@users.sourceforge.net> + * Copyright (C) 2005-2012 Regis Houssin <regis.houssin@capnetworks.com> + * Copyright (C) 2008 Raphael Bertrand <raphael.bertrand@resultic.fr> + * Copyright (C) 2010-2014 Juanjo Menent <jmenent@2byte.es> + * Copyright (C) 2012 Christophe Battarel <christophe.battarel@altairis.fr> + * + * 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 <http://www.gnu.org/licenses/>. + * or see http://www.gnu.org/ + */ + +/** + * \file htdocs/core/modules/propale/doc/pdf_azur.modules.php + * \ingroup propale + * \brief Fichier de la classe permettant de generer les propales au modele Azur + */ +require_once DOL_DOCUMENT_ROOT.'/core/modules/askpricesupplier/modules_askpricesupplier.php'; +require_once DOL_DOCUMENT_ROOT.'/product/class/product.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/pdf.lib.php'; + + +/** + * Class to generate PDF proposal Azur + */ +class pdf_aurore extends ModelePDFAskPriceSupplier +{ + var $db; + var $name; + var $description; + var $type; + + var $phpmin = array(4,3,0); // Minimum version of PHP required by module + var $version = 'dolibarr'; + + var $page_largeur; + var $page_hauteur; + var $format; + var $marge_gauche; + var $marge_droite; + var $marge_haute; + var $marge_basse; + + var $emetteur; // Objet societe qui emet + + + /** + * Constructor + * + * @param DoliDB $db Database handler + */ + function __construct($db) + { + global $conf,$langs,$mysoc; + + $langs->load("main"); + $langs->load("bills"); + + $this->db = $db; + $this->name = "aurore"; + $this->description = $langs->trans('DocModelAuroreDescription'); + + // Dimension page pour format A4 + $this->type = 'pdf'; + $formatarray=pdf_getFormat(); + $this->page_largeur = $formatarray['width']; + $this->page_hauteur = $formatarray['height']; + $this->format = array($this->page_largeur,$this->page_hauteur); + $this->marge_gauche=isset($conf->global->MAIN_PDF_MARGIN_LEFT)?$conf->global->MAIN_PDF_MARGIN_LEFT:10; + $this->marge_droite=isset($conf->global->MAIN_PDF_MARGIN_RIGHT)?$conf->global->MAIN_PDF_MARGIN_RIGHT:10; + $this->marge_haute =isset($conf->global->MAIN_PDF_MARGIN_TOP)?$conf->global->MAIN_PDF_MARGIN_TOP:10; + $this->marge_basse =isset($conf->global->MAIN_PDF_MARGIN_BOTTOM)?$conf->global->MAIN_PDF_MARGIN_BOTTOM:10; + + $this->option_logo = 1; // Affiche logo + $this->option_tva = 1; // Gere option tva FACTURE_TVAOPTION + $this->option_modereg = 1; // Affiche mode reglement + $this->option_condreg = 1; // Affiche conditions reglement + $this->option_codeproduitservice = 1; // Affiche code produit-service + $this->option_multilang = 1; // Dispo en plusieurs langues + $this->option_escompte = 1; // Affiche si il y a eu escompte + $this->option_credit_note = 1; // Support credit notes + $this->option_freetext = 1; // Support add of a personalised text + $this->option_draft_watermark = 1; //Support add of a watermark on drafts + + $this->franchise=!$mysoc->tva_assuj; + + // Get source company + $this->emetteur=$mysoc; + if (empty($this->emetteur->country_code)) $this->emetteur->country_code=substr($langs->defaultlang,-2); // By default, if was not defined + + // Define position of columns + $this->posxdesc=$this->marge_gauche+1; + $this->posxtva=102; + $this->posxup=116; + $this->posxqty=145; + $this->posxdiscount=162; + $this->postotalht=174; + if (! empty($conf->global->MAIN_GENERATE_DOCUMENTS_WITHOUT_VAT)) $this->posxtva=$this->posxup; + $this->posxpicture=$this->posxtva - (empty($conf->global->MAIN_DOCUMENTS_WITH_PICTURE_WIDTH)?20:$conf->global->MAIN_DOCUMENTS_WITH_PICTURE_WIDTH); // width of images + if ($this->page_largeur < 210) // To work with US executive format + { + $this->posxpicture-=20; + $this->posxtva-=20; + $this->posxup-=20; + $this->posxqty-=20; + $this->posxdiscount-=20; + $this->postotalht-=20; + } + + $this->tva=array(); + $this->localtax1=array(); + $this->localtax2=array(); + $this->atleastoneratenotnull=0; + $this->atleastonediscount=0; + } + + /** + * Function to build pdf onto disk + * + * @param Object $object Object to generate + * @param Translate $outputlangs Lang output object + * @param string $srctemplatepath Full path of source filename for generator using a template file + * @param int $hidedetails Do not show line details + * @param int $hidedesc Do not show desc + * @param int $hideref Do not show ref + * @return int 1=OK, 0=KO + */ + function write_file($object,$outputlangs,$srctemplatepath='',$hidedetails=0,$hidedesc=0,$hideref=0) + { + global $user,$langs,$conf,$mysoc,$db,$hookmanager; + + if (! is_object($outputlangs)) $outputlangs=$langs; + // For backward compatibility with FPDF, force output charset to ISO, because FPDF expect text to be encoded in ISO + if (! empty($conf->global->MAIN_USE_FPDF)) $outputlangs->charset_output='ISO-8859-1'; + + $outputlangs->load("main"); + $outputlangs->load("dict"); + $outputlangs->load("companies"); + $outputlangs->load("bills"); + $outputlangs->load("askpricesupplier"); + $outputlangs->load("products"); + + $nblignes = count($object->lines); + + // Loop on each lines to detect if there is at least one image to show + $realpatharray=array(); + if (! empty($conf->global->MAIN_GENERATE_ASKPRICESUPPLIER_WITH_PICTURE)) + { + for ($i = 0 ; $i < $nblignes ; $i++) + { + if (empty($object->lines[$i]->fk_product)) continue; + + $objphoto = new Product($this->db); + $objphoto->fetch($object->lines[$i]->fk_product); + + $pdir = get_exdir($object->lines[$i]->fk_product,2) . $object->lines[$i]->fk_product ."/photos/"; + $dir = $conf->product->dir_output.'/'.$pdir; + + $realpath=''; + foreach ($objphoto->liste_photos($dir,1) as $key => $obj) + { + $filename=$obj['photo']; + //if ($obj['photo_vignette']) $filename='thumbs/'.$obj['photo_vignette']; + $realpath = $dir.$filename; + break; + } + + if ($realpath) $realpatharray[$i]=$realpath; + } + } + if (count($realpatharray) == 0) $this->posxpicture=$this->posxtva; + + if ($conf->askpricesupplier->dir_output) + { + $object->fetch_thirdparty(); + + // $deja_regle = 0; + + // Definition of $dir and $file + if ($object->specimen) + { + $dir = $conf->askpricesupplier->dir_output; + $file = $dir . "/SPECIMEN.pdf"; + } + else + { + $objectref = dol_sanitizeFileName($object->ref); + $dir = $conf->askpricesupplier->dir_output . "/" . $objectref; + $file = $dir . "/" . $objectref . ".pdf"; + } + + if (! file_exists($dir)) + { + if (dol_mkdir($dir) < 0) + { + $this->error=$langs->transnoentities("ErrorCanNotCreateDir",$dir); + return 0; + } + } + + if (file_exists($dir)) + { + // Add pdfgeneration hook + if (! is_object($hookmanager)) + { + include_once DOL_DOCUMENT_ROOT.'/core/class/hookmanager.class.php'; + $hookmanager=new HookManager($this->db); + } + $hookmanager->initHooks(array('pdfgeneration')); + $parameters=array('file'=>$file,'object'=>$object,'outputlangs'=>$outputlangs); + global $action; + $reshook=$hookmanager->executeHooks('beforePDFCreation',$parameters,$object,$action); // Note that $action and $object may have been modified by some hooks + + // Create pdf instance + $pdf=pdf_getInstance($this->format); + $default_font_size = pdf_getPDFFontSize($outputlangs); // Must be after pdf_getInstance + $heightforinfotot = 50; // Height reserved to output the info and total part + $heightforfreetext= (isset($conf->global->MAIN_PDF_FREETEXT_HEIGHT)?$conf->global->MAIN_PDF_FREETEXT_HEIGHT:5); // Height reserved to output the free text on last page + $heightforfooter = $this->marge_basse + 8; // Height reserved to output the footer (value include bottom margin) + $pdf->SetAutoPageBreak(1,0); + + if (class_exists('TCPDF')) + { + $pdf->setPrintHeader(false); + $pdf->setPrintFooter(false); + } + $pdf->SetFont(pdf_getPDFFont($outputlangs)); + // Set path to the background PDF File + if (empty($conf->global->MAIN_DISABLE_FPDI) && ! empty($conf->global->MAIN_ADD_PDF_BACKGROUND)) + { + $pagecount = $pdf->setSourceFile($conf->mycompany->dir_output.'/'.$conf->global->MAIN_ADD_PDF_BACKGROUND); + $tplidx = $pdf->importPage(1); + } + + $pdf->Open(); + $pagenb=0; + $pdf->SetDrawColor(128,128,128); + + $pdf->SetTitle($outputlangs->convToOutputCharset($object->ref)); + $pdf->SetSubject($outputlangs->transnoentities("CommercialAsk")); + $pdf->SetCreator("Dolibarr ".DOL_VERSION); + $pdf->SetAuthor($outputlangs->convToOutputCharset($user->getFullName($outputlangs))); + $pdf->SetKeyWords($outputlangs->convToOutputCharset($object->ref)." ".$outputlangs->transnoentities("CommercialAsk")); + if (! empty($conf->global->MAIN_DISABLE_PDF_COMPRESSION)) $pdf->SetCompression(false); + + $pdf->SetMargins($this->marge_gauche, $this->marge_haute, $this->marge_droite); // Left, Top, Right + + // Positionne $this->atleastonediscount si on a au moins une remise + for ($i = 0 ; $i < $nblignes ; $i++) + { + if ($object->lines[$i]->remise_percent) + { + $this->atleastonediscount++; + } + } + if (empty($this->atleastonediscount)) + { + $this->posxpicture+=($this->postotalht - $this->posxdiscount); + $this->posxtva+=($this->postotalht - $this->posxdiscount); + $this->posxup+=($this->postotalht - $this->posxdiscount); + $this->posxqty+=($this->postotalht - $this->posxdiscount); + $this->posxdiscount+=($this->postotalht - $this->posxdiscount); + //$this->postotalht; + } + + // New page + $pdf->AddPage(); + if (! empty($tplidx)) $pdf->useTemplate($tplidx); + $pagenb++; + $this->_pagehead($pdf, $object, 1, $outputlangs); + $pdf->SetFont('','', $default_font_size - 1); + $pdf->MultiCell(0, 3, ''); // Set interline to 3 + $pdf->SetTextColor(0,0,0); + + $tab_top = 90; + $tab_top_newpage = (empty($conf->global->MAIN_PDF_DONOTREPEAT_HEAD)?42:10); + $tab_height = 130; + $tab_height_newpage = 150; + + // Affiche notes + $notetoshow=empty($object->note_public)?'':$object->note_public; + if (! empty($conf->global->MAIN_ADD_SALE_REP_SIGNATURE_IN_NOTE)) + { + // Get first sale rep + if (is_object($object->thirdparty)) + { + $salereparray=$object->thirdparty->getSalesRepresentatives($user); + $salerepobj=new User($this->db); + $salerepobj->fetch($salereparray[0]['id']); + if (! empty($salerepobj->signature)) $notetoshow=dol_concatdesc($notetoshow, $salerepobj->signature); + } + } + if ($notetoshow) + { + $tab_top = 88; + + $pdf->SetFont('','', $default_font_size - 1); + $pdf->writeHTMLCell(190, 3, $this->posxdesc-1, $tab_top, dol_htmlentitiesbr($notetoshow), 0, 1); + $nexY = $pdf->GetY(); + $height_note=$nexY-$tab_top; + + // Rect prend une longueur en 3eme param + $pdf->SetDrawColor(192,192,192); + $pdf->Rect($this->marge_gauche, $tab_top-1, $this->page_largeur-$this->marge_gauche-$this->marge_droite, $height_note+1); + + $tab_height = $tab_height - $height_note; + $tab_top = $nexY+6; + } + else + { + $height_note=0; + } + + $iniY = $tab_top + 7; + $curY = $tab_top + 7; + $nexY = $tab_top + 7; + + // Loop on each lines + for ($i = 0 ; $i < $nblignes ; $i++) + { + $curY = $nexY; + $pdf->SetFont('','', $default_font_size - 1); // Into loop to work with multipage + $pdf->SetTextColor(0,0,0); + + // Define size of image if we need it + $imglinesize=array(); + if (! empty($realpatharray[$i])) $imglinesize=pdf_getSizeForImage($realpatharray[$i]); + + $pdf->setTopMargin($tab_top_newpage); + $pdf->setPageOrientation('', 1, $heightforfooter+$heightforfreetext+$heightforinfotot); // The only function to edit the bottom margin of current page to set it. + $pageposbefore=$pdf->getPage(); + + $showpricebeforepagebreak=1; + $posYAfterImage=0; + $posYAfterDescription=0; + + // We start with Photo of product line + if (isset($imglinesize['width']) && isset($imglinesize['height']) && ($curY + $imglinesize['height']) > ($this->page_hauteur-($heightforfooter+$heightforfreetext+$heightforinfotot))) // If photo too high, we moved completely on new page + { + $pdf->AddPage('','',true); + if (! empty($tplidx)) $pdf->useTemplate($tplidx); + if (empty($conf->global->MAIN_PDF_DONOTREPEAT_HEAD)) $this->_pagehead($pdf, $object, 0, $outputlangs); + $pdf->setPage($pageposbefore+1); + + $curY = $tab_top_newpage; + $showpricebeforepagebreak=0; + } + + if (isset($imglinesize['width']) && isset($imglinesize['height'])) + { + $curX = $this->posxpicture-1; + $pdf->Image($realpatharray[$i], $curX + (($this->posxtva-$this->posxpicture-$imglinesize['width'])/2), $curY, $imglinesize['width'], $imglinesize['height'], '', '', '', 2, 300); // Use 300 dpi + // $pdf->Image does not increase value return by getY, so we save it manually + $posYAfterImage=$curY+$imglinesize['height']; + } + + // Description of product line + $curX = $this->posxdesc-1; + + $pdf->startTransaction(); + pdf_writelinedesc($pdf,$object,$i,$outputlangs,$this->posxpicture-$curX,3,$curX,$curY,$hideref,$hidedesc); + + $pageposafter=$pdf->getPage(); + if ($pageposafter > $pageposbefore) // There is a pagebreak + { + $pdf->rollbackTransaction(true); + $pageposafter=$pageposbefore; + //print $pageposafter.'-'.$pageposbefore;exit; + $pdf->setPageOrientation('', 1, $heightforfooter); // The only function to edit the bottom margin of current page to set it. + pdf_writelinedesc($pdf,$object,$i,$outputlangs,$this->posxpicture-$curX,3,$curX,$curY,$hideref,$hidedesc); + + $pageposafter=$pdf->getPage(); + $posyafter=$pdf->GetY(); + //var_dump($posyafter); var_dump(($this->page_hauteur - ($heightforfooter+$heightforfreetext+$heightforinfotot))); exit; + if ($posyafter > ($this->page_hauteur - ($heightforfooter+$heightforfreetext+$heightforinfotot))) // There is no space left for total+free text + { + if ($i == ($nblignes-1)) // No more lines, and no space left to show total, so we create a new page + { + $pdf->AddPage('','',true); + if (! empty($tplidx)) $pdf->useTemplate($tplidx); + if (empty($conf->global->MAIN_PDF_DONOTREPEAT_HEAD)) $this->_pagehead($pdf, $object, 0, $outputlangs); + $pdf->setPage($pageposafter+1); + } + } + else + { + // We found a page break + $showpricebeforepagebreak=0; + } + } + else // No pagebreak + { + $pdf->commitTransaction(); + } + $posYAfterDescription=$pdf->GetY(); + + $nexY = $pdf->GetY(); + $pageposafter=$pdf->getPage(); + + $pdf->setPage($pageposbefore); + $pdf->setTopMargin($this->marge_haute); + $pdf->setPageOrientation('', 1, 0); // The only function to edit the bottom margin of current page to set it. + + // We suppose that a too long description or photo were moved completely on next page + if ($pageposafter > $pageposbefore && empty($showpricebeforepagebreak)) { + $pdf->setPage($pageposafter); $curY = $tab_top_newpage; + } + + $pdf->SetFont('','', $default_font_size - 1); // On repositionne la police par defaut + + // VAT Rate + if (empty($conf->global->MAIN_GENERATE_DOCUMENTS_WITHOUT_VAT)) + { + $vat_rate = pdf_getlinevatrate($object, $i, $outputlangs, $hidedetails); + $pdf->SetXY($this->posxtva, $curY); + $pdf->MultiCell($this->posxup-$this->posxtva-3, 3, $vat_rate, 0, 'R'); + } + + // Unit price before discount + $up_excl_tax = pdf_getlineupexcltax($object, $i, $outputlangs, $hidedetails); + $pdf->SetXY($this->posxup, $curY); + if ($up_excl_tax > 0) + $pdf->MultiCell($this->posxqty-$this->posxup-0.8, 3, $up_excl_tax, 0, 'R', 0); + + // Quantity + $qty = pdf_getlineqty($object, $i, $outputlangs, $hidedetails); + $pdf->SetXY($this->posxqty, $curY); + $pdf->MultiCell($this->posxdiscount-$this->posxqty-0.8, 3, $qty, 0, 'R'); // Enough for 6 chars + + // Discount on line + if ($object->lines[$i]->remise_percent) + { + $pdf->SetXY($this->posxdiscount-2, $curY); + $remise_percent = pdf_getlineremisepercent($object, $i, $outputlangs, $hidedetails); + $pdf->MultiCell($this->postotalht-$this->posxdiscount+2, 3, $remise_percent, 0, 'R'); + } + + // Total HT line + $total_excl_tax = pdf_getlinetotalexcltax($object, $i, $outputlangs, $hidedetails); + $pdf->SetXY($this->postotalht, $curY); + if ($total_excl_tax > 0) + $pdf->MultiCell($this->page_largeur-$this->marge_droite-$this->postotalht, 3, $total_excl_tax, 0, 'R', 0); + + // Collecte des totaux par valeur de tva dans $this->tva["taux"]=total_tva + $tvaligne=$object->lines[$i]->total_tva; + $localtax1ligne=$object->lines[$i]->total_localtax1; + $localtax2ligne=$object->lines[$i]->total_localtax2; + $localtax1_rate=$object->lines[$i]->localtax1_tx; + $localtax2_rate=$object->lines[$i]->localtax2_tx; + $localtax1_type=$object->lines[$i]->localtax1_type; + $localtax2_type=$object->lines[$i]->localtax2_type; + + if ($object->remise_percent) $tvaligne-=($tvaligne*$object->remise_percent)/100; + if ($object->remise_percent) $localtax1ligne-=($localtax1ligne*$object->remise_percent)/100; + if ($object->remise_percent) $localtax2ligne-=($localtax2ligne*$object->remise_percent)/100; + + $vatrate=(string) $object->lines[$i]->tva_tx; + + // Retrieve type from database for backward compatibility with old records + if ((! isset($localtax1_type) || $localtax1_type=='' || ! isset($localtax2_type) || $localtax2_type=='') // if tax type not defined + && (! empty($localtax1_rate) || ! empty($localtax2_rate))) // and there is local tax + { + $localtaxtmp_array=getLocalTaxesFromRate($vatrate,0,$object->thirdparty,$mysoc); + $localtax1_type = $localtaxtmp_array[0]; + $localtax2_type = $localtaxtmp_array[2]; + } + + // retrieve global local tax + if ($localtax1_type && $localtax1ligne != 0) + $this->localtax1[$localtax1_type][$localtax1_rate]+=$localtax1ligne; + if ($localtax2_type && $localtax2ligne != 0) + $this->localtax2[$localtax2_type][$localtax2_rate]+=$localtax2ligne; + + if (($object->lines[$i]->info_bits & 0x01) == 0x01) $vatrate.='*'; + if (! isset($this->tva[$vatrate])) $this->tva[$vatrate]=''; + $this->tva[$vatrate] += $tvaligne; + + if ($posYAfterImage > $posYAfterDescription) $nexY=$posYAfterImage; + + // Add line + if (! empty($conf->global->MAIN_PDF_DASH_BETWEEN_LINES) && $i < ($nblignes - 1)) + { + $pdf->setPage($pageposafter); + $pdf->SetLineStyle(array('dash'=>'1,1','color'=>array(210,210,210))); + //$pdf->SetDrawColor(190,190,200); + $pdf->line($this->marge_gauche, $nexY+1, $this->page_largeur - $this->marge_droite, $nexY+1); + $pdf->SetLineStyle(array('dash'=>0)); + } + + $nexY+=2; // Passe espace entre les lignes + + // Detect if some page were added automatically and output _tableau for past pages + while ($pagenb < $pageposafter) + { + $pdf->setPage($pagenb); + if ($pagenb == 1) + { + $this->_tableau($pdf, $tab_top, $this->page_hauteur - $tab_top - $heightforfooter, 0, $outputlangs, 0, 1); + } + else + { + $this->_tableau($pdf, $tab_top_newpage, $this->page_hauteur - $tab_top_newpage - $heightforfooter, 0, $outputlangs, 1, 1); + } + $this->_pagefoot($pdf,$object,$outputlangs,1); + $pagenb++; + $pdf->setPage($pagenb); + $pdf->setPageOrientation('', 1, 0); // The only function to edit the bottom margin of current page to set it. + if (empty($conf->global->MAIN_PDF_DONOTREPEAT_HEAD)) $this->_pagehead($pdf, $object, 0, $outputlangs); + } + if (isset($object->lines[$i+1]->pagebreak) && $object->lines[$i+1]->pagebreak) + { + if ($pagenb == 1) + { + $this->_tableau($pdf, $tab_top, $this->page_hauteur - $tab_top - $heightforfooter, 0, $outputlangs, 0, 1); + } + else + { + $this->_tableau($pdf, $tab_top_newpage, $this->page_hauteur - $tab_top_newpage - $heightforfooter, 0, $outputlangs, 1, 1); + } + $this->_pagefoot($pdf,$object,$outputlangs,1); + // New page + $pdf->AddPage(); + if (! empty($tplidx)) $pdf->useTemplate($tplidx); + $pagenb++; + if (empty($conf->global->MAIN_PDF_DONOTREPEAT_HEAD)) $this->_pagehead($pdf, $object, 0, $outputlangs); + } + } + + // Show square + if ($pagenb == 1) + { + $this->_tableau($pdf, $tab_top, $this->page_hauteur - $tab_top - $heightforinfotot - $heightforfreetext - $heightforfooter, 0, $outputlangs, 0, 0); + $bottomlasttab=$this->page_hauteur - $heightforinfotot - $heightforfreetext - $heightforfooter + 1; + } + else + { + $this->_tableau($pdf, $tab_top_newpage, $this->page_hauteur - $tab_top_newpage - $heightforinfotot - $heightforfreetext - $heightforfooter, 0, $outputlangs, 1, 0); + $bottomlasttab=$this->page_hauteur - $heightforinfotot - $heightforfreetext - $heightforfooter + 1; + } + + // Affiche zone infos + $posy=$this->_tableau_info($pdf, $object, $bottomlasttab, $outputlangs); + + // Affiche zone totaux + $posy=$this->_tableau_tot($pdf, $object, 0, $bottomlasttab, $outputlangs); + + // Affiche zone versements + /* + if ($deja_regle || $amount_credit_notes_included || $amount_deposits_included) + { + $posy=$this->_tableau_versements($pdf, $object, $posy, $outputlangs); + } + */ + + // Pied de page + $this->_pagefoot($pdf,$object,$outputlangs); + if (method_exists($pdf,'AliasNbPages')) $pdf->AliasNbPages(); + + $pdf->Close(); + + $pdf->Output($file,'F'); + + //Add pdfgeneration hook + $hookmanager->initHooks(array('pdfgeneration')); + $parameters=array('file'=>$file,'object'=>$object,'outputlangs'=>$outputlangs); + global $action; + $reshook=$hookmanager->executeHooks('afterPDFCreation',$parameters,$this,$action); // Note that $action and $object may have been modified by some hooks + + if (! empty($conf->global->MAIN_UMASK)) + @chmod($file, octdec($conf->global->MAIN_UMASK)); + + return 1; // Pas d'erreur + } + else + { + $this->error=$langs->trans("ErrorCanNotCreateDir",$dir); + return 0; + } + } + else + { + $this->error=$langs->trans("ErrorConstantNotDefined","PROP_OUTPUTDIR"); + return 0; + } + + $this->error=$langs->trans("ErrorUnknown"); + return 0; // Erreur par defaut + } + + /** + * Show payments table + * + * @param PDF $pdf Object PDF + * @param Object $object Object proposal + * @param int $posy Position y in PDF + * @param Translate $outputlangs Object langs for output + * @return int <0 if KO, >0 if OK + */ + function _tableau_versements(&$pdf, $object, $posy, $outputlangs) + { + + } + + + /** + * Show miscellaneous information (payment mode, payment term, ...) + * + * @param PDF $pdf Object PDF + * @param Object $object Object to show + * @param int $posy Y + * @param Translate $outputlangs Langs object + * @return void + */ + function _tableau_info(&$pdf, $object, $posy, $outputlangs) + { + global $conf; + $default_font_size = pdf_getPDFFontSize($outputlangs); + + $pdf->SetFont('','', $default_font_size - 1); + + // If France, show VAT mention if not applicable + if ($this->emetteur->country_code == 'FR' && $this->franchise == 1) + { + $pdf->SetFont('','B', $default_font_size - 2); + $pdf->SetXY($this->marge_gauche, $posy); + $pdf->MultiCell(100, 3, $outputlangs->transnoentities("VATIsNotUsedForInvoice"), 0, 'L', 0); + + $posy=$pdf->GetY()+4; + } + + $posxval=52; + + // Show shipping date + if (! empty($object->date_livraison)) + { + $outputlangs->load("sendings"); + $pdf->SetFont('','B', $default_font_size - 2); + $pdf->SetXY($this->marge_gauche, $posy); + $titre = $outputlangs->transnoentities("DateDeliveryPlanned").':'; + $pdf->MultiCell(80, 4, $titre, 0, 'L'); + $pdf->SetFont('','', $default_font_size - 2); + $pdf->SetXY($posxval, $posy); + $dlp=dol_print_date($object->date_livraison,"daytext",false,$outputlangs,true); + $pdf->MultiCell(80, 4, $dlp, 0, 'L'); + + $posy=$pdf->GetY()+1; + } + else { + $outputlangs->load("sendings"); + $pdf->SetFont('','B', $default_font_size - 2); + $pdf->SetXY($this->marge_gauche, $posy); + $titre = $outputlangs->transnoentities("DateDeliveryPlanned").':'; + $pdf->MultiCell(80, 4, $titre, 0, 'L'); + $pdf->SetFont('','', $default_font_size - 2); + $pdf->SetXY($posxval, $posy); + //$dlp=dol_print_date($object->date_livraison,"daytext",false,$outputlangs,true); + $pdf->MultiCell(80, 4, $dlp, 0, 'L'); + + $posy=$pdf->GetY()+1; + } + /* PHFAVRE + elseif ($object->availability_code || $object->availability) // Show availability conditions + { + $pdf->SetFont('','B', $default_font_size - 2); + $pdf->SetXY($this->marge_gauche, $posy); + $titre = $outputlangs->transnoentities("AvailabilityPeriod").':'; + $pdf->MultiCell(80, 4, $titre, 0, 'L'); + $pdf->SetTextColor(0,0,0); + $pdf->SetFont('','', $default_font_size - 2); + $pdf->SetXY($posxval, $posy); + $lib_availability=$outputlangs->transnoentities("AvailabilityType".$object->availability_code)!=('AvailabilityType'.$object->availability_code)?$outputlangs->transnoentities("AvailabilityType".$object->availability_code):$outputlangs->convToOutputCharset($object->availability); + $lib_availability=str_replace('\n',"\n",$lib_availability); + $pdf->MultiCell(80, 4, $lib_availability, 0, 'L'); + + $posy=$pdf->GetY()+1; + }*/ + + // Show payments conditions + if (empty($conf->global->ASKPRICESUPPLIER_PDF_HIDE_PAYMENTTERMCOND) && ($object->cond_reglement_code || $object->cond_reglement)) + { + $pdf->SetFont('','B', $default_font_size - 2); + $pdf->SetXY($this->marge_gauche, $posy); + $titre = $outputlangs->transnoentities("PaymentConditions").':'; + $pdf->MultiCell(80, 4, $titre, 0, 'L'); + + $pdf->SetFont('','', $default_font_size - 2); + $pdf->SetXY($posxval, $posy); + $lib_condition_paiement=$outputlangs->transnoentities("PaymentCondition".$object->cond_reglement_code)!=('PaymentCondition'.$object->cond_reglement_code)?$outputlangs->transnoentities("PaymentCondition".$object->cond_reglement_code):$outputlangs->convToOutputCharset($object->cond_reglement_doc); + $lib_condition_paiement=str_replace('\n',"\n",$lib_condition_paiement); + $pdf->MultiCell(80, 4, $lib_condition_paiement,0,'L'); + + $posy=$pdf->GetY()+3; + } + else { + $pdf->SetFont('','B', $default_font_size - 2); + $pdf->SetXY($this->marge_gauche, $posy); + $titre = $outputlangs->transnoentities("PaymentConditions").':'; + $pdf->MultiCell(80, 4, $titre, 0, 'L'); + + $pdf->SetFont('','', $default_font_size - 2); + $pdf->SetXY($posxval, $posy); + + $lib_condition_paiement=str_replace('\n',"\n",$lib_condition_paiement); + $pdf->MultiCell(80, 4, $lib_condition_paiement,0,'L'); + + $posy=$pdf->GetY()+3; + } + + if (empty($conf->global->ASKPRICESUPPLIER_PDF_HIDE_PAYMENTTERMCOND)) + { + // Show payment mode + if ($object->mode_reglement_code + && $object->mode_reglement_code != 'CHQ' + && $object->mode_reglement_code != 'VIR') + { + $pdf->SetFont('','B', $default_font_size - 2); + $pdf->SetXY($this->marge_gauche, $posy-2); + $titre = $outputlangs->transnoentities("PaymentMode").':'; + $pdf->MultiCell(80, 5, $titre, 0, 'L'); + $pdf->SetFont('','', $default_font_size - 2); + $pdf->SetXY($posxval, $posy-2); + $lib_mode_reg=$outputlangs->transnoentities("PaymentType".$object->mode_reglement_code)!=('PaymentType'.$object->mode_reglement_code)?$outputlangs->transnoentities("PaymentType".$object->mode_reglement_code):$outputlangs->convToOutputCharset($object->mode_reglement); + $pdf->MultiCell(80, 5, $lib_mode_reg,0,'L'); + + $posy=$pdf->GetY()+2; + } + + // Show payment mode CHQ + if (empty($object->mode_reglement_code) || $object->mode_reglement_code == 'CHQ') + { + // Si mode reglement non force ou si force a CHQ + if (! empty($conf->global->FACTURE_CHQ_NUMBER)) + { + $diffsizetitle=(empty($conf->global->PDF_DIFFSIZE_TITLE)?3:$conf->global->PDF_DIFFSIZE_TITLE); + + if ($conf->global->FACTURE_CHQ_NUMBER > 0) + { + $account = new Account($this->db); + $account->fetch($conf->global->FACTURE_CHQ_NUMBER); + + $pdf->SetXY($this->marge_gauche, $posy); + $pdf->SetFont('','B', $default_font_size - $diffsizetitle); + $pdf->MultiCell(100, 3, $outputlangs->transnoentities('PaymentByChequeOrderedTo',$account->proprio),0,'L',0); + $posy=$pdf->GetY()+1; + + if (empty($conf->global->MAIN_PDF_HIDE_CHQ_ADDRESS)) + { + $pdf->SetXY($this->marge_gauche, $posy); + $pdf->SetFont('','', $default_font_size - $diffsizetitle); + $pdf->MultiCell(100, 3, $outputlangs->convToOutputCharset($account->owner_address), 0, 'L', 0); + $posy=$pdf->GetY()+2; + } + } + if ($conf->global->FACTURE_CHQ_NUMBER == -1) + { + $pdf->SetXY($this->marge_gauche, $posy); + $pdf->SetFont('','B', $default_font_size - $diffsizetitle); + $pdf->MultiCell(100, 3, $outputlangs->transnoentities('PaymentByChequeOrderedTo',$this->emetteur->name),0,'L',0); + $posy=$pdf->GetY()+1; + + if (empty($conf->global->MAIN_PDF_HIDE_CHQ_ADDRESS)) + { + $pdf->SetXY($this->marge_gauche, $posy); + $pdf->SetFont('','', $default_font_size - $diffsizetitle); + $pdf->MultiCell(100, 3, $outputlangs->convToOutputCharset($this->emetteur->getFullAddress()), 0, 'L', 0); + $posy=$pdf->GetY()+2; + } + } + } + } + + // If payment mode not forced or forced to VIR, show payment with BAN + if (empty($object->mode_reglement_code) || $object->mode_reglement_code == 'VIR') + { + if (! empty($object->fk_bank) || ! empty($conf->global->FACTURE_RIB_NUMBER)) + { + $bankid=(empty($object->fk_bank)?$conf->global->FACTURE_RIB_NUMBER:$object->fk_bank); + $account = new Account($this->db); + $account->fetch($bankid); + + $curx=$this->marge_gauche; + $cury=$posy; + + $posy=pdf_bank($pdf,$outputlangs,$curx,$cury,$account,0,$default_font_size); + + $posy+=2; + } + } + } + + return $posy; + } + + + /** + * Show total to pay + * + * @param PDF $pdf Object PDF + * @param Facture $object Object invoice + * @param int $deja_regle Montant deja regle + * @param int $posy Position depart + * @param Translate $outputlangs Objet langs + * @return int Position pour suite + */ + function _tableau_tot(&$pdf, $object, $deja_regle, $posy, $outputlangs) + { + global $conf,$mysoc; + $default_font_size = pdf_getPDFFontSize($outputlangs); + + $tab2_top = $posy; + $tab2_hl = 4; + $pdf->SetFont('','', $default_font_size - 1); + + // Tableau total + $col1x = 120; $col2x = 170; + if ($this->page_largeur < 210) // To work with US executive format + { + $col2x-=20; + } + $largcol2 = ($this->page_largeur - $this->marge_droite - $col2x); + + $useborder=0; + $index = 0; + + // Total HT + $pdf->SetFillColor(255,255,255); + $pdf->SetXY($col1x, $tab2_top + 0); + $pdf->MultiCell($col2x-$col1x, $tab2_hl, $outputlangs->transnoentities("TotalHT"), 0, 'L', 1); + + $pdf->SetXY($col2x, $tab2_top + 0); + $pdf->MultiCell($largcol2, $tab2_hl, price($object->total_ht + (! empty($object->remise)?$object->remise:0), 0, $outputlangs), 0, 'R', 1); + + // Show VAT by rates and total + $pdf->SetFillColor(248,248,248); + + $this->atleastoneratenotnull=0; + if (empty($conf->global->MAIN_GENERATE_DOCUMENTS_WITHOUT_VAT)) + { + $tvaisnull=((! empty($this->tva) && count($this->tva) == 1 && isset($this->tva['0.000']) && is_float($this->tva['0.000'])) ? true : false); + if (! empty($conf->global->MAIN_GENERATE_DOCUMENTS_WITHOUT_VAT_ISNULL) && $tvaisnull) + { + // Nothing to do + } + else + { + //Local tax 1 before VAT + //if (! empty($conf->global->FACTURE_LOCAL_TAX1_OPTION) && $conf->global->FACTURE_LOCAL_TAX1_OPTION=='localtax1on') + //{ + foreach( $this->localtax1 as $localtax_type => $localtax_rate ) + { + if (in_array((string) $localtax_type, array('1','3','5'))) continue; + + foreach( $localtax_rate as $tvakey => $tvaval ) + { + if ($tvakey!=0) // On affiche pas taux 0 + { + //$this->atleastoneratenotnull++; + + $index++; + $pdf->SetXY($col1x, $tab2_top + $tab2_hl * $index); + + $tvacompl=''; + if (preg_match('/\*/',$tvakey)) + { + $tvakey=str_replace('*','',$tvakey); + $tvacompl = " (".$outputlangs->transnoentities("NonPercuRecuperable").")"; + } + $totalvat = $outputlangs->transcountrynoentities("TotalLT1",$mysoc->country_code).' '; + $totalvat.=vatrate(abs($tvakey),1).$tvacompl; + $pdf->MultiCell($col2x-$col1x, $tab2_hl, $totalvat, 0, 'L', 1); + + $pdf->SetXY($col2x, $tab2_top + $tab2_hl * $index); + $pdf->MultiCell($largcol2, $tab2_hl, price($tvaval, 0, $outputlangs), 0, 'R', 1); + } + } + } + //} + //Local tax 2 before VAT + //if (! empty($conf->global->FACTURE_LOCAL_TAX2_OPTION) && $conf->global->FACTURE_LOCAL_TAX2_OPTION=='localtax2on') + //{ + foreach( $this->localtax2 as $localtax_type => $localtax_rate ) + { + if (in_array((string) $localtax_type, array('1','3','5'))) continue; + + foreach( $localtax_rate as $tvakey => $tvaval ) + { + if ($tvakey!=0) // On affiche pas taux 0 + { + //$this->atleastoneratenotnull++; + + + + $index++; + $pdf->SetXY($col1x, $tab2_top + $tab2_hl * $index); + + $tvacompl=''; + if (preg_match('/\*/',$tvakey)) + { + $tvakey=str_replace('*','',$tvakey); + $tvacompl = " (".$outputlangs->transnoentities("NonPercuRecuperable").")"; + } + $totalvat = $outputlangs->transcountrynoentities("TotalLT2", $mysoc->country_code).' '; + $totalvat.=vatrate(abs($tvakey),1).$tvacompl; + $pdf->MultiCell($col2x-$col1x, $tab2_hl, $totalvat, 0, 'L', 1); + + $pdf->SetXY($col2x, $tab2_top + $tab2_hl * $index); + $pdf->MultiCell($largcol2, $tab2_hl, price($tvaval, 0, $outputlangs), 0, 'R', 1); + + } + } + } + //} + // VAT + foreach($this->tva as $tvakey => $tvaval) + { + if ($tvakey > 0) // On affiche pas taux 0 + { + $this->atleastoneratenotnull++; + + $index++; + $pdf->SetXY($col1x, $tab2_top + $tab2_hl * $index); + + $tvacompl=''; + if (preg_match('/\*/',$tvakey)) + { + $tvakey=str_replace('*','',$tvakey); + $tvacompl = " (".$outputlangs->transnoentities("NonPercuRecuperable").")"; + } + $totalvat =$outputlangs->transnoentities("TotalVAT").' '; + $totalvat.=vatrate($tvakey,1).$tvacompl; + $pdf->MultiCell($col2x-$col1x, $tab2_hl, $totalvat, 0, 'L', 1); + + $pdf->SetXY($col2x, $tab2_top + $tab2_hl * $index); + $pdf->MultiCell($largcol2, $tab2_hl, price($tvaval, 0, $outputlangs), 0, 'R', 1); + } + } + + //Local tax 1 after VAT + //if (! empty($conf->global->FACTURE_LOCAL_TAX1_OPTION) && $conf->global->FACTURE_LOCAL_TAX1_OPTION=='localtax1on') + //{ + foreach( $this->localtax1 as $localtax_type => $localtax_rate ) + { + if (in_array((string) $localtax_type, array('2','4','6'))) continue; + + foreach( $localtax_rate as $tvakey => $tvaval ) + { + if ($tvakey != 0) // On affiche pas taux 0 + { + //$this->atleastoneratenotnull++; + + $index++; + $pdf->SetXY($col1x, $tab2_top + $tab2_hl * $index); + + $tvacompl=''; + if (preg_match('/\*/',$tvakey)) + { + $tvakey=str_replace('*','',$tvakey); + $tvacompl = " (".$outputlangs->transnoentities("NonPercuRecuperable").")"; + } + $totalvat = $outputlangs->transcountrynoentities("TotalLT1",$mysoc->country_code).' '; + + $totalvat.=vatrate(abs($tvakey),1).$tvacompl; + $pdf->MultiCell($col2x-$col1x, $tab2_hl, $totalvat, 0, 'L', 1); + $pdf->SetXY($col2x, $tab2_top + $tab2_hl * $index); + $pdf->MultiCell($largcol2, $tab2_hl, price($tvaval, 0, $outputlangs), 0, 'R', 1); + } + } + } + //} + //Local tax 2 after VAT + //if (! empty($conf->global->FACTURE_LOCAL_TAX2_OPTION) && $conf->global->FACTURE_LOCAL_TAX2_OPTION=='localtax2on') + //{ + foreach( $this->localtax2 as $localtax_type => $localtax_rate ) + { + if (in_array((string) $localtax_type, array('2','4','6'))) continue; + + foreach( $localtax_rate as $tvakey => $tvaval ) + { + // retrieve global local tax + if ($tvakey != 0) // On affiche pas taux 0 + { + //$this->atleastoneratenotnull++; + + $index++; + $pdf->SetXY($col1x, $tab2_top + $tab2_hl * $index); + + $tvacompl=''; + if (preg_match('/\*/',$tvakey)) + { + $tvakey=str_replace('*','',$tvakey); + $tvacompl = " (".$outputlangs->transnoentities("NonPercuRecuperable").")"; + } + $totalvat = $outputlangs->transcountrynoentities("TotalLT2",$mysoc->country_code).' '; + + $totalvat.=vatrate(abs($tvakey),1).$tvacompl; + $pdf->MultiCell($col2x-$col1x, $tab2_hl, $totalvat, 0, 'L', 1); + + $pdf->SetXY($col2x, $tab2_top + $tab2_hl * $index); + $pdf->MultiCell($largcol2, $tab2_hl, price($tvaval, 0, $outputlangs), 0, 'R', 1); + } + } + } + //} + + // Total TTC + $index++; + $pdf->SetXY($col1x, $tab2_top + $tab2_hl * $index); + $pdf->SetTextColor(0,0,60); + $pdf->SetFillColor(224,224,224); + $pdf->MultiCell($col2x-$col1x, $tab2_hl, $outputlangs->transnoentities("TotalTTC"), $useborder, 'L', 1); + + $pdf->SetXY($col2x, $tab2_top + $tab2_hl * $index); + $pdf->MultiCell($largcol2, $tab2_hl, price($object->total_ttc, 0, $outputlangs), $useborder, 'R', 1); + } + } + + $pdf->SetTextColor(0,0,0); + + /* + $resteapayer = $object->total_ttc - $deja_regle; + if (! empty($object->paye)) $resteapayer=0; + */ + + if ($deja_regle > 0) + { + $index++; + + $pdf->SetXY($col1x, $tab2_top + $tab2_hl * $index); + $pdf->MultiCell($col2x-$col1x, $tab2_hl, $outputlangs->transnoentities("AlreadyPaid"), 0, 'L', 0); + + $pdf->SetXY($col2x, $tab2_top + $tab2_hl * $index); + $pdf->MultiCell($largcol2, $tab2_hl, price($deja_regle, 0, $outputlangs), 0, 'R', 0); + + /* + if ($object->close_code == 'discount_vat') + { + $index++; + $pdf->SetFillColor(255,255,255); + + $pdf->SetXY($col1x, $tab2_top + $tab2_hl * $index); + $pdf->MultiCell($col2x-$col1x, $tab2_hl, $outputlangs->transnoentities("EscompteOffered"), $useborder, 'L', 1); + + $pdf->SetXY($col2x, $tab2_top + $tab2_hl * $index); + $pdf->MultiCell($largcol2, $tab2_hl, price($object->total_ttc - $deja_regle, 0, $outputlangs), $useborder, 'R', 1); + + $resteapayer=0; + } + */ + + $index++; + $pdf->SetTextColor(0,0,60); + $pdf->SetFillColor(224,224,224); + $pdf->SetXY($col1x, $tab2_top + $tab2_hl * $index); + $pdf->MultiCell($col2x-$col1x, $tab2_hl, $outputlangs->transnoentities("RemainderToPay"), $useborder, 'L', 1); + + $pdf->SetXY($col2x, $tab2_top + $tab2_hl * $index); + $pdf->MultiCell($largcol2, $tab2_hl, price($resteapayer, 0, $outputlangs), $useborder, 'R', 1); + + $pdf->SetFont('','', $default_font_size - 1); + $pdf->SetTextColor(0,0,0); + } + + $index++; + return ($tab2_top + ($tab2_hl * $index)); + } + + /** + * Show table for lines + * + * @param PDF $pdf Object PDF + * @param string $tab_top Top position of table + * @param string $tab_height Height of table (rectangle) + * @param int $nexY Y (not used) + * @param Translate $outputlangs Langs object + * @param int $hidetop 1=Hide top bar of array and title, 0=Hide nothing, -1=Hide only title + * @param int $hidebottom Hide bottom bar of array + * @return void + */ + function _tableau(&$pdf, $tab_top, $tab_height, $nexY, $outputlangs, $hidetop=0, $hidebottom=0) + { + global $conf; + + // Force to disable hidetop and hidebottom + $hidebottom=0; + if ($hidetop) $hidetop=-1; + + $default_font_size = pdf_getPDFFontSize($outputlangs); + + // Amount in (at tab_top - 1) + $pdf->SetTextColor(0,0,0); + $pdf->SetFont('','',$default_font_size - 2); + + if (empty($hidetop)) + { + $titre = $outputlangs->transnoentities("AmountInCurrency",$outputlangs->transnoentitiesnoconv("Currency".$conf->currency)); + $pdf->SetXY($this->page_largeur - $this->marge_droite - ($pdf->GetStringWidth($titre) + 3), $tab_top-4); + $pdf->MultiCell(($pdf->GetStringWidth($titre) + 3), 2, $titre); + + //$conf->global->MAIN_PDF_TITLE_BACKGROUND_COLOR='230,230,230'; + if (! empty($conf->global->MAIN_PDF_TITLE_BACKGROUND_COLOR)) $pdf->Rect($this->marge_gauche, $tab_top, $this->page_largeur-$this->marge_droite-$this->marge_gauche, 5, 'F', null, explode(',',$conf->global->MAIN_PDF_TITLE_BACKGROUND_COLOR)); + } + + $pdf->SetDrawColor(128,128,128); + $pdf->SetFont('','',$default_font_size - 1); + + // Output Rect + $this->printRect($pdf,$this->marge_gauche, $tab_top, $this->page_largeur-$this->marge_gauche-$this->marge_droite, $tab_height, $hidetop, $hidebottom); // Rect prend une longueur en 3eme param et 4eme param + + if (empty($hidetop)) + { + $pdf->line($this->marge_gauche, $tab_top+5, $this->page_largeur-$this->marge_droite, $tab_top+5); // line prend une position y en 2eme param et 4eme param + + $pdf->SetXY($this->posxdesc-1, $tab_top+1); + $pdf->MultiCell(108,2, $outputlangs->transnoentities("Designation"),'','L'); + } + + if (! empty($conf->global->MAIN_GENERATE_PROPOSALS_WITH_PICTURE)) + { + $pdf->line($this->posxpicture-1, $tab_top, $this->posxpicture-1, $tab_top + $tab_height); + if (empty($hidetop)) + { + //$pdf->SetXY($this->posxpicture-1, $tab_top+1); + //$pdf->MultiCell($this->posxtva-$this->posxpicture-1,2, $outputlangs->transnoentities("Photo"),'','C'); + } + } + + if (empty($conf->global->MAIN_GENERATE_DOCUMENTS_WITHOUT_VAT)) + { + //$pdf->line($this->posxtva-1, $tab_top, $this->posxtva-1, $tab_top + $tab_height); + $pdf->line($this->posxtva-2, $tab_top, $this->posxtva-2, $tab_top + $tab_height); + if (empty($hidetop)) + { + $pdf->SetXY($this->posxtva-5, $tab_top+1); + $pdf->MultiCell($this->posxup-$this->posxtva+3,2, $outputlangs->transnoentities("VAT"),'','C'); + } + } + + $pdf->line($this->posxup-3, $tab_top, $this->posxup-3, $tab_top + $tab_height); + if (empty($hidetop)) + { + $pdf->SetXY($this->posxup-1, $tab_top+1); + $pdf->MultiCell($this->posxqty-$this->posxup-1,2, $outputlangs->transnoentities("AskPriceSupplierUHT"),'','C'); + } + + $pdf->line($this->posxqty-1, $tab_top, $this->posxqty-1, $tab_top + $tab_height); + if (empty($hidetop)) + { + $pdf->SetXY($this->posxqty-1, $tab_top+1); + $pdf->MultiCell($this->posxdiscount-$this->posxqty-1,2, $outputlangs->transnoentities("Qty"),'','C'); + } + + $pdf->line($this->posxdiscount-1, $tab_top, $this->posxdiscount-1, $tab_top + $tab_height); + if (empty($hidetop)) + { + if ($this->atleastonediscount) + { + $pdf->SetXY($this->posxdiscount-1, $tab_top+1); + $pdf->MultiCell($this->postotalht-$this->posxdiscount+1,2, $outputlangs->transnoentities("ReductionShort"),'','C'); + } + } + if ($this->atleastonediscount) + { + $pdf->line($this->postotalht, $tab_top, $this->postotalht, $tab_top + $tab_height); + } + if (empty($hidetop)) + { + $pdf->SetXY($this->postotalht-1, $tab_top+1); + $pdf->MultiCell(30,2, $outputlangs->transnoentities("TotalHT"),'','C'); + } + } + + /** + * Show top header of page. + * + * @param PDF $pdf Object PDF + * @param Object $object Object to show + * @param int $showaddress 0=no, 1=yes + * @param Translate $outputlangs Object lang for output + * @return void + */ + function _pagehead(&$pdf, $object, $showaddress, $outputlangs) + { + global $conf,$langs; + + $outputlangs->load("main"); + $outputlangs->load("bills"); + $outputlangs->load("askpricesupplier"); + $outputlangs->load("companies"); + + $default_font_size = pdf_getPDFFontSize($outputlangs); + + pdf_pagehead($pdf,$outputlangs,$this->page_hauteur); + + // Show Draft Watermark + if($object->statut==0 && (! empty($conf->global->ASKPRICESUPPLIER_DRAFT_WATERMARK)) ) + { + pdf_watermark($pdf,$outputlangs,$this->page_hauteur,$this->page_largeur,'mm',$conf->global->ASKPRICESUPPLIER_DRAFT_WATERMARK); + } + + $pdf->SetTextColor(0,0,60); + $pdf->SetFont('','B', $default_font_size + 3); + + $posy=$this->marge_haute; + $posx=$this->page_largeur-$this->marge_droite-100; + + $pdf->SetXY($this->marge_gauche,$posy); + + // Logo + $logo=$conf->mycompany->dir_output.'/logos/'.$this->emetteur->logo; + if ($this->emetteur->logo) + { + if (is_readable($logo)) + { + $height=pdf_getHeightForLogo($logo); + $pdf->Image($logo, $this->marge_gauche, $posy, 0, $height); // width=0 (auto) + } + else + { + $pdf->SetTextColor(200,0,0); + $pdf->SetFont('','B',$default_font_size - 2); + $pdf->MultiCell(100, 3, $outputlangs->transnoentities("ErrorLogoFileNotFound",$logo), 0, 'L'); + $pdf->MultiCell(100, 3, $outputlangs->transnoentities("ErrorGoToGlobalSetup"), 0, 'L'); + } + } + else + { + $text=$this->emetteur->name; + $pdf->MultiCell(100, 4, $outputlangs->convToOutputCharset($text), 0, 'L'); + } + + $pdf->SetFont('','B',$default_font_size + 3); + $pdf->SetXY($posx,$posy); + $pdf->SetTextColor(0,0,60); + $title=$outputlangs->transnoentities("CommercialAsk"); + $pdf->MultiCell(100, 4, $title, '', 'R'); + + $pdf->SetFont('','B',$default_font_size); + + $posy+=5; + $pdf->SetXY($posx,$posy); + $pdf->SetTextColor(0,0,60); + $pdf->MultiCell(100, 4, $outputlangs->transnoentities("Ref")." : " . $outputlangs->convToOutputCharset($object->ref), '', 'R'); + + $posy+=1; + $pdf->SetFont('','', $default_font_size - 2); + + if ($object->ref_client) + { + $posy+=4; + $pdf->SetXY($posx,$posy); + $pdf->SetTextColor(0,0,60); + $pdf->MultiCell(100, 3, $outputlangs->transnoentities("RefCustomer")." : " . $outputlangs->convToOutputCharset($object->ref_client), '', 'R'); + } +/* PHFAVRE + $posy+=4; + $pdf->SetXY($posx,$posy); + $pdf->SetTextColor(0,0,60); + $pdf->MultiCell(100, 3, $outputlangs->transnoentities("AskPriceSupplierDate")." : " . dol_print_date($object->date_livraison,"day",false,$outputlangs,true), '', 'R'); +*/ + + if ($object->client->code_client) + { + $posy+=4; + $pdf->SetXY($posx,$posy); + $pdf->SetTextColor(0,0,60); + $pdf->MultiCell(100, 3, $outputlangs->transnoentities("CustomerCode")." : " . $outputlangs->transnoentities($object->client->code_client), '', 'R'); + } + + $posy+=2; + + // Show list of linked objects + $posy = pdf_writeLinkedObjects($pdf, $object, $outputlangs, $posx, $posy, 100, 3, 'R', $default_font_size); + + if ($showaddress) + { + // Sender properties + $carac_emetteur=''; + // Add internal contact of proposal if defined + $arrayidcontact=$object->getIdContact('internal','SALESREPFOLL'); + if (count($arrayidcontact) > 0) + { + $object->fetch_user($arrayidcontact[0]); + $carac_emetteur .= ($carac_emetteur ? "\n" : '' ).$outputlangs->transnoentities("Name").": ".$outputlangs->convToOutputCharset($object->user->getFullName($outputlangs))."\n"; + } + + $carac_emetteur .= pdf_build_address($outputlangs, $this->emetteur, $object->client); + + // Show sender + $posy=42; + $posx=$this->marge_gauche; + if (! empty($conf->global->MAIN_INVERT_SENDER_RECIPIENT)) $posx=$this->page_largeur-$this->marge_droite-80; + $hautcadre=40; + + // Show sender frame + $pdf->SetTextColor(0,0,0); + $pdf->SetFont('','', $default_font_size - 2); + $pdf->SetXY($posx,$posy-5); + $pdf->MultiCell(66,5, $outputlangs->transnoentities("BillFrom").":", 0, 'L'); + $pdf->SetXY($posx,$posy); + $pdf->SetFillColor(230,230,230); + $pdf->MultiCell(82, $hautcadre, "", 0, 'R', 1); + $pdf->SetTextColor(0,0,60); + + // Show sender name + $pdf->SetXY($posx+2,$posy+3); + $pdf->SetFont('','B', $default_font_size); + $pdf->MultiCell(80, 4, $outputlangs->convToOutputCharset($this->emetteur->name), 0, 'L'); + $posy=$pdf->getY(); + + // Show sender information + $pdf->SetXY($posx+2,$posy); + $pdf->SetFont('','', $default_font_size - 1); + $pdf->MultiCell(80, 4, $carac_emetteur, 0, 'L'); + + + // If CUSTOMER contact defined, we use it + $usecontact=false; + $arrayidcontact=$object->getIdContact('external','CUSTOMER'); + if (count($arrayidcontact) > 0) + { + $usecontact=true; + $result=$object->fetch_contact($arrayidcontact[0]); + } + + // Recipient name + if (! empty($usecontact)) + { + // On peut utiliser le nom de la societe du contact + if (! empty($conf->global->MAIN_USE_COMPANY_NAME_OF_CONTACT)) $socname = $object->contact->socname; + else $socname = $object->client->name; + $carac_client_name=$outputlangs->convToOutputCharset($socname); + } + else + { + $carac_client_name=$outputlangs->convToOutputCharset($object->client->name); + } + + $carac_client=pdf_build_address($outputlangs,$this->emetteur,$object->client,($usecontact?$object->contact:''),$usecontact,'target'); + + // Show recipient + $widthrecbox=100; + if ($this->page_largeur < 210) $widthrecbox=84; // To work with US executive format + $posy=42; + $posx=$this->page_largeur-$this->marge_droite-$widthrecbox; + if (! empty($conf->global->MAIN_INVERT_SENDER_RECIPIENT)) $posx=$this->marge_gauche; + + // Show recipient frame + $pdf->SetTextColor(0,0,0); + $pdf->SetFont('','', $default_font_size - 2); + $pdf->SetXY($posx+2,$posy-5); + $pdf->MultiCell($widthrecbox, 5, $outputlangs->transnoentities("BillTo").":", 0, 'L'); + $pdf->Rect($posx, $posy, $widthrecbox, $hautcadre); + + // Show recipient name + $pdf->SetXY($posx+2,$posy+3); + $pdf->SetFont('','B', $default_font_size); + $pdf->MultiCell($widthrecbox, 4, $carac_client_name, 0, 'L'); + + // Show recipient information + $pdf->SetFont('','', $default_font_size - 1); + $pdf->SetXY($posx+2,$posy+4+(dol_nboflines_bis($carac_client_name,50)*4)); + $pdf->MultiCell($widthrecbox, 4, $carac_client, 0, 'L'); + } + + $pdf->SetTextColor(0,0,0); + } + + /** + * Show footer of page. Need this->emetteur object + * + * @param PDF $pdf PDF + * @param Object $object Object to show + * @param Translate $outputlangs Object lang for output + * @param int $hidefreetext 1=Hide free text + * @return int Return height of bottom margin including footer text + */ + function _pagefoot(&$pdf,$object,$outputlangs,$hidefreetext=0) + { + $showdetails=0; + return pdf_pagefoot($pdf,$outputlangs,'ASKPRICESUPPLIER_FREE_TEXT',$this->emetteur,$this->marge_basse,$this->marge_gauche,$this->page_hauteur,$object,$showdetails,$hidefreetext); + } + +} + diff --git a/htdocs/core/modules/askpricesupplier/index.html b/htdocs/core/modules/askpricesupplier/index.html new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/htdocs/core/modules/askpricesupplier/mod_askpricesupplier_marbre.php b/htdocs/core/modules/askpricesupplier/mod_askpricesupplier_marbre.php new file mode 100644 index 0000000000000000000000000000000000000000..d1912b98a9a1e2d3c8d9d5ace8468b83ccad4491 --- /dev/null +++ b/htdocs/core/modules/askpricesupplier/mod_askpricesupplier_marbre.php @@ -0,0 +1,153 @@ +<?php +/* Copyright (C) 2005-2008 Laurent Destailleur <eldy@users.sourceforge.net> + * Copyright (C) 2005-2012 Regis Houssin <regis.houssin@capnetworks.com> + * + * 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 <http://www.gnu.org/licenses/>. + * or see http://www.gnu.org/ + */ + +/** + * \file htdocs/core/modules/propale/mod_propale_marbre.php + * \ingroup propale + * \brief File of class to manage commercial proposal numbering rules Marbre + */ + +require_once DOL_DOCUMENT_ROOT .'/core/modules/askpricesupplier/modules_askpricesupplier.php'; + + +/** + * Class to manage customer order numbering rules Marbre + */ +class mod_askpricesupplier_marbre extends ModeleNumRefAskPriceSupplier +{ + var $version='dolibarr'; // 'development', 'experimental', 'dolibarr' + var $prefix='DF'; + var $error=''; + var $nom = "Marbre"; + + + /** + * Return description of numbering module + * + * @return string Text with description + */ + function info() + { + global $langs; + return $langs->trans("SimpleNumRefModelDesc",$this->prefix); + } + + + /** + * Return an example of numbering module values + * + * @return string Example + */ + function getExample() + { + return $this->prefix."0501-0001"; + } + + + /** + * Test si les numeros deje en vigueur dans la base ne provoquent pas de + * de conflits qui empechera cette numerotation de fonctionner. + * + * @return boolean false si conflit, true si ok + */ + function canBeActivated() + { + global $conf,$langs,$db; + + $pryymm=''; $max=''; + + $posindice=8; + $sql = "SELECT MAX(CAST(SUBSTRING(ref FROM ".$posindice.") AS SIGNED)) as max"; + $sql.= " FROM ".MAIN_DB_PREFIX."askpricesupplier"; + $sql.= " WHERE ref LIKE '".$this->prefix."____-%'"; + $sql.= " AND entity = ".$conf->entity; + + $resql=$db->query($sql); + if ($resql) + { + $row = $db->fetch_row($resql); + if ($row) { $pryymm = substr($row[0],0,6); $max=$row[0]; } + } + + if (! $pryymm || preg_match('/'.$this->prefix.'[0-9][0-9][0-9][0-9]/i',$pryymm)) + { + return true; + } + else + { + $langs->load("errors"); + $this->error=$langs->trans('ErrorNumRefModel',$max); + return false; + } + } + + /** + * Return next value + * + * @param Societe $objsoc Object third party + * @param Propal $askpricesupplier Object commercial proposal + * @return string Next value + */ + function getNextValue($objsoc,$askpricesupplier) + { + global $db,$conf; + + // D'abord on recupere la valeur max + $posindice=8; + $sql = "SELECT MAX(CAST(SUBSTRING(ref FROM ".$posindice.") AS SIGNED)) as max"; // This is standard SQL + $sql.= " FROM ".MAIN_DB_PREFIX."askpricesupplier"; + $sql.= " WHERE ref LIKE '".$this->prefix."____-%'"; + $sql.= " AND entity = ".$conf->entity; + + $resql=$db->query($sql); + if ($resql) + { + $obj = $db->fetch_object($resql); + if ($obj) $max = intval($obj->max); + else $max=0; + } + else + { + dol_syslog(get_class($this)."::getNextValue", LOG_DEBUG); + return -1; + } + + $date = time(); + $yymm = strftime("%y%m",$date); + + if ($max >= (pow(10, 4) - 1)) $num=$max+1; // If counter > 9999, we do not format on 4 chars, we take number as it is + else $num = sprintf("%04s",$max+1); + + dol_syslog(get_class($this)."::getNextValue return ".$this->prefix.$yymm."-".$num); + return $this->prefix.$yymm."-".$num; + } + + /** + * Return next free value + * + * @param Societe $objsoc Object third party + * @param Object $objforref Object for number to search + * @return string Next free value + */ + function getNumRef($objsoc,$objforref) + { + return $this->getNextValue($objsoc,$objforref); + } + +} diff --git a/htdocs/core/modules/askpricesupplier/mod_askpricesupplier_saphir.php b/htdocs/core/modules/askpricesupplier/mod_askpricesupplier_saphir.php new file mode 100644 index 0000000000000000000000000000000000000000..22582308f22f3200383fe9d4f635f0fab5f1ae4c --- /dev/null +++ b/htdocs/core/modules/askpricesupplier/mod_askpricesupplier_saphir.php @@ -0,0 +1,131 @@ +<?php +/* Copyright (C) 2003-2007 Rodolphe Quiedeville <rodolphe@quiedeville.org> + * Copyright (C) 2004-2010 Laurent Destailleur <eldy@users.sourceforge.net> + * Copyright (C) 2005-2007 Regis Houssin <regis.houssin@capnetworks.com> + * Copyright (C) 2008 Raphael Bertrand (Resultic) <raphael.bertrand@resultic.fr> + * + * 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 <http://www.gnu.org/licenses/>. + * or see http://www.gnu.org/ + */ + +/** + * \file htdocs/core/modules/propale/mod_propale_saphir.php + * \ingroup propale + * \brief File that contains the numbering module rules Saphir + */ + +require_once DOL_DOCUMENT_ROOT .'/core/modules/askpricesupplier/modules_askpricesupplier.php'; + + +/** + * Class of file that contains the numbering module rules Saphir + */ +class mod_askpricesupplier_saphir extends ModeleNumRefAskPriceSupplier +{ + var $version='dolibarr'; // 'development', 'experimental', 'dolibarr' + var $error = ''; + var $nom = 'Saphir'; + + + /** + * Return description of module + * + * @return string Texte descripif + */ + function info() + { + global $conf,$langs; + + $langs->load("bills"); + + $form = new Form($this->db); + + $texte = $langs->trans('GenericNumRefModelDesc')."<br>\n"; + $texte.= '<form action="'.$_SERVER["PHP_SELF"].'" method="POST">'; + $texte.= '<input type="hidden" name="token" value="'.$_SESSION['newtoken'].'">'; + $texte.= '<input type="hidden" name="action" value="updateMask">'; + $texte.= '<input type="hidden" name="maskconstaskpricesupplier" value="ASKPRICESUPPLIER_SAPHIR_MASK">'; + $texte.= '<table class="nobordernopadding" width="100%">'; + + $tooltip=$langs->trans("GenericMaskCodes",$langs->transnoentities("CommRequest"),$langs->transnoentities("CommRequest")); + $tooltip.=$langs->trans("GenericMaskCodes2"); + $tooltip.=$langs->trans("GenericMaskCodes3"); + $tooltip.=$langs->trans("GenericMaskCodes4a",$langs->transnoentities("CommRequest"),$langs->transnoentities("CommRequest")); + $tooltip.=$langs->trans("GenericMaskCodes5"); + + // Parametrage du prefix + $texte.= '<tr><td>'.$langs->trans("Mask").':</td>'; + $texte.= '<td align="right">'.$form->textwithpicto('<input type="text" class="flat" size="24" name="maskaskpricesupplier" value="'.$conf->global->ASKPRICESUPPLIER_SAPHIR_MASK.'">',$tooltip,1,1).'</td>'; + + $texte.= '<td align="left" rowspan="2"> <input type="submit" class="button" value="'.$langs->trans("Modify").'" name="Button"></td>'; + + $texte.= '</tr>'; + + $texte.= '</table>'; + $texte.= '</form>'; + + return $texte; + } + + /** + * Renvoi un exemple de numerotation + * + * @return string Example + */ + function getExample() + { + global $conf,$langs,$mysoc; + + $old_code_client=$mysoc->code_client; + $mysoc->code_client='CCCCCCCCCC'; + $numExample = $this->getNextValue($mysoc,''); + $mysoc->code_client=$old_code_client; + + if (! $numExample) + { + $numExample = 'NotConfigured'; + } + return $numExample; + } + + /** + * Return next value + * + * @param Societe $objsoc Object third party + * @param Propal $askpricesupplier Object askpricesupplier + * @return string Value if OK, 0 if KO + */ + function getNextValue($objsoc,$askpricesupplier) + { + global $db,$conf; + + require_once DOL_DOCUMENT_ROOT .'/core/lib/functions2.lib.php'; + + // On defini critere recherche compteur + $mask=$conf->global->ASKPRICESUPPLIER_SAPHIR_MASK; + + if (! $mask) + { + $this->error='NotConfigured'; + return 0; + } + + $date=$askpricesupplier->datep; + $customercode=$objsoc->code_client; + $numFinal=get_next_value($db,$mask,'askpricesupplier','ref','',$customercode,$date); + + return $numFinal; + } + +} diff --git a/htdocs/core/modules/askpricesupplier/modules_askpricesupplier.php b/htdocs/core/modules/askpricesupplier/modules_askpricesupplier.php new file mode 100644 index 0000000000000000000000000000000000000000..1b0095308c88f962468a0fee758a8cca8dad01a8 --- /dev/null +++ b/htdocs/core/modules/askpricesupplier/modules_askpricesupplier.php @@ -0,0 +1,165 @@ +<?php +/* Copyright (C) 2003 Rodolphe Quiedeville <rodolphe@quiedeville.org> + * Copyright (C) 2004-2012 Laurent Destailleur <eldy@users.sourceforge.net> + * Copyright (C) 2005-2012 Regis Houssin <regis.houssin@capnetworks.com> + * Copyright (C) 2012 Juanjo Menent <jmenent@2byte.es> + * Copyright (C) 2014 Marcos García <marcosgdf@gmail.com> + * + * 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 <http://www.gnu.org/licenses/>. + * or see http://www.gnu.org/ + */ + +/** + * \file htdocs/core/modules/propale/modules_propale.php + * \ingroup propale + * \brief Fichier contenant la classe mere de generation des propales en PDF + * et la classe mere de numerotation des propales + */ + +require_once DOL_DOCUMENT_ROOT.'/core/class/commondocgenerator.class.php'; +require_once DOL_DOCUMENT_ROOT.'/compta/bank/class/account.class.php'; // Requis car utilise dans les classes qui heritent + + +/** + * Classe mere des modeles de propale + */ +abstract class ModelePDFAskPriceSupplier extends CommonDocGenerator +{ + var $error=''; + + + /** + * Return list of active generation modules + * + * @param DoliDB $db Database handler + * @param string $maxfilenamelength Max length of value to show + * @return array List of templates + */ + static function liste_modeles($db,$maxfilenamelength=0) + { + global $conf; + + $type='askpricesupplier'; + $liste=array(); + + include_once DOL_DOCUMENT_ROOT.'/core/lib/functions2.lib.php'; + $liste=getListOfModels($db,$type,$maxfilenamelength); + + return $liste; + } +} + + +/** + * Classe mere des modeles de numerotation des references de propales + */ +abstract class ModeleNumRefAskPriceSupplier +{ + var $error=''; + + /** + * Return if a module can be used or not + * + * @return boolean true if module can be used + */ + function isEnabled() + { + return true; + } + + /** + * Renvoi la description par defaut du modele de numerotation + * + * @return string Texte descripif + */ + function info() + { + global $langs; + $langs->load("askpricesupplier"); + return $langs->trans("NoDescription"); + } + + /** + * Renvoi un exemple de numerotation + * + * @return string Example + */ + function getExample() + { + global $langs; + $langs->load("askpricesupplier"); + return $langs->trans("NoExample"); + } + + /** + * Test si les numeros deja en vigueur dans la base ne provoquent pas de + * de conflits qui empechera cette numerotation de fonctionner. + * + * @return boolean false si conflit, true si ok + */ + function canBeActivated() + { + return true; + } + + /** + * Renvoi prochaine valeur attribuee + * + * @param Societe $objsoc Object third party + * @param Propal $propal Object commercial proposal + * @return string Valeur + */ + function getNextValue($objsoc,$propal) + { + global $langs; + return $langs->trans("NotAvailable"); + } + + /** + * Renvoi version du module numerotation + * + * @return string Valeur + */ + function getVersion() + { + global $langs; + $langs->load("admin"); + + if ($this->version == 'development') return $langs->trans("VersionDevelopment"); + if ($this->version == 'experimental') return $langs->trans("VersionExperimental"); + if ($this->version == 'dolibarr') return DOL_VERSION; + if ($this->version) return $this->version; + return $langs->trans("NotAvailable"); + } +} + + +/** + * Create a document onto disk according to template module. + * + * @param DoliDB $db Database handler + * @param object $object Object askpricesupplier + * @param string $modele Force model to use ('' to not force) + * @param Translate $outputlangs Object langs to use for output + * @param int $hidedetails Hide details of lines + * @param int $hidedesc Hide description + * @param int $hideref Hide ref + * @return int 0 if KO, 1 if OK + * @deprecated Use the new function generateDocument of Propal class + */ +function askpricesupplier_pdf_create(DoliDB $db, AskPriceSupplier $object, $modele, $outputlangs, $hidedetails=0, $hidedesc=0, $hideref=0) +{ + return $object->generateDocument($modele, $outputlangs, $hidedetails, $hidedesc, $hideref); +} + diff --git a/htdocs/core/modules/modAskPriceSupplier.class.php b/htdocs/core/modules/modAskPriceSupplier.class.php new file mode 100644 index 0000000000000000000000000000000000000000..f64126e224e25f3c13c35a9e99310b98c59c9c18 --- /dev/null +++ b/htdocs/core/modules/modAskPriceSupplier.class.php @@ -0,0 +1,238 @@ +<?php +/* Copyright (C) 2003-2004 Rodolphe Quiedeville <rodolphe@quiedeville.org> + * Copyright (C) 2004-2010 Laurent Destailleur <eldy@users.sourceforge.net> + * Copyright (C) 2004 Sebastien Di Cintio <sdicintio@ressource-toi.org> + * Copyright (C) 2004 Benoit Mortier <benoit.mortier@opensides.be> + * Copyright (C) 2005-2012 Regis Houssin <regis.houssin@capnetworks.com> + * Copyright (C) 2012 Juanjo Menent <jmenent@2byte.es> + * + * 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 <http://www.gnu.org/licenses/>. + */ + +/** + * \defgroup askpricesupplier Module de demandes de prix fournisseurs + * \brief Module pour gerer la tenue des demandes fournisseurs + * \file htdocs/core/modules/modAskPriceSupplier.class.php + * \ingroup askpricesupplier + * \brief Fichier de description et activation du module AskPriceSupplier + */ +include_once DOL_DOCUMENT_ROOT .'/core/modules/DolibarrModules.class.php'; + + +/** + * Classe de description et activation du module AskPriceSupllier + */ +class modAskPriceSupplier extends DolibarrModules +{ + + /** + * Constructor. Define names, constants, directories, boxes, permissions + * + * @param DoliDB $db Database handler + */ + function __construct($db) + { + global $conf; + + $this->db = $db; + $this->numero = 1120; + + $this->family = "products"; + $this->name = preg_replace('/^mod/i','',get_class($this)); + $this->description = "askpricesupplierDESC"; + + $this->version = 'experimental'; + + $this->const_name = 'MAIN_MODULE_'.strtoupper($this->name); + $this->special = 0; + $this->picto='askpricesupplier'; + + $this->dirs = array(); + + // Dependancies + $this->depends = array('modFournisseur'); + $this->requiredby = array(); + $this->config_page_url = array("askpricesupplier.php"); + $this->langfiles = array("askpricesupplier"); + + // Constants + $this->const = array(); + $r=0; + + $this->const[$r][0] = "ASKPRICESUPPLIER_ADDON_PDF"; + $this->const[$r][1] = "chaine"; + $this->const[$r][2] = "aurore"; + $this->const[$r][3] = 'Name of submodule to generate PDF for supplier quotation request'; + $this->const[$r][4] = 0; + $r++; + + $this->const[$r][0] = "ASKPRICESUPPLIER_ADDON"; + $this->const[$r][1] = "chaine"; + $this->const[$r][2] = "mod_askpricesupplier_marbre"; + $this->const[$r][3] = 'Name of submodule to number supplier quotation request'; + $this->const[$r][4] = 0; + $r++; + + $this->const[$r][0] = "ASKPRICESUPPLIER_ADDON_PDF_ODT_PATH"; + $this->const[$r][1] = "chaine"; + $this->const[$r][2] = "DOL_DATA_ROOT/doctemplates/askpricesupplier"; + $this->const[$r][3] = ""; + $this->const[$r][4] = 0; + + // Boxes + $this->boxes = array(); + + // Permissions + $this->rights = array(); + $this->rights_class = 'askpricesupplier'; + $r=0; + + $r++; + $this->rights[$r][0] = $this->numero + $r; // id de la permission + $this->rights[$r][1] = 'Read supplier proposals'; // libelle de la permission + $this->rights[$r][3] = 1; // La permission est-elle une permission par defaut + $this->rights[$r][4] = 'lire'; + + $r++; + $this->rights[$r][0] = $this->numero + $r; // id de la permission + $this->rights[$r][1] = 'Create/modify supplier proposals'; // libelle de la permission + $this->rights[$r][3] = 1; // La permission est-elle une permission par defaut + $this->rights[$r][4] = 'creer'; + + + $r++; + $this->rights[$r][0] = $this->numero + $r; // id de la permission + $this->rights[$r][1] = 'Validate supplier proposals'; // libelle de la permission + $this->rights[$r][3] = 0; // La permission est-elle une permission par defaut + $this->rights[$r][4] = ''; + $this->rights[$r][5] = 'validate'; + + $r++; + $this->rights[$r][0] = $this->numero + $r; // id de la permission + $this->rights[$r][1] = 'Envoyer les demandes fournisseurs'; // libelle de la permission + $this->rights[$r][3] = 0; // La permission est-elle une permission par defaut + $this->rights[$r][4] = ''; + $this->rights[$r][5] = 'send_advance'; + + $r++; + $this->rights[$r][0] = $this->numero + $r; // id de la permission + $this->rights[$r][1] = 'Delete supplier proposals'; // libelle de la permission + $this->rights[$r][3] = 0; // La permission est-elle une permission par defaut + $this->rights[$r][4] = 'supprimer'; + + $r++; + $this->rights[$r][0] = $this->numero + $r; // id de la permission + $this->rights[$r][1] = 'Close supplier price requests'; // libelle de la permission + $this->rights[$r][3] = 0; // La permission est-elle une permission par defaut + $this->rights[$r][4] = 'cloturer'; + + // Main menu entries + $this->menu = array(); // List of menus to add + $r=0; + $this->menu[$r]=array( + 'fk_menu'=>'fk_mainmenu=commercial', // Use 'fk_mainmenu=xxx' or 'fk_mainmenu=xxx,fk_leftmenu=yyy' where xxx is mainmenucode and yyy is a leftmenucode + 'type'=>'left', // This is a Left menu entry + 'titre'=>'askpricesupplierMENU_LEFT_TITLE', + 'leftmenu'=>'askpricesuppliersubmenu', + 'url'=>'/comm/askpricesupplier/index.php', + 'langs'=>'askpricesupplier', // Lang file to use (without .lang) by module. File must be in langs/code_CODE/ directory. + 'enabled'=>'$conf->askpricesupplier->enabled', // Define condition to show or hide menu entry. Use '$conf->mymodule->enabled' if entry must be visible if module is enabled. Use '$leftmenu==\'system\'' to show if leftmenu system is selected. + 'perms'=>'$user->rights->askpricesupplier->lire', // Use 'perms'=>'$user->rights->mymodule->level1->level2' if you want your menu with a permission rules + 'user'=>2 // 0=Menu for internal users, 1=external users, 2=both + ); + $r++; + + $this->menu[$r]=array( + 'fk_menu'=>'fk_mainmenu=commercial,fk_leftmenu=askpricesuppliersubmenu', + 'type'=>'left', + 'titre'=>'askpricesupplierMENU_LEFT_TITLE_NEW', + 'url'=>'/comm/askpricesupplier/card.php?action=create', + 'langs'=>'askpricesupplier', + 'enabled'=>'$conf->askpricesupplier->enabled', + 'perms'=>'$user->rights->askpricesupplier->creer', + 'user'=>2 + ); + $r++; + + $this->menu[$r]=array( + 'fk_menu'=>'fk_mainmenu=commercial,fk_leftmenu=askpricesuppliersubmenu', + 'type'=>'left', + 'titre'=>'askpricesupplierMENU_LEFT_TITLE_LIST', + 'url'=>'/comm/askpricesupplier/list.php', + 'langs'=>'askpricesupplier', + 'enabled'=>'$conf->askpricesupplier->enabled', + 'perms'=>'$user->rights->askpricesupplier->lire', + 'user'=>2 + ); + $r++; + } + + + /** + * Function called when module is enabled. + * The init function add constants, boxes, permissions and menus (defined in constructor) into Dolibarr database. + * It also creates data directories + * + * @param string $options Options when enabling module ('', 'noboxes') + * @return int 1 if OK, 0 if KO + */ + function init($options='') + { + global $conf,$langs; + + // Remove permissions and default values + $this->remove($options); + + //ODT template + $src=DOL_DOCUMENT_ROOT.'/install/doctemplates/askpricesupplier/template_askpricesupplier.odt'; + $dirodt=DOL_DATA_ROOT.'/doctemplates/askpricesupplier'; + $dest=$dirodt.'/template_askpricesupplier.odt'; + + if (file_exists($src) && ! file_exists($dest)) + { + require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php'; + dol_mkdir($dirodt); + $result=dol_copy($src,$dest,0,0); + if ($result < 0) + { + $langs->load("errors"); + $this->error=$langs->trans('ErrorFailToCopyFile',$src,$dest); + return 0; + } + } + + $sql = array( + "DELETE FROM ".MAIN_DB_PREFIX."document_model WHERE nom = '".$this->const[0][2]."' AND entity = ".$conf->entity, + "INSERT INTO ".MAIN_DB_PREFIX."document_model (nom, type, entity) VALUES('".$this->const[0][2]."','askpricesupplier',".$conf->entity.")", + ); + + return $this->_init($sql, $options); + } + + /** + * Function called when module is disabled. + * Remove from database constants, boxes and permissions from Dolibarr database. + * Data directories are not deleted + * + * @param string $options Options when enabling module ('', 'noboxes') + * @return int 1 if OK, 0 if KO + */ + function remove($options='') + { + $sql = array(); + + return $this->_remove($sql,$options); + } + +} \ No newline at end of file diff --git a/htdocs/core/tpl/document_actions_post_headers.tpl.php b/htdocs/core/tpl/document_actions_post_headers.tpl.php index abd42296cdeab989c3acb85c410a5935e75f695b..c7d5dc2c0834a9620467bbf2c43f4c4656f931de 100644 --- a/htdocs/core/tpl/document_actions_post_headers.tpl.php +++ b/htdocs/core/tpl/document_actions_post_headers.tpl.php @@ -47,7 +47,7 @@ $savingdocmask=''; if (empty($conf->global->MAIN_DISABLE_SUGGEST_REF_AS_PREFIX)) { //var_dump($modulepart); - if (in_array($modulepart,array('facture_fournisseur','commande_fournisseur','facture','commande','propal','ficheinter','contract','project','project_task','expensereport'))) + if (in_array($modulepart,array('facture_fournisseur','commande_fournisseur','facture','commande','propal','askpricesupplier','ficheinter','contract','project','project_task','expensereport'))) { $savingdocmask=$object->ref.'___file__'; } diff --git a/htdocs/core/tpl/notes.tpl.php b/htdocs/core/tpl/notes.tpl.php index 66b310da69d8887d40f632737fc8402558517ad1..5773d7ce9d872c9e43b8ab7132f471ec97969269 100644 --- a/htdocs/core/tpl/notes.tpl.php +++ b/htdocs/core/tpl/notes.tpl.php @@ -50,6 +50,7 @@ if (! empty($conf->global->MAIN_AUTO_TIMESTAMP_IN_PRIVATE_NOTES)) // Special cases if ($module == 'propal') { $permission=$user->rights->propale->creer;} +elseif ($module == 'askpricesupplier') { $permission=$user->rights->askpricesupplier->creer;} elseif ($module == 'fichinter') { $permission=$user->rights->ficheinter->creer;} elseif ($module == 'project') { $permission=$user->rights->projet->creer;} elseif ($module == 'project_task') { $permission=$user->rights->projet->creer;} diff --git a/htdocs/core/tpl/objectline_create.tpl.php b/htdocs/core/tpl/objectline_create.tpl.php index 8a98ac2f6130674804678dce6e6a29543b49b118..a72ceb658d13ba9759a6799564a9442853b98aba 100644 --- a/htdocs/core/tpl/objectline_create.tpl.php +++ b/htdocs/core/tpl/objectline_create.tpl.php @@ -31,7 +31,7 @@ $usemargins=0; -if (! empty($conf->margin->enabled) && ! empty($object->element) && in_array($object->element,array('facture','propal','commande'))) $usemargins=1; +if (! empty($conf->margin->enabled) && ! empty($object->element) && in_array($object->element,array('facture','propal', 'askpricesupplier','commande'))) $usemargins=1; global $forceall, $senderissupplier, $inputalsopricewithtax; if (empty($dateSelector)) $dateSelector=0; @@ -43,7 +43,7 @@ if (empty($inputalsopricewithtax)) $inputalsopricewithtax=0; // Define colspan for button Add $colspan = 3; // Col total ht + col edit + col delete if (! empty($inputalsopricewithtax)) $colspan++; // We add 1 if col total ttc -if (in_array($object->element,array('propal','facture','invoice','commande','order'))) $colspan++; // With this, there is a column move button +if (in_array($object->element,array('propal', 'askpricesupplier','facture','invoice','commande','order'))) $colspan++; // With this, there is a column move button ?> <!-- BEGIN PHP TEMPLATE objectline_create.tpl.php --> @@ -52,6 +52,9 @@ if (in_array($object->element,array('propal','facture','invoice','commande','ord <td<?php echo (! empty($conf->global->MAIN_VIEW_LINE_NUMBER) ? ' colspan="2"' : ''); ?>> <div id="add"></div><span class="hideonsmartphone"><?php echo $langs->trans('AddNewLine'); ?></span><?php // echo $langs->trans("FreeZone"); ?> </td> + <?php if ($object->element == 'askpricesupplier') { ?> + <td align="right"><span id="title_fourn_ref"><?php echo $langs->trans('AskPriceSupplierRefFourn'); ?></span></td> + <?php } ?> <td align="right"><span id="title_vat"><?php echo $langs->trans('VAT'); ?></span></td> <td align="right"><span id="title_up_ht"><?php echo $langs->trans('PriceUHT'); ?></span></td> <?php if (! empty($inputalsopricewithtax)) { ?> @@ -195,7 +198,11 @@ else { $doleditor->Create(); ?> </td> - + + <?php if ($object->element == 'askpricesupplier') { ?> + <td align="right"><input id="fourn_ref" name="fourn_ref" class="flat" value="" size="12"></td> + <?php } ?> + <td align="right"><?php if (GETPOST('prod_entry_mode') != 'predef') { @@ -211,7 +218,7 @@ else { </td> <?php if (! empty($inputalsopricewithtax)) { ?> <td align="right"> - <?php if (GETPOST('prod_entry_mode') != 'predef') { ?> + <?php if ($object->element == 'askpricesupplier' || GETPOST('prod_entry_mode') != 'predef') { ?> <input type="text" size="5" name="price_ttc" id="price_ttc" class="flat" value="<?php echo (isset($_POST["price_ttc"])?$_POST["price_ttc"]:''); ?>"> <?php } ?> </td> @@ -271,6 +278,9 @@ else { elseif ($this->table_element_line=='propaldet') { $newline = new PropaleLigne($this->db); } + elseif ($this->table_element_line=='askpricesupplierdet') { + $newline = new AskPriceSupplierLigne($this->db); + } elseif ($this->table_element_line=='facturedet') { $newline = new FactureLigne($this->db); } @@ -297,7 +307,7 @@ if (! empty($conf->service->enabled) && $dateSelector && GETPOST('type') != '0') else $colspan = 9; if($this->situation_cycle_ref) $colspan++; if (! empty($inputalsopricewithtax)) $colspan++; // We add 1 if col total ttc - if (in_array($object->element,array('propal','facture','invoice','commande','order'))) $colspan++; // With this, there is a column move button + if (in_array($object->element,array('propal', 'askpricesupplier','facture','invoice','commande','order'))) $colspan++; // With this, there is a column move button if (! empty($usemargins)) { @@ -572,12 +582,14 @@ function setforpredef() { jQuery("#select_type").val(-1); jQuery("#prod_entry_mode_free").attr('checked',false); jQuery("#prod_entry_mode_predef").attr('checked',true); - jQuery("#price_ht").hide(); + <?php if ($object->element != 'askpricesupplier') { ?> + jQuery("#price_ht").hide(); + jQuery("#title_up_ht").hide(); + <?php } ?> jQuery("#price_ttc").hide(); // May no exists jQuery("#tva_tx").hide(); jQuery("#buying_price").show(); jQuery("#title_vat").hide(); - jQuery("#title_up_ht").hide(); jQuery("#title_up_ttc").hide(); jQuery("#np_marginRate").hide(); // May no exists jQuery("#np_markRate").hide(); // May no exists diff --git a/htdocs/core/tpl/objectline_edit.tpl.php b/htdocs/core/tpl/objectline_edit.tpl.php index 98f1b842f1acc8834d570b6ad3047d5a45411760..0969d128504771bb31429eac86877f65b597e226 100644 --- a/htdocs/core/tpl/objectline_edit.tpl.php +++ b/htdocs/core/tpl/objectline_edit.tpl.php @@ -31,7 +31,7 @@ $usemargins=0; -if (! empty($conf->margin->enabled) && ! empty($object->element) && in_array($object->element,array('facture','propal','commande'))) $usemargins=1; +if (! empty($conf->margin->enabled) && ! empty($object->element) && in_array($object->element,array('facture','propal', 'askpricesupplier','commande'))) $usemargins=1; global $forceall, $senderissupplier, $inputalsopricewithtax; if (empty($dateSelector)) $dateSelector=0; @@ -43,7 +43,7 @@ if (empty($inputalsopricewithtax)) $inputalsopricewithtax=0; // Define colspan for button Add $colspan = 3; // Col total ht + col edit + col delete if (! empty($inputalsopricewithtax)) $colspan++; // We add 1 if col total ttc -if (in_array($object->element,array('propal','facture','invoice','commande','order','order_supplier','invoice_supplier'))) $colspan++; // With this, there is a column move button +if (in_array($object->element,array('propal','askpricesupplier','facture','invoice','commande','order','order_supplier','invoice_supplier'))) $colspan++; // With this, there is a column move button ?> <!-- BEGIN PHP TEMPLATE objectline_edit.tpl.php --> @@ -100,6 +100,10 @@ $coldisplay=-1; // We remove first td ?> </td> + <?php if ($object->element == 'askpricesupplier') { ?> + <td align="right"><input id="fourn_ref" name="fourn_ref" class="flat" value="<?php echo $line->ref_fourn; ?>" size="12"></td> + <?php } ?> + <?php $coldisplay++; if ($this->situation_counter == 1 || !$this->situation_cycle_ref) { diff --git a/htdocs/core/tpl/objectline_view.tpl.php b/htdocs/core/tpl/objectline_view.tpl.php index 0664d471decb2fe9fdebac561be742b5c136ea8b..79652c9c5c4cac89cf703824bfd7ec7258db1ce8 100644 --- a/htdocs/core/tpl/objectline_view.tpl.php +++ b/htdocs/core/tpl/objectline_view.tpl.php @@ -35,6 +35,10 @@ */ global $forceall, $senderissupplier, $inputalsopricewithtax, $usemargins; + +$usemargins=0; +if (! empty($conf->margin->enabled) && ! empty($object->element) && in_array($object->element,array('facture','propal', 'askpricesupplier','commande'))) $usemargins=1; + if (empty($dateSelector)) $dateSelector=0; if (empty($forceall)) $forceall=0; if (empty($senderissupplier)) $senderissupplier=0; @@ -119,7 +123,9 @@ if (empty($usemargins)) $usemargins=0; } ?> </td> - + <?php if ($object->element == 'askpricesupplier') { ?> + <td align="right"><?php echo $line->ref_fourn; ?></td> + <?php } ?> <td align="right" class="nowrap"><?php $coldisplay++; ?><?php echo vatrate($line->tva_tx,'%',$line->info_bits); ?></td> <td align="right" class="nowrap"><?php $coldisplay++; ?><?php echo (isset($line->pu_ht)?price($line->pu_ht):price($line->subprice)); ?></td> diff --git a/htdocs/core/triggers/interface_90_all_Demo.class.php-NORUN b/htdocs/core/triggers/interface_90_all_Demo.class.php-NORUN index d3abf17501df62b5ebb282af1676777a7b4f39ab..c50a4afcc0166bad6dd2fbb36c2ed4c802203f8a 100644 --- a/htdocs/core/triggers/interface_90_all_Demo.class.php-NORUN +++ b/htdocs/core/triggers/interface_90_all_Demo.class.php-NORUN @@ -151,6 +151,19 @@ class InterfaceDemo extends DolibarrTriggers case 'LINEPROPAL_UPDATE': case 'LINEPROPAL_DELETE': + // Askpricesupplier + case 'ASKPRICESUPPLIER_CREATE': + case 'ASKPRICESUPPLIER_CLONE': + case 'ASKPRICESUPPLIER_MODIFY': + case 'ASKPRICESUPPLIER_VALIDATE': + case 'ASKPRICESUPPLIER_SENTBYMAIL': + case 'ASKPRICESUPPLIER_CLOSE_SIGNED': + case 'ASKPRICESUPPLIER_CLOSE_REFUSED': + case 'ASKPRICESUPPLIER_DELETE': + case 'LINEASKPRICESUPPLIER_INSERT': + case 'LINEASKPRICESUPPLIER_UPDATE': + case 'LINEASKPRICESUPPLIER_DELETE': + // Contracts case 'CONTRACT_CREATE': case 'CONTRACT_ACTIVATE': diff --git a/htdocs/fourn/card.php b/htdocs/fourn/card.php index 3f0636e324ab46be182932444d504f9e1ace8cb5..df2f09cc3e3643cd4c611d2ec827cae7a2d74e0a 100644 --- a/htdocs/fourn/card.php +++ b/htdocs/fourn/card.php @@ -499,6 +499,12 @@ if ($object->id > 0) print '<a class="butAction" href="'.DOL_URL_ROOT.'/fourn/facture/card.php?action=create&socid='.$object->id.'">'.$langs->trans("AddBill").'</a>'; } + if ($conf->askpricesupplier->enabled && $user->rights->askpricesupplier->creer) + { + $langs->load("askpricesupplier"); + print '<a class="butAction" href="'.DOL_URL_ROOT.'/comm/askpricesupplier/card.php?action=create&socid='.$object->id.'">'.$langs->trans("AddAskPriceSupplier").'</a>'; + } + if ($user->rights->fournisseur->facture->creer) { if (! empty($orders2invoice) && $orders2invoice > 0) print '<div class="inline-block divButAction"><a class="butAction" href="'.DOL_URL_ROOT.'/fourn/commande/orderstoinvoice.php?socid='.$object->id.'">'.$langs->trans("CreateInvoiceForThisCustomer").'</a></div>'; diff --git a/htdocs/fourn/class/fournisseur.commande.class.php b/htdocs/fourn/class/fournisseur.commande.class.php index e626760f83ec81c64f4320362016f52dcc230f4a..b8c709d7d0314820fb915f44fc0aa9ecc94233b7 100644 --- a/htdocs/fourn/class/fournisseur.commande.class.php +++ b/htdocs/fourn/class/fournisseur.commande.class.php @@ -88,6 +88,11 @@ class CommandeFournisseur extends CommonOrder var $extraparams=array(); + //Ajout pour askpricesupplier + var $origin; + var $origin_id; + var $linked_objects=array(); + var $lines = array(); /** * Constructor @@ -984,30 +989,27 @@ class CommandeFournisseur extends CommonOrder // Add entry into log $this->log($user, 0, $now); - if (! $error) + // Add link with price request and supplier order + if ($this->id) { - $action='create'; - - // Actions on extra fields (by external module or standard code) - // FIXME le hook fait double emploi avec le trigger !! - $hookmanager->initHooks(array('supplierorderdao')); - $parameters=array('socid'=>$this->id); - $reshook=$hookmanager->executeHooks('insertExtraFields',$parameters,$this,$action); // Note that $action and $object may have been modified by some hooks - if (empty($reshook)) - { - if (empty($conf->global->MAIN_EXTRAFIELDS_DISABLED)) // For avoid conflicts if trigger used - { - $result=$this->insertExtraFields(); - if ($result < 0) - { - $error++; - } - } - } - else if ($reshook < 0) $error++; + $this->ref="(PROV".$this->id.")"; + + // Add object linked + if (is_array($this->linked_objects) && ! empty($this->linked_objects)) + { + foreach($this->linked_objects as $origin => $origin_id) + { + $ret = $this->add_object_linked($origin, $origin_id); + if (! $ret) + { + dol_print_error($this->db); + $error++; + } + } + } } - if (! $notrigger) + if (! $error && ! $notrigger) { // Call trigger $result=$this->call_trigger('ORDER_SUPPLIER_CREATE',$user); @@ -1024,7 +1026,7 @@ class CommandeFournisseur extends CommonOrder } else { - $this->error=$this->db->error(); + $this->error=$this->db->lasterror(); $this->db->rollback(); return -2; } @@ -1032,7 +1034,7 @@ class CommandeFournisseur extends CommonOrder } else { - $this->error=$this->db->error(); + $this->error=$this->db->lasterror(); $this->db->rollback(); return -1; } @@ -1521,6 +1523,10 @@ class CommandeFournisseur extends CommonOrder } } + // Delete linked object + $res = $this->deleteObjectLinked(); + if ($res < 0) $error++; + if (! $error) { // We remove directory @@ -1691,6 +1697,40 @@ class CommandeFournisseur extends CommonOrder } } + /** + * Set the id projet + * + * @param User $user Objet utilisateur qui modifie + * @param int $id_projet Date de livraison + * @return int <0 si ko, >0 si ok + */ + function set_id_projet($user, $id_projet) + { + if ($user->rights->fournisseur->commande->creer) + { + $sql = "UPDATE ".MAIN_DB_PREFIX."commande_fournisseur"; + $sql.= " SET fk_projet = ".($id_projet > 0 ? (int) $id_projet : 'null'); + $sql.= " WHERE rowid = ".$this->id; + + dol_syslog(get_class($this)."::set_id_projet", LOG_DEBUG); + $resql=$this->db->query($sql); + if ($resql) + { + $this->fk_projet = $id_projet; + return 1; + } + else + { + $this->error=$this->db->error(); + return -1; + } + } + else + { + return -2; + } + } + /** * Update a supplier order from a customer order * diff --git a/htdocs/fourn/commande/card.php b/htdocs/fourn/commande/card.php index 68724345411edcc2b16337cefa8a5377beb0f4bd..f372222a16f307e64bf6b51562782de09c8b1515 100644 --- a/htdocs/fourn/commande/card.php +++ b/htdocs/fourn/commande/card.php @@ -40,6 +40,8 @@ require_once DOL_DOCUMENT_ROOT.'/core/lib/fourn.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/class/doleditor.class.php'; +if (! empty($conf->askpricesupplier->enabled)) + require DOL_DOCUMENT_ROOT . '/comm/askpricesupplier/class/askpricesupplier.class.php'; if (!empty($conf->produit->enabled)) require_once DOL_DOCUMENT_ROOT.'/product/class/product.class.php'; if (!empty($conf->projet->enabled)) @@ -52,6 +54,7 @@ $langs->load('sendings'); $langs->load('companies'); $langs->load('bills'); $langs->load('propal'); +$langs->load('askpricesupplier'); $langs->load('deliveries'); $langs->load('products'); $langs->load('stocks'); @@ -66,6 +69,10 @@ $projectid = GETPOST('projectid','int'); $cancel = GETPOST('cancel','alpha'); $lineid = GETPOST('lineid', 'int'); +$lineid = GETPOST('lineid', 'int'); +$origin = GETPOST('origin', 'alpha'); +$originid = (GETPOST('originid', 'int') ? GETPOST('originid', 'int') : GETPOST('origin_id', 'int')); // For backward compatibility + //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)); @@ -832,6 +839,7 @@ if (empty($reshook)) } } + /* * Create an order */ @@ -869,12 +877,132 @@ if (empty($reshook)) if (! $error) { - $id = $object->create($user); - if ($id < 0) - { - $error++; - setEventMessage($langs->trans($object->error), 'errors'); - } + // If creation from another object of another module (Example: origin=propal, originid=1) + if (! empty($origin) && ! empty($originid)) + { + $element = 'comm/askpricesupplier'; + $subelement = 'askpricesupplier'; + + $object->origin = $origin; + $object->origin_id = $originid; + + // Possibility to add external linked objects with hooks + $object->linked_objects [$object->origin] = $object->origin_id; + $other_linked_objects = GETPOST('other_linked_objects', 'array'); + if (! empty($other_linked_objects)) { + $object->linked_objects = array_merge($object->linked_objects, $other_linked_objects); + } + + $object_id = $object->create($user); + + if ($object_id > 0) + { + dol_include_once('/' . $element . '/class/' . $subelement . '.class.php'); + + $classname = ucfirst($subelement); + $srcobject = new $classname($db); + $srcobject->fetch($object->origin_id); + + $object->set_date_livraison($user, $srcobject->date_livraison); + $object->set_id_projet($user, $srcobject->fk_project); + + dol_syslog("Try to find source object origin=" . $object->origin . " originid=" . $object->origin_id . " to add lines"); + $result = $srcobject->fetch($object->origin_id); + if ($result > 0) + { + $lines = $srcobject->lines; + if (empty($lines) && method_exists($srcobject, 'fetch_lines')) + { + $srcobject->fetch_lines(); + $lines = $srcobject->lines; + } + + $fk_parent_line = 0; + $num = count($lines); + + $productsupplier = new ProductFournisseur($db); + + for($i = 0; $i < $num; $i ++) + { + + if (empty($lines[$i]->subprice) || $lines[$i]->qty <= 0) + continue; + + $label = (! empty($lines [$i]->label) ? $lines [$i]->label : ''); + $desc = (! empty($lines [$i]->desc) ? $lines [$i]->desc : $lines [$i]->libelle); + $product_type = (! empty($lines [$i]->product_type) ? $lines [$i]->product_type : 0); + + // Reset fk_parent_line for no child products and special product + if (($lines [$i]->product_type != 9 && empty($lines [$i]->fk_parent_line)) || $lines [$i]->product_type == 9) { + $fk_parent_line = 0; + } + + // Extrafields + if (empty($conf->global->MAIN_EXTRAFIELDS_DISABLED) && method_exists($lines [$i], 'fetch_optionals')) // For avoid conflicts if + // trigger used + { + $lines [$i]->fetch_optionals($lines [$i]->rowid); + $array_option = $lines [$i]->array_options; + } + + $idprod = $productsupplier->find_min_price_product_fournisseur($lines [$i]->fk_product, $lines [$i]->qty); + $res = $productsupplier->fetch($idProductFourn); + + $result = $object->addline( + $desc, + $lines [$i]->subprice, + $lines [$i]->qty, + $lines [$i]->tva_tx, + $lines [$i]->localtax1_tx, + $lines [$i]->localtax2_tx, + $lines [$i]->fk_product, + $productsupplier->product_fourn_price_id, + $productsupplier->ref_fourn, + $lines [$i]->remise_percent, + 'HT', + 0, + $lines [$i]->product_type, + '', + '', + null, + null + ); + + if ($result < 0) { + $error ++; + break; + } + + // Defined the new fk_parent_line + if ($result > 0 && $lines [$i]->product_type == 9) { + $fk_parent_line = $result; + } + } + + // Hooks + $parameters = array('objFrom' => $srcobject); + $reshook = $hookmanager->executeHooks('createFrom', $parameters, $object, $action); // Note that $action and $object may have been + // modified by hook + if ($reshook < 0) + $error ++; + } else { + setEventMessage($srcobject->error, 'errors'); + $error ++; + } + } else { + setEventMessage($object->error, 'errors'); + $error ++; + } + } + else + { + $id = $object->create($user); + if ($id < 0) + { + $error++; + setEventMessage($langs->trans($object->error), 'errors'); + } + } } if ($error) @@ -1243,7 +1371,7 @@ $productstatic = new Product($db); /* *************************************************************************** */ $now=dol_now(); -if ($action=="create") +if ($action=='create') { print_fiche_titre($langs->trans('NewOrder')); @@ -1256,12 +1384,68 @@ if ($action=="create") $societe->fetch($socid); } - $cond_reglement_id = $societe->cond_reglement_supplier_id; - $mode_reglement_id = $societe->mode_reglement_supplier_id; + if (! empty($origin) && ! empty($originid)) + { + // Parse element/subelement (ex: project_task) + $element = $subelement = $origin; + if (preg_match('/^([^_]+)_([^_]+)/i', $origin, $regs)) { + $element = $regs [1]; + $subelement = $regs [2]; + } + + $element = 'comm/askpricesupplier'; + $subelement = 'askpricesupplier'; + + dol_include_once('/' . $element . '/class/' . $subelement . '.class.php'); + + $classname = ucfirst($subelement); + $objectsrc = new $classname($db); + $objectsrc->fetch($originid); + if (empty($objectsrc->lines) && method_exists($objectsrc, 'fetch_lines')) + $objectsrc->fetch_lines(); + $objectsrc->fetch_thirdparty(); + + // Replicate extrafields + $objectsrc->fetch_optionals($originid); + $object->array_options = $objectsrc->array_options; + + $projectid = (! empty($objectsrc->fk_project) ? $objectsrc->fk_project : ''); + $ref_client = (! empty($objectsrc->ref_client) ? $objectsrc->ref_client : ''); + + $soc = $objectsrc->client; + $cond_reglement_id = (!empty($objectsrc->cond_reglement_id)?$objectsrc->cond_reglement_id:(!empty($soc->cond_reglement_id)?$soc->cond_reglement_id:1)); + $mode_reglement_id = (!empty($objectsrc->mode_reglement_id)?$objectsrc->mode_reglement_id:(!empty($soc->mode_reglement_id)?$soc->mode_reglement_id:0)); + $fk_account = (! empty($objectsrc->fk_account)?$objectsrc->fk_account:(! empty($soc->fk_account)?$soc->fk_account:0)); + $availability_id = (!empty($objectsrc->availability_id)?$objectsrc->availability_id:(!empty($soc->availability_id)?$soc->availability_id:0)); + $shipping_method_id = (! empty($objectsrc->shipping_method_id)?$objectsrc->shipping_method_id:(! empty($soc->shipping_method_id)?$soc->shipping_method_id:0)); + $demand_reason_id = (!empty($objectsrc->demand_reason_id)?$objectsrc->demand_reason_id:(!empty($soc->demand_reason_id)?$soc->demand_reason_id:0)); + $remise_percent = (!empty($objectsrc->remise_percent)?$objectsrc->remise_percent:(!empty($soc->remise_percent)?$soc->remise_percent:0)); + $remise_absolue = (!empty($objectsrc->remise_absolue)?$objectsrc->remise_absolue:(!empty($soc->remise_absolue)?$soc->remise_absolue:0)); + $dateinvoice = empty($conf->global->MAIN_AUTOFILL_DATE)?-1:''; + + $datedelivery = (! empty($objectsrc->date_livraison) ? $objectsrc->date_livraison : ''); + + $note_private = (! empty($objectsrc->note_private) ? $objectsrc->note_private : (! empty($objectsrc->note_private) ? $objectsrc->note_private : '')); + $note_public = (! empty($objectsrc->note_public) ? $objectsrc->note_public : ''); + + // Object source contacts list + $srccontactslist = $objectsrc->liste_contact(- 1, 'external', 1); + + } + else + { + $cond_reglement_id = $societe->cond_reglement_supplier_id; + $mode_reglement_id = $societe->mode_reglement_supplier_id; + } print '<form name="add" action="'.$_SERVER["PHP_SELF"].'" method="post">'; print '<input type="hidden" name="token" value="'.$_SESSION['newtoken'].'">'; print '<input type="hidden" name="action" value="add">'; + print '<input type="hidden" name="socid" value="' . $soc->id . '">' . "\n"; + print '<input type="hidden" name="remise_percent" value="' . $soc->remise_percent . '">'; + print '<input type="hidden" name="origin" value="' . $origin . '">'; + print '<input type="hidden" name="originid" value="' . $originid . '">'; + print '<table class="border" width="100%">'; // Ref @@ -1319,7 +1503,7 @@ if ($action=="create") print '<tr><td>'.$langs->trans('NotePublic').'</td>'; print '<td>'; - $doleditor = new DolEditor('note_public', GETPOST('note_public'), '', 80, 'dolibarr_notes', 'In', 0, false, true, ROWS_3, 70); + $doleditor = new DolEditor('note_public', isset($note_public) ? $note_public : GETPOST('note_public'), '', 80, 'dolibarr_notes', 'In', 0, false, true, ROWS_3, 70); print $doleditor->Create(1); print '</td>'; //print '<textarea name="note_public" wrap="soft" cols="60" rows="'.ROWS_5.'"></textarea>'; @@ -1327,13 +1511,40 @@ if ($action=="create") print '<tr><td>'.$langs->trans('NotePrivate').'</td>'; print '<td>'; - $doleditor = new DolEditor('note_private', GETPOST('note_private'), '', 80, 'dolibarr_notes', 'In', 0, false, true, ROWS_3, 70); + $doleditor = new DolEditor('note_private', isset($note_private) ? $note_private : GETPOST('note_private'), '', 80, 'dolibarr_notes', 'In', 0, false, true, ROWS_3, 70); print $doleditor->Create(1); print '</td>'; //print '<td><textarea name="note_private" wrap="soft" cols="60" rows="'.ROWS_5.'"></textarea></td>'; print '</tr>'; + if (! empty($origin) && ! empty($originid) && is_object($objectsrc)) { + + print "\n<!-- " . $classname . " info -->"; + print "\n"; + print '<input type="hidden" name="amount" value="' . $objectsrc->total_ht . '">' . "\n"; + print '<input type="hidden" name="total" value="' . $objectsrc->total_ttc . '">' . "\n"; + print '<input type="hidden" name="tva" value="' . $objectsrc->total_tva . '">' . "\n"; + print '<input type="hidden" name="origin" value="' . $objectsrc->element . '">'; + print '<input type="hidden" name="originid" value="' . $objectsrc->id . '">'; + + $newclassname = $classname; + if ($newclassname == 'AskPriceSupplier') + $newclassname = 'CommercialAskPriceSupplier'; + print '<tr><td>' . $langs->trans($newclassname) . '</td><td colspan="2">' . $objectsrc->getNomUrl(1) . '</td></tr>'; + print '<tr><td>' . $langs->trans('TotalHT') . '</td><td colspan="2">' . price($objectsrc->total_ht) . '</td></tr>'; + print '<tr><td>' . $langs->trans('TotalVAT') . '</td><td colspan="2">' . price($objectsrc->total_tva) . "</td></tr>"; + if ($mysoc->localtax1_assuj == "1" || $objectsrc->total_localtax1 != 0) // Localtax1 RE + { + print '<tr><td>' . $langs->transcountry("AmountLT1", $mysoc->country_code) . '</td><td colspan="2">' . price($objectsrc->total_localtax1) . "</td></tr>"; + } + if ($mysoc->localtax2_assuj == "1" || $objectsrc->total_localtax2 != 0) // Localtax2 IRPF + { + print '<tr><td>' . $langs->transcountry("AmountLT2", $mysoc->country_code) . '</td><td colspan="2">' . price($objectsrc->total_localtax2) . "</td></tr>"; + } + + print '<tr><td>' . $langs->trans('TotalTTC') . '</td><td colspan="2">' . price($objectsrc->total_ttc) . "</td></tr>"; + } // Other options $parameters=array(); @@ -1350,6 +1561,18 @@ if ($action=="create") print '<br><div class="center"><input type="submit" class="button" name="bouton" value="'.$langs->trans('CreateDraft').'"></div>'; print "</form>\n"; + + // Show origin lines + if (! empty($origin) && ! empty($originid) && is_object($objectsrc)) { + $title = $langs->trans('ProductsAndServices'); + print_titre($title); + + print '<table class="noborder" width="100%">'; + + $objectsrc->printOriginLinesList(); + + print '</table>'; + } } elseif (! empty($object->id)) { diff --git a/htdocs/install/doctemplates/askpricesupplier/index.html b/htdocs/install/doctemplates/askpricesupplier/index.html new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/htdocs/install/doctemplates/askpricesupplier/template_askpricesupplier.odt b/htdocs/install/doctemplates/askpricesupplier/template_askpricesupplier.odt new file mode 100644 index 0000000000000000000000000000000000000000..8ece83c989c9ff688337dbb0edf6febd47eb0dcf Binary files /dev/null and b/htdocs/install/doctemplates/askpricesupplier/template_askpricesupplier.odt differ diff --git a/htdocs/install/mysql/migration/3.7.0-3.8.0.sql b/htdocs/install/mysql/migration/3.7.0-3.8.0.sql index 849909678562f9128f8fc5dd07a58a5d52aadbac..6a6fe87a584782b16ab0743058fbdb8fb9787e2a 100755 --- a/htdocs/install/mysql/migration/3.7.0-3.8.0.sql +++ b/htdocs/install/mysql/migration/3.7.0-3.8.0.sql @@ -112,6 +112,7 @@ ALTER TABLE llx_contratdet_extrafields ADD INDEX idx_contratdet_extrafields (fk_ ALTER TABLE llx_product_fournisseur_price ADD COLUMN delivery_time_days integer; + ALTER TABLE llx_commande_fournisseur_dispatch ADD COLUMN comment varchar(255); ALTER TABLE llx_commande_fournisseur_dispatch ADD COLUMN status integer; ALTER TABLE llx_commande_fournisseur_dispatch ADD COLUMN tms timestamp; @@ -227,3 +228,94 @@ ALTER TABLE llx_commande_fournisseurdet ADD COLUMN special_code integer DEFAULT ALTER TABLE llx_commande_fournisseurdet ADD COLUMN rang integer DEFAULT 0; ALTER TABLE llx_commande_fournisseurdet ADD COLUMN fk_parent_line integer NULL after fk_commande; +ALTER TABLE llx_projet ADD COLUMN date_close datetime DEFAULT NULL; +ALTER TABLE llx_projet ADD COLUMN fk_user_close integer DEFAULT NULL; + + + +-- Module AskPriceSupplier -- +CREATE TABLE llx_askpricesupplier ( + rowid integer NOT NULL AUTO_INCREMENT PRIMARY KEY, + ref varchar(30) NOT NULL, + entity integer NOT NULL DEFAULT '1', + ref_ext varchar(255) DEFAULT NULL, + ref_int varchar(255) DEFAULT NULL, + fk_soc integer DEFAULT NULL, + fk_projet integer DEFAULT NULL, + tms timestamp, + datec datetime DEFAULT NULL, + date_valid datetime DEFAULT NULL, + date_cloture datetime DEFAULT NULL, + fk_user_author integer DEFAULT NULL, + fk_user_modif integer DEFAULT NULL, + fk_user_valid integer DEFAULT NULL, + fk_user_cloture integer DEFAULT NULL, + fk_statut smallint NOT NULL DEFAULT '0', + price double DEFAULT '0', + remise_percent double DEFAULT '0', + remise_absolue double DEFAULT '0', + remise double DEFAULT '0', + total_ht double(24,8) DEFAULT 0, + tva double(24,8) DEFAULT 0, + localtax1 double(24,8) DEFAULT 0, + localtax2 double(24,8) DEFAULT 0, + total double(24,8) DEFAULT 0, + fk_account integer DEFAULT NULL, + fk_currency varchar(3) DEFAULT NULL, + fk_cond_reglement integer DEFAULT NULL, + fk_mode_reglement integer DEFAULT NULL, + note_private text, + note_public text, + model_pdf varchar(255) DEFAULT NULL, + date_livraison date DEFAULT NULL, + fk_shipping_method integer DEFAULT NULL, + import_key varchar(14) DEFAULT NULL, + extraparams varchar(255) DEFAULT NULL +) ENGINE=innodb; + +CREATE TABLE llx_askpricesupplierdet ( + rowid integer NOT NULL AUTO_INCREMENT PRIMARY KEY, + fk_askpricesupplier integer NOT NULL, + fk_parent_line integer DEFAULT NULL, + fk_product integer DEFAULT NULL, + label varchar(255) DEFAULT NULL, + description text, + fk_remise_except integer DEFAULT NULL, + tva_tx double(6,3) DEFAULT 0, + localtax1_tx double(6,3) DEFAULT 0, + localtax1_type varchar(10) DEFAULT NULL, + localtax2_tx double(6,3) DEFAULT 0, + localtax2_type varchar(10) DEFAULT NULL, + qty double DEFAULT NULL, + remise_percent double DEFAULT '0', + remise double DEFAULT '0', + price double DEFAULT NULL, + subprice double(24,8) DEFAULT 0, + total_ht double(24,8) DEFAULT 0, + total_tva double(24,8) DEFAULT 0, + total_localtax1 double(24,8) DEFAULT 0, + total_localtax2 double(24,8) DEFAULT 0, + total_ttc double(24,8) DEFAULT 0, + product_type integer DEFAULT 0, + info_bits integer DEFAULT 0, + buy_price_ht double(24,8) DEFAULT 0, + fk_product_fournisseur_price integer DEFAULT NULL, + special_code integer DEFAULT 0, + rang integer DEFAULT 0, + ref_fourn varchar(30) DEFAULT NULL +) ENGINE=innodb; + +CREATE TABLE llx_askpricesupplier_extrafields ( + rowid integer AUTO_INCREMENT PRIMARY KEY, + tms timestamp, + fk_object integer NOT NULL, + import_key varchar(14) DEFAULT NULL +) ENGINE=innodb; + +CREATE TABLE llx_askpricesupplierdet_extrafields ( + rowid integer AUTO_INCREMENT PRIMAR KEY, + tms timestamp, + fk_object integer NOT NULL, + import_key varchar(14) DEFAULT NULL +) ENGINE=innodb; +-- End Module AskPriceSupplier -- diff --git a/htdocs/install/mysql/tables/llx_projet.sql b/htdocs/install/mysql/tables/llx_projet.sql index 0bfde5c026b1ac354be8d6c39f5ca50f95c0053d..d9192c191ba3c1baa901bc6f3cd98237ba4d2ca6 100644 --- a/htdocs/install/mysql/tables/llx_projet.sql +++ b/htdocs/install/mysql/tables/llx_projet.sql @@ -32,6 +32,8 @@ create table llx_projet fk_user_creat integer NOT NULL, -- createur du projet public integer, -- project is public or not fk_statut smallint DEFAULT 0 NOT NULL, + date_close datetime DEFAULT NULL, + fk_user_close integer DEFAULT NULL, note_private text, note_public text, --budget_days real, -- budget in days is sum of field planned_workload of tasks diff --git a/htdocs/langs/en_US/admin.lang b/htdocs/langs/en_US/admin.lang index 1335239fd8d013b2dad72a812c803c6ae5c4ebf2..e701db321068f5798c9b7947e70ad471992932f4 100755 --- a/htdocs/langs/en_US/admin.lang +++ b/htdocs/langs/en_US/admin.lang @@ -1170,6 +1170,13 @@ UseOptionLineIfNoQuantity=A line of product/service with a zero amount is consid FreeLegalTextOnProposal=Free text on commercial proposals WatermarkOnDraftProposal=Watermark on draft commercial proposals (none if empty) BANK_ASK_PAYMENT_BANK_DURING_PROPOSAL=Ask for bank account destination of proposal +##### AskPriceSupplier ##### +AskPriceSupplierSetup=Price requests suppliers module setup +AskPriceSupplierNumberingModules=Price requests suppliers numbering models +AskPriceSupplierPDFModules=Price requests suppliers documents models +FreeLegalTextOnAskPriceSupplier=Free text on price requests suppliers +WatermarkOnDraftAskPriceSupplier=Watermark on draft price requests suppliers (none if empty) +BANK_ASK_PAYMENT_BANK_DURING_ASKPRICESUPPLIER=Ask for bank account destination of price request ##### Orders ##### OrdersSetup=Order management setup OrdersNumberingModules=Orders numbering models diff --git a/htdocs/langs/en_US/askpricesupplier.lang b/htdocs/langs/en_US/askpricesupplier.lang new file mode 100644 index 0000000000000000000000000000000000000000..b75a3284146212a80971f885e21956e2d763f282 --- /dev/null +++ b/htdocs/langs/en_US/askpricesupplier.lang @@ -0,0 +1,57 @@ +# Dolibarr language file - Source file is en_US - askpricesupplier +AskPriceSupplier=Supplier commercial proposals +askpricesupplierDESC=Manage price requests to suppliers +askpricesupplierMENU_LEFT_TITLE=Price request supplier +askpricesupplierMENU_LEFT_TITLE_NEW=New request +askpricesupplierMENU_LEFT_TITLE_LIST=List +CommRequest=Price request +CommRequests=Price requests +SearchRequest=Find a request +DraftRequests=Draft requests +LastModifiedRequests=Last %s modified price requests +RequestsOpened=Opened price requests +AskPriceSupplierArea=Area price requests suppliers +Askpricesupplier=Price request supplier +NewAskPrice=New price request +NewAsk=New request +ShowAskpricesupplier=Show price request +AddAskPriceSupplier=Create a price request +AskPriceSupplierRefFourn=Supplier ref +AskPriceSupplierDate=Delivery date +AskPriceSupplierRefFournNotice=Before closing to "Accepted", think to grasp suppliers references. +RelatedAskPriceSupplier=Related price requests suppliers +ConfirmValidateAsk=Are you sure you want to validate this price request under name <b>%s</b> ? +DateAsk=Date of request +DeleteAsk=Delete request +ValidateAsk=Validate request +AddAsk=Create a request +AskpricesupplierDraft=Drafts +AskpricesupplierOpened=Opened +AskpricesupplierStatusDraft=Draft (needs to be validated) +AskpricesupplierStatusValidated=Validated (request is open) +AskpricesupplierStatusOpened=Validated (request is open) +AskpricesupplierStatusClosed=Closed +AskpricesupplierStatusSigned=Accepted +AskpricesupplierStatusNotSigned=Refused +AskpricesupplierStatusDraftShort=Draft +AskpricesupplierStatusValidatedShort=Validated +AskpricesupplierStatusOpenedShort=Opened +AskpricesupplierStatusClosedShort=Closed +AskpricesupplierStatusSignedShort=Accepted +AskpricesupplierStatusNotSignedShort=Refused +CopyAskFrom=Create price request by copying existing a request +CreateEmptyAsk=Create blank request +CloneAsk=Clone price request +ConfirmCloneAsk=Are you sure you want to clone the price request <b>%s</b> ? +ConfirmReOpenAsk=Are you sure you want to open back the price request <b>%s</b> ? +SendAskByMail=Send price request by mail +SendAskRef=Sending the price request %s +AskPriceSupplierCard=Request card +ConfirmDeleteAsk=Are you sure you want to delete this price request ? +ActionsOnAskPriceSupplier=Events on price request +DocModelAuroreDescription=A complete request model (logo...) +CommercialAsk=Price request +DefaultModelAskPriceSupplierCreate=Default model creation +DefaultModelAskPriceSupplierToBill=Default template when closing a price request (accepted) +DefaultModelAskPriceSupplierClosed=Default template when closing a price request (refused) +ListOfAskPriceSupplier=Liste des demandes de prix fournisseurs \ No newline at end of file diff --git a/htdocs/langs/en_US/main.lang b/htdocs/langs/en_US/main.lang index 0b5347f6e38d1359dea2e1b37d577f5eeb7271dc..ba7353b015d8ecac3fe618204b98bcfc87739f68 100644 --- a/htdocs/langs/en_US/main.lang +++ b/htdocs/langs/en_US/main.lang @@ -296,6 +296,7 @@ UnitPriceHT=Unit price (net) UnitPriceTTC=Unit price PriceU=U.P. PriceUHT=U.P. (net) +AskPriceSupplierUHT=P.U. HT Requested PriceUTTC=U.P. Amount=Amount AmountInvoice=Invoice amount diff --git a/htdocs/langs/en_US/other.lang b/htdocs/langs/en_US/other.lang index f5b39b3f704ea18fcdedfd0196860f7ca29bd38d..d87601d8126fc8355329e300ae9d71587a135944 100644 --- a/htdocs/langs/en_US/other.lang +++ b/htdocs/langs/en_US/other.lang @@ -60,6 +60,7 @@ PredefinedMailTestHtml=This is a <b>test</b> mail (the word test must be in bold PredefinedMailContentSendInvoice=__CONTACTCIVNAME__\n\nYou will find here the invoice __FACREF__\n\n__PERSONALIZED__Sincerely\n\n__SIGNATURE__ PredefinedMailContentSendInvoiceReminder=__CONTACTCIVNAME__\n\nWe would like to warn you that the invoice __FACREF__ seems to not being payed. So this is the invoice in attachment again, as a reminder.\n\n__PERSONALIZED__Sincerely\n\n__SIGNATURE__ PredefinedMailContentSendProposal=__CONTACTCIVNAME__\n\nYou will find here the commercial proposal __PROPREF__\n\n__PERSONALIZED__Sincerely\n\n__SIGNATURE__ +PredefinedMailContentSendAskPriceSupplier=__CONTACTCIVNAME__\n\nYou will find here the price request __ASKREF__\n\n__PERSONALIZED__Sincerely\n\n__SIGNATURE__ PredefinedMailContentSendOrder=__CONTACTCIVNAME__\n\nYou will find here the order __ORDERREF__\n\n__PERSONALIZED__Sincerely\n\n__SIGNATURE__ PredefinedMailContentSendSupplierOrder=__CONTACTCIVNAME__\n\nYou will find here our order __ORDERREF__\n\n__PERSONALIZED__Sincerely\n\n__SIGNATURE__ PredefinedMailContentSendSupplierInvoice=__CONTACTCIVNAME__\n\nYou will find here the invoice __FACREF__\n\n__PERSONALIZED__Sincerely\n\n__SIGNATURE__ diff --git a/htdocs/langs/fr_FR/admin.lang b/htdocs/langs/fr_FR/admin.lang index 6e619a96b077b592d1af5211d50ab4efea5db048..9a5488c0860e568c49cbb8803758f5d809db9c34 100644 --- a/htdocs/langs/fr_FR/admin.lang +++ b/htdocs/langs/fr_FR/admin.lang @@ -264,6 +264,7 @@ MAIN_MAIL_EMAIL_FROM=Adresse email de l'émetteur pour l'envoi d'emails automati MAIN_MAIL_ERRORS_TO=Adresse email utilisée pour les retours d'erreurs des emails envoyés MAIN_MAIL_AUTOCOPY_TO= Envoyer systématiquement une copie cachée des emails envoyés à MAIN_MAIL_AUTOCOPY_PROPOSAL_TO= Envoyer systématiquement une copie cachée des propositions envoyées par email à +MAIN_MAIL_AUTOCOPY_ASKPRICESUPPLIER_TO= Envoyer systématiquement une copie cachée des demandes de prix envoyées par email à MAIN_MAIL_AUTOCOPY_ORDER_TO= Envoyer systématiquement une copie cachée des commandes envoyées par emails à MAIN_MAIL_AUTOCOPY_INVOICE_TO= Envoyer systématiquement une copie cachée des factures envoyées par email à MAIN_DISABLE_ALL_MAILS=Désactiver globalement tout envoi d'emails (pour mode test ou démos) @@ -1152,6 +1153,14 @@ UseOptionLineIfNoQuantity=Une ligne de produit/service ayant une quantité nulle FreeLegalTextOnProposal=Mention complémentaire sur les propositions commerciales WatermarkOnDraftProposal=Filigrane sur les brouillons de propositions commerciales (aucun si vide) BANK_ASK_PAYMENT_BANK_DURING_PROPOSAL=Saisir le compte bancaire cible lors de la proposition commerciale +##### AskPriceSupplier ##### +AskPriceSupplierSetup=Configuration du module Demandes de Prix Fournisseurs +AskPriceSupplierNumberingModules=Modèles de numérotation des demandes de prix fournisseurs +AskPriceSupplierPDFModules=Modèles de documents de demandes de prix fournisseurs +AskPriceSupplierPDFModules=Modèles de documents de demandes de prix fournisseurs +FreeLegalTextOnAskPriceSupplier=Mention complémentaire sur les demandes de prix fournisseurs +WatermarkOnDraftAskPriceSupplier=Filigrane sur les brouillons de demandes de prix (aucun si vide) +BANK_ASK_PAYMENT_BANK_DURING_ASKPRICESUPPLIER=Saisir le compte bancaire cible lors de la demande de prix ##### Orders ##### OrdersSetup=Configuration du module Commandes OrdersNumberingModules=Modèles de numérotation des commandes diff --git a/htdocs/langs/fr_FR/askpricesupplier.lang b/htdocs/langs/fr_FR/askpricesupplier.lang new file mode 100644 index 0000000000000000000000000000000000000000..50ba0c96d8d7e6629b1d086a0893edd8e580b465 --- /dev/null +++ b/htdocs/langs/fr_FR/askpricesupplier.lang @@ -0,0 +1,57 @@ +# Dolibarr language file - Source file is en_US - askpricesupplier +AskPriceSupplier=Proposition commerciales fournisseurs +askpricesupplierDESC=Gestion des demandes de prix aux fournisseurs +askpricesupplierMENU_LEFT_TITLE=Demandes de prix fourn. +askpricesupplierMENU_LEFT_TITLE_NEW=Nouvelle demande +askpricesupplierMENU_LEFT_TITLE_LIST=Liste +CommRequest=Demande de prix +CommRequests=Demandes de prix +SearchRequest=Rechercher une demande +DraftRequests=Demandes brouillons +LastModifiedRequests=Les %s dernières demandes de prix modifiées +RequestsOpened=Demandes de prix ouvertes +AskPriceSupplierArea=Espace des demandes de prix fournisseurs +Askpricesupplier=Demande de prix fournisseur +NewAskPrice=Nouvelle demande de prix +NewAsk=Nouvelle demande +ShowAskpricesupplier=Afficher la demande de prix +AddAskPriceSupplier=Créer une demande de prix +AskPriceSupplierRefFourn=Réf. fournisseur +AskPriceSupplierDate=Date de livraison +AskPriceSupplierRefFournNotice=Avant de clôturer à "Acceptée", pensez à saisir les références fournisseurs. +RelatedAskPriceSupplier=Demandes de prix fournisseurs associées +ConfirmValidateAsk=Êtes-vous sûr de vouloir valider cette demande de prix sous la référence <b>%s</b> ? +DateAsk=Date de demande +DeleteAsk=Supprimer demande +ValidateAsk=Valider demande +AddAsk=Créer une demande +AskpricesupplierDraft=Brouillons +AskpricesupplierOpened=Ouvertes +AskpricesupplierStatusDraft=Brouillon (à valider) +AskpricesupplierStatusValidated=Validée (demande ouverte) +AskpricesupplierStatusOpened=Validée (demande ouverte) +AskpricesupplierStatusClosed=Fermée +AskpricesupplierStatusSigned=Acceptée +AskpricesupplierStatusNotSigned=Refusée +AskpricesupplierStatusDraftShort=Brouillon +AskpricesupplierStatusValidatedShort=Validée +AskpricesupplierStatusOpenedShort=Ouverte +AskpricesupplierStatusClosedShort=Fermée +AskpricesupplierStatusSignedShort=Acceptée +AskpricesupplierStatusNotSignedShort=Refusée +CopyAskFrom=Créer demande/devis par recopie d'une demande existante +CreateEmptyAsk=Créer demande/devis vierge +CloneAsk=Cloner demande de prix +ConfirmCloneAsk=Êtes-vous sûr de vouloir cloner la demande de prix <b>%s</b> ? +ConfirmReOpenAsk=Êtes-vous sûr de vouloir réouvrir la demande de prix <b>%s</b> ? +SendAskByMail=Envoyer demande de prix par email +SendAskRef=Envoi de la demande de prix %s +AskPriceSupplierCard=Fiche demande +ConfirmDeleteAsk=Êtes-vous sûr de vouloir effacer cette demande de prix <b>%s</b> ? +ActionsOnAskPriceSupplier=Événements sur la demande +DocModelAuroreDescription=Modèle de demande de prix fournisseur complet (logo…) +CommercialAsk=Demande de prix +DefaultModelAskPriceSupplierCreate=Modèle par défaut à la création +DefaultModelAskPriceSupplierToBill=Modèle par défaut lors de la clôture d'une demande de prix (à accéptée) +DefaultModelAskPriceSupplierClosed=Modèle par défaut lors de la clôture d'une demande de prix (refusée) +ListOfAskPriceSupplier=Liste des demandes de prix fournisseurs \ No newline at end of file diff --git a/htdocs/langs/fr_FR/main.lang b/htdocs/langs/fr_FR/main.lang index a8ab47c9c4d0132ab276a8a72c5b2f5b8e0e5223..dc889cdd2b414ca1f786afe70c2695d40dc156a7 100644 --- a/htdocs/langs/fr_FR/main.lang +++ b/htdocs/langs/fr_FR/main.lang @@ -295,6 +295,7 @@ UnitPriceHT=Prix unitaire HT UnitPriceTTC=Prix unitaire TTC PriceU=P.U. PriceUHT=P.U. HT +AskPriceSupplierUHT=P.U. HT Demandé PriceUTTC=P.U. TTC Amount=Montant AmountInvoice=Montant facture diff --git a/htdocs/langs/fr_FR/other.lang b/htdocs/langs/fr_FR/other.lang index 1c23cce68cb5b6df9da301ccbab5fbb1836edf92..a3d9e75a4ac3b3c232bbf575e725f793e5c6ef73 100644 --- a/htdocs/langs/fr_FR/other.lang +++ b/htdocs/langs/fr_FR/other.lang @@ -60,6 +60,7 @@ PredefinedMailTestHtml=Ceci est un message de <b>test</b> (le mot test doit êtr PredefinedMailContentSendInvoice=__CONTACTCIVNAME__\n\nVeuillez trouver ci-joint la facture __FACREF__\n\n__PERSONALIZED__Cordialement\n\n__SIGNATURE__ PredefinedMailContentSendInvoiceReminder=__CONTACTCIVNAME__ \n\nNous voudrions porter à votre connaissance que la facture __FACREF__ ne semble pas avoir été réglée. La voici donc, pour rappel, en pièce jointe.\n\n__PERSONALIZED__Cordialement\n\n__SIGNATURE__ PredefinedMailContentSendProposal=__CONTACTCIVNAME__\n\nVeuillez trouver ci-joint la proposition commerciale __PROPREF__\n\n__PERSONALIZED__Cordialement\n\n__SIGNATURE__ +PredefinedMailContentSendAskPriceSupplier=__CONTACTCIVNAME__\n\nVeuillez trouver ci-joint la demande de prix __ASKREF__\n\n__PERSONALIZED__Cordialement\n\n__SIGNATURE__ PredefinedMailContentSendOrder=__CONTACTCIVNAME__\n\nVeuillez trouver ci-joint la commande __ORDERREF__\n\n__PERSONALIZED__Cordialement\n\n__SIGNATURE__ PredefinedMailContentSendSupplierOrder=__CONTACTCIVNAME__\n\nVeuillez trouver ci-joint notre commande __ORDERREF__\n\n__PERSONALIZED__Cordialement\n\n__SIGNATURE__ PredefinedMailContentSendSupplierInvoice=__CONTACTCIVNAME__\n\nVeuillez trouver ci-joint la facture __FACREF__\n\n__PERSONALIZED__Cordialement\n\n__SIGNATURE__ diff --git a/htdocs/product/class/product.class.php b/htdocs/product/class/product.class.php index e5a8afc274badaf23bf1cacb969012279caf78e6..f73a6bac70d52daec6ea22ad55936cb48ed2f230 100755 --- a/htdocs/product/class/product.class.php +++ b/htdocs/product/class/product.class.php @@ -43,7 +43,7 @@ class Product extends CommonObject public $element='product'; public $table_element='product'; public $fk_element='fk_product'; - protected $childtables=array('propaldet','commandedet','facturedet','contratdet','facture_fourn_det','commande_fournisseurdet'); // To test if we can delete object + protected $childtables=array('askpricesupplierdet', 'propaldet','commandedet','facturedet','contratdet','facture_fourn_det','commande_fournisseurdet'); // To test if we can delete object protected $isnolinkedbythird = 1; // No field fk_soc protected $ismultientitymanaged = 1; // 0=No test on entity, 1=Test with field entity, 2=Test with link by societe diff --git a/htdocs/projet/class/project.class.php b/htdocs/projet/class/project.class.php index 7d5cece47075c8ab3bb542961a69cf69248ab73c..bc9e6bd37b5c198d682492694873ee5d438897a6 100644 --- a/htdocs/projet/class/project.class.php +++ b/htdocs/projet/class/project.class.php @@ -49,8 +49,10 @@ class Project extends CommonObject var $title; var $date_start; var $date_end; + var $date_close; var $socid; var $user_author_id; //!< Id of project creator. Not defined if shared project. + var $user_close_id; var $public; //!< Tell if this is a public or private project var $note_private; var $note_public; @@ -212,6 +214,8 @@ class Project extends CommonObject $sql.= ", datec=" . ($this->date_c != '' ? "'".$this->db->idate($this->date_c)."'" : 'null'); $sql.= ", dateo=" . ($this->date_start != '' ? "'".$this->db->idate($this->date_start)."'" : 'null'); $sql.= ", datee=" . ($this->date_end != '' ? "'".$this->db->idate($this->date_end)."'" : 'null'); + $sql.= ", date_close=" . ($this->date_close != '' ? "'".$this->db->idate($this->date_close)."'" : 'null'); + $sql.= ", fk_user_close=" . ($this->fk_user_close > 0 ? $this->fk_user_close : "null"); $sql.= ", budget_amount = " . ($this->budget_amount > 0 ? $this->budget_amount : "null"); $sql.= " WHERE rowid = " . $this->id; @@ -299,7 +303,7 @@ class Project extends CommonObject if (empty($id) && empty($ref)) return -1; $sql = "SELECT rowid, ref, title, description, public, datec, budget_amount,"; - $sql.= " tms, dateo, datee, fk_soc, fk_user_creat, fk_statut, note_private, note_public, model_pdf"; + $sql.= " tms, dateo, datee, date_close, fk_soc, fk_user_creat, fk_user_close, fk_statut, note_private, note_public, model_pdf"; $sql.= " FROM " . MAIN_DB_PREFIX . "projet"; if (! empty($id)) { @@ -330,10 +334,12 @@ class Project extends CommonObject $this->datem = $this->db->jdate($obj->tms); // TODO deprecated $this->date_start = $this->db->jdate($obj->dateo); $this->date_end = $this->db->jdate($obj->datee); + $this->date_close = $this->db->jdate($obj->date_close); $this->note_private = $obj->note_private; $this->note_public = $obj->note_public; $this->socid = $obj->fk_soc; $this->user_author_id = $obj->fk_user_creat; + $this->user_close_id = $obj->fk_user_close; $this->public = $obj->public; $this->statut = $obj->fk_statut; $this->budget_amount = $obj->budget_amount; @@ -682,13 +688,15 @@ class Project extends CommonObject /** * Close a project * - * @param User $user User that validate + * @param User $user User that close project * @return int <0 if KO, >0 if OK */ function setClose($user) { global $langs, $conf; + $now = dol_now(); + $error=0; if ($this->statut != 2) @@ -696,7 +704,7 @@ class Project extends CommonObject $this->db->begin(); $sql = "UPDATE " . MAIN_DB_PREFIX . "projet"; - $sql.= " SET fk_statut = 2"; + $sql.= " SET fk_statut = 2, fk_user_close = ".$user->id.", date_close = '".$this->db->idate($now)."'"; $sql.= " WHERE rowid = " . $this->id; $sql.= " AND entity = " . $conf->entity; $sql.= " AND fk_statut = 1"; diff --git a/htdocs/societe/class/societe.class.php b/htdocs/societe/class/societe.class.php index 77673b82ed3faf2a6222f60d1941152a85e16b81..e9d536d4a89b9cfb0a4fc528c3d73660b526aa9a 100644 --- a/htdocs/societe/class/societe.class.php +++ b/htdocs/societe/class/societe.class.php @@ -42,7 +42,7 @@ class Societe extends CommonObject public $element='societe'; public $table_element = 'societe'; public $fk_element='fk_soc'; - protected $childtables=array("propal","commande","facture","contrat","facture_fourn","commande_fournisseur"); // To test if we can delete object + protected $childtables=array("askpricesupplier", "propal","commande","facture","contrat","facture_fourn","commande_fournisseur"); // To test if we can delete object /** * 0=No test on entity, 1=Test with field entity, 2=Test with link by societe diff --git a/htdocs/theme/eldy/img/object_askpricesupplier.png b/htdocs/theme/eldy/img/object_askpricesupplier.png new file mode 100644 index 0000000000000000000000000000000000000000..2dc60e66b3ec3d81f7a71167d00921dbb1bca75b Binary files /dev/null and b/htdocs/theme/eldy/img/object_askpricesupplier.png differ diff --git a/test/phpunit/ProjectTest.php b/test/phpunit/ProjectTest.php index e27cd1e02237686fa83b59f1065743ee483a24eb..c2f5d5b81617919c0053e9025fde6b883649a9d8 100644 --- a/test/phpunit/ProjectTest.php +++ b/test/phpunit/ProjectTest.php @@ -189,7 +189,7 @@ class ProjectTest extends PHPUnit_Framework_TestCase } /** - * testProjectOther + * testProjectClose * * @param Project $localobject Project * @return int @@ -205,6 +205,10 @@ class ProjectTest extends PHPUnit_Framework_TestCase $langs=$this->savlangs; $db=$this->savdb; + $result=$localobject->setClose($user); + + print __METHOD__." id=".$localobject->id." result=".$result."\n"; + $this->assertLessThan($result, 0); return $localobject->id; } @@ -214,7 +218,7 @@ class ProjectTest extends PHPUnit_Framework_TestCase * @param int $id Id of project * @return void * - * @depends testProjectOther + * @depends testProjectClose * The depends says test is run only if previous is ok */ public function testProjectDelete($id)