diff --git a/htdocs/admin/commande_fournisseur_dispatch_extrafields.php b/htdocs/admin/commande_fournisseur_dispatch_extrafields.php new file mode 100644 index 00000000000..9abc3dc23c7 --- /dev/null +++ b/htdocs/admin/commande_fournisseur_dispatch_extrafields.php @@ -0,0 +1,127 @@ + + * Copyright (C) 2003 Jean-Louis Bergamo + * Copyright (C) 2004-2013 Laurent Destailleur + * Copyright (C) 2012 Regis Houssin + * Copyright (C) 2012 Florian Henry + * Copyright (C) 2013 Philippe Grand + * Copyright (C) 2013 Florian Henry + * Copyright (C) 2015 Claudio Aschieri + * Copyright (C) 2018 Quentin Vial-Gouteyron + * + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/** + * \file htdocs/admin/commandefournisseurdispatch_extrafields.php + * \ingroup reception + * \brief Page to setup extra fields of reception + */ + +require '../main.inc.php'; +require_once DOL_DOCUMENT_ROOT.'/core/lib/reception.lib.php'; +require_once DOL_DOCUMENT_ROOT.'/core/class/extrafields.class.php'; + + +if (!$user->admin) + accessforbidden(); + +$langs->load("admin"); +$langs->load("other"); +$langs->load("receptions"); + +$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='commande_fournisseur_dispatch'; //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("Receptions"); + +llxHeader('',$langs->trans("ReceptionsSetup")); + +$linkback=''.$langs->trans("BackToModuleList").''; +print load_fiche_titre($langs->trans("ReceptionsSetup"),$linkback,'title_setup'); +print "
\n"; + +$head = reception_admin_prepare_head(); + +dol_fiche_head($head, 'attributeslines_reception', $langs->trans("Receptions"), -1, 'sending'); + +require DOL_DOCUMENT_ROOT.'/core/tpl/admin_extrafields_view.tpl.php'; + +dol_fiche_end(); + + +// Buttons +if ($action != 'create' && $action != 'edit') +{ + print '
'; + print "".$langs->trans("NewAttribute").""; + print "
"; +} + + +/* ************************************************************************** */ +/* */ +/* Creation of an optional field */ +/* */ +/* ************************************************************************** */ + +if ($action == 'create') +{ + print "
"; + print load_fiche_titre($langs->trans('NewAttribute')); + + require DOL_DOCUMENT_ROOT.'/core/tpl/admin_extrafields_add.tpl.php'; +} + +/* ************************************************************************** */ +/* */ +/* Edition of an optional field */ +/* */ +/* ************************************************************************** */ +if ($action == 'edit' && ! empty($attrname)) +{ + print "
"; + print load_fiche_titre($langs->trans("FieldEdition", $attrname)); + + require DOL_DOCUMENT_ROOT.'/core/tpl/admin_extrafields_edit.tpl.php'; +} + +llxFooter(); + +$db->close(); diff --git a/htdocs/admin/dict.php b/htdocs/admin/dict.php index 1b03101a2ae..7e59fa333bb 100644 --- a/htdocs/admin/dict.php +++ b/htdocs/admin/dict.php @@ -423,7 +423,7 @@ $tabcond[14]= (! empty($conf->product->enabled) && (! empty($conf->ecotax->enabl $tabcond[15]= true; $tabcond[16]= (! empty($conf->societe->enabled) && empty($conf->global->SOCIETE_DISABLE_PROSPECTS)); $tabcond[17]= (! empty($conf->deplacement->enabled) || ! empty($conf->expensereport->enabled)); -$tabcond[18]= ! empty($conf->expedition->enabled); +$tabcond[18]= ! empty($conf->expedition->enabled) || ! empty($conf->reception->enabled); $tabcond[19]= ! empty($conf->societe->enabled); $tabcond[20]= ! empty($conf->fournisseur->enabled); $tabcond[21]= ! empty($conf->propal->enabled); diff --git a/htdocs/admin/mails_templates.php b/htdocs/admin/mails_templates.php index 79614cbd3a0..aaafae90372 100644 --- a/htdocs/admin/mails_templates.php +++ b/htdocs/admin/mails_templates.php @@ -161,6 +161,7 @@ if ($conf->propal->enabled) $elementList['propal_send']=$langs->trans if ($conf->commande->enabled) $elementList['order_send']=$langs->trans('MailToSendOrder'); if ($conf->facture->enabled) $elementList['facture_send']=$langs->trans('MailToSendInvoice'); if ($conf->expedition->enabled) $elementList['shipping_send']=$langs->trans('MailToSendShipment'); +if ($conf->reception->enabled) $elementList['reception_send']=$langs->trans('MailToSendReception'); if ($conf->ficheinter->enabled) $elementList['fichinter_send']=$langs->trans('MailToSendIntervention'); if ($conf->supplier_proposal->enabled) $elementList['supplier_proposal_send']=$langs->trans('MailToSendSupplierRequestForQuotation'); if ($conf->fournisseur->enabled) $elementList['order_supplier_send']=$langs->trans('MailToSendSupplierOrder'); diff --git a/htdocs/admin/reception_extrafields.php b/htdocs/admin/reception_extrafields.php new file mode 100644 index 00000000000..dbfccb60773 --- /dev/null +++ b/htdocs/admin/reception_extrafields.php @@ -0,0 +1,127 @@ + + * Copyright (C) 2003 Jean-Louis Bergamo + * Copyright (C) 2004-2013 Laurent Destailleur + * Copyright (C) 2012 Regis Houssin + * Copyright (C) 2012 Florian Henry + * Copyright (C) 2013 Philippe Grand + * Copyright (C) 2015 Claudio Aschieri + * Copyright (C) 2018 Quentin Vial-Gouteyron + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/** + * \file htdocs/admin/reception_extrafields.php + * \ingroup reception + * \brief Page to setup extra fields of reception + */ + +require '../main.inc.php'; +require_once DOL_DOCUMENT_ROOT.'/core/lib/reception.lib.php'; +require_once DOL_DOCUMENT_ROOT.'/core/class/extrafields.class.php'; + + +if (!$user->admin) + accessforbidden(); + +$langs->load("admin"); +$langs->load("other"); +$langs->load("receptions"); +$langs->load("deliveries"); + + +$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='reception'; //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("Receptions"); + +llxHeader('',$langs->trans("ReceptionsSetup")); + +$linkback=''.$langs->trans("BackToModuleList").''; +print load_fiche_titre($langs->trans("ReceptionsSetup"),$linkback,'title_setup'); +print "
\n"; + +$head = reception_admin_prepare_head(); + +dol_fiche_head($head, 'attributes_reception', $langs->trans("Receptions"), -1, 'sending'); + +require DOL_DOCUMENT_ROOT.'/core/tpl/admin_extrafields_view.tpl.php'; + +dol_fiche_end(); + + +// Buttons +if ($action != 'create' && $action != 'edit') +{ + print '
'; + print "".$langs->trans("NewAttribute").""; + print "
"; +} + + +/* ************************************************************************** */ +/* */ +/* Creation of an optional field */ +/* */ +/* ************************************************************************** */ + +if ($action == 'create') +{ + print "
"; + print load_fiche_titre($langs->trans('NewAttribute')); + + require DOL_DOCUMENT_ROOT.'/core/tpl/admin_extrafields_add.tpl.php'; +} + +/* ************************************************************************** */ +/* */ +/* Edition of an optional field */ +/* */ +/* ************************************************************************** */ +if ($action == 'edit' && ! empty($attrname)) +{ + print "
"; + print load_fiche_titre($langs->trans("FieldEdition", $attrname)); + + require DOL_DOCUMENT_ROOT.'/core/tpl/admin_extrafields_edit.tpl.php'; +} + +llxFooter(); + +$db->close(); diff --git a/htdocs/admin/reception_setup.php b/htdocs/admin/reception_setup.php new file mode 100644 index 00000000000..4aa362932af --- /dev/null +++ b/htdocs/admin/reception_setup.php @@ -0,0 +1,520 @@ + + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/** + * \file htdocs/admin/confexped.php + * \ingroup produit + * \brief Page to setup reception module + */ + +require '../main.inc.php'; +require_once DOL_DOCUMENT_ROOT.'/core/lib/admin.lib.php'; +require_once DOL_DOCUMENT_ROOT.'/core/lib/reception.lib.php'; +require_once DOL_DOCUMENT_ROOT.'/core/lib/pdf.lib.php'; +require_once DOL_DOCUMENT_ROOT.'/reception/class/reception.class.php'; + +$langs->load("admin"); +$langs->load("receptions"); +$langs->load('other'); + + +if (!$user->admin) + accessforbidden(); + +$action=GETPOST('action','alpha'); +$value=GETPOST('value','alpha'); +$label = GETPOST('label','alpha'); +$scandir = GETPOST('scan_dir','alpha'); +$type='reception'; + + +/* + * Actions + */ + +if (! empty($conf->reception->enabled) && empty($conf->global->MAIN_SUBMODULE_RECEPTION)) +{ + // This option should always be set to on when module is on. + dolibarr_set_const($db, "MAIN_SUBMODULE_RECEPTION", "1",'chaine',0,'',$conf->entity); +} + +if (empty($conf->global->RECEPTION_ADDON_NUMBER)) +{ + $conf->global->RECEPTION_ADDON_NUMBER='mod_reception_beryl'; +} + + +/* + * Actions + */ + +include DOL_DOCUMENT_ROOT.'/core/actions_setmoduleoptions.inc.php'; + +if ($action == 'updateMask') +{ + $maskconst=GETPOST('maskconstreception','alpha'); + $maskvalue=GETPOST('maskreception','alpha'); + if (! empty($maskconst)) + $res = dolibarr_set_const($db,$maskconst,$maskvalue,'chaine',0,'',$conf->entity); + + if (isset($res)) + { + if ($res > 0) + setEventMessages($langs->trans("SetupSaved"), null, 'mesgs'); + else + setEventMessages($langs->trans("Error"), null, 'errors'); + } +} + +else if ($action == 'set_param') +{ + $freetext=GETPOST('RECEPTION_FREE_TEXT','none'); // No alpha here, we want exact string + $res = dolibarr_set_const($db, "RECEPTION_FREE_TEXT",$freetext,'chaine',0,'',$conf->entity); + if ($res <= 0) + { + $error++; + setEventMessages($langs->trans("Error"), null, 'errors'); + } + + $draft=GETPOST('RECEPTION_DRAFT_WATERMARK','alpha'); + $res = dolibarr_set_const($db, "RECEPTION_DRAFT_WATERMARK",trim($draft),'chaine',0,'',$conf->entity); + if ($res <= 0) + { + $error++; + setEventMessages($langs->trans("Error"), null, 'errors'); + } + + if (! $error) + { + setEventMessages($langs->trans("SetupSaved"), null, 'mesgs'); + } +} + +else if ($action == 'specimen') +{ + $modele=GETPOST('module','alpha'); + + $exp = new Reception($db); + $exp->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/reception/doc/pdf_".$modele.".modules.php",0); + if (file_exists($file)) + { + $filefound=1; + $classname = "pdf_".$modele; + break; + } + } + + if ($filefound) + { + require_once $file; + + $module = new $classname($db); + + if ($module->write_file($exp,$langs) > 0) + { + header("Location: ".DOL_URL_ROOT."/document.php?modulepart=reception&file=SPECIMEN.pdf"); + return; + } + else + { + setEventMessages($module->error, $module->errors, 'errors'); + dol_syslog($module->error, LOG_ERR); + } + } + else + { + setEventMessages($langs->trans("ErrorModuleNotFound"), null, 'errors'); + dol_syslog($langs->trans("ErrorModuleNotFound"), LOG_ERR); + } +} + +// Activate a model +else if ($action == 'set') +{ + $ret = addDocumentModel($value, $type, $label, $scandir); +} + +else if ($action == 'del') +{ + $ret = delDocumentModel($value, $type); + if ($ret > 0) + { + if ($conf->global->RECEPTION_ADDON_PDF == "$value") dolibarr_del_const($db, 'RECEPTION_ADDON_PDF',$conf->entity); + } +} + +// Set default model +else if ($action == 'setdoc') +{ + if (dolibarr_set_const($db, "RECEPTION_ADDON_PDF",$value,'chaine',0,'',$conf->entity)) + { + // La constante qui a ete lue en avant du nouveau set + // on passe donc par une variable pour avoir un affichage coherent + $conf->global->RECEPTION_ADDON_PDF = $value; + } + + // On active le modele + $ret = delDocumentModel($value, $type); + if ($ret > 0) + { + $ret = addDocumentModel($value, $type, $label, $scandir); + } +} + +else if ($action == 'setmodel') +{ + dolibarr_set_const($db, "RECEPTION_ADDON_NUMBER",$value,'chaine',0,'',$conf->entity); +} + + + + +/* + * View + */ + +$dirmodels=array_merge(array('/'),(array) $conf->modules_parts['models']); + +$form=new Form($db); + +llxHeader("",$langs->trans("ReceptionsSetup")); + +$linkback=''.$langs->trans("BackToModuleList").''; +print load_fiche_titre($langs->trans("ReceptionsSetup"),$linkback,'title_setup'); +print '
'; +$head = reception_admin_prepare_head(); + +dol_fiche_head($head, 'reception', $langs->trans("Receptions"), -1, 'sending'); + +// Reception numbering model + +print load_fiche_titre($langs->trans("ReceptionsNumberingModules")); + +print ''; +print ''; +print ''; +print ''; +print ''; +print ''; +print ''; +print "\n"; + +clearstatcache(); + +foreach ($dirmodels as $reldir) +{ + $dir = dol_buildpath($reldir."core/modules/reception/"); + + if (is_dir($dir)) + { + $handle = opendir($dir); + if (is_resource($handle)) + { + while (($file = readdir($handle))!==false) + { + if (substr($file, 0, 14) == 'mod_reception_' && substr($file, dol_strlen($file)-3, 3) == 'php') + { + $file = substr($file, 0, dol_strlen($file)-4); + + require_once $dir.$file.'.php'; + + $module = new $file; + + if ($module->isEnabled()) + { + // 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; + + print '\n"; + print ''; + + // Show example of numbering module + print ''."\n"; + + print ''; + + $reception=new Reception($db); + $reception->initAsSpecimen(); + + // Info + $htmltooltip=''; + $htmltooltip.=''.$langs->trans("Version").': '.$module->getVersion().'
'; + $nextval=$module->getNextValue($mysoc,$reception); + 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.'
'; + } else { + $htmltooltip.=$langs->trans($module->error).'
'; + } + } + + print ''; + + print ''; + } + } + } + closedir($handle); + } + } +} + +print '
'.$langs->trans("Name").''.$langs->trans("Description").''.$langs->trans("Example").''.$langs->trans("Status").''.$langs->trans("ShortInfo").'
'.$module->nom."'; + print $module->info(); + print ''; + $tmp=$module->getExample(); + if (preg_match('/^Error/',$tmp)) { + $langs->load("errors"); print '
'.$langs->trans($tmp).'
'; + } + elseif ($tmp=='NotConfigured') print $langs->trans($tmp); + else print $tmp; + print '
'; + if ($conf->global->RECEPTION_ADDON_NUMBER == "$file") + { + print img_picto($langs->trans("Activated"),'switch_on'); + } + else + { + print 'scandir.'&label='.urlencode($module->name).'">'; + print img_picto($langs->trans("Disabled"),'switch_off'); + print ''; + } + print ''; + print $form->textwithpicto('',$htmltooltip,1,0); + print '

'; + + +/* + * Documents models for Receptions Receipt + */ +print load_fiche_titre($langs->trans("ReceptionsReceiptModel")); + +// Defini tableau def de modele invoice +$type="reception"; +$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 ''; +print ''; +print ''; +print ''; +print ''; +print ''; +print ''; +print ''; +print "\n"; + +clearstatcache(); + +foreach ($dirmodels as $reldir) +{ + foreach (array('','/doc') as $valdir) + { + $dir = dol_buildpath($reldir."core/modules/reception".$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) + { + print ''; + + // Active + if (in_array($name, $def)) + { + print ''; + } + else + { + print '"; + } + + // Defaut + print ''; + + // Info + $htmltooltip = ''.$langs->trans("Name").': '.$module->name; + $htmltooltip.='
'.$langs->trans("Type").': '.($module->type?$module->type:$langs->trans("Unknown")); + if ($module->type == 'pdf') + { + $htmltooltip.='
'.$langs->trans("Width").'/'.$langs->trans("Height").': '.$module->page_largeur.'/'.$module->page_hauteur; + } + $htmltooltip.='

'.$langs->trans("FeaturesSupported").':'; + $htmltooltip.='
'.$langs->trans("Logo").': '.yn($module->option_logo,1,1); + $htmltooltip.='
'.$langs->trans("PaymentMode").': '.yn($module->option_modereg,1,1); + $htmltooltip.='
'.$langs->trans("PaymentConditions").': '.yn($module->option_condreg,1,1); + $htmltooltip.='
'.$langs->trans("MultiLanguage").': '.yn($module->option_multilang,1,1); + $htmltooltip.='
'.$langs->trans("WatermarkOnDraftOrders").': '.yn($module->option_draft_watermark,1,1); + + print ''; + + // Preview + print ''; + + print "\n"; + } + } + } + } + } + } + } +} + +print '
'.$langs->trans("Name").''.$langs->trans("Description").''.$langs->trans("Status").''.$langs->trans("Default").''.$langs->trans("ShortInfo").''.$langs->trans("Preview").'
'; + print (empty($module->name)?$name:$module->name); + print "\n"; + if (method_exists($module,'info')) print $module->info($langs); + else print $module->description; + print ''."\n"; + print ''; + print img_picto($langs->trans("Enabled"),'switch_on'); + print ''; + print ''."\n"; + print 'scandir.'&label='.urlencode($module->name).'">'.img_picto($langs->trans("Disabled"),'switch_off').''; + print "'; + if ($conf->global->RECEPTION_ADDON_PDF == $name) + { + print img_picto($langs->trans("Default"),'on'); + } + else + { + print 'scandir.'&label='.urlencode($module->name).'" alt="'.$langs->trans("Default").'">'.img_picto($langs->trans("Disabled"),'off').''; + } + print ''; + print $form->textwithpicto('',$htmltooltip,1,0); + print ''; + if ($module->type == 'pdf') + { + print 'scandir.'&label='.urlencode($module->name).'">'.img_object($langs->trans("Preview"),'reception').''; + } + else + { + print img_object($langs->trans("PreviewNotAvailable"),'generic'); + } + print '
'; +print '
'; + + +/* + * Other options + * + */ +/* +print load_fiche_titre($langs->trans("OtherOptions")); + +print '
'; +print ''; +print ''; + +print ""; +print ""; +print "\n"; +print ""; + +$substitutionarray=pdf_getSubstitutionArray($langs); +$substitutionarray['__(AnyTranslationKey)__']=$langs->trans("Translation"); +$htmltext = ''.$langs->trans("AvailableVariables").':
'; +foreach($substitutionarray as $key => $val) $htmltext.=$key.'
'; +$htmltext.='
'; + +print '\n"; + +print '\n"; +*/ +print '
".$langs->trans("Parameter")."
'; +print $form->textwithpicto($langs->trans("FreeLegalTextOnReceptions"), $langs->trans("AddCRIfTooLong").'

'.$htmltext).'
'; +$variablename='RECEPTION_FREE_TEXT'; +if (empty($conf->global->PDF_ALLOW_HTML_FOR_FREE_TEXT)) +{ + print ''; +} +else +{ + include_once DOL_DOCUMENT_ROOT.'/core/class/doleditor.class.php'; + $doleditor=new DolEditor($variablename, $conf->global->$variablename,'',80,'dolibarr_notes'); + print $doleditor->Create(); +} +print "
'; +print $form->textwithpicto($langs->trans("WatermarkOnDraftContractCards"), $htmltext).'
'; +print ''; +print "
'; + +print '
'; + +print '
'; + +llxFooter(); +$db->close(); diff --git a/htdocs/admin/stock.php b/htdocs/admin/stock.php index 2ce29bca165..86930956d1a 100644 --- a/htdocs/admin/stock.php +++ b/htdocs/admin/stock.php @@ -78,16 +78,22 @@ if($action) // Mode of stock increase if ($action == 'STOCK_CALCULATE_ON_SUPPLIER_BILL' || $action == 'STOCK_CALCULATE_ON_SUPPLIER_VALIDATE_ORDER' - || $action == 'STOCK_CALCULATE_ON_SUPPLIER_DISPATCH_ORDER') + || $action == 'STOCK_CALCULATE_ON_SUPPLIER_DISPATCH_ORDER' + || $action == 'STOCK_CALCULATE_ON_RECEPTION' + || $action == 'STOCK_CALCULATE_ON_RECEPTION_CLOSE') { //Use variable cause empty(GETPOST()) do not work with php version < 5.4 $valdispatch=GETPOST('STOCK_CALCULATE_ON_SUPPLIER_DISPATCH_ORDER','alpha'); $res=dolibarr_set_const($db, "STOCK_CALCULATE_ON_SUPPLIER_BILL", '','chaine',0,'',$conf->entity); $res=dolibarr_set_const($db, "STOCK_CALCULATE_ON_SUPPLIER_VALIDATE_ORDER", '','chaine',0,'',$conf->entity); + $res=dolibarr_set_const($db, "STOCK_CALCULATE_ON_RECEPTION", '','chaine',0,'',$conf->entity); + $res=dolibarr_set_const($db, "STOCK_CALCULATE_ON_RECEPTION_CLOSE", '','chaine',0,'',$conf->entity); $res=dolibarr_set_const($db, "STOCK_CALCULATE_ON_SUPPLIER_DISPATCH_ORDER", '','chaine',0,'',$conf->entity); if ($action == 'STOCK_CALCULATE_ON_SUPPLIER_BILL') $res=dolibarr_set_const($db, "STOCK_CALCULATE_ON_SUPPLIER_BILL", GETPOST('STOCK_CALCULATE_ON_SUPPLIER_BILL','alpha'),'chaine',0,'',$conf->entity); if ($action == 'STOCK_CALCULATE_ON_SUPPLIER_VALIDATE_ORDER') $res=dolibarr_set_const($db, "STOCK_CALCULATE_ON_SUPPLIER_VALIDATE_ORDER", GETPOST('STOCK_CALCULATE_ON_SUPPLIER_VALIDATE_ORDER','alpha'),'chaine',0,'',$conf->entity); + if ($action == 'STOCK_CALCULATE_ON_RECEPTION') $res=dolibarr_set_const($db, "STOCK_CALCULATE_ON_RECEPTION", GETPOST('STOCK_CALCULATE_ON_RECEPTION','alpha'),'chaine',0,'',$conf->entity); + if ($action == 'STOCK_CALCULATE_ON_RECEPTION_CLOSE') $res=dolibarr_set_const($db, "STOCK_CALCULATE_ON_RECEPTION_CLOSE", GETPOST('STOCK_CALCULATE_ON_RECEPTION_CLOSE','alpha'),'chaine',0,'',$conf->entity); if ($action == 'STOCK_CALCULATE_ON_SUPPLIER_DISPATCH_ORDER') $res=dolibarr_set_const($db, "STOCK_CALCULATE_ON_SUPPLIER_DISPATCH_ORDER", $valdispatch,'chaine',0,'',$conf->entity); if (empty($valdispatch)) { $res=dolibarr_set_const($db, "SUPPLIER_ORDER_USE_DISPATCH_STATUS", '','chaine',0,'',$conf->entity); @@ -307,25 +313,58 @@ else print "\n\n"; $found++; - -print ''; -print ''.$langs->trans("ReStockOnDispatchOrder").''; -print ''; -if (! empty($conf->fournisseur->enabled)) +if (!empty($conf->reception->enabled)) { - print "
"; + print ''; + print ''.$langs->trans("StockOnReception").''; + print ''; + + print ""; print ''; - print ""; - print $form->selectyesno("STOCK_CALCULATE_ON_SUPPLIER_DISPATCH_ORDER",$conf->global->STOCK_CALCULATE_ON_SUPPLIER_DISPATCH_ORDER,1,$disabled); + print ""; + print $form->selectyesno("STOCK_CALCULATE_ON_RECEPTION", $conf->global->STOCK_CALCULATE_ON_RECEPTION, 1, $disabled); print ''; print "
\n"; + + print "\n\n"; + $found++; + + +print ''; + print ''.$langs->trans("StockOnReceptionOnClosing").''; + print ''; + + print "
"; + print ''; + print ""; + print $form->selectyesno("STOCK_CALCULATE_ON_RECEPTION_CLOSE", $conf->global->STOCK_CALCULATE_ON_RECEPTION_CLOSE, 1, $disabled); + print ''; + print "
\n"; + + print "\n\n"; + $found++; } else { - print $langs->trans("ModuleMustBeEnabledFirst", $langs->transnoentitiesnoconv("Module40Name")); + print ''; + print ''.$langs->trans("ReStockOnDispatchOrder").''; + print ''; + if (! empty($conf->fournisseur->enabled)) + { + print "
"; + print ''; + print ""; + print $form->selectyesno("STOCK_CALCULATE_ON_SUPPLIER_DISPATCH_ORDER",$conf->global->STOCK_CALCULATE_ON_SUPPLIER_DISPATCH_ORDER,1,$disabled); + print ''; + print "
\n"; + } + else + { + print $langs->trans("ModuleMustBeEnabledFirst", $langs->transnoentitiesnoconv("Module40Name")); + } + print "\n\n"; + $found++; } -print "\n\n"; -$found++; /*if (! $found) { diff --git a/htdocs/admin/workflow.php b/htdocs/admin/workflow.php index 26b66136d76..109335ccbf3 100644 --- a/htdocs/admin/workflow.php +++ b/htdocs/admin/workflow.php @@ -28,7 +28,7 @@ require '../main.inc.php'; require_once DOL_DOCUMENT_ROOT.'/core/lib/admin.lib.php'; // Load translation files required by the page -$langs->loadLangs(array("admin","workflow","propal","workflow","orders","supplier_proposals")); +$langs->loadLangs(array("admin","workflow","propal","workflow","orders","supplier_proposals","receptions")); if (! $user->admin) accessforbidden(); @@ -86,6 +86,8 @@ $workflowcodes=array( 'WORKFLOW_ORDER_CLASSIFY_BILLED_SUPPLIER_PROPOSAL'=>array('family'=>'classify_supplier_proposal', 'position'=>60, 'enabled'=>'! empty($conf->supplier_proposal->enabled) && ! empty($conf->fournisseur->enabled)', 'picto'=>'propal','warning'=>''), // Automatic classification supplier order 'WORKFLOW_INVOICE_AMOUNT_CLASSIFY_BILLED_SUPPLIER_ORDER'=>array('family'=>'classify_supplier_order', 'position'=>62, 'enabled'=>'! empty($conf->fournisseur->enabled)', 'picto'=>'order','warning'=>''), + //Automatic classification reception + 'WORKFLOW_BILL_ON_RECEPTION'=>array('family'=>'classify_reception', 'position'=>30, 'enabled'=>'! empty($conf->reception->enabled) && ! empty($conf->fournisseur->enabled)', 'picto'=>'bill'), ); if (! empty($conf->modules_parts['workflow']) && is_array($conf->modules_parts['workflow'])) @@ -138,6 +140,7 @@ foreach($workflowcodes as $key => $params) if ($reg[1] == 'order') print ' - '.$langs->trans('Order'); if ($reg[1] == 'supplier_proposal') print ' - '.$langs->trans('SupplierProposal'); if ($reg[1] == 'supplier_order') print ' - '.$langs->trans('SupplierOrder'); + if ($reg[1] == 'reception') print ' - '.$langs->trans('Reception'); } else { diff --git a/htdocs/core/class/commonobject.class.php b/htdocs/core/class/commonobject.class.php index b7b4f79300f..31f4d32d2c4 100644 --- a/htdocs/core/class/commonobject.class.php +++ b/htdocs/core/class/commonobject.class.php @@ -1165,6 +1165,9 @@ abstract class CommonObject if($this->element=='shipping' && $this->origin_id != 0) { $id=$this->origin_id; $element='commande'; + } else if($this->element=='reception' && $this->origin_id != 0) { + $id=$this->origin_id; + $element='order_supplier'; } else { $id=$this->id; $element=$this->element; @@ -1409,6 +1412,7 @@ abstract class CommonObject // phpcs:enable if ($this->origin == 'shipping') $this->origin = 'expedition'; if ($this->origin == 'delivery') $this->origin = 'livraison'; + if ($this->origin == 'order_supplier') $this->origin = 'commandeFournisseur'; $origin = $this->origin; @@ -2917,7 +2921,7 @@ abstract class CommonObject if ($origin == 'order') $origin='commande'; if ($origin == 'invoice') $origin='facture'; if ($origin == 'invoice_template') $origin='facturerec'; - + if ($origin == 'supplierorder') $origin='order_supplier'; $this->db->begin(); $sql = "INSERT INTO ".MAIN_DB_PREFIX."element_element ("; @@ -3580,6 +3584,10 @@ abstract class CommonObject { if (empty($totalToShip)) $totalToShip=0; // Avoid warning because $totalToShip is '' $totalToShip+=$line->qty_shipped; // defined for shipment only + }else if ($line->element == 'commandefournisseurdispatch' && isset($line->qty)) + { + if (empty($totalToShip)) $totalToShip=0; + $totalToShip+=$line->qty; // defined for reception only } // Define qty, weight, volume, weight_units, volume_units @@ -3592,10 +3600,14 @@ abstract class CommonObject } $weight = $line->weight ? $line->weight : 0; + ($weight==0 && !empty($line->product->weight))? $weight=$line->product->weight: 0; $volume = $line->volume ? $line->volume : 0; + ($volume==0 && !empty($line->product->volume))? $volume=$line->product->volume: 0; $weight_units=$line->weight_units; + ($weight_units==0 && !empty($line->product->weight_units))? $weight_units=$line->product->weight_units: 0; $volume_units=$line->volume_units; + ($volume_units==0 && !empty($line->product->volume_units))? $volume_units=$line->product->volume_units: 0; $weightUnit=0; $volumeUnit=0; @@ -4192,6 +4204,11 @@ abstract class CommonObject $productstatic->id = $line->fk_product; $productstatic->ref = $line->ref; $productstatic->type = $line->fk_product_type; + if(empty($productstatic->ref)){ + $line->fetch_product(); + $productstatic = $line->product; + } + $this->tpl['label'].= $productstatic->getNomUrl(1); $this->tpl['label'].= ' - '.(! empty($line->label)?$line->label:$line->product_label); // Dates @@ -4208,6 +4225,7 @@ abstract class CommonObject }else { $this->tpl['label'].= ($line->label ? ' '.$line->label : ''); } + // Dates if ($line->product_type == 1 && ($date_start || $date_end)) { diff --git a/htdocs/core/class/conf.class.php b/htdocs/core/class/conf.class.php index 5bfa27eadbc..de39260e007 100644 --- a/htdocs/core/class/conf.class.php +++ b/htdocs/core/class/conf.class.php @@ -458,7 +458,11 @@ class Conf $this->global->STOCK_CALCULATE_ON_SHIPMENT_CLOSE=0; $this->global->STOCK_CALCULATE_ON_SUPPLIER_BILL=0; $this->global->STOCK_CALCULATE_ON_SUPPLIER_VALIDATE_ORDER=0; - $this->global->STOCK_CALCULATE_ON_SUPPLIER_DISPATCH_ORDER=1; + if(empty($this->reception->enabled))$this->global->STOCK_CALCULATE_ON_SUPPLIER_DISPATCH_ORDER=1; + else { + $this->global->STOCK_CALCULATE_ON_RECEPTION=1; + $this->global->STOCK_CALCULATE_ON_RECEPTION_CLOSE=0; + } } // conf->currency diff --git a/htdocs/core/class/html.form.class.php b/htdocs/core/class/html.form.class.php index 8c17f189502..40cc022f029 100644 --- a/htdocs/core/class/html.form.class.php +++ b/htdocs/core/class/html.form.class.php @@ -6377,6 +6377,10 @@ class Form $tplpath = 'expedition'; if (empty($conf->expedition->enabled)) continue; // Do not show if module disabled } + else if ($objecttype == 'reception') { + $tplpath = 'reception'; + if (empty($conf->reception->enabled)) continue; // Do not show if module disabled + } else if ($objecttype == 'delivery') { $tplpath = 'livraison'; if (empty($conf->expedition->enabled)) continue; // Do not show if module disabled diff --git a/htdocs/core/class/html.formfile.class.php b/htdocs/core/class/html.formfile.class.php index be9993a74b5..e283f6de4cf 100644 --- a/htdocs/core/class/html.formfile.class.php +++ b/htdocs/core/class/html.formfile.class.php @@ -414,6 +414,15 @@ class FormFile $modellist=ModelePDFExpedition::liste_modeles($this->db); } } + elseif ($modulepart == 'reception') + { + if (is_array($genallowed)) $modellist=$genallowed; + else + { + include_once DOL_DOCUMENT_ROOT.'/core/modules/reception/modules_reception.php'; + $modellist = ModelePdfReception::liste_modeles($this->db); + } + } elseif ($modulepart == 'livraison') { if (is_array($genallowed)) $modellist=$genallowed; diff --git a/htdocs/core/lib/fourn.lib.php b/htdocs/core/lib/fourn.lib.php index c251c5d03b9..4f3351a4d86 100644 --- a/htdocs/core/lib/fourn.lib.php +++ b/htdocs/core/lib/fourn.lib.php @@ -121,7 +121,7 @@ function ordersupplier_prepare_head($object) $h++; } - if (! empty($conf->stock->enabled) && ! empty($conf->global->STOCK_CALCULATE_ON_SUPPLIER_DISPATCH_ORDER)) + if (! empty($conf->stock->enabled) && (! empty($conf->global->STOCK_CALCULATE_ON_SUPPLIER_DISPATCH_ORDER) || !empty($conf->global->STOCK_CALCULATE_ON_RECEPTION) || !empty($conf->global->STOCK_CALCULATE_ON_RECEPTION_CLOSE))) { $langs->load("stocks"); $head[$h][0] = DOL_URL_ROOT.'/fourn/commande/dispatch.php?id='.$object->id; diff --git a/htdocs/core/lib/reception.lib.php b/htdocs/core/lib/reception.lib.php new file mode 100644 index 00000000000..0fc71c555dd --- /dev/null +++ b/htdocs/core/lib/reception.lib.php @@ -0,0 +1,129 @@ + + * Copyright (C) 2007 Rodolphe Quiedeville + * Copyright (C) 2010-2012 Regis Houssin + * Copyright (C) 2010 Juanjo Menent + * Copyright (C) 2015 Claudio Aschieri + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * or see http://www.gnu.org/ + */ + +/** + * \file htdocs/core/lib/reception.lib.php + * \brief Function for reception module + * \ingroup reception + */ + +/** + * Prepare array with list of tabs + * + * @param Reception $object Object related to tabs + * @return array Array of tabs to show + */ +function reception_prepare_head(Reception $object) +{ + global $db, $langs, $conf, $user; + + $langs->load("sendings"); + $langs->load("deliveries"); + + $h = 0; + $head = array(); + + $head[$h][0] = DOL_URL_ROOT."/reception/card.php?id=".$object->id; + $head[$h][1] = $langs->trans("ReceptionCard"); + $head[$h][2] = 'reception'; + $h++; + + + + if (empty($conf->global->MAIN_DISABLE_CONTACTS_TAB)) + { + $objectsrc = $object; + if ($object->origin == 'commande' && $object->origin_id > 0) + { + $objectsrc = new Commande($db); + $objectsrc->fetch($object->origin_id); + } + $nbContact = count($objectsrc->liste_contact(-1,'internal')) + count($objectsrc->liste_contact(-1,'external')); + $head[$h][0] = DOL_URL_ROOT."/reception/contact.php?id=".$object->id; + $head[$h][1] = $langs->trans("ContactsAddresses"); + if ($nbContact > 0) $head[$h][1].= ' '.$nbContact.''; + $head[$h][2] = 'contact'; + $h++; + } + + $nbNote = 0; + if (!empty($object->note_private)) $nbNote++; + if (!empty($object->note_public)) $nbNote++; + $head[$h][0] = DOL_URL_ROOT."/reception/note.php?id=".$object->id; + $head[$h][1] = $langs->trans("Notes"); + if ($nbNote > 0) $head[$h][1].= ' '.$nbNote.''; + $head[$h][2] = 'note'; + $h++; + + + + + + + complete_head_from_modules($conf,$langs,$object,$head,$h,'order','remove'); + + return $head; +} + +/** + * Return array head with list of tabs to view object informations. + * + * @return array head array with tabs + */ +function reception_admin_prepare_head() +{ + global $langs, $conf, $user; + $langs->load("receptions"); + + $h = 0; + $head = array(); + + $head[$h][0] = DOL_URL_ROOT."/admin/reception_setup.php"; + $head[$h][1] = $langs->trans("Reception"); + $head[$h][2] = 'reception'; + $h++; + + + if (! empty($conf->global->MAIN_SUBMODULE_RECEPTION)) + { + $head[$h][0] = DOL_URL_ROOT.'/admin/reception_extrafields.php'; + $head[$h][1] = $langs->trans("ExtraFields"); + $head[$h][2] = 'attributes_reception'; + $h++; + } + + if (! empty($conf->global->MAIN_SUBMODULE_RECEPTION)) + { + $head[$h][0] = DOL_URL_ROOT.'/admin/commande_fournisseur_dispatch_extrafields.php'; + $head[$h][1] = $langs->trans("ExtraFieldsLines"); + $head[$h][2] = 'attributeslines_reception'; + $h++; + } + + + + complete_head_from_modules($conf,$langs,null,$head,$h,'reception_admin','remove'); + + return $head; +} + + diff --git a/htdocs/core/menus/init_menu_auguria.sql b/htdocs/core/menus/init_menu_auguria.sql index 8792d8b762a..d16a846cf4c 100644 --- a/htdocs/core/menus/init_menu_auguria.sql +++ b/htdocs/core/menus/init_menu_auguria.sql @@ -132,6 +132,11 @@ insert into llx_menu (module, enabled, menu_handler, type, rowid, mainmenu, left insert into llx_menu (module, enabled, menu_handler, type, rowid, mainmenu, leftmenu, fk_menu, url, titre, level, langs, perms, target, usertype, position, entity) values ('', '$conf->expedition->enabled && $leftmenu=="sendings"', __HANDLER__, 'left', 1301__+MAX_llx_menu__, 'commercial', '', 1300__+MAX_llx_menu__, '/expedition/card.php?action=create2&leftmenu=sendings', 'NewSending', 1, 'sendings', '$user->rights->expedition->creer', '', 2, 0, __ENTITY__); insert into llx_menu (module, enabled, menu_handler, type, rowid, mainmenu, leftmenu, fk_menu, url, titre, level, langs, perms, target, usertype, position, entity) values ('', '$conf->expedition->enabled && $leftmenu=="sendings"', __HANDLER__, 'left', 1302__+MAX_llx_menu__, 'commercial', '', 1300__+MAX_llx_menu__, '/expedition/list.php?leftmenu=sendings', 'List', 1, 'sendings', '$user->rights->expedition->lire', '', 2, 1, __ENTITY__); insert into llx_menu (module, enabled, menu_handler, type, rowid, mainmenu, leftmenu, fk_menu, url, titre, level, langs, perms, target, usertype, position, entity) values ('', '$conf->expedition->enabled && $leftmenu=="sendings"', __HANDLER__, 'left', 1303__+MAX_llx_menu__, 'commercial', '', 1300__+MAX_llx_menu__, '/expedition/stats/index.php?leftmenu=sendings', 'Statistics', 1, 'sendings', '$user->rights->expedition->lire', '', 2, 2, __ENTITY__); +-- Product - Reception +insert into llx_menu (module, enabled, menu_handler, type, rowid, mainmenu, leftmenu, fk_menu, url, titre, level, langs, perms, target, usertype, position, entity) values ('', '$conf->reception->enabled', __HANDLER__, 'left', 1300__+MAX_llx_menu__, 'commercial', 'receptions', 3__+MAX_llx_menu__, '/reception/index.php?leftmenu=receptions', 'Receptions', 0, 'receptions', '$user->rights->reception->lire', '', 2, 6, __ENTITY__); +insert into llx_menu (module, enabled, menu_handler, type, rowid, mainmenu, leftmenu, fk_menu, url, titre, level, langs, perms, target, usertype, position, entity) values ('', '$conf->reception->enabled && $leftmenu=="receptions"', __HANDLER__, 'left', 1301__+MAX_llx_menu__, 'commercial', '', 1300__+MAX_llx_menu__, '/reception/card.php?action=create2&leftmenu=receptions', 'NewSending', 1, 'receptions', '$user->rights->reception->creer', '', 2, 0, __ENTITY__); +insert into llx_menu (module, enabled, menu_handler, type, rowid, mainmenu, leftmenu, fk_menu, url, titre, level, langs, perms, target, usertype, position, entity) values ('', '$conf->reception->enabled && $leftmenu=="receptions"', __HANDLER__, 'left', 1302__+MAX_llx_menu__, 'commercial', '', 1300__+MAX_llx_menu__, '/reception/list.php?leftmenu=receptions', 'List', 1, 'receptions', '$user->rights->reception->lire', '', 2, 1, __ENTITY__); +insert into llx_menu (module, enabled, menu_handler, type, rowid, mainmenu, leftmenu, fk_menu, url, titre, level, langs, perms, target, usertype, position, entity) values ('', '$conf->reception->enabled && $leftmenu=="receptions"', __HANDLER__, 'left', 1303__+MAX_llx_menu__, 'commercial', '', 1300__+MAX_llx_menu__, '/reception/stats/index.php?leftmenu=receptions', 'Statistics', 1, 'receptions', '$user->rights->reception->lire', '', 2, 2, __ENTITY__); -- Commercial - Proposals insert into llx_menu (module, enabled, menu_handler, type, rowid, mainmenu, leftmenu, fk_menu, url, titre, level, langs, perms, target, usertype, position, entity) values ('', '$conf->propal->enabled', __HANDLER__, 'left', 1100__+MAX_llx_menu__, 'commercial', 'propals', 5__+MAX_llx_menu__, '/comm/propal/index.php?leftmenu=propals', 'Prop', 0, 'propal', '$user->rights->propale->lire', '', 2, 4, __ENTITY__); diff --git a/htdocs/core/menus/standard/eldy.lib.php b/htdocs/core/menus/standard/eldy.lib.php index 8e9d4d1b5ed..fb6b25796d3 100644 --- a/htdocs/core/menus/standard/eldy.lib.php +++ b/htdocs/core/menus/standard/eldy.lib.php @@ -1406,7 +1406,7 @@ function print_left_eldy_menu($db,$menu_array_before,$menu_array_after,&$tabMenu } } - // Expeditions + // Shipments if (! empty($conf->expedition->enabled)) { $langs->load("sendings"); @@ -1420,6 +1420,19 @@ function print_left_eldy_menu($db,$menu_array_before,$menu_array_after,&$tabMenu } $newmenu->add("/expedition/stats/index.php?leftmenu=sendings", $langs->trans("Statistics"), 1, $user->rights->expedition->lire); } + + // Receptions + if (! empty($conf->reception->enabled)) + { + $langs->load("receptions"); + $newmenu->add("/reception/index.php?leftmenu=receptions", $langs->trans("Receptions"), 0, $user->rights->reception->lire, '', $mainmenu, 'receptions'); + $newmenu->add("/reception/card.php?action=create2&leftmenu=receptions", $langs->trans("NewReception"), 1, $user->rights->reception->creer); + $newmenu->add("/reception/list.php?leftmenu=receptions", $langs->trans("List"), 1, $user->rights->reception->lire); + if ($usemenuhider || empty($leftmenu) || $leftmenu=="receptions") $newmenu->add("/reception/list.php?leftmenu=receptions&viewstatut=0", $langs->trans("StatusReceptionDraftShort"), 2, $user->rights->reception->lire); + if ($usemenuhider || empty($leftmenu) || $leftmenu=="receptions") $newmenu->add("/reception/list.php?leftmenu=receptions&viewstatut=1", $langs->trans("StatusReceptionValidatedShort"), 2, $user->rights->reception->lire); + if ($usemenuhider || empty($leftmenu) || $leftmenu=="receptions") $newmenu->add("/reception/list.php?leftmenu=receptions&viewstatut=2", $langs->trans("StatusReceptionProcessedShort"), 2, $user->rights->reception->lire); + $newmenu->add("/reception/stats/index.php?leftmenu=receptions", $langs->trans("Statistics"), 1, $user->rights->reception->lire); + } } /* diff --git a/htdocs/core/modules/modReception.class.php b/htdocs/core/modules/modReception.class.php new file mode 100644 index 00000000000..be2e1cc8d62 --- /dev/null +++ b/htdocs/core/modules/modReception.class.php @@ -0,0 +1,266 @@ + + * + * 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 . + */ + +/** + * \defgroup reception Module reception + * \brief Module pour gerer les réceptions de produits + * \file htdocs/core/modules/modReception.class.php + * \ingroup reception + * \brief Fichier de description et activation du module Reception + */ + +include_once DOL_DOCUMENT_ROOT .'/core/modules/DolibarrModules.class.php'; + + +/** + * Class to describe and enable module Reception + */ +class modReception extends DolibarrModules +{ + + /** + * Constructor. Define names, constants, directories, boxes, permissions + * + * @param DoliDB $db Database handler + */ + function __construct($db) + { + global $conf, $user; + + $this->db = $db; + $this->numero = 104160; + + $this->family = "srm"; + $this->module_position = 40; + // Module label (no space allowed), used if translation string 'ModuleXXXName' not found (where XXX is value of numeric property 'numero' of module) + $this->name = preg_replace('/^mod/i','',get_class($this)); + $this->description = "Gestion des réceptions fournisseurs"; + + // Possible values for version are: 'development', 'experimental', 'dolibarr' or version + $this->version = 'development'; + + $this->const_name = 'MAIN_MODULE_'.strtoupper($this->name); + $this->special = 0; + $this->picto = "sending"; + + // Data directories to create when module is enabled + $this->dirs = array("/reception/receipt", + "/reception/receipt/temp", + "/doctemplates/reception" + ); + + // Config pages + $this->config_page_url = array("reception_setup.php"); + + // Dependencies + $this->depends = array("modFournisseur"); + $this->requiredby = array(); + $this->conflictwith = array(); + $this->langfiles = array('receptions'); + + // Constants + $this->const = array(); + $r=0; + + $this->const[$r][0] = "RECEPTION_ADDON_PDF"; + $this->const[$r][1] = "chaine"; + $this->const[$r][2] = "squille"; + $this->const[$r][3] = 'Nom du gestionnaire de generation des bons receptions en PDF'; + $this->const[$r][4] = 0; + $r++; + + $this->const[$r][0] = "RECEPTION_ADDON_NUMBER"; + $this->const[$r][1] = "chaine"; + $this->const[$r][2] = "mod_reception_beryl"; + $this->const[$r][3] = 'Name for numbering manager for receptions'; + $this->const[$r][4] = 0; + $r++; + + $this->const[$r][0] = "RECEPTION_ADDON_PDF_ODT_PATH"; + $this->const[$r][1] = "chaine"; + $this->const[$r][2] = "DOL_DATA_ROOT/doctemplates/receptions"; + $this->const[$r][3] = ""; + $this->const[$r][4] = 0; + $r++; + + $this->const[$r][0] = "MAIN_SUBMODULE_RECEPTION"; + $this->const[$r][1] = "chaine"; + $this->const[$r][2] = "1"; + $this->const[$r][3] = "Enable receptions"; + $this->const[$r][4] = 0; + $r++; + + // Boxes + $this->boxes = array(); + + // Permissions + $this->rights = array(); + $this->rights_class = 'reception'; + $r=0; + + $r++; + $this->rights[$r][0] = $this->numero.$r; + $this->rights[$r][1] = 'Lire les receptions'; + $this->rights[$r][2] = 'r'; + $this->rights[$r][3] = 0; + $this->rights[$r][4] = 'lire'; + + $r++; + $this->rights[$r][0] = $this->numero.$r; + $this->rights[$r][1] = 'Creer modifier les receptions'; + $this->rights[$r][2] = 'w'; + $this->rights[$r][3] = 0; + $this->rights[$r][4] = 'creer'; + + $r++; + $this->rights[$r][0] = $this->numero.$r; + $this->rights[$r][1] = 'Valider les receptions'; + $this->rights[$r][2] = 'd'; + $this->rights[$r][3] = 0; + $this->rights[$r][4] = 'reception_advance'; + $this->rights[$r][5] = 'validate'; + + $r++; + $this->rights[$r][0] = $this->numero.$r; // id de la permission + $this->rights[$r][1] = 'Envoyer les receptions aux clients'; // libelle de la permission + $this->rights[$r][2] = 'd'; // type de la permission (deprecie a ce jour) + $this->rights[$r][3] = 0; // La permission est-elle une permission par defaut + $this->rights[$r][4] = 'reception_advance'; + $this->rights[$r][5] = 'send'; + + $r++; + $this->rights[$r][0] = $this->numero.$r; + $this->rights[$r][1] = 'Exporter les receptions'; + $this->rights[$r][2] = 'r'; + $this->rights[$r][3] = 0; + $this->rights[$r][4] = 'reception'; + $this->rights[$r][5] = 'export'; + + $r++; + $this->rights[$r][0] = $this->numero.$r; + $this->rights[$r][1] = 'Supprimer les receptions'; + $this->rights[$r][2] = 'd'; + $this->rights[$r][3] = 0; + $this->rights[$r][4] = 'supprimer'; + + + // Menus + //------- + $this->menu = 1; // This module add menu entries. They are coded into menu manager. + + + // Exports + //-------- + $r=0; + + include_once DOL_DOCUMENT_ROOT.'/fourn/class/fournisseur.commande.class.php'; + $shipment=new CommandeFournisseur($this->db); + $contact_arrays=$shipment->liste_type_contact('external','',0,0,''); + if (is_array($contact_arrays) && count($contact_arrays)>0){ + $idcontacts=join(',',array_keys($shipment->liste_type_contact('external','',0,0,''))); + } else { + $idcontacts=0; + } + + + $r++; + $this->export_code[$r]=$this->rights_class.'_'.$r; + $this->export_label[$r]='Receptions'; // Translation key (used only if key ExportDataset_xxx_z not found) + $this->export_permission[$r]=array(array("reception","reception","export")); + $this->export_fields_array[$r]=array('s.rowid'=>"IdCompany",'s.nom'=>'ThirdParty','s.address'=>'Address','s.zip'=>'Zip','s.town'=>'Town','d.nom'=>'State','co.label'=>'Country','co.code'=>'CountryCode','s.phone'=>'Phone','s.siren'=>'ProfId1','s.siret'=>'ProfId2','s.ape'=>'ProfId3','s.idprof4'=>'ProfId4','s.idprof5'=>'ProfId5','s.idprof6'=>'ProfId6','c.rowid'=>"Id",'c.ref'=>"Ref",'c.ref_supplier'=>"RefSupplier",'c.fk_soc'=>"IdCompany",'c.date_creation'=>"DateCreation",'c.date_delivery'=>"DateDeliveryPlanned",'c.tracking_number'=>"TrackingNumber",'c.height'=>"Height",'c.width'=>"Width",'c.size'=>"Depth",'c.size_units'=>'SizeUnits','c.weight'=>"Weight",'c.weight_units'=>"WeightUnits",'c.fk_statut'=>'Status','c.note_public'=>"NotePublic",'ed.rowid'=>'LineId','ed.comment'=>'Description','ed.qty'=>"Qty",'p.rowid'=>'ProductId','p.ref'=>'ProductRef','p.label'=>'ProductLabel','p.weight'=>'ProductWeight','p.weight_units'=>'WeightUnits','p.volume'=>'ProductVolume','p.volume_units'=>'VolumeUnits'); + if ($idcontacts && ! empty($conf->global->RECEPTION_ADD_CONTACTS_IN_EXPORT)) $this->export_fields_array[$r]+=array('sp.rowid'=>'IdContact','sp.lastname'=>'Lastname','sp.firstname'=>'Firstname','sp.note_public'=>'NotePublic'); + //$this->export_TypeFields_array[$r]=array('s.rowid'=>"List:societe:nom",'s.nom'=>'Text','s.address'=>'Text','s.zip'=>'Text','s.town'=>'Text','co.label'=>'List:c_country:label:label','co.code'=>'Text','s.phone'=>'Text','s.siren'=>'Text','s.siret'=>'Text','s.ape'=>'Text','s.idprof4'=>'Text','c.ref'=>"Text",'c.ref_client'=>"Text",'c.date_creation'=>"Date",'c.date_commande'=>"Date",'c.amount_ht'=>"Numeric",'c.remise_percent'=>"Numeric",'c.total_ht'=>"Numeric",'c.total_ttc'=>"Numeric",'c.facture'=>"Boolean",'c.fk_statut'=>'Status','c.note_public'=>"Text",'c.date_livraison'=>'Date','ed.qty'=>"Text"); + $this->export_TypeFields_array[$r]=array('s.nom'=>'Text','s.address'=>'Text','s.zip'=>'Text','s.town'=>'Text','co.label'=>'List:c_country:label:label','co.code'=>'Text','s.phone'=>'Text','s.siren'=>'Text','s.siret'=>'Text','s.ape'=>'Text','s.idprof4'=>'Text','c.ref'=>"Text",'c.ref_supplier'=>"Text",'c.date_creation'=>"Date",'c.date_delivery'=>"Date",'c.tracking_number'=>"Numeric",'c.height'=>"Numeric",'c.width'=>"Numeric",'c.weight'=>"Numeric",'c.fk_statut'=>'Status','c.note_public'=>"Text",'ed.qty'=>"Numeric",'d.nom'=>'Text'); + $this->export_entities_array[$r]=array('s.rowid'=>"company",'s.nom'=>'company','s.address'=>'company','s.zip'=>'company','s.town'=>'company','d.nom'=>'company','co.label'=>'company','co.code'=>'company','s.fk_pays'=>'company','s.phone'=>'company','s.siren'=>'company','s.ape'=>'company','s.siret'=>'company','s.idprof4'=>'company','s.idprof5'=>'company','s.idprof6'=>'company','c.rowid'=>"reception",'c.ref'=>"reception",'c.ref_supplier'=>"reception",'c.fk_soc'=>"reception",'c.date_creation'=>"reception",'c.date_delivery'=>"reception",'c.tracking_number'=>'reception','c.height'=>"reception",'c.width'=>"reception",'c.size'=>'reception','c.size_units'=>'reception','c.weight'=>"reception",'c.weight_units'=>'reception','c.fk_statut'=>"reception",'c.note_public'=>"reception",'ed.rowid'=>'reception_line','ed.comment'=>'reception_line','ed.qty'=>"reception_line",'p.rowid'=>'product','p.ref'=>'product','p.label'=>'product','p.weight'=>'product','p.weight_units'=>'product','p.volume'=>'product','p.volume_units'=>'product'); + if ($idcontacts && ! empty($conf->global->RECEPTION_ADD_CONTACTS_IN_EXPORT)) $this->export_entities_array[$r]+=array('sp.rowid'=>'contact','sp.lastname'=>'contact','sp.firstname'=>'contact','sp.note_public'=>'contact'); + $this->export_dependencies_array[$r]=array('reception_line'=>'ed.rowid','product'=>'ed.rowid'); // To add unique key if we ask a field of a child to avoid the DISTINCT to discard them + if ($idcontacts && ! empty($conf->global->RECEPTION_ADD_CONTACTS_IN_EXPORT)) + { + $keyforselect='socpeople'; $keyforelement='contact'; $keyforaliasextra='extra3'; + include DOL_DOCUMENT_ROOT.'/core/extrafieldsinexport.inc.php'; + } + $keyforselect='reception'; $keyforelement='reception'; $keyforaliasextra='extra'; + include DOL_DOCUMENT_ROOT.'/core/extrafieldsinexport.inc.php'; + $keyforselect='commande_fournisseur_dispatch'; $keyforelement='reception_line'; $keyforaliasextra='extra2'; + include DOL_DOCUMENT_ROOT.'/core/extrafieldsinexport.inc.php'; + + $this->export_sql_start[$r]='SELECT DISTINCT '; + $this->export_sql_end[$r] =' FROM '.MAIN_DB_PREFIX.'reception as c'; + $this->export_sql_end[$r] .=' LEFT JOIN '.MAIN_DB_PREFIX.'reception_extrafields as extra ON c.rowid = extra.fk_object,'; + $this->export_sql_end[$r] .=' '.MAIN_DB_PREFIX.'societe as s'; + if(!$user->rights->societe->client->voir) $this->export_sql_end[$r] .=' LEFT JOIN '.MAIN_DB_PREFIX.'societe_commerciaux as sc ON sc.fk_soc = s.rowid'; + $this->export_sql_end[$r] .=' LEFT JOIN '.MAIN_DB_PREFIX.'c_departements as d ON s.fk_departement = d.rowid'; + $this->export_sql_end[$r] .=' LEFT JOIN '.MAIN_DB_PREFIX.'c_country as co ON s.fk_pays = co.rowid,'; + $this->export_sql_end[$r] .=' '.MAIN_DB_PREFIX.'commande_fournisseur_dispatch as ed'; + $this->export_sql_end[$r] .=' LEFT JOIN '.MAIN_DB_PREFIX.'commande_fournisseur_dispatch_extrafields as extra2 ON ed.rowid = extra2.fk_object'; + $this->export_sql_end[$r] .=' , '.MAIN_DB_PREFIX.'commande_fournisseurdet as cd'; + $this->export_sql_end[$r] .=' LEFT JOIN '.MAIN_DB_PREFIX.'product as p on cd.fk_product = p.rowid'; + if ($idcontacts && ! empty($conf->global->RECEPTION_ADD_CONTACTS_IN_EXPORT)) + { + $this->export_sql_end[$r] .=' LEFT JOIN '.MAIN_DB_PREFIX.'element_contact as ee ON ee.element_id = cd.fk_commande AND ee.fk_c_type_contact IN ('.$idcontacts.')'; + $this->export_sql_end[$r] .=' LEFT JOIN '.MAIN_DB_PREFIX.'socpeople as sp ON sp.rowid = ee.fk_socpeople'; + $this->export_sql_end[$r] .=' LEFT JOIN '.MAIN_DB_PREFIX.'socpeople_extrafields as extra3 ON sp.rowid = extra3.fk_object'; + } + $this->export_sql_end[$r] .=' WHERE c.fk_soc = s.rowid AND c.rowid = ed.fk_reception AND ed.fk_commandefourndet = cd.rowid'; + $this->export_sql_end[$r] .=' AND c.entity IN ('.getEntity('reception').')'; + if(!$user->rights->societe->client->voir) $this->export_sql_end[$r] .=' AND sc.fk_user = '.$user->id; + } + + + /** + * 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; + + // Permissions + $this->remove($options); + + //ODT template + $src=DOL_DOCUMENT_ROOT.'/install/doctemplates/reception/template_reception.odt'; + $dirodt=DOL_DATA_ROOT.'/doctemplates/reception'; + $dest=$dirodt.'/template_reception.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(); + + $sql = array( + "DELETE FROM ".MAIN_DB_PREFIX."document_model WHERE nom = '".$this->db->escape($this->const[0][2])."' AND type = 'reception' AND entity = ".$conf->entity, + "INSERT INTO ".MAIN_DB_PREFIX."document_model (nom, type, entity) VALUES('".$this->db->escape($this->const[0][2])."','reception',".$conf->entity.")", + ); + + return $this->_init($sql,$options); + } +} diff --git a/htdocs/core/modules/reception/doc/doc_generic_reception_odt.modules.php b/htdocs/core/modules/reception/doc/doc_generic_reception_odt.modules.php new file mode 100644 index 00000000000..4a19d82e449 --- /dev/null +++ b/htdocs/core/modules/reception/doc/doc_generic_reception_odt.modules.php @@ -0,0 +1,522 @@ + +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 3 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see . +* or see http://www.gnu.org/ +*/ + +/** + * \file htdocs/core/modules/reception/doc/doc_generic_reception_odt.modules.php + * \ingroup reception + * \brief File of class to build ODT documents for reception + */ + +require_once DOL_DOCUMENT_ROOT.'/core/modules/reception/modules_reception.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_reception_odt extends ModelePdfReception +{ + 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 = 'RECEPTION_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 RECEPTION_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.".
\n"; + $texte.= '
'; + $texte.= ''; + $texte.= ''; + $texte.= ''; + $texte.= ''; + + // List of directories area + $texte.= ''; + + $texte.= ''; + $texte.= ''; + + $texte.= '
'; + $texttitle=$langs->trans("ListOfDirectories"); + $listofdir=explode(',',preg_replace('/[\r\n]+/',',',trim($conf->global->RECEPTION_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.='
'.$langs->trans("FollowingSubstitutionKeysCanBeUsed").'
'; + $texthelp.=$langs->transnoentitiesnoconv("FullListOnOnlineDocumentation"); // This contains an url, we don't modify it + + $texte.= $form->textwithpicto($texttitle,$texthelp,1,'help','',1); + $texte.= '
'; + $texte.= ''; + $texte.= '
'; + $texte.= ''; + $texte.= '
'; + + // Scan directories + $nbofiles=count($listoffiles); + if (! empty($conf->global->RECEPTION_ADDON_PDF_ODT_PATH)) + { + $texte.=$langs->trans("NumberOfModelFilesFound").': '; + //$texte.=$nbofiles?'':''; + $texte.=count($listoffiles); + //$texte.=$nbofiles?'':''; + $texte.=''; + } + if ($nbofiles) + { + $texte.='
'; + $texte.= $langs->trans("ExampleOfDirectoriesForModelGen"); + $texte.= '
'; + $texte.= '
'; + + return $texte; + } + + /** + * Function to build a document on disk using the generic odt module. + * + * @param Reception $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->reception->dir_output."/reception") + { + // If $object is id instead of object + if (! is_object($object)) + { + $id = $object; + $object = new Reception($this->db); + $result=$object->fetch($id); + if ($result < 0) + { + dol_print_error($this->db,$object->error); + return -1; + } + } + + $dir = $conf->reception->dir_output."/reception"; + $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; + //$file=$dir.'/'.$newfiletmp.'.'.dol_print_date(dol_now(),'%Y%m%d%H%M%S').'.odt'; + // Get extension (ods or odt) + $newfileformat=substr($newfile, strrpos($newfile, '.')+1); + if ( ! empty($conf->global->MAIN_DOC_USE_TIMING)) + { + $format=$conf->global->MAIN_DOC_USE_TIMING; + if ($format == '1') $format='%Y%m%d%H%M%S'; + $filename=$newfiletmp.'-'.dol_print_date(dol_now(),$format).'.'.$newfileformat; + } + else + { + $filename=$newfiletmp.'.'.$newfileformat; + } + $file=$dir.'/'.$filename; + //print "newdir=".$dir; + //print "newfile=".$newfile; + //print "file=".$file; + //print "conf->societe->dir_temp=".$conf->societe->dir_temp; + + dol_mkdir($conf->reception->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->thirdparty; + } + else + { + $socobject=$object->thirdparty; + } + + // 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='RECEPTION_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->reception->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 of user info + $tmparray=$this->get_substitutionarray_user($user,$outputlangs); + //var_dump($tmparray); exit; + foreach($tmparray as $key=>$value) + { + try { + if (preg_match('/logo$/',$key)) // Image + { + //var_dump($value);exit; + if (file_exists($value)) $odfHandler->setImage($key, $value); + else $odfHandler->setVars($key, 'ErrorFileNotFound', true, 'UTF-8'); + } + else // Text + { + $odfHandler->setVars($key, $value, true, 'UTF-8'); + } + } + catch(OdfException $e) + { + } + } + // Make substitutions into odt of mysoc + $tmparray=$this->get_substitutionarray_mysoc($mysoc,$outputlangs); + //var_dump($tmparray); exit; + foreach($tmparray as $key=>$value) + { + try { + if (preg_match('/logo$/',$key)) // Image + { + //var_dump($value);exit; + if (file_exists($value)) $odfHandler->setImage($key, $value); + else $odfHandler->setVars($key, 'ErrorFileNotFound', true, 'UTF-8'); + } + else // Text + { + $odfHandler->setVars($key, $value, true, 'UTF-8'); + } + } + catch(OdfException $e) + { + } + } + // Make substitutions into odt of thirdparty + $tmparray=$this->get_substitutionarray_thirdparty($socobject,$outputlangs); + foreach($tmparray as $key=>$value) + { + try { + if (preg_match('/logo$/',$key)) // Image + { + if (file_exists($value)) $odfHandler->setImage($key, $value); + else $odfHandler->setVars($key, 'ErrorFileNotFound', true, 'UTF-8'); + } + else // Text + { + $odfHandler->setVars($key, $value, true, 'UTF-8'); + } + } + catch(OdfException $e) + { + } + } + // Replace tags of object + external modules + $tmparray=$this->get_substitutionarray_reception($object,$outputlangs); + complete_substitutions_array($tmparray, $outputlangs, $object); + // Call the ODTSubstitution hook + $parameters=array('odfHandler'=>&$odfHandler,'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_reception_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,'substitutionarray'=>&$tmparray); + $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; + } + } + $parameters=array('odfHandler'=>&$odfHandler,'file'=>$file,'object'=>$object,'outputlangs'=>$outputlangs,'substitutionarray'=>&$tmparray); + $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/reception/doc/index.html b/htdocs/core/modules/reception/doc/index.html new file mode 100644 index 00000000000..e69de29bb2d diff --git a/htdocs/core/modules/reception/doc/pdf_squille.modules.php b/htdocs/core/modules/reception/doc/pdf_squille.modules.php new file mode 100644 index 00000000000..ed885643a66 --- /dev/null +++ b/htdocs/core/modules/reception/doc/pdf_squille.modules.php @@ -0,0 +1,1044 @@ + + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * or see http://www.gnu.org/ + */ + +/** + * \file htdocs/core/modules/reception/doc/pdf_squille.modules.php + * \ingroup reception + * \brief Fichier de la classe permettant de generer les bordereaux envoi au modele Squille + */ + +require_once DOL_DOCUMENT_ROOT.'/core/modules/reception/modules_reception.php'; +require_once DOL_DOCUMENT_ROOT.'/core/lib/company.lib.php'; +require_once DOL_DOCUMENT_ROOT.'/core/lib/pdf.lib.php'; + + +/** + * Classe permettant de generer les borderaux envoi au modele Squille + */ +class pdf_squille extends ModelePdfReception +{ + var $emetteur; // Objet societe qui emet + + + /** + * Constructor + * + * @param DoliDB $db Database handler + */ + function __construct($db=0) + { + global $conf,$langs,$mysoc; + + $this->db = $db; + $this->name = "squille"; + $this->description = $langs->trans("DocumentModelStandardPDF"); + + $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; + + // Get source company + $this->emetteur=$mysoc; + if (! $this->emetteur->country_code) $this->emetteur->country_code=substr($langs->defaultlang,-2); // By default if not defined + + // Define position of columns + $this->posxdesc=$this->marge_gauche+1; + $this->posxweightvol=$this->page_largeur - $this->marge_droite - 78; + $this->posxqtyordered=$this->page_largeur - $this->marge_droite - 56; + $this->posxqtytoship=$this->page_largeur - $this->marge_droite - 28; + $this->posxpuht=$this->page_largeur - $this->marge_droite; + + if (!empty($conf->global->MAIN_PDF_RECEPTION_DISPLAY_AMOUNT_HT)) { + + $this->posxweightvol=$this->page_largeur - $this->marge_droite - 118; + $this->posxqtyordered=$this->page_largeur - $this->marge_droite - 96; + $this->posxqtytoship=$this->page_largeur - $this->marge_droite - 68; + $this->posxpuht=$this->page_largeur - $this->marge_droite - 40; + $this->posxtotalht=$this->page_largeur - $this->marge_droite - 20; + } + + $this->posxpicture=$this->posxweightvol - (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->posxweightvol-=20; + $this->posxpicture-=20; + $this->posxqtyordered-=20; + $this->posxqtytoship-=20; + } + + if (! empty($conf->global->RECEPTION_PDF_HIDE_ORDERED)) + { + $this->posxweightvol += ($this->posxqtytoship - $this->posxqtyordered); + $this->posxpicture += ($this->posxqtytoship - $this->posxqtyordered); + $this->posxqtyordered = $this->posxqtytoship; + } + } + + /** + * Function to build pdf onto disk + * + * @param Object $object Object reception to generate (or id if old method) + * @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,$conf,$langs,$hookmanager; + + $object->fetch_thirdparty(); + + 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("products"); + $outputlangs->load("propal"); + $outputlangs->load("deliveries"); + $outputlangs->load("receptions"); + $outputlangs->load("productbatch"); + + $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_SHIPMENT_WITH_PICTURE)) + { + $objphoto = new Product($this->db); + + 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,0,0,$objphoto,'product') . $object->lines[$i]->fk_product ."/photos/"; + $dir = $conf->product->dir_output.'/'.$pdir; + + $realpath=''; + + foreach ($objphoto->liste_photos($dir,1) as $key => $obj) + { + if (empty($conf->global->CAT_HIGH_QUALITY_IMAGES)) // If CAT_HIGH_QUALITY_IMAGES not defined, we use thumb if defined and then original photo + { + if ($obj['photo_vignette']) + { + $filename= $obj['photo_vignette']; + } + else + { + $filename=$obj['photo']; + } + } + else + { + $filename=$obj['photo']; + } + + $realpath = $dir.$filename; + break; + } + + if ($realpath) $realpatharray[$i]=$realpath; + } + } + + if (count($realpatharray) == 0) $this->posxpicture=$this->posxweightvol; + + if ($conf->reception->dir_output) + { + // Definition de $dir et $file + if ($object->specimen) + { + $dir = $conf->reception->dir_output; + $file = $dir . "/SPECIMEN.pdf"; + } + else + { + $rcpref = dol_sanitizeFileName($object->ref); + $dir = $conf->reception->dir_output."/" . $rcpref; + $file = $dir . "/" . $rcpref . ".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 + + // Set nblignes with the new facture lines content after hook + $nblignes = count($object->lines); + + $pdf=pdf_getInstance($this->format); + $default_font_size = pdf_getPDFFontSize($outputlangs); + $heightforinfotot = 8; // 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); + + if (method_exists($pdf,'AliasNbPages')) $pdf->AliasNbPages(); + + $pdf->SetTitle($outputlangs->convToOutputCharset($object->ref)); + $pdf->SetSubject($outputlangs->transnoentities("Reception")); + $pdf->SetCreator("Dolibarr ".DOL_VERSION); + $pdf->SetAuthor($outputlangs->convToOutputCharset($user->getFullName($outputlangs))); + $pdf->SetKeyWords($outputlangs->convToOutputCharset($object->ref)." ".$outputlangs->transnoentities("Reception")); + 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 + + // 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; + + // Incoterm + $height_incoterms = 0; + if ($conf->incoterm->enabled) + { + $desc_incoterms = $object->getIncotermsForPDF(); + if ($desc_incoterms) + { + $tab_top = 88; + + $pdf->SetFont('','', $default_font_size - 1); + $pdf->writeHTMLCell(190, 3, $this->posxdesc-1, $tab_top-1, dol_htmlentitiesbr($desc_incoterms), 0, 1); + $nexY = $pdf->GetY(); + $height_incoterms=$nexY-$tab_top; + + // Rect prend une longueur en 3eme param + $pdf->SetDrawColor(192,192,192); + $pdf->Rect($this->marge_gauche, $tab_top-1, $this->page_largeur-$this->marge_gauche-$this->marge_droite, $height_incoterms+1); + + $tab_top = $nexY+6; + $height_incoterms += 4; + } + } + + if (! empty($object->note_public) || ! empty($object->tracking_number)) + { + $tab_top = 88 + $height_incoterms; + $tab_top_alt = $tab_top; + + $pdf->SetFont('','B', $default_font_size - 2); + $pdf->writeHTMLCell(60, 4, $this->posxdesc-1, $tab_top-1, $outputlangs->transnoentities("TrackingNumber")." : " . $object->tracking_number, 0, 1, false, true, 'L'); + + $tab_top_alt = $pdf->GetY(); + //$tab_top_alt += 1; + + // Tracking number + if (! empty($object->tracking_number)) + { + $object->GetUrlTrackingStatus($object->tracking_number); + if (! empty($object->tracking_url)) + { + if ($object->reception_method_id > 0) + { + // Get code using getLabelFromKey + $code=$outputlangs->getLabelFromKey($this->db,$object->shipment_method_id,'c_shipment_mode','rowid','code'); + $label=''; + if ($object->tracking_url != $object->tracking_number) $label.=$outputlangs->trans("LinkToTrackYourPackage")."
"; + $label.=$outputlangs->trans("ReceptionMethod").": ".$outputlangs->trans("ReceptionMethod".strtoupper($code)); + //var_dump($object->tracking_url != $object->tracking_number);exit; + if ($object->tracking_url != $object->tracking_number) + { + $label.=" : "; + $label.=$object->tracking_url; + } + $pdf->SetFont('','B', $default_font_size - 2); + $pdf->writeHTMLCell(60, 4, $this->posxdesc-1, $tab_top_alt, $label, 0, 1, false, true, 'L'); + + $tab_top_alt = $pdf->GetY(); + } + } + } + + // Notes + if (! empty($object->note_public)) + { + $pdf->SetFont('','', $default_font_size - 1); // Dans boucle pour gerer multi-page + $pdf->writeHTMLCell(190, 3, $this->posxdesc-1, $tab_top_alt, dol_htmlentitiesbr($object->note_public), 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; + $fk_commandefourndet=0; + $totalOrdered=0; + // 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->posxweightvol-$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; + } + + // We suppose that a too long description is moved completely on next page + if ($pageposafter > $pageposbefore) { + $pdf->setPage($pageposafter); $curY = $tab_top_newpage; + } + + $pdf->SetFont('','', $default_font_size - 1); // On repositionne la police par defaut + + $pdf->SetXY($this->posxweightvol, $curY); + $weighttxt=''; + if ($object->lines[$i]->fk_product_type == 0 && $object->lines[$i]->product->weight) + { + $weighttxt=round($object->lines[$i]->product->weight * $object->lines[$i]->qty, 5).' '.measuring_units_string($object->lines[$i]->product->weight_units,"weight"); + } + $voltxt=''; + if ($object->lines[$i]->fk_product_type == 0 && $object->lines[$i]->product->volume) + { + $voltxt=round($object->lines[$i]->product->volume * $object->lines[$i]->qty, 5).' '.measuring_units_string($object->lines[$i]->product->volume_units?$object->lines[$i]->product->volume_units:0,"volume"); + } + + $pdf->writeHTMLCell($this->posxqtyordered - $this->posxweightvol + 2, 3, $this->posxweightvol - 1, $curY, $weighttxt.(($weighttxt && $voltxt)?'
':'').$voltxt, 0, 0, false, true, 'C'); + //$pdf->MultiCell(($this->posxqtyordered - $this->posxweightvol), 3, $weighttxt.(($weighttxt && $voltxt)?'
':'').$voltxt,'','C'); + + if (empty($conf->global->RECEPTION_PDF_HIDE_ORDERED)) + { + $pdf->SetXY($this->posxqtyordered, $curY); + if($object->lines[$i]->fk_commandefourndet!=$fk_commandefourndet){ + $pdf->MultiCell(($this->posxqtytoship - $this->posxqtyordered), 3, $object->lines[$i]->qty_asked,'','C'); + $totalOrdered+=$object->lines[$i]->qty_asked; + } + $fk_commandefourndet = $object->lines[$i]->fk_commandefourndet; + } + + $pdf->SetXY($this->posxqtytoship, $curY); + $pdf->MultiCell(($this->posxpuht - $this->posxqtytoship), 3, $object->lines[$i]->qty,'','C'); + + if(!empty($conf->global->MAIN_PDF_RECEPTION_DISPLAY_AMOUNT_HT)) + { + $pdf->SetXY($this->posxpuht, $curY); + $pdf->MultiCell(($this->posxtotalht - $this->posxpuht-1), 3, price($object->lines[$i]->subprice, 0, $outputlangs),'','R'); + + $pdf->SetXY($this->posxtotalht, $curY); + $pdf->MultiCell(($this->page_largeur - $this->marge_droite - $this->posxtotalht), 3, price($object->lines[$i]->total_ht, 0, $outputlangs),'','R'); + } + + $nexY+=3; + if ($weighttxt && $voltxt) $nexY+=2; + + // 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(80,80,80))); + //$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)); + } + + // 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 (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++; + } + } + + // 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 totaux + $posy=$this->_tableau_tot($pdf, $object, 0, $bottomlasttab, $outputlangs,$totalOrdered); + + // 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; // No error + } + else + { + $this->error=$langs->transnoentities("ErrorCanNotCreateDir",$dir); + return 0; + } + } + else + { + $this->error=$langs->transnoentities("ErrorConstantNotDefined","EXP_OUTPUTDIR"); + return 0; + } + } + + /** + * 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,$totalOrdered) + { + global $conf,$mysoc; + + $sign=1; + + $default_font_size = pdf_getPDFFontSize($outputlangs); + + $tab2_top = $posy; + $tab2_hl = 4; + $pdf->SetFont('','B', $default_font_size - 1); + + // Tableau total + $col1x = $this->posxweightvol-50; $col2x = $this->posxweightvol; + /*if ($this->page_largeur < 210) // To work with US executive format + { + $col2x-=20; + }*/ + if (empty($conf->global->RECEPTION_PDF_HIDE_ORDERED)) $largcol2 = ($this->posxqtyordered - $this->posxweightvol); + else $largcol2 = ($this->posxqtytoship - $this->posxweightvol); + + $useborder=0; + $index = 0; + + $totalWeighttoshow=''; + $totalVolumetoshow=''; + + // Load dim data + $tmparray=$object->getTotalWeightVolume(); + $totalWeight=$tmparray['weight']; + $totalVolume=$tmparray['volume']; + $totalToShip=$tmparray['toship']; + + + + + // Set trueVolume and volume_units not currently stored into database + if ($object->trueWidth && $object->trueHeight && $object->trueDepth) + { + $object->trueVolume= ($object->trueWidth * $object->trueHeight * $object->trueDepth); + $object->volume_units=$object->size_units * 3; + + } + + if ($totalWeight!='') $totalWeighttoshow=showDimensionInBestUnit($totalWeight, 0, "weight", $outputlangs); + if ($totalVolume!='') $totalVolumetoshow=showDimensionInBestUnit($totalVolume, 0, "volume", $outputlangs); + if ($object->trueWeight) $totalWeighttoshow=showDimensionInBestUnit($object->trueWeight, $object->weight_units, "weight", $outputlangs); + if ($object->trueVolume) $totalVolumetoshow=showDimensionInBestUnit($object->trueVolume, $object->volume_units, "volume", $outputlangs); + + $pdf->SetFillColor(255,255,255); + $pdf->SetXY($col1x, $tab2_top + $tab2_hl * $index); + $pdf->MultiCell($col2x-$col1x, $tab2_hl, $outputlangs->transnoentities("Total"), 0, 'L', 1); + + if (empty($conf->global->RECEPTION_PDF_HIDE_ORDERED)) + { + $pdf->SetXY($this->posxqtyordered, $tab2_top + $tab2_hl * $index); + $pdf->MultiCell($this->posxqtytoship - $this->posxqtyordered, $tab2_hl, $totalOrdered, 0, 'C', 1); + } + + $pdf->SetXY($this->posxqtytoship, $tab2_top + $tab2_hl * $index); + $pdf->MultiCell($this->posxpuht - $this->posxqtytoship, $tab2_hl, $totalToShip, 0, 'C', 1); + + if(!empty($conf->global->MAIN_PDF_RECEPTION_DISPLAY_AMOUNT_HT)) { + + $pdf->SetXY($this->posxpuht, $tab2_top + $tab2_hl * $index); + $pdf->MultiCell($this->posxtotalht - $this->posxpuht, $tab2_hl, '', 0, 'C', 1); + + $pdf->SetXY($this->posxtotalht, $tab2_top + $tab2_hl * $index); + $pdf->MultiCell($this->page_largeur - $this->marge_droite - $this->posxtotalht, $tab2_hl, price($object->total_ht, 0, $outputlangs), 0, 'C', 1); + + } + + // Total Weight + if ($totalWeighttoshow) + { + $pdf->SetXY($this->posxweightvol, $tab2_top + $tab2_hl * $index); + $pdf->MultiCell(($this->posxqtyordered - $this->posxweightvol), $tab2_hl, $totalWeighttoshow, 0, 'C', 1); + + $index++; + } + if ($totalVolumetoshow) + { + $pdf->SetXY($this->posxweightvol, $tab2_top + $tab2_hl * $index); + $pdf->MultiCell(($this->posxqtyordered - $this->posxweightvol), $tab2_hl, $totalVolumetoshow, 0, 'C', 1); + + $index++; + } + if (! $totalWeighttoshow && ! $totalVolumetoshow) $index++; + + $pdf->SetTextColor(0,0,0); + + 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 + * @param Translate $outputlangs Langs object + * @param int $hidetop Hide top bar of array + * @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); + + // 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 + + $pdf->SetDrawColor(128,128,128); + $pdf->SetFont('','', $default_font_size - 1); + + if (empty($hidetop)) + { + $pdf->line($this->marge_gauche, $tab_top+5, $this->page_largeur-$this->marge_droite, $tab_top+5); + + $pdf->SetXY($this->posxdesc-1, $tab_top+1); + $pdf->MultiCell($this->posxqtyordered - $this->posxdesc, 2, $outputlangs->transnoentities("Description"), '', 'L'); + } + + $pdf->line($this->posxweightvol-1, $tab_top, $this->posxweightvol-1, $tab_top + $tab_height); + if (empty($hidetop)) + { + $pdf->SetXY($this->posxweightvol-1, $tab_top+1); + $pdf->MultiCell(($this->posxqtyordered - $this->posxweightvol), 2, $outputlangs->transnoentities("WeightVolShort"),'','C'); + } + + if (empty($conf->global->RECEPTION_PDF_HIDE_ORDERED)) + { + $pdf->line($this->posxqtyordered-1, $tab_top, $this->posxqtyordered-1, $tab_top + $tab_height); + if (empty($hidetop)) + { + $pdf->SetXY($this->posxqtyordered-1, $tab_top+1); + $pdf->MultiCell(($this->posxqtytoship - $this->posxqtyordered), 2, $outputlangs->transnoentities("QtyOrdered"),'','C'); + } + } + + $pdf->line($this->posxqtytoship-1, $tab_top, $this->posxqtytoship-1, $tab_top + $tab_height); + if (empty($hidetop)) + { + $pdf->SetXY($this->posxqtytoship, $tab_top+1); + $pdf->MultiCell(($this->posxpuht - $this->posxqtytoship), 2, $outputlangs->transnoentities("QtyToReceive"),'','C'); + } + + if(!empty($conf->global->MAIN_PDF_RECEPTION_DISPLAY_AMOUNT_HT)) { + + $pdf->line($this->posxpuht-1, $tab_top, $this->posxpuht-1, $tab_top + $tab_height); + if (empty($hidetop)) + { + $pdf->SetXY($this->posxpuht-1, $tab_top+1); + $pdf->MultiCell(($this->posxtotalht - $this->posxpuht), 2, $outputlangs->transnoentities("PriceUHT"),'','C'); + } + + $pdf->line($this->posxtotalht-1, $tab_top, $this->posxtotalht-1, $tab_top + $tab_height); + if (empty($hidetop)) + { + $pdf->SetXY($this->posxtotalht-1, $tab_top+1); + $pdf->MultiCell(($this->page_largeur - $this->marge_droite - $this->posxtotalht), 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,$mysoc; + + $langs->load("orders"); + + $default_font_size = pdf_getPDFFontSize($outputlangs); + + pdf_pagehead($pdf,$outputlangs,$this->page_hauteur); + + // Show Draft Watermark + if($object->statut==0 && (! empty($conf->global->RECEPTION_DRAFT_WATERMARK)) ) + { + pdf_watermark($pdf,$outputlangs,$this->page_hauteur,$this->page_largeur,'mm',$conf->global->RECEPTION_DRAFT_WATERMARK); + } + + //Prepare la suite + $pdf->SetTextColor(0,0,60); + $pdf->SetFont('','B', $default_font_size + 3); + + $w = 110; + + $posy=$this->marge_haute; + $posx=$this->page_largeur-$this->marge_droite-$w; + + $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($w, 3, $outputlangs->transnoentities("ErrorLogoFileNotFound",$logo), 0, 'L'); + $pdf->MultiCell($w, 3, $outputlangs->transnoentities("ErrorGoToGlobalSetup"), 0, 'L'); + } + } + else + { + $text=$this->emetteur->name; + $pdf->MultiCell($w, 4, $outputlangs->convToOutputCharset($text), 0, 'L'); + } + + // Show barcode + if (! empty($conf->barcode->enabled)) + { + $posx=105; + } + else + { + $posx=$this->marge_gauche+3; + } + //$pdf->Rect($this->marge_gauche, $this->marge_haute, $this->page_largeur-$this->marge_gauche-$this->marge_droite, 30); + if (! empty($conf->barcode->enabled)) + { + // TODO Build code bar with function writeBarCode of barcode module for reception ref $object->ref + //$pdf->SetXY($this->marge_gauche+3, $this->marge_haute+3); + //$pdf->Image($logo,10, 5, 0, 24); + } + + $pdf->SetDrawColor(128,128,128); + if (! empty($conf->barcode->enabled)) + { + // TODO Build code bar with function writeBarCode of barcode module for reception ref $object->ref + //$pdf->SetXY($this->marge_gauche+3, $this->marge_haute+3); + //$pdf->Image($logo,10, 5, 0, 24); + } + + + $posx=$this->page_largeur - $w - $this->marge_droite; + $posy=$this->marge_haute; + + $pdf->SetFont('','B', $default_font_size + 2); + $pdf->SetXY($posx,$posy); + $pdf->SetTextColor(0,0,60); + $title=$outputlangs->transnoentities("ReceptionSheet"); + $pdf->MultiCell($w, 4, $title, '', 'R'); + + $pdf->SetFont('','', $default_font_size + 1); + + $posy+=5; + + $pdf->SetXY($posx,$posy); + $pdf->SetTextColor(0,0,60); + $pdf->MultiCell($w, 4, $outputlangs->transnoentities("RefReception") ." : ".$object->ref, '', 'R'); + + // Date planned delivery + if (! empty($object->date_delivery)) + { + $posy+=4; + $pdf->SetXY($posx,$posy); + $pdf->SetTextColor(0,0,60); + $pdf->MultiCell($w, 4, $outputlangs->transnoentities("DateDeliveryPlanned")." : ".dol_print_date($object->date_delivery,"day",false,$outputlangs,true), '', 'R'); + } + + if (! empty($object->thirdparty->code_fournisseur)) + { + $posy+=4; + $pdf->SetXY($posx,$posy); + $pdf->SetTextColor(0,0,60); + $pdf->MultiCell($w, 3, $outputlangs->transnoentities("SupplierCode")." : " . $outputlangs->transnoentities($object->thirdparty->code_fournisseur), '', 'R'); + } + + + $pdf->SetFont('','', $default_font_size + 3); + $Yoff=25; + + // Add list of linked orders + $origin = $object->origin; + $origin_id = $object->origin_id; + + // TODO move to external function + if (! empty($conf->fournisseur->enabled)) // commonly $origin='commande' + { + $outputlangs->load('orders'); + + $classname = 'CommandeFournisseur'; + $linkedobject = new $classname($this->db); + $result=$linkedobject->fetch($origin_id); + if ($result >= 0) + { + //$linkedobject->fetchObjectLinked() Get all linked object to the $linkedobject (commonly order) into $linkedobject->linkedObjects + + $pdf->SetFont('','', $default_font_size - 2); + $text=$linkedobject->ref; + if ($linkedobject->ref_client) $text.=' ('.$linkedobject->ref_client.')'; + $Yoff = $Yoff+8; + $pdf->SetXY($this->page_largeur - $this->marge_droite - $w,$Yoff); + $pdf->MultiCell($w, 2, $outputlangs->transnoentities("RefOrder") ." : ".$outputlangs->transnoentities($text), 0, 'R'); + $Yoff = $Yoff+3; + $pdf->SetXY($this->page_largeur - $this->marge_droite - $w,$Yoff); + $pdf->MultiCell($w, 2, $outputlangs->transnoentities("OrderDate")." : ".dol_print_date($linkedobject->date,"day",false,$outputlangs,true), 0, 'R'); + } + } + + if ($showaddress) + { + // Sender properties + $carac_emetteur=''; + // Add internal contact of origin element if defined + $arrayidcontact=array(); + if (! empty($origin) && is_object($object->$origin)) $arrayidcontact=$object->$origin->getIdContact('internal','SALESREPFOLL'); + if(empty($arrayidcontact)) $arrayidcontact=$object->$origin->getIdContact('internal','SHIPPING'); + if (count($arrayidcontact) > 0) + { + $object->fetch_user(reset($arrayidcontact)); + $carac_emetteur .= ($carac_emetteur ? "\n" : '' ).$outputlangs->transnoentities("Name").": ".$outputlangs->convToOutputCharset($object->user->getFullName($outputlangs))."\n"; + } + + $carac_emetteur .= pdf_build_address($outputlangs, $this->emetteur, $object->thirdparty); + + // Show sender + $posy=!empty($conf->global->MAIN_PDF_USE_ISO_LOCATION) ? 40 : 42; + $posx=$this->marge_gauche; + if (! empty($conf->global->MAIN_INVERT_SENDER_RECIPIENT)) $posx=$this->page_largeur-$this->marge_droite-80; + + $hautcadre=!empty($conf->global->MAIN_PDF_USE_ISO_LOCATION) ? 38 : 40; + $widthrecbox=!empty($conf->global->MAIN_PDF_USE_ISO_LOCATION) ? 92 : 82; + + // 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("Sender").":", 0, 'L'); + $pdf->SetXY($posx,$posy); + $pdf->SetFillColor(230,230,230); + $pdf->MultiCell($widthrecbox, $hautcadre, "", 0, 'R', 1); + $pdf->SetTextColor(0,0,60); + $pdf->SetFillColor(255,255,255); + + // If RECEPTION contact defined, we use it + $usecontact=false; + $arrayidcontact=$object->$origin->getIdContact('external','SHIPPING'); + + if (count($arrayidcontact) > 0) + { + $usecontact=true; + $result=$object->fetch_contact($arrayidcontact[0]); + } + + //Recipient name + // On peut utiliser le nom de la societe du contact + if ($usecontact && !empty($conf->global->MAIN_USE_COMPANY_NAME_OF_CONTACT)) { + $thirdparty = $object->contact; + } else { + $thirdparty = $object->thirdparty; + } + + $carac_client_name= pdfBuildThirdpartyName($thirdparty, $outputlangs); + + $carac_client=pdf_build_address($outputlangs,$this->emetteur,$object->thirdparty,(!empty($object->contact)?$object->contact:null),$usecontact,'targetwithdetails',$object); + + // Show recipient name + $pdf->SetXY($posx+2,$posy+3); + $pdf->SetFont('','B', $default_font_size); + $pdf->MultiCell($widthrecbox-2, 4, $carac_client_name, 0, 'L'); + + $posy = $pdf->getY(); + + // Show recipient information + $pdf->SetFont('','', $default_font_size - 1); + $pdf->SetXY($posx+2,$posy); + $pdf->MultiCell($widthrecbox-2, 4, $carac_client, 0, 'L'); + + // Show recipient + $widthrecbox=!empty($conf->global->MAIN_PDF_USE_ISO_LOCATION) ? 92 : 100; + if ($this->page_largeur < 210) $widthrecbox=84; // To work with US executive format + $posy=!empty($conf->global->MAIN_PDF_USE_ISO_LOCATION) ? 40 : 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("Recipient").":", 0, 'L'); + $pdf->Rect($posx, $posy, $widthrecbox, $hautcadre); + + + + // Show sender name + $pdf->SetXY($posx+2,$posy+3); + $pdf->SetFont('','B',$default_font_size); + $pdf->MultiCell($widthrecbox, 2, $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($widthrecbox, 4, $carac_emetteur, 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) + { + global $conf; + $showdetails=$conf->global->MAIN_GENERATE_DOCUMENTS_SHOW_FOOT_DETAILS; + return pdf_pagefoot($pdf,$outputlangs,'RECEPTION_FREE_TEXT',$this->emetteur,$this->marge_basse,$this->marge_gauche,$this->page_hauteur,$object,$showdetails,$hidefreetext); + } + +} + diff --git a/htdocs/core/modules/reception/index.html b/htdocs/core/modules/reception/index.html new file mode 100644 index 00000000000..e69de29bb2d diff --git a/htdocs/core/modules/reception/mod_reception_beryl.php b/htdocs/core/modules/reception/mod_reception_beryl.php new file mode 100644 index 00000000000..49369f91c87 --- /dev/null +++ b/htdocs/core/modules/reception/mod_reception_beryl.php @@ -0,0 +1,145 @@ + + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * or see http://www.gnu.org/ + */ + +/** + * \file htdocs/core/modules/reception/mod_reception_beryl.php + * \ingroup reception + * \brief File of class to manage shipments numbering rules Beryl + */ +require_once DOL_DOCUMENT_ROOT .'/core/modules/reception/modules_reception.php'; + +/** + * Class to manage reception numbering rules Beryl + */ +class mod_reception_beryl extends ModelNumRefReception +{ + var $version='dolibarr'; + var $prefix='RCP'; + var $error=''; + var $nom='Beryl'; + + + /** + * Return default description of numbering model + * + * @return string text description + */ + function info() + { + global $langs; + return $langs->trans("SimpleNumRefModelDesc",$this->prefix); + } + + + /** + * Return numbering example + * + * @return string Example + */ + function getExample() + { + return $this->prefix."0501-0001"; + } + + + /** + * Test if existing numbers make problems with numbering + * + * @return boolean false if conflit, true if ok + */ + function canBeActivated() + { + global $conf,$langs,$db; + + $coyymm=''; $max=''; + + $posindice=8; + $sql = "SELECT MAX(CAST(SUBSTRING(ref FROM ".$posindice.") AS SIGNED)) as max"; + $sql.= " FROM ".MAIN_DB_PREFIX."reception"; + $sql.= " WHERE ref LIKE '".$this->prefix."____-%'"; + $sql.= " AND entity = ".$conf->entity; + + $resql=$db->query($sql); + if ($resql) + { + $row = $db->fetch_row($resql); + if ($row) { $coyymm = substr($row[0],0,6); $max=$row[0]; } + } + if ($coyymm && ! preg_match('/'.$this->prefix.'[0-9][0-9][0-9][0-9]/i',$coyymm)) + { + $langs->load("errors"); + $this->error=$langs->trans('ErrorNumRefModel', $max); + return false; + } + + return true; + } + + /** + * Return next value + * + * @param Societe $objsoc Third party object + * @param Object $shipment Shipment object + * @return string Value if OK, 0 if KO + */ + function getNextValue($objsoc,$shipment) + { + global $db,$conf; + + $posindice=9; + $sql = "SELECT MAX(CAST(SUBSTRING(ref FROM ".$posindice.") AS SIGNED)) as max"; + $sql.= " FROM ".MAIN_DB_PREFIX."reception"; + $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("mod_reception_beryl::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("mod_reception_beryl::getNextValue return ".$this->prefix.$yymm."-".$num); + return $this->prefix.$yymm."-".$num; + } + + /** + * Return next free value + * + * @param Societe $objsoc Third party object + * @param Object $objforref Shipment object + * @return string Next free value + */ + function reception_get_num($objsoc,$objforref) + { + return $this->getNextValue($objsoc,$objforref); + } + +} diff --git a/htdocs/core/modules/reception/mod_reception_moonstone.php b/htdocs/core/modules/reception/mod_reception_moonstone.php new file mode 100644 index 00000000000..0c661e12cbe --- /dev/null +++ b/htdocs/core/modules/reception/mod_reception_moonstone.php @@ -0,0 +1,137 @@ + + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * or see http://www.gnu.org/ + */ + +/** + * \file htdocs/core/modules/reception/mod_reception_moonstone.php + * \ingroup reception + * \brief File of class to manage reception numbering rules Moonstone + */ + +require_once DOL_DOCUMENT_ROOT .'/core/modules/reception/modules_reception.php'; + +/** + * Class to manage reception numbering rules Moonstone + */ +class mod_reception_moonstone extends ModelNumRefReception +{ + var $version='dolibarr'; + var $error = ''; + var $nom = 'Moonstone'; + + /** + * Return default description of numbering model + * + * @return string text description + */ + function info() + { + global $conf,$langs; + + $langs->load("bills"); + + $form = new Form($this->db); + + $texte = $langs->trans('GenericNumRefModelDesc')."
\n"; + $texte.= '
'; + $texte.= ''; + $texte.= ''; + $texte.= ''; + $texte.= ''; + + $tooltip=$langs->trans("GenericMaskCodes",$langs->transnoentities("Reception"),$langs->transnoentities("Reception")); + $tooltip.=$langs->trans("GenericMaskCodes2"); + $tooltip.=$langs->trans("GenericMaskCodes3"); + $tooltip.=$langs->trans("GenericMaskCodes4a",$langs->transnoentities("Reception"),$langs->transnoentities("Reception")); + $tooltip.=$langs->trans("GenericMaskCodes5"); + + $texte.= ''; + $texte.= ''; + $texte.= ''; + $texte.= ''; + $texte.= '
'.$langs->trans("Mask").':'.$form->textwithpicto('',$tooltip,1,1).' 
'; + $texte.= '
'; + + return $texte; + } + + /** + * Return numbering example + * + * @return string Example + */ + function getExample() + { + global $conf,$langs,$mysoc; + + $old_code_client=$mysoc->code_client; + $old_code_type=$mysoc->typent_code; + $mysoc->code_client='CCCCCCCCCC'; + $mysoc->typent_code='TTTTTTTTTT'; + $numExample = $this->getNextValue($mysoc,''); + $mysoc->code_client=$old_code_client; + $mysoc->typent_code=$old_code_type; + + if (! $numExample) + { + $numExample = $langs->trans('NotConfigured'); + } + return $numExample; + } + + /** + * Return next value + * + * @param Societe $objsoc Third party object + * @param Object $reception Reception object + * @return string Value if OK, 0 if KO + */ + function getNextValue($objsoc,$reception) + { + global $db,$conf; + + require_once DOL_DOCUMENT_ROOT .'/core/lib/functions2.lib.php'; + + $mask=$conf->global->RECEPTION_MOONSTONE_MASK; + + if (! $mask) + { + $this->error='NotConfigured'; + return 0; + } + + $date = $reception->date_reception; + + $numFinal=get_next_value($db,$mask,'reception','ref','',$objsoc,$date); + + return $numFinal; + } + + /** + * Return next free value + * + * @param Societe $objsoc Third party object + * @param Object $objforref Reception object + * @return string Next free value + */ + function reception_get_num($objsoc,$objforref) + { + return $this->getNextValue($objsoc,$objforref); + } + +} + diff --git a/htdocs/core/modules/reception/modules_reception.php b/htdocs/core/modules/reception/modules_reception.php new file mode 100644 index 00000000000..609e5e315ad --- /dev/null +++ b/htdocs/core/modules/reception/modules_reception.php @@ -0,0 +1,136 @@ + + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * or see http://www.gnu.org/ + */ + +/** + * \file htdocs/core/modules/reception/modules_reception.php + * \ingroup reception + * \brief File that contains parent class for sending receipts models + * and parent class for sending receipts numbering models + */ + require_once DOL_DOCUMENT_ROOT.'/core/class/commondocgenerator.class.php'; + +/** + * Parent class of sending receipts models + */ +abstract class ModelePdfReception extends CommonDocGenerator +{ + var $error=''; + + + /** + * Return list of active generation modules + * + * @param DoliDB $db Database handler + * @param integer $maxfilenamelength Max length of value to show + * @return array List of templates + */ + static function liste_modeles($db,$maxfilenamelength=0) + { + global $conf; + + $type='reception'; + $liste=array(); + + include_once DOL_DOCUMENT_ROOT.'/core/lib/functions2.lib.php'; + $liste=getListOfModels($db,$type,$maxfilenamelength); + + return $liste; + } +} + + +/** + * Parent Class of numbering models of sending receipts references + */ +abstract class ModelNumRefReception +{ + var $error=''; + + /** Return if a model can be used or not + * + * @return boolean true if model can be used + */ + function isEnabled() + { + return true; + } + + /** + * Return default description of numbering model + * + * @return string text description + */ + function info() + { + global $langs; + $langs->load("reception"); + return $langs->trans("NoDescription"); + } + + /** + * Returns numbering example + * + * @return string Example + */ + function getExample() + { + global $langs; + $langs->load("reception"); + return $langs->trans("NoExample"); + } + + /** + * Test if existing numbers make problems with numbering + * + * @return boolean false if conflit, true if ok + */ + function canBeActivated() + { + return true; + } + + /** + * Returns next value assigned + * + * @param Societe $objsoc Third party object + * @param Object $shipment Shipment object + * @return string Value + */ + function getNextValue($objsoc, $shipment) + { + global $langs; + return $langs->trans("NotAvailable"); + } + + /** + * Returns version of the numbering model + * + * @return string Value + */ + 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"); + } +} diff --git a/htdocs/core/modules/supplier_invoice/pdf/pdf_canelle_reception.modules.php b/htdocs/core/modules/supplier_invoice/pdf/pdf_canelle_reception.modules.php new file mode 100644 index 00000000000..39a9ed44875 --- /dev/null +++ b/htdocs/core/modules/supplier_invoice/pdf/pdf_canelle_reception.modules.php @@ -0,0 +1,1223 @@ + + * Copyright (C) 2010-2014 Laurent Destailleur + * Copyright (C) 2015 Marcos García + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * or see http://www.gnu.org/ + */ + +/** + * \file htdocs/core/modules/supplier_invoice/pdf/pdf_canelle_reception.modules.php + * \ingroup fournisseur + * \brief Class file to generate the supplier invoices with the canelle_reception model + */ + +require_once DOL_DOCUMENT_ROOT.'/core/modules/supplier_invoice/modules_facturefournisseur.php'; +require_once DOL_DOCUMENT_ROOT.'/fourn/class/fournisseur.facture.class.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/pdf.lib.php'; + + +/** + * Class to generate the supplier invoices with the canelle_reception model + */ +class pdf_canelle_reception extends ModelePDFSuppliersInvoices +{ + 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"); + $langs->load("receptions"); + + $this->db = $db; + $this->name = "canelle_reception"; + $this->description = $langs->trans('SuppliersInvoiceModel'); + + // 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->franchise=!$mysoc->tva_assuj; + + // Defini position des colonnes + $this->posxdesc=$this->marge_gauche+1; + $this->posxreception=67; + $this->posxtva=112; + $this->posxup=126; + $this->posxqty=145; + $this->posxdiscount=162; + $this->postotalht=174; + + if($conf->global->PRODUCT_USE_UNITS) { + $this->posxreception=57; + $this->posxtva=99; + $this->posxup=114; + $this->posxqty=130; + $this->posxunit=147; + } + //if (! empty($conf->global->MAIN_GENERATE_DOCUMENTS_WITHOUT_VAT)) $this->posxtva=$this->posxup; + $this->posxpicture=$this->posxreception - (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->posxreception-=20; + $this->posxtva-=20; + $this->posxup-=20; + $this->posxqty-=20; + $this->posxunit-=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 FactureFournisseur $object Id of 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,$hookmanager; + + // Get source company + if (! is_object($object->thirdparty)) $object->fetch_thirdparty(); + if (! is_object($object->thirdparty)) $object->thirdparty=$mysoc; // If fetch_thirdparty fails, object has no socid (specimen) + $this->emetteur=$object->thirdparty; + if (! $this->emetteur->country_code) $this->emetteur->country_code=substr($langs->defaultlang,-2); // By default, if was not defined + + 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("products"); + + if ($conf->fournisseur->dir_output.'/facture') + { + $object->fetch_thirdparty(); + + $deja_regle = $object->getSommePaiement(); + //$amount_credit_notes_included = $object->getSumCreditNotesUsed(); + //$amount_deposits_included = $object->getSumDepositsUsed(); + + // Definition of $dir and $file + if ($object->specimen) + { + $dir = $conf->fournisseur->facture->dir_output; + $file = $dir . "/SPECIMEN.pdf"; + } + else + { + $objectref = dol_sanitizeFileName($object->ref); + $objectrefsupplier = dol_sanitizeFileName($object->ref_supplier); + $dir = $conf->fournisseur->facture->dir_output.'/'.get_exdir($object->id,2,0,0,$object,'invoice_supplier').$objectref; + $file = $dir . "/" . $objectref . ".pdf"; + if (! empty($conf->global->SUPPLIER_REF_IN_NAME)) $file = $dir . "/" . $objectref . ($objectrefsupplier?"_".$objectrefsupplier:"").".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 + + $nblignes = count($object->lines); + + $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("Invoice")); + $pdf->SetCreator("Dolibarr ".DOL_VERSION); + $pdf->SetAuthor($outputlangs->convToOutputCharset($user->getFullName($outputlangs))); + $pdf->SetKeyWords($outputlangs->convToOutputCharset($object->ref)." ".$outputlangs->transnoentities("Order")." ".$outputlangs->convToOutputCharset($object->thirdparty->name)); + 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) && empty($conf->global->PRODUCT_USE_UNITS)) + { + $this->posxpicture+=($this->postotalht - $this->posxdiscount); + $this->posxreception+=($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; + + // Incoterm + $height_incoterms = 0; + if ($conf->incoterm->enabled) + { + $desc_incoterms = $object->getIncotermsForPDF(); + if ($desc_incoterms) + { + $tab_top = 88; + + $pdf->SetFont('','', $default_font_size - 1); + $pdf->writeHTMLCell(190, 3, $this->posxdesc-1, $tab_top-1, dol_htmlentitiesbr($desc_incoterms), 0, 1); + $nexY = $pdf->GetY(); + $height_incoterms=$nexY-$tab_top; + + // Rect prend une longueur en 3eme param + $pdf->SetDrawColor(192,192,192); + $pdf->Rect($this->marge_gauche, $tab_top-1, $this->page_largeur-$this->marge_gauche-$this->marge_droite, $height_incoterms+1); + + $tab_top = $nexY+6; + $height_incoterms += 4; + } + } + + // Affiche notes + if (! empty($object->note_public)) + { + $tab_top = 88 + $height_incoterms; + + $pdf->SetFont('','', $default_font_size - 1); + $pdf->writeHTMLCell(190, 3, $this->posxdesc-1, $tab_top, dol_htmlentitiesbr($object->note_public), 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); + + $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(); + + // Description of product line + $curX = $this->posxdesc-1; + $showpricebeforepagebreak=1; + + $pdf->startTransaction(); + pdf_writelinedesc($pdf,$object,$i,$outputlangs,$this->posxreception-$curX,3,$curX,$curY,$hideref,$hidedesc,1); + $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->posxreception-$curX,4,$curX,$curY,$hideref,$hidedesc,1); + $posyafter=$pdf->GetY(); + 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(); + } + + $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 is 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 + + + // Reception + $object->fetchObjectLinked(); + $reception_content = ''; + if(!empty($object->linkedObjects['reception'])){ + if(count($object->linkedObjects['reception']) == 1){ + $reception = array_shift($object->linkedObjects['reception']); + $reception_content = $reception->ref; + if(!empty($reception->date_delivery))$reception_content .=' du '.date('d/m/Y', $reception->date_delivery); + }else { + $object->lines[$i]->fetchObjectLinked(); + if (!empty($object->lines[$i]->linkedObjects['reception'])) + { + $reception = array_shift($object->lines[$i]->linkedObjects['reception']); + $reception_content = $reception->ref; + if(!empty($reception->date_delivery))$reception_content .=' du '.date('d/m/Y', $reception->date_delivery); + + } + } + } + + + + $pdf->SetXY($this->posxreception-1, $curY); + $pdf->MultiCell($this->posxtva-$this->posxreception+1, 3, $reception_content, 0, 'C'); + + // 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-1, 3, $vat_rate, 0, 'R'); + } + + // Unit price before discount + $up_excl_tax = pdf_getlineupexcltax($object, $i, $outputlangs, $hidedetails); + $pdf->SetXY($this->posxup, $curY); + $pdf->MultiCell($this->posxqty-$this->posxup-0.8, 3, $up_excl_tax, 0, 'R', 0); + + // Unit price before discount + $up_excl_tax = pdf_getlineupexcltax($object, $i, $outputlangs, $hidedetails); + $pdf->SetXY($this->posxup, $curY); + $pdf->MultiCell($this->posxqty-$this->posxup-0.8, 3, $up_excl_tax, 0, 'R', 0); + + // Quantity + $pdf->SetXY($this->posxqty, $curY); + // Enough for 6 chars + if($conf->global->PRODUCT_USE_UNITS) + { + $pdf->MultiCell($this->posxunit-$this->posxqty-0.8, 4, $object->lines[$i]->qty, 0, 'R'); + } + else + { + $pdf->MultiCell($this->posxdiscount-$this->posxqty-0.8, 4, $object->lines[$i]->qty, 0, 'R'); + } + + // Unit + if($conf->global->PRODUCT_USE_UNITS) + { + $unit = pdf_getlineunit($object, $i, $outputlangs, $hidedetails, $hookmanager); + $pdf->SetXY($this->posxunit, $curY); + $pdf->MultiCell($this->posxdiscount-$this->posxunit-0.8, 4, $unit, 0, 'L'); + } + + // Discount on line + $pdf->SetXY($this->posxdiscount, $curY); + if ($object->lines[$i]->remise_percent) + { + $pdf->MultiCell($this->postotalht-$this->posxdiscount-1, 3, $object->lines[$i]->remise_percent."%", 0, 'R'); + } + + // Total HT line + $total_excl_tax = pdf_getlinetotalexcltax($object, $i, $outputlangs); + $pdf->SetXY($this->postotalht, $curY); + $pdf->MultiCell($this->page_largeur-$this->marge_droite-$this->postotalht, 3, $total_excl_tax, 0, 'R', 0); + + // Collecte des totaux par valeur de tva dans $this->tva["taux"]=total_tva + if ($conf->multicurrency->enabled && $object->multicurrency_tx != 1) $tvaligne=$object->lines[$i]->multicurrency_total_tva; + else $tvaligne=$object->lines[$i]->total_tva; + + $localtax1ligne=$object->lines[$i]->total_localtax1; + $localtax2ligne=$object->lines[$i]->total_localtax2; + + if (! empty($object->remise_percent)) $tvaligne-=($tvaligne*$object->remise_percent)/100; + + $vatrate=(string) $object->lines[$i]->tva_tx; + $localtax1rate=(string) $object->lines[$i]->localtax1_tx; + $localtax2rate=(string) $object->lines[$i]->localtax2_tx; + + if (($object->lines[$i]->info_bits & 0x01) == 0x01) $vatrate.='*'; + if (empty($this->tva[$vatrate])) $this->tva[$vatrate]=0; + if (empty($this->localtax1[$localtax1rate])) $this->localtax1[$localtax1rate]=0; + if (empty($this->localtax2[$localtax2rate])) $this->localtax2[$localtax2rate]=0; + $this->tva[$vatrate] += $tvaligne; + $this->localtax1[$localtax1rate]+=$localtax1ligne; + $this->localtax2[$localtax2rate]+=$localtax2ligne; + + // 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(80,80,80))); + //$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, $object->multicurrency_code); + } + else + { + $this->_tableau($pdf, $tab_top_newpage, $this->page_hauteur - $tab_top_newpage - $heightforfooter, 0, $outputlangs, 1, 1, $object->multicurrency_code); + } + $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, $object->multicurrency_code); + } + else + { + $this->_tableau($pdf, $tab_top_newpage, $this->page_hauteur - $tab_top_newpage - $heightforfooter, 0, $outputlangs, 1, 1, $object->multicurrency_code); + } + $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, $object->multicurrency_code); + $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, $object->multicurrency_code); + $bottomlasttab=$this->page_hauteur - $heightforinfotot - $heightforfreetext - $heightforfooter + 1; + } + + // Affiche zone totaux + $posy=$this->_tableau_tot($pdf, $object, $deja_regle, $bottomlasttab, $outputlangs); + + $amount_credit_notes_included=0; + $amount_deposits_included=0; + + 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","SUPPLIER_OUTPUTDIR"); + return 0; + } + } + + /** + * 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); + + $pdf->SetXY($this->marge_gauche, $tab2_top + 0); + // If France, show VAT mention if not applicable + if ($this->emetteur->country_code == 'FR' && $this->franchise == 1) + { + $pdf->MultiCell(100, $tab2_hl, $outputlangs->transnoentities("VATIsNotUsedForInvoice"), 0, 'L', 0); + } + + // 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); + + $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); + + $total_ht = ($conf->multicurrency->enabled && $object->mylticurrency_tx != 1 ? $object->multicurrency_total_ht : $object->total_ht); + $pdf->SetXY($col2x, $tab2_top + 0); + $pdf->MultiCell($largcol2, $tab2_hl, price($total_ht + $object->remise), 0, 'R', 1); + + // Show VAT by rates and total + $pdf->SetFillColor(248,248,248); + + 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->transcountrynoentities("TotalVAT",$mysoc->country_code).' '; + $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, 'R', 1); + } + } + if (! $this->atleastoneratenotnull) // If no vat at all + { + $index++; + $pdf->SetXY($col1x, $tab2_top + $tab2_hl * $index); + $pdf->MultiCell($col2x-$col1x, $tab2_hl, $outputlangs->transcountrynoentities("TotalVAT", $mysoc->country_code), 0, 'L', 1); + $pdf->SetXY($col2x, $tab2_top + $tab2_hl * $index); + $pdf->MultiCell($largcol2, $tab2_hl, price($object->total_tva), 0, 'R', 1); + + // Total LocalTax1 + if (! empty($conf->global->FACTURE_LOCAL_TAX1_OPTION) && $conf->global->FACTURE_LOCAL_TAX1_OPTION=='localtax1on' && $object->total_localtax1>0) + { + $index++; + $pdf->SetXY($col1x, $tab2_top + $tab2_hl * $index); + $pdf->MultiCell($col2x-$col1x, $tab2_hl, $outputlangs->transcountrynoentities("TotalLT1",$mysoc->country_code), 0, 'L', 1); + $pdf->SetXY($col2x, $tab2_top + $tab2_hl * $index); + $pdf->MultiCell($largcol2, $tab2_hl, price($object->total_localtax1), 0, 'R', 1); + } + + // Total LocalTax2 + if (! empty($conf->global->FACTURE_LOCAL_TAX2_OPTION) && $conf->global->FACTURE_LOCAL_TAX2_OPTION=='localtax2on' && $object->total_localtax2>0) + { + $index++; + $pdf->SetXY($col1x, $tab2_top + $tab2_hl * $index); + $pdf->MultiCell($col2x-$col1x, $tab2_hl, $outputlangs->transcountrynoentities("TotalLT2",$mysoc->country_code), 0, 'L', 1); + $pdf->SetXY($col2x, $tab2_top + $tab2_hl * $index); + $pdf->MultiCell($largcol2, $tab2_hl, price($object->total_localtax2), 0, 'R', 1); + } + } + else + { + //if (! empty($conf->global->FACTURE_LOCAL_TAX1_OPTION) && $conf->global->FACTURE_LOCAL_TAX1_OPTION=='localtax1on') + //{ + //Local tax 1 + foreach( $this->localtax1 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, 'R', 1); + } + } + //} + + //if (! empty($conf->global->FACTURE_LOCAL_TAX2_OPTION) && $conf->global->FACTURE_LOCAL_TAX2_OPTION=='localtax2on') + //{ + //Local tax 2 + foreach( $this->localtax2 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, 'R', 1); + } + } + //} + } + + $useborder=0; + + // 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); + + $total_ttc = ($conf->multicurrency->enabled && $object->multicurrency_tx != 1) ? $object->multicurrency_total_ttc : $object->total_ttc; + $pdf->SetXY($col2x, $tab2_top + $tab2_hl * $index); + $pdf->MultiCell($largcol2, $tab2_hl, price($total_ttc), $useborder, 'R', 1); + + $creditnoteamount=0; + $depositsamount=0; + //$creditnoteamount=$object->getSumCreditNotesUsed(); + //$depositsamount=$object->getSumDepositsUsed(); + //print "x".$creditnoteamount."-".$depositsamount;exit; + $resteapayer = price2num($total_ttc - $deja_regle - $creditnoteamount - $depositsamount, 'MT'); + 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, 'R', 0); + + $index++; + $pdf->SetTextColor(0,0,60); + $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), $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 Hide top bar of array + * @param int $hidebottom Hide bottom bar of array + * @param string $currency Currency code + * @return void + */ + function _tableau(&$pdf, $tab_top, $tab_height, $nexY, $outputlangs, $hidetop=0, $hidebottom=0, $currency='') + { + global $conf; + + // Force to disable hidetop and hidebottom + $hidebottom=0; + if ($hidetop) $hidetop=-1; + + $currency = !empty($currency) ? $currency : $conf->currency; + $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".$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'); + } + + $pdf->line($this->posxreception-1, $tab_top, $this->posxreception-1, $tab_top + $tab_height); + + if (empty($hidetop)) + { + $pdf->SetXY($this->posxreception-3, $tab_top+1); + $pdf->MultiCell($this->posxtva-$this->posxreception+3,2, $outputlangs->transnoentities("Reception"),'','C'); + } + + if (empty($conf->global->MAIN_GENERATE_DOCUMENTS_WITHOUT_VAT)) + { + $pdf->line($this->posxtva-1, $tab_top, $this->posxtva-1, $tab_top + $tab_height); + if (empty($hidetop)) + { + $pdf->SetXY($this->posxtva-3, $tab_top+1); + $pdf->MultiCell($this->posxup-$this->posxtva+3,2, $outputlangs->transnoentities("VAT"),'','C'); + } + } + + $pdf->line($this->posxup-1, $tab_top, $this->posxup-1, $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("PriceUHT"),'','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); + if($conf->global->PRODUCT_USE_UNITS) + { + $pdf->MultiCell($this->posxunit-$this->posxqty-1,2, $outputlangs->transnoentities("Qty"),'','C'); + } + else + { + $pdf->MultiCell($this->posxdiscount-$this->posxqty-1,2, $outputlangs->transnoentities("Qty"),'','C'); + } + } + + if($conf->global->PRODUCT_USE_UNITS) { + $pdf->line($this->posxunit - 1, $tab_top, $this->posxunit - 1, $tab_top + $tab_height); + if (empty($hidetop)) { + $pdf->SetXY($this->posxunit - 1, $tab_top + 1); + $pdf->MultiCell($this->posxdiscount - $this->posxunit - 1, 2, $outputlangs->transnoentities("Unit"), '', + '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("TotalHTShort"),'','C'); + } + + } + + /** + * Show payments table + * + * @param PDF $pdf Object PDF + * @param FactureFournisseur $object Object invoice + * @param int $posy Position y in PDF + * @param Translate $outputlangs Object langs for output + * @return int <0 if KO, >0 if OK + */ + function _tableau_versements(&$pdf, $object, $posy, $outputlangs) + { + global $conf; + + $sign=1; + if ($object->type == 2 && ! empty($conf->global->INVOICE_POSITIVE_CREDIT_NOTE)) $sign=-1; + + $tab3_posx = 120; + $tab3_top = $posy + 8; + $tab3_width = 80; + $tab3_height = 4; + if ($this->page_largeur < 210) // To work with US executive format + { + $tab3_posx -= 20; + } + + $default_font_size = pdf_getPDFFontSize($outputlangs); + + $pdf->SetFont('','', $default_font_size - 3); + $pdf->SetXY($tab3_posx, $tab3_top - 4); + $pdf->MultiCell(60, 3, $outputlangs->transnoentities("PaymentsAlreadyDone"), 0, 'L', 0); + + $pdf->line($tab3_posx, $tab3_top, $tab3_posx+$tab3_width, $tab3_top); + + $pdf->SetFont('','', $default_font_size - 4); + $pdf->SetXY($tab3_posx, $tab3_top); + $pdf->MultiCell(20, 3, $outputlangs->transnoentities("Payment"), 0, 'L', 0); + $pdf->SetXY($tab3_posx+21, $tab3_top); + $pdf->MultiCell(20, 3, $outputlangs->transnoentities("Amount"), 0, 'L', 0); + $pdf->SetXY($tab3_posx+40, $tab3_top); + $pdf->MultiCell(20, 3, $outputlangs->transnoentities("Type"), 0, 'L', 0); + $pdf->SetXY($tab3_posx+58, $tab3_top); + $pdf->MultiCell(20, 3, $outputlangs->transnoentities("Num"), 0, 'L', 0); + + $pdf->line($tab3_posx, $tab3_top-1+$tab3_height, $tab3_posx+$tab3_width, $tab3_top-1+$tab3_height); + + $y=0; + + $pdf->SetFont('','', $default_font_size - 4); + + // Loop on each deposits and credit notes included + // + + // Loop on each payment + $sql = "SELECT p.datep as date, p.fk_paiement as type, p.num_paiement as num, pf.amount as amount, pf.multicurrency_amount,"; + $sql.= " cp.code"; + $sql.= " FROM ".MAIN_DB_PREFIX."paiementfourn_facturefourn as pf, ".MAIN_DB_PREFIX."paiementfourn as p"; + $sql.= " LEFT JOIN ".MAIN_DB_PREFIX."c_paiement as cp ON p.fk_paiement = cp.id"; + $sql.= " WHERE pf.fk_paiementfourn = p.rowid and pf.fk_facturefourn = ".$object->id; + $sql.= " ORDER BY p.datep"; + $resql=$this->db->query($sql); + if ($resql) + { + $num = $this->db->num_rows($resql); + $i=0; + while ($i < $num) { + $y+=3; + $row = $this->db->fetch_object($resql); + + $pdf->SetXY($tab3_posx, $tab3_top+$y); + $pdf->MultiCell(20, 3, dol_print_date($this->db->jdate($row->date),'day',false,$outputlangs,true), 0, 'L', 0); + $pdf->SetXY($tab3_posx+21, $tab3_top+$y); + $pdf->MultiCell(20, 3, price($sign * (($conf->multicurrency->enabled && $object->multicurrency_tx != 1) ? $row->multicurrency_amount : $row->amount)), 0, 'L', 0); + $pdf->SetXY($tab3_posx+40, $tab3_top+$y); + $oper = $outputlangs->transnoentitiesnoconv("PaymentTypeShort" . $row->code); + + $pdf->MultiCell(20, 3, $oper, 0, 'L', 0); + $pdf->SetXY($tab3_posx+58, $tab3_top+$y); + $pdf->MultiCell(30, 3, $row->num, 0, 'L', 0); + + $pdf->line($tab3_posx, $tab3_top+$y+3, $tab3_posx+$tab3_width, $tab3_top+$y+3); + + $i++; + } + } + else + { + $this->error=$this->db->lasterror(); + return -1; + } + + } + + /** + * Show top header of page. + * + * @param PDF $pdf Object PDF + * @param FactureFournisseur $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 $langs,$conf,$mysoc; + + $outputlangs->load("main"); + $outputlangs->load("bills"); + $outputlangs->load("orders"); + $outputlangs->load("companies"); + $default_font_size = pdf_getPDFFontSize($outputlangs); + + // Do not add the BACKGROUND as this is for suppliers + //pdf_pagehead($pdf,$outputlangs,$this->page_hauteur); + + $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/'.$mysoc->logo; + if ($mysoc->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("ErrorGoToModuleSetup"), 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); + $pdf->MultiCell(100, 3, $outputlangs->transnoentities("SupplierInvoice")." ".$outputlangs->convToOutputCharset($object->ref), '', 'R'); + $posy+=1; + + if ($object->ref_supplier) + { + $posy+=4; + $pdf->SetFont('','B', $default_font_size); + $pdf->SetXY($posx,$posy); + $pdf->SetTextColor(0,0,60); + $pdf->MultiCell(100, 4, $outputlangs->transnoentities("RefSupplier")." : " . $object->ref_supplier, '', 'R'); + $posy+=1; + } + + $pdf->SetFont('','', $default_font_size - 1); + + if (! empty($conf->global->PDF_SHOW_PROJECT)) + { + $object->fetch_projet(); + if (! empty($object->project->ref)) + { + $posy+=4; + $pdf->SetXY($posx,$posy); + $langs->load("projects"); + $pdf->SetTextColor(0,0,60); + $pdf->MultiCell(100, 3, $outputlangs->transnoentities("Project")." : " . (empty($object->project->ref)?'':$object->projet->ref), '', 'R'); + } + } + + if ($object->date) + { + $posy+=4; + $pdf->SetXY($posx,$posy); + $pdf->SetTextColor(0,0,60); + $pdf->MultiCell(100, 4, $outputlangs->transnoentities("Date")." : " . dol_print_date($object->date,"day",false,$outputlangs,true), '', 'R'); + } + else + { + $posy+=4; + $pdf->SetXY($posx,$posy); + $pdf->SetTextColor(255,0,0); + $pdf->MultiCell(100, 4, strtolower($outputlangs->transnoentities("OrderToProcess")), '', 'R'); + } + + if ($object->thirdparty->code_fournisseur) + { + $posy+=4; + $pdf->SetXY($posx,$posy); + $pdf->SetTextColor(0,0,60); + $pdf->MultiCell(100, 3, $outputlangs->transnoentities("SupplierCode")." : " . $outputlangs->transnoentities($object->thirdparty->code_fournisseur), '', 'R'); + } + + $posy+=1; + $pdf->SetTextColor(0,0,60); + + // Show list of linked objects + $posy = pdf_writeLinkedObjects($pdf, $object, $outputlangs, $posx, $posy, 100, 3, 'R', $default_font_size); + + if ($showaddress) + { + // Sender properties + $carac_emetteur = pdf_build_address($outputlangs, $this->emetteur, $object->thirdparty); + + // 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 BILLING contact defined on invoice, we use it + $usecontact=false; + $arrayidcontact=$object->getIdContact('internal','BILLING'); + if (count($arrayidcontact) > 0) + { + $usecontact=true; + $result=$object->fetch_contact($arrayidcontact[0]); + } + + //Recipient name + // On peut utiliser le nom de la societe du contact + if ($usecontact && !empty($conf->global->MAIN_USE_COMPANY_NAME_OF_CONTACT)) { + $thirdparty = $object->contact; + } else { + $thirdparty = $mysoc; + } + + $carac_client_name= pdfBuildThirdpartyName($thirdparty, $outputlangs); + + $carac_client=pdf_build_address($outputlangs,$this->emetteur,$mysoc,((!empty($object->contact))?$object->contact:null),$usecontact,'target',$object); + + // 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'); + + $posy = $pdf->getY(); + + // Show recipient information + $pdf->SetFont('','', $default_font_size - 1); + $pdf->SetXY($posx+2,$posy); + $pdf->MultiCell($widthrecbox, 4, $carac_client, 0, 'L'); + } + } + + /** + * Show footer of page. Need this->emetteur object + * + * @param PDF $pdf PDF + * @param FactureFournisseur $object Object to show + * @param Translate $outputlangs Object lang for output + * @param int $hidefreetext 1=Hide free text + * @return int Return height of bottom margin including footer text + */ + function _pagefoot(&$pdf, $object, $outputlangs,$hidefreetext=0) + { + global $conf; + $showdetails=$conf->global->MAIN_GENERATE_DOCUMENTS_SHOW_FOOT_DETAILS; + return pdf_pagefoot($pdf,$outputlangs,'SUPPLIER_INVOICE_FREE_TEXT',$this->emetteur,$this->marge_basse,$this->marge_gauche,$this->page_hauteur,$object,$showdetails,$hidefreetext); + } + +} + diff --git a/htdocs/core/tpl/contacts.tpl.php b/htdocs/core/tpl/contacts.tpl.php index 9ae34602ef6..317a0607e3a 100644 --- a/htdocs/core/tpl/contacts.tpl.php +++ b/htdocs/core/tpl/contacts.tpl.php @@ -42,6 +42,7 @@ elseif ($module == 'invoice_supplier') { $permission=$user->rights->fournisseur- elseif ($module == 'project') { $permission=$user->rights->projet->creer; } elseif ($module == 'action') { $permission=$user->rights->agenda->myactions->create; } elseif ($module == 'shipping') { $permission=$user->rights->expedition->creer; } +elseif ($module == 'reception') { $permission=$user->rights->reception->creer; } elseif ($module == 'project_task') { $permission=$user->rights->projet->creer; } elseif (! isset($permission) && isset($user->rights->$module->creer)) { @@ -94,7 +95,7 @@ if ($permission) {
element == 'shipping' && is_object($objectsrc)) $tmpobject=$objectsrc; + if (($object->element == 'shipping' || $object->element == 'reception') && is_object($objectsrc)) $tmpobject=$objectsrc; echo $formcompany->selectTypeContact($tmpobject, '', 'type','internal'); ?>
 
@@ -133,7 +134,7 @@ if ($permission) {
element == 'shipping' && is_object($objectsrc)) $tmpobject=$objectsrc; + if (($object->element == 'shipping'|| $object->element == 'reception') && is_object($objectsrc)) $tmpobject=$objectsrc; $formcompany->selectTypeContact($tmpobject, '', 'type','external', 'position', 0, 'minwidth100imp'); ?>
 
@@ -161,7 +162,7 @@ if ($permission) { foreach($arrayofsource as $source) { $tmpobject=$object; - if ($object->element == 'shipping' && is_object($objectsrc)) $tmpobject=$objectsrc; + if (($object->element == 'shipping'|| $object->element == 'reception') && is_object($objectsrc)) $tmpobject=$objectsrc; $tab = $tmpobject->liste_contact(-1,$source); $num=count($tab); diff --git a/htdocs/core/triggers/interface_20_modWorkflow_WorkflowManager.class.php b/htdocs/core/triggers/interface_20_modWorkflow_WorkflowManager.class.php index 39b48cd2315..e203b9aad1e 100644 --- a/htdocs/core/triggers/interface_20_modWorkflow_WorkflowManager.class.php +++ b/htdocs/core/triggers/interface_20_modWorkflow_WorkflowManager.class.php @@ -315,6 +315,33 @@ class InterfaceWorkflowManager extends DolibarrTriggers } } } + // classify billed reception + if ($action == 'BILL_SUPPLIER_VALIDATE') + { + dol_syslog("Trigger '".$this->name."' for action '$action' launched by ".__FILE__.". id=".$object->id, LOG_DEBUG); + + if (! empty($conf->reception->enabled) && ! empty($conf->global->WORKFLOW_BILL_ON_RECEPTION)) + { + $object->fetchObjectLinked('','reception',$object->id,$object->element); + if (! empty($object->linkedObjects)) + { + $totalonlinkedelements=0; + foreach($object->linkedObjects['reception'] as $element) + { + if ($element->statut == Reception::STATUS_VALIDATED) $totalonlinkedelements += $element->total_ht; + } + dol_syslog("Amount of linked proposals = ".$totalonlinkedelements.", of invoice = ".$object->total_ht.", egality is ".($totalonlinkedelements == $object->total_ht), LOG_DEBUG); + if ($totalonlinkedelements == $object->total_ht) + { + foreach($object->linkedObjects['reception'] as $element) + { + $ret=$element->set_billed(); + } + } + } + return $ret; + } + } return 0; } diff --git a/htdocs/core/triggers/interface_50_modAgenda_ActionsAuto.class.php b/htdocs/core/triggers/interface_50_modAgenda_ActionsAuto.class.php index e8ae0a8e6c6..b055a8150df 100644 --- a/htdocs/core/triggers/interface_50_modAgenda_ActionsAuto.class.php +++ b/htdocs/core/triggers/interface_50_modAgenda_ActionsAuto.class.php @@ -401,6 +401,35 @@ class InterfaceActionsAuto extends DolibarrTriggers $object->actionmsg=$langs->transnoentities("ShippingSentByEMail",$object->ref); } + // Parameters $object->sendtoid defined by caller + //$object->sendtoid=0; + } elseif ($action == 'RECEPTION_VALIDATE') + { + $langs->load("agenda"); + $langs->load("other"); + $langs->load("receptions"); + + if (empty($object->actionmsg2)) $object->actionmsg2=$langs->transnoentities("ReceptionValidated",($object->newref?$object->newref:$object->ref)); + if (empty($object->actionmsg)) + { + $object->actionmsg=$langs->transnoentities("ReceptionValidated",($object->newref?$object->newref:$object->ref)); + } + + // Parameters $object->sendtoid defined by caller + //$object->sendtoid=0; + } + elseif ($action == 'RECEPTION_SENTBYMAIL') + { + $langs->load("agenda"); + $langs->load("other"); + $langs->load("receptions"); + + if (empty($object->actionmsg2)) $object->actionmsg2=$langs->transnoentities("ReceptionSentByEMail",$object->ref); + if (empty($object->actionmsg)) + { + $object->actionmsg=$langs->transnoentities("ReceptionSentByEMail",$object->ref); + } + // Parameters $object->sendtoid defined by caller //$object->sendtoid=0; } diff --git a/htdocs/exports/export.php b/htdocs/exports/export.php index 54a9b64cb8f..bdead78017c 100644 --- a/htdocs/exports/export.php +++ b/htdocs/exports/export.php @@ -67,6 +67,8 @@ $entitytoicon = array( 'category' => 'category', 'shipment' => 'sending', 'shipment_line'=> 'sending', + 'reception'=> 'sending', + 'reception_line'=> 'sending', 'expensereport'=> 'trip', 'expensereport_line'=> 'trip', 'holiday' => 'holiday', diff --git a/htdocs/fourn/class/fournisseur.commande.class.php b/htdocs/fourn/class/fournisseur.commande.class.php index 9f17e9afdf2..8dc10d82b3b 100644 --- a/htdocs/fourn/class/fournisseur.commande.class.php +++ b/htdocs/fourn/class/fournisseur.commande.class.php @@ -3146,6 +3146,54 @@ class CommandeFournisseur extends CommonOrder } return 0; } + + /** + * Load array this->receptions of lines of shipments with nb of products sent for each order line + * Note: For a dedicated shipment, the fetch_lines can be used to load the qty_asked and qty_shipped. This function is use to return qty_shipped cumulated for the order + * + * @param int $filtre_statut Filter on shipment status + * @return int <0 if KO, Nb of lines found if OK + */ + function loadReceptions($filtre_statut=-1) + { + $this->receptions = array(); + + $sql = 'SELECT cd.rowid, cd.fk_product,'; + $sql.= ' sum(cfd.qty) as qty'; + $sql.= ' FROM '.MAIN_DB_PREFIX.'commande_fournisseur_dispatch as cfd,'; + if ($filtre_statut >= 0) $sql.= ' '.MAIN_DB_PREFIX.'reception as e,'; + $sql.= ' '.MAIN_DB_PREFIX.'commande_fournisseurdet as cd'; + $sql.= ' WHERE'; + if ($filtre_statut >= 0) $sql.= ' cfd.fk_reception = e.rowid AND'; + $sql.= ' cfd.fk_commandefourndet = cd.rowid'; + $sql.= ' AND cd.fk_commande =' .$this->id; + if ($this->fk_product > 0) $sql.= ' AND cd.fk_product = '.$this->fk_product; + if ($filtre_statut >= 0) $sql.=' AND e.fk_statut >= '.$filtre_statut; + $sql.= ' GROUP BY cd.rowid, cd.fk_product'; + + + dol_syslog(get_class($this)."::loadReceptions", LOG_DEBUG); + $result = $this->db->query($sql); + if ($result) + { + $num = $this->db->num_rows($result); + $i = 0; + while ($i < $num) + { + $obj = $this->db->fetch_object($result); + empty($this->receptions[$obj->rowid])?$this->receptions[$obj->rowid] = $obj->qty:$this->receptions[$obj->rowid] += $obj->qty; + $i++; + } + $this->db->free(); + + return $num; + } + else + { + $this->error=$this->db->lasterror(); + return -1; + } + } } diff --git a/htdocs/fourn/class/fournisseur.commande.dispatch.class.php b/htdocs/fourn/class/fournisseur.commande.dispatch.class.php index c7b5d00c797..12e19e3315d 100644 --- a/htdocs/fourn/class/fournisseur.commande.dispatch.class.php +++ b/htdocs/fourn/class/fournisseur.commande.dispatch.class.php @@ -25,6 +25,7 @@ // Put here all includes required by your class file require_once DOL_DOCUMENT_ROOT."/core/class/commonobject.class.php"; +require_once DOL_DOCUMENT_ROOT."/reception/class/reception.class.php"; //require_once DOL_DOCUMENT_ROOT."/societe/class/societe.class.php"; //require_once DOL_DOCUMENT_ROOT."/product/class/product.class.php"; @@ -136,7 +137,7 @@ class CommandeFournisseurDispatch extends CommonObject */ function create($user, $notrigger=0) { - global $conf, $langs; + global $conf, $langs, $hookmanager; $error=0; // Clean parameters @@ -150,6 +151,8 @@ class CommandeFournisseurDispatch extends CommonObject if (isset($this->comment)) $this->comment=trim($this->comment); if (isset($this->status)) $this->status=trim($this->status); if (isset($this->batch)) $this->batch=trim($this->batch); + if(empty($this->datec)) $this->datec = dol_now(); + // Check parameters // Put here code to add control on parameters values @@ -167,7 +170,10 @@ class CommandeFournisseurDispatch extends CommonObject $sql.= "status,"; $sql.= "batch,"; $sql.= "eatby,"; - $sql.= "sellby"; + $sql.= "sellby,"; + $sql.= "fk_reception"; + + $sql.= ") VALUES ("; $sql.= " ".(! isset($this->fk_commande)?'NULL':"'".$this->db->escape($this->fk_commande)."'").","; $sql.= " ".(! isset($this->fk_product)?'NULL':"'".$this->db->escape($this->fk_product)."'").","; @@ -180,9 +186,10 @@ class CommandeFournisseurDispatch extends CommonObject $sql.= " ".(! isset($this->status)?'NULL':"'".$this->db->escape($this->status)."'").","; $sql.= " ".(! isset($this->batch)?'NULL':"'".$this->db->escape($this->batch)."'").","; $sql.= " ".(! isset($this->eatby) || dol_strlen($this->eatby)==0?'NULL':"'".$this->db->idate($this->eatby)."'").","; - $sql.= " ".(! isset($this->sellby) || dol_strlen($this->sellby)==0?'NULL':"'".$this->db->idate($this->sellby)."'").""; + $sql.= " ".(! isset($this->sellby) || dol_strlen($this->sellby)==0?'NULL':"'".$this->db->idate($this->sellby)."'").","; + $sql.= " ".(! isset($this->fk_reception)?'NULL':"'".$this->fk_reception."'").""; $sql.= ")"; - + $this->db->begin(); dol_syslog(__METHOD__, LOG_DEBUG); @@ -204,6 +211,24 @@ class CommandeFournisseurDispatch extends CommonObject //// End call triggers } } + + // Actions on extra fields (by external module or standard code) + // TODO le hook fait double emploi avec le trigger !! + $hookmanager->initHooks(array('commandefournisseurdispatchdao')); + $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++; + } + } + } // Commit or rollback if ($error) @@ -249,7 +274,8 @@ class CommandeFournisseurDispatch extends CommonObject $sql.= " t.tms,"; $sql.= " t.batch,"; $sql.= " t.eatby,"; - $sql.= " t.sellby"; + $sql.= " t.sellby,"; + $sql.= " t.fk_reception"; $sql.= " FROM ".MAIN_DB_PREFIX.$this->table_element." as t"; @@ -349,14 +375,21 @@ class CommandeFournisseurDispatch extends CommonObject if (! $error) { + if (empty($conf->global->MAIN_EXTRAFIELDS_DISABLED)) // For avoid conflicts if trigger used + { + if(empty($this->id) && !empty($this->rowid))$this->id=$this->rowid; + $result=$this->insertExtraFields(); + if ($result < 0) + { + $error++; + } + } + if (! $notrigger) { // Uncomment this and change MYOBJECT to your own tag if you - // want this action calls a trigger. - - //// Call triggers - //$result=$this->call_trigger('MYOBJECT_MODIFY',$user); - //if ($result < 0) { $error++; //Do also what you must do to rollback action if trigger fail} + $result=$this->call_trigger('LINERECEPTION_UPDATE',$user); + if ($result < 0) $error++; //// End call triggers } } diff --git a/htdocs/fourn/class/fournisseur.facture.class.php b/htdocs/fourn/class/fournisseur.facture.class.php index a4b89edff42..504a011997f 100644 --- a/htdocs/fourn/class/fournisseur.facture.class.php +++ b/htdocs/fourn/class/fournisseur.facture.class.php @@ -2902,6 +2902,8 @@ class SupplierInvoiceLine extends CommonObjectLine } } + $this->deleteObjectLinked(); + if (!$error) { // Supprime ligne $sql = 'DELETE FROM '.MAIN_DB_PREFIX.'facture_fourn_det '; diff --git a/htdocs/fourn/commande/card.php b/htdocs/fourn/commande/card.php index d0ba9e83656..c60b2dc2cbd 100644 --- a/htdocs/fourn/commande/card.php +++ b/htdocs/fourn/commande/card.php @@ -2364,7 +2364,8 @@ elseif (! empty($object->id)) } // Ship - if (! empty($conf->stock->enabled) && ! empty($conf->global->STOCK_CALCULATE_ON_SUPPLIER_DISPATCH_ORDER)) + + if (! empty($conf->stock->enabled) && (! empty($conf->global->STOCK_CALCULATE_ON_SUPPLIER_DISPATCH_ORDER) || !empty($conf->global->STOCK_CALCULATE_ON_RECEPTION) || !empty($conf->global->STOCK_CALCULATE_ON_RECEPTION_CLOSE))) { if (in_array($object->statut, array(3,4,5))) { if ($conf->fournisseur->enabled && $user->rights->fournisseur->commande->receptionner) { diff --git a/htdocs/fourn/commande/dispatch.php b/htdocs/fourn/commande/dispatch.php index 5b5ae13f86b..931942debb7 100644 --- a/htdocs/fourn/commande/dispatch.php +++ b/htdocs/fourn/commande/dispatch.php @@ -41,7 +41,7 @@ if (! empty($conf->projet->enabled)) require_once DOL_DOCUMENT_ROOT . '/projet/class/project.class.php'; // Load translation files required by the page -$langs->loadLangs(array("bills", "orders", "sendings", "companies", "deliveries", "products", "stocks")); +$langs->loadLangs(array("bills", "orders", "sendings", "companies", "deliveries", "products", "stocks","receptions")); if (! empty($conf->productbatch->enabled)) $langs->load('productbatch'); @@ -459,9 +459,12 @@ if ($id > 0 || ! empty($ref)) { $entrepot = new Entrepot($db); $listwarehouses = $entrepot->list_array(1); - print '
'; + if(empty($conf->reception->enabled))print ''; + else print ''; + print ''; - print ''; + if(empty($conf->reception->enabled))print ''; + else print ''; print '
'; print ''; @@ -723,6 +726,7 @@ if ($id > 0 || ! empty($ref)) { // modified by hook if (empty($reshook)) { + if(empty($conf->reception->enabled)){ print $langs->trans("Comment").' : '; print 'trans("DispatchSupplierOrder", $object->ref); @@ -730,8 +734,10 @@ if ($id > 0 || ! empty($ref)) { print '" class="flat">
'; print ' '.$checkboxlabel; + } + empty($conf->reception->enabled)?$dispatchBt=$langs->trans("DispatchVerb"):$dispatchBt=$langs->trans("Receive"); - print '
'; @@ -757,9 +763,11 @@ if ($id > 0 || ! empty($ref)) { $sql = "SELECT p.ref, p.label,"; $sql .= " e.rowid as warehouse_id, e.ref as entrepot,"; $sql .= " cfd.rowid as dispatchlineid, cfd.fk_product, cfd.qty, cfd.eatby, cfd.sellby, cfd.batch, cfd.comment, cfd.status, cfd.datec"; + if($conf->reception->enabled)$sql.=" ,cfd.fk_reception, r.date_delivery"; $sql .= " FROM " . MAIN_DB_PREFIX . "product as p,"; $sql .= " " . MAIN_DB_PREFIX . "commande_fournisseur_dispatch as cfd"; $sql .= " LEFT JOIN " . MAIN_DB_PREFIX . "entrepot as e ON cfd.fk_entrepot = e.rowid"; + if($conf->reception->enabled)$sql.=" LEFT JOIN " . MAIN_DB_PREFIX . "reception as r ON cfd.fk_reception = r.rowid"; $sql .= " WHERE cfd.fk_commande = " . $object->id; $sql .= " AND cfd.fk_product = p.rowid"; $sql .= " ORDER BY cfd.rowid ASC"; @@ -778,7 +786,11 @@ if ($id > 0 || ! empty($ref)) { print '
'; print ''; + if($conf->reception->enabled)print ''; + print ''; + print ''; + print ''; if (! empty($conf->productbatch->enabled)) { print ''; print ''; @@ -788,19 +800,34 @@ if ($id > 0 || ! empty($ref)) { print ''; print ''; print ''; - if (! empty($conf->global->SUPPLIER_ORDER_USE_DISPATCH_STATUS)) + if (! empty($conf->global->SUPPLIER_ORDER_USE_DISPATCH_STATUS) || !empty($conf->reception->enabled)) print ''; - print ''; + print "\n"; while ( $i < $num ) { $objp = $db->fetch_object($resql); print ""; + + if(!empty($conf->reception->enabled) ){ + print '"; + } + print '\n"; + print ''; + print ''; if (! empty($conf->productbatch->enabled)) { print ''; @@ -820,10 +847,10 @@ if ($id > 0 || ! empty($ref)) { print ''; // Comment - print ''; + print ''; // Status - if (! empty($conf->global->SUPPLIER_ORDER_USE_DISPATCH_STATUS)) { + if (! empty($conf->global->SUPPLIER_ORDER_USE_DISPATCH_STATUS) && empty($reception->rowid)) { print ''; + }else if(!empty($conf->reception->enabled)){ + print ''; + print ''; + print ''; + + print "\n"; diff --git a/htdocs/fourn/facture/card.php b/htdocs/fourn/facture/card.php index 5f3c51a6e38..67ae1dc623a 100644 --- a/htdocs/fourn/facture/card.php +++ b/htdocs/fourn/facture/card.php @@ -863,6 +863,27 @@ if (empty($reshook)) $object->origin = GETPOST('origin'); $object->origin_id = GETPOST('originid'); + + require_once DOL_DOCUMENT_ROOT.'/'.$element.'/class/'.$subelement.'.class.php'; + $classname = ucfirst($subelement); + if ($classname == 'Fournisseur.commande') $classname='CommandeFournisseur'; + $objectsrc = new $classname($db); + $objectsrc->fetch($originid); + $objectsrc->fetch_thirdparty(); + + if ($object->origin == 'reception') + { + $objectsrc->fetchObjectLinked(); + + if (count($objectsrc->linkedObjectsIds['order_supplier']) > 0) + { + foreach ($objectsrc->linkedObjectsIds['order_supplier'] as $key => $value) + { + $object->linked_objects['order_supplier'] = $value; + } + } + } + $id = $object->create($user); // Add lines @@ -926,7 +947,9 @@ if (empty($reshook)) 0, $lines[$i]->array_options, $lines[$i]->fk_unit, - $lines[$i]->id + $lines[$i]->id, + 0, + $lines[$i]->ref_supplier ); if ($result < 0) @@ -1630,8 +1653,7 @@ if ($action == 'create') $projectid = $originid; $element = 'projet'; } - else if (in_array($element,array('order_supplier'))) - { + // For compatibility if ($element == 'order') { $element = $subelement = 'commande'; @@ -1678,7 +1700,6 @@ if ($action == 'create') // Replicate extrafields $objectsrc->fetch_optionals($originid); $object->array_options = $objectsrc->array_options; - } } else { @@ -1739,7 +1760,7 @@ if ($action == 'create') print ''; // Ref supplier - print ''; + print ''; print ''; // Type invoice @@ -2022,6 +2043,7 @@ if ($action == 'create') print ''; print ''; @@ -2032,6 +2054,8 @@ if ($action == 'create') print ''; print ''; diff --git a/htdocs/install/mysql/data/llx_c_action_trigger.sql b/htdocs/install/mysql/data/llx_c_action_trigger.sql index 601e6c2aac3..d8123d3ca8f 100644 --- a/htdocs/install/mysql/data/llx_c_action_trigger.sql +++ b/htdocs/install/mysql/data/llx_c_action_trigger.sql @@ -81,6 +81,8 @@ insert into llx_c_action_trigger (code,label,description,elementtype,rang) value insert into llx_c_action_trigger (code,label,description,elementtype,rang) values ('SHIPPING_VALIDATE','Shipping validated','Executed when a shipping is validated','shipping',20); insert into llx_c_action_trigger (code,label,description,elementtype,rang) values ('SHIPPING_SENTBYMAIL','Shipping sent by mail','Executed when a shipping is sent by mail','shipping',21); insert into llx_c_action_trigger (code,label,description,elementtype,rang) values ('SHIPPING_DELETE','Shipping sent is deleted','Executed when a shipping is deleted','shipping',21); +insert into llx_c_action_trigger (code,label,description,elementtype,rang) values ('RECEPTION_VALIDATE','Reception validated','Executed when a reception is validated','reception',22); +insert into llx_c_action_trigger (code,label,description,elementtype,rang) values ('RECEPTION_SENTBYMAIL','Reception sent by mail','Executed when a reception is sent by mail','reception',22); insert into llx_c_action_trigger (code,label,description,elementtype,rang) values ('MEMBER_VALIDATE','Member validated','Executed when a member is validated','member',22); insert into llx_c_action_trigger (code,label,description,elementtype,rang) values ('MEMBER_SENTBYMAIL','Mails sent from member card','Executed when you send email from member card','member',23); insert into llx_c_action_trigger (code,label,description,elementtype,rang) values ('MEMBER_SUBSCRIPTION_CREATE','Member subscribtion recorded','Executed when a member subscribtion is deleted','member',24); diff --git a/htdocs/install/mysql/tables/llx_commande_fournisseur_dispatch.key.sql b/htdocs/install/mysql/tables/llx_commande_fournisseur_dispatch.key.sql index ba7c02280ec..369a25f2b32 100644 --- a/htdocs/install/mysql/tables/llx_commande_fournisseur_dispatch.key.sql +++ b/htdocs/install/mysql/tables/llx_commande_fournisseur_dispatch.key.sql @@ -16,4 +16,6 @@ -- -- =================================================================== -ALTER TABLE llx_commande_fournisseur_dispatch ADD INDEX idx_commande_fournisseur_dispatch_fk_commande (fk_commande); \ No newline at end of file +ALTER TABLE llx_commande_fournisseur_dispatch ADD INDEX idx_commande_fournisseur_dispatch_fk_commande (fk_commande); +ALTER TABLE llx_commande_fournisseur_dispatch ADD INDEX idx_commande_fournisseur_dispatch_fk_reception (fk_reception); +ALTER TABLE llx_commande_fournisseur_dispatch ADD CONSTRAINT fk_commande_fournisseur_dispatch_fk_reception FOREIGN KEY (fk_reception) REFERENCES llx_reception (rowid); \ No newline at end of file diff --git a/htdocs/install/mysql/tables/llx_commande_fournisseur_dispatch.sql b/htdocs/install/mysql/tables/llx_commande_fournisseur_dispatch.sql index 789ec3e7a9b..9a6e05d1af1 100644 --- a/htdocs/install/mysql/tables/llx_commande_fournisseur_dispatch.sql +++ b/htdocs/install/mysql/tables/llx_commande_fournisseur_dispatch.sql @@ -25,6 +25,8 @@ create table llx_commande_fournisseur_dispatch fk_commande integer, fk_product integer, fk_commandefourndet integer, + fk_projet integer DEFAULT NULL, + fk_reception integer DEFAULT NULL, qty float, -- qty fk_entrepot integer, fk_user integer, diff --git a/htdocs/install/mysql/tables/llx_commande_fournisseur_dispatch_extrafields.key.sql b/htdocs/install/mysql/tables/llx_commande_fournisseur_dispatch_extrafields.key.sql new file mode 100644 index 00000000000..c836fbaea6a --- /dev/null +++ b/htdocs/install/mysql/tables/llx_commande_fournisseur_dispatch_extrafields.key.sql @@ -0,0 +1,20 @@ +-- =================================================================== +-- Copyright (C) 2015 Claudio Aschieri +-- +-- 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 . +-- +-- =================================================================== + + +ALTER TABLE llx_commande_fournisseur_dispatch_extrafields ADD INDEX idx_commande_fournisseur_dispatch_extrafields (fk_object); diff --git a/htdocs/install/mysql/tables/llx_commande_fournisseur_dispatch_extrafields.sql b/htdocs/install/mysql/tables/llx_commande_fournisseur_dispatch_extrafields.sql new file mode 100644 index 00000000000..f00eabf42fa --- /dev/null +++ b/htdocs/install/mysql/tables/llx_commande_fournisseur_dispatch_extrafields.sql @@ -0,0 +1,25 @@ +-- =================================================================== +-- Copyright (C) 2015 Claudio Aschieri +-- +-- This program is free software; you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation; either version 3 of the License, or +-- (at your option) any later version. +-- +-- This program is distributed in the hope that it will be useful, +-- but WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-- GNU General Public License for more details. +-- +-- You should have received a copy of the GNU General Public License +-- along with this program. If not, see . +-- +-- =================================================================== + +create table llx_commande_fournisseur_dispatch_extrafields +( + rowid integer AUTO_INCREMENT PRIMARY KEY, + tms timestamp, + fk_object integer NOT NULL, -- object id + import_key varchar(14) -- import key +)ENGINE=innodb; diff --git a/htdocs/install/mysql/tables/llx_reception.key.sql b/htdocs/install/mysql/tables/llx_reception.key.sql new file mode 100644 index 00000000000..a107c2a7d12 --- /dev/null +++ b/htdocs/install/mysql/tables/llx_reception.key.sql @@ -0,0 +1,31 @@ +-- =================================================================== +-- Copyright (C) 2005 Laurent Destailleur +-- Copyright (C) 2008-2010 Regis Houssin +-- +-- This program is free software; you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- 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 . +-- +-- =================================================================== + + +ALTER TABLE llx_reception ADD UNIQUE INDEX idx_reception_uk_ref (ref, entity); + +ALTER TABLE llx_reception ADD INDEX idx_reception_fk_soc (fk_soc); +ALTER TABLE llx_reception ADD INDEX idx_reception_fk_user_author (fk_user_author); +ALTER TABLE llx_reception ADD INDEX idx_reception_fk_user_valid (fk_user_valid); +ALTER TABLE llx_reception ADD INDEX idx_reception_fk_shipping_method (fk_shipping_method); + +ALTER TABLE llx_reception ADD CONSTRAINT fk_reception_fk_soc FOREIGN KEY (fk_soc) REFERENCES llx_societe (rowid); +ALTER TABLE llx_reception ADD CONSTRAINT fk_reception_fk_user_author FOREIGN KEY (fk_user_author) REFERENCES llx_user (rowid); +ALTER TABLE llx_reception ADD CONSTRAINT fk_reception_fk_user_valid FOREIGN KEY (fk_user_valid) REFERENCES llx_user (rowid); +ALTER TABLE llx_reception ADD CONSTRAINT fk_reception_fk_shipping_method FOREIGN KEY (fk_shipping_method) REFERENCES llx_c_shipment_mode (rowid); diff --git a/htdocs/install/mysql/tables/llx_reception.sql b/htdocs/install/mysql/tables/llx_reception.sql new file mode 100644 index 00000000000..34565f7f29a --- /dev/null +++ b/htdocs/install/mysql/tables/llx_reception.sql @@ -0,0 +1,61 @@ +-- =================================================================== +-- Copyright (C) 2003-2010 Rodolphe Quiedeville +-- Copyright (C) 2008-2010 Regis Houssin +-- Copyright (C) 2011-2012 Laurent Destailleur +-- Copyright (C) 2012 Juanjo Menent +-- +-- This program is free software; you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation; either version 3 of the License, or +-- (at your option) any later version. +-- +-- This program is distributed in the hope that it will be useful, +-- but WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-- GNU General Public License for more details. +-- +-- You should have received a copy of the GNU General Public License +-- along with this program. If not, see . +-- +-- =================================================================== + +create table llx_reception +( + rowid integer AUTO_INCREMENT PRIMARY KEY, + tms timestamp, + ref varchar(30) NOT NULL, + entity integer DEFAULT 1 NOT NULL, -- multi company id + fk_soc integer NOT NULL, + fk_projet integer DEFAULT NULL, + + ref_ext varchar(30), -- reference into an external system (not used by dolibarr) + ref_int varchar(30), -- reference into an internal system (used by dolibarr to store extern id like paypal info) + ref_supplier varchar(30), -- customer number + + date_creation datetime, -- date de creation + fk_user_author integer, -- author of creation + fk_user_modif integer, -- author of last change + date_valid datetime, -- date de validation + fk_user_valid integer, -- valideur + date_delivery datetime DEFAULT NULL, -- date planned of delivery + date_reception datetime, + fk_shipping_method integer, + tracking_number varchar(50), + fk_statut smallint DEFAULT 0, -- 0 = draft, 1 = validated, 2 = billed or closed depending on WORKFLOW_BILL_ON_SHIPMENT option + billed smallint DEFAULT 0, + + height float, -- height + width float, -- with + size_units integer, -- unit of all sizes (height, width, depth) + size float, -- depth + weight_units integer, -- unit of weight + weight float, -- weight + note_private text, + note_public text, + model_pdf varchar(255), + fk_incoterms integer, -- for incoterms + location_incoterms varchar(255), -- for incoterms + + import_key varchar(14), + extraparams varchar(255) -- for other parameters with json format +)ENGINE=innodb; diff --git a/htdocs/install/mysql/tables/llx_reception_extrafields.key.sql b/htdocs/install/mysql/tables/llx_reception_extrafields.key.sql new file mode 100644 index 00000000000..f3a35acd8a3 --- /dev/null +++ b/htdocs/install/mysql/tables/llx_reception_extrafields.key.sql @@ -0,0 +1,20 @@ +-- =================================================================== +-- Copyright (C) 2015 Claudio Aschieri +-- +-- 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 . +-- +-- =================================================================== + + +ALTER TABLE llx_reception_extrafields ADD INDEX idx_reception_extrafields (fk_object); diff --git a/htdocs/install/mysql/tables/llx_reception_extrafields.sql b/htdocs/install/mysql/tables/llx_reception_extrafields.sql new file mode 100644 index 00000000000..7a3126b2015 --- /dev/null +++ b/htdocs/install/mysql/tables/llx_reception_extrafields.sql @@ -0,0 +1,26 @@ +-- ======================================================================== +-- Copyright (C) 2015 Claudio Aschieri +-- +-- This program is free software; you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation; either version 3 of the License, or +-- (at your option) any later version. +-- +-- This program is distributed in the hope that it will be useful, +-- but WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-- GNU General Public License for more details. +-- +-- You should have received a copy of the GNU General Public License +-- along with this program. If not, see . +-- +-- ======================================================================== + +create table llx_reception_extrafields +( + rowid integer AUTO_INCREMENT PRIMARY KEY, + tms timestamp, + fk_object integer NOT NULL, + import_key varchar(14) -- import key +) ENGINE=innodb; + diff --git a/htdocs/langs/en_US/agenda.lang b/htdocs/langs/en_US/agenda.lang index 09bb0364333..119f3fb20f8 100644 --- a/htdocs/langs/en_US/agenda.lang +++ b/htdocs/langs/en_US/agenda.lang @@ -60,6 +60,7 @@ MemberSubscriptionDeletedInDolibarr=Subscription %s for member %s deleted ShipmentValidatedInDolibarr=Shipment %s validated ShipmentClassifyClosedInDolibarr=Shipment %s classified billed ShipmentUnClassifyCloseddInDolibarr=Shipment %s classified reopened +ShipmentBackToDraftInDolibarr=Shipment %s go back to draft status ShipmentDeletedInDolibarr=Shipment %s deleted OrderCreatedInDolibarr=Order %s created OrderValidatedInDolibarr=Order %s validated diff --git a/htdocs/langs/en_US/receptions.lang b/htdocs/langs/en_US/receptions.lang new file mode 100644 index 00000000000..87cf954fea8 --- /dev/null +++ b/htdocs/langs/en_US/receptions.lang @@ -0,0 +1,70 @@ +# Dolibarr language file - Source file is en_US - receptions +RefReception=Ref. reception +Reception=Reception +Receptions=Receptions +AllReceptions=All Receptions +Reception=Reception +Receptions=Receptions +ShowReception=Show Receptions +Receivings=Delivery Receipts +ReceptionsArea=Receptions area +ListOfReceptions=List of receptions +ReceptionMethod=Reception method +LastReceptions=Latest %s receptions +StatisticsOfReceptions=Statistics for receptions +NbOfReceptions=Number of receptions +NumberOfReceptionsByMonth=Number of receptions by month +ReceptionCard=Reception card +NewReception=New reception +CreateReception=Create reception +QtyShipped=Qty shipped +QtyPreparedOrShipped=Qty prepared or shipped +QtyToShip=Qty to ship +QtyReceived=Qty received +QtyInOtherReceptions=Qty in other receptions +KeepToShip=Remain to ship +OtherReceptionsForSameOrder=Other receptions for this order +ReceptionsAndReceivingForSameOrder=Receptions and receipts for this order +ReceptionsToValidate=Receptions to validate +StatusReceptionCanceled=Canceled +StatusReceptionDraft=Draft +StatusReceptionValidated=Validated (products to ship or already shipped) +StatusReceptionProcessed=Processed +StatusReceptionDraftShort=Draft +StatusReceptionValidatedShort=Validated +StatusReceptionProcessedShort=Processed +ReceptionSheet=Reception sheet +ConfirmDeleteReception=Are you sure you want to delete this reception? +ConfirmValidateReception=Are you sure you want to validate this reception with reference %s? +ConfirmCancelReception=Are you sure you want to cancel this reception? +DocumentModelMerou=Merou A5 model +WarningNoQtyLeftToSend=Warning, no products waiting to be shipped. +StatsOnReceptionsOnlyValidated=Statistics conducted on receptions only validated. Date used is date of validation of reception (planed delivery date is not always known). +DateDeliveryPlanned=Planned date of delivery +RefDeliveryReceipt=Ref delivery receipt +StatusReceipt=Status delivery receipt +DateReceived=Date delivery received +SendReceptionByEMail=Send reception by EMail +SendReceptionRef=Submission of reception %s +ActionsOnReception=Events on reception +LinkToTrackYourPackage=Link to track your package +ReceptionCreationIsDoneFromOrder=For the moment, creation of a new reception is done from the order card. +ReceptionLine=Reception line +ProductQtyInCustomersOrdersRunning=Product quantity into open customers orders +ProductQtyInSuppliersOrdersRunning=Product quantity into open suppliers orders +ProductQtyInReceptionAlreadySent=Product quantity from open customer order already sent +ProductQtyInSuppliersReceptionAlreadyRecevied=Product quantity from open supplier order already received +NoProductToShipFoundIntoStock=No product to ship found into warehouse %s. Correct stock or go back to choose another warehouse. +WeightVolShort=Weight/Vol. +ValidateOrderFirstBeforeReception=You must first validate the order before being able to make receptions. + +# Reception methods +# ModelDocument +DocumentModelTyphon=More complete document model for delivery receipts (logo...) +Error_EXPEDITION_ADDON_NUMBER_NotDefined=Constant EXPEDITION_ADDON_NUMBER not defined +SumOfProductVolumes=Sum of product volumes +SumOfProductWeights=Sum of product weights + +# warehouse details +DetailWarehouseNumber= Warehouse details +DetailWarehouseFormat= W:%s (Qty : %d) diff --git a/htdocs/langs/fr_FR/admin.lang b/htdocs/langs/fr_FR/admin.lang index ad93ef9427b..17e6c09a776 100644 --- a/htdocs/langs/fr_FR/admin.lang +++ b/htdocs/langs/fr_FR/admin.lang @@ -1519,6 +1519,11 @@ SendingsNumberingModules=Modèles de numérotation des expéditions SendingsAbility=Prise en charge des bons d'expédition pour les livraisons clients NoNeedForDeliveryReceipts=Dans le plupart des cas, la fiche expédition est utilisée en tant que bon d'expédition (liste des produits expédiés) et bon de livraison (signée par le client). Le bon de réception est un doublon de fonctionnalité et est rarement utilisé. FreeLegalTextOnShippings=Mention complémentaire sur les expéditions +##### Reception ##### +ReceptionsSetup=Configuration du module Réception +ReceptionsReceiptModel=Modèles de bordereau de réception +ReceptionsNumberingModules=Modèles de numérotation des réceptions +FreeLegalTextOnShippings=Mention complémentaire sur les réceptions ##### Deliveries ##### DeliveryOrderNumberingModules=Modèle de numérotation des bons de réception client DeliveryOrderModel=Modèle de bon de réception client @@ -1753,6 +1758,7 @@ MailToSendSupplierRequestForQuotation=Demande de devis MailToSendSupplierOrder=Commandes fournisseurs MailToSendSupplierInvoice=Factures fournisseur MailToSendContract=Contrats +MailToSendReception=Réceptions fournisseurs MailToThirdparty=Tiers MailToMember=Adhérents MailToUser=Utilisateurs diff --git a/htdocs/langs/fr_FR/agenda.lang b/htdocs/langs/fr_FR/agenda.lang index 6cd0dd2e74c..f6ef3cc6d9d 100644 --- a/htdocs/langs/fr_FR/agenda.lang +++ b/htdocs/langs/fr_FR/agenda.lang @@ -60,7 +60,13 @@ MemberSubscriptionDeletedInDolibarr=Abonnement %s pour l'adhérent %s supprimé ShipmentValidatedInDolibarr=Expédition %s validée ShipmentClassifyClosedInDolibarr=Expédition %s classée payée ShipmentUnClassifyCloseddInDolibarr=Expédition %s réouverte +ShipmentBackToDraftInDolibarr=Expédition %s repassée en brouillon ShipmentDeletedInDolibarr=Expédition %s supprimée +ReceptionValidatedInDolibarr=Réception %s validée +ReceptionClassifyClosedInDolibarr=Réception %s classée payée +ReceptionUnClassifyCloseddInDolibarr=Réception %s réouverte +ReceptionBackToDraftInDolibarr=Réception %s repassée en brouillon +ReceptionDeletedInDolibarr=Réception %s supprimée OrderCreatedInDolibarr=Commande %s créée OrderValidatedInDolibarr=Commande %s validée OrderDeliveredInDolibarr=Commande %s classée Livrée @@ -77,6 +83,8 @@ SupplierOrderSentByEMail=Commande fournisseur %s envoyée par email SupplierInvoiceSentByEMail=Facture fournisseur %s envoyée par email ShippingSentByEMail=Bon d'expédition %s envoyé par email ShippingValidated= Expédition %s validée +ReceptionSentByEMail=Réception %s envoyée par email +ReceptionValidated= Réception %s validée InterventionSentByEMail=Intervention %s envoyée par email ProposalDeleted=Proposition commerciale supprimée OrderDeleted=Commande supprimée diff --git a/htdocs/langs/fr_FR/orders.lang b/htdocs/langs/fr_FR/orders.lang index 6b24934922b..158c566ca30 100644 --- a/htdocs/langs/fr_FR/orders.lang +++ b/htdocs/langs/fr_FR/orders.lang @@ -25,6 +25,7 @@ OrdersToBill=Commandes clients à délivrer OrdersInProcess=Commandes clients en traitement OrdersToProcess=Commandes clients à traiter SuppliersOrdersToProcess=Commandes fournisseurs à traiter +SuppliersOrdersInProcess=Commandes fournisseurs en traitement StatusOrderCanceledShort=Annulée StatusOrderDraftShort=Brouillon StatusOrderValidatedShort=Validée diff --git a/htdocs/langs/fr_FR/products.lang b/htdocs/langs/fr_FR/products.lang index 3c66c355246..571376ebeb0 100644 --- a/htdocs/langs/fr_FR/products.lang +++ b/htdocs/langs/fr_FR/products.lang @@ -281,7 +281,7 @@ ProductsOrServicesTranslations=Traduction des produits ou des services TranslatedLabel=Titre traduit TranslatedDescription=Description traduite TranslatedNote=Notes traduites -ProductWeight=Poids pour 1 articlejavascript:; +ProductWeight=Poids pour 1 article ProductVolume=Volume pour 1 article WeightUnits=Unité de poids VolumeUnits=Unité de volume diff --git a/htdocs/langs/fr_FR/receptions.lang b/htdocs/langs/fr_FR/receptions.lang new file mode 100644 index 00000000000..8e766344d94 --- /dev/null +++ b/htdocs/langs/fr_FR/receptions.lang @@ -0,0 +1,83 @@ +# Dolibarr language file - Source file is en_US - receptions +RefReception=Réf. réception +Reception=Réception +reception=Réception +reception_line=Ligne de réception +Receptions=Réceptions +AllReceptions=Toutes les réceptions +Reception=Réception +Receptions=Réceptions +ShowReception=Afficher Réceptions +Receivings=Bons de réceptions +ReceptionsArea=Espace réceptions +ListOfReceptions=Liste des réceptions +ReceptionMethod=Mode de transport +LastReceptions=Les %s dernières réceptions +StatisticsOfReceptions=Statistiques des réceptions +NbOfReceptions=Nombre de réceptions +NumberOfReceptionsByMonth=Nombre de réceptions par mois +ReceptionCard=Fiche réception +NewReception=Nouvelle réception +CreateReception=Créer réception +QtyShipped=Qté. expédiée +QtyPreparedOrShipped=Quantité préparée ou envoyée +QtyToReceive=Qté. à recevoir +QtyReceived=Qté. reçue +QtyInOtherReceptions=Qté dans les autres réceptions +KeepToShip=Reste à expédier +OtherReceptionsForSameOrder=Autres réceptions pour cette commande +ReceptionsAndReceivingForSameOrder=Réceptions et réceptions pour cette commande +ReceptionsToValidate=Réceptions à valider +StatusReceptionCanceled=Annulée +StatusReceptionDraft=Brouillon +StatusReceptionValidated=Validée +StatusReceptionProcessed=Traitée +StatusReceptionDraftShort=Brouillon +StatusReceptionValidatedShort=Validée +StatusReceptionProcessedShort=Traitée +ReceptionSheet=Fiche réception +ConfirmDeleteReception=Êtes-vous sûr de vouloir supprimer cette réception ? +ConfirmValidateReception=Êtes-vous sûr de vouloir valider cette réception sous la référence %s? +ConfirmCancelReception=Êtes-vous sûr de vouloir annuler cette réception ? +DocumentModelMerou=Modèle Merou A5 +WarningNoQtyLeftToSend=Alerte, aucun produit en attente de réception. +StatsOnReceptionsOnlyValidated=Statistiques effectuées sur les réceptions validées uniquement. La date prise en compte est la date de validation (la date de prévision de livraison n'étant pas toujours renseignée). +DateDeliveryPlanned=Date prévue de livraison +RefDeliveryReceipt=Ref bon de réception +StatusReceipt=Status du bon de réception +DateReceived=Date de réception réelle +SendReceptionByEMail=Envoyer bon de réception par email +SendReceptionRef=Envoi du bordereau de réception %s +ActionsOnReception=Événements sur l'réception +LinkToTrackYourPackage=Lien pour le suivi de votre colis +ReceptionCreationIsDoneFromOrder=Pour le moment, la création d'une nouvelle réception se fait depuis la fiche commande fournisseur. +ReceptionLine=Ligne de réception +RefSupplierOrder=Ref. Commande fournisseur +ProductQtyInCustomersOrdersRunning=Quantité de produit en commandes client ouvertes +ProductQtyInSuppliersOrdersRunning=Quantité de produit en commandes fournisseur ouvertes +ProductQtyInReceptionAlreadySent=Quantité de produit en commande client ouverte déjà expédiée +ProductQtyInSuppliersReceptionAlreadyRecevied=Quantité de produit déjà reçu en commandes fournisseur ouvertes +NoProductToShipFoundIntoStock=Aucun produit à expédier n'a été trouver dans l'entrepôt %s. Corrigez l'inventaire ou retourner choisir un autre entrepôt. +WeightVolShort=Poids/vol. +ValidateOrderFirstBeforeReception=Vous devez d'abord valider la commande pour pouvoir créer une réception. +CreateInvoiceForThisSupplier=Facturer réceptions +ErrorRefAlreadyExists = La référence fournisseur existe déjà + +# Reception methods +# ModelDocument +DocumentModelTyphon=Modèle de bon de réception/livraison complet (logo…) +Error_EXPEDITION_ADDON_NUMBER_NotDefined=Constante EXPEDITION_ADDON_NUMBER non définie +SumOfProductVolumes=Somme des volumes des produits +SumOfProductWeights=Somme des poids des produits + +# warehouse details +DetailWarehouseNumber= Détail de l'entrepôt +DetailWarehouseFormat= W:%s (Qté : %d) + +Billed=Facturé +ClassifyUnbilled=Classer non facturé + +DateInvoice=Date de facturation +CreateOneBillByThird=Créer une facture par tiers (sinon une par réception) +ValidateInvoices=Factures validées +StatusMustBeValidate=La réception %s doit être au statut 'Validée' diff --git a/htdocs/langs/fr_FR/stocks.lang b/htdocs/langs/fr_FR/stocks.lang index 8cd53d0aed4..02800c3a8ac 100644 --- a/htdocs/langs/fr_FR/stocks.lang +++ b/htdocs/langs/fr_FR/stocks.lang @@ -63,11 +63,13 @@ RuleForStockManagementDecrease=Choisissez Règle pour la réduction automatique RuleForStockManagementIncrease=Choisissez Règle pour augmentation de stock automatique (une augmentation manuelle est toujours possible, même si une règle d’augmentation automatique est activée) DeStockOnBill=Diminution des stocks réels lors de la validation de la facture client / note de crédit DeStockOnValidateOrder=Diminuer les stocks réels lors de la validation de la commande client -DeStockOnShipment=Décrémenter les stocks physiques sur validation des expéditions -DeStockOnShipmentOnClosing=Décrémenter les stocks physiques au classement "clôturée" de l'expédition +DeStockOnShipment=Réduire les stocks physiques sur validation des expéditions +DeStockOnShipmentOnClosing=Réduire les stocks physiques au classement "clôturée" de l'expédition ReStockOnBill=Augmenter les stocks réels lors de la validation de la facture fournisseur / de la note de crédit ReStockOnValidateOrder=Augmenter les stocks réels lors de l'approbation des bons de commande ReStockOnDispatchOrder=Augmenter les stocks réels lors de l'expédition manuelle dans l'entrepôt, après la réception de la commande fournisseur +StockOnReception=Augmenter les stocks physiques sur validation des réceptions +StockOnReceptionOnClosing=Augmenter les stocks réels au classement "clôturée" de la réception OrderStatusNotReadyToDispatch=La commande n'a pas encore ou n'a plus un statut permettant une ventilation en stock. StockDiffPhysicTeoric=Explication de l'écart stock physique-virtuel NoPredefinedProductToDispatch=Pas de produits prédéfinis dans cet objet. Aucune ventilation en stock n'est donc à faire. diff --git a/htdocs/langs/fr_FR/workflow.lang b/htdocs/langs/fr_FR/workflow.lang index 154d1aaf3d7..a3dbe4cb07e 100644 --- a/htdocs/langs/fr_FR/workflow.lang +++ b/htdocs/langs/fr_FR/workflow.lang @@ -16,5 +16,6 @@ descWORKFLOW_ORDER_CLASSIFY_SHIPPED_SHIPPING=Classer la commande source à expé # Autoclassify supplier order descWORKFLOW_ORDER_CLASSIFY_BILLED_SUPPLIER_PROPOSAL=Classer la ou les proposition(s) commerciale(s) fournisseur sources facturées quand une facture fournisseur est validée (et si le montant de la facture est le même que le total des propositions sources liées) descWORKFLOW_INVOICE_AMOUNT_CLASSIFY_BILLED_SUPPLIER_ORDER=Classer la ou les commande(s) fournisseur(s) de source(s) à facturée(s) lorsque la facture fournisseur est validée (et si le montant de la facture est le même que le montant total des commandes liées) +descWORKFLOW_BILL_ON_RECEPTION=Classer la/les réception(s) facturée(s) à la validation d'une facture fournisseur AutomaticCreation=Création automatique AutomaticClassification=Classification automatique diff --git a/htdocs/product/class/product.class.php b/htdocs/product/class/product.class.php index b872a6e401e..ed22a5f7824 100644 --- a/htdocs/product/class/product.class.php +++ b/htdocs/product/class/product.class.php @@ -4153,84 +4153,86 @@ class Product extends CommonObject } } + // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps - /** - * Load value ->stock_theorique of a product. Property this->id must be defined. - * This function need a lot of load. If you use it on list, use a cache to execute it one for each product id. - * - * @return int < 0 if KO, > 0 if OK - * @see load_stock(), loadBatchInfo() - */ - function load_virtual_stock() - { - // phpcs:enable - global $conf, $hookmanager, $action; + /** + * Load value ->stock_theorique of a product. Property this->id must be defined. + * This function need a lot of load. If you use it on list, use a cache to execute it one for each product id. + * + * @return int < 0 if KO, > 0 if OK + * @see load_stock(), loadBatchInfo() + */ + function load_virtual_stock() + { + // phpcs:enable + global $conf, $hookmanager, $action; - $stock_commande_client=0; - $stock_commande_fournisseur=0; - $stock_sending_client=0; - $stock_reception_fournisseur=0; + $stock_commande_client=0; + $stock_commande_fournisseur=0; + $stock_sending_client=0; + $stock_reception_fournisseur=0; - if (! empty($conf->commande->enabled)) { - $result=$this->load_stats_commande(0, '1,2', 1); - if ($result < 0) { dol_print_error($this->db, $this->error); - } - $stock_commande_client=$this->stats_commande['qty']; - } - if (! empty($conf->expedition->enabled)) { - $result=$this->load_stats_sending(0, '1,2', 1); - if ($result < 0) { dol_print_error($this->db, $this->error); - } - $stock_sending_client=$this->stats_expedition['qty']; - } - if (! empty($conf->fournisseur->enabled)) { - $result=$this->load_stats_commande_fournisseur(0, '1,2,3,4', 1); - if ($result < 0) { dol_print_error($this->db, $this->error); - } - $stock_commande_fournisseur=$this->stats_commande_fournisseur['qty']; + if (! empty($conf->commande->enabled)) + { + $result=$this->load_stats_commande(0,'1,2', 1); + if ($result < 0) dol_print_error($this->db,$this->error); + $stock_commande_client=$this->stats_commande['qty']; + } + if (! empty($conf->expedition->enabled)) + { + $result=$this->load_stats_sending(0,'1,2', 1); + if ($result < 0) dol_print_error($this->db,$this->error); + $stock_sending_client=$this->stats_expedition['qty']; + } + if (! empty($conf->fournisseur->enabled)) + { + $result=$this->load_stats_commande_fournisseur(0,'1,2,3,4', 1); + if ($result < 0) dol_print_error($this->db,$this->error); + $stock_commande_fournisseur=$this->stats_commande_fournisseur['qty']; - $result=$this->load_stats_reception(0, '4', 1); - if ($result < 0) { dol_print_error($this->db, $this->error); - } - $stock_reception_fournisseur=$this->stats_reception['qty']; - } + $result=$this->load_stats_reception(0,'4', 1); + if ($result < 0) dol_print_error($this->db,$this->error); + $stock_reception_fournisseur=$this->stats_reception['qty']; + } - // Stock decrease mode - if (! empty($conf->global->STOCK_CALCULATE_ON_SHIPMENT) || ! empty($conf->global->STOCK_CALCULATE_ON_SHIPMENT_CLOSE)) { - $this->stock_theorique=$this->stock_reel-$stock_commande_client+$stock_sending_client; - } - if (! empty($conf->global->STOCK_CALCULATE_ON_VALIDATE_ORDER)) { - $this->stock_theorique=$this->stock_reel; - } - if (! empty($conf->global->STOCK_CALCULATE_ON_BILL)) { - $this->stock_theorique=$this->stock_reel-$stock_commande_client; - } - // Stock Increase mode - if (! empty($conf->global->STOCK_CALCULATE_ON_SUPPLIER_DISPATCH_ORDER)) { - $this->stock_theorique+=$stock_commande_fournisseur-$stock_reception_fournisseur; - } - if (! empty($conf->global->STOCK_CALCULATE_ON_SUPPLIER_VALIDATE_ORDER)) { - $this->stock_theorique-=$stock_reception_fournisseur; - } - if (! empty($conf->global->STOCK_CALCULATE_ON_SUPPLIER_BILL)) { + // Stock decrease mode + if (! empty($conf->global->STOCK_CALCULATE_ON_SHIPMENT) || ! empty($conf->global->STOCK_CALCULATE_ON_SHIPMENT_CLOSE)) { + $this->stock_theorique=$this->stock_reel-$stock_commande_client+$stock_sending_client; + } + if (! empty($conf->global->STOCK_CALCULATE_ON_VALIDATE_ORDER)) { + $this->stock_theorique=$this->stock_reel; + } + if (! empty($conf->global->STOCK_CALCULATE_ON_BILL)) { + $this->stock_theorique=$this->stock_reel-$stock_commande_client; + } + // Stock Increase mode + if (! empty($conf->global->STOCK_CALCULATE_ON_RECEPTION) || ! empty($conf->global->STOCK_CALCULATE_ON_RECEPTION_CLOSE)) { $this->stock_theorique+=$stock_commande_fournisseur-$stock_reception_fournisseur; } + if (! empty($conf->global->STOCK_CALCULATE_ON_SUPPLIER_DISPATCH_ORDER)) { + $this->stock_theorique+=$stock_commande_fournisseur-$stock_reception_fournisseur; + } + if (! empty($conf->global->STOCK_CALCULATE_ON_SUPPLIER_VALIDATE_ORDER)) { + $this->stock_theorique-=$stock_reception_fournisseur; + } + if (! empty($conf->global->STOCK_CALCULATE_ON_SUPPLIER_BILL)) { + $this->stock_theorique+=$stock_commande_fournisseur-$stock_reception_fournisseur; + } - if (! is_object($hookmanager)) { - include_once DOL_DOCUMENT_ROOT.'/core/class/hookmanager.class.php'; - $hookmanager=new HookManager($this->db); - } - $hookmanager->initHooks(array('productdao')); - $parameters=array('id'=>$this->id); - // Note that $action and $object may have been modified by some hooks - $reshook=$hookmanager->executeHooks('loadvirtualstock', $parameters, $this, $action); - if ($reshook > 0) { $this->stock_theorique = $hookmanager->resArray['stock_theorique']; - } - - return 1; - } - + if (! is_object($hookmanager)) { + include_once DOL_DOCUMENT_ROOT.'/core/class/hookmanager.class.php'; + $hookmanager=new HookManager($this->db); + } + $hookmanager->initHooks(array('productdao')); + $parameters=array('id'=>$this->id); + // Note that $action and $object may have been modified by some hooks + $reshook=$hookmanager->executeHooks('loadvirtualstock', $parameters, $this, $action); + if ($reshook > 0) $this->stock_theorique = $hookmanager->resArray['stock_theorique']; + return 1; + } + + /** * Load existing information about a serial * @@ -4266,7 +4268,6 @@ class Product extends CommonObject } } - // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps /** * Move an uploaded file described into $file array into target directory $sdir. @@ -4348,7 +4349,6 @@ class Product extends CommonObject return false; } - // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps /** * Retourne tableau de toutes les photos du produit diff --git a/htdocs/product/list.php b/htdocs/product/list.php index 323d21e5629..5047ba16100 100644 --- a/htdocs/product/list.php +++ b/htdocs/product/list.php @@ -120,7 +120,7 @@ else $result=restrictedArea($user,'produit|service','','','','','',$objcanvas); // Define virtualdiffersfromphysical $virtualdiffersfromphysical=0; -if (! empty($conf->global->STOCK_CALCULATE_ON_SHIPMENT) || ! empty($conf->global->STOCK_CALCULATE_ON_SUPPLIER_DISPATCH_ORDER)) +if (! empty($conf->global->STOCK_CALCULATE_ON_SHIPMENT) || ! empty($conf->global->STOCK_CALCULATE_ON_SUPPLIER_DISPATCH_ORDER) || ! empty($conf->global->STOCK_CALCULATE_ON_RECEPTION) ) { $virtualdiffersfromphysical=1; // According to increase/decrease stock options, virtual and physical stock may differs. } diff --git a/htdocs/product/reassort.php b/htdocs/product/reassort.php index 71482d6c86a..d14bfeb9df2 100644 --- a/htdocs/product/reassort.php +++ b/htdocs/product/reassort.php @@ -77,7 +77,7 @@ if (! empty($canvas)) // Define virtualdiffersfromphysical $virtualdiffersfromphysical=0; -if (! empty($conf->global->STOCK_CALCULATE_ON_SHIPMENT) || ! empty($conf->global->STOCK_CALCULATE_ON_SUPPLIER_DISPATCH_ORDER)) +if (! empty($conf->global->STOCK_CALCULATE_ON_SHIPMENT) || ! empty($conf->global->STOCK_CALCULATE_ON_SUPPLIER_DISPATCH_ORDER)|| ! empty($conf->global->STOCK_CALCULATE_ON_RECEPTION)) { $virtualdiffersfromphysical=1; // According to increase/decrease stock options, virtual and physical stock may differs. } diff --git a/htdocs/product/stock/class/mouvementstock.class.php b/htdocs/product/stock/class/mouvementstock.class.php index 98103af8ccf..e19df0aaa1a 100644 --- a/htdocs/product/stock/class/mouvementstock.class.php +++ b/htdocs/product/stock/class/mouvementstock.class.php @@ -370,6 +370,7 @@ class MouvementStock extends CommonObject dol_syslog(get_class($this)."::_create insert record into stock_mouvement", LOG_DEBUG); $resql = $this->db->query($sql); + if ($resql) { $mvid = $this->db->last_insert_id(MAIN_DB_PREFIX."stock_mouvement"); @@ -412,7 +413,7 @@ class MouvementStock extends CommonObject $error = -2; } } - + // Calculate new PMP. $newpmp=0; if (! $error) @@ -442,7 +443,6 @@ class MouvementStock extends CommonObject $newpmp = $oldpmp; } } - // Update stock quantity if (! $error) { diff --git a/htdocs/product/stock/product.php b/htdocs/product/stock/product.php index 54a4cd564ab..6d41e9589cb 100644 --- a/htdocs/product/stock/product.php +++ b/htdocs/product/stock/product.php @@ -641,6 +641,8 @@ if ($id > 0 || $ref) $text_stock_options .= (!empty($conf->global->STOCK_CALCULATE_ON_SUPPLIER_BILL) ? $langs->trans("ReStockOnBill") . '
' : ''); $text_stock_options .= (!empty($conf->global->STOCK_CALCULATE_ON_SUPPLIER_VALIDATE_ORDER) ? $langs->trans("ReStockOnValidateOrder") . '
' : ''); $text_stock_options .= (!empty($conf->global->STOCK_CALCULATE_ON_SUPPLIER_DISPATCH_ORDER) ? $langs->trans("ReStockOnDispatchOrder") . '
' : ''); + $text_stock_options.= (! empty($conf->global->STOCK_CALCULATE_ON_RECEPTION) || ! empty($conf->global->STOCK_CALCULATE_ON_RECEPTION_CLOSE)?$langs->trans("StockOnReception").'
':''); + print '
'; diff --git a/htdocs/product/stock/replenish.php b/htdocs/product/stock/replenish.php index 5ffd668680f..7677460aee7 100644 --- a/htdocs/product/stock/replenish.php +++ b/htdocs/product/stock/replenish.php @@ -82,7 +82,9 @@ if (!$sortorder) { $virtualdiffersfromphysical=0; if (! empty($conf->global->STOCK_CALCULATE_ON_SHIPMENT) || ! empty($conf->global->STOCK_CALCULATE_ON_SUPPLIER_DISPATCH_ORDER) -|| ! empty($conf->global->STOCK_CALCULATE_ON_SHIPMENT_CLOSE)) +|| ! empty($conf->global->STOCK_CALCULATE_ON_SHIPMENT_CLOSE) +|| !empty($conf->global->STOCK_CALCULATE_ON_RECEPTION) +|| !empty($conf->global->STOCK_CALCULATE_ON_RECEPTION_CLOSE)) { $virtualdiffersfromphysical=1; // According to increase/decrease stock options, virtual and physical stock may differs. } diff --git a/htdocs/product/stock/replenishorders.php b/htdocs/product/stock/replenishorders.php index a4deee38715..c0e2973b4f8 100644 --- a/htdocs/product/stock/replenishorders.php +++ b/htdocs/product/stock/replenishorders.php @@ -119,7 +119,7 @@ $sql.= ' WHERE cf.fk_soc = s.rowid '; $sql.= ' AND cf.entity = ' . $conf->entity; if ($conf->global->STOCK_CALCULATE_ON_SUPPLIER_VALIDATE_ORDER) { $sql .= ' AND cf.fk_statut < 3'; -} elseif ($conf->global->STOCK_CALCULATE_ON_SUPPLIER_DISPATCH_ORDER) { +} elseif ($conf->global->STOCK_CALCULATE_ON_SUPPLIER_DISPATCH_ORDER|| !empty($conf->global->STOCK_CALCULATE_ON_RECEPTION) || !empty($conf->global->STOCK_CALCULATE_ON_RECEPTION_CLOSE)) { $sql .= ' AND cf.fk_statut < 6'; // We want also status 5, we will keep them visible if dispatching is not yet finished (tested with function dolDispatchToDo). } else { $sql .= ' AND cf.fk_statut < 5'; diff --git a/htdocs/reception/card.php b/htdocs/reception/card.php new file mode 100644 index 00000000000..ffbb5dbd765 --- /dev/null +++ b/htdocs/reception/card.php @@ -0,0 +1,2307 @@ + + * Copyright (C) 2005-2016 Laurent Destailleur + * Copyright (C) 2005 Simon TOSSER + * Copyright (C) 2005-2012 Regis Houssin + * Copyright (C) 2011-2017 Juanjo Menent + * Copyright (C) 2013 Florian Henry + * Copyright (C) 2013 Marcos García + * Copyright (C) 2014 Cedric GROSS + * Copyright (C) 2014-2017 Francis Appels + * Copyright (C) 2015 Claudio Aschieri + * Copyright (C) 2016 Ferran Marcet + * Copyright (C) 2016 Yasser Carreón + * Copyright (C) 2018 Quentin Vial-Gouteyron + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/** + * \file htdocs/reception/card.php + * \ingroup reception + * \brief Card of a reception + */ + +require '../main.inc.php'; +require_once DOL_DOCUMENT_ROOT.'/core/class/html.formfile.class.php'; +require_once DOL_DOCUMENT_ROOT.'/reception/class/reception.class.php'; +require_once DOL_DOCUMENT_ROOT.'/product/class/html.formproduct.class.php'; +require_once DOL_DOCUMENT_ROOT.'/core/lib/product.lib.php'; +require_once DOL_DOCUMENT_ROOT.'/core/lib/reception.lib.php'; +require_once DOL_DOCUMENT_ROOT.'/core/modules/reception/modules_reception.php'; +require_once DOL_DOCUMENT_ROOT.'/core/class/doleditor.class.php'; +require_once DOL_DOCUMENT_ROOT.'/core/class/extrafields.class.php'; +require_once DOL_DOCUMENT_ROOT.'/product/stock/class/entrepot.class.php'; +require_once DOL_DOCUMENT_ROOT.'/product/stock/class/productlot.class.php'; +if (! empty($conf->product->enabled) || ! empty($conf->service->enabled)) require_once DOL_DOCUMENT_ROOT.'/product/class/product.class.php'; +if (! empty($conf->propal->enabled)) require_once DOL_DOCUMENT_ROOT.'/comm/propal/class/propal.class.php'; +if (! empty($conf->fournisseur->enabled)){ + require_once DOL_DOCUMENT_ROOT.'/fourn/class/fournisseur.commande.class.php'; + require_once DOL_DOCUMENT_ROOT.'/fourn/class/fournisseur.commande.dispatch.class.php'; +} +if (! empty($conf->productbatch->enabled)) require_once DOL_DOCUMENT_ROOT.'/product/class/productbatch.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->loadLangs(array("receptions","companies","bills",'deliveries','orders','stocks','other','propal')); + +if (!empty($conf->incoterm->enabled)) $langs->load('incoterm'); +if (! empty($conf->productbatch->enabled)) $langs->load('productbatch'); + +$origin = GETPOST('origin','alpha')?GETPOST('origin','alpha'):'reception'; // Example: commande, propal +$origin_id = GETPOST('id','int')?GETPOST('id','int'):''; +$id = $origin_id; +if (empty($origin_id)) $origin_id = GETPOST('origin_id','int'); // Id of order or propal +if (empty($origin_id)) $origin_id = GETPOST('object_id','int'); // Id of order or propal +if (empty($origin_id)) $origin_id = GETPOST('originid','int'); // Id of order or propal +$ref=GETPOST('ref','alpha'); +$line_id = GETPOST('lineid','int')?GETPOST('lineid','int'):''; + +// Security check +$socid=''; +if ($user->societe_id) $socid=$user->societe_id; + +if ($origin == 'reception') $result=restrictedArea($user, $origin, $id); +else { + $result=restrictedArea($user, 'reception'); + if($origin == 'supplierorder'){ + if (empty($user->rights->fournisseur->commande->lire) && empty($user->rights->fournisseur->commande->read)) accessforbidden(); + }else if (empty($user->rights->{$origin}->lire) && empty($user->rights->{$origin}->read)) accessforbidden(); +} + +$action = GETPOST('action','alpha'); +//Select mail models is same action as presend +if (GETPOST('modelselected')) { + $action = 'presend'; +} +$confirm = GETPOST('confirm','alpha'); +$cancel = GETPOST('cancel','alpha'); + +//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)); + +$object = new Reception($db); +$extrafields = new ExtraFields($db); +$extrafieldsline = new ExtraFields($db); + +// fetch optionals attributes and labels +$extralabels = $extrafields->fetch_name_optionals_label($object->table_element); + +// fetch optionals attributes lines and labels +$extralabelslines=$extrafieldsline->fetch_name_optionals_label($object->table_element_line); + + +// Load object. Make an object->fetch +include DOL_DOCUMENT_ROOT.'/core/actions_fetchobject.inc.php'; // Must be include, not include_once + +// Initialize technical object to manage hooks of page. Note that conf->hooks_modules contains array of hook context +$hookmanager->initHooks(array('receptioncard','globalcard')); + +$permissiondellink=$user->rights->reception->creer; // Used by the include of actions_dellink.inc.php +//var_dump($object->lines[0]->detail_batch); + + +/* + * Actions + */ + +$parameters=array(); +$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)) +{ + if ($cancel) + { + $action = ''; + $object->fetch($id); // show reception also after canceling modification + } + + include DOL_DOCUMENT_ROOT.'/core/actions_dellink.inc.php'; // Must be include, not include_once + + // Reopen + if ($action == 'reopen' && $user->rights->reception->creer) + { + $object->fetch($id); + $result = $object->reOpen(); + } + + // Confirm back to draft status + if ($action == 'modif' && $user->rights->reception->creer) + { + $result = $object->set_draft($user); + if ($result >= 0) + { + // Define output language + if (empty($conf->global->MAIN_DISABLE_PDF_AUTOUPDATE)) + { + $outputlangs = $langs; + $newlang = ''; + if ($conf->global->MAIN_MULTILANGS && empty($newlang) && GETPOST('lang_id','aZ09')) $newlang = GETPOST('lang_id','aZ09'); + 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); + } + } + } + + // Set incoterm + if ($action == 'set_incoterms' && !empty($conf->incoterm->enabled)) + { + $result = $object->setIncoterms(GETPOST('incoterm_id', 'int'), GETPOST('location_incoterms', 'alpha')); + } + + if ($action == 'setref_supplier') + { + $result = $object->fetch($id); + if ($result < 0) { + setEventMessages($object->error, $object->errors, 'errors'); + } + + $result = $object->setValueFrom('ref_supplier', GETPOST('ref_supplier','alpha'), '', null, 'text', '', $user, 'RECEPTION_MODIFY'); + if ($result < 0) { + setEventMessages($object->error, $object->errors, 'errors'); + $action = 'editref_supplier'; + } else { + header("Location: ".$_SERVER['PHP_SELF']."?id=".$object->id); + exit; + } + } + + 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) + // TODO le hook fait double emploi avec le trigger !! + $hookmanager->initHooks(array('receptiondao')); + $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) + { + setEventMessages($object->error, $object->errors, 'errors'); + $error++; + } + } else if ($reshook < 0) + $error++; + } + + if ($error) + $action = 'edit_extras'; + } + + // Create reception + if ($action == 'add' && $user->rights->reception->creer) + { + + $error = 0; + $predef = ''; + + $db->begin(); + + $object->note = GETPOST('note', 'alpha'); + $object->origin = $origin; + $object->origin_id = $origin_id; + $object->fk_project = GETPOST('projectid', 'int'); + $object->weight = GETPOST('weight', 'int') == '' ? "NULL" : GETPOST('weight', 'int'); + $object->sizeH = GETPOST('sizeH', 'int') == '' ? "NULL" : GETPOST('sizeH', 'int'); + $object->sizeW = GETPOST('sizeW', 'int') == '' ? "NULL" : GETPOST('sizeW', 'int'); + $object->sizeS = GETPOST('sizeS', 'int') == '' ? "NULL" : GETPOST('sizeS', 'int'); + $object->size_units = GETPOST('size_units', 'int'); + $object->weight_units = GETPOST('weight_units', 'int'); + + $date_delivery = dol_mktime(GETPOST('date_deliveryhour', 'int'), GETPOST('date_deliverymin', 'int'), 0, GETPOST('date_deliverymonth', 'int'), GETPOST('date_deliveryday', 'int'), GETPOST('date_deliveryyear', 'int')); + + // On va boucler sur chaque ligne du document d'origine pour completer objet reception + // avec info diverses + qte a livrer + + if ($object->origin == "supplierorder") + $classname = 'CommandeFournisseur'; + else + $classname = ucfirst($object->origin); + $objectsrc = new $classname($db); + $objectsrc->fetch($object->origin_id); + + + + $object->socid = $objectsrc->socid; + $object->ref_supplier = GETPOST('ref_supplier', 'alpha'); + $object->model_pdf = GETPOST('model'); + $object->date_delivery = $date_delivery; // Date delivery planed + $object->fk_delivery_address = $objectsrc->fk_delivery_address; + $object->shipping_method_id = GETPOST('shipping_method_id', 'int'); + $object->tracking_number = GETPOST('tracking_number', 'alpha'); + $object->ref_int = GETPOST('ref_int', 'alpha'); + $object->note_private = GETPOST('note_private', 'none'); + $object->note_public = GETPOST('note_public', 'none'); + $object->fk_incoterms = GETPOST('incoterm_id', 'int'); + $object->location_incoterms = GETPOST('location_incoterms', 'alpha'); + + $batch_line = array(); + $stockLine = array(); + $array_options = array(); + + $totalqty = 0; + + $num = 0; + foreach ($_POST as $key => $value) + { + // without batch module enabled + + if (strpos($key, 'qtyasked') !== false) + { + $num++; + } + } + + for ($i = 1; $i <= $num; $i++) + { + $idl = "idl".$i; + + $sub_qty = array(); + $subtotalqty = 0; + + $j = 0; + $batch = "batchl".$i."_0"; + $stockLocation = "ent1".$i."_0"; + $qty = "qtyl".$i; + + + + //var_dump(GETPOST($qty,'int')); var_dump($_POST); var_dump($batch);exit; + //reception line for product with no batch management and no multiple stock location + if (GETPOST($qty, 'int') > 0) + $totalqty += GETPOST($qty, 'int'); + + + // Extrafields + $extralabelsline = $extrafieldsline->fetch_name_optionals_label($object->table_element_line); + $array_options[$i] = $extrafieldsline->getOptionalsFromPost($extralabelsline, $i); + + + } + + + + + if ($totalqty > 0) // There is at least one thing to ship + { + //var_dump($_POST);exit; + for ($i = 1; $i <= $num; $i++) + { + $lineToTest = ''; + foreach($objectsrc->lines as $linesrc){ + if($linesrc->id == GETPOST($idl, 'int'))$lineToTest=$linesrc; + } + $qty = "qtyl".$i; + $comment = "comment".$i; + $eatby = "dlc".$i; + $sellby = "dluo".$i; + $batch = "batch".$i; + + + + $timeFormat = '%d/%m/%Y'; + + if (GETPOST($qty, 'int') > 0 || (GETPOST($qty, 'int') == 0 && $conf->global->RECEPTION_GETS_ALL_ORDER_PRODUCTS)) + { + $ent = "entl".$i; + + $idl = "idl".$i; + + $entrepot_id = is_numeric(GETPOST($ent, 'int')) ? GETPOST($ent, 'int') : GETPOST('entrepot_id', 'int'); + + if ($entrepot_id < 0) + $entrepot_id = ''; + if (!($linesrc->fk_product > 0) && empty($conf->global->STOCK_SUPPORTS_SERVICES)) + $entrepot_id = 0; + $eatby = GETPOST($eatby, 'alpha'); + $sellby = GETPOST($sellby, 'alpha'); + $eatbydate = str_replace('/','-',$eatby); + $sellbydate = str_replace('/','-',$sellby); + + + $ret = $object->addline($entrepot_id, GETPOST($idl, 'int'), GETPOST($qty, 'int'), $array_options[$i], GETPOST($comment, 'alpha'), strtotime($eatbydate),strtotime($sellbydate), GETPOST($batch, 'alpha')); + if ($ret < 0) + { + setEventMessages($object->error, $object->errors, 'errors'); + $error++; + } + } + } + + + // Fill array 'array_options' with data from add form + $ret = $extrafields->setOptionalsFromPost($extralabels, $object); + if ($ret < 0) $error++; + if (! $error) + { + $ret=$object->create($user); // This create reception (like Odoo picking) and line of receptions. Stock movement will when validating reception. + + if ($ret <= 0) + { + setEventMessages($object->error, $object->errors, 'errors'); + $error++; + } + } + } + else + { + setEventMessages($langs->trans("ErrorFieldRequired",$langs->transnoentitiesnoconv("QtyToReceive").'/'.$langs->transnoentitiesnoconv("Warehouse")), null, 'errors'); + $error++; + } + + if (! $error) + { + $db->commit(); + header("Location: card.php?id=".$object->id); + exit; + } + else + { + $db->rollback(); + $_GET["commande_id"]=GETPOST('commande_id','int'); + $action='create'; + } + } + + + else if ($action == 'confirm_valid' && $confirm == 'yes' && + ((empty($conf->global->MAIN_USE_ADVANCED_PERMS) && ! empty($user->rights->reception->creer)) + || (! empty($conf->global->MAIN_USE_ADVANCED_PERMS) && ! empty($user->rights->reception->reception_advance->validate))) + ) + { + $object->fetch_thirdparty(); + + $result = $object->valid($user); + + if ($result < 0) + { + $langs->load("errors"); + setEventMessages($langs->trans($object->error), null, 'errors'); + } + else + { + // Define output language + if (empty($conf->global->MAIN_DISABLE_PDF_AUTOUPDATE)) + { + $outputlangs = $langs; + $newlang = ''; + if ($conf->global->MAIN_MULTILANGS && empty($newlang) && GETPOST('lang_id','aZ09')) $newlang = GETPOST('lang_id','aZ09'); + 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); + } + } + } + + else if ($action == 'confirm_delete' && $confirm == 'yes' && $user->rights->reception->supprimer) + { + $result = $object->delete(); + if ($result > 0) + { + header("Location: ".DOL_URL_ROOT.'/reception/index.php'); + exit; + } + else + { + setEventMessages($object->error, $object->errors, 'errors'); + } + } + // TODO add alternative status + /*else if ($action == 'reopen' && (! empty($user->rights->reception->creer) || ! empty($user->rights->reception->reception_advance->validate))) + { + $result = $object->setStatut(0); + if ($result < 0) + { + setEventMessages($object->error, $object->errors, 'errors'); + } + }*/ + + else if ($action == 'setdate_livraison' && $user->rights->reception->creer) + { + //print "x ".$_POST['liv_month'].", ".$_POST['liv_day'].", ".$_POST['liv_year']; + $datedelivery=dol_mktime(GETPOST('liv_hour','int'), GETPOST('liv_min','int'), 0, GETPOST('liv_month','int'), GETPOST('liv_day','int'), GETPOST('liv_year','int')); + + $object->fetch($id); + $result=$object->set_date_livraison($user,$datedelivery); + if ($result < 0) + { + setEventMessages($object->error, $object->errors, 'errors'); + } + } + + // Action update + else if ($action == 'settracking_number' || $action == 'settracking_url' + || $action == 'settrueWeight' + || $action == 'settrueWidth' + || $action == 'settrueHeight' + || $action == 'settrueDepth' + || $action == 'setshipping_method_id') + { + $error=0; + + if ($action == 'settracking_number') $object->tracking_number = trim(GETPOST('tracking_number','alpha')); + if ($action == 'settracking_url') $object->tracking_url = trim(GETPOST('tracking_url','int')); + if ($action == 'settrueWeight') { + $object->trueWeight = trim(GETPOST('trueWeight','int')); + $object->weight_units = GETPOST('weight_units','int'); + } + if ($action == 'settrueWidth') $object->trueWidth = trim(GETPOST('trueWidth','int')); + if ($action == 'settrueHeight'){ + $object->trueHeight = trim(GETPOST('trueHeight','int')); + $object->size_units = GETPOST('size_units','int'); + } + if ($action == 'settrueDepth') $object->trueDepth = trim(GETPOST('trueDepth','int')); + if ($action == 'setshipping_method_id') $object->shipping_method_id = trim(GETPOST('shipping_method_id','int')); + + if (! $error) + { + if ($object->update($user) >= 0) + { + header("Location: card.php?id=".$object->id); + exit; + } + setEventMessages($object->error, $object->errors, 'errors'); + } + + $action=""; + } + + // Build document + else if ($action == 'builddoc') // En get ou en post + { + // Save last template used to generate document + if (GETPOST('model')) $object->setDocModel($user, GETPOST('model','alpha')); + + // Define output language + $outputlangs = $langs; + $newlang=''; + if ($conf->global->MAIN_MULTILANGS && empty($newlang) && GETPOST('lang_id','aZ09')) $newlang=GETPOST('lang_id','aZ09'); + if ($conf->global->MAIN_MULTILANGS && empty($newlang)) $newlang=$reception->thirdparty->default_lang; + if (! empty($newlang)) + { + $outputlangs = new Translate("",$conf); + $outputlangs->setDefaultLang($newlang); + } + $result = $object->generateDocument($object->modelpdf, $outputlangs, $hidedetails, $hidedesc, $hideref); + if ($result <= 0) + { + setEventMessages($object->error, $object->errors, 'errors'); + $action=''; + } + } + + // Delete file in doc form + elseif ($action == 'remove_file') + { + require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php'; + + $upload_dir = $conf->reception->dir_output ; + $file = $upload_dir . '/' . GETPOST('file'); + $ret=dol_delete_file($file,0,0,0,$object); + if ($ret) setEventMessages($langs->trans("FileWasRemoved", GETPOST('urlfile')), null, 'mesgs'); + else setEventMessages($langs->trans("ErrorFailToDeleteFile", GETPOST('urlfile')), null, 'errors'); + } + + elseif ($action == 'classifybilled') + { + $object->fetch($id); + $result = $object->set_billed(); + if($result >= 0) { + header('Location: ' . $_SERVER["PHP_SELF"] . '?id=' . $object->id); + exit(); + } + } + + elseif ($action == 'classifyclosed') + { + $object->fetch($id); + $result = $object->setClosed(); + if($result >= 0) { + header('Location: ' . $_SERVER["PHP_SELF"] . '?id=' . $object->id); + exit(); + } + } + + /* + * delete a line + */ + elseif ($action == 'deleteline' && ! empty($line_id)) + { + $object->fetch($id); + $lines = $object->lines; + $line = new CommandeFournisseurDispatch($db); + + $num_prod = count($lines); + for ($i = 0 ; $i < $num_prod ; $i++) + { + if ($lines[$i]->id == $line_id) + { + + // delete single warehouse line + $line->id = $line_id; + if (! $error && $line->delete($user) < 0) + { + $error++; + } + + } + unset($_POST["lineid"]); + } + + if(! $error) { + header('Location: ' . $_SERVER["PHP_SELF"] . '?id=' . $object->id); + exit(); + } + else + { + setEventMessages($line->error, $line->errors, 'errors'); + } + } + + /* + * Update a line + */ + else if ($action == 'updateline' && $user->rights->reception->creer && GETPOST('save')) + { + // Clean parameters + $qty = 0; + $entrepot_id = 0; + $batch_id = 0; + + $lines = $object->lines; + $num_prod = count($lines); + for ($i = 0; $i < $num_prod; $i++) + { + if ($lines[$i]->id == $line_id) // we have found line to update + { + $line = new CommandeFournisseurDispatch($db); + $line->fetch($line_id); + // Extrafields Lines + $extrafieldsline = new ExtraFields($db); + $extralabelsline = $extrafieldsline->fetch_name_optionals_label($object->table_element_line); + $line->array_options = $extrafieldsline->getOptionalsFromPost($extralabelsline); + + + $line->fk_product = $lines[$i]->fk_product; + + + + + if ($lines[$i]->fk_product > 0) + { + + // single warehouse reception line + $stockLocation = "entl".$line_id; + $qty = "qtyl".$line_id; + $comment = "comment".$line_id; + + + $line->id = $line_id; + $line->fk_entrepot = GETPOST($stockLocation, 'int'); + $line->qty = GETPOST($qty, 'int'); + $line->comment = GETPOST($comment, 'alpha'); + + if(!empty($conf->productbatch->enabled)){ + $batch = "batch".$line_id; + $dlc = "dlc".$line_id; + $dluo = "dluo".$line_id; + $eatby = GETPOST($dlc, 'alpha'); + $eatbydate = str_replace('/','-',$eatby); + $sellby = GETPOST($dluo, 'alpha'); + $sellbydate = str_replace('/','-',$sellby); + $line->batch = GETPOST($batch, 'alpha'); + $line->eatby = strtotime($eatbydate); + $line->sellby = strtotime($sellbydate); + } + + + + if ($line->update($user) < 0) + { + setEventMessages($line->error, $line->errors, 'errors'); + $error++; + } + + + + } + else // Product no predefined + { + $qty = "qtyl".$line_id; + $line->id = $line_id; + $line->qty = GETPOST($qty, 'int'); + $line->fk_entrepot = 0; + if ($line->update($user) < 0) + { + setEventMessages($line->error, $line->errors, 'errors'); + $error++; + } + unset($_POST[$qty]); + } + } + } + + unset($_POST["lineid"]); + + if (! $error) { + if (empty($conf->global->MAIN_DISABLE_PDF_AUTOUPDATE)) { + // Define output language + $outputlangs = $langs; + $newlang = ''; + if ($conf->global->MAIN_MULTILANGS && empty($newlang) && GETPOST('lang_id','aZ09')) + $newlang = GETPOST('lang_id','aZ09'); + if ($conf->global->MAIN_MULTILANGS && empty($newlang)) + $newlang = $object->thirdparty->default_lang; + if (! empty($newlang)) { + $outputlangs = new Translate("", $conf); + $outputlangs->setDefaultLang($newlang); + } + + $ret = $object->fetch($object->id); // Reload to get new records + $object->generateDocument($object->modelpdf, $outputlangs, $hidedetails, $hidedesc, $hideref); + } + } + else + { + header('Location: ' . $_SERVER['PHP_SELF'] . '?id=' . $object->id); // Pour reaffichage de la fiche en cours d'edition + exit(); + } + } + + else if ($action == 'updateline' && $user->rights->reception->creer && GETPOST('cancel','alpha') == $langs->trans('Cancel')) { + header('Location: ' . $_SERVER['PHP_SELF'] . '?id=' . $object->id); // Pour reaffichage de la fiche en cours d'edition + exit(); + } + + include DOL_DOCUMENT_ROOT.'/core/actions_printing.inc.php'; + + // Actions to send emails + if (empty($id)) $id=$facid; + $trigger_name='RECEPTION_SENTBYMAIL'; + $paramname='id'; + $mode='emailfromreception'; + $trackid='shi'.$object->id; + include DOL_DOCUMENT_ROOT.'/core/actions_sendmails.inc.php'; + +} + + +/* + * View + */ + +llxHeader('',$langs->trans('Reception'),'Reception'); + +$form = new Form($db); +$formfile = new FormFile($db); +$formproduct = new FormProduct($db); +if (! empty($conf->projet->enabled)) { $formproject = new FormProjets($db); } + +$product_static = new Product($db); +$reception_static = new Reception($db); +$warehousestatic = new Entrepot($db); + +if ($action == 'create2') +{ + print load_fiche_titre($langs->trans("CreateReception")).'
'; + print $langs->trans("ReceptionCreationIsDoneFromOrder"); + $action=''; $id=''; $ref=''; +} + +// Mode creation. +if ($action == 'create') +{ + $recept = new Reception($db); + + print load_fiche_titre($langs->trans("CreateReception")); + if (! $origin) + { + setEventMessages($langs->trans("ErrorBadParameters"), null, 'errors'); + } + + if ($origin) + { + if($origin == 'supplierorder')$classname = 'CommandeFournisseur'; + else $classname = ucfirst($origin); + + $object = new $classname($db); + if ($object->fetch($origin_id)) // This include the fetch_lines + { + $soc = new Societe($db); + $soc->fetch($object->socid); + + $author = new User($db); + $author->fetch($object->user_author_id); + + if (! empty($conf->stock->enabled)) $entrepot = new Entrepot($db); + + print ''; + print ''; + print ''; + print ''; + print ''; + print ''; + if (GETPOST('entrepot_id','int')) + { + print ''; + } + + dol_fiche_head(''); + + print '
' . $langs->trans("Reception") . '' . $langs->trans("Product") . '' . $langs->trans("DateCreation") . '' . $langs->trans("DateDeliveryPlanned") . '' . $langs->trans("batch_number") . '' . $langs->trans("EatByDate") . '' . $langs->trans("Warehouse") . '' . $langs->trans("Comment") . '' . $langs->trans("Status") . '' . $langs->trans("Date") . '
'; + if (!empty($objp->fk_reception)){ + + $reception = new Reception($db); + $reception->fetch($objp->fk_reception); + print $reception->getNomUrl(1); + } + + print "'; print '' . img_object($langs->trans("ShowProduct"), 'product') . ' ' . $objp->ref . ''; print ' - ' . $objp->label; print "'.dol_print_date($db->jdate($objp->datec),'day').''.dol_print_date($db->jdate($objp->date_delivery),'day').'' . $objp->batch . '' . $objp->comment . '' . $objp->comment . ''; $supplierorderdispatch->status = (empty($objp->status) ? 0 : $objp->status); // print $supplierorderdispatch->status; @@ -859,9 +886,17 @@ if ($id > 0 || ! empty($ref)) { } } print ''; + if(!empty($reception->id)){ + print $reception->getLibStatut(5); + } } - // date - print '' . dol_print_date($objp->datec, "dayhour") . ''; + print '
'.$langs->trans('RefSupplier').'
'.$langs->trans('RefSupplier').'
'.$langs->trans('NotePublic').''; $note_public = $object->getDefaultCreateValueFor('note_public'); + if(empty($note_public))$note_public = $objectsrc->note_public; $doleditor = new DolEditor('note_public', $note_public, '', 80, 'dolibarr_notes', 'In', 0, false, true, ROWS_3, '90%'); print $doleditor->Create(1); print '
'.$langs->trans('NotePrivate').''; $note_private = $object->getDefaultCreateValueFor('note_private'); + if(empty($note_private))$note_private = $objectsrc->note_private; + $doleditor = new DolEditor('note_private', $note_private, '', 80, 'dolibarr_notes', 'In', 0, false, true, ROWS_3, '90%'); print $doleditor->Create(1); print '
'; print $form->textwithpicto($langs->trans("PhysicalStock"), $text_stock_options, 1); print '
'; + + // Ref + print ''; + print "\n"; + // Ref client + print ''; + print ''; + + // Tiers + print ''; + print ''; + print ''; + + // Project + if (! empty($conf->projet->enabled)) + { + $projectid = GETPOST('projectid','int')?GETPOST('projectid','int'):0; + if(empty($projectid) && ! empty($object->fk_project)) $projectid = $object->fk_project; + if ($origin == 'project') $projectid = ($originid ? $originid : 0); + + $langs->load("projects"); + print ''; + print ''; + print ''; + } + + // Date delivery planned + print ''; + print '\n"; + print ''; + + // Note Public + print ''; + print '"; + + // Note Private + if ($object->note_private && ! $user->societe_id) + { + print ''; + print '"; + } + + // Weight + print ''; + // Dim + print ''; + + // Delivery method + print ""; + print '\n"; + + // Tracking number + print ""; + print '\n"; + + // Other attributes + $parameters = array('objectsrc' => $objectsrc, 'colspan' => ' colspan="3"', 'socid'=>$socid); + $reshook=$hookmanager->executeHooks('formObjectOptions',$parameters,$recept,$action); // Note that $action and $object may have been modified by hook + print $hookmanager->resPrint; + + if (empty($reshook) && ! empty($extrafields->attribute_label)) { + // copy from order + $orderExtrafields = new Extrafields($db); + $orderExtrafieldLabels = $orderExtrafields->fetch_name_optionals_label($object->table_element); + if ($object->fetch_optionals($object->id, $orderExtrafieldLabels) > 0) { + $recept->array_options = array_merge($recept->array_options, $object->array_options); + } + print $object->showOptionals($extrafields, 'edit'); + } + + + // Incoterms + if (!empty($conf->incoterm->enabled)) + { + print ''; + print ''; + print ''; + } + + // Document model + include_once DOL_DOCUMENT_ROOT . '/core/modules/reception/modules_reception.php'; + $liste = ModelePdfReception::liste_modeles($db); + + if (count($liste) > 1) + { + print ""; + print '\n"; + } + + print "
'; + if ($origin == 'supplierorder' && ! empty($conf->fournisseur->enabled)) + { + print $langs->trans("RefOrder").''.img_object($langs->trans("ShowOrder"),'order').' '.$object->ref; + } + if ($origin == 'propal' && ! empty($conf->propal->enabled)) + { + print $langs->trans("RefProposal").''.img_object($langs->trans("ShowProposal"),'propal').' '.$object->ref; + } + print '
'; + if ($origin == 'supplier_order') print $langs->trans('RefSupplierOrder'); + else print $langs->trans('RefSupplier'); + print ''; + print ''; + print '
'.$langs->trans('Company').''.$soc->getNomUrl(1).'
' . $langs->trans("Project") . ''; + $numprojet = $formproject->select_projects($soc->id, $projectid, 'projectid', 0); + print '   id).'">' . $langs->trans("AddProject") . ''; + print '
'.$langs->trans("DateDeliveryPlanned").''; + //print dol_print_date($object->date_livraison,"day"); // date_livraison come from order and will be stored into date_delivery planed. + $date_delivery = ($date_delivery?$date_delivery:$object->date_livraison); // $date_delivery comes from GETPOST + print $form->select_date($date_delivery?$date_delivery:-1,'date_delivery',1,1,1); + print "
'.$langs->trans("NotePublic").''; + $doleditor = new DolEditor('note_public', $object->note_public, '', 60, 'dolibarr_notes', 'In', 0, false, true, ROWS_3, '90%'); + print $doleditor->Create(1); + print "
'.$langs->trans("NotePrivate").''; + $doleditor = new DolEditor('note_private', $object->note_private, '', 60, 'dolibarr_notes', 'In', 0, false, true, ROWS_3, '90%'); + print $doleditor->Create(1); + print "
'; + print $langs->trans("Weight"); + print ' '; + $text=$formproduct->select_measuring_units("weight_units","weight",GETPOST('weight_units','int')); + $htmltext=$langs->trans("KeepEmptyForAutoCalculation"); + print $form->textwithpicto($text, $htmltext); + print '
'; + print $langs->trans("Width").' x '.$langs->trans("Height").' x '.$langs->trans("Depth"); + print ' '; + print ' x '; + print ' x '; + print ' '; + $text=$formproduct->select_measuring_units("size_units","size"); + $htmltext=$langs->trans("KeepEmptyForAutoCalculation"); + print $form->textwithpicto($text, $htmltext); + print '
".$langs->trans("ReceptionMethod")."'; + $recept->fetch_delivery_methods(); + print $form->selectarray("shipping_method_id", $recept->meths, GETPOST('shipping_method_id','int'),1,0,0,"",1); + if ($user->admin) print info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"),1); + print "
".$langs->trans("TrackingNumber")."'; + print ''; + print "
'; + print $form->select_incoterms((!empty($object->fk_incoterms) ? $object->fk_incoterms : ''), (!empty($object->location_incoterms)?$object->location_incoterms:'')); + print '
".$langs->trans("DefaultModel")."'; + print $form->selectarray('model', $liste, $conf->global->RECEPTION_ADDON_PDF); + print "
"; + + dol_fiche_end(); + + + // Reception lines + $numAsked=0; + $dispatchLines = array(); + foreach ($_POST as $key => $value) + { + // without batch module enabled + if (preg_match('/^product_([0-9]+)_([0-9]+)$/i', $key, $reg)) + { + $numAsked ++; + + // $numline=$reg[2] + 1; // line of product + $numline = $numAsked; + $prod = "product_".$reg[1].'_'.$reg[2]; + $qty = "qty_".$reg[1].'_'.$reg[2]; + $ent = "entrepot_".$reg[1].'_'.$reg[2]; + $pu = "pu_".$reg[1].'_'.$reg[2]; // This is unit price including discount + $fk_commandefourndet = "fk_commandefourndet_".$reg[1].'_'.$reg[2]; + $dispatchLines[$numAsked]=array('prod' => GETPOST($prod, 'int'), 'qty' =>GETPOST($qty), 'ent' =>GETPOST($ent, 'int'), 'pu' =>GETPOST($pu), 'comment' =>GETPOST('comment'),'fk_commandefourndet' => GETPOST($fk_commandefourndet, 'int')); + + + } + // with batch module enabled + if (preg_match('/^product_batch_([0-9]+)_([0-9]+)$/i', $key, $reg)) + { + +$numAsked ++; + // eat-by date dispatch + // $numline=$reg[2] + 1; // line of product + $numline = $numAsked; + $prod = 'product_batch_'.$reg[1].'_'.$reg[2]; + $qty = 'qty_'.$reg[1].'_'.$reg[2]; + $ent = 'entrepot_'.$reg[1].'_'.$reg[2]; + $pu = 'pu_'.$reg[1].'_'.$reg[2]; + $lot = 'lot_number_'.$reg[1].'_'.$reg[2]; + $dDLUO = dol_mktime(12, 0, 0, $_POST['dluo_'.$reg[1].'_'.$reg[2].'month'], $_POST['dluo_'.$reg[1].'_'.$reg[2].'day'], $_POST['dluo_'.$reg[1].'_'.$reg[2].'year']); + $dDLC = dol_mktime(12, 0, 0, $_POST['dlc_'.$reg[1].'_'.$reg[2].'month'], $_POST['dlc_'.$reg[1].'_'.$reg[2].'day'], $_POST['dlc_'.$reg[1].'_'.$reg[2].'year']); + $fk_commandefourndet = 'fk_commandefourndet_'.$reg[1].'_'.$reg[2]; + $dispatchLines[$numAsked]=array('prod' => GETPOST($prod, 'int'), 'qty' =>GETPOST($qty), 'ent' =>GETPOST($ent, 'int'), 'pu' =>GETPOST($pu), 'comment' =>GETPOST('comment'),'fk_commandefourndet' => GETPOST($fk_commandefourndet, 'int'),'DLC'=> $dDLC,'DLUO'=> $dDLUO,'lot'=> GETPOST($lot, 'alpha')); + + } + } + + + print ''; + + + print '
'; + + + print ''; + + + // Load receptions already done for same order + $object->loadReceptions(); + + if ($numAsked) + { + print ''; + print ''; + print ''; + print ''; + print ''; + if (! empty($conf->stock->enabled)) + { + + print ''; + + } + if (!empty($conf->productbatch->enabled)) + { + print ''; + print ''; + print ''; + } + print "\n"; + } + + $var=true; + $indiceAsked =1; + while ($indiceAsked <= $numAsked) + { + $product = new Product($db); + foreach($object->lines as $supplierLine){ + if($dispatchLines[$indiceAsked]['fk_commandefourndet'] == $supplierLine->id){ + $line = $supplierLine; + break; + } + } + + + // Show product and description + $type=$line->product_type?$line->product_type:$line->fk_product_type; + // Try to enhance type detection using date_start and date_end for free lines where type + // was not saved. + if (! empty($line->date_start)) $type=1; + if (! empty($line->date_end)) $type=1; + + print ''."\n"; + print ''."\n"; + + + // Product label + if ($line->fk_product > 0) // If predefined product + { + $product->fetch($line->fk_product); + $product->load_stock('warehouseopen'); // Load all $product->stock_warehouse[idwarehouse]->detail_batch + //var_dump($product->stock_warehouse[1]); + + print ''; + } + else + { + print "\n"; + } + + // Qty + print ''; + $qtyProdCom=$line->qty; + + // Qty already received + print ''; + + + if ($line->product_type == 1 && empty($conf->global->STOCK_SUPPORTS_SERVICES)) + { + $quantityToBeDelivered = 0; + } + else + { + $quantityToBeDelivered = $dispatchLines[$indiceAsked]['qty']; + } + $warehouse_id = $dispatchLines[$indiceAsked]['ent']; + + + $warehouseObject = null; + if ( !empty($conf->stock->enabled)) // If warehouse was already selected or if product is not a predefined, we go into this part with no multiwarehouse selection + { + print ''; + + $stock = + $product->stock_warehouse[$dispatchLines[$indiceAsked]['ent']]->real; // Convert to number + $deliverableQty=$dispatchLines[$indiceAsked]['qty']; + + + + // Quantity to send + print ''; + + // Stock + if (! empty($conf->stock->enabled)) + { + print ''; + } + + if(!empty($conf->productbatch->enabled) ){ + if( !empty($product->status_batch)){ + print ''; + print ''; + print ''; + }else { + print ''; + + } + + + } + print "\n"; + + + + + } + + + + + //Display lines extrafields + if (is_array($extralabelslines) && count($extralabelslines)>0) + { + $colspan=5; + if($conf->productbatch->enabled)$colspan+=3; + $orderLineExtrafields = new Extrafields($db); + $orderLineExtrafieldLabels = $orderLineExtrafields->fetch_name_optionals_label($object->table_element_line); + $srcLine = new CommandeFournisseurLigne($db); + $srcLine->fetch_optionals($line->id,$orderLineExtrafieldLabels); // fetch extrafields also available in orderline + $line = new CommandeFournisseurDispatch($db); + $line->fetch_optionals($object->id,$extralabelslines); + $line->array_options = array_merge($line->array_options, $srcLine->array_options); + print ''; + print $line->showOptionals($extrafieldsline, 'edit', array('style'=>$bc[$var], 'colspan'=>$colspan),$indiceAsked); + print ''; + } + + $indiceAsked++; + } + + print "
'.$langs->trans("Description").''.$langs->trans("QtyOrdered").''.$langs->trans("QtyReceived").''.$langs->trans("QtyToReceive"); + if (empty($conf->productbatch->enabled)) + { + print '
('.$langs->trans("Fill").''; + print ' / '.$langs->trans("Reset").')'; + } + print '
'.$langs->trans("Warehouse").' ('.$langs->trans("Stock").')'.$langs->trans("batch_number").''.$langs->trans("EatByDate").''.$langs->trans("SellByDate").'
'; + print ''; // ancre pour retourner sur la ligne + + // Show product and description + $product_static->type=$line->fk_product_type; + $product_static->id=$line->fk_product; + $product_static->ref=$line->ref; + $product_static->status_batch=$line->product_tobatch; + + $text=$product_static->getNomUrl(1); + $text.= ' - '.(! empty($line->label)?$line->label:$line->product_label); + $description=($conf->global->PRODUIT_DESC_IN_FORM?'':dol_htmlentitiesbr($line->desc)); + print $form->textwithtooltip($text,$description,3,'','',$i); + + // Show range + print_date_range($db->jdate($line->date_start),$db->jdate($line->date_end)); + + // Add description in form + if (! empty($conf->global->PRODUIT_DESC_IN_FORM)) + { + print ($line->desc && $line->desc!=$line->product_label)?'
'.dol_htmlentitiesbr($line->desc):''; + } + + print '
"; + if ($type==1) $text = img_object($langs->trans('Service'),'service'); + else $text = img_object($langs->trans('Product'),'product'); + + if (! empty($line->label)) { + $text.= ' '.$line->label.''; + print $form->textwithtooltip($text,$line->desc,3,'','',$i); + } else { + print $text.' '.nl2br($line->desc); + } + + // Show range + print_date_range($db->jdate($line->date_start),$db->jdate($line->date_end)); + print "'.$line->qty; + print 'id.'\' />'; + print ''; + print ''; + print ''; + + + $quantityDelivered = $object->receptions[$line->id]; + print $quantityDelivered; + print ''; + print ''; + if ($line->product_type == Product::TYPE_PRODUCT || ! empty($conf->global->STOCK_SUPPORTS_SERVICES)) + { + if (GETPOST('qtyl'.$indiceAsked, 'int')) $defaultqty=GETPOST('qtyl'.$indiceAsked, 'int'); + print ''; + print ''; + } + else print $langs->trans("NA"); + print ''; + if ($line->product_type == Product::TYPE_PRODUCT || ! empty($conf->global->STOCK_SUPPORTS_SERVICES)) // Type of product need stock change ? + { + // Show warehouse combo list + $ent = "entl".$indiceAsked; + $idl = "idl".$indiceAsked; + $tmpentrepot_id = is_numeric(GETPOST($ent,'int'))?GETPOST($ent,'int'):$warehouse_id; + if ($line->fk_product > 0) + { + print ''; + print $formproduct->selectWarehouses($tmpentrepot_id, 'entl'.$indiceAsked, '', 0 , 0, $line->fk_product, '', 1); + + } + } + else + { + print $langs->trans("Service"); + } + print ''; + print $form->select_date($dispatchLines[$indiceAsked]['DLC'],'dlc' . $indiceAsked, '', '', 1, ""); + print ''; + print $form->select_date($dispatchLines[$indiceAsked]['DLUO'],'dluo' . $indiceAsked, '', '', 1, ""); + print '
"; + + print '
'; + + print '
'; + print ''; + print '  '; + print ''; // Cancel for create does not post form if we don't know the backtopage + print '
'; + + print ''; + + print '
'; + } + else + { + dol_print_error($db); + } + } +} +else if ($id || $ref) +/* *************************************************************************** */ +/* */ +/* Edit and view mode */ +/* */ +/* *************************************************************************** */ +{ + $lines = $object->lines; + + $num_prod = count($lines); + + if ($object->id > 0) + { + if (!empty($object->origin) && $object->origin_id > 0) + { + $object->origin = 'CommandeFournisseur'; + $typeobject = $object->origin; + $origin = $object->origin; + $origin_id = $object->origin_id; + $object->fetch_origin(); // Load property $object->commande, $object->propal, ... + } + + $soc = new Societe($db); + $soc->fetch($object->socid); + + $res = $object->fetch_optionals($object->id, $extralabels); + + $head=reception_prepare_head($object); + dol_fiche_head($head, 'reception', $langs->trans("Reception"), -1, 'reception'); + + $formconfirm=''; + + // Confirm deleteion + if ($action == 'delete') + { + $formconfirm=$form->formconfirm($_SERVER['PHP_SELF'].'?id='.$object->id,$langs->trans('DeleteReception'),$langs->trans("ConfirmDeleteReception",$object->ref),'confirm_delete','',0,1); + } + + // Confirmation validation + if ($action == 'valid') + { + $objectref = substr($object->ref, 1, 4); + if ($objectref == 'PROV') + { + $numref = $object->getNextNumRef($soc); + } + else + { + $numref = $object->ref; + } + + $text = $langs->trans("ConfirmValidateReception",$numref); + + if (! empty($conf->notification->enabled)) + { + require_once DOL_DOCUMENT_ROOT .'/core/class/notify.class.php'; + $notify=new Notify($db); + $text.='
'; + $text.=$notify->confirmMessage('RECEPTION_VALIDATE',$object->socid, $object); + } + + $formconfirm=$form->formconfirm($_SERVER['PHP_SELF'].'?id='.$object->id,$langs->trans('ValidateReception'),$text,'confirm_valid','',0,1); + + } + // Confirm cancelation + if ($action == 'annuler') + { + $formconfirm=$form->formconfirm($_SERVER['PHP_SELF'].'?id='.$object->id,$langs->trans('CancelReception'),$langs->trans("ConfirmCancelReception",$object->ref),'confirm_cancel','',0,1); + + } + + if (! $formconfirm) { + $parameters = array(); + $reshook = $hookmanager->executeHooks('formConfirm', $parameters, $object, $action); // Note that $action and $object may have been modified by hook + if (empty($reshook)) $formconfirm.=$hookmanager->resPrint; + elseif ($reshook > 0) $formconfirm=$hookmanager->resPrint; + } + + // Print form confirm + print $formconfirm; + + + // Calculate totalWeight and totalVolume for all products + // by adding weight and volume of each product line. + $tmparray=$object->getTotalWeightVolume(); + $totalWeight=$tmparray['weight']; + $totalVolume=$tmparray['volume']; + + + if ($typeobject == 'commande' && $object->$typeobject->id && ! empty($conf->commande->enabled)) + { + $objectsrc=new Commande($db); + $objectsrc->fetch($object->$typeobject->id); + } + if ($typeobject == 'propal' && $object->$typeobject->id && ! empty($conf->propal->enabled)) + { + $objectsrc=new Propal($db); + $objectsrc->fetch($object->$typeobject->id); + } + if ($typeobject == 'CommandeFournisseur' && $object->$typeobject->id && ! empty($conf->fournisseur->enabled)) + { + $objectsrc=new CommandeFournisseur($db); + $objectsrc->fetch($object->$typeobject->id); + } + // Reception card + $linkback = ''.$langs->trans("BackToList").''; + $morehtmlref='
'; + // Ref customer reception + + $morehtmlref.=$form->editfieldkey("RefSupplier", 'ref_supplier', $object->ref_supplier, $object, $user->rights->reception->creer, 'string', '', 0, 1); + $morehtmlref.=$form->editfieldval("RefSupplier", 'ref_supplier', $object->ref_supplier, $object, $user->rights->reception->creer, 'string', '', null, null, '', 1); + + // Thirdparty + $morehtmlref.='
'.$langs->trans('ThirdParty') . ' : ' . $object->thirdparty->getNomUrl(1); + // Project + if (! empty($conf->projet->enabled)) { + $langs->load("projects"); + $morehtmlref .= '
' . $langs->trans('Project') . ' '; + if (0) { // Do not change on reception + if ($action != 'classify') { + $morehtmlref .= '' . img_edit($langs->transnoentitiesnoconv('SetProject')) . ' : '; + } + if ($action == 'classify') { + // $morehtmlref.=$form->form_project($_SERVER['PHP_SELF'] . '?id=' . $object->id, $object->socid, $object->fk_project, 'projectid', 0, 0, 1, 1); + $morehtmlref .= '
'; + $morehtmlref .= ''; + $morehtmlref .= ''; + $morehtmlref .= $formproject->select_projects($object->socid, $object->fk_project, 'projectid', $maxlength, 0, 1, 0, 1, 0, 0, '', 1); + $morehtmlref .= ''; + $morehtmlref .= '
'; + } else { + $morehtmlref .= $form->form_project($_SERVER['PHP_SELF'] . '?id=' . $object->id, $object->socid, $object->fk_project, 'none', 0, 0, 0, 1); + } + } else { + // We don't have project on reception, so we will use the project or source object instead + // TODO Add project on reception + $morehtmlref .= ' : '; + if (! empty($objectsrc->fk_project)) { + $proj = new Project($db); + $proj->fetch($objectsrc->fk_project); + $morehtmlref .= ''; + $morehtmlref .= $proj->ref; + $morehtmlref .= ''; + } else { + $morehtmlref .= ''; + } + } + } + $morehtmlref.='
'; + + $object->picto = 'sending'; + dol_banner_tab($object, 'ref', $linkback, 1, 'ref', 'ref', $morehtmlref); + + + print '
'; + print '
'; + print '
'; + + print ''; + + // Linked documents + if ($typeobject == 'commande' && $object->$typeobject->id && ! empty($conf->commande->enabled)) + { + print ''; + print '\n"; + print ''; + } + if ($typeobject == 'propal' && $object->$typeobject->id && ! empty($conf->propal->enabled)) + { + print ''; + print '\n"; + print ''; + } + if ($typeobject == 'CommandeFournisseur' && $object->$typeobject->id && ! empty($conf->propal->enabled)) + { + print ''; + print '\n"; + print ''; + } + + // Date creation + print ''; + print '\n"; + print ''; + + // Delivery date planned + print ''; + print ''; + + // Weight + print ''; + + // Width + print ''; + + // Height + print ''; + + // Depth + print ''; + + // Volume + print ''; + print '\n"; + print ''; + + // Other attributes + $cols = 2; + + include DOL_DOCUMENT_ROOT . '/core/tpl/extrafields_view.tpl.php'; + + print '
'; + print $langs->trans("RefOrder").''; + print $objectsrc->getNomUrl(1,'commande'); + print "
'; + print $langs->trans("RefProposal").''; + print $objectsrc->getNomUrl(1,'reception'); + print "
'; + print $langs->trans("RefSupplierOrder").''; + print $objectsrc->getNomUrl(1,'reception'); + print "
'.$langs->trans("DateCreation").''.dol_print_date($object->date_creation,"dayhour")."
'; + print ''; + + if ($action != 'editdate_livraison') print ''; + print '
'; + print $langs->trans('DateDeliveryPlanned'); + print 'id.'">'.img_edit($langs->trans('SetDeliveryDate'),1).'
'; + print '
'; + if ($action == 'editdate_livraison') + { + print '
'; + print ''; + print ''; + print $form->select_date($object->date_delivery?$object->date_delivery:-1,'liv_',1,1,'',"setdate_livraison",1,0,1); + print ''; + print '
'; + } + else + { + print $object->date_delivery ? dol_print_date($object->date_delivery,'dayhour') : ' '; + } + print '
'; + print $form->editfieldkey("Weight",'trueWeight',$object->trueWeight,$object,$user->rights->reception->creer); + print ''; + + if ($action=='edittrueWeight') + { + print '
'; + print ''; + print ''; + print ''; + print ''; + print $formproduct->select_measuring_units("weight_units","weight",$object->weight_units); + print ' '; + print ' '; + print '
'; + + } + else + { + print $object->trueWeight; + print ($object->trueWeight && $object->weight_units!='')?' '.measuring_units_string($object->weight_units,"weight"):''; + } + + // Calculated + if ($totalWeight > 0) + { + if (!empty($object->trueWeight)) print ' ('.$langs->trans("SumOfProductWeights").': '; + //print $totalWeight.' '.measuring_units_string(0,"weight"); + print showDimensionInBestUnit($totalWeight, 0, "weight", $langs, isset($conf->global->MAIN_WEIGHT_DEFAULT_ROUND)?$conf->global->MAIN_WEIGHT_DEFAULT_ROUND:-1, isset($conf->global->MAIN_WEIGHT_DEFAULT_UNIT)?$conf->global->MAIN_WEIGHT_DEFAULT_UNIT:'no'); + //if (empty($object->trueWeight)) print ' ('.$langs->trans("Calculated").')'; + if (!empty($object->trueWeight)) print ')'; + } + print '
'.$form->editfieldkey("Width",'trueWidth',$object->trueWidth,$object,$user->rights->reception->creer).''; + print $form->editfieldval("Width",'trueWidth',$object->trueWidth,$object,$user->rights->reception->creer); + print ($object->trueWidth && $object->width_units!='')?' '.measuring_units_string($object->width_units,"size"):''; + print '
'.$form->editfieldkey("Height",'trueHeight',$object->trueHeight,$object,$user->rights->reception->creer).''; + if($action=='edittrueHeight') + { + print '
'; + print ''; + print ''; + print ''; + print ''; + print $formproduct->select_measuring_units("size_units","size",$object->size_units); + print ' '; + print ' '; + print '
'; + + } + else + { + print $object->trueHeight; + print ($object->trueHeight && $object->height_units!='')?' '.measuring_units_string($object->height_units,"size"):''; + } + + print '
'.$form->editfieldkey("Depth",'trueDepth',$object->trueDepth,$object,$user->rights->reception->creer).''; + print $form->editfieldval("Depth",'trueDepth',$object->trueDepth,$object,$user->rights->reception->creer); + print ($object->trueDepth && $object->depth_units!='')?' '.measuring_units_string($object->depth_units,"size"):''; + print '
'; + print $langs->trans("Volume"); + print ''; + $calculatedVolume=0; + $volumeUnit=0; + if ($object->trueWidth && $object->trueHeight && $object->trueDepth) + { + $calculatedVolume=($object->trueWidth * $object->trueHeight * $object->trueDepth); + $volumeUnit=$object->size_units * 3; + } + // If reception volume not defined we use sum of products + if ($calculatedVolume > 0) + { + if ($volumeUnit < 50) + { + //print $calculatedVolume.' '.measuring_units_string($volumeUnit,"volume"); + print showDimensionInBestUnit($calculatedVolume, $volumeUnit, "volume", $langs, isset($conf->global->MAIN_VOLUME_DEFAULT_ROUND)?$conf->global->MAIN_VOLUME_DEFAULT_ROUND:-1, isset($conf->global->MAIN_VOLUME_DEFAULT_UNIT)?$conf->global->MAIN_VOLUME_DEFAULT_UNIT:'no'); + } + else print $calculatedVolume.' '.measuring_units_string($volumeUnit,"volume"); + } + if ($totalVolume > 0) + { + if ($calculatedVolume) print ' ('.$langs->trans("SumOfProductVolumes").': '; + //print $totalVolume.' '.measuring_units_string(0,"volume"); + print showDimensionInBestUnit($totalVolume, 0, "volume", $langs, isset($conf->global->MAIN_VOLUME_DEFAULT_ROUND)?$conf->global->MAIN_VOLUME_DEFAULT_ROUND:-1, isset($conf->global->MAIN_VOLUME_DEFAULT_UNIT)?$conf->global->MAIN_VOLUME_DEFAULT_UNIT:'no'); + //if (empty($calculatedVolume)) print ' ('.$langs->trans("Calculated").')'; + if ($calculatedVolume) print ')'; + } + print "
'; + + print '
'; + print '
'; + print '
'; + print '
'; + + print ''; + + // Reception method + print ''; + print ''; + + // Tracking Number + + print ''; + + // Incoterms + if (!empty($conf->incoterm->enabled)) + { + print ''; + print ''; + } + + print "
'; + print ''; + + if ($action != 'editshipping_method_id') print ''; + print '
'; + print $langs->trans('ReceptionMethod'); + print 'id.'">'.img_edit($langs->trans('SetReceptionMethod'),1).'
'; + print '
'; + if ($action == 'editshipping_method_id') + { + print '
'; + print ''; + print ''; + $object->fetch_delivery_methods(); + print $form->selectarray("shipping_method_id",$object->meths,$object->shipping_method_id,1,0,0,"",1); + if ($user->admin) print info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"),1); + print ''; + print '
'; + } + else + { + if ($object->shipping_method_id > 0) + { + // Get code using getLabelFromKey + $code=$langs->getLabelFromKey($db,$object->shipping_method_id,'c_shipment_mode','rowid','code'); + print $langs->trans("SendingMethod".strtoupper($code)); + } + } + print '
'.$form->editfieldkey("TrackingNumber",'tracking_number',$object->tracking_number,$object,$user->rights->reception->creer).''; + print $form->editfieldval("TrackingNumber",'tracking_number',$object->tracking_url,$object,$user->rights->reception->creer,'string',$object->tracking_number); + print '
'; + print '
'; + print $langs->trans('IncotermLabel'); + print ''; + if ($user->rights->reception->creer) print ''.img_edit().''; + else print ' '; + print '
'; + print '
'; + if ($action != 'editincoterm') + { + print $form->textwithpicto($object->display_incoterms(), $object->libelle_incoterms, 1); + } + else + { + print $form->select_incoterms((!empty($object->fk_incoterms) ? $object->fk_incoterms : ''), (!empty($object->location_incoterms)?$object->location_incoterms:''), $_SERVER['PHP_SELF'].'?id='.$object->id); + } + print '
"; + + print '
'; + print '
'; + print '
'; + + print '
'; + + + // Lines of products + + if ($action == 'editline') + { + print '
+ + + + + '; + } + print '
'; + + print '
'; + print ''; + print ''; + // # + if (! empty($conf->global->MAIN_VIEW_LINE_NUMBER)) + { + print ''; + } + // Product/Service + print ''; + // Comment + print ''; + // Qty + print ''; + if ($origin && $origin_id > 0) + { + print ''; + } + if ($action == 'editline') + { + $editColspan = 3; + if (empty($conf->stock->enabled)) $editColspan--; + if (empty($conf->productbatch->enabled)) $editColspan--; + print ''; + } + else + { + if ($object->statut <= 1) + { + print ''; + } + else + { + print ''; + } + if (! empty($conf->stock->enabled)) + { + print ''; + } + + if (! empty($conf->productbatch->enabled)) + { + print ''; + } + } + print ''; + print ''; + //print ''; + if ($object->statut == 0) + { + print ''; + print ''; + } + print "\n"; + + $var=false; + + if (! empty($conf->global->MAIN_MULTILANGS) && ! empty($conf->global->PRODUIT_TEXTS_IN_THIRDPARTY_LANGUAGE)) + { + $object->fetch_thirdparty(); + $outputlangs = $langs; + $newlang=''; + if (empty($newlang) && GETPOST('lang_id','aZ09')) $newlang=GETPOST('lang_id','aZ09'); + if (empty($newlang)) $newlang=$object->thirdparty->default_lang; + if (! empty($newlang)) + { + $outputlangs = new Translate("",$conf); + $outputlangs->setDefaultLang($newlang); + } + } + + // Get list of products already sent for same source object into $alreadysent + $alreadysent = array(); + + $origin = 'commande_fournisseur'; + + if ($origin && $origin_id > 0) + { + $sql = "SELECT obj.rowid, obj.fk_product, obj.label, obj.description, obj.product_type as fk_product_type, obj.qty as qty_asked, obj.date_start, obj.date_end"; + $sql.= ", ed.rowid as receptionline_id, ed.qty, ed.fk_reception as reception_id, ed.fk_entrepot"; + $sql.= ", e.rowid as reception_id, e.ref as reception_ref, e.date_creation, e.date_valid, e.date_delivery, e.date_reception"; + //if ($conf->livraison_bon->enabled) $sql .= ", l.rowid as livraison_id, l.ref as livraison_ref, l.date_delivery, ld.qty as qty_received"; + $sql.= ', p.label as product_label, p.ref, p.fk_product_type, p.rowid as prodid, p.tobatch as product_tobatch'; + $sql.= ', p.description as product_desc'; + $sql.= " FROM ".MAIN_DB_PREFIX."commande_fournisseur_dispatch as ed"; + $sql.= ", ".MAIN_DB_PREFIX."reception as e"; + $sql.= ", ".MAIN_DB_PREFIX.$origin."det as obj"; + //if ($conf->livraison_bon->enabled) $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."livraison as l ON l.fk_reception = e.rowid LEFT JOIN ".MAIN_DB_PREFIX."livraisondet as ld ON ld.fk_livraison = l.rowid AND obj.rowid = ld.fk_origin_line"; + $sql.= " LEFT JOIN ".MAIN_DB_PREFIX."product as p ON obj.fk_product = p.rowid"; + $sql.= " WHERE e.entity IN (".getEntity('reception').")"; + $sql.= " AND obj.fk_commande = ".$origin_id; + $sql.= " AND obj.rowid = ed.fk_commandefourndet"; + $sql.= " AND ed.fk_reception = e.rowid"; + $sql.= " AND ed.fk_reception !=".$object->id; + //if ($filter) $sql.= $filter; + $sql.= " ORDER BY obj.fk_product"; + + dol_syslog("get list of reception lines", LOG_DEBUG); + $resql = $db->query($sql); + if ($resql) + { + $num = $db->num_rows($resql); + $i = 0; + + while($i < $num) + { + $obj = $db->fetch_object($resql); + if ($obj) + { + // $obj->rowid is rowid in $origin."det" table + $alreadysent[$obj->rowid][$obj->receptionline_id]=array('reception_ref'=>$obj->reception_ref, 'reception_id'=>$obj->reception_id, 'warehouse'=>$obj->fk_entrepot, 'qty'=>$obj->qty, 'date_valid'=>$obj->date_valid, 'date_delivery'=>$obj->date_delivery); + } + $i++; + } + } + //var_dump($alreadysent); + } + + // Loop on each product to send/sent + for ($i = 0 ; $i < $num_prod ; $i++) + { + print ''; // id of order line + print ''; + + // # + if (! empty($conf->global->MAIN_VIEW_LINE_NUMBER)) + { + print ''; + } + + // Predefined product or service + if ($lines[$i]->fk_product > 0) + { + // Define output language + if (! empty($conf->global->MAIN_MULTILANGS) && ! empty($conf->global->PRODUIT_TEXTS_IN_THIRDPARTY_LANGUAGE)) + { + $prod = new Product($db); + $prod->fetch($lines[$i]->fk_product); + $label = ( ! empty($prod->multilangs[$outputlangs->defaultlang]["label"])) ? $prod->multilangs[$outputlangs->defaultlang]["label"] : $lines[$i]->product->label; + } + else + $label = (! empty($lines[$i]->product->label)?$lines[$i]->product->label:$lines[$i]->product->product_label); + + print '\n"; + } + else + { + print "\n"; + } + + if ($action == 'editline' && $lines[$i]->id == $line_id) + { + print ''; + } + else + { + print ''; + } + + + // Qty ordered + print ''; + + // Qty in other receptions (with reception and warehouse used) + if ($origin && $origin_id > 0) + { + print ''; + + if ($action == 'editline' && $lines[$i]->id == $line_id) + { + // edit mode + print ''; + } + else + { + // Qty to receive or received + print ''; + + // Warehouse source + if (! empty($conf->stock->enabled)) + { + print ''; + } + + // Batch number managment + if (! empty($conf->productbatch->enabled)) + { + if (isset($lines[$i]->batch)) + { + print ''; + print ''; + } else { + print ''; + } + } + } + + // Weight + print ''; + + // Volume + print ''; + + + if ($action == 'editline' && $lines[$i]->id == $line_id) + { + print ''; + print ''; + + // Display lines extrafields + if (! empty($rowExtrafieldsStart)) + { + print $rowExtrafieldsStart; + print $rowExtrafieldsView; + print $rowEnd; + } + } + print ""; + + // Display lines extrafields + if (is_array($extralabelslines) && count($extralabelslines)>0) { + $colspan= empty($conf->productbatch->enabled) ? 8 : 9; + $line = new CommandeFournisseurDispatch($db); + $line->fetch_optionals($lines[$i]->id,$extralabelslines); + print ''; + if ($action == 'editline' && $lines[$i]->id == $line_id) + { + print $line->showOptionals($extrafieldsline, 'edit', array('style'=>$bc[$var], 'colspan'=>$colspan),$indiceAsked); + } + else + { + print $line->showOptionals($extrafieldsline, 'view', array('style'=>$bc[$var], 'colspan'=>$colspan),$indiceAsked); + } + print ''; + } + } + + // TODO Show also lines ordered but not delivered + + print "
 '.$langs->trans("Products").''.$langs->trans("Description").''.$langs->trans("QtyOrdered").''.$langs->trans("QtyInOtherReceptions").''; + if ($object->statut <= 1) + { + print $langs->trans("QtyToReceive").' - '; + } + else + { + print $langs->trans("QtyReceived").' - '; + } + if (! empty($conf->stock->enabled)) + { + print $langs->trans("WarehouseSource").' - '; + } + if (! empty($conf->productbatch->enabled)) + { + print $langs->trans("Batch"); + } + print ''.$langs->trans("QtyToReceive").''.$langs->trans("QtyReceived").''.$langs->trans("WarehouseSource").''.$langs->trans("Batch").''.$langs->trans("CalculatedWeight").''.$langs->trans("CalculatedVolume").''.$langs->trans("Size").'
'.($i+1).''; + + + + $text=$lines[$i]->product->getNomUrl(1); + $text.= ' - '.$label; + $description=(! empty($conf->global->PRODUIT_DESC_IN_FORM)?'':dol_htmlentitiesbr($lines[$i]->product->description)); + print $form->textwithtooltip($text,$description,3,'','',$i); + print_date_range($lines[$i]->date_start,$lines[$i]->date_end); + if (! empty($conf->global->PRODUIT_DESC_IN_FORM)) + { + print (! empty($lines[$i]->product->description) && $lines[$i]->description!=$lines[$i]->product->description)?'
'.dol_htmlentitiesbr($lines[$i]->description):''; + } + print "
"; + if ($lines[$i]->product_type == Product::TYPE_SERVICE) $text = img_object($langs->trans('Service'),'service'); + else $text = img_object($langs->trans('Product'),'product'); + + if (! empty($lines[$i]->label)) { + $text.= ' '.$lines[$i]->label.''; + print $form->textwithtooltip($text,$lines[$i]->description,3,'','',$i); + } else { + print $text.' '.nl2br($lines[$i]->description); + } + + print_date_range($lines[$i]->date_start,$lines[$i]->date_end); + print "'.$lines[$i]->comment.''.$lines[$i]->qty_asked.''; + foreach ($alreadysent as $key => $val) + { + if ($lines[$i]->fk_commandefourndet == $key) + { + $j = 0; + foreach($val as $receptionline_id=> $receptionline_var) + { + if ($receptionline_var['reception_id'] == $lines[$i]->fk_reception) continue; // We want to show only "other receptions" + + $j++; + if ($j > 1) print '
'; + $reception_static->fetch($receptionline_var['reception_id']); + print $reception_static->getNomUrl(1); + print ' - '.$receptionline_var['qty']; + + $htmltext=$langs->trans("DateValidation").' : '.(empty($receptionline_var['date_valid'])?$langs->trans("Draft"):dol_print_date($receptionline_var['date_valid'], 'dayhour')); + if (! empty($conf->stock->enabled) && $receptionline_var['warehouse'] > 0) + { + $warehousestatic->fetch($receptionline_var['warehouse']); + $htmltext .= '
'.$langs->trans("From").' : '.$warehousestatic->getNomUrl(1); + } + print ' '.$form->textwithpicto('', $htmltext, 1); + } + } + } + } + print '
'; + if (! empty($conf->stock->enabled)) + { + if ($lines[$i]->fk_product > 0) + { + print ''; + print ''; + // Qty to receive or received + print ''; + // Warehouse source + print ''; + // Batch number managment + if($conf->productbatch->enabled && !empty($lines[$i]->product->status_batch)){ + print ''; + } + print ''; + + } + else + { + print ''; + print ''; + // Qty to receive or received + print ''; + // Warehouse source + print ''; + // Batch number managment + print ''; + print ''; + } + } + print '
' . '' . '' . $formproduct->selectWarehouses($lines[$i]->fk_entrepot, 'entl'.$line_id, '', 1, 0, $lines[$i]->fk_product, '', 1). '
'; + print $langs->trans('EatByDate').' : '; + print $form->select_date($lines[$i]->eatby,'dlc' .$line_id , '', '', 1, ""). '
'; + print $langs->trans('SellByDate').' : '; + print $form->select_date($lines[$i]->sellby,'dluo' .$line_id , '', '', 1, ""); + print '
' . '' . '' . '' . '
'.$lines[$i]->qty.''; + + if ($lines[$i]->fk_entrepot > 0) + { + $entrepot = new Entrepot($db); + $entrepot->fetch($lines[$i]->fk_entrepot); + print $entrepot->getNomUrl(1); + } + + print ''; + $detail =''; + if ($lines[$i]->product->status_batch) + { + + $detail.= $langs->trans("Batch").': '.$lines[$i]->batch; + $detail.= ' - '.$langs->trans("SellByDate").': '.dol_print_date($lines[$i]->sellby,"day"); + $detail.= ' - '.$langs->trans("EatByDate").': '.dol_print_date($lines[$i]->eatby,"day"); + + $detail.= '
'; + + print $form->textwithtooltip(img_picto('', 'object_barcode').' '.$langs->trans("DetailBatchNumber"),$detail); + } + else + { + print $langs->trans("NA"); + } + print '
'; + if ($lines[$i]->fk_product_type == Product::TYPE_PRODUCT) print $lines[$i]->product->weight*$lines[$i]->qty.' '.measuring_units_string($lines[$i]->product->weight_units,"weight"); + else print ' '; + print ''; + if ($lines[$i]->fk_product_type == Product::TYPE_PRODUCT) print $lines[$i]->product->volume*$lines[$i]->qty.' '.measuring_units_string($lines[$i]->product->volume_units,"volume"); + else print ' '; + print ''; + print '
'; + print '
'; + } + else if ($object->statut == 0) + { + // edit-delete buttons + print '
'; + print 'id . '">' . img_edit() . ''; + print ''; + print 'id . '">' . img_delete() . ''; + print '
\n"; + print '
'; + } + + + dol_fiche_end(); + + + $object->fetchObjectLinked($object->id,$object->element); + + + /* + * Boutons actions + */ + + if (($user->societe_id == 0) && ($action!='presend')) + { + print '
'; + + $parameters = array(); + $reshook = $hookmanager->executeHooks('addMoreActionsButtons', $parameters, $object, $action); // Note that $action and $object may have been + // modified by hook + if (empty($reshook)) + { + + if ($object->statut == Reception::STATUS_DRAFT && $num_prod > 0) + { + if ((empty($conf->global->MAIN_USE_ADVANCED_PERMS) && ! empty($user->rights->reception->creer)) + || (! empty($conf->global->MAIN_USE_ADVANCED_PERMS) && ! empty($user->rights->reception->reception_advance->validate))) + { + print ''.$langs->trans("Validate").''; + } + else + { + print ''.$langs->trans("Validate").''; + } + } + // Edit + if ($object->statut == Reception::STATUS_VALIDATED && $user->rights->reception->creer) { + print ''; + } + + // TODO add alternative status + // 0=draft, 1=validated, 2=billed, we miss a status "delivered" (only available on order) + if ($object->statut == Reception::STATUS_CLOSED && $user->rights->reception->creer) + { + if (! empty($conf->facture->enabled) && ! empty($conf->global->WORKFLOW_BILL_ON_RECEPTION)) // Quand l'option est on, il faut avoir le bouton en plus et non en remplacement du Close ? + { + print ''.$langs->trans("ClassifyUnbilled").''; + } + else + { + print ''.$langs->trans("ReOpen").''; + } + } + + // Send + if ($object->statut > 0) + { + if (empty($conf->global->MAIN_USE_ADVANCED_PERMS) || $user->rights->reception->reception_advance->send) + { + print ''.$langs->trans('SendByMail').''; + } + else print ''.$langs->trans('SendByMail').''; + } + + // Create bill + if (! empty($conf->fournisseur->enabled) && ($object->statut == Reception::STATUS_VALIDATED || $object->statut == Reception::STATUS_CLOSED)) + { + if ($user->rights->fournisseur->facture->creer) + { + // TODO show button only if (! empty($conf->global->WORKFLOW_BILL_ON_RECEPTION)) + // If we do that, we must also make this option official. + print ''.$langs->trans("CreateBill").''; + } + } + + + // Close + if ($object->statut == Reception::STATUS_VALIDATED) + { + if ($user->rights->reception->creer && $object->statut > 0 && ! $object->billed) + { + $label="Close"; $paramaction='classifyclosed'; // = Transferred/Received + // Label here should be "Close" or "ClassifyBilled" if we decided to make bill on receptions instead of orders + if (! empty($conf->fournisseur->enabled) && ! empty($conf->global->WORKFLOW_BILL_ON_RECEPTION)) // Quand l'option est on, il faut avoir le bouton en plus et non en remplacement du Close ? + { + $label="ClassifyBilled"; + $paramaction='classifybilled'; + } + print ''.$langs->trans($label).''; + } + } + + if ($user->rights->reception->supprimer) + { + print ''.$langs->trans("Delete").''; + } + + } + + print '
'; + } + + + /* + * Documents generated + */ + + if ($action != 'presend' && $action != 'editline') + { + print '
'; + + $objectref = dol_sanitizeFileName($object->ref); + $filedir = $conf->reception->dir_output . "/" .$objectref; + + $urlsource = $_SERVER["PHP_SELF"]."?id=".$object->id; + + $genallowed=$user->rights->reception->lire; + $delallowed=$user->rights->reception->creer; + + print $formfile->showdocuments('reception',$objectref,$filedir,$urlsource,$genallowed,$delallowed,$object->modelpdf,1,0,0,28,0,'','','',$soc->default_lang); + + + // Show links to link elements + //$linktoelem = $form->showLinkToObjectBlock($object, null, array('order')); + $somethingshown = $form->showLinkedObjectBlock($object, ''); + + + print '
'; + + } + + if ($action == 'presend') + { + $ref = dol_sanitizeFileName($object->ref); + include_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php'; + $fileparams = dol_most_recent_file($conf->reception->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('receptions'); + } + // 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,$object->error,$object->errors); + exit; + } + $fileparams = dol_most_recent_file($conf->reception->dir_output . '/reception/' . $ref, preg_quote($ref, '/').'[^\-]+'); + $file=$fileparams['fullname']; + } + print '
'; + print '
'; + print '
'; + print load_fiche_titre($langs->trans('SendReceptionByEMail')); + dol_fiche_head(''); + // Cree l'objet formulaire mail + 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 = (GETPOST('fromtype')?GETPOST('fromtype'):(!empty($conf->global->MAIN_MAIL_DEFAULT_FROMTYPE)?$conf->global->MAIN_MAIL_DEFAULT_FROMTYPE:'user')); + if($formmail->fromtype === 'user'){ + $formmail->fromid = $user->id; + } + $formmail->trackid='shi'.$object->id; + if (! empty($conf->global->MAIN_EMAIL_ADD_TRACK_ID) && ($conf->global->MAIN_EMAIL_ADD_TRACK_ID & 2)) // If bit 2 is set + { + include DOL_DOCUMENT_ROOT.'/core/lib/functions2.lib.php'; + $formmail->frommail=dolAddEmailTrackId($formmail->frommail, 'shi'.$object->id); + } + $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=$conf->global->MAIN_EMAIL_USECCC; + $formmail->withtopic=$outputlangs->trans('SendReceptionRef','__RECEPTIONREF__'); + $formmail->withfile=2; + $formmail->withbody=1; + $formmail->withdeliveryreceipt=1; + $formmail->withcancel=1; + // Tableau des substitutions + $formmail->setSubstitFromObject($object,$langs); + $formmail->substit['__RECEPTIONREF__']=$object->ref; + $formmail->substit['__RECEPTIONTRACKNUM__']=$object->tracking_number; + $formmail->substit['__RECEPTIONTRACKNUMURL__']=$object->tracking_url; + //Find the good contact adress + if ($typeobject == 'commande' && $object->$typeobject->id && ! empty($conf->commande->enabled)) { + $objectsrc=new Commande($db); + $objectsrc->fetch($object->$typeobject->id); + } + if ($typeobject == 'propal' && $object->$typeobject->id && ! empty($conf->propal->enabled)) { + $objectsrc=new Propal($db); + $objectsrc->fetch($object->$typeobject->id); + } + $custcontact=''; + $contactarr=array(); + if (is_object($objectsrc)) // For the case the reception was created without orders + { + $contactarr=$objectsrc->liste_contact(-1,'external'); + } + if (is_array($contactarr) && count($contactarr)>0) { + foreach($contactarr as $contact) { + if ($contact['libelle']==$langs->trans('TypeContact_commande_external_CUSTOMER')) { + require_once DOL_DOCUMENT_ROOT . '/contact/class/contact.class.php'; + $contactstatic=new Contact($db); + $contactstatic->fetch($contact['id']); + $custcontact=$contactstatic->getFullName($langs,1); + } + } + if (!empty($custcontact)) { + $formmail->substit['__CONTACTCIVNAME__']=$custcontact; + } + } + // Tableau des parametres complementaires + $formmail->param['action']='send'; + $formmail->param['models']='reception_send'; + $formmail->param['models_id']=GETPOST('modelmailselected','int'); + $formmail->param['receptionid']=$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)); + } + // Show form + print $formmail->get_form(); + dol_fiche_end(); + } + + + +} + + +llxFooter(); + +$db->close(); diff --git a/htdocs/reception/class/index.html b/htdocs/reception/class/index.html new file mode 100644 index 00000000000..e69de29bb2d diff --git a/htdocs/reception/class/reception.class.php b/htdocs/reception/class/reception.class.php new file mode 100644 index 00000000000..06b35efd940 --- /dev/null +++ b/htdocs/reception/class/reception.class.php @@ -0,0 +1,1993 @@ + + * Copyright (C) 2005-2012 Regis Houssin + * Copyright (C) 2007 Franky Van Liedekerke + * Copyright (C) 2006-2012 Laurent Destailleur + * Copyright (C) 2011-2017 Juanjo Menent + * Copyright (C) 2013 Florian Henry + * Copyright (C) 2014 Cedric GROSS + * Copyright (C) 2014-2015 Marcos García + * Copyright (C) 2014-2015 Francis Appels + * Copyright (C) 2015 Claudio Aschieri + * Copyright (C) 2016 Ferran Marcet + * Copyright (C) 2018 Quentin Vial-Gouteyron + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/** + * \file htdocs/reception/class/reception.class.php + * \ingroup reception + * \brief Fichier de la classe de gestion des receptions + */ + +require_once DOL_DOCUMENT_ROOT.'/core/class/commonobject.class.php'; +require_once DOL_DOCUMENT_ROOT."/core/class/commonobjectline.class.php"; +if (! empty($conf->propal->enabled)) require_once DOL_DOCUMENT_ROOT.'/comm/propal/class/propal.class.php'; +if (! empty($conf->commande->enabled)) require_once DOL_DOCUMENT_ROOT.'/commande/class/commande.class.php'; + + +/** + * Class to manage receptions + */ +class Reception extends CommonObject +{ + public $element="reception"; + public $fk_element="fk_reception"; + public $table_element="reception"; + public $table_element_line="commande_fournisseur_dispatch"; + protected $ismultientitymanaged = 1; // 0=No test on entity, 1=Test with field entity, 2=Test with link by societe + public $picto = 'reception'; + + var $socid; + var $ref_supplier; + var $ref_int; + var $brouillon; + var $entrepot_id; + var $lines=array(); + var $tracking_number; + var $tracking_url; + var $billed; + var $model_pdf; + + var $trueWeight; + var $weight_units; + var $trueWidth; + var $width_units; + var $trueHeight; + var $height_units; + var $trueDepth; + var $depth_units; + // A denormalized value + var $trueSize; + + var $date_delivery; // Date delivery planed + + + /** + * Effective delivery date + * @var int + */ + public $date_reception; + var $date_creation; + var $date_valid; + + var $meths; + var $listmeths; // List of carriers + + + const STATUS_DRAFT = 0; + const STATUS_VALIDATED = 1; + const STATUS_CLOSED = 2; + + + + /** + * Constructor + * + * @param DoliDB $db Database handler + */ + function __construct($db) + { + $this->db = $db; + $this->lines = array(); + $this->products = array(); + + // List of long language codes for status + $this->statuts = array(); + $this->statuts[-1] = 'StatusReceptionCanceled'; + $this->statuts[0] = 'StatusReceptionDraft'; + $this->statuts[1] = 'StatusReceptionValidated'; + $this->statuts[2] = 'StatusReceptionProcessed'; + } + + /** + * Return next contract ref + * + * @param Societe $soc Thirdparty object + * @return string Free reference for contract + */ + function getNextNumRef($soc) + { + global $langs, $conf; + $langs->load("receptions"); + + if (!empty($conf->global->RECEPTION_ADDON_NUMBER)) + { + $mybool = false; + + $file = $conf->global->RECEPTION_ADDON_NUMBER.".php"; + $classname = $conf->global->RECEPTION_ADDON_NUMBER; + + // Include file with class + $dirmodels = array_merge(array('/'), (array) $conf->modules_parts['models']); + + foreach ($dirmodels as $reldir) { + + $dir = dol_buildpath($reldir."core/modules/reception/"); + + // 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 + { + dol_print_error($this->db,get_class($this)."::getNextNumRef ".$obj->error); + return ""; + } + } + else + { + print $langs->trans("Error")." ".$langs->trans("Error_RECEPTION_ADDON_NUMBER_NotDefined"); + return ""; + } + } + + /** + * Create reception en base + * + * @param User $user Objet du user qui cree + * @param int $notrigger 1=Does not execute triggers, 0= execute triggers + * @return int <0 si erreur, id reception creee si ok + */ + function create($user, $notrigger=0) + { + global $conf, $hookmanager; + + $now=dol_now(); + + require_once DOL_DOCUMENT_ROOT .'/product/stock/class/mouvementstock.class.php'; + $error = 0; + + // Clean parameters + $this->brouillon = 1; + $this->tracking_number = dol_sanitizeFileName($this->tracking_number); + if (empty($this->fk_project)) $this->fk_project = 0; + + $this->user = $user; + + + $this->db->begin(); + + $sql = "INSERT INTO ".MAIN_DB_PREFIX."reception ("; + $sql.= "ref"; + $sql.= ", entity"; + $sql.= ", ref_supplier"; + $sql.= ", ref_int"; + $sql.= ", date_creation"; + $sql.= ", fk_user_author"; + $sql.= ", date_reception"; + $sql.= ", date_delivery"; + $sql.= ", fk_soc"; + $sql.= ", fk_projet"; + $sql.= ", fk_shipping_method"; + $sql.= ", tracking_number"; + $sql.= ", weight"; + $sql.= ", size"; + $sql.= ", width"; + $sql.= ", height"; + $sql.= ", weight_units"; + $sql.= ", size_units"; + $sql.= ", note_private"; + $sql.= ", note_public"; + $sql.= ", model_pdf"; + $sql.= ", fk_incoterms, location_incoterms"; + $sql.= ") VALUES ("; + $sql.= "'(PROV)'"; + $sql.= ", ".$conf->entity; + $sql.= ", ".($this->ref_supplier?"'".$this->db->escape($this->ref_supplier)."'":"null"); + $sql.= ", ".($this->ref_int?"'".$this->db->escape($this->ref_int)."'":"null"); + $sql.= ", '".$this->db->idate($now)."'"; + $sql.= ", ".$user->id; + $sql.= ", ".($this->date_reception>0?"'".$this->db->idate($this->date_reception)."'":"null"); + $sql.= ", ".($this->date_delivery>0?"'".$this->db->idate($this->date_delivery)."'":"null"); + $sql.= ", ".$this->socid; + $sql.= ", ".$this->fk_project; + $sql.= ", ".($this->shipping_method_id>0?$this->shipping_method_id:"null"); + $sql.= ", '".$this->db->escape($this->tracking_number)."'"; + $sql.= ", ".$this->weight; + $sql.= ", ".$this->sizeS; // TODO Should use this->trueDepth + $sql.= ", ".$this->sizeW; // TODO Should use this->trueWidth + $sql.= ", ".$this->sizeH; // TODO Should use this->trueHeight + $sql.= ", ".$this->weight_units; + $sql.= ", ".$this->size_units; + $sql.= ", ".(!empty($this->note_private)?"'".$this->db->escape($this->note_private)."'":"null"); + $sql.= ", ".(!empty($this->note_public)?"'".$this->db->escape($this->note_public)."'":"null"); + $sql.= ", ".(!empty($this->model_pdf)?"'".$this->db->escape($this->model_pdf)."'":"null"); + $sql.= ", ".(int) $this->fk_incoterms; + $sql.= ", '".$this->db->escape($this->location_incoterms)."'"; + $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."reception"); + + $sql = "UPDATE ".MAIN_DB_PREFIX."reception"; + $sql.= " SET ref = '(PROV".$this->id.")'"; + $sql.= " WHERE rowid = ".$this->id; + + dol_syslog(get_class($this)."::create", LOG_DEBUG); + if ($this->db->query($sql)) + { + // Insertion des lignes + $num=count($this->lines); + for ($i = 0; $i < $num; $i++) + { + $this->lines[$i]->fk_reception = $this->id; + + if (! $this->lines[$i]->create($user) > 0) + { + $error++; + } + + + } + + if (! $error && $this->id && $this->origin_id) + { + $ret = $this->add_object_linked(); + if (!$ret) + { + $error++; + } + } + + // Actions on extra fields (by external module or standard code) + // TODO le hook fait double emploi avec le trigger !! + $hookmanager->initHooks(array('receptiondao')); + $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 (! $error && ! $notrigger) + { + // Call trigger + $result=$this->call_trigger('RECEPTION_CREATE',$user); + if ($result < 0) { $error++; } + // End call triggers + + if (! $error) + { + $this->db->commit(); + return $this->id; + } + else + { + foreach($this->errors as $errmsg) + { + dol_syslog(get_class($this)."::create ".$errmsg, LOG_ERR); + $this->error.=($this->error?', '.$errmsg:$errmsg); + } + $this->db->rollback(); + return -1*$error; + } + + } + else + { + $error++; + $this->error=$this->db->lasterror()." - sql=$sql"; + $this->db->rollback(); + return -3; + } + } + else + { + $error++; + $this->error=$this->db->lasterror()." - sql=$sql"; + $this->db->rollback(); + return -2; + } + } + else + { + $error++; + $this->error=$this->db->error()." - sql=$sql"; + $this->db->rollback(); + return -1; + } + } + + + + /** + * Get object and lines from database + * + * @param int $id Id of object to load + * @param string $ref Ref of object + * @param string $ref_ext External reference of object + * @param string $ref_int Internal reference of other object + * @return int >0 if OK, 0 if not found, <0 if KO + */ + function fetch($id, $ref='', $ref_ext='', $ref_int='') + { + global $conf; + + // Check parameters + if (empty($id) && empty($ref) && empty($ref_ext) && empty($ref_int)) return -1; + + $sql = "SELECT e.rowid, e.ref, e.fk_soc as socid, e.date_creation, e.ref_supplier, e.ref_ext, e.ref_int, e.fk_user_author, e.fk_statut"; + $sql.= ", e.weight, e.weight_units, e.size, e.size_units, e.width, e.height"; + $sql.= ", e.date_reception as date_reception, e.model_pdf, e.date_delivery"; + $sql.= ", e.fk_shipping_method, e.tracking_number"; + $sql.= ", el.fk_source as origin_id, el.sourcetype as origin"; + $sql.= ", e.note_private, e.note_public"; + $sql.= ', e.fk_incoterms, e.location_incoterms'; + $sql.= ', i.libelle as libelle_incoterms'; + $sql.= " FROM ".MAIN_DB_PREFIX."reception as e"; + $sql.= " LEFT JOIN ".MAIN_DB_PREFIX."element_element as el ON el.fk_target = e.rowid AND el.targettype = '".$this->db->escape($this->element)."'"; + $sql.= ' LEFT JOIN '.MAIN_DB_PREFIX.'c_incoterms as i ON e.fk_incoterms = i.rowid'; + $sql.= " WHERE e.entity IN (".getEntity('reception').")"; + if ($id) $sql.= " AND e.rowid=".$id; + if ($ref) $sql.= " AND e.ref='".$this->db->escape($ref)."'"; + if ($ref_ext) $sql.= " AND e.ref_ext='".$this->db->escape($ref_ext)."'"; + if ($ref_int) $sql.= " AND e.ref_int='".$this->db->escape($ref_int)."'"; + + dol_syslog(get_class($this)."::fetch", LOG_DEBUG); + $result = $this->db->query($sql); + if ($result) + { + if ($this->db->num_rows($result)) + { + $obj = $this->db->fetch_object($result); + + $this->id = $obj->rowid; + $this->ref = $obj->ref; + $this->socid = $obj->socid; + $this->ref_supplier = $obj->ref_supplier; + $this->ref_ext = $obj->ref_ext; + $this->ref_int = $obj->ref_int; + $this->statut = $obj->fk_statut; + $this->user_author_id = $obj->fk_user_author; + $this->date_creation = $this->db->jdate($obj->date_creation); + $this->date = $this->db->jdate($obj->date_reception); // TODO deprecated + $this->date_reception = $this->db->jdate($obj->date_reception); // TODO deprecated + $this->date_reception = $this->db->jdate($obj->date_reception); // Date real + $this->date_delivery = $this->db->jdate($obj->date_delivery); // Date planed + $this->fk_delivery_address = $obj->fk_address; + $this->modelpdf = $obj->model_pdf; + $this->shipping_method_id = $obj->fk_shipping_method; + $this->tracking_number = $obj->tracking_number; + $this->origin = ($obj->origin?$obj->origin:'commande'); // For compatibility + $this->origin_id = $obj->origin_id; + $this->billed = ($obj->fk_statut==2?1:0); + + $this->trueWeight = $obj->weight; + $this->weight_units = $obj->weight_units; + + $this->trueWidth = $obj->width; + $this->width_units = $obj->size_units; + $this->trueHeight = $obj->height; + $this->height_units = $obj->size_units; + $this->trueDepth = $obj->size; + $this->depth_units = $obj->size_units; + + $this->note_public = $obj->note_public; + $this->note_private = $obj->note_private; + + // A denormalized value + $this->trueSize = $obj->size."x".$obj->width."x".$obj->height; + $this->size_units = $obj->size_units; + + //Incoterms + $this->fk_incoterms = $obj->fk_incoterms; + $this->location_incoterms = $obj->location_incoterms; + $this->libelle_incoterms = $obj->libelle_incoterms; + + $this->db->free($result); + + if ($this->statut == 0) $this->brouillon = 1; + + $file = $conf->reception->dir_output . "/" .get_exdir($this->id, 2, 0, 0, $this, 'reception') . "/" . $this->id.".pdf"; + $this->pdf_filename = $file; + + // Tracking url + $this->GetUrlTrackingStatus($obj->tracking_number); + + /* + * Thirparty + */ + $result=$this->fetch_thirdparty(); + + + // Retrieve all extrafields for reception + // 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); + + /* + * Lines + */ + $result=$this->fetch_lines(); + if ($result < 0) + { + return -3; + } + + return 1; + } + else + { + dol_syslog(get_class($this).'::Fetch no reception found', LOG_ERR); + $this->error='Delivery with id '.$id.' not found'; + return 0; + } + } + else + { + $this->error=$this->db->error(); + return -1; + } + } + + /** + * Validate object and update stock if option enabled + * + * @param User $user Object user that validate + * @param int $notrigger 1=Does not execute triggers, 0= execute triggers + * @return int <0 if OK, >0 if KO + */ + function valid($user, $notrigger=0) + { + global $conf, $langs; + + require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php'; + + dol_syslog(get_class($this)."::valid"); + + // Protection + if ($this->statut) + { + dol_syslog(get_class($this)."::valid no draft status", LOG_WARNING); + return 0; + } + + if (! ((empty($conf->global->MAIN_USE_ADVANCED_PERMS) && ! empty($user->rights->reception->creer)) + || (! empty($conf->global->MAIN_USE_ADVANCED_PERMS) && ! empty($user->rights->reception->reception_advance->validate)))) + { + $this->error='Permission denied'; + dol_syslog(get_class($this)."::valid ".$this->error, LOG_ERR); + return -1; + } + + $this->db->begin(); + + $error = 0; + + // Define new ref + $soc = new Societe($this->db); + $soc->fetch($this->socid); + + + + // Define new ref + if (! $error && (preg_match('/^[\(]?PROV/i', $this->ref) || empty($this->ref))) // empty should not happened, but when it occurs, the test save life + { + $numref = $this->getNextNumRef($soc); + } + else { + $numref = $this->ref; + } + + $this->newref = $numref; + + $now=dol_now(); + + // Validate + $sql = "UPDATE ".MAIN_DB_PREFIX."reception SET"; + $sql.= " ref='".$numref."'"; + $sql.= ", fk_statut = 1"; + $sql.= ", date_valid = '".$this->db->idate($now)."'"; + $sql.= ", fk_user_valid = ".$user->id; + $sql.= " WHERE rowid = ".$this->id; + dol_syslog(get_class($this)."::valid update reception", LOG_DEBUG); + $resql=$this->db->query($sql); + if (! $resql) + { + $this->error=$this->db->lasterror(); + $error++; + } + + // If stock increment is done on reception (recommanded choice) + if (! $error && ! empty($conf->stock->enabled) && ! empty($conf->global->STOCK_CALCULATE_ON_RECEPTION)) + { + require_once DOL_DOCUMENT_ROOT.'/product/stock/class/mouvementstock.class.php'; + + $langs->load("agenda"); + + // Loop on each product line to add a stock movement + // TODO in future, reception lines may not be linked to order line + $sql = "SELECT cd.fk_product, cd.subprice,"; + $sql.= " ed.rowid, ed.qty, ed.fk_entrepot,"; + $sql.= " ed.eatby, ed.sellby, ed.batch"; + $sql.= " FROM ".MAIN_DB_PREFIX."commande_fournisseurdet as cd,"; + $sql.= " ".MAIN_DB_PREFIX."commande_fournisseur_dispatch as ed"; + $sql.= " WHERE ed.fk_reception = ".$this->id; + $sql.= " AND cd.rowid = ed.fk_commandefourndet"; + + + + dol_syslog(get_class($this)."::valid select details", LOG_DEBUG); + $resql=$this->db->query($sql); + if ($resql) + { + $cpt = $this->db->num_rows($resql); + for ($i = 0; $i < $cpt; $i++) + { + $obj = $this->db->fetch_object($resql); + + $qty = $obj->qty; + + if ($qty <= 0) continue; + dol_syslog(get_class($this)."::valid movement index ".$i." ed.rowid=".$obj->rowid." edb.rowid=".$obj->edbrowid); + + //var_dump($this->lines[$i]); + $mouvS = new MouvementStock($this->db); + $mouvS->origin = &$this; + + if (empty($obj->batch)) + { + // line without batch detail + + // We decrement stock of product (and sub-products) -> update table llx_product_stock (key of this table is fk_product+fk_entrepot) and add a movement record. + $result=$mouvS->reception($user, $obj->fk_product, $obj->fk_entrepot, $qty, $obj->subprice, $langs->trans("ReceptionValidatedInDolibarr",$numref)); + if ($result < 0) { + $error++; + $this->errors[]=$mouvS->error; + $this->errors = array_merge($this->errors, $mouvS->errors); + break; + } + } + else + { + // line with batch detail + + // We decrement stock of product (and sub-products) -> update table llx_product_stock (key of this table is fk_product+fk_entrepot) and add a movement record. + // Note: ->fk_origin_stock = id into table llx_product_batch (may be rename into llx_product_stock_batch in another version) + $result=$mouvS->reception($user, $obj->fk_product, $obj->fk_entrepot, $qty, $obj->subprice, $langs->trans("ReceptionValidatedInDolibarr",$numref), $this->db->jdate($obj->eatby), $this->db->jdate($obj->sellby), $obj->batch); + if ($result < 0) { + $error++; + $this->errors[]=$mouvS->error; + $this->errors = array_merge($this->errors, $mouvS->errors); + break; + } + } + } + } + else + { + $this->db->rollback(); + $this->error=$this->db->error(); + return -2; + } + + } + + // Change status of order to "reception in process" + $ret = $this->setStatut(4, $this->origin_id, 'commande_fournisseur'); + + if (! $ret) + { + $error++; + } + + if (! $error && ! $notrigger) + { + // Call trigger + $result=$this->call_trigger('RECEPTION_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)) + { + // On renomme repertoire ($this->ref = ancienne ref, $numfa = nouvelle ref) + // in order not to lose the attached files + $oldref = dol_sanitizeFileName($this->ref); + $newref = dol_sanitizeFileName($numref); + $dirsource = $conf->reception->dir_output.'/'.$oldref; + $dirdest = $conf->reception->dir_output.'/'.$newref; + if (file_exists($dirsource)) + { + dol_syslog(get_class($this)."::valid 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->reception->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); + } + } + } + } + } + + // Set new ref and current status + if (! $error) + { + $this->ref = $numref; + $this->statut = 1; + } + + if (! $error) + { + $this->db->commit(); + return 1; + } + else + { + foreach($this->errors as $errmsg) + { + dol_syslog(get_class($this)."::valid ".$errmsg, LOG_ERR); + $this->error.=($this->error?', '.$errmsg:$errmsg); + } + $this->db->rollback(); + return -1*$error; + } + } + + + + /** + * Add an reception line. + * If STOCK_WAREHOUSE_NOT_REQUIRED_FOR_RECEPTIONS is set, you can add a reception line, with no stock source defined + * If STOCK_MUST_BE_ENOUGH_FOR_RECEPTION is not set, you can add a reception line, even if not enough into stock + * + * @param int $entrepot_id Id of warehouse + * @param int $id Id of source line (supplier order line) + * @param int $qty Quantity + * @param array $array_options extrafields array + * @param string $comment Comment for stock movement + * @param date $eatby eat-by date + * @param date $sellby sell-by date + * @param string $batch Lot number + * @return int <0 if KO, >0 if OK + */ + function addline($entrepot_id, $id, $qty, $array_options=0, $comment='', $eatby='', $sellby='', $batch='') + { + global $conf, $langs, $user; + + $num = count($this->lines); + $line = new CommandeFournisseurDispatch($this->db); + + $line->fk_entrepot = $entrepot_id; + $line->fk_commandefourndet = $id; + $line->qty = $qty; + + $supplierorderline = new CommandeFournisseurLigne($this->db); + $supplierorderline->fetch($id); + + if (! empty($conf->stock->enabled) && ! empty($supplierorderline->fk_product)) + { + $fk_product = $supplierorderline->fk_product; + + if (! ($entrepot_id > 0) && empty($conf->global->STOCK_WAREHOUSE_NOT_REQUIRED_FOR_RECEPTIONS)) + { + $langs->load("errors"); + $this->error=$langs->trans("ErrorWarehouseRequiredIntoReceptionLine"); + return -1; + } + + + } + + // extrafields + if (empty($conf->global->MAIN_EXTRAFIELDS_DISABLED) && is_array($array_options) && count($array_options)>0) // For avoid conflicts if trigger used + $line->array_options = $array_options; + + $line->fk_product = $fk_product; + $line->fk_commande = $supplierorderline->fk_commande ; + $line->fk_user = $user->id ; + $line->comment = $comment; + $line->batch = $batch; + $line->eatby = $eatby; + $line->sellby = $sellby; + $line->status=1; + $line->fk_reception=$this->id; + + $this->lines[$num] = $line; + } + + + /** + * Update database + * + * @param User $user User that modify + * @param int $notrigger 0=launch triggers after, 1=disable triggers + * @return int <0 if KO, >0 if OK + */ + function update($user=null, $notrigger=0) + { + global $conf; + $error=0; + + // Clean parameters + + if (isset($this->ref)) $this->ref=trim($this->ref); + if (isset($this->entity)) $this->entity=trim($this->entity); + if (isset($this->ref_supplier)) $this->ref_supplier=trim($this->ref_supplier); + if (isset($this->socid)) $this->socid=trim($this->socid); + if (isset($this->fk_user_author)) $this->fk_user_author=trim($this->fk_user_author); + if (isset($this->fk_user_valid)) $this->fk_user_valid=trim($this->fk_user_valid); + if (isset($this->fk_delivery_address)) $this->fk_delivery_address=trim($this->fk_delivery_address); + if (isset($this->shipping_method_id)) $this->shipping_method_id=trim($this->shipping_method_id); + if (isset($this->tracking_number)) $this->tracking_number=trim($this->tracking_number); + if (isset($this->statut)) $this->statut=(int) $this->statut; + if (isset($this->trueDepth)) $this->trueDepth=trim($this->trueDepth); + if (isset($this->trueWidth)) $this->trueWidth=trim($this->trueWidth); + if (isset($this->trueHeight)) $this->trueHeight=trim($this->trueHeight); + if (isset($this->size_units)) $this->size_units=trim($this->size_units); + if (isset($this->weight_units)) $this->weight_units=trim($this->weight_units); + if (isset($this->trueWeight)) $this->weight=trim($this->trueWeight); + if (isset($this->note_private)) $this->note=trim($this->note_private); + if (isset($this->note_public)) $this->note=trim($this->note_public); + if (isset($this->modelpdf)) $this->modelpdf=trim($this->modelpdf); + + + + // Check parameters + // Put here code to add control on parameters values + + // Update request + $sql = "UPDATE ".MAIN_DB_PREFIX."reception SET"; + + $sql.= " tms=".(dol_strlen($this->tms)!=0 ? "'".$this->db->idate($this->tms)."'" : 'null').","; + $sql.= " ref=".(isset($this->ref)?"'".$this->db->escape($this->ref)."'":"null").","; + $sql.= " ref_supplier=".(isset($this->ref_supplier)?"'".$this->db->escape($this->ref_supplier)."'":"null").","; + $sql.= " fk_soc=".(isset($this->socid)?$this->socid:"null").","; + $sql.= " date_creation=".(dol_strlen($this->date_creation)!=0 ? "'".$this->db->idate($this->date_creation)."'" : 'null').","; + $sql.= " fk_user_author=".(isset($this->fk_user_author)?$this->fk_user_author:"null").","; + $sql.= " date_valid=".(dol_strlen($this->date_valid)!=0 ? "'".$this->db->idate($this->date_valid)."'" : 'null').","; + $sql.= " fk_user_valid=".(isset($this->fk_user_valid)?$this->fk_user_valid:"null").","; + $sql.= " date_reception=".(dol_strlen($this->date_reception)!=0 ? "'".$this->db->idate($this->date_reception)."'" : 'null').","; + $sql.= " date_delivery=".(dol_strlen($this->date_delivery)!=0 ? "'".$this->db->idate($this->date_delivery)."'" : 'null').","; + $sql.= " fk_shipping_method=".((isset($this->shipping_method_id) && $this->shipping_method_id > 0)?$this->shipping_method_id:"null").","; + $sql.= " tracking_number=".(isset($this->tracking_number)?"'".$this->db->escape($this->tracking_number)."'":"null").","; + $sql.= " fk_statut=".(isset($this->statut)?$this->statut:"null").","; + $sql.= " height=".(($this->trueHeight != '')?$this->trueHeight:"null").","; + $sql.= " width=".(($this->trueWidth != '')?$this->trueWidth:"null").","; + $sql.= " size_units=".(isset($this->size_units)?$this->size_units:"null").","; + $sql.= " size=".(($this->trueDepth != '')?$this->trueDepth:"null").","; + $sql.= " weight_units=".(isset($this->weight_units)?$this->weight_units:"null").","; + $sql.= " weight=".(($this->trueWeight != '')?$this->trueWeight:"null").","; + $sql.= " note_private=".(isset($this->note_private)?"'".$this->db->escape($this->note_private)."'":"null").","; + $sql.= " note_public=".(isset($this->note_public)?"'".$this->db->escape($this->note_public)."'":"null").","; + $sql.= " model_pdf=".(isset($this->modelpdf)?"'".$this->db->escape($this->modelpdf)."'":"null").","; + $sql.= " entity=".$conf->entity; + + $sql.= " WHERE rowid=".$this->id; + + $this->db->begin(); + + dol_syslog(get_class($this)."::update", 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('RECEPTION_MODIFY',$user); + if ($result < 0) { $error++; } + // End call triggers + } + } + + // Commit or rollback + if ($error) + { + foreach($this->errors as $errmsg) + { + dol_syslog(get_class($this)."::update ".$errmsg, LOG_ERR); + $this->error.=($this->error?', '.$errmsg:$errmsg); + } + $this->db->rollback(); + return -1*$error; + } + else + { + $this->db->commit(); + return 1; + } + } + + /** + * Delete reception. + * + * @return int >0 if OK, 0 if deletion done but failed to delete files, <0 if KO + */ + function delete() + { + global $conf, $langs, $user; + require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php'; + + $error=0; + $this->error=''; + + + + $this->db->begin(); + // Stock control + if ($conf->stock->enabled && $conf->global->STOCK_CALCULATE_ON_RECEPTION && $this->statut > 0) + { + require_once(DOL_DOCUMENT_ROOT."/product/stock/class/mouvementstock.class.php"); + + $langs->load("agenda"); + + // Loop on each product line to add a stock movement + $sql = "SELECT cd.fk_product, cd.subprice, ed.qty, ed.fk_entrepot, ed.eatby, ed.sellby, ed.batch, ed.rowid as commande_fournisseur_dispatch_id"; + $sql.= " FROM ".MAIN_DB_PREFIX."commande_fournisseurdet as cd,"; + $sql.= " ".MAIN_DB_PREFIX."commande_fournisseur_dispatch as ed"; + $sql.= " WHERE ed.fk_reception = ".$this->id; + $sql.= " AND cd.rowid = ed.fk_commandefourndet"; + + dol_syslog(get_class($this)."::delete select details", LOG_DEBUG); + $resql=$this->db->query($sql); + if ($resql) + { + $cpt = $this->db->num_rows($resql); + for ($i = 0; $i < $cpt; $i++) + { + dol_syslog(get_class($this)."::delete movement index ".$i); + $obj = $this->db->fetch_object($resql); + + $mouvS = new MouvementStock($this->db); + // we do not log origin because it will be deleted + $mouvS->origin = null; + + + $result=$mouvS->livraison($user, $obj->fk_product, $obj->fk_entrepot, $obj->qty, 0, $langs->trans("ReceptionDeletedInDolibarr", $this->ref),'', $obj->eatby, $obj->sellby, $obj->batch); // Price is set to 0, because we don't want to see WAP changed + + + } + } + else + { + $error++;$this->errors[]="Error ".$this->db->lasterror(); + } + } + + if (! $error) + { + $sql = "DELETE FROM ".MAIN_DB_PREFIX."commande_fournisseur_dispatch"; + $sql.= " WHERE fk_reception = ".$this->id; + + if ( $this->db->query($sql) ) + { + // Delete linked object + $res = $this->deleteObjectLinked(); + if ($res < 0) $error++; + + if (! $error) + { + $sql = "DELETE FROM ".MAIN_DB_PREFIX."reception"; + $sql.= " WHERE rowid = ".$this->id; + + if ($this->db->query($sql)) + { + // Call trigger + $result=$this->call_trigger('RECEPTION_DELETE',$user); + if ($result < 0) { $error++; } + // End call triggers + + if (! empty($this->origin) && $this->origin_id > 0) + { + $this->fetch_origin(); + $origin=$this->origin; + if ($this->$origin->statut == 4) // If order source of reception is "partially received" + { + // Check if there is no more reception. If not, we can move back status of order to "validated" instead of "reception in progress" + $this->$origin->loadReceptions(); + //var_dump($this->$origin->receptions);exit; + if (count($this->$origin->receptions) <= 0) + { + $this->$origin->setStatut(3); // ordered + } + } + } + + if (! $error) + { + $this->db->commit(); + + // We delete PDFs + $ref = dol_sanitizeFileName($this->ref); + if (! empty($conf->reception->dir_output)) + { + $dir = $conf->reception->dir_output . '/' . $ref ; + $file = $dir . '/' . $ref . '.pdf'; + if (file_exists($file)) + { + if (! dol_delete_file($file)) + { + return 0; + } + } + if (file_exists($dir)) + { + if (!dol_delete_dir_recursive($dir)) + { + $this->error=$langs->trans("ErrorCanNotDeleteDir",$dir); + return 0; + } + } + } + + return 1; + } + else + { + $this->db->rollback(); + return -1; + } + } + else + { + $this->error=$this->db->lasterror()." - sql=$sql"; + $this->db->rollback(); + return -3; + } + } + else + { + $this->error=$this->db->lasterror()." - sql=$sql"; + $this->db->rollback(); + return -2; + } + } + else + { + $this->error=$this->db->lasterror()." - sql=$sql"; + $this->db->rollback(); + return -1; + } + } + else + { + $this->db->rollback(); + return -1; + } + + } + // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps + /** + * Load lines + * + * @return int >0 if OK, Otherwise if KO + */ + function fetch_lines() + { + // phpcs:enable + global $db; + dol_include_once('/fourn/class/fournisseur.commande.dispatch.class.php'); + $sql = 'SELECT rowid FROM '.MAIN_DB_PREFIX.'commande_fournisseur_dispatch WHERE fk_reception='.$this->id; + $resql = $db->query($sql); + + if(!empty($resql)){ + $this->lines = array(); + while ($obj = $resql->fetch_object()){ + $line = new CommandeFournisseurDispatch($db); + $line->fetch($obj->rowid); + $line->fetch_product(); + $sql_commfourndet = 'SELECT qty, ref, label, tva_tx, vat_src_code, subprice, multicurrency_subprice, remise_percent FROM llx_commande_fournisseurdet WHERE rowid='.$line->fk_commandefourndet; + $resql_commfourndet = $db->query($sql_commfourndet); + if(!empty($resql_commfourndet)){ + $obj = $db->fetch_object($resql_commfourndet); + $line->qty_asked = $obj->qty; + $line->description = $line->comment; + $line->desc = $line->comment; + $line->tva_tx = $obj->tva_tx; + $line->vat_src_code = $obj->vat_src_code; + $line->subprice = $obj->subprice; + $line->multicurrency_subprice = $obj->multicurrency_subprice; + $line->remise_percent = $obj->remise_percent; + $line->label = !empty($obj->label)?$obj->label:$line->product->label; + $line->ref_supplier = $obj->ref; + }else { + $line->qty_asked = 0; + $line->description = ''; + $line->label = $obj->label; + } + + $pu_ht=($line->subprice*$line->qty)*(100-$line->remise_percent)/100; + $tva = $pu_ht*$line->tva_tx/100; + $this->total_ht += $pu_ht; + $this->total_tva += $pu_ht*$line->tva_tx/100; + + $this->total_ttc += $pu_ht+$tva; + + + $this->lines[]=$line; + } + + return 1; + }else { + return -1; + } + + } + + /** + * Return clicable link of object (with eventually picto) + * + * @param int $withpicto Add picto into link + * @param int $option Where point the link + * @param int $max Max length to show + * @param int $short Use short labels + * @param int $notooltip 1=No tooltip + * @return string String with URL + */ + function getNomUrl($withpicto=0,$option=0,$max=0,$short=0,$notooltip=0) + { + global $langs; + $result=''; + $label = '' . $langs->trans("ShowReception") . ''; + $label .= '
' . $langs->trans('Ref') . ': '.$this->ref; + $label .= '
'.$langs->trans('RefSupplier').': '.($this->ref_supplier ? $this->ref_supplier : $this->ref_client); + + $url = DOL_URL_ROOT.'/reception/card.php?id='.$this->id; + + if ($short) return $url; + + $linkclose=''; + if (empty($notooltip)) + { + if (! empty($conf->global->MAIN_OPTIMIZEFORTEXTBROWSER)) + { + $label=$langs->trans("ShowReception"); + $linkclose.=' alt="'.dol_escape_htmltag($label, 1).'"'; + } + $linkclose.= ' title="'.dol_escape_htmltag($label, 1).'"'; + $linkclose.=' class="classfortooltip"'; + } + + $linkstart = ''; + $linkend=''; + + $picto='sending'; + + if ($withpicto) $result.=($linkstart.img_object(($notooltip?'':$label), $picto, ($notooltip?'':'class="classfortooltip"'), 0, 0, $notooltip?0:1).$linkend); + if ($withpicto && $withpicto != 2) $result.=' '; + $result.=$linkstart.$this->ref.$linkend; + return $result; + } + + /** + * Return status label + * + * @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 Libelle + */ + function getLibStatut($mode=0) + { + return $this->LibStatut($this->statut,$mode); + } + + /** + * Return label of a status + * + * @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 of status + */ + function LibStatut($statut,$mode) + { + global $langs; + + if ($mode==0) + { + if ($statut==0) return $langs->trans($this->statuts[$statut]); + if ($statut==1) return $langs->trans($this->statuts[$statut]); + if ($statut==2) return $langs->trans($this->statuts[$statut]); + } + if ($mode==1) + { + if ($statut==0) return $langs->trans('StatusReceptionDraftShort'); + if ($statut==1) return $langs->trans('StatusReceptionValidatedShort'); + if ($statut==2) return $langs->trans('StatusReceptionProcessedShort'); + } + if ($mode == 3) + { + if ($statut==0) return img_picto($langs->trans($this->statuts[$statut]),'statut0'); + if ($statut==1) return img_picto($langs->trans($this->statuts[$statut]),'statut4'); + if ($statut==2) return img_picto($langs->trans('StatusReceptionProcessed'),'statut6'); + } + if ($mode == 4) + { + if ($statut==0) return img_picto($langs->trans($this->statuts[$statut]),'statut0').' '.$langs->trans($this->statuts[$statut]); + if ($statut==1) return img_picto($langs->trans($this->statuts[$statut]),'statut4').' '.$langs->trans($this->statuts[$statut]); + if ($statut==2) return img_picto($langs->trans('StatusReceptionProcessed'),'statut6').' '.$langs->trans('StatusReceptionProcessed'); + } + if ($mode == 5) + { + if ($statut==0) return $langs->trans('StatusReceptionDraftShort').' '.img_picto($langs->trans($this->statuts[$statut]),'statut0'); + if ($statut==1) return $langs->trans('StatusReceptionValidatedShort').' '.img_picto($langs->trans($this->statuts[$statut]),'statut4'); + if ($statut==2) return $langs->trans('StatusReceptionProcessedShort').' '.img_picto($langs->trans('StatusReceptionProcessedShort'),'statut6'); + } + } + + /** + * 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 $langs; + dol_include_once('/fourn/class/fournisseur.commande.dispatch.class.php'); + $now=dol_now(); + + dol_syslog(get_class($this)."::initAsSpecimen"); + + // Load array of products prodids + $num_prods = 0; + $prodids = array(); + $sql = "SELECT rowid"; + $sql.= " FROM ".MAIN_DB_PREFIX."product"; + $sql.= " WHERE entity IN (".getEntity('product').")"; + $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]; + } + } + + $order=new Commande($this->db); + $order->initAsSpecimen(); + + // Initialise parametres + $this->id=0; + $this->ref = 'SPECIMEN'; + $this->specimen=1; + $this->statut = 1; + $this->livraison_id = 0; + $this->date = $now; + $this->date_creation = $now; + $this->date_valid = $now; + $this->date_delivery = $now; + $this->date_reception = $now + 24*3600; + + $this->entrepot_id = 0; + $this->fk_delivery_address = 0; + $this->socid = 1; + + $this->commande_id = 0; + $this->commande = $order; + + $this->origin_id = 1; + $this->origin = 'commande'; + + $this->note_private = 'Private note'; + $this->note_public = 'Public note'; + + $nbp = 5; + $xnbp = 0; + while ($xnbp < $nbp) + { + $line=new CommandeFournisseurDispatch($this->db); + $line->desc=$langs->trans("Description")." ".$xnbp; + $line->libelle=$langs->trans("Description")." ".$xnbp; + $line->qty=10; + + $line->fk_product=$this->commande->lines[$xnbp]->fk_product; + + $this->lines[]=$line; + $xnbp++; + } + + } + + // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps + /** + * Set the planned delivery date + * + * @param User $user Objet utilisateur qui modifie + * @param timestamp $date_livraison Date de livraison + * @return int <0 if KO, >0 if OK + */ + function set_date_livraison($user, $date_livraison) + { + // phpcs:enable + if ($user->rights->reception->creer) + { + $sql = "UPDATE ".MAIN_DB_PREFIX."reception"; + $sql.= " SET date_delivery = ".($date_livraison ? "'".$this->db->idate($date_livraison)."'" : 'null'); + $sql.= " WHERE rowid = ".$this->id; + + dol_syslog(get_class($this)."::set_date_livraison", LOG_DEBUG); + $resql=$this->db->query($sql); + if ($resql) + { + $this->date_delivery = $date_livraison; + return 1; + } + else + { + $this->error=$this->db->error(); + return -1; + } + } + else + { + return -2; + } + } + // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps + /** + * Fetch deliveries method and return an array. Load array this->meths(rowid=>label). + * + * @return void + */ + function fetch_delivery_methods() + { + // phpcs:enable + global $langs; + $this->meths = array(); + + $sql = "SELECT em.rowid, em.code, em.libelle"; + $sql.= " FROM ".MAIN_DB_PREFIX."c_shipment_mode as em"; + $sql.= " WHERE em.active = 1"; + $sql.= " ORDER BY em.libelle ASC"; + + $resql = $this->db->query($sql); + if ($resql) + { + while ($obj = $this->db->fetch_object($resql)) + { + $label=$langs->trans('ReceptionMethod'.$obj->code); + $this->meths[$obj->rowid] = ($label != 'ReceptionMethod'.$obj->code?$label:$obj->libelle); + } + } + } + // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps + /** + * Fetch all deliveries method and return an array. Load array this->listmeths. + * + * @param id $id only this carrier, all if none + * @return void + */ + function list_delivery_methods($id='') + { + // phpcs:enable + global $langs; + + $this->listmeths = array(); + $i=0; + + $sql = "SELECT em.rowid, em.code, em.libelle, em.description, em.tracking, em.active"; + $sql.= " FROM ".MAIN_DB_PREFIX."c_shipment_mode as em"; + if ($id!='') $sql.= " WHERE em.rowid=".$id; + + $resql = $this->db->query($sql); + if ($resql) + { + while ($obj = $this->db->fetch_object($resql)) + { + $this->listmeths[$i]['rowid'] = $obj->rowid; + $this->listmeths[$i]['code'] = $obj->code; + $label=$langs->trans('ReceptionMethod'.$obj->code); + $this->listmeths[$i]['libelle'] = ($label != 'ReceptionMethod'.$obj->code?$label:$obj->libelle); + $this->listmeths[$i]['description'] = $obj->description; + $this->listmeths[$i]['tracking'] = $obj->tracking; + $this->listmeths[$i]['active'] = $obj->active; + $i++; + } + } + } + + // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps + /** + * Update/create delivery method. + * + * @param string $id id method to activate + * + * @return void + */ + function update_delivery_method($id='') + { + // phpcs:enable + if ($id=='') + { + $sql = "INSERT INTO ".MAIN_DB_PREFIX."c_shipment_mode (code, libelle, description, tracking)"; + $sql.=" VALUES ('".$this->update['code']."','".$this->update['libelle']."','".$this->update['description']."','".$this->update['tracking']."')"; + $resql = $this->db->query($sql); + } + else + { + $sql = "UPDATE ".MAIN_DB_PREFIX."c_shipment_mode SET"; + $sql.= " code='".$this->db->escape($this->update['code'])."'"; + $sql.= ",libelle='".$this->db->escape($this->update['libelle'])."'"; + $sql.= ",description='".$this->db->escape($this->update['description'])."'"; + $sql.= ",tracking='".$this->db->escape($this->update['tracking'])."'"; + $sql.= " WHERE rowid=".$id; + $resql = $this->db->query($sql); + } + if ($resql < 0) dol_print_error($this->db,''); + } + + // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps + /** + * Activate delivery method. + * + * @param id $id id method to activate + * + * @return void + */ + function activ_delivery_method($id) + { + // phpcs:enable + $sql = 'UPDATE '.MAIN_DB_PREFIX.'c_shipment_mode SET active=1'; + $sql.= ' WHERE rowid='.$id; + + $resql = $this->db->query($sql); + + } + + // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps + /** + * DesActivate delivery method. + * + * @param id $id id method to desactivate + * + * @return void + */ + function disable_delivery_method($id) + { + // phpcs:enable + $sql = 'UPDATE '.MAIN_DB_PREFIX.'c_shipment_mode SET active=0'; + $sql.= ' WHERE rowid='.$id; + + $resql = $this->db->query($sql); + + } + + + /** + * Forge an set tracking url + * + * @param string $value Value + * @return void + */ + function GetUrlTrackingStatus($value='') + { + if (! empty($this->shipping_method_id)) + { + $sql = "SELECT em.code, em.tracking"; + $sql.= " FROM ".MAIN_DB_PREFIX."c_shipment_mode as em"; + $sql.= " WHERE em.rowid = ".$this->shipping_method_id; + + $resql = $this->db->query($sql); + if ($resql) + { + if ($obj = $this->db->fetch_object($resql)) + { + $tracking = $obj->tracking; + } + } + } + + if (!empty($tracking) && !empty($value)) + { + $url = str_replace('{TRACKID}', $value, $tracking); + $this->tracking_url = sprintf(''.($value?$value:'url').'',$url,$url); + } + else + { + $this->tracking_url = $value; + } + } + + /** + * Classify the reception as closed. + * + * @return int <0 if KO, >0 if OK + */ + function setClosed() + { + global $conf,$langs,$user; + + $error=0; + + $this->db->begin(); + + $sql = 'UPDATE '.MAIN_DB_PREFIX.'reception SET fk_statut='.self::STATUS_CLOSED; + $sql .= ' WHERE rowid = '.$this->id.' AND fk_statut > 0'; + + $resql=$this->db->query($sql); + if ($resql) + { + // Set order billed if 100% of order is received (qty in reception lines match qty in order lines) + if ($this->origin == 'order_supplier' && $this->origin_id > 0) + { + $order = new CommandeFournisseur($this->db); + $order->fetch($this->origin_id); + + $order->loadReceptions(self::STATUS_CLOSED); // Fill $order->receptions = array(orderlineid => qty) + + $receptions_match_order = 1; + foreach($order->lines as $line) + { + $lineid = $line->id; + $qty = $line->qty; + if (($line->product_type == 0 || ! empty($conf->global->STOCK_SUPPORTS_SERVICES)) && $order->receptions[$lineid] < $qty) + { + $receptions_match_order = 0; + $text='Qty for order line id '.$lineid.' is '.$qty.'. However in the receptions with status Reception::STATUS_CLOSED='.self::STATUS_CLOSED.' we have qty = '.$order->receptions[$lineid].', so we can t close order'; + dol_syslog($text); + break; + } + } + if ($receptions_match_order) + { + dol_syslog("Qty for the ".count($order->lines)." lines of order have same value for receptions with status Reception::STATUS_CLOSED=".self::STATUS_CLOSED.', so we close order'); + $order->Livraison($user, dol_now(), 'tot', 'Reception '.$this->ref); + } + } + + $this->statut=self::STATUS_CLOSED; + + + // If stock increment is done on closing + if (! $error && ! empty($conf->stock->enabled) && ! empty($conf->global->STOCK_CALCULATE_ON_RECEPTION_CLOSE)) + { + require_once DOL_DOCUMENT_ROOT.'/product/stock/class/mouvementstock.class.php'; + + $langs->load("agenda"); + + // Loop on each product line to add a stock movement + // TODO possibilite de receptionner a partir d'une propale ou autre origine ? + $sql = "SELECT cd.fk_product, cd.subprice,"; + $sql.= " ed.rowid, ed.qty, ed.fk_entrepot,"; + $sql.= " ed.eatby, ed.sellby, ed.batch"; + $sql.= " FROM ".MAIN_DB_PREFIX."commande_fournisseurdet as cd,"; + $sql.= " ".MAIN_DB_PREFIX."commande_fournisseur_dispatch as ed"; + $sql.= " WHERE ed.fk_reception = ".$this->id; + $sql.= " AND cd.rowid = ed.fk_commandefourndet"; + + dol_syslog(get_class($this)."::valid select details", LOG_DEBUG); + $resql=$this->db->query($sql); + + if ($resql) + { + $cpt = $this->db->num_rows($resql); + for ($i = 0; $i < $cpt; $i++) + { + $obj = $this->db->fetch_object($resql); + + $qty = $obj->qty; + + if ($qty <= 0) continue; + dol_syslog(get_class($this)."::valid movement index ".$i." ed.rowid=".$obj->rowid." edb.rowid=".$obj->edbrowid); + + $mouvS = new MouvementStock($this->db); + $mouvS->origin = &$this; + + if (empty($obj->batch)) + { + // line without batch detail + + // We decrement stock of product (and sub-products) -> update table llx_product_stock (key of this table is fk_product+fk_entrepot) and add a movement record + $result=$mouvS->reception($user, $obj->fk_product, $obj->fk_entrepot, $qty, $obj->subprice, $langs->trans("ReceptionClassifyClosedInDolibarr",$numref)); + if ($result < 0) { + $this->error = $mouvS->error; + $this->errors = $mouvS->errors; + $error++; break; + } + + } + else + { + // line with batch detail + + // We decrement stock of product (and sub-products) -> update table llx_product_stock (key of this table is fk_product+fk_entrepot) and add a movement record + $result=$mouvS->reception($user, $obj->fk_product, $obj->fk_entrepot, $qty, $obj->subprice, $langs->trans("ReceptionClassifyClosedInDolibarr",$numref), $this->db->jdate($obj->eatby), $this->db->jdate($obj->sellby), $obj->batch); + + if ($result < 0) { + $this->error = $mouvS->error; + $this->errors = $mouvS->errors; + $error++; break; + } + } + + } + } + else + { + $this->error=$this->db->lasterror(); + $error++; + } + } + + // Call trigger + if (! $error) + { + $result=$this->call_trigger('RECEPTION_CLOSED',$user); + if ($result < 0) { + $error++; + } + } + } + else + { + dol_print_error($this->db); + $error++; + } + + if (! $error) + { + $this->db->commit(); + return 1; + } + else + { + $this->db->rollback(); + return -1; + } + } + // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps + /** + * Classify the reception as invoiced (used when WORKFLOW_BILL_ON_RECEPTION is on) + * + * @return int <0 if ko, >0 if ok + */ + function set_billed() + { + // phpcs:enable + global $user; + $error=0; + + $this->db->begin(); + + $this->setClosed(); + + $sql = 'UPDATE '.MAIN_DB_PREFIX.'reception SET billed=1'; + $sql .= ' WHERE rowid = '.$this->id.' AND fk_statut > 0'; + + $resql=$this->db->query($sql); + if ($resql) + { + $this->statut=2; + $this->billed=1; + + // Call trigger + $result=$this->call_trigger('RECEPTION_BILLED',$user); + if ($result < 0) { + $error++; + } + + } else { + $error++; + $this->errors[]=$this->db->lasterror; + } + + if (empty($error)) { + $this->db->commit(); + return 1; + } + else + { + $this->db->rollback(); + return -1; + } + } + + /** + * Classify the reception as validated/opened + * + * @return int <0 if ko, >0 if ok + */ + function reOpen() + { + global $conf,$langs,$user; + + $error=0; + + $this->db->begin(); + + $sql = 'UPDATE '.MAIN_DB_PREFIX.'reception SET fk_statut=1, billed=0'; + $sql .= ' WHERE rowid = '.$this->id.' AND fk_statut > 0'; + + $resql=$this->db->query($sql); + if ($resql) + { + $this->statut=1; + $this->billed=0; + + // If stock increment is done on closing + if (! $error && ! empty($conf->stock->enabled) && ! empty($conf->global->STOCK_CALCULATE_ON_RECEPTION_CLOSE)) + { + require_once DOL_DOCUMENT_ROOT.'/product/stock/class/mouvementstock.class.php'; + $numref = $this->ref; + $langs->load("agenda"); + + // Loop on each product line to add a stock movement + // TODO possibilite de receptionner a partir d'une propale ou autre origine + $sql = "SELECT ed.fk_product, cd.subprice,"; + $sql.= " ed.rowid, ed.qty, ed.fk_entrepot,"; + $sql.= " ed.eatby, ed.sellby, ed.batch"; + $sql.= " FROM ".MAIN_DB_PREFIX."commande_fournisseurdet as cd,"; + $sql.= " ".MAIN_DB_PREFIX."commande_fournisseur_dispatch as ed"; + $sql.= " WHERE ed.fk_reception = ".$this->id; + $sql.= " AND cd.rowid = ed.fk_commandefourndet"; + + dol_syslog(get_class($this)."::valid select details", LOG_DEBUG); + $resql=$this->db->query($sql); + if ($resql) + { + $cpt = $this->db->num_rows($resql); + for ($i = 0; $i < $cpt; $i++) + { + $obj = $this->db->fetch_object($resql); + + $qty = $obj->qty; + + if ($qty <= 0) continue; + + dol_syslog(get_class($this)."::reopen reception movement index ".$i." ed.rowid=".$obj->rowid); + + //var_dump($this->lines[$i]); + $mouvS = new MouvementStock($this->db); + $mouvS->origin = &$this; + + if (empty($obj->batch)) + { + // line without batch detail + + // We decrement stock of product (and sub-products) -> update table llx_product_stock (key of this table is fk_product+fk_entrepot) and add a movement record + $result=$mouvS->reception($user, $obj->fk_product, $obj->fk_entrepot, -$qty, $obj->subprice, $langs->trans("ReceptionUnClassifyCloseddInDolibarr",$numref)); + if ($result < 0) { + $this->error = $mouvS->error; + $this->errors = $mouvS->errors; + $error++; break; + } + } + else + { + // line with batch detail + + // We decrement stock of product (and sub-products) -> update table llx_product_stock (key of this table is fk_product+fk_entrepot) and add a movement record + $result=$mouvS->reception($user, $obj->fk_product, $obj->fk_entrepot, -$qty, $obj->subprice, $langs->trans("ReceptionUnClassifyCloseddInDolibarr",$numref), $this->db->jdate($obj->eatby), $this->db->jdate($obj->sellby), $obj->batch, $obj->fk_origin_stock); + if ($result < 0) { + $this->error = $mouvS->error; + $this->errors = $mouvS->errors; + $error++; break; + } + } + } + } + else + { + $this->error=$this->db->lasterror(); + $error++; + } + } + + if (! $error) + { + // Call trigger + $result=$this->call_trigger('RECEPTION_REOPEN',$user); + if ($result < 0) { + $error++; + } + } + + if($this->origin == 'order_supplier'){ + $commande = new CommandeFournisseur($this->db); + $commande->fetch($this->origin_id); + $commande->setStatus($user,4); + } + + } else { + $error++; + $this->errors[]=$this->db->lasterror(); + } + + if (! $error) + { + $this->db->commit(); + return 1; + } + else + { + $this->db->rollback(); + return -1; + } + } + + + // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps + /** + * Set draft status + * + * @param User $user Object user that modify + * @return int <0 if KO, >0 if OK + */ + function set_draft($user) + { + // phpcs:enable + global $conf,$langs; + + $error=0; + + // Protection + if ($this->statut <= self::STATUS_DRAFT) + { + return 0; + } + + if (! ((empty($conf->global->MAIN_USE_ADVANCED_PERMS) && ! empty($user->rights->reception->creer)) + || (! empty($conf->global->MAIN_USE_ADVANCED_PERMS) && ! empty($user->rights->reception->reception_advance->validate)))) + { + $this->error='Permission denied'; + return -1; + } + + $this->db->begin(); + + $sql = "UPDATE ".MAIN_DB_PREFIX."reception"; + $sql.= " SET fk_statut = ".self::STATUS_DRAFT; + $sql.= " WHERE rowid = ".$this->id; + + dol_syslog(get_class($this)."::set_draft", LOG_DEBUG); + if ($this->db->query($sql)) + { + // If stock increment is done on closing + if (! $error && ! empty($conf->stock->enabled) && ! empty($conf->global->STOCK_CALCULATE_ON_RECEPTION)) + { + require_once DOL_DOCUMENT_ROOT.'/product/stock/class/mouvementstock.class.php'; + + $langs->load("agenda"); + + // Loop on each product line to add a stock movement + // TODO possibilite de receptionner a partir d'une propale ou autre origine + $sql = "SELECT cd.fk_product, cd.subprice,"; + $sql.= " ed.rowid, ed.qty, ed.fk_entrepot,"; + $sql.= " ed.eatby, ed.sellby, ed.batch"; + $sql.= " FROM ".MAIN_DB_PREFIX."commande_fournisseurdet as cd,"; + $sql.= " ".MAIN_DB_PREFIX."commande_fournisseur_dispatch as ed"; + $sql.= " WHERE ed.fk_reception = ".$this->id; + $sql.= " AND cd.rowid = ed.fk_commandefourndet"; + + dol_syslog(get_class($this)."::valid select details", LOG_DEBUG); + $resql=$this->db->query($sql); + if ($resql) + { + $cpt = $this->db->num_rows($resql); + for ($i = 0; $i < $cpt; $i++) + { + $obj = $this->db->fetch_object($resql); + + $qty = $obj->qty; + + + if ($qty <= 0) continue; + dol_syslog(get_class($this)."::reopen reception movement index ".$i." ed.rowid=".$obj->rowid." edb.rowid=".$obj->edbrowid); + + //var_dump($this->lines[$i]); + $mouvS = new MouvementStock($this->db); + $mouvS->origin = &$this; + + if (empty($obj->batch)) + { + // line without batch detail + + // We decrement stock of product (and sub-products) -> update table llx_product_stock (key of this table is fk_product+fk_entrepot) and add a movement record + $result=$mouvS->reception($user, $obj->fk_product, $obj->fk_entrepot, -$qty, $obj->subprice, $langs->trans("ReceptionBackToDraftInDolibarr",$this->ref)); + if ($result < 0) { + $this->error = $mouvS->error; + $this->errors = $mouvS->errors; + $error++; break; + + } + } + else + { + // line with batch detail + + // We decrement stock of product (and sub-products) -> update table llx_product_stock (key of this table is fk_product+fk_entrepot) and add a movement record + $result=$mouvS->reception($user, $obj->fk_product, $obj->fk_entrepot, -$qty, $obj->subprice, $langs->trans("ReceptionBackToDraftInDolibarr",$this->ref), $this->db->jdate($obj->eatby), $this->db->jdate($obj->sellby), $obj->batch); + if ($result < 0) { + $this->error = $mouvS->error; + $this->errors = $mouvS->errors; + $error++; break; + } + } + + } + } + else + { + $this->error=$this->db->lasterror(); + $error++; + } + } + + if (!$error) { + // Call trigger + $result=$this->call_trigger('RECEPTION_UNVALIDATE',$user); + if ($result < 0) $error++; + } + if ($this->origin == 'order_supplier') + { + if (!empty($this->origin) && $this->origin_id > 0) + { + $this->fetch_origin(); + $origin = $this->origin; + if ($this->$origin->statut == 4) // If order source of reception is "partially received" + { + // Check if there is no more reception validated. + $this->$origin->fetchObjectLinked(); + $setStatut = 1; + if (!empty($this->$origin->linkedObjects['reception'])) + { + foreach ($this->$origin->linkedObjects['reception'] as $rcption) + { + if ($rcption->statut > 0) + { + $setStatut = 0; + break; + } + } + //var_dump($this->$origin->receptions);exit; + if ($setStatut) + { + $this->$origin->setStatut(3); // ordered + } + } + } + } + } + + + if (!$error) { + $this->statut=self::STATUS_DRAFT; + $this->db->commit(); + return 1; + }else { + $this->db->rollback(); + return -1; + } + } + else + { + $this->error=$this->db->error(); + $this->db->rollback(); + return -1; + } + } + + /** + * Create a document onto disk according to template module. + * + * @param string $modele Force the model to using ('' to not force) + * @param Translate $outputlangs object lang to use for translations + * @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,$langs; + + $langs->load("receptions"); + + if (! dol_strlen($modele)) { + + $modele = 'squille'; + + if ($this->modelpdf) { + $modele = $this->modelpdf; + } elseif (! empty($conf->global->RECEPTION_ADDON_PDF)) { + $modele = $conf->global->RECEPTION_ADDON_PDF; + } + } + + $modelpath = "core/modules/reception/doc/"; + + $this->fetch_origin(); + + return $this->commonGenerateDocument($modelpath, $modele, $outputlangs, $hidedetails, $hidedesc, $hideref); + } + + /** + * Function used to replace a thirdparty id with another one. + * + * @param DoliDB $db Database handler + * @param int $origin_id Old thirdparty id + * @param int $dest_id New thirdparty id + * @return bool + */ + public static function replaceThirdparty(DoliDB $db, $origin_id, $dest_id) + { + $tables = array( + 'reception' + ); + + return CommonObject::commonReplaceThirdparty($db, $origin_id, $dest_id, $tables); + } +} diff --git a/htdocs/reception/class/receptionstats.class.php b/htdocs/reception/class/receptionstats.class.php new file mode 100644 index 00000000000..510bd4d8410 --- /dev/null +++ b/htdocs/reception/class/receptionstats.class.php @@ -0,0 +1,142 @@ + + * Copyright (c) 2005-2013 Laurent Destailleur + * Copyright (C) 2005-2009 Regis Houssin + * Copyright (C) 2011 Juanjo Menent + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/** + * \file htdocs/reception/class/receptionstats.class.php + * \ingroup reception + * \brief File of class fo tmanage reception statistics + */ + +include_once DOL_DOCUMENT_ROOT . '/core/class/stats.class.php'; +include_once DOL_DOCUMENT_ROOT . '/reception/class/reception.class.php'; +include_once DOL_DOCUMENT_ROOT . '/core/lib/date.lib.php'; + + +/** + * Class to manage reception statistics + */ +class ReceptionStats extends Stats +{ + public $table_element; + + var $socid; + var $userid; + + var $from; + var $field; + var $where; + + + /** + * Constructor + * + * @param DoliDB $db Database handler + * @param int $socid Id third party for filter + * @param string $mode Option (not used) + * @param int $userid Id user for filter (creation user) + */ + function __construct($db, $socid, $mode, $userid=0) + { + global $user, $conf; + + $this->db = $db; + + $this->socid = ($socid > 0 ? $socid : 0); + $this->userid = $userid; + $this->cachefilesuffix = $mode; + + $object=new Reception($this->db); + $this->from = MAIN_DB_PREFIX.$object->table_element." as c"; + //$this->from.= ", ".MAIN_DB_PREFIX."societe as s"; + $this->field='weight'; // Warning, unit of weight is NOT USED AND MUST BE + $this->where.= " c.fk_statut > 0"; // Not draft and not cancelled + + //$this->where.= " AND c.fk_soc = s.rowid AND c.entity = ".$conf->entity; + $this->where.= " AND c.entity = ".$conf->entity; + if (!$user->rights->societe->client->voir && !$this->socid) $this->where .= " AND c.fk_soc = sc.fk_soc AND sc.fk_user = " .$user->id; + if ($this->socid) + { + $this->where.=" AND c.fk_soc = ".$this->socid; + } + if ($this->userid > 0) $this->where.=' AND c.fk_user_author = '.$this->userid; + } + + /** + * Return reception number by month for a year + * + * @param int $year Year to scan + * @return array Array with number by month + */ + function getNbByMonth($year) + { + global $user; + + $sql = "SELECT date_format(c.date_valid,'%m') as dm, COUNT(*) as nb"; + $sql.= " FROM ".$this->from; + if (!$user->rights->societe->client->voir && !$this->socid) $sql .= ", ".MAIN_DB_PREFIX."societe_commerciaux as sc"; + $sql.= " WHERE c.date_valid BETWEEN '".$this->db->idate(dol_get_first_day($year))."' AND '".$this->db->idate(dol_get_last_day($year))."'"; + $sql.= " AND ".$this->where; + $sql.= " GROUP BY dm"; + $sql.= $this->db->order('dm','DESC'); + + $res=$this->_getNbByMonth($year, $sql); + return $res; + } + + /** + * Return receptions number per year + * + * @return array Array with number by year + * + */ + function getNbByYear() + { + global $user; + + $sql = "SELECT date_format(c.date_valid,'%Y') as dm, COUNT(*) as nb, SUM(c.".$this->field.")"; + $sql.= " FROM ".$this->from; + if (!$user->rights->societe->client->voir && !$this->socid) $sql .= ", ".MAIN_DB_PREFIX."societe_commerciaux as sc"; + $sql.= " WHERE ".$this->where; + $sql.= " GROUP BY dm"; + $sql.= $this->db->order('dm','DESC'); + + return $this->_getNbByYear($sql); + } + + /** + * Return nb, total and average + * + * @return array Array of values + */ + function getAllByYear() + { + global $user; + + $sql = "SELECT date_format(c.date_valid,'%Y') as year, COUNT(*) as nb, SUM(c.".$this->field.") as total, AVG(".$this->field.") as avg"; + $sql.= " FROM ".$this->from; + if (!$user->rights->societe->client->voir && !$this->socid) $sql .= ", ".MAIN_DB_PREFIX."societe_commerciaux as sc"; + $sql.= " WHERE ".$this->where; + $sql.= " GROUP BY year"; + $sql.= $this->db->order('year','DESC'); + + return $this->_getAllByYear($sql); + } +} + diff --git a/htdocs/reception/contact.php b/htdocs/reception/contact.php new file mode 100644 index 00000000000..ef8f9650b5e --- /dev/null +++ b/htdocs/reception/contact.php @@ -0,0 +1,277 @@ + + * Copyright (C) 2005-2011 Laurent Destailleur + * Copyright (C) 2005-2012 Regis Houssin + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/** + * \file htdocs/reception/contact.php + * \ingroup reception + * \brief Onglet de gestion des contacts de reception + */ + +require '../main.inc.php'; +require_once DOL_DOCUMENT_ROOT.'/reception/class/reception.class.php'; +require_once DOL_DOCUMENT_ROOT.'/fourn/class/fournisseur.commande.class.php'; +require_once DOL_DOCUMENT_ROOT.'/contact/class/contact.class.php'; +require_once DOL_DOCUMENT_ROOT.'/core/lib/reception.lib.php'; +require_once DOL_DOCUMENT_ROOT.'/core/class/html.formother.class.php'; +require_once DOL_DOCUMENT_ROOT.'/core/class/html.formcompany.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("orders"); +$langs->load("receptions"); +$langs->load("companies"); + +$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, 'reception', $id,''); + +$object = new Reception($db); +if ($id > 0 || ! empty($ref)) +{ + $object->fetch($id, $ref); + $object->fetch_thirdparty(); + + if (!empty($object->origin)) + { + $origin = $object->origin; + + $object->fetch_origin(); + $typeobject = $object->origin; + + } + + // Linked documents + if ($origin == 'order_supplier' && $object->$typeobject->id && ! empty($conf->fournisseur->enabled)) + { + $objectsrc=new CommandeFournisseur($db); + $objectsrc->fetch($object->$typeobject->id); + } + if ($typeobject == 'propal' && $object->$typeobject->id && ! empty($conf->propal->enabled)) + { + $objectsrc=new Propal($db); + $objectsrc->fetch($object->$typeobject->id); + } +} + + +/* + * Actions + */ + +if ($action == 'addcontact' && $user->rights->reception->creer) +{ + if ($result > 0 && $id > 0) + { + $result = $objectsrc->add_contact(GETPOST('userid') ? GETPOST('userid') : GETPOST('contactid'), $_POST["type"], $_POST["source"]); + } + + if ($result >= 0) + { + header("Location: ".$_SERVER['PHP_SELF']."?id=".$object->id); + exit; + } + else + { + if ($objectsrc->error == 'DB_ERROR_RECORD_ALREADY_EXISTS') + { + $langs->load("errors"); + $mesg = $langs->trans("ErrorThisContactIsAlreadyDefinedAsThisType"); + } else { + $mesg = $objectsrc->error; + $mesgs = $objectsrc->errors; + } + setEventMessages($mesg, $mesgs, 'errors'); + } +} + +// bascule du statut d'un contact +else if ($action == 'swapstatut' && $user->rights->reception->creer) +{ + $result=$objectsrc->swapContactStatus(GETPOST('ligne')); +} + +// Efface un contact +else if ($action == 'deletecontact' && $user->rights->reception->creer) +{ + $result = $objectsrc->delete_contact(GETPOST("lineid")); + + if ($result >= 0) + { + header("Location: ".$_SERVER['PHP_SELF']."?id=".$object->id); + exit; + } + else { + dol_print_error($db); + } +} +/* +else if ($action == 'setaddress' && $user->rights->reception->creer) +{ + $object->fetch($id); + $result=$object->setDeliveryAddress($_POST['fk_address']); + if ($result < 0) dol_print_error($db,$object->error); +}*/ + + +/* + * View + */ + +llxHeader('',$langs->trans('Reception'),'EN:Customers_Orders|FR:receptions_Clients|ES:Pedidos de clientes'); + +$form = new Form($db); +$formcompany = new FormCompany($db); +$formother = new FormOther($db); +$contactstatic=new Contact($db); +$userstatic=new User($db); + + +/* *************************************************************************** */ +/* */ +/* Mode vue et edition */ +/* */ +/* *************************************************************************** */ + +if ($id > 0 || ! empty($ref)) +{ + $langs->trans("OrderCard"); + + $head = reception_prepare_head($object); + dol_fiche_head($head, 'contact', $langs->trans("Reception"), -1, 'sending'); + + + // Reception card + $linkback = ''.$langs->trans("BackToList").''; + + $morehtmlref='
'; + // Ref customer reception + $morehtmlref.=$form->editfieldkey("RefSupplier", '', $object->ref_supplier, $object, $user->rights->reception->creer, 'string', '', 0, 1); + $morehtmlref.=$form->editfieldval("RefSupplier", '', $object->ref_supplier, $object, $user->rights->reception->creer, 'string', '', null, null, '', 1); + // Thirdparty + $morehtmlref.='
'.$langs->trans('ThirdParty') . ' : ' . $object->thirdparty->getNomUrl(1); + // Project + if (! empty($conf->projet->enabled)) { + $langs->load("projects"); + $morehtmlref .= '
' . $langs->trans('Project') . ' '; + if (0) { // Do not change on reception + if ($action != 'classify') { + $morehtmlref .= '' . img_edit($langs->transnoentitiesnoconv('SetProject')) . ' : '; + } + if ($action == 'classify') { + // $morehtmlref.=$form->form_project($_SERVER['PHP_SELF'] . '?id=' . $object->id, $object->socid, $object->fk_project, 'projectid', 0, 0, 1, 1); + $morehtmlref .= ''; + $morehtmlref .= ''; + $morehtmlref .= ''; + $morehtmlref .= $formproject->select_projects($object->socid, $object->fk_project, 'projectid', $maxlength, 0, 1, 0, 1, 0, 0, '', 1); + $morehtmlref .= ''; + $morehtmlref .= ''; + } else { + $morehtmlref .= $form->form_project($_SERVER['PHP_SELF'] . '?id=' . $object->id, $object->socid, $object->fk_project, 'none', 0, 0, 0, 1); + } + } else { + // We don't have project on reception, so we will use the project or source object instead + // TODO Add project on reception + $morehtmlref .= ' : '; + if (! empty($objectsrc->fk_project)) { + $proj = new Project($db); + $proj->fetch($objectsrc->fk_project); + $morehtmlref .= ''; + $morehtmlref .= $proj->ref; + $morehtmlref .= ''; + } else { + $morehtmlref .= ''; + } + } + } + $morehtmlref.='
'; + + $object->picto = 'sending'; + dol_banner_tab($object, 'ref', $linkback, 1, 'ref', 'ref', $morehtmlref); + + + print '
'; + //print '
'; + print '
'; + + print ''; + // Linked documents + if ($origin == 'order_supplier' && $object->$typeobject->id && ! empty($conf->fournisseur->enabled)) + { + print ''; + print '\n"; + print ''; + } + if ($typeobject == 'propal' && $object->$typeobject->id && ! empty($conf->propal->enabled)) + { + print ''; + print '\n"; + print ''; + } + + print "
'; + $objectsrc=new CommandeFournisseur($db); + $objectsrc->fetch($object->$typeobject->id); + print $langs->trans("RefOrder").''; + print $objectsrc->getNomUrl(1,'commande'); + print "
'; + $objectsrc=new Propal($db); + $objectsrc->fetch($object->$typeobject->id); + print $langs->trans("RefProposal").''; + print $objectsrc->getNomUrl(1,'reception'); + print "
"; + + + //print '
'; + //print '
'; + //print '
'; + //print '
'; + + + //print '
'; + //print '
'; + print '
'; + + print '
'; + + + dol_fiche_end(); + + // Lignes de contacts + echo '
'; + + // Contacts lines (modules that overwrite templates must declare this into descriptor) + $dirtpls=array_merge($conf->modules_parts['tpl'],array('/core/tpl')); + foreach($dirtpls as $reldir) + { + $res=@include dol_buildpath($reldir.'/contacts.tpl.php'); + if ($res) break; + } + + +} + +llxFooter(); + +$db->close(); diff --git a/htdocs/reception/index.php b/htdocs/reception/index.php new file mode 100644 index 00000000000..d8fef2e7d52 --- /dev/null +++ b/htdocs/reception/index.php @@ -0,0 +1,297 @@ + + * Copyright (C) 2004-2011 Laurent Destailleur + * Copyright (C) 2005-2012 Regis Houssin + * Copyright (C) 2018 Quentin Vial-Gouteyron + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/** + * \file htdocs/reception/index.php + * \ingroup reception + * \brief Home page of reception area. + */ + +require '../main.inc.php'; +require_once DOL_DOCUMENT_ROOT.'/fourn/class/fournisseur.commande.class.php'; +require_once DOL_DOCUMENT_ROOT.'/reception/class/reception.class.php'; + +$langs->load("orders"); +$langs->load("receptions"); + +/* + * View + */ + +$orderstatic=new CommandeFournisseur($db); +$companystatic=new Societe($db); +$reception=new Reception($db); + +$helpurl='EN:Module_Receptions|FR:Module_Receptions|ES:Módulo_Receptiones'; +llxHeader('',$langs->trans("Reception"),$helpurl); + +print load_fiche_titre($langs->trans("ReceptionsArea")); + + +print '
'; + + +if (! empty($conf->global->MAIN_SEARCH_FORM_ON_HOME_AREAS)) // This is useless due to the global search combo +{ + print '
'; + print ''; + print ''; + print ''; + print ''; + print "
'.$langs->trans("Search").'
'; + print $langs->trans("Reception").':

\n"; +} + +/* + * Receptions to validate + */ +$clause = " WHERE "; + +$sql = "SELECT e.rowid, e.ref, e.ref_supplier,"; +$sql.= " s.nom as name, s.rowid as socid,"; +$sql.= " c.ref as commande_fournisseur_ref, c.rowid as commande_fournisseur_id"; +$sql.= " FROM ".MAIN_DB_PREFIX."reception as e"; +$sql.= " LEFT JOIN ".MAIN_DB_PREFIX."element_element as el ON e.rowid = el.fk_target AND el.targettype = 'reception'"; +$sql.= " LEFT JOIN ".MAIN_DB_PREFIX."commande_fournisseur as c ON el.fk_source = c.rowid"; +$sql.= " LEFT JOIN ".MAIN_DB_PREFIX."societe as s ON s.rowid = e.fk_soc"; +if (!$user->rights->societe->client->voir && !$socid) +{ + $sql.= " LEFT JOIN ".MAIN_DB_PREFIX."societe_commerciaux as sc ON e.fk_soc = sc.fk_soc"; + $sql.= $clause." sc.fk_user = " .$user->id; + $clause = " AND "; +} +$sql.= $clause." e.fk_statut = 0"; +$sql.= " AND e.entity IN (".getEntity('reception').")"; +if ($socid) $sql.= " AND c.fk_soc = ".$socid; + +$resql=$db->query($sql); +if ($resql) +{ + $num = $db->num_rows($resql); + if ($num) + { + print ''; + print ''; + print ''; + $i = 0; + while ($i < $num) + { + $obj = $db->fetch_object($resql); + + $reception->id=$obj->rowid; + $reception->ref=$obj->ref; + $reception->ref_supplier=$obj->ref_supplier; + + print '"; + print ''; + print ''; + $i++; + } + print "
'.$langs->trans("ReceptionsToValidate").'
'; + print $reception->getNomUrl(1); + print "'; + print ''.$obj->name.''; + print ''; + if ($obj->commande_fournisseur_id) print ''.$obj->commande_fournisseur_ref.''; + print '

"; + } +} + + +/* + * CommandeFournisseurs a traiter + */ +$sql = "SELECT c.rowid, c.ref, c.ref_supplier as ref_supplier, c.fk_statut, s.nom as name, s.rowid as socid"; +$sql.= " FROM ".MAIN_DB_PREFIX."commande_fournisseur 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 = 3";//Commandé +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.rowid ASC"; +$resql=$db->query($sql); +if ($resql) +{ + $num = $db->num_rows($resql); + if ($num) + { + $langs->load("orders"); + + $i = 0; + print ''; + print ''; + print ''; + while ($i < $num) + { + $obj = $db->fetch_object($resql); + + $orderstatic->id=$obj->rowid; + $orderstatic->ref=$obj->ref; + $orderstatic->ref_supplier=$obj->ref_supplier; + $orderstatic->statut=$obj->fk_statut; + $orderstatic->facturee=0; + + $companystatic->name=$obj->name; + $companystatic->id=$obj->socid; + + print ''; + print ''; + print ''; + print ''; + print ''; + $i++; + } + print "
'.$langs->trans("SuppliersOrdersToProcess").'
'; + print $orderstatic->getNomUrl(1); + print ''; + print $companystatic->getNomUrl(1,'customer',32); + print ''; + print $orderstatic->getLibStatut(3); + print '

"; + } +} + + +//print ''; +print '
'; + + +/* + * CommandeFournisseurs en traitement + */ +$sql = "SELECT c.rowid, c.ref, c.ref_supplier as ref_supplier, c.fk_statut as status, c.billed as billed, s.nom as name, s.rowid as socid"; +$sql.= " FROM ".MAIN_DB_PREFIX."commande_fournisseur 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 IN (4)"; +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 ) +{ + $langs->load("orders"); + + $num = $db->num_rows($resql); + if ($num) + { + $i = 0; + print ''; + print ''; + print ''; + while ($i < $num) + { + $obj = $db->fetch_object($resql); + + $orderstatic->id=$obj->rowid; + $orderstatic->ref=$obj->ref; + $orderstatic->ref_supplier=$obj->ref_supplier; + $orderstatic->statut=$obj->status; + $orderstatic->facturee=$obj->billed; + + $companystatic->name=$obj->name; + $companystatic->id=$obj->socid; + + print ''; + print ''; + print ''; + print ''; + $i++; + } + print "
'.$langs->trans("SuppliersOrdersInProcess").'
'; + print $orderstatic->getNomUrl(1); + print ''; + print $companystatic->getNomUrl(1,'customer'); + print ''; + print $orderstatic->getLibStatut(3); + print '

"; + } +} +else dol_print_error($db); + + +/* + * Last receptions + */ +$sql = "SELECT e.rowid, e.ref, e.ref_supplier,"; +$sql.= " s.nom as name, s.rowid as socid,"; +$sql.= " c.ref as commande_fournisseur_ref, c.rowid as commande_fournisseur_id"; +$sql.= " FROM ".MAIN_DB_PREFIX."reception as e"; +$sql.= " LEFT JOIN ".MAIN_DB_PREFIX."element_element as el ON e.rowid = el.fk_target AND el.targettype = 'reception' AND el.sourcetype IN ('order_supplier')"; +$sql.= " LEFT JOIN ".MAIN_DB_PREFIX."commande_fournisseur as c ON el.fk_source = c.rowid AND el.sourcetype IN ('order_supplier') AND el.targettype = 'reception'"; +$sql.= " LEFT JOIN ".MAIN_DB_PREFIX."societe as s ON s.rowid = e.fk_soc"; +if (! $user->rights->societe->client->voir && ! $socid) $sql.= " LEFT JOIN ".MAIN_DB_PREFIX."societe_commerciaux as sc ON e.fk_soc = sc.fk_soc"; +$sql.= " WHERE e.entity IN (".getEntity('reception').")"; +if (! $user->rights->societe->client->voir && ! $socid) $sql.= " AND sc.fk_user = " .$user->id; +$sql.= " AND e.fk_statut = 1"; +if ($socid) $sql.= " AND c.fk_soc = ".$socid; +$sql.= " ORDER BY e.date_delivery DESC"; + +$sql.= $db->plimit(5, 0); + +$resql = $db->query($sql); +if ($resql) +{ + $num = $db->num_rows($resql); + if ($num) + { + $i = 0; + print ''; + print ''; + print ''; + while ($i < $num) + { + $obj = $db->fetch_object($resql); + + $reception->id=$obj->rowid; + $reception->ref=$obj->ref; + $reception->ref_supplier=$obj->ref_supplier; + + print ''; + print ''; + print ''; + $i++; + } + print "
'.$langs->trans("LastReceptions", $num).'
'; + print $reception->getNomUrl(1); + print ''.img_object($langs->trans("ShowCompany"),"company").' '.$obj->name.''; + if ($obj->commande_fournisseur_id > 0) + { + $orderstatic->id=$obj->commande_fournisseur_id; + $orderstatic->ref=$obj->commande_fournisseur_ref; + print $orderstatic->getNomUrl(1); + } + else print ' '; + print '

"; + } + $db->free($resql); +} +else dol_print_error($db); + + +print '
'; + + +llxFooter(); +$db->close(); diff --git a/htdocs/reception/list.php b/htdocs/reception/list.php new file mode 100644 index 00000000000..f05debc8858 --- /dev/null +++ b/htdocs/reception/list.php @@ -0,0 +1,1003 @@ + + * Copyright (C) 2004-2015 Laurent Destailleur + * Copyright (C) 2005-2010 Regis Houssin + * Copyright (C) 2016 Ferran Marcet + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/** + * \file htdocs/reception/list.php + * \ingroup reception + * \brief Page to list all receptions + */ + +require '../main.inc.php'; +require_once DOL_DOCUMENT_ROOT.'/reception/class/reception.class.php'; +require_once DOL_DOCUMENT_ROOT.'/fourn/class/fournisseur.facture.class.php'; +require_once DOL_DOCUMENT_ROOT.'/fourn/class/fournisseur.commande.class.php'; +require_once DOL_DOCUMENT_ROOT.'/fourn/class/fournisseur.product.class.php'; +require_once DOL_DOCUMENT_ROOT.'/core/class/html.formcompany.class.php'; +require_once DOL_DOCUMENT_ROOT.'/core/class/html.formfile.class.php'; +require_once DOL_DOCUMENT_ROOT.'/core/lib/date.lib.php'; +require_once DOL_DOCUMENT_ROOT.'/core/lib/company.lib.php'; + +$langs->load("receptions"); +$langs->load("deliveries"); +$langs->load('companies'); +$langs->load('bills'); + +$socid=GETPOST('socid','int'); +$massaction=GETPOST('massaction','alpha'); +$toselect = GETPOST('toselect', 'array'); + +// Security check +$receptionid = GETPOST('id','int'); +if ($user->societe_id) $socid=$user->societe_id; +$result = restrictedArea($user, 'reception',$receptionid,''); + +$diroutputmassaction=$conf->reception->dir_output . '/temp/massgeneration/'.$user->id; + +$search_ref_rcp = GETPOST("search_ref_rcp"); +$search_ref_liv = GETPOST('search_ref_liv'); +$search_ref_supplier = GETPOST('search_ref_supplier'); +$search_company = GETPOST("search_company"); +$search_town=GETPOST('search_town','alpha'); +$search_zip=GETPOST('search_zip','alpha'); +$search_state=trim(GETPOST("search_state")); +$search_country=GETPOST("search_country",'int'); +$search_type_thirdparty=GETPOST("search_type_thirdparty",'int'); +$search_billed=GETPOST("search_billed",'int'); +$sall = GETPOST('sall', 'alphanohtml'); +$optioncss = GETPOST('optioncss','alpha'); + +$limit = GETPOST('limit','int')?GETPOST('limit','int'):$conf->liste_limit; +$sortfield = GETPOST('sortfield','alpha'); +$sortorder = GETPOST('sortorder','alpha'); +$page = GETPOST('page','int'); +if (! $sortfield) $sortfield="e.ref"; +if (! $sortorder) $sortorder="DESC"; +if (empty($page) || $page == -1) { $page = 0; } // If $page is not defined, or '' or -1 +$offset = $limit * $page; +$pageprev = $page - 1; +$pagenext = $page + 1; + +// Initialize technical object to manage hooks of page. Note that conf->hooks_modules contains array of hook context +$contextpage='receptionlist'; + +$viewstatut=GETPOST('viewstatut'); + +// Initialize technical object to manage hooks of page. Note that conf->hooks_modules contains array of hook context +$hookmanager->initHooks(array('receptionlist')); +$extrafields = new ExtraFields($db); + +// fetch optionals attributes and labels +$extralabels = $extrafields->fetch_name_optionals_label('reception'); +$search_array_options=$extrafields->getOptionalsFromPost($extralabels,'','search_'); + +// List of fields to search into when doing a "search in all" +$fieldstosearchall = array( + 'e.ref'=>"Ref", + 's.nom'=>"ThirdParty", + 'e.note_public'=>'NotePublic', +); +if (empty($user->socid)) $fieldstosearchall["e.note_private"]="NotePrivate"; + +$checkedtypetiers=0; +$arrayfields=array( + 'e.ref'=>array('label'=>$langs->trans("Ref"), 'checked'=>1), + 'e.ref_supplier'=>array('label'=>$langs->trans("RefSupplier"), 'checked'=>1), + 's.nom'=>array('label'=>$langs->trans("ThirdParty"), 'checked'=>1), + 's.town'=>array('label'=>$langs->trans("Town"), 'checked'=>1), + 's.zip'=>array('label'=>$langs->trans("Zip"), 'checked'=>1), + 'state.nom'=>array('label'=>$langs->trans("StateShort"), 'checked'=>0), + 'country.code_iso'=>array('label'=>$langs->trans("Country"), 'checked'=>0), + 'typent.code'=>array('label'=>$langs->trans("ThirdPartyType"), 'checked'=>$checkedtypetiers), + 'e.date_delivery'=>array('label'=>$langs->trans("DateDeliveryPlanned"), 'checked'=>1), + 'e.datec'=>array('label'=>$langs->trans("DateCreation"), 'checked'=>0, 'position'=>500), + 'e.tms'=>array('label'=>$langs->trans("DateModificationShort"), 'checked'=>0, 'position'=>500), + 'e.fk_statut'=>array('label'=>$langs->trans("Status"), 'checked'=>1, 'position'=>1000), + 'e.billed'=>array('label'=>$langs->trans("Billed"), 'checked'=>1, 'position'=>1000, 'enabled'=>(!empty($conf->global->WORKFLOW_BILL_ON_RECEPTION))) +); + +// Extra fields +if (is_array($extrafields->attribute_label) && count($extrafields->attribute_label)) +{ + foreach($extrafields->attribute_label as $key => $val) + { + $arrayfields["ef.".$key]=array('label'=>$extrafields->attribute_label[$key], 'checked'=>$extrafields->attribute_list[$key], 'position'=>$extrafields->attribute_pos[$key], 'enabled'=>$extrafields->attribute_perms[$key]); + } +} + + +/* + * Actions + */ + +if (GETPOST('cancel')) { $action='list'; $massaction=''; } +if (! GETPOST('confirmmassaction') && $massaction != 'confirm_createbills') { $massaction=''; } + +$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'); + +include DOL_DOCUMENT_ROOT.'/core/actions_changeselectedfields.inc.php'; + +// Purge search criteria +if (GETPOST('button_removefilter_x','alpha') || GETPOST('button_removefilter.x','alpha') || GETPOST('button_removefilter','alpha')) // All tests are required to be compatible with all browsers +{ + $search_ref_supplier=''; + $search_ref_rcp=''; + $search_ref_liv=''; + $search_company=''; + $search_town=''; + $search_zip=""; + $search_state=""; + $search_type=''; + $search_country=''; + $search_type_thirdparty=''; + $search_billed=''; + $viewstatut=''; + $search_array_options=array(); +} + +if (empty($reshook)) +{ + if ($massaction == 'confirm_createbills') { + + $receptions = GETPOST('toselect','array'); + $createbills_onebythird = GETPOST('createbills_onebythird', 'int'); + $validate_invoices = GETPOST('valdate_invoices', 'int'); + + $TFact = array(); + $TFactThird = array(); + + $nb_bills_created = 0; + + $db->begin(); + $errors =array(); + foreach($receptions as $id_reception) + { + $rcp = new Reception($db); + // On ne facture que les réceptions validées + if ($rcp->fetch($id_reception) <= 0 || $rcp->statut != 1){ + $errors[]=$langs->trans('StatusMustBeValidate',$rcp->ref); + $error++; + continue; + } + + $object = new FactureFournisseur($db); + if (!empty($createbills_onebythird) && !empty($TFactThird[$rcp->socid])){ + $object = $TFactThird[$rcp->socid]; // If option "one bill per third" is set, we use already created reception. + if(empty($object->rowid)&&$object->id != null)$object->rowid = $object->id; + if(!empty($object->rowid))$object->fetchObjectLinked(); + $rcp->fetchObjectLinked(); + + if (count($rcp->linkedObjectsIds['order_supplier']) > 0) + { + foreach ($rcp->linkedObjectsIds['order_supplier'] as $key => $value) + { + if(empty($object->linkedObjectsIds['order_supplier']) || !in_array($value, $object->linkedObjectsIds['order_supplier']))//Dont try to link if already linked + $object->add_object_linked('order_supplier', $value); // add supplier order linked object + } + } + + } + else { + + + + $object->socid = $rcp->socid; + $object->type = FactureFournisseur::TYPE_STANDARD; + $object->cond_reglement_id = $rcp->thirdparty->cond_reglement_supplier_id; + $object->mode_reglement_id = $rcp->thirdparty->mode_reglement_supplier_id; + $object->fk_account = !empty($rcp->thirdparty->fk_account)?$rcp->thirdparty->fk_account:0; + $object->remise_percent = !empty($rcp->thirdparty->remise_percent)?$rcp->thirdparty->remise_percent:0; + $object->remise_absolue = !empty($rcp->thirdparty->remise_absolue)?$rcp->thirdparty->remise_absolue:0; + + $object->fk_project = $rcp->fk_project; + $object->ref_supplier = $rcp->ref_supplier; + + $datefacture = dol_mktime(12, 0, 0, GETPOST('remonth'),GETPOST('reday'), GETPOST('reyear')); + if (empty($datefacture)) + { + $datefacture = dol_mktime(date("h"), date("M"), 0, date("m"), date("d"), date("Y")); + } + + $object->date = $datefacture; + $object->origin = 'reception'; + $object->origin_id = $id_reception; + + $rcp->fetchObjectLinked(); + if (count($rcp->linkedObjectsIds['order_supplier']) > 0) + { + foreach ($rcp->linkedObjectsIds['order_supplier'] as $key => $value) + { + $object->linked_objects['order_supplier'] = $value; + } + } + + $res = $object->create($user); + //var_dump($object->error);exit; + if($res > 0){ + $nb_bills_created++; + $object->id = $res; + }else { + $errors[]=$rcp->ref.' : '.$langs->trans($object->error); + $error++; + } + } + + if ($object->id > 0) + { + if(!empty($createbills_onebythird) && !empty($TFactThird[$rcp->socid])){ //cause function create already add object linked for facturefournisseur + $res = $object->add_object_linked($object->origin,$id_reception); + + if ($res==0) + { + $errors[]=$object->error; + $error++; + } + } + + if (! $error) + { + $lines = $rcp->lines; + if (empty($lines) && method_exists($rcp, 'fetch_lines')) + { + $rcp->fetch_lines(); + $lines = $rcp->lines; + } + + $fk_parent_line=0; + $num=count($lines); + + for ($i=0;$i<$num;$i++) + { + $desc=($lines[$i]->desc?$lines[$i]->desc:$lines[$i]->libelle); + if ($lines[$i]->subprice < 0) + { + // Negative line, we create a discount line + $discount = new DiscountAbsolute($db); + $discount->fk_soc=$object->socid; + $discount->amount_ht=abs($lines[$i]->total_ht); + $discount->amount_tva=abs($lines[$i]->total_tva); + $discount->amount_ttc=abs($lines[$i]->total_ttc); + $discount->tva_tx=$lines[$i]->tva_tx; + $discount->fk_user=$user->id; + $discount->description=$desc; + $discountid=$discount->create($user); + if ($discountid > 0) + { + $result=$object->insert_discount($discountid); + //$result=$discount->link_to_invoice($lineid,$id); + } + else + { + setEventMessages($discount->error, $discount->errors, 'errors'); + $error++; + break; + } + } + else + { + // Positive line + $product_type=($lines[$i]->product_type?$lines[$i]->product_type:0); + // Date start + $date_start=false; + if ($lines[$i]->date_debut_prevue) $date_start=$lines[$i]->date_debut_prevue; + if ($lines[$i]->date_debut_reel) $date_start=$lines[$i]->date_debut_reel; + if ($lines[$i]->date_start) $date_start=$lines[$i]->date_start; + //Date end + $date_end=false; + if ($lines[$i]->date_fin_prevue) $date_end=$lines[$i]->date_fin_prevue; + if ($lines[$i]->date_fin_reel) $date_end=$lines[$i]->date_fin_reel; + if ($lines[$i]->date_end) $date_end=$lines[$i]->date_end; + // 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; + } + $result = $object->addline( + $desc, + $lines[$i]->subprice, + $lines[$i]->tva_tx, + $lines[$i]->localtax1_tx, + $lines[$i]->localtax2_tx, + $lines[$i]->qty, + $lines[$i]->fk_product, + $lines[$i]->remise_percent, + $date_start, + $date_end, + 0, + $lines[$i]->info_bits, + 'HT', + $product_type, + $i, + false, + 0, + null, + $lines[$i]->rowid, + 0, + $lines[$i]->ref_supplier + + ); + + $rcp->add_object_linked('facture_fourn_det',$result); + + 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; + } + } + } + } + } + + //$rcp->classifyBilled($user); // Disabled. This behavior must be set or not using the workflow module. + + if(!empty($createbills_onebythird) && empty($TFactThird[$rcp->socid])) $TFactThird[$rcp->socid] = $object; + else $TFact[$object->id] = $object; + } + + // Build doc with all invoices + $TAllFact = empty($createbills_onebythird) ? $TFact : $TFactThird; + $toselect = array(); + + if (! $error && $validate_invoices) + { + $massaction = $action = 'builddoc'; + foreach($TAllFact as &$object) + { + $result = $object->validate($user); + if ($result <= 0) + { + $error++; + setEventMessages($object->error, $object->errors, 'errors'); + break; + } + + $id = $object->id; // For builddoc action + + // Fac builddoc + $donotredirect = 1; + $upload_dir = $conf->fournisseur->facture->dir_output; + $permissioncreate=$user->rights->fournisseur->facture->creer; + include DOL_DOCUMENT_ROOT.'/core/actions_builddoc.inc.php'; + } + + $massaction = $action = 'confirm_createbills'; + } + + if (! $error) + { + $db->commit(); + setEventMessage($langs->trans('BillCreated', $nb_bills_created)); + } + else + { + + $db->rollback(); + $action='create'; + $_GET["origin"]=$_POST["origin"]; + $_GET["originid"]=$_POST["originid"]; + setEventMessages($object->error, $errors, 'errors'); + $error++; + } + } + + +} + + + + +/* + * View + */ + +$form=new Form($db); +$companystatic=new Societe($db); +$reception=new Reception($db); +$formcompany=new FormCompany($db); +$formfile = new FormFile($db); + + +$helpurl='EN:Module_Receptions|FR:Module_Receptions|ES:Módulo_Receptiones'; +llxHeader('',$langs->trans('ListOfReceptions'),$helpurl); + +$sql = "SELECT e.rowid, e.ref, e.ref_supplier, e.date_reception as date_reception, e.date_delivery as date_livraison, l.date_delivery as date_reception, e.fk_statut, e.billed,"; +$sql.= ' s.rowid as socid, s.nom as name, s.town, s.zip, s.fk_pays, s.client, s.code_client, '; +$sql.= " typent.code as typent_code,"; +$sql.= " state.code_departement as state_code, state.nom as state_name,"; +$sql.= ' e.date_creation as date_creation, e.tms as date_update'; +// Add fields from extrafields +foreach ($extrafields->attribute_label as $key => $val) $sql.=($extrafields->attribute_type[$key] != 'separate' ? ",ef.".$key.' as options_'.$key : ''); +// Add fields from hooks +$parameters=array(); +$reshook=$hookmanager->executeHooks('printFieldListSelect',$parameters); // Note that $action and $object may have been modified by hook +$sql.=$hookmanager->resPrint; +$sql.= " FROM ".MAIN_DB_PREFIX."reception as e"; +if (is_array($extrafields->attribute_label) && count($extrafields->attribute_label)) $sql.= " LEFT JOIN ".MAIN_DB_PREFIX."reception_extrafields as ef on (e.rowid = ef.fk_object)"; +$sql.= " LEFT JOIN ".MAIN_DB_PREFIX."societe as s ON s.rowid = e.fk_soc"; +$sql.= " LEFT JOIN ".MAIN_DB_PREFIX."c_country as country on (country.rowid = s.fk_pays)"; +$sql.= " LEFT JOIN ".MAIN_DB_PREFIX."c_typent as typent on (typent.id = s.fk_typent)"; +$sql.= " LEFT JOIN ".MAIN_DB_PREFIX."c_departements as state on (state.rowid = s.fk_departement)"; +$sql.= " LEFT JOIN ".MAIN_DB_PREFIX."element_element as ee ON e.rowid = ee.fk_source AND ee.sourcetype = 'reception' AND ee.targettype = 'delivery'"; +$sql.= " LEFT JOIN ".MAIN_DB_PREFIX."livraison as l ON l.rowid = ee.fk_target"; +if (!$user->rights->societe->client->voir && !$socid) // Internal user with no permission to see all +{ + $sql.= ", ".MAIN_DB_PREFIX."societe_commerciaux as sc"; +} +$sql.= " WHERE e.entity IN (".getEntity('reception').")"; +if (!$user->rights->societe->client->voir && !$socid) // Internal user with no permission to see all +{ + $sql.= " AND e.fk_soc = sc.fk_soc"; + $sql.= " AND sc.fk_user = " .$user->id; +} +if ($socid) +{ + $sql.= " AND e.fk_soc = ".$socid; +} +if ($viewstatut <> '' && $viewstatut >= 0) { + $sql.= " AND e.fk_statut = ".$viewstatut; +} +if ($search_billed != '' && $search_billed >= 0) $sql.=' AND e.billed = '.$search_billed; +if ($search_town) $sql.= natural_search('s.town', $search_town); +if ($search_zip) $sql.= natural_search("s.zip",$search_zip); +if ($search_state) $sql.= natural_search("state.nom",$search_state); +if ($search_country) $sql .= " AND s.fk_pays IN (".$search_country.')'; +if ($search_type_thirdparty) $sql .= " AND s.fk_typent IN (".$search_type_thirdparty.')'; +if ($search_ref_rcp) $sql .= natural_search('e.ref', $search_ref_rcp); +if ($search_ref_liv) $sql .= natural_search('l.ref', $search_ref_liv); +if ($search_company) $sql .= natural_search('s.nom', $search_company); +if ($search_ref_supplier) $sql .= natural_search('e.ref_supplier', $search_ref_supplier); +if ($sall) $sql .= natural_search(array_keys($fieldstosearchall), $sall); + +// Add where from extra fields +foreach ($search_array_options as $key => $val) +{ + $crit=$val; + $tmpkey=preg_replace('/search_options_/','',$key); + $typ=$extrafields->attribute_type[$tmpkey]; + $mode=0; + if (in_array($typ, array('int','double','real'))) $mode=1; // Search on a numeric + if (in_array($typ, array('sellist')) && $crit != '0' && $crit != '-1') $mode=2; // Search on a foreign key int + if ($crit != '' && (! in_array($typ, array('select','sellist')) || $crit != '0')) + { + $sql .= natural_search('ef.'.$tmpkey, $crit, $mode); + } +} +// Add where from hooks +$parameters=array(); +$reshook=$hookmanager->executeHooks('printFieldListWhere',$parameters); // Note that $action and $object may have been modified by hook +$sql.=$hookmanager->resPrint; + +$nbtotalofrecords = ''; +if (empty($conf->global->MAIN_DISABLE_FULL_SCANLIST)) +{ + $result = $db->query($sql); + $nbtotalofrecords = $db->num_rows($result); +} + +$sql.= $db->order($sortfield,$sortorder); +$sql.= $db->plimit($limit + 1,$offset); + +//print $sql; +$resql=$db->query($sql); +if ($resql) +{ + $num = $db->num_rows($resql); + + $reception = new Reception($db); + + $arrayofselected=is_array($toselect)?$toselect:array(); + + $param=''; + if (! empty($contextpage) && $contextpage != $_SERVER["PHP_SELF"]) $param.='&contextpage='.$contextpage; + if ($limit > 0 && $limit != $conf->liste_limit) $param.='&limit='.$limit; + if ($sall) $param.= "&sall=".$sall; + if ($search_ref_rcp) $param.= "&search_ref_rcp=".$search_ref_rcp; + if ($search_ref_liv) $param.= "&search_ref_liv=".$search_ref_liv; + if ($search_company) $param.= "&search_company=".$search_company; + if ($optioncss != '') $param.='&optioncss='.$optioncss; + if ($search_billed != '' && $search_billed >= 0)$param.= "&search_billed=".$search_billed; + if ($search_town) $param.= "&search_town=".$search_town; + if ($search_zip) $param.= "&search_zip=".$search_zip; + if ($search_state) $param.= "&search_state=".$search_state; + if ($viewstatut) $param.= "&viewstatut=".$viewstatut; + if ($search_country) $param.= "&search_country=".$search_country; + if ($search_type_thirdparty) $param.= "&search_type_thirdparty=".$search_type_thirdparty; + if ($search_ref_supplier) $param.= "&search_ref_supplier=".$search_ref_supplier; + // Add $param from extra fields + foreach ($search_array_options as $key => $val) + { + $crit=$val; + $tmpkey=preg_replace('/search_options_/','',$key); + if ($val != '') $param.='&search_options_'.$tmpkey.'='.urlencode($val); + } + + + $arrayofmassactions = array( +// 'presend'=>$langs->trans("SendByMail"), +); + + if($user->rights->fournisseur->facture->creer)$arrayofmassactions['createbills']=$langs->trans("CreateInvoiceForThisSupplier"); + if($massaction == 'createbills') $arrayofmassactions=array(); + $massactionbutton=$form->selectMassAction('', $arrayofmassactions); + //$massactionbutton=$form->selectMassAction('', $massaction == 'presend' ? array() : array('presend'=>$langs->trans("SendByMail"), 'builddoc'=>$langs->trans("PDFMerge"))); + + $i = 0; + print '
'."\n"; + if ($optioncss != '') print ''; + print ''; + print ''; + print ''; + print ''; + print ''; + print ''; + + print_barre_liste($langs->trans('ListOfReceptions'), $page, $_SERVER["PHP_SELF"],$param,$sortfield,$sortorder,$massactionbutton,$num, $nbtotalofrecords, '', 0, '', '', $limit); + + + if ($massaction == 'createbills') + { + //var_dump($_REQUEST); + print ''; + + print ''; + print ''; + print ''; + print ''; + print ''; + print ''; + print ''; + print ''; + print ''; + print ''; + print ''; + print ''; + print ''; + print '
'; + print $langs->trans('DateInvoice'); + print ''; + print $form->select_date('', '', '', '', '', '', 1, 1); + print '
'; + print $langs->trans('CreateOneBillByThird'); + print ''; + print $form->selectyesno('createbills_onebythird', '', 1); + print '
'; + print $langs->trans('ValidateInvoices'); + print ''; + if (! empty($conf->stock->enabled) && ! empty($conf->global->STOCK_CALCULATE_ON_BILL)) + { + print $form->selectyesno('valdate_invoices', 0, 1, 1); + print ' ('.$langs->trans("AutoValidationNotPossibleWhenStockIsDecreasedOnInvoiceValidation").')'; + } + else + { + print $form->selectyesno('valdate_invoices', 0, 1); + } + print '
'; + + print '
'; + print '
'; + print ' '; + print ''; + print '
'; + print '
'; + } + + if ($sall) + { + foreach($fieldstosearchall as $key => $val) $fieldstosearchall[$key]=$langs->trans($val); + print $langs->trans("FilterOnInto", $sall) . join(', ',$fieldstosearchall); + } + + $moreforfilter=''; + if (! empty($moreforfilter)) + { + print '
'; + print $moreforfilter; + $parameters=array('type'=>$type); + $reshook=$hookmanager->executeHooks('printFieldPreListTitle',$parameters); // Note that $action and $object may have been modified by hook + print $hookmanager->resPrint; + print '
'; + } + + $varpage=empty($contextpage)?$_SERVER["PHP_SELF"]:$contextpage; + $selectedfields=$form->multiSelectArrayWithCheckbox('selectedfields', $arrayfields, $varpage); // This also change content of $arrayfields + $selectedfields.=$form->showCheckAddButtons('checkforselect', 1); + + + print '
'; + print ''."\n"; + + // Lignes des champs de filtre + print ''; + // Ref + if (! empty($arrayfields['e.ref']['checked'])) + { + print ''; + } + // Ref customer + if (! empty($arrayfields['e.ref_supplier']['checked'])) + { + print ''; + } + // Thirdparty + if (! empty($arrayfields['s.nom']['checked'])) + { + print ''; + } + // Town + if (! empty($arrayfields['s.town']['checked'])) print ''; + // Zip + if (! empty($arrayfields['s.zip']['checked'])) print ''; + // State + if (! empty($arrayfields['state.nom']['checked'])) + { + print ''; + } + // Country + if (! empty($arrayfields['country.code_iso']['checked'])) + { + print ''; + } + // Company type + if (! empty($arrayfields['typent.code']['checked'])) + { + print ''; + } + // Date delivery planned + if (! empty($arrayfields['e.date_delivery']['checked'])) + { + print ''; + } + if (! empty($arrayfields['l.ref']['checked'])) + { + // Delivery ref + print ''; + } + // Extra fields + if (is_array($extrafields->attribute_label) && count($extrafields->attribute_label)) + { + foreach($extrafields->attribute_label as $key => $val) + { + if (! empty($arrayfields["ef.".$key]['checked'])) + { + $align=$extrafields->getAlignFlag($key); + $typeofextrafield=$extrafields->attribute_type[$key]; + print ''; + } + } + } + // Fields from hook + $parameters=array('arrayfields'=>$arrayfields); + $reshook=$hookmanager->executeHooks('printFieldListOption',$parameters); // Note that $action and $object may have been modified by hook + print $hookmanager->resPrint; + // Date creation + if (! empty($arrayfields['e.datec']['checked'])) + { + print ''; + } + // Date modification + if (! empty($arrayfields['e.tms']['checked'])) + { + print ''; + } + // Status + if (! empty($arrayfields['e.fk_statut']['checked'])) + { + print ''; + } + // Status billed + if (! empty($arrayfields['e.billed']['checked'])) + { + print ''; + } + // Action column + print ''; + print "\n"; + + print ''; + if (! empty($arrayfields['e.ref']['checked'])) print_liste_field_titre($arrayfields['e.ref']['label'], $_SERVER["PHP_SELF"],"e.ref","",$param,'',$sortfield,$sortorder); + if (! empty($arrayfields['e.ref_supplier']['checked'])) print_liste_field_titre($arrayfields['e.ref_supplier']['label'], $_SERVER["PHP_SELF"],"e.ref_supplier","",$param,'',$sortfield,$sortorder); + if (! empty($arrayfields['s.nom']['checked'])) print_liste_field_titre($arrayfields['s.nom']['label'], $_SERVER["PHP_SELF"],"s.nom", "", $param,'align="left"',$sortfield,$sortorder); + if (! empty($arrayfields['s.town']['checked'])) print_liste_field_titre($arrayfields['s.town']['label'],$_SERVER["PHP_SELF"],'s.town','',$param,'',$sortfield,$sortorder); + if (! empty($arrayfields['s.zip']['checked'])) print_liste_field_titre($arrayfields['s.zip']['label'],$_SERVER["PHP_SELF"],'s.zip','',$param,'',$sortfield,$sortorder); + if (! empty($arrayfields['state.nom']['checked'])) print_liste_field_titre($arrayfields['state.nom']['label'],$_SERVER["PHP_SELF"],"state.nom","",$param,'',$sortfield,$sortorder); + if (! empty($arrayfields['country.code_iso']['checked'])) print_liste_field_titre($arrayfields['country.code_iso']['label'],$_SERVER["PHP_SELF"],"country.code_iso","",$param,'align="center"',$sortfield,$sortorder); + if (! empty($arrayfields['typent.code']['checked'])) print_liste_field_titre($arrayfields['typent.code']['label'],$_SERVER["PHP_SELF"],"typent.code","",$param,'align="center"',$sortfield,$sortorder); + if (! empty($arrayfields['e.date_delivery']['checked'])) print_liste_field_titre($arrayfields['e.date_delivery']['label'], $_SERVER["PHP_SELF"],"e.date_delivery","",$param, 'align="center"',$sortfield,$sortorder); + if (! empty($arrayfields['l.ref']['checked'])) print_liste_field_titre($arrayfields['l.ref']['label'], $_SERVER["PHP_SELF"],"l.ref","",$param, '',$sortfield,$sortorder); + if (! empty($arrayfields['l.date_delivery']['checked'])) print_liste_field_titre($arrayfields['l.date_delivery']['label'], $_SERVER["PHP_SELF"],"l.date_delivery","",$param, 'align="center"',$sortfield,$sortorder); + // Extra fields + if (is_array($extrafields->attribute_label) && count($extrafields->attribute_label)) + { + foreach($extrafields->attribute_label as $key => $val) + { + if (! empty($arrayfields["ef.".$key]['checked'])) + { + $align=$extrafields->getAlignFlag($key); + $sortonfield = "ef.".$key; + if (! empty($extrafields->attribute_computed[$key])) $sortonfield=''; + print_liste_field_titre($extralabels[$key],$_SERVER["PHP_SELF"],$sortonfield,"",$param,($align?'align="'.$align.'"':''),$sortfield,$sortorder); + } + } + } + // Hook fields + $parameters=array('arrayfields'=>$arrayfields); + $reshook=$hookmanager->executeHooks('printFieldListTitle',$parameters); // Note that $action and $object may have been modified by hook + print $hookmanager->resPrint; + if (! empty($arrayfields['e.datec']['checked'])) print_liste_field_titre($arrayfields['e.datec']['label'],$_SERVER["PHP_SELF"],"e.date_creation","",$param,'align="center" class="nowrap"',$sortfield,$sortorder); + if (! empty($arrayfields['e.tms']['checked'])) print_liste_field_titre($arrayfields['e.tms']['label'],$_SERVER["PHP_SELF"],"e.tms","",$param,'align="center" class="nowrap"',$sortfield,$sortorder); + if (! empty($arrayfields['e.fk_statut']['checked'])) print_liste_field_titre($arrayfields['e.fk_statut']['label'],$_SERVER["PHP_SELF"],"e.fk_statut","",$param,'align="right"',$sortfield,$sortorder); + if (! empty($arrayfields['e.billed']['checked'])) print_liste_field_titre($arrayfields['e.billed']['label'],$_SERVER["PHP_SELF"],"e.billed","",$param,'align="center"',$sortfield,$sortorder); + print_liste_field_titre($selectedfields, $_SERVER["PHP_SELF"],"",'','','align="center"',$sortfield,$sortorder,'maxwidthsearch '); + print "\n"; + + $i=0; + $var=true; + $totalarray=array(); + while ($i < min($num,$limit)) + { + $obj = $db->fetch_object($resql); + + $reception->id=$obj->rowid; + $reception->ref=$obj->ref; + + $companystatic->id=$obj->socid; + $companystatic->ref=$obj->name; + $companystatic->name=$obj->name; + + + print ''; + + // Ref + if (! empty($arrayfields['e.ref']['checked'])) + { + print "\n"; + + if (! $i) $totalarray['nbfield']++; + } + + // Ref customer + if (! empty($arrayfields['e.ref_supplier']['checked'])) + { + print "\n"; + if (! $i) $totalarray['nbfield']++; + } + + // Third party + if (! empty($arrayfields['s.nom']['checked'])) + { + print ''; + if (! $i) $totalarray['nbfield']++; + } + // Town + if (! empty($arrayfields['s.town']['checked'])) + { + print ''; + if (! $i) $totalarray['nbfield']++; + } + // Zip + if (! empty($arrayfields['s.zip']['checked'])) + { + print ''; + if (! $i) $totalarray['nbfield']++; + } + // State + if (! empty($arrayfields['state.nom']['checked'])) + { + print "\n"; + if (! $i) $totalarray['nbfield']++; + } + // Country + if (! empty($arrayfields['country.code_iso']['checked'])) + { + print ''; + if (! $i) $totalarray['nbfield']++; + } + // Type ent + if (! empty($arrayfields['typent.code']['checked'])) + { + print ''; + if (! $i) $totalarray['nbfield']++; + } + + // Date delivery planed + if (! empty($arrayfields['e.date_delivery']['checked'])) + { + print '\n"; + } + + if (! empty($arrayfields['l.ref']['checked']) || ! empty($arrayfields['l.date_delivery']['checked'])) + { + $reception->fetchObjectLinked($reception->id,$reception->element); + $receiving=''; + if (count($reception->linkedObjects['delivery']) > 0) $receiving=reset($reception->linkedObjects['delivery']); + + if (! empty($arrayfields['l.ref']['checked'])) + { + // Ref + print ''; + } + + if (! empty($arrayfields['l.date_delivery']['checked'])) + { + // Date received + print ''."\n"; + } + } + + // Extra fields + if (is_array($extrafields->attribute_label) && count($extrafields->attribute_label)) + { + foreach($extrafields->attribute_label as $key => $val) + { + if (! empty($arrayfields["ef.".$key]['checked'])) + { + print ''; + if (! $i) $totalarray['nbfield']++; + } + } + } + // Fields from hook + $parameters=array('arrayfields'=>$arrayfields, 'obj'=>$obj); + $reshook=$hookmanager->executeHooks('printFieldListValue',$parameters); // Note that $action and $object may have been modified by hook + print $hookmanager->resPrint; + // Date creation + if (! empty($arrayfields['e.datec']['checked'])) + { + print ''; + if (! $i) $totalarray['nbfield']++; + } + // Date modification + if (! empty($arrayfields['e.tms']['checked'])) + { + print ''; + if (! $i) $totalarray['nbfield']++; + } + // Status + if (! empty($arrayfields['e.fk_statut']['checked'])) + { + print ''; + if (! $i) $totalarray['nbfield']++; + } + // Billed + if (! empty($arrayfields['e.billed']['checked'])) + { + print ''; + if (! $i) $totalarray['nbfield']++; + } + + // Action column + print ''; + if (! $i) $totalarray['nbfield']++; + + print "\n"; + + $i++; + } + + print "
'; + print ''; + print ''; + print ''; + print ''; + print ''; + print ''; + print ''; + print ''; + print $form->select_country($search_country,'search_country','',0,'maxwidth100'); + print ''; + print $form->selectarray("search_type_thirdparty", $formcompany->typent_array(0), $search_type_thirdparty, 0, 0, 0, '', 0, 0, 0, (empty($conf->global->SOCIETE_SORT_ON_TYPEENT)?'ASC':$conf->global->SOCIETE_SORT_ON_TYPEENT)); + print ' '; + print ''; + } + if (! empty($arrayfields['l.date_delivery']['checked'])) + { + // Date received + print ' '; + if (in_array($typeofextrafield, array('varchar', 'int', 'double', 'select'))) + { + $crit=$val; + $tmpkey=preg_replace('/search_options_/','',$key); + $searchclass=''; + if (in_array($typeofextrafield, array('varchar', 'select'))) $searchclass='searchstring'; + if (in_array($typeofextrafield, array('int', 'double'))) $searchclass='searchnum'; + print ''; + } + print ''; + print ''; + print ''; + print $form->selectarray('viewstatut', array('0'=>$langs->trans('StatusReceptionDraftShort'),'1'=>$langs->trans('StatusReceptionValidatedShort'),'2'=>$langs->trans('StatusReceptionProcessedShort')),$viewstatut,1); + print ''; + print $form->selectyesno('search_billed', $search_billed, 1, 0, 1); + print ''; + $searchpicto=$form->showFilterAndCheckAddButtons(0); + print $searchpicto; + print '
"; + print $reception->getNomUrl(1); + $filename=dol_sanitizeFileName($reception->ref); + $filedir=$conf->reception->dir_output . '/' . dol_sanitizeFileName($reception->ref); + $urlsource=$_SERVER['PHP_SELF'].'?id='.$reception->rowid; + print $formfile->getDocumentsLink($reception->element, $filename, $filedir); + print ""; + print $obj->ref_supplier; + print "'; + print $companystatic->getNomUrl(1); + print ''; + print $obj->town; + print ''; + print $obj->zip; + print '".$obj->state_name."'; + $tmparray=getCountry($obj->fk_pays,'all'); + print $tmparray['label']; + print ''; + if (count($typenArray)==0) $typenArray = $formcompany->typent_array(1); + print $typenArray[$obj->typent_code]; + print ''; + print dol_print_date($db->jdate($obj->date_livraison),"day"); + /*$now = time(); + if ( ($now - $db->jdate($obj->date_reception)) > $conf->warnings->lim && $obj->statutid == 1 ) + { + }*/ + print "'; + print !empty($receiving) ? $receiving->getNomUrl($db) : ''; + print ''; + print dol_print_date($db->jdate($obj->date_reception),"day"); + print 'getAlignFlag($key); + if ($align) print ' align="'.$align.'"'; + print '>'; + $tmpkey='options_'.$key; + print $extrafields->showOutputField($key, $obj->$tmpkey, '', 1); + print ''; + print dol_print_date($db->jdate($obj->date_creation), 'dayhour'); + print ''; + print dol_print_date($db->jdate($obj->date_update), 'dayhour'); + print ''.$reception->LibStatut($obj->fk_statut,5).''.yn($obj->billed).''; + if ($massactionbutton || $massaction) // If we are in select mode (massactionbutton defined) or if we have already selected and sent an action ($massaction) defined + { + $selected=0; + if (in_array($obj->rowid, $arrayofselected)) $selected=1; + print ''; + } + print '
"; + print "
"; + print '
'; + $db->free($resql); +} +else +{ + dol_print_error($db); +} + +llxFooter(); +$db->close(); diff --git a/htdocs/reception/note.php b/htdocs/reception/note.php new file mode 100644 index 00000000000..8ffa32f1715 --- /dev/null +++ b/htdocs/reception/note.php @@ -0,0 +1,165 @@ + + * Copyright (C) 2004-2008 Laurent Destailleur + * Copyright (C) 2005-2012 Regis Houssin + * Copyright (C) 2013 Florian Henry + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/** + * \file htdocs/reception/nosendingte.php + * \ingroup receptionsending + * \brief Note card reception + */ + +require '../main.inc.php'; +require_once DOL_DOCUMENT_ROOT.'/reception/class/reception.class.php'; +require_once DOL_DOCUMENT_ROOT.'/core/lib/reception.lib.php'; +dol_include_once('/fourn/class/fournisseur.commande.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("receptions"); +$langs->load("companies"); +$langs->load("bills"); +$langs->load('deliveries'); +$langs->load('orders'); +$langs->load('stocks'); +$langs->load('other'); +$langs->load('propal'); + +$id=(GETPOST('id','int')?GETPOST('id','int'):GETPOST('facid','int')); // For backward compatibility +$ref=GETPOST('ref','alpha'); +$action=GETPOST('action','alpha'); + +// Security check +$socid=''; +if ($user->societe_id) $socid=$user->societe_id; +$result=restrictedArea($user, $origin, $origin_id); + +$object = new Reception($db); +if ($id > 0 || ! empty($ref)) +{ + $object->fetch($id, $ref); + $object->fetch_thirdparty(); + + if (!empty($object->origin)) + { + $typeobject = $object->origin; + $origin = $object->origin; + $object->fetch_origin(); + } + + // Linked documents + if ($typeobject == 'commande' && $object->$typeobject->id && ! empty($conf->commande->enabled)) + { + $objectsrc=new Commande($db); + $objectsrc->fetch($object->$typeobject->id); + } + if ($typeobject == 'propal' && $object->$typeobject->id && ! empty($conf->propal->enabled)) + { + $objectsrc=new Propal($db); + $objectsrc->fetch($object->$typeobject->id); + } +} + +$permissionnote=$user->rights->reception->creer; // Used by the include of actions_setnotes.inc.php + + +/* + * Actions + */ + +include DOL_DOCUMENT_ROOT.'/core/actions_setnotes.inc.php'; // Must be include, not includ_once + + +/* + * View + */ + +llxHeader('','Reception'); + +$form = new Form($db); + +if ($id > 0 || ! empty($ref)) +{ + + $head=reception_prepare_head($object); + dol_fiche_head($head, 'note', $langs->trans("Reception"), -1, 'sending'); + + + // Reception card + $linkback = ''.$langs->trans("BackToList").''; + + $morehtmlref='
'; + // Ref customer reception + $morehtmlref.=$form->editfieldkey("RefSupplier", '', $object->ref_supplier, $object, $user->rights->reception->creer, 'string', '', 0, 1); + $morehtmlref.=$form->editfieldval("RefSupplier", '', $object->ref_supplier, $object, $user->rights->reception->creer, 'string', '', null, null, '', 1); + // Thirdparty + $morehtmlref.='
'.$langs->trans('ThirdParty') . ' : ' . $object->thirdparty->getNomUrl(1); + // Project + if (! empty($conf->projet->enabled)) { + $langs->load("projects"); + $morehtmlref .= '
' . $langs->trans('Project') . ' '; + if (0) { // Do not change on reception + if ($action != 'classify') { + $morehtmlref .= '' . img_edit($langs->transnoentitiesnoconv('SetProject')) . ' : '; + } + if ($action == 'classify') { + // $morehtmlref.=$form->form_project($_SERVER['PHP_SELF'] . '?id=' . $object->id, $object->socid, $object->fk_project, 'projectid', 0, 0, 1, 1); + $morehtmlref .= '
'; + $morehtmlref .= ''; + $morehtmlref .= ''; + $morehtmlref .= $formproject->select_projects($object->socid, $object->fk_project, 'projectid', $maxlength, 0, 1, 0, 1, 0, 0, '', 1); + $morehtmlref .= ''; + $morehtmlref .= '
'; + } else { + $morehtmlref .= $form->form_project($_SERVER['PHP_SELF'] . '?id=' . $object->id, $object->socid, $object->fk_project, 'none', 0, 0, 0, 1); + } + } else { + // We don't have project on reception, so we will use the project or source object instead + // TODO Add project on reception + $morehtmlref .= ' : '; + if (! empty($objectsrc->fk_project)) { + $proj = new Project($db); + $proj->fetch($objectsrc->fk_project); + $morehtmlref .= ''; + $morehtmlref .= $proj->ref; + $morehtmlref .= ''; + } else { + $morehtmlref .= ''; + } + } + } + $morehtmlref.='
'; + + $object->picto = 'sending'; + dol_banner_tab($object, 'ref', $linkback, 1, 'ref', 'ref', $morehtmlref); + + + print '
'; + + $cssclass='titlefield'; + include DOL_DOCUMENT_ROOT.'/core/tpl/notes.tpl.php'; + + dol_fiche_end(); +} + + +llxFooter(); + +$db->close(); diff --git a/htdocs/reception/stats/index.php b/htdocs/reception/stats/index.php new file mode 100644 index 00000000000..d47f1bf550b --- /dev/null +++ b/htdocs/reception/stats/index.php @@ -0,0 +1,365 @@ + + * Copyright (C) 2004-2016 Laurent Destailleur + * Copyright (C) 2005-2009 Regis Houssin + * Copyright (C) 2018 Quentin Vial-Gouteyron + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/** + * \file htdocs/reception/stats/index.php + * \ingroup reception + * \brief Page with reception statistics + */ + +require '../../main.inc.php'; +require_once DOL_DOCUMENT_ROOT.'/reception/class/reception.class.php'; +require_once DOL_DOCUMENT_ROOT.'/reception/class/receptionstats.class.php'; +require_once DOL_DOCUMENT_ROOT.'/core/class/dolgraph.class.php'; + +$WIDTH=DolGraph::getDefaultGraphSizeForStats('width'); +$HEIGHT=DolGraph::getDefaultGraphSizeForStats('height'); + +$userid=GETPOST('userid','int'); +$socid=GETPOST('socid','int'); +// Security check +if ($user->societe_id > 0) +{ + $action = ''; + $socid = $user->societe_id; +} + +$nowyear=strftime("%Y", dol_now()); +$year = GETPOST('year')>0?GETPOST('year'):$nowyear; +//$startyear=$year-2; +$startyear=$year-1; +$endyear=$year; + +$langs->load("reception"); +$langs->load("other"); +$langs->load("companies"); + + +/* + * View + */ + +$form=new Form($db); + +llxHeader(); + +print load_fiche_titre($langs->trans("StatisticsOfReceptions"), $mesg); + + +dol_mkdir($dir); + +$stats = new ReceptionStats($db, $socid, $mode, ($userid>0?$userid:0)); + +// Build graphic number of object +$data = $stats->getNbByMonthWithPrevYear($endyear,$startyear); +//var_dump($data);exit; +// $data = array(array('Lib',val1,val2,val3),...) + + +if (!$user->rights->societe->client->voir || $user->societe_id) +{ + $filenamenb = $dir.'/receptionsnbinyear-'.$user->id.'-'.$year.'.png'; + if ($mode == 'customer') $fileurlnb = DOL_URL_ROOT.'/viewimage.php?modulepart=receptionstats&file=receptionsnbinyear-'.$user->id.'-'.$year.'.png'; + if ($mode == 'supplier') $fileurlnb = DOL_URL_ROOT.'/viewimage.php?modulepart=receptionstatssupplier&file=receptionsnbinyear-'.$user->id.'-'.$year.'.png'; +} +else +{ + $filenamenb = $dir.'/receptionsnbinyear-'.$year.'.png'; + if ($mode == 'customer') $fileurlnb = DOL_URL_ROOT.'/viewimage.php?modulepart=receptionstats&file=receptionsnbinyear-'.$year.'.png'; + if ($mode == 'supplier') $fileurlnb = DOL_URL_ROOT.'/viewimage.php?modulepart=receptionstatssupplier&file=receptionsnbinyear-'.$year.'.png'; +} + +$px1 = new DolGraph(); +$mesg = $px1->isGraphKo(); +if (! $mesg) +{ + $px1->SetData($data); + $px1->SetPrecisionY(0); + $i=$startyear;$legend=array(); + while ($i <= $endyear) + { + $legend[]=$i; + $i++; + } + $px1->SetLegend($legend); + $px1->SetMaxValue($px1->GetCeilMaxValue()); + $px1->SetMinValue(min(0,$px1->GetFloorMinValue())); + $px1->SetWidth($WIDTH); + $px1->SetHeight($HEIGHT); + $px1->SetYLabel($langs->trans("NbOfReceptions")); + $px1->SetShading(3); + $px1->SetHorizTickIncrement(1); + $px1->SetPrecisionY(0); + $px1->mode='depth'; + $px1->SetTitle($langs->trans("NumberOfReceptionsByMonth")); + + $px1->draw($filenamenb,$fileurlnb); +} + +// Build graphic amount of object +/* +$data = $stats->getAmountByMonthWithPrevYear($endyear,$startyear); +//var_dump($data); +// $data = array(array('Lib',val1,val2,val3),...) + +if (!$user->rights->societe->client->voir || $user->societe_id) +{ + $filenameamount = $dir.'/receptionsamountinyear-'.$user->id.'-'.$year.'.png'; + if ($mode == 'customer') $fileurlamount = DOL_URL_ROOT.'/viewimage.php?modulepart=receptionstats&file=receptionsamountinyear-'.$user->id.'-'.$year.'.png'; + if ($mode == 'supplier') $fileurlamount = DOL_URL_ROOT.'/viewimage.php?modulepart=receptionstatssupplier&file=receptionsamountinyear-'.$user->id.'-'.$year.'.png'; +} +else +{ + $filenameamount = $dir.'/receptionsamountinyear-'.$year.'.png'; + if ($mode == 'customer') $fileurlamount = DOL_URL_ROOT.'/viewimage.php?modulepart=receptionstats&file=receptionsamountinyear-'.$year.'.png'; + if ($mode == 'supplier') $fileurlamount = DOL_URL_ROOT.'/viewimage.php?modulepart=receptionstatssupplier&file=receptionsamountinyear-'.$year.'.png'; +} + +$px2 = new DolGraph(); +$mesg = $px2->isGraphKo(); +if (! $mesg) +{ + $px2->SetData($data); + $i=$startyear;$legend=array(); + while ($i <= $endyear) + { + $legend[]=$i; + $i++; + } + $px2->SetLegend($legend); + $px2->SetMaxValue($px2->GetCeilMaxValue()); + $px2->SetMinValue(min(0,$px2->GetFloorMinValue())); + $px2->SetWidth($WIDTH); + $px2->SetHeight($HEIGHT); + $px2->SetYLabel($langs->trans("AmountOfReceptions")); + $px2->SetShading(3); + $px2->SetHorizTickIncrement(1); + $px2->SetPrecisionY(0); + $px2->mode='depth'; + $px2->SetTitle($langs->trans("AmountOfReceptionsByMonthHT")); + + $px2->draw($filenameamount,$fileurlamount); +} +*/ + +/* +$data = $stats->getAverageByMonthWithPrevYear($endyear, $startyear); + +if (!$user->rights->societe->client->voir || $user->societe_id) +{ + $filename_avg = $dir.'/receptionsaverage-'.$user->id.'-'.$year.'.png'; + if ($mode == 'customer') $fileurl_avg = DOL_URL_ROOT.'/viewimage.php?modulepart=receptionstats&file=receptionsaverage-'.$user->id.'-'.$year.'.png'; + if ($mode == 'supplier') $fileurl_avg = DOL_URL_ROOT.'/viewimage.php?modulepart=receptionstatssupplier&file=receptionsaverage-'.$user->id.'-'.$year.'.png'; +} +else +{ + $filename_avg = $dir.'/receptionsaverage-'.$year.'.png'; + if ($mode == 'customer') $fileurl_avg = DOL_URL_ROOT.'/viewimage.php?modulepart=receptionstats&file=receptionsaverage-'.$year.'.png'; + if ($mode == 'supplier') $fileurl_avg = DOL_URL_ROOT.'/viewimage.php?modulepart=receptionstatssupplier&file=receptionsaverage-'.$year.'.png'; +} + +$px3 = new DolGraph(); +$mesg = $px3->isGraphKo(); +if (! $mesg) +{ + $px3->SetData($data); + $i=$startyear;$legend=array(); + while ($i <= $endyear) + { + $legend[]=$i; + $i++; + } + $px3->SetLegend($legend); + $px3->SetYLabel($langs->trans("AmountAverage")); + $px3->SetMaxValue($px3->GetCeilMaxValue()); + $px3->SetMinValue($px3->GetFloorMinValue()); + $px3->SetWidth($WIDTH); + $px3->SetHeight($HEIGHT); + $px3->SetShading(3); + $px3->SetHorizTickIncrement(1); + $px3->SetPrecisionY(0); + $px3->mode='depth'; + $px3->SetTitle($langs->trans("AmountAverage")); + + $px3->draw($filename_avg,$fileurl_avg); +} +*/ + + +// Show array +$data = $stats->getAllByYear(); +$arrayyears=array(); +foreach($data as $val) { + if (! empty($val['year'])) { + $arrayyears[$val['year']]=$val['year']; + } +} +if (! count($arrayyears)) $arrayyears[$nowyear]=$nowyear; + +$h=0; +$head = array(); +$head[$h][0] = DOL_URL_ROOT . '/commande/stats/index.php?mode='.$mode; +$head[$h][1] = $langs->trans("ByMonthYear"); +$head[$h][2] = 'byyear'; +$h++; + +$type='reception_stats'; + +complete_head_from_modules($conf,$langs,null,$head,$h,$type); + +dol_fiche_head($head, 'byyear', $langs->trans("Statistics"), -1); + + +print '
'; + + +//if (empty($socid)) +//{ + // Show filter box + print '
'; + print ''; + + print ''; + print ''; + // Company + print ''; + // User + print ''; + // Year + print ''; + print ''; + print '
'.$langs->trans("Filter").'
'.$langs->trans("ThirdParty").''; + if ($mode == 'customer') $filter='s.client in (1,2,3)'; + if ($mode == 'supplier') $filter='s.fournisseur = 1'; + print $form->select_company($socid,'socid',$filter,1,0,0,array(),0,'','style="width: 95%"'); + print '
'.$langs->trans("CreatedBy").''; + print $form->select_dolusers($userid, 'userid', 1, '', 0, '', '', 0, 0, 0, '', 0, '', 'maxwidth300'); + print '
'.$langs->trans("Year").''; + if (! in_array($year,$arrayyears)) $arrayyears[$year]=$year; + if (! in_array($nowyear,$arrayyears)) $arrayyears[$nowyear]=$nowyear; + arsort($arrayyears); + print $form->selectarray('year',$arrayyears,$year,0); + print '
'; + print '
'; + print '

'; +//} + +print ''; +print ''; +print ''; +print ''; +/*print ''; +print '';*/ +print ''; + +$oldyear=0; +foreach ($data as $val) +{ + $year = $val['year']; + while (! empty($year) && $oldyear > $year+1) + { // If we have empty year + $oldyear--; + + + print ''; + print ''; + + print ''; + /*print ''; + print '';*/ + print ''; + } + + print ''; + print ''; + print ''; + /*print ''; + print '';*/ + print ''; + $oldyear=$year; +} + +print '
'.$langs->trans("Year").''.$langs->trans("NbOfReceptions").''.$langs->trans("AmountTotal").''.$langs->trans("AmountAverage").'
'.$oldyear.'000
'; + if ($year) print ''.$year.''; + else print $langs->trans("ValidationDateNotDefinedEvenIfReceptionValidated"); + print ''.$val['nb'].''.price(price2num($val['total'],'MT'),1).''.price(price2num($val['avg'],'MT'),1).'
'; + + +print '
'; + + +// Show graphs +print '
'; +if ($mesg) { print $mesg; } +else { + print $px1->show(); + print "
\n"; + /*print $px2->show(); + print "
\n"; + print $px3->show();*/ +} +print '
'; + + +print '
'; +print '
'; + +dol_fiche_end(); + + + +// TODO USe code similar to commande/stats/index.php instead of this one. +/* +print ''; +print ''; +print ''; + +$sql = "SELECT count(*) as nb, date_format(date_reception,'%Y') as dm"; +$sql.= " FROM ".MAIN_DB_PREFIX."reception"; +$sql.= " WHERE fk_statut > 0"; +$sql.= " AND entity = ".$conf->entity; +$sql.= " GROUP BY dm DESC"; + +$resql=$db->query($sql); +if ($resql) +{ + $num = $db->num_rows($resql); + $i = 0; + while ($i < $num) + { + $row = $db->fetch_row($resql); + $nbproduct = $row[0]; + $year = $row[1]; + print ""; + print ''; + $i++; + } +} +$db->free($resql); + +print '
'.$langs->trans("Year").''.$langs->trans("NbOfReceptions").'
'.$year.''.$nbproduct.'
'; +*/ + +print '
'; +print ''.$langs->trans("StatsOnReceptionsOnlyValidated").''; + +llxFooter(); + +$db->close(); diff --git a/htdocs/reception/stats/month.php b/htdocs/reception/stats/month.php new file mode 100644 index 00000000000..df11f046e65 --- /dev/null +++ b/htdocs/reception/stats/month.php @@ -0,0 +1,76 @@ + + * Copyright (C) 2004-2009 Laurent Destailleur + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/** + * \file htdocs/reception/stats/month.php + * \ingroup commande + * \brief Page des stats receptions par mois + */ + +require '../../main.inc.php'; +require_once DOL_DOCUMENT_ROOT.'/reception/class/reception.class.php'; +require_once DOL_DOCUMENT_ROOT.'/reception/class/receptionstats.class.php'; +require_once DOL_DOCUMENT_ROOT.'/core/class/dolgraph.class.php'; + + +/* + * View + */ + +llxHeader(); + +$WIDTH=DolGraph::getDefaultGraphSizeForStats('width'); +$HEIGHT=DolGraph::getDefaultGraphSizeForStats('height'); + +$mesg = ''; + +print load_fiche_titre($langs->trans("StatisticsOfReceptions").' '.$_GET["year"], $mesg); + +$stats = new ReceptionStats($db); +$data = $stats->getNbReceptionByMonth($_GET["year"]); + +dol_mkdir($conf->reception->dir_temp); + +$filename = $conf->reception->dir_temp."/reception".$year.".png"; +$fileurl = DOL_URL_ROOT.'/viewimage.php?modulepart=receptionstats&file=reception'.$year.'.png'; + +$px = new DolGraph(); +$mesg = $px->isGraphKo(); +if (! $mesg) +{ + $px->SetData($data); + $px->SetMaxValue($px->GetCeilMaxValue()); + $px->SetWidth($WIDTH); + $px->SetHeight($HEIGHT); + $px->SetYLabel($langs->trans("NbOfOrders")); + $px->SetShading(3); + $px->SetHorizTickIncrement(1); + $px->SetPrecisionY(0); + $px->draw($filename,$fileurl); +} + +print ''; +print ''; +print ''; +print '
Nombre d reception par mois'; +print $px->show(); +print '
'; + +llxFooter(); + +$db->close(); diff --git a/htdocs/reception/tpl/index.html b/htdocs/reception/tpl/index.html new file mode 100644 index 00000000000..e69de29bb2d diff --git a/htdocs/reception/tpl/linkedobjectblock.tpl.php b/htdocs/reception/tpl/linkedobjectblock.tpl.php new file mode 100644 index 00000000000..50069f0a14f --- /dev/null +++ b/htdocs/reception/tpl/linkedobjectblock.tpl.php @@ -0,0 +1,80 @@ + + * Copyright (C) 2014 Marcos García + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * 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 . + * + */ +?> + + + +load("receptions"); + +$total=0; $ilink=0; +$var=true; +foreach($linkedObjectBlock as $key => $objectlink) +{ + $ilink++; + + $trclass=($var?'pair':'impair'); + if ($ilink == count($linkedObjectBlock) && empty($noMoreLinkedObjectBlockAfter) && count($linkedObjectBlock) <= 1) $trclass.=' liste_sub_total'; +?> + + trans("Reception"); ?> + getNomUrl(1); ?> + + date_delivery,'day'); ?> + rights->reception->lire) { + $total = $total + $objectlink->total_ht; + echo price($objectlink->total_ht); + } ?> + getLibStatut(3); ?> + + element != 'order_supplier') { + ?> + ">transnoentitiesnoconv("RemoveLink"), 'unlink'); ?> + + + 1) +{ + ?> + + trans("Total"); ?> + + + + + + + + + +