diff --git a/class/diffusioncontact.class.php b/class/diffusioncontact.class.php index 5d135fa..6cbfe02 100644 --- a/class/diffusioncontact.class.php +++ b/class/diffusioncontact.class.php @@ -1,1438 +1,1605 @@ - - * Copyright (C) 2023-2024 Frédéric France - * Copyright (C) 2025 Pierre ARDOIN - * - * 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 class/diffusioncontact.class.php - * \ingroup diffusionplans - * \brief This file is a CRUD class file for DiffusionContact (Create/Read/Update/Delete) - */ - -// Put here all includes required by your class file -require_once DOL_DOCUMENT_ROOT.'/core/class/commonobject.class.php'; -require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php'; -//require_once DOL_DOCUMENT_ROOT . '/societe/class/societe.class.php'; -//require_once DOL_DOCUMENT_ROOT . '/product/class/product.class.php'; - -/** - * Class for DiffusionContact - */ -class DiffusionContact extends CommonObject -{ - /** - * @var string ID of module. - */ - public $module = 'diffusionplans'; - - /** - * @var string ID to identify managed object. - */ - public $element = 'diffusioncontact'; - - /** - * @var string Name of table without prefix where object is stored. This is also the key used for extrafields management (so extrafields know the link to the parent table). - */ - public $table_element = 'diffusionplans_diffusioncontact'; - - /** - * @var string If permission must be checkec with hasRight('diffusionplans', 'read') and not hasright('mymodyle', 'diffusioncontact', 'read'), you can uncomment this line - */ - //public $element_for_permission = 'diffusionplans'; - - /** - * @var string String with name of icon for diffusioncontact. Must be a 'fa-xxx' fontawesome code (or 'fa-xxx_fa_color_size') or 'diffusioncontact@diffusionplans' if picto is file 'img/object_diffusioncontact.png'. - */ - public $picto = 'fa-address-book'; - - - const STATUS_DRAFT = 0; - const STATUS_VALIDATED = 1; - const STATUS_CANCELED = 9; - - /** - * 'type' field format: - * 'integer', 'integer:ObjectClass:PathToClass[:AddCreateButtonOrNot[:Filter[:Sortfield]]]', - * 'select' (list of values are in 'options'. for integer list of values are in 'arrayofkeyval'), - * 'sellist:TableName:LabelFieldName[:KeyFieldName[:KeyFieldParent[:Filter[:CategoryIdType[:CategoryIdList[:SortField]]]]]]', - * 'chkbxlst:...', - * 'varchar(x)', - * 'text', 'text:none', 'html', - * 'double(24,8)', 'real', 'price', 'stock', - * 'date', 'datetime', 'timestamp', 'duration', - * 'boolean', 'checkbox', 'radio', 'array', - * 'mail', 'phone', 'url', 'password', 'ip' - * Note: Filter must be a Dolibarr Universal Filter syntax string. Example: "(t.ref:like:'SO-%') or (t.date_creation:<:'20160101') or (t.status:!=:0) or (t.nature:is:NULL)" - * 'length' the length of field. Example: 255, '24,8' - * 'label' the translation key. - * 'langfile' the key of the language file for translation. - * 'alias' the alias used into some old hard coded SQL requests - * 'picto' is code of a picto to show before value in forms - * 'enabled' is a condition when the field must be managed (Example: 1 or 'getDolGlobalInt("MY_SETUP_PARAM")' or 'isModEnabled("multicurrency")' ...) - * 'position' is the sort order of field. - * 'notnull' is set to 1 if not null in database. Set to -1 if we must set data to null if empty ('' or 0). - * 'visible' says if field is visible in list (Examples: 0=Not visible, 1=Visible on list and create/update/view forms, 2=Visible on list only, 3=Visible on create/update/view form only (not list), 4=Visible on list and update/view form (not create). 5=Visible on list and view form (not create/not update). 6=visible on list and update/view form (not update). Using a negative value means field is not shown by default on list but can be selected for viewing) - * 'noteditable' says if field is not editable (1 or 0) - * 'alwayseditable' says if field can be modified also when status is not draft ('1' or '0') - * 'default' is a default value for creation (can still be overwrote by the Setup of Default Values if field is editable in creation form). Note: If default is set to '(PROV)' and field is 'ref', the default value will be set to '(PROVid)' where id is rowid when a new record is created. - * 'index' if we want an index in database. - * 'foreignkey'=>'tablename.field' if the field is a foreign key (it is recommended to name the field fk_...). - * 'searchall' is 1 if we want to search in this field when making a search from the quick search button. - * 'isameasure' must be set to 1 or 2 if field can be used for measure. Field type must be summable like integer or double(24,8). Use 1 in most cases, or 2 if you don't want to see the column total into list (for example for percentage) - * 'css' and 'cssview' and 'csslist' is the CSS style to use on field. 'css' is used in creation and update. 'cssview' is used in view mode. 'csslist' is used for columns in lists. For example: 'css'=>'minwidth300 maxwidth500 widthcentpercentminusx', 'cssview'=>'wordbreak', 'csslist'=>'tdoverflowmax200' - * 'placeholder' to set the placeholder of a varchar field. - * 'help' and 'helplist' is a 'TranslationString' to use to show a tooltip on field. You can also use 'TranslationString:keyfortooltiponlick' for a tooltip on click. - * 'showoncombobox' if value of the field must be visible into the label of the combobox that list record - * 'disabled' is 1 if we want to have the field locked by a 'disabled' attribute. In most cases, this is never set into the definition of $fields into class, but is set dynamically by some part of code like the constructor of the class. - * 'arrayofkeyval' to set a list of values if type is a list of predefined values. For example: array("0"=>"Draft","1"=>"Active","-1"=>"Cancel"). Note that type can be 'integer' or 'varchar' - * 'autofocusoncreate' to have field having the focus on a create form. Only 1 field should have this property set to 1. - * 'comment' is not used. You can store here any text of your choice. It is not used by application. - * 'validate' is 1 if you need to validate the field with $this->validateField(). Need MAIN_ACTIVATE_VALIDATION_RESULT. - * 'copytoclipboard' is 1 or 2 to allow to add a picto to copy value into clipboard (1=picto after label, 2=picto after value) - * - * Note: To have value dynamic, you can set value to 0 in definition and edit the value on the fly into the constructor. - */ - - // BEGIN MODULEBUILDER PROPERTIES - /** - * @inheritdoc - * Array with all fields and their property. Do not use it as a static var. It may be modified by constructor. - */ - public $fields = array( - "rowid" => array("type" => "integer", "label" => "TechnicalID", "enabled" => "1", 'position' => 1, 'notnull' => 1, "visible" => "0", "noteditable" => "1", "index" => "1", "css" => "left", "comment" => "Id"), - "fk_contact" => array("type" => "integer", "label" => "fk_contact", "enabled" => "1", 'position' => 2, 'notnull' => 0, "visible" => "0",), - "fk_diffusion" => array("type" => "integer", "label" => "fk_diffusion", "enabled" => "1", 'position' => 1, 'notnull' => 0, "visible" => "0",), - "mail_status" => array("type" => "integer", "label" => "method_mail", "enabled" => "1", 'position' => 3, 'notnull' => 1, "visible" => "0", "default" => "0", "arrayofkeyval" => array("0" => "Désactivé", "1" => "Actif"),), - "letter_status" => array("type" => "integer", "label" => "method_letter", "enabled" => "1", 'position' => 4, 'notnull' => 1, "visible" => "0", "default" => "0", "arrayofkeyval" => array("0" => "Désactivé", "1" => "Actif"),), - "hand_status" => array("type" => "integer", "label" => "method_hand", "enabled" => "1", 'position' => 5, 'notnull' => 1, "visible" => "0", "default" => "0", "arrayofkeyval" => array("0" => "Désactivé", "1" => "Actif"),), - "fk_user_modif" => array("type" => "integer:user:user/class/user.class.php", "label" => "UserModif", "enabled" => "1", 'position' => 511, 'notnull' => 0, "visible" => "0",), - ); - public $rowid; - public $fk_contact; - public $fk_diffusion; - public $mail_status; - public $letter_status; - public $hand_status; - public $fk_user_modif; - // END MODULEBUILDER PROPERTIES - - - // If this object has a subtable with lines - - // /** - // * @var string Name of subtable line - // */ - // public $table_element_line = 'diffusionplans_diffusioncontactline'; - - // /** - // * @var string Field with ID of parent key if this object has a parent - // */ - public $fk_element = 'fk_diffusion'; - - // /** - // * @var string Name of subtable class that manage subtable lines - // */ - // public $class_element_line = 'DiffusionContactline'; - - // /** - // * @var array List of child tables. To test if we can delete object. - // */ - // protected $childtables = array('mychildtable' => array('name'=>'DiffusionContact', 'fk_element'=>'fk_diffusioncontact')); - - // /** - // * @var array List of child tables. To know object to delete on cascade. - // * If name matches '@ClassNAme:FilePathClass;ParentFkFieldName' it will - // * call method deleteByParentField(parentId, ParentFkFieldName) to fetch and delete child object - // */ - // protected $childtablesoncascade = array('diffusionplans_diffusioncontactdet'); - - // /** - // * @var DiffusionContactLine[] Array of subtable lines - // */ - // public $lines = array(); - - - - /** - * Constructor - * - * @param DoliDB $db Database handler - */ - public function __construct(DoliDB $db) - { - global $conf, $langs; - - $this->db = $db; - $this->ismultientitymanaged = 0; - $this->isextrafieldmanaged = 1; - - $entity = !empty($conf->entity) ? (int) $conf->entity : 1; - - if (!isset($conf->diffusionplans) || !is_object($conf->diffusionplans)) { - $conf->diffusionplans = new stdClass(); - } - - if (empty($conf->diffusionplans->dir_output)) { - $conf->diffusionplans->dir_output = DOL_DATA_ROOT.($entity > 1 ? '/'.$entity : '').'/diffusionplans'; - } - - if (empty($conf->diffusionplans->multidir_output) || !is_array($conf->diffusionplans->multidir_output)) { - $conf->diffusionplans->multidir_output = array(); - } - - if (empty($conf->diffusionplans->multidir_output[$entity])) { - $conf->diffusionplans->multidir_output[$entity] = $conf->diffusionplans->dir_output; - } - - if (!isset($conf->diffusioncontact) || !is_object($conf->diffusioncontact)) { - $conf->diffusioncontact = new stdClass(); - } - - if (empty($conf->diffusioncontact->dir_output)) { - $conf->diffusioncontact->dir_output = $conf->diffusionplans->dir_output.'/diffusioncontact'; - } - - if (empty($conf->diffusioncontact->multidir_output) || !is_array($conf->diffusioncontact->multidir_output)) { - $conf->diffusioncontact->multidir_output = array(); - } - - if (empty($conf->diffusioncontact->multidir_output[$entity])) { - $conf->diffusioncontact->multidir_output[$entity] = $conf->diffusioncontact->dir_output; - } - - $this->modulepart = 'diffusioncontact'; - $this->dir_output = $conf->diffusioncontact->multidir_output[$entity]; - - if (!empty($this->dir_output)) { - dol_mkdir($this->dir_output); - } - - if (!getDolGlobalInt('MAIN_SHOW_TECHNICAL_ID') && isset($this->fields['rowid']) && !empty($this->fields['ref'])) { - $this->fields['rowid']['visible'] = 0; - } - if (!isModEnabled('multicompany') && isset($this->fields['entity'])) { - $this->fields['entity']['enabled'] = 0; - } - - // Example to show how to set values of fields definition dynamically - /*if ($user->hasRight('diffusionplans', 'diffusioncontact', 'read')) { - $this->fields['myfield']['visible'] = 1; - $this->fields['myfield']['noteditable'] = 0; - }*/ - - // Unset fields that are disabled - foreach ($this->fields as $key => $val) { - if (isset($val['enabled']) && empty($val['enabled'])) { - unset($this->fields[$key]); - } - } - - // Translate some data of arrayofkeyval - if (is_object($langs)) { - foreach ($this->fields as $key => $val) { - if (!empty($val['arrayofkeyval']) && is_array($val['arrayofkeyval'])) { - foreach ($val['arrayofkeyval'] as $key2 => $val2) { - $this->fields[$key]['arrayofkeyval'][$key2] = $langs->trans($val2); - } - } - } - } - } - - /** - * Create object into database - * - * @param int<0,1> $notrigger 0=launch triggers after, 1=disable triggers - * @return int<-1,max> Return integer <0 if KO, Id of created object if OK - */ - public function create($notrigger = 0) - { - //$resultcreate = $this->createCommon($user, $notrigger); - - // uncomment lines below if you want to validate object after creation - // $this->fetch($this->id); // needed to retrieve some fields (ie date_creation for masked ref) - // $resultcreate = $this->validate($user, $notrigger); - - //return $resultcreate; - - global $langs, $user, $conf, $object, $contactid; - - $this->db->begin(); - - $sql = "INSERT INTO ".MAIN_DB_PREFIX."diffusionplans_diffusioncontact"; - $sql.= " (`fk_diffusion`, `fk_contact`, `contact_source`, `mail_status`, `letter_status`, `hand_status`)"; - $sql.= " VALUES (".$object->id.","; - $sql.= " '".$contactid."', "; - $sql.= " '".GETPOST("source", 'aZ09')."', "; - $sql.= " 0,"; - $sql.= " 0,"; - $sql.= " 0"; - $sql.= ')'; - - //var_dump($sql); - - dol_syslog("DiffusionContact::insert sql=".$sql); - - $resql = $this->db->query($sql); - //var_dump("Contact ID : ".$resql); - - if ($resql) - { - if (! $notrigger) - { - // Appel des triggers - include_once(DOL_DOCUMENT_ROOT . "/core/class/interfaces.class.php"); - $interface = new Interfaces($this->db); - $result = $interface->run_triggers('DIFFUSIONCONTACT_INSERT', $this, $user ,$langs, $conf); - if ($result < 0) { - $this->error = $langs->trans('ErrorCallingTrigger'); - $this->db->rollback(); - return -1; - } - // Fin appel triggers - } - - $this->db->commit(); - - return 1; - - } - else - { - $this->error = $this->db->error()." sql=".$sql; - $this->db->rollback(); - - return -2; - } - } - - /** - * Clone an object into another one - * - * @param User $user User that creates - * @param int $fromid Id of object to clone - * @return self|int<-1,-1> New object created, <0 if KO - */ - public function createFromClone(User $user, $fromid) - { - global $langs, $extrafields; - $error = 0; - - dol_syslog(__METHOD__, LOG_DEBUG); - - $object = new self($this->db); - - $this->db->begin(); - - // Load source object - $result = $object->fetchCommon($fromid); - if ($result > 0 && !empty($object->table_element_line)) { - $object->fetchLines(); - } - - // get lines so they will be clone - //foreach($this->lines as $line) - // $line->fetch_optionals(); - - // Reset some properties - unset($object->id); - unset($object->fk_user_creat); - unset($object->import_key); - - // Clear fields - if (property_exists($object, 'ref')) { - $object->ref = empty($this->fields['ref']['default']) ? "Copy_Of_".$object->ref : $this->fields['ref']['default']; - } - if (property_exists($object, 'label')) { - $object->label = empty($this->fields['label']['default']) ? $langs->trans("CopyOf")." ".$object->label : $this->fields['label']['default']; - } - if (property_exists($object, 'status')) { - $object->status = self::STATUS_DRAFT; - } - if (property_exists($object, 'date_creation')) { - $object->date_creation = dol_now(); - } - if (property_exists($object, 'date_modification')) { - $object->date_modification = null; - } - // ... - // Clear extrafields that are unique - if (is_array($object->array_options) && count($object->array_options) > 0) { - $extrafields->fetch_name_optionals_label($this->table_element); - foreach ($object->array_options as $key => $option) { - $shortkey = preg_replace('/options_/', '', $key); - if (!empty($extrafields->attributes[$this->table_element]['unique'][$shortkey])) { - //var_dump($key); - //var_dump($clonedObj->array_options[$key]); exit; - unset($object->array_options[$key]); - } - } - } - - // Create clone - $object->context['createfromclone'] = 'createfromclone'; - $result = $object->createCommon($user); - if ($result < 0) { - $error++; - $this->setErrorsFromObject($object); - } - - if (!$error) { - // copy internal contacts - if ($this->copy_linked_contact($object, 'internal') < 0) { - $error++; - } - } - - if (!$error) { - // copy external contacts if same company - if (!empty($object->socid) && property_exists($this, 'fk_soc') && $this->fk_soc == $object->socid) { - if ($this->copy_linked_contact($object, 'external') < 0) { - $error++; - } - } - } - - unset($object->context['createfromclone']); - - // End - if (!$error) { - $this->db->commit(); - return $object; - } else { - $this->db->rollback(); - return -1; - } - } - - /** - * Load object in memory from the database - * - * @param int $id Id object - * @param string $ref Ref - * @param int<0,1> $noextrafields 0=Default to load extrafields, 1=No extrafields - * @param int<0,1> $nolines 0=Default to load extrafields, 1=No extrafields - * @return int<-1,1> Return integer <0 if KO, 0 if not found, >0 if OK - */ - public function fetch() - { - global $langs, $user, $conf, $object, $entry; - - $element = "diffusioncontact"; - $table_element = "diffusionplans_diffusioncontact"; - $module = "diffusionplans"; - - $this->db->begin(); - - $sql = "SELECT * FROM `".MAIN_DB_PREFIX."diffusionplans_diffusioncontact`" ; - $sql.= " WHERE `fk_contact`='".$entry->contact_id."'"; - $sql.= " AND `fk_diffusion`='".$object->id."'"; - $sql.= " AND `contact_source`='".$entry->source."'"; - - //var_dump($sql); - - dol_syslog("DiffusionContact::fetch sql=".$sql); - - $resql = $this->db->query($sql); - - if ($resql = 1) - { - $num = $this->db->num_rows($resql); - $i = 0; - - //var_dump($num); - - if ($num) - { - while ($i < $num) - { - $obj = $this->db->fetch_object($resql); - - //var_dump($obj); - - $this->lines[$i] = $obj; - $this->lines[$i]->id = trim($obj->rowid); - $this->lines[$i]->mail_status = trim($obj->mail_status); - $this->lines[$i]->letter_status = trim($obj->letter_status); - $this->lines[$i]->hand_status = trim($obj->hand_status); - $i++; - } - } - - $result = array( - 'id' => $this->lines[0]->id, - 'module' => $module, - 'element'=> $element, - 'table_element' =>$table_element, - 'fields' => $object->fields, - 'diffusion' => $object->id, - 'mail_status' => $this->lines[0]->mail_status, - 'letter_status' => $this->lines[0]->letter_status, - 'hand_status'=> $this->lines[0]->hand_status, - - ); - - return $result; - } - else - { - $this->error = $this->db->error()." sql=".$sql; - return -1; - } - - //$result = $this->fetchCommon($id, $ref, '', $noextrafields); - //if ($result > 0 && !empty($this->table_element_line) && empty($nolines)) { - // $this->fetchLines($noextrafields); - //} - //return $result; - } - - /** - * Load object lines in memory from the database - * - * @param int<0,1> $noextrafields 0=Default to load extrafields, 1=No extrafields - * @return int<-1,1> Return integer <0 if KO, 0 if not found, >0 if OK - */ - public function fetchLines($noextrafields = 0) - { - $this->lines = array(); - - $result = $this->fetchLinesCommon('', $noextrafields); - return $result; - } - - - /** - * Load list of objects in memory from the database. - * Using a fetchAll() with limit = 0 is a very bad practice. Instead try to forge yourself an optimized SQL request with - * your own loop with start and stop pagination. - * - * @param string $sortorder Sort Order - * @param string $sortfield Sort field - * @param int<0,max> $limit Limit the number of lines returned - * @param int<0,max> $offset Offset - * @param string $filter Filter as an Universal Search string. - * Example: '((client:=:1) OR ((client:>=:2) AND (client:<=:3))) AND (client:!=:8) AND (nom:like:'a%')' - * @param string $filtermode No longer used - * @return array|int<-1,-1> <0 if KO, array of pages if OK - */ - public function fetchAll($sortorder = '', $sortfield = '', $limit = 1000, $offset = 0, string $filter = '', $filtermode = 'AND') - { - dol_syslog(__METHOD__, LOG_DEBUG); - - $records = array(); - - $sql = "SELECT "; - $sql.= $this->getFieldList('t'); - $sql.= " FROM ".$this->db->prefix().$this->table_element." as t"; - if (isset($this->isextrafieldmanaged) && $this->isextrafieldmanaged == 1) { - $sql.= " LEFT JOIN ".$this->db->prefix().$this->table_element."_extrafields as te ON te.fk_object = t.rowid"; - } - if (isset($this->ismultientitymanaged) && $this->ismultientitymanaged == 1) { - $sql.= " WHERE t.entity IN (".getEntity($this->element).")"; - } else { - $sql.= " WHERE 1 = 1"; - } - - // Manage filter - $errormessage = ''; - $sql.= forgeSQLFromUniversalSearchCriteria($filter, $errormessage); - if ($errormessage) { - $this->errors[] = $errormessage; - dol_syslog(__METHOD__.' '.implode(',', $this->errors), LOG_ERR); - return -1; - } - - if (!empty($sortfield)) { - $sql.= $this->db->order($sortfield, $sortorder); - } - if (!empty($limit)) { - $sql.= $this->db->plimit($limit, $offset); - } - - $resql = $this->db->query($sql); - if ($resql) { - $num = $this->db->num_rows($resql); - $i = 0; - while ($i < ($limit ? min($limit, $num) : $num)) { - $obj = $this->db->fetch_object($resql); - - $record = new self($this->db); - $record->setVarsFromFetchObj($obj); - - if (!empty($record->isextrafieldmanaged)) { - $record->fetch_optionals(); - } - - $records[$record->id] = $record; - - $i++; - } - $this->db->free($resql); - - return $records; - } else { - $this->errors[] = 'Error '.$this->db->lasterror(); - dol_syslog(__METHOD__.' '.implode(',', $this->errors), LOG_ERR); - - return -1; - } - } - - /** - * Update object into database - * - * @param User $user User that modifies - * @param int<0,1> $notrigger 0=launch triggers after, 1=disable triggers - * @return int<-1,1> Return integer <0 if KO, >0 if OK - */ - public function update(User $user, $notrigger = 0) - { - global $langs, $user, $conf, $object, $field, $value, $id, $db; - - $error = 0; - - dol_syslog(__METHOD__, LOG_DEBUG); - - $sql = "UPDATE ".MAIN_DB_PREFIX."$object->table_element" ; - $sql.= " SET ".$field." = ".(int) $value.""; - $sql.= " , fk_user_modif = ".$user->id; - $sql.= " WHERE rowid = ".(int) $id; - - dol_syslog("DiffusionContact::update sql=".$sql); - - $resql = $this->db->query($sql); - - if ($resql) - { - // Appel des triggers - include_once DOL_DOCUMENT_ROOT . '/core/class/interfaces.class.php'; - $interface=new Interfaces($db); - $result2=$interface->run_triggers('DIFFUSIONCONTACT_UPDATELINE',$this,$user,$langs,$conf); - if ($result2 < 0) { $error++; $db->errors=$interface->errors; } - // Fin appel triggers - - $db->commit(); - return $resql; - } - else - { - $db->error=$this->db->lasterror(); - dol_syslog("DiffusionContact::updateLine ".$this->error, LOG_ERR); - $db->rollback(); - - return -1; - } - - - //return $this->updateCommon($user, $notrigger); - } - - /** - * Delete object in database - * - * @param User $user User that deletes - * @param int<0,1> $notrigger 0=launch triggers, 1=disable triggers - * @return int<-1,1> Return integer <0 if KO, >0 if OK - */ - public function delete(User $user, $notrigger = 0) - { - //return $this->deleteCommon($user, $notrigger); - //return $this->deleteCommon($user, $notrigger, 1); - } - - /** - * Delete a line of object in database - * - * @param User $user User that delete - * @param int $idline Id of line to delete - * @param int<0,1> $notrigger 0=launch triggers after, 1=disable triggers - * @return int<-2,1> >0 if OK, <0 if KO - */ - public function deleteLine($notrigger = 0) - { - //if ($this->status < 0) { - // $this->error = 'ErrorDeleteLineNotAllowedByObjectStatus'; - // return -2; - //} - - global $conf, $user, $langs, $object, $contactid; - - $error=0; - - $sql = "DELETE FROM ".MAIN_DB_PREFIX."diffusionplans_diffusioncontact" ; - $sql.= " WHERE fk_diffusion=".$object->id; - $sql.= " AND fk_contact='".$contactid."'"; - $sql.= " AND contact_source='".GETPOST('source', 'aZ09')."'"; - - dol_syslog("DiffusionContact::deleteLine sql=".$sql); - //var_dump($sql); - - $resql=$this->db->query($sql); - - if ($resql) - { - // Appel des triggers - include_once DOL_DOCUMENT_ROOT . '/core/class/interfaces.class.php'; - $interface=new Interfaces($this->db); - $result=$interface->run_triggers('DIFFUSIONCONTACT_DELETELINE',$this,$user,$langs,$conf); - if ($result < 0) { $error++; $this->errors=$interface->errors; } - // Fin appel triggers - - return 1; - } - else - { - $this->error=$this->db->lasterror(); - dol_syslog("DiffusionContact::deleteLine ".$this->error, LOG_ERR); - return -1; - } - - //return $this->deleteLineCommon($user, $idline, $notrigger); - } - - - /** - * Validate object - * - * @param User $user User making status change - * @param int<0,1> $notrigger 1=Does not execute triggers, 0= execute triggers - * @return int<-1,1> Return integer <=0 if OK, 0=Nothing done, >0 if KO - */ - public function validate($user, $notrigger = 0) - { - global $conf; - - require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php'; - - $error = 0; - - // Protection - if ($this->status == self::STATUS_VALIDATED) { - dol_syslog(get_class($this)."::validate action abandoned: already validated", LOG_WARNING); - return 0; - } - - /* if (! ((!getDolGlobalInt('MAIN_USE_ADVANCED_PERMS') && $user->hasRight('diffusionplans', 'diffusioncontact', 'write')) - || (getDolGlobalInt('MAIN_USE_ADVANCED_PERMS') && $user->hasRight('diffusionplans', 'diffusioncontact_advance', 'validate'))) - { - $this->error='NotEnoughPermissions'; - dol_syslog(get_class($this)."::valid ".$this->error, LOG_ERR); - return -1; - }*/ - - $now = dol_now(); - - $this->db->begin(); - - // 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 - $num = $this->getNextNumRef(); - } else { - $num = $this->ref; - } - $this->newref = $num; - - if (!empty($num)) { - // Validate - $sql = "UPDATE ".MAIN_DB_PREFIX.$this->table_element; - $sql .= " SET "; - if (!empty($this->fields['ref'])) { - $sql .= " ref = '".$this->db->escape($num)."',"; - } - $sql .= " status = ".self::STATUS_VALIDATED; - if (!empty($this->fields['date_validation'])) { - $sql .= ", date_validation = '".$this->db->idate($now)."'"; - } - if (!empty($this->fields['fk_user_valid'])) { - $sql .= ", fk_user_valid = ".((int) $user->id); - } - $sql .= " WHERE rowid = ".((int) $this->id); - - dol_syslog(get_class($this)."::validate()", LOG_DEBUG); - $resql = $this->db->query($sql); - if (!$resql) { - dol_print_error($this->db); - $this->error = $this->db->lasterror(); - $error++; - } - - if (!$error && !$notrigger) { - // Call trigger - $result = $this->call_trigger('MYOBJECT_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)) { - // Now we rename also files into index - $sql = 'UPDATE '.MAIN_DB_PREFIX."ecm_files set filename = CONCAT('".$this->db->escape($this->newref)."', SUBSTR(filename, ".(strlen($this->ref) + 1).")), filepath = 'diffusioncontact/".$this->db->escape($this->newref)."'"; - $sql .= " WHERE filename LIKE '".$this->db->escape($this->ref)."%' AND filepath = 'diffusioncontact/".$this->db->escape($this->ref)."' and entity = ".$conf->entity; - $resql = $this->db->query($sql); - if (!$resql) { - $error++; - $this->error = $this->db->lasterror(); - } - $sql = 'UPDATE '.MAIN_DB_PREFIX."ecm_files set filepath = 'diffusioncontact/".$this->db->escape($this->newref)."'"; - $sql .= " WHERE filepath = 'diffusioncontact/".$this->db->escape($this->ref)."' and entity = ".$conf->entity; - $resql = $this->db->query($sql); - if (!$resql) { - $error++; - $this->error = $this->db->lasterror(); - } - - // We rename directory ($this->ref = old ref, $num = new ref) in order not to lose the attachments - $oldref = dol_sanitizeFileName($this->ref); - $newref = dol_sanitizeFileName($num); - $dirsource = $conf->diffusionplans->dir_output.'/diffusioncontact/'.$oldref; - $dirdest = $conf->diffusionplans->dir_output.'/diffusioncontact/'.$newref; - if (!$error && file_exists($dirsource)) { - dol_syslog(get_class($this)."::validate() rename dir ".$dirsource." into ".$dirdest); - - if (@rename($dirsource, $dirdest)) { - dol_syslog("Rename ok"); - // Rename docs starting with $oldref with $newref - $listoffiles = dol_dir_list($conf->diffusionplans->dir_output.'/diffusioncontact/'.$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 = $num; - $this->status = self::STATUS_VALIDATED; - } - - if (!$error) { - $this->db->commit(); - return 1; - } else { - $this->db->rollback(); - return -1; - } - } - - - /** - * Set draft status - * - * @param User $user Object user that modify - * @param int<0,1> $notrigger 1=Does not execute triggers, 0=Execute triggers - * @return int<0,1> Return integer <0 if KO, >0 if OK - */ - public function setDraft($user, $notrigger = 0) - { - // Protection - if ($this->status <= self::STATUS_DRAFT) { - return 0; - } - - /* if (! ((!getDolGlobalInt('MAIN_USE_ADVANCED_PERMS') && $user->hasRight('diffusionplans','write')) - || (getDolGlobalInt('MAIN_USE_ADVANCED_PERMS') && $user->hasRight('diffusionplans','diffusionplans_advance','validate')))) - { - $this->error='Permission denied'; - return -1; - }*/ - - return $this->setStatusCommon($user, self::STATUS_DRAFT, $notrigger, 'DIFFUSIONPLANS_MYOBJECT_UNVALIDATE'); - } - - /** - * Set cancel status - * - * @param User $user Object user that modify - * @param int<0,1> $notrigger 1=Does not execute triggers, 0=Execute triggers - * @return int<-1,1> Return integer <0 if KO, 0=Nothing done, >0 if OK - */ - public function cancel($user, $notrigger = 0) - { - // Protection - if ($this->status != self::STATUS_VALIDATED) { - return 0; - } - - /* if (! ((!getDolGlobalInt('MAIN_USE_ADVANCED_PERMS') && $user->hasRight('diffusionplans','write')) - || (getDolGlobalInt('MAIN_USE_ADVANCED_PERMS') && $user->hasRight('diffusionplans','diffusionplans_advance','validate')))) - { - $this->error='Permission denied'; - return -1; - }*/ - - return $this->setStatusCommon($user, self::STATUS_CANCELED, $notrigger, 'DIFFUSIONPLANS_MYOBJECT_CANCEL'); - } - - /** - * Set back to validated status - * - * @param User $user Object user that modify - * @param int<0,1> $notrigger 1=Does not execute triggers, 0=Execute triggers - * @return int<-1,1> Return integer <0 if KO, 0=Nothing done, >0 if OK - */ - public function reopen($user, $notrigger = 0) - { - // Protection - if ($this->status == self::STATUS_VALIDATED) { - return 0; - } - - /*if (! ((!getDolGlobalInt('MAIN_USE_ADVANCED_PERMS') && $user->hasRight('diffusionplans','write')) - || (getDolGlobalInt('MAIN_USE_ADVANCED_PERMS') && $user->hasRight('diffusionplans','diffusionplans_advance','validate')))) - { - $this->error='Permission denied'; - return -1; - }*/ - - return $this->setStatusCommon($user, self::STATUS_VALIDATED, $notrigger, 'DIFFUSIONPLANS_MYOBJECT_REOPEN'); - } - - /** - * getTooltipContentArray - * - * @param array $params Params to construct tooltip data - * @since v18 - * @return array{optimize?:string,picto?:string,ref?:string} - */ - public function getTooltipContentArray($params) - { - global $langs; - - $datas = []; - - if (getDolGlobalInt('MAIN_OPTIMIZEFORTEXTBROWSER')) { - return ['optimize' => $langs->trans("ShowDiffusionContact")]; - } - $datas['picto'] = img_picto('', $this->picto).' '.$langs->trans("DiffusionContact").''; - if (isset($this->status)) { - $datas['picto'] .= ' '.$this->getLibStatut(5); - } - if (property_exists($this, 'ref')) { - $datas['ref'] = '
'.$langs->trans('Ref').': '.$this->ref; - } - if (property_exists($this, 'label')) { - $datas['ref'] = '
'.$langs->trans('Label').': '.$this->label; - } - - return $datas; - } - - /** - * Return a link to the object card (with optionally the picto) - * - * @param int $withpicto Include picto in link (0=No picto, 1=Include picto into link, 2=Only picto) - * @param string $option On what the link point to ('nolink', ...) - * @param int $notooltip 1=Disable tooltip - * @param string $morecss Add more css on link - * @param int $save_lastsearch_value -1=Auto, 0=No save of lastsearch_values when clicking, 1=Save lastsearch_values whenclicking - * @return string String with URL - */ - public function getNomUrl($withpicto = 0, $option = '', $notooltip = 0, $morecss = '', $save_lastsearch_value = -1) - { - global $conf, $langs, $hookmanager; - - if (!empty($conf->dol_no_mouse_hover)) { - $notooltip = 1; // Force disable tooltips - } - - $result = ''; - $params = [ - 'id' => $this->id, - 'objecttype' => $this->element.($this->module ? '@'.$this->module : ''), - 'option' => $option, - ]; - $classfortooltip = 'classfortooltip'; - $dataparams = ''; - if (getDolGlobalInt('MAIN_ENABLE_AJAX_TOOLTIP')) { - $classfortooltip = 'classforajaxtooltip'; - $dataparams = ' data-params="'.dol_escape_htmltag(json_encode($params)).'"'; - $label = ''; - } else { - $label = implode($this->getTooltipContentArray($params)); - } - - $url = dol_buildpath('/diffusionplans/diffusioncontact_card.php', 1).'?id='.$this->id; - - if ($option !== 'nolink') { - // Add param to save lastsearch_values or not - $add_save_lastsearch_values = ($save_lastsearch_value == 1 ? 1 : 0); - if ($save_lastsearch_value == -1 && isset($_SERVER["PHP_SELF"]) && preg_match('/list\.php/', $_SERVER["PHP_SELF"])) { - $add_save_lastsearch_values = 1; - } - if ($url && $add_save_lastsearch_values) { - $url .= '&save_lastsearch_values=1'; - } - } - - $linkclose = ''; - if (empty($notooltip)) { - if (getDolGlobalInt('MAIN_OPTIMIZEFORTEXTBROWSER')) { - $label = $langs->trans("ShowDiffusionContact"); - $linkclose .= ' alt="'.dolPrintHTMLForAttribute($label).'"'; - } - $linkclose .= ($label ? ' title="'.dolPrintHTMLForAttribute($label).'"' : ' title="tocomplete"'); - $linkclose .= $dataparams.' class="'.$classfortooltip.($morecss ? ' '.$morecss : '').'"'; - } else { - $linkclose = ($morecss ? ' class="'.$morecss.'"' : ''); - } - - if ($option == 'nolink' || empty($url)) { - $linkstart = ''; - if ($option == 'nolink' || empty($url)) { - $linkend = ''; - } else { - $linkend = ''; - } - - $result .= $linkstart; - - if (empty($this->showphoto_on_popup)) { - if ($withpicto) { - $result .= img_object(($notooltip ? '' : $label), ($this->picto ? $this->picto : 'generic'), (($withpicto != 2) ? 'class="paddingright"' : ''), 0, 0, $notooltip ? 0 : 1); - } - } else { - if ($withpicto) { - require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php'; - - list($class, $module) = explode('@', $this->picto); - $upload_dir = $conf->$module->multidir_output[$conf->entity]."/$class/".dol_sanitizeFileName($this->ref); - $filearray = dol_dir_list($upload_dir, "files"); - $filename = $filearray[0]['name']; - if (!empty($filename)) { - $pospoint = strpos($filearray[0]['name'], '.'); - - $pathtophoto = $class.'/'.$this->ref.'/thumbs/'.substr($filename, 0, $pospoint).'_mini'.substr($filename, $pospoint); - if (!getDolGlobalString(strtoupper($module.'_'.$class).'_FORMATLISTPHOTOSASUSERS')) { - $result .= '
No photo
'; - } else { - $result .= '
No photo
'; - } - - $result .= ''; - } else { - $result .= img_object(($notooltip ? '' : $label), ($this->picto ? $this->picto : 'generic'), ($notooltip ? (($withpicto != 2) ? 'class="paddingright"' : '') : 'class="'.(($withpicto != 2) ? 'paddingright ' : '').'"'), 0, 0, $notooltip ? 0 : 1); - } - } - } - - if ($withpicto != 2) { - $result .= $this->ref; - } - - $result .= $linkend; - //if ($withpicto != 2) $result.=(($addlabel && $this->label) ? $sep . dol_trunc($this->label, ($addlabel > 1 ? $addlabel : 0)) : ''); - - global $action, $hookmanager; - $hookmanager->initHooks(array($this->element.'dao')); - $parameters = array('id' => $this->id, 'getnomurl' => &$result); - $reshook = $hookmanager->executeHooks('getNomUrl', $parameters, $this, $action); // Note that $action and $object may have been modified by some hooks - if ($reshook > 0) { - $result = $hookmanager->resPrint; - } else { - $result .= $hookmanager->resPrint; - } - - return $result; - } - - /** - * Return a thumb for kanban views - * - * @param string $option Where point the link (0=> main card, 1,2 => shipment, 'nolink'=>No link) - * @param ?array $arraydata Array of data - * @return string HTML Code for Kanban thumb. - */ - public function getKanbanView($option = '', $arraydata = null) - { - global $conf, $langs; - - $selected = (empty($arraydata['selected']) ? 0 : $arraydata['selected']); - - $return = '
'; - $return .= '
'; - $return .= ''; - $return .= img_picto('', $this->picto); - $return .= ''; - $return .= '
'; - $return .= ''.(method_exists($this, 'getNomUrl') ? $this->getNomUrl() : $this->ref).''; - if ($selected >= 0) { - $return .= ''; - } - if (property_exists($this, 'label')) { - $return .= '
'.$this->label.'
'; - } - if (property_exists($this, 'thirdparty') && is_object($this->thirdparty)) { - $return .= '
'.$this->thirdparty->getNomUrl(1).'
'; - } - if (property_exists($this, 'amount')) { - $return .= '
'; - $return .= ''.price($this->amount, 0, $langs, 1, -1, -1, $conf->currency).''; - } - if (method_exists($this, 'getLibStatut')) { - $return .= '
'.$this->getLibStatut(3).'
'; - } - $return .= '
'; - $return .= '
'; - $return .= '
'; - - return $return; - } - - /** - * Return the label of the status - * - * @param int<0,6> $mode 0=long label, 1=short label, 2=Picto + short label, 3=Picto, 4=Picto + long label, 5=Short label + Picto, 6=Long label + Picto - * @return string Label of status - */ - public function getLabelStatus($mode = 0) - { - return $this->LibStatut($this->status, $mode); - } - - /** - * Return the label of the status - * - * @param int<0,6> $mode 0=long label, 1=short label, 2=Picto + short label, 3=Picto, 4=Picto + long label, 5=Short label + Picto, 6=Long label + Picto - * @return string Label of status - */ - public function getLibStatut($mode = 0) - { - return $this->LibStatut($this->status, $mode); - } - - // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps - /** - * Return the label of a given status - * - * @param int $status Id status - * @param int<0,6> $mode 0=long label, 1=short label, 2=Picto + short label, 3=Picto, 4=Picto + long label, 5=Short label + Picto, 6=Long label + Picto - * @return string Label of status - */ - public function LibStatut($status, $mode = 0) - { - // phpcs:enable - if (is_null($status)) { - return ''; - } - - if (empty($this->labelStatus) || empty($this->labelStatusShort)) { - global $langs; - //$langs->load("diffusionplans@diffusionplans"); - $this->labelStatus[self::STATUS_DRAFT] = $langs->transnoentitiesnoconv('Draft'); - $this->labelStatus[self::STATUS_VALIDATED] = $langs->transnoentitiesnoconv('Enabled'); - $this->labelStatus[self::STATUS_CANCELED] = $langs->transnoentitiesnoconv('Disabled'); - $this->labelStatusShort[self::STATUS_DRAFT] = $langs->transnoentitiesnoconv('Draft'); - $this->labelStatusShort[self::STATUS_VALIDATED] = $langs->transnoentitiesnoconv('Enabled'); - $this->labelStatusShort[self::STATUS_CANCELED] = $langs->transnoentitiesnoconv('Disabled'); - } - - $statusType = 'status'.$status; - //if ($status == self::STATUS_VALIDATED) $statusType = 'status1'; - if ($status == self::STATUS_CANCELED) { - $statusType = 'status6'; - } - - return dolGetStatus($this->labelStatus[$status], $this->labelStatusShort[$status], '', $statusType, $mode); - } - - /** - * Load the info information in the object - * - * @param int $id Id of object - * @return void - */ - public function info($id) - { - $sql = "SELECT rowid,"; - $sql .= " date_creation as datec, tms as datem"; - if (!empty($this->fields['date_validation'])) { - $sql .= ", date_validation as datev"; - } - if (!empty($this->fields['fk_user_creat'])) { - $sql .= ", fk_user_creat"; - } - if (!empty($this->fields['fk_user_modif'])) { - $sql .= ", fk_user_modif"; - } - if (!empty($this->fields['fk_user_valid'])) { - $sql .= ", fk_user_valid"; - } - $sql .= " FROM ".MAIN_DB_PREFIX.$this->table_element." as t"; - $sql .= " WHERE t.rowid = ".((int) $id); - - $result = $this->db->query($sql); - if ($result) { - if ($this->db->num_rows($result)) { - $obj = $this->db->fetch_object($result); - - $this->id = $obj->rowid; - - if (!empty($this->fields['fk_user_creat'])) { - $this->user_creation_id = $obj->fk_user_creat; - } - if (!empty($this->fields['fk_user_modif'])) { - $this->user_modification_id = $obj->fk_user_modif; - } - if (!empty($this->fields['fk_user_valid'])) { - $this->user_validation_id = $obj->fk_user_valid; - } - $this->date_creation = $this->db->jdate($obj->datec); - $this->date_modification = empty($obj->datem) ? '' : $this->db->jdate($obj->datem); - if (!empty($obj->datev)) { - $this->date_validation = empty($obj->datev) ? '' : $this->db->jdate($obj->datev); - } - } - - $this->db->free($result); - } else { - dol_print_error($this->db); - } - } - - /** - * Initialize object with example values - * Id must be 0 if object instance is a specimen - * - * @return int - */ - public function initAsSpecimen() - { - // Set here init that are not commonf fields - // $this->property1 = ... - // $this->property2 = ... - - return $this->initAsSpecimenCommon(); - } - - /** - * Create an array of lines - * - * @return CommonObjectLine[]|int array of lines if OK, <0 if KO - */ - public function getLinesArray() - { - $this->lines = array(); - - $objectline = new DiffusionContactLine($this->db); - $result = $objectline->fetchAll('ASC', 'position', 0, 0, '(fk_diffusioncontact:=:'.((int) $this->id).')'); - - if (is_numeric($result)) { - $this->setErrorsFromObject($objectline); - return $result; - } else { - $this->lines = $result; - return $this->lines; - } - } - - /** - * Returns the reference to the following non used object depending on the active numbering module. - * - * @return string Object free reference - */ - public function getNextNumRef() - { - global $langs, $conf; - $langs->load("diffusionplans@diffusionplans"); - - if (!getDolGlobalString('DIFFUSIONPLANS_MYOBJECT_ADDON')) { - $conf->global->DIFFUSIONPLANS_MYOBJECT_ADDON = 'mod_diffusioncontact_standard'; - } - - if (getDolGlobalString('DIFFUSIONPLANS_MYOBJECT_ADDON')) { - $mybool = false; - - $file = getDolGlobalString('DIFFUSIONPLANS_MYOBJECT_ADDON').".php"; - $classname = getDolGlobalString('DIFFUSIONPLANS_MYOBJECT_ADDON'); - - // Include file with class - $dirmodels = array_merge(array('/'), (array) $conf->modules_parts['models']); - foreach ($dirmodels as $reldir) { - $dir = dol_buildpath($reldir."core/modules/diffusionplans/"); - - // Load file with numbering class (if found) - $mybool = $mybool || @include_once $dir.$file; - } - - if (!$mybool) { - dol_print_error(null, "Failed to include file ".$file); - return ''; - } - - if (class_exists($classname)) { - $obj = new $classname(); - '@phan-var-force ModeleNumRefDiffusionContact $obj'; - $numref = $obj->getNextValue($this); - - if ($numref != '' && $numref != '-1') { - return $numref; - } else { - $this->error = $obj->error; - //dol_print_error($this->db,get_class($this)."::getNextNumRef ".$obj->error); - return ""; - } - } else { - print $langs->trans("Error")." ".$langs->trans("ClassNotFound").' '.$classname; - return ""; - } - } else { - print $langs->trans("ErrorNumberingModuleNotSetup", $this->element); - return ""; - } - } - - /** - * Create a document onto disk according to template module. - * - * @param string $modele Force template to use ('' to not force) - * @param Translate $outputlangs object lang a utiliser pour traduction - * @param int<0,1> $hidedetails Hide details of lines - * @param int<0,1> $hidedesc Hide description - * @param int<0,1> $hideref Hide ref - * @param ?array $moreparams Array to provide more information - * @return int 0 if KO, 1 if OK - */ - public function generateDocument($modele, $outputlangs, $hidedetails = 0, $hidedesc = 0, $hideref = 0, $moreparams = null) - { - global $langs; - - $result = 0; - $includedocgeneration = 1; - - $langs->load("diffusionplans@diffusionplans"); - - if (!dol_strlen($modele)) { - $modele = 'standard_diffusioncontact'; - - if (!empty($this->model_pdf)) { - $modele = $this->model_pdf; - } elseif (getDolGlobalString('MYOBJECT_ADDON_PDF')) { - $modele = getDolGlobalString('MYOBJECT_ADDON_PDF'); - } - } - - $modelpath = "core/modules/diffusionplans/doc/"; - - if ($includedocgeneration && !empty($modele)) { - $result = $this->commonGenerateDocument($modelpath, $modele, $outputlangs, $hidedetails, $hidedesc, $hideref, $moreparams); - } - - return $result; - } - - /** - * Return validation test result for a field. - * Need MAIN_ACTIVATE_VALIDATION_RESULT to be called. - * - * @param array|string,position:int,notnull?:int,visible:int<-2,5>|string,noteditable?:int<0,1>,default?:int<0,1>|string,index?:int,foreignkey?:string,searchall?:int<0,1>,isameasure?:int<0,1>,css?:string,csslist?:string,help?:string,showoncombobox?:int<0,2>,disabled?:int<0,1>,arrayofkeyval?:array,comment?:string,validate?:int<0,1>}> $fields Array of properties of field to show - * @param string $fieldKey Key of attribute - * @param string $fieldValue value of attribute - * @return bool Return false if fail, true on success, set $this->error for error message - */ - public function validateField($fields, $fieldKey, $fieldValue) - { - // Add your own validation rules here. - // ... - - return parent::validateField($fields, $fieldKey, $fieldValue); - } - - /** - * Action executed by scheduler - * CAN BE A CRON TASK. In such a case, parameters come from the schedule job setup field 'Parameters' - * Use public function doScheduledJob($param1, $param2, ...) to get parameters - * - * @return int 0 if OK, <>0 if KO (this function is used also by cron so only 0 is OK) - */ - public function doScheduledJob() - { - //global $conf, $langs; - - //$conf->global->SYSLOG_FILE = 'DOL_DATA_ROOT/dolibarr_mydedicatedlogfile.log'; - - $error = 0; - $this->output = ''; - $this->error = ''; - - dol_syslog(__METHOD__." start", LOG_INFO); - - $now = dol_now(); - - $this->db->begin(); - - // ... - - $this->db->commit(); - - dol_syslog(__METHOD__." end", LOG_INFO); - - return $error; - } -} - - -require_once DOL_DOCUMENT_ROOT.'/core/class/commonobjectline.class.php'; - -/** - * Class DiffusionContactLine. You can also remove this and generate a CRUD class for lines objects. - */ -class DiffusionContactLine extends CommonObjectLine -{ - // To complete with content of an object DiffusionContactLine - // We should have a field rowid, fk_diffusioncontact and position - - /** - * To overload - * @see CommonObjectLine - */ - public $parent_element = ''; // Example: '' or 'diffusioncontact' - - /** - * To overload - * @see CommonObjectLine - */ - public $fk_parent_attribute = ''; // Example: '' or 'fk_diffusioncontact' - - /** - * Constructor - * - * @param DoliDB $db Database handler - */ - public function __construct(DoliDB $db) - { - $this->db = $db; - - $this->isextrafieldmanaged = 0; - } -} + + * Copyright (C) 2023-2024 Frédéric France + * Copyright (C) 2025 Pierre Ardoin + * + * 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 class/diffusioncontact.class.php + * \ingroup diffusionplans + * \brief This file is a CRUD class file for DiffusionContact (Create/Read/Update/Delete) + */ + +// Put here all includes required by your class file +require_once DOL_DOCUMENT_ROOT.'/core/class/commonobject.class.php'; +require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php'; +//require_once DOL_DOCUMENT_ROOT . '/societe/class/societe.class.php'; +//require_once DOL_DOCUMENT_ROOT . '/product/class/product.class.php'; + +/** + * Class for DiffusionContact + */ +class DiffusionContact extends CommonObject +{ + /** + * @var string ID of module. + */ + public $module = 'diffusionplans'; + + /** + * @var string ID to identify managed object. + */ + public $element = 'diffusioncontact'; + + /** + * @var string Name of table without prefix where object is stored. This is also the key used for extrafields management (so extrafields know the link to the parent table). + */ + public $table_element = 'diffusionplans_diffusioncontact'; + + /** + * @var string If permission must be checkec with hasRight('diffusionplans', 'read') and not hasright('mymodyle', 'diffusioncontact', 'read'), you can uncomment this line + */ + //public $element_for_permission = 'diffusionplans'; + + /** + * @var string String with name of icon for diffusioncontact. Must be a 'fa-xxx' fontawesome code (or 'fa-xxx_fa_color_size') or 'diffusioncontact@diffusionplans' if picto is file 'img/object_diffusioncontact.png'. + */ + public $picto = 'fa-address-book'; + + + const STATUS_DRAFT = 0; + const STATUS_VALIDATED = 1; + const STATUS_CANCELED = 9; + + /** + * 'type' field format: + * 'integer', 'integer:ObjectClass:PathToClass[:AddCreateButtonOrNot[:Filter[:Sortfield]]]', + * 'select' (list of values are in 'options'. for integer list of values are in 'arrayofkeyval'), + * 'sellist:TableName:LabelFieldName[:KeyFieldName[:KeyFieldParent[:Filter[:CategoryIdType[:CategoryIdList[:SortField]]]]]]', + * 'chkbxlst:...', + * 'varchar(x)', + * 'text', 'text:none', 'html', + * 'double(24,8)', 'real', 'price', 'stock', + * 'date', 'datetime', 'timestamp', 'duration', + * 'boolean', 'checkbox', 'radio', 'array', + * 'mail', 'phone', 'url', 'password', 'ip' + * Note: Filter must be a Dolibarr Universal Filter syntax string. Example: "(t.ref:like:'SO-%') or (t.date_creation:<:'20160101') or (t.status:!=:0) or (t.nature:is:NULL)" + * 'length' the length of field. Example: 255, '24,8' + * 'label' the translation key. + * 'langfile' the key of the language file for translation. + * 'alias' the alias used into some old hard coded SQL requests + * 'picto' is code of a picto to show before value in forms + * 'enabled' is a condition when the field must be managed (Example: 1 or 'getDolGlobalInt("MY_SETUP_PARAM")' or 'isModEnabled("multicurrency")' ...) + * 'position' is the sort order of field. + * 'notnull' is set to 1 if not null in database. Set to -1 if we must set data to null if empty ('' or 0). + * 'visible' says if field is visible in list (Examples: 0=Not visible, 1=Visible on list and create/update/view forms, 2=Visible on list only, 3=Visible on create/update/view form only (not list), 4=Visible on list and update/view form (not create). 5=Visible on list and view form (not create/not update). 6=visible on list and update/view form (not update). Using a negative value means field is not shown by default on list but can be selected for viewing) + * 'noteditable' says if field is not editable (1 or 0) + * 'alwayseditable' says if field can be modified also when status is not draft ('1' or '0') + * 'default' is a default value for creation (can still be overwrote by the Setup of Default Values if field is editable in creation form). Note: If default is set to '(PROV)' and field is 'ref', the default value will be set to '(PROVid)' where id is rowid when a new record is created. + * 'index' if we want an index in database. + * 'foreignkey'=>'tablename.field' if the field is a foreign key (it is recommended to name the field fk_...). + * 'searchall' is 1 if we want to search in this field when making a search from the quick search button. + * 'isameasure' must be set to 1 or 2 if field can be used for measure. Field type must be summable like integer or double(24,8). Use 1 in most cases, or 2 if you don't want to see the column total into list (for example for percentage) + * 'css' and 'cssview' and 'csslist' is the CSS style to use on field. 'css' is used in creation and update. 'cssview' is used in view mode. 'csslist' is used for columns in lists. For example: 'css'=>'minwidth300 maxwidth500 widthcentpercentminusx', 'cssview'=>'wordbreak', 'csslist'=>'tdoverflowmax200' + * 'placeholder' to set the placeholder of a varchar field. + * 'help' and 'helplist' is a 'TranslationString' to use to show a tooltip on field. You can also use 'TranslationString:keyfortooltiponlick' for a tooltip on click. + * 'showoncombobox' if value of the field must be visible into the label of the combobox that list record + * 'disabled' is 1 if we want to have the field locked by a 'disabled' attribute. In most cases, this is never set into the definition of $fields into class, but is set dynamically by some part of code like the constructor of the class. + * 'arrayofkeyval' to set a list of values if type is a list of predefined values. For example: array("0"=>"Draft","1"=>"Active","-1"=>"Cancel"). Note that type can be 'integer' or 'varchar' + * 'autofocusoncreate' to have field having the focus on a create form. Only 1 field should have this property set to 1. + * 'comment' is not used. You can store here any text of your choice. It is not used by application. + * 'validate' is 1 if you need to validate the field with $this->validateField(). Need MAIN_ACTIVATE_VALIDATION_RESULT. + * 'copytoclipboard' is 1 or 2 to allow to add a picto to copy value into clipboard (1=picto after label, 2=picto after value) + * + * Note: To have value dynamic, you can set value to 0 in definition and edit the value on the fly into the constructor. + */ + + // BEGIN MODULEBUILDER PROPERTIES + /** + * @inheritdoc + * Array with all fields and their property. Do not use it as a static var. It may be modified by constructor. + */ + public $fields = array( + "rowid" => array("type" => "integer", "label" => "TechnicalID", "enabled" => "1", 'position' => 1, 'notnull' => 1, "visible" => "0", "noteditable" => "1", "index" => "1", "css" => "left", "comment" => "Id"), + "fk_contact" => array("type" => "integer", "label" => "fk_contact", "enabled" => "1", 'position' => 2, 'notnull' => 0, "visible" => "0",), + "fk_diffusion" => array("type" => "integer", "label" => "fk_diffusion", "enabled" => "1", 'position' => 1, 'notnull' => 0, "visible" => "0",), + "contact_source" => array("type" => "varchar(128)", "label" => "ContactSource", "enabled" => "1", 'position' => 2, 'notnull' => 1, "visible" => "0"), + "mail_status" => array("type" => "integer", "label" => "method_mail", "enabled" => "1", 'position' => 3, 'notnull' => 1, "visible" => "0", "default" => "0", "arrayofkeyval" => array("0" => "Désactivé", "1" => "Actif"),), + "letter_status" => array("type" => "integer", "label" => "method_letter", "enabled" => "1", 'position' => 4, 'notnull' => 1, "visible" => "0", "default" => "0", "arrayofkeyval" => array("0" => "Désactivé", "1" => "Actif"),), + "hand_status" => array("type" => "integer", "label" => "method_hand", "enabled" => "1", 'position' => 5, 'notnull' => 1, "visible" => "0", "default" => "0", "arrayofkeyval" => array("0" => "Désactivé", "1" => "Actif"),), + "fk_user_modif" => array("type" => "integer:user:user/class/user.class.php", "label" => "UserModif", "enabled" => "1", 'position' => 511, 'notnull' => 0, "visible" => "0",), + ); + public $rowid; + public $fk_contact; + public $fk_diffusion; + public $contact_source; + public $mail_status; + public $letter_status; + public $hand_status; + public $fk_user_modif; + // END MODULEBUILDER PROPERTIES + + + // If this object has a subtable with lines + + // /** + // * @var string Name of subtable line + // */ + // public $table_element_line = 'diffusionplans_diffusioncontactline'; + + // /** + // * @var string Field with ID of parent key if this object has a parent + // */ + public $fk_element = 'fk_diffusion'; + + // /** + // * @var string Name of subtable class that manage subtable lines + // */ + // public $class_element_line = 'DiffusionContactline'; + + // /** + // * @var array List of child tables. To test if we can delete object. + // */ + // protected $childtables = array('mychildtable' => array('name'=>'DiffusionContact', 'fk_element'=>'fk_diffusioncontact')); + + // /** + // * @var array List of child tables. To know object to delete on cascade. + // * If name matches '@ClassNAme:FilePathClass;ParentFkFieldName' it will + // * call method deleteByParentField(parentId, ParentFkFieldName) to fetch and delete child object + // */ + // protected $childtablesoncascade = array('diffusionplans_diffusioncontactdet'); + + // /** + // * @var DiffusionContactLine[] Array of subtable lines + // */ + // public $lines = array(); + + + + /** + * Constructor + * + * @param DoliDB $db Database handler + */ + public function __construct(DoliDB $db) + { + global $conf, $langs; + + $this->db = $db; + $this->ismultientitymanaged = 0; + $this->isextrafieldmanaged = 1; + + $entity = !empty($conf->entity) ? (int) $conf->entity : 1; + + if (!isset($conf->diffusionplans) || !is_object($conf->diffusionplans)) { + $conf->diffusionplans = new stdClass(); + } + + if (empty($conf->diffusionplans->dir_output)) { + $conf->diffusionplans->dir_output = DOL_DATA_ROOT.($entity > 1 ? '/'.$entity : '').'/diffusionplans'; + } + + if (empty($conf->diffusionplans->multidir_output) || !is_array($conf->diffusionplans->multidir_output)) { + $conf->diffusionplans->multidir_output = array(); + } + + if (empty($conf->diffusionplans->multidir_output[$entity])) { + $conf->diffusionplans->multidir_output[$entity] = $conf->diffusionplans->dir_output; + } + + if (!isset($conf->diffusioncontact) || !is_object($conf->diffusioncontact)) { + $conf->diffusioncontact = new stdClass(); + } + + if (empty($conf->diffusioncontact->dir_output)) { + $conf->diffusioncontact->dir_output = $conf->diffusionplans->dir_output.'/diffusioncontact'; + } + + if (empty($conf->diffusioncontact->multidir_output) || !is_array($conf->diffusioncontact->multidir_output)) { + $conf->diffusioncontact->multidir_output = array(); + } + + if (empty($conf->diffusioncontact->multidir_output[$entity])) { + $conf->diffusioncontact->multidir_output[$entity] = $conf->diffusioncontact->dir_output; + } + + $this->modulepart = 'diffusioncontact'; + $this->dir_output = $conf->diffusioncontact->multidir_output[$entity]; + + if (!empty($this->dir_output)) { + dol_mkdir($this->dir_output); + } + + if (!getDolGlobalInt('MAIN_SHOW_TECHNICAL_ID') && isset($this->fields['rowid']) && !empty($this->fields['ref'])) { + $this->fields['rowid']['visible'] = 0; + } + if (!isModEnabled('multicompany') && isset($this->fields['entity'])) { + $this->fields['entity']['enabled'] = 0; + } + + // Example to show how to set values of fields definition dynamically + /*if ($user->hasRight('diffusionplans', 'diffusioncontact', 'read')) { + $this->fields['myfield']['visible'] = 1; + $this->fields['myfield']['noteditable'] = 0; + }*/ + + // Unset fields that are disabled + foreach ($this->fields as $key => $val) { + if (isset($val['enabled']) && empty($val['enabled'])) { + unset($this->fields[$key]); + } + } + + // Translate some data of arrayofkeyval + if (is_object($langs)) { + foreach ($this->fields as $key => $val) { + if (!empty($val['arrayofkeyval']) && is_array($val['arrayofkeyval'])) { + foreach ($val['arrayofkeyval'] as $key2 => $val2) { + $this->fields[$key]['arrayofkeyval'][$key2] = $langs->trans($val2); + } + } + } + } + } + + /** + * Create object into database + * + * @param int<0,1> $notrigger 0=launch triggers after, 1=disable triggers + * @return int<-1,max> Return integer <0 if KO, Id of created object if OK + */ + public function create($notrigger = 0) + { + return $this->syncLink($this->fk_diffusion, $this->fk_contact, $this->contact_source, $notrigger); + } + + /** + * FR: Synchronise (crée si nécessaire) le lien entre une diffusion et un contact. + * EN: Synchronise (create if required) the link between a diffusion and a contact. + * + * @param int $diffusionId Diffusion identifier + * @param int $contactId Contact identifier + * @param string $source Source flag (internal/external) + * @param int<0,1> $notrigger 0 to execute triggers, 1 to skip them + * @return int<-1,1> >0 if OK, <0 if KO + */ + public function syncLink($diffusionId, $contactId, $source, $notrigger = 0) + { + global $langs, $user, $conf; + + $diffusionId = (int) $diffusionId; + $contactId = (int) $contactId; + $source = strtolower((string) $source); + $source = preg_replace('/[^a-z0-9_]/', '', $source); + + if ($diffusionId <= 0 || $contactId <= 0 || empty($source)) { + $this->error = $langs->trans('DiffusionContactSyncError'); + + return -1; + } + + $this->db->begin(); + + $sql = 'SELECT rowid FROM '.MAIN_DB_PREFIX.'diffusionplans_diffusioncontact'; + $sql .= ' WHERE fk_diffusion = '.$diffusionId; + $sql .= ' AND fk_contact = '.$contactId; + $sql .= " AND contact_source = '".$this->db->escape($source)."'"; + + dol_syslog(__METHOD__." fetch existing link sql=".$sql, LOG_DEBUG); + $resql = $this->db->query($sql); + if (!$resql) { + $this->error = $this->db->lasterror(); + $this->db->rollback(); + + return -1; + } + + $existing = $this->db->fetch_object($resql); + $this->db->free($resql); + + if ($existing) { + $this->id = (int) $existing->rowid; + + $updateSql = 'UPDATE '.MAIN_DB_PREFIX.'diffusionplans_diffusioncontact'; + $updateSql .= ' SET fk_user_modif = '.((int) $user->id); + $updateSql .= ' WHERE rowid = '.$this->id; + + dol_syslog(__METHOD__." update existing link sql=".$updateSql, LOG_DEBUG); + if (!$this->db->query($updateSql)) { + $this->error = $this->db->lasterror(); + $this->db->rollback(); + + return -1; + } + + $this->db->commit(); + + return 1; + } + + $insertSql = 'INSERT INTO '.MAIN_DB_PREFIX.'diffusionplans_diffusioncontact'; + $insertSql .= ' (fk_diffusion, fk_contact, contact_source, mail_status, letter_status, hand_status, fk_user_modif)'; + $insertSql .= ' VALUES ('; + $insertSql .= $diffusionId.','; + $insertSql .= $contactId.", '".$this->db->escape($source)."',"; + $insertSql .= ' 0, 0, 0,'; + $insertSql .= (int) $user->id; + $insertSql .= ')'; + + dol_syslog(__METHOD__." insert link sql=".$insertSql, LOG_DEBUG); + if (!$this->db->query($insertSql)) { + $this->error = $this->db->lasterror(); + $this->db->rollback(); + + return -1; + } + + $this->id = (int) $this->db->last_insert_id(MAIN_DB_PREFIX.'diffusionplans_diffusioncontact'); + + if (!$notrigger) { + include_once DOL_DOCUMENT_ROOT.'/core/class/interfaces.class.php'; + $interface = new Interfaces($this->db); + $result = $interface->run_triggers('DIFFUSIONCONTACT_INSERT', $this, $user, $langs, $conf); + if ($result < 0) { + $this->error = $langs->trans('ErrorCallingTrigger'); + $this->db->rollback(); + + return -1; + } + } + + $this->db->commit(); + + return 1; + } + + /** + * FR: Récupère les liens de contacts d'une diffusion pour alimenter l'affichage et le PDF. + * EN: Retrieve diffusion contact links to feed the user interface and the PDF. + * + * @param int $diffusionId Diffusion identifier + * @return array> + */ + public function fetchDiffusionContactLinks($diffusionId) + { + $diffusionId = (int) $diffusionId; + $result = array(); + + if ($diffusionId <= 0) { + return $result; + } + + // FR: Construit la requête à partir de la table dédiée aux diffusions pour suivre l'état exact des liens. + // EN: Build the query from the dedicated diffusion table to mirror the exact state of the links. + $sql = 'SELECT'; + $sql .= ' dc.rowid as link_rowid,'; + $sql .= ' dc.fk_contact,'; + $sql .= ' dc.contact_source,'; + $sql .= ' dc.mail_status,'; + $sql .= ' dc.letter_status,'; + $sql .= ' dc.hand_status,'; + $sql .= ' ec.position,'; + $sql .= ' ec.fk_c_type_contact,'; + $sql .= ' ctc.libelle as type_label,'; + $sql .= ' ctc.code as type_code,'; + $sql .= ' u.firstname as user_firstname,'; + $sql .= ' u.lastname as user_lastname,'; + $sql .= ' u.login as user_login,'; + $sql .= ' u.email as user_email,'; + $sql .= ' u.office_phone as user_office_phone,'; + $sql .= ' u.user_mobile as user_mobile,'; + $sql .= ' sp.firstname as contact_firstname,'; + $sql .= ' sp.lastname as contact_lastname,'; + $sql .= ' sp.email as contact_email,'; + $sql .= ' sp.phone_pro as contact_phone_pro,'; + $sql .= ' sp.phone_perso as contact_phone_perso,'; + $sql .= ' sp.phone_mobile as contact_phone_mobile,'; + $sql .= ' sp.fk_soc as contact_fk_soc,'; + $sql .= ' s.nom as company_name'; + $sql .= ' FROM '.MAIN_DB_PREFIX.'diffusionplans_diffusioncontact as dc'; + $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."element_contact as ec ON ec.element = 'diffusion'"; + $sql .= ' AND ec.fk_element = dc.fk_diffusion'; + $sql .= " AND ((dc.contact_source = 'internal' AND ec.source = 'internal' AND ec.fk_user = dc.fk_contact)"; + $sql .= " OR (dc.contact_source = 'external' AND ec.source = 'external' AND ec.fk_socpeople = dc.fk_contact))"; + $sql .= ' LEFT JOIN '.MAIN_DB_PREFIX.'c_type_contact as ctc ON ec.fk_c_type_contact = ctc.rowid'; + $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."user as u ON (dc.contact_source = 'internal' AND u.rowid = dc.fk_contact)"; + $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."socpeople as sp ON (dc.contact_source = 'external' AND sp.rowid = dc.fk_contact)"; + $sql .= ' LEFT JOIN '.MAIN_DB_PREFIX.'societe as s ON sp.fk_soc = s.rowid'; + $sql .= ' WHERE dc.fk_diffusion = ' . $diffusionId; + $sql .= ' ORDER BY COALESCE(ec.position, dc.rowid), dc.rowid'; + + $resql = $this->db->query($sql); + if (!$resql) { + dol_syslog(__METHOD__.' sql='.$sql.' '.$this->db->lasterror(), LOG_ERR); + + return $result; + } + + while ($obj = $this->db->fetch_object($resql)) { + // FR: Construit un tableau associatif fidèle aux informations disponibles côté fiche diffusion. + // EN: Build an associative array consistent with the data displayed on the diffusion card. + $result[] = array( + 'rowid' => isset($obj->link_rowid) ? (int) $obj->link_rowid : 0, + 'fk_contact' => isset($obj->fk_contact) ? (int) $obj->fk_contact : 0, + 'contact_source' => !empty($obj->contact_source) ? (string) $obj->contact_source : '', + 'fk_c_type_contact' => isset($obj->fk_c_type_contact) ? (int) $obj->fk_c_type_contact : null, + 'type_label' => !empty($obj->type_label) ? (string) $obj->type_label : '', + 'type_code' => !empty($obj->type_code) ? (string) $obj->type_code : '', + 'position' => isset($obj->position) ? (int) $obj->position : null, + 'mail_status' => isset($obj->mail_status) ? (int) $obj->mail_status : 0, + 'letter_status' => isset($obj->letter_status) ? (int) $obj->letter_status : 0, + 'hand_status' => isset($obj->hand_status) ? (int) $obj->hand_status : 0, + 'user_firstname' => !empty($obj->user_firstname) ? (string) $obj->user_firstname : '', + 'user_lastname' => !empty($obj->user_lastname) ? (string) $obj->user_lastname : '', + 'user_login' => !empty($obj->user_login) ? (string) $obj->user_login : '', + 'user_email' => !empty($obj->user_email) ? (string) $obj->user_email : '', + 'user_office_phone' => !empty($obj->user_office_phone) ? (string) $obj->user_office_phone : '', + 'user_mobile' => !empty($obj->user_mobile) ? (string) $obj->user_mobile : '', + 'contact_firstname' => !empty($obj->contact_firstname) ? (string) $obj->contact_firstname : '', + 'contact_lastname' => !empty($obj->contact_lastname) ? (string) $obj->contact_lastname : '', + 'contact_email' => !empty($obj->contact_email) ? (string) $obj->contact_email : '', + 'contact_phone_pro' => !empty($obj->contact_phone_pro) ? (string) $obj->contact_phone_pro : '', + 'contact_phone_perso' => !empty($obj->contact_phone_perso) ? (string) $obj->contact_phone_perso : '', + 'contact_phone_mobile' => !empty($obj->contact_phone_mobile) ? (string) $obj->contact_phone_mobile : '', + 'contact_fk_soc' => isset($obj->contact_fk_soc) ? (int) $obj->contact_fk_soc : 0, + 'company_name' => !empty($obj->company_name) ? (string) $obj->company_name : '', + ); + } + + $this->db->free($resql); + + return $result; + } + + + public function removeLink($diffusionId, $contactId, $source, $notrigger = 0) + { + global $langs, $user, $conf; + + $diffusionId = (int) $diffusionId; + $contactId = (int) $contactId; + $source = strtolower((string) $source); + $source = preg_replace('/[^a-z0-9_]/', '', $source); + + if ($diffusionId <= 0 || $contactId <= 0 || empty($source)) { + $this->error = $langs->trans('DiffusionContactRemoveError'); + + return -1; + } + + $sql = 'DELETE FROM '.MAIN_DB_PREFIX."diffusionplans_diffusioncontact"; + $sql .= ' WHERE fk_diffusion = '.$diffusionId; + $sql .= ' AND fk_contact = '.$contactId; + $sql .= " AND contact_source = '".$this->db->escape($source)."'"; + + dol_syslog(__METHOD__." delete link sql=".$sql, LOG_DEBUG); + if (!$this->db->query($sql)) { + $this->error = $this->db->lasterror(); + + return -1; + } + + if (!$notrigger) { + include_once DOL_DOCUMENT_ROOT.'/core/class/interfaces.class.php'; + $interface = new Interfaces($this->db); + $result = $interface->run_triggers('DIFFUSIONCONTACT_DELETELINE', $this, $user, $langs, $conf); + if ($result < 0) { + $this->error = $langs->trans('ErrorCallingTrigger'); + + return -1; + } + } + + return 1; + } + + /** + * Clone an object into another one + * + * @param User $user User that creates + * @param int $fromid Id of object to clone + * @return self|int<-1,-1> New object created, <0 if KO + */ + public function createFromClone(User $user, $fromid) + { + global $langs, $extrafields; + $error = 0; + + dol_syslog(__METHOD__, LOG_DEBUG); + + $object = new self($this->db); + + $this->db->begin(); + + // Load source object + $result = $object->fetchCommon($fromid); + if ($result > 0 && !empty($object->table_element_line)) { + $object->fetchLines(); + } + + // get lines so they will be clone + //foreach($this->lines as $line) + // $line->fetch_optionals(); + + // Reset some properties + unset($object->id); + unset($object->fk_user_creat); + unset($object->import_key); + + // Clear fields + if (property_exists($object, 'ref')) { + $object->ref = empty($this->fields['ref']['default']) ? "Copy_Of_".$object->ref : $this->fields['ref']['default']; + } + if (property_exists($object, 'label')) { + $object->label = empty($this->fields['label']['default']) ? $langs->trans("CopyOf")." ".$object->label : $this->fields['label']['default']; + } + if (property_exists($object, 'status')) { + $object->status = self::STATUS_DRAFT; + } + if (property_exists($object, 'date_creation')) { + $object->date_creation = dol_now(); + } + if (property_exists($object, 'date_modification')) { + $object->date_modification = null; + } + // ... + // Clear extrafields that are unique + if (is_array($object->array_options) && count($object->array_options) > 0) { + $extrafields->fetch_name_optionals_label($this->table_element); + foreach ($object->array_options as $key => $option) { + $shortkey = preg_replace('/options_/', '', $key); + if (!empty($extrafields->attributes[$this->table_element]['unique'][$shortkey])) { + //var_dump($key); + //var_dump($clonedObj->array_options[$key]); exit; + unset($object->array_options[$key]); + } + } + } + + // Create clone + $object->context['createfromclone'] = 'createfromclone'; + $result = $object->createCommon($user); + if ($result < 0) { + $error++; + $this->setErrorsFromObject($object); + } + + if (!$error) { + // copy internal contacts + if ($this->copy_linked_contact($object, 'internal') < 0) { + $error++; + } + } + + if (!$error) { + // copy external contacts if same company + if (!empty($object->socid) && property_exists($this, 'fk_soc') && $this->fk_soc == $object->socid) { + if ($this->copy_linked_contact($object, 'external') < 0) { + $error++; + } + } + } + + unset($object->context['createfromclone']); + + // End + if (!$error) { + $this->db->commit(); + return $object; + } else { + $this->db->rollback(); + return -1; + } + } + + /** + * Load object in memory from the database + * + * @param int $id Id object + * @param string $ref Ref + * @param int<0,1> $noextrafields 0=Default to load extrafields, 1=No extrafields + * @param int<0,1> $nolines 0=Default to load extrafields, 1=No extrafields + * @return int<-1,1> Return integer <0 if KO, 0 if not found, >0 if OK + */ + public function fetch() + { + global $langs, $user, $conf, $object, $entry; + + $element = "diffusioncontact"; + $table_element = "diffusionplans_diffusioncontact"; + $module = "diffusionplans"; + + $this->db->begin(); + + $sql = "SELECT * FROM `".MAIN_DB_PREFIX."diffusionplans_diffusioncontact`" ; + $sql.= " WHERE `fk_contact`='".$entry->contact_id."'"; + $sql.= " AND `fk_diffusion`='".$object->id."'"; + $sql.= " AND `contact_source`='".$entry->source."'"; + + //var_dump($sql); + + dol_syslog("DiffusionContact::fetch sql=".$sql); + + $resql = $this->db->query($sql); + + if ($resql = 1) + { + $num = $this->db->num_rows($resql); + $i = 0; + + //var_dump($num); + + if ($num) + { + while ($i < $num) + { + $obj = $this->db->fetch_object($resql); + + //var_dump($obj); + + $this->lines[$i] = $obj; + $this->lines[$i]->id = trim($obj->rowid); + $this->lines[$i]->mail_status = trim($obj->mail_status); + $this->lines[$i]->letter_status = trim($obj->letter_status); + $this->lines[$i]->hand_status = trim($obj->hand_status); + $i++; + } + } + + $result = array( + 'id' => $this->lines[0]->id, + 'module' => $module, + 'element'=> $element, + 'table_element' =>$table_element, + 'fields' => $object->fields, + 'diffusion' => $object->id, + 'mail_status' => $this->lines[0]->mail_status, + 'letter_status' => $this->lines[0]->letter_status, + 'hand_status'=> $this->lines[0]->hand_status, + + ); + + return $result; + } + else + { + $this->error = $this->db->error()." sql=".$sql; + return -1; + } + + //$result = $this->fetchCommon($id, $ref, '', $noextrafields); + //if ($result > 0 && !empty($this->table_element_line) && empty($nolines)) { + // $this->fetchLines($noextrafields); + //} + //return $result; + } + + /** + * Load object lines in memory from the database + * + * @param int<0,1> $noextrafields 0=Default to load extrafields, 1=No extrafields + * @return int<-1,1> Return integer <0 if KO, 0 if not found, >0 if OK + */ + public function fetchLines($noextrafields = 0) + { + $this->lines = array(); + + $result = $this->fetchLinesCommon('', $noextrafields); + return $result; + } + + + /** + * Load list of objects in memory from the database. + * Using a fetchAll() with limit = 0 is a very bad practice. Instead try to forge yourself an optimized SQL request with + * your own loop with start and stop pagination. + * + * @param string $sortorder Sort Order + * @param string $sortfield Sort field + * @param int<0,max> $limit Limit the number of lines returned + * @param int<0,max> $offset Offset + * @param string $filter Filter as an Universal Search string. + * Example: '((client:=:1) OR ((client:>=:2) AND (client:<=:3))) AND (client:!=:8) AND (nom:like:'a%')' + * @param string $filtermode No longer used + * @return array|int<-1,-1> <0 if KO, array of pages if OK + */ + public function fetchAll($sortorder = '', $sortfield = '', $limit = 1000, $offset = 0, string $filter = '', $filtermode = 'AND') + { + dol_syslog(__METHOD__, LOG_DEBUG); + + $records = array(); + + $sql = "SELECT "; + $sql.= $this->getFieldList('t'); + $sql.= " FROM ".$this->db->prefix().$this->table_element." as t"; + if (isset($this->isextrafieldmanaged) && $this->isextrafieldmanaged == 1) { + $sql.= " LEFT JOIN ".$this->db->prefix().$this->table_element."_extrafields as te ON te.fk_object = t.rowid"; + } + if (isset($this->ismultientitymanaged) && $this->ismultientitymanaged == 1) { + $sql.= " WHERE t.entity IN (".getEntity($this->element).")"; + } else { + $sql.= " WHERE 1 = 1"; + } + + // Manage filter + $errormessage = ''; + $sql.= forgeSQLFromUniversalSearchCriteria($filter, $errormessage); + if ($errormessage) { + $this->errors[] = $errormessage; + dol_syslog(__METHOD__.' '.implode(',', $this->errors), LOG_ERR); + return -1; + } + + if (!empty($sortfield)) { + $sql.= $this->db->order($sortfield, $sortorder); + } + if (!empty($limit)) { + $sql.= $this->db->plimit($limit, $offset); + } + + $resql = $this->db->query($sql); + if ($resql) { + $num = $this->db->num_rows($resql); + $i = 0; + while ($i < ($limit ? min($limit, $num) : $num)) { + $obj = $this->db->fetch_object($resql); + + $record = new self($this->db); + $record->setVarsFromFetchObj($obj); + + if (!empty($record->isextrafieldmanaged)) { + $record->fetch_optionals(); + } + + $records[$record->id] = $record; + + $i++; + } + $this->db->free($resql); + + return $records; + } else { + $this->errors[] = 'Error '.$this->db->lasterror(); + dol_syslog(__METHOD__.' '.implode(',', $this->errors), LOG_ERR); + + return -1; + } + } + + /** + * Update object into database + * + * @param User $user User that modifies + * @param int<0,1> $notrigger 0=launch triggers after, 1=disable triggers + * @return int<-1,1> Return integer <0 if KO, >0 if OK + */ + public function update(User $user, $notrigger = 0) + { + global $langs, $user, $conf, $object, $field, $value, $id, $db; + + $error = 0; + + dol_syslog(__METHOD__, LOG_DEBUG); + + $sql = "UPDATE ".MAIN_DB_PREFIX."$object->table_element" ; + $sql.= " SET ".$field." = ".(int) $value.""; + $sql.= " , fk_user_modif = ".$user->id; + $sql.= " WHERE rowid = ".(int) $id; + + dol_syslog("DiffusionContact::update sql=".$sql); + + $resql = $this->db->query($sql); + + if ($resql) + { + // Appel des triggers + include_once DOL_DOCUMENT_ROOT . '/core/class/interfaces.class.php'; + $interface=new Interfaces($db); + $result2=$interface->run_triggers('DIFFUSIONCONTACT_UPDATELINE',$this,$user,$langs,$conf); + if ($result2 < 0) { $error++; $db->errors=$interface->errors; } + // Fin appel triggers + + $db->commit(); + return $resql; + } + else + { + $db->error=$this->db->lasterror(); + dol_syslog("DiffusionContact::updateLine ".$this->error, LOG_ERR); + $db->rollback(); + + return -1; + } + + + //return $this->updateCommon($user, $notrigger); + } + + /** + * Delete object in database + * + * @param User $user User that deletes + * @param int<0,1> $notrigger 0=launch triggers, 1=disable triggers + * @return int<-1,1> Return integer <0 if KO, >0 if OK + */ + public function delete(User $user, $notrigger = 0) + { + //return $this->deleteCommon($user, $notrigger); + //return $this->deleteCommon($user, $notrigger, 1); + } + + /** + * Delete a line of object in database + * + * @param User $user User that delete + * @param int $idline Id of line to delete + * @param int<0,1> $notrigger 0=launch triggers after, 1=disable triggers + * @return int<-2,1> >0 if OK, <0 if KO + */ + public function deleteLine($notrigger = 0) + { + //if ($this->status < 0) { + // $this->error = 'ErrorDeleteLineNotAllowedByObjectStatus'; + // return -2; + //} + + global $langs, $object, $contactid; + + if (!empty($this->fk_diffusion) && !empty($this->fk_contact) && !empty($this->contact_source)) { + return $this->removeLink($this->fk_diffusion, $this->fk_contact, $this->contact_source, $notrigger); + } + + $source = GETPOST('source', 'aZ09'); + if (!empty($object->id) && !empty($contactid) && !empty($source)) { + return $this->removeLink($object->id, $contactid, $source, $notrigger); + } + + $this->error = $langs->trans('DiffusionContactRemoveError'); + + return -1; + } + + + /** + * Validate object + * + * @param User $user User making status change + * @param int<0,1> $notrigger 1=Does not execute triggers, 0= execute triggers + * @return int<-1,1> Return integer <=0 if OK, 0=Nothing done, >0 if KO + */ + public function validate($user, $notrigger = 0) + { + global $conf; + + require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php'; + + $error = 0; + + // Protection + if ($this->status == self::STATUS_VALIDATED) { + dol_syslog(get_class($this)."::validate action abandoned: already validated", LOG_WARNING); + return 0; + } + + /* if (! ((!getDolGlobalInt('MAIN_USE_ADVANCED_PERMS') && $user->hasRight('diffusionplans', 'diffusioncontact', 'write')) + || (getDolGlobalInt('MAIN_USE_ADVANCED_PERMS') && $user->hasRight('diffusionplans', 'diffusioncontact_advance', 'validate'))) + { + $this->error='NotEnoughPermissions'; + dol_syslog(get_class($this)."::valid ".$this->error, LOG_ERR); + return -1; + }*/ + + $now = dol_now(); + + $this->db->begin(); + + // 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 + $num = $this->getNextNumRef(); + } else { + $num = $this->ref; + } + $this->newref = $num; + + if (!empty($num)) { + // Validate + $sql = "UPDATE ".MAIN_DB_PREFIX.$this->table_element; + $sql .= " SET "; + if (!empty($this->fields['ref'])) { + $sql .= " ref = '".$this->db->escape($num)."',"; + } + $sql .= " status = ".self::STATUS_VALIDATED; + if (!empty($this->fields['date_validation'])) { + $sql .= ", date_validation = '".$this->db->idate($now)."'"; + } + if (!empty($this->fields['fk_user_valid'])) { + $sql .= ", fk_user_valid = ".((int) $user->id); + } + $sql .= " WHERE rowid = ".((int) $this->id); + + dol_syslog(get_class($this)."::validate()", LOG_DEBUG); + $resql = $this->db->query($sql); + if (!$resql) { + dol_print_error($this->db); + $this->error = $this->db->lasterror(); + $error++; + } + + if (!$error && !$notrigger) { + // Call trigger + $result = $this->call_trigger('MYOBJECT_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)) { + // Now we rename also files into index + $sql = 'UPDATE '.MAIN_DB_PREFIX."ecm_files set filename = CONCAT('".$this->db->escape($this->newref)."', SUBSTR(filename, ".(strlen($this->ref) + 1).")), filepath = 'diffusioncontact/".$this->db->escape($this->newref)."'"; + $sql .= " WHERE filename LIKE '".$this->db->escape($this->ref)."%' AND filepath = 'diffusioncontact/".$this->db->escape($this->ref)."' and entity = ".$conf->entity; + $resql = $this->db->query($sql); + if (!$resql) { + $error++; + $this->error = $this->db->lasterror(); + } + $sql = 'UPDATE '.MAIN_DB_PREFIX."ecm_files set filepath = 'diffusioncontact/".$this->db->escape($this->newref)."'"; + $sql .= " WHERE filepath = 'diffusioncontact/".$this->db->escape($this->ref)."' and entity = ".$conf->entity; + $resql = $this->db->query($sql); + if (!$resql) { + $error++; + $this->error = $this->db->lasterror(); + } + + // We rename directory ($this->ref = old ref, $num = new ref) in order not to lose the attachments + $oldref = dol_sanitizeFileName($this->ref); + $newref = dol_sanitizeFileName($num); + $dirsource = $conf->diffusionplans->dir_output.'/diffusioncontact/'.$oldref; + $dirdest = $conf->diffusionplans->dir_output.'/diffusioncontact/'.$newref; + if (!$error && file_exists($dirsource)) { + dol_syslog(get_class($this)."::validate() rename dir ".$dirsource." into ".$dirdest); + + if (@rename($dirsource, $dirdest)) { + dol_syslog("Rename ok"); + // Rename docs starting with $oldref with $newref + $listoffiles = dol_dir_list($conf->diffusionplans->dir_output.'/diffusioncontact/'.$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 = $num; + $this->status = self::STATUS_VALIDATED; + } + + if (!$error) { + $this->db->commit(); + return 1; + } else { + $this->db->rollback(); + return -1; + } + } + + + /** + * Set draft status + * + * @param User $user Object user that modify + * @param int<0,1> $notrigger 1=Does not execute triggers, 0=Execute triggers + * @return int<0,1> Return integer <0 if KO, >0 if OK + */ + public function setDraft($user, $notrigger = 0) + { + // Protection + if ($this->status <= self::STATUS_DRAFT) { + return 0; + } + + /* if (! ((!getDolGlobalInt('MAIN_USE_ADVANCED_PERMS') && $user->hasRight('diffusionplans','write')) + || (getDolGlobalInt('MAIN_USE_ADVANCED_PERMS') && $user->hasRight('diffusionplans','diffusionplans_advance','validate')))) + { + $this->error='Permission denied'; + return -1; + }*/ + + return $this->setStatusCommon($user, self::STATUS_DRAFT, $notrigger, 'DIFFUSIONPLANS_MYOBJECT_UNVALIDATE'); + } + + /** + * Set cancel status + * + * @param User $user Object user that modify + * @param int<0,1> $notrigger 1=Does not execute triggers, 0=Execute triggers + * @return int<-1,1> Return integer <0 if KO, 0=Nothing done, >0 if OK + */ + public function cancel($user, $notrigger = 0) + { + // Protection + if ($this->status != self::STATUS_VALIDATED) { + return 0; + } + + /* if (! ((!getDolGlobalInt('MAIN_USE_ADVANCED_PERMS') && $user->hasRight('diffusionplans','write')) + || (getDolGlobalInt('MAIN_USE_ADVANCED_PERMS') && $user->hasRight('diffusionplans','diffusionplans_advance','validate')))) + { + $this->error='Permission denied'; + return -1; + }*/ + + return $this->setStatusCommon($user, self::STATUS_CANCELED, $notrigger, 'DIFFUSIONPLANS_MYOBJECT_CANCEL'); + } + + /** + * Set back to validated status + * + * @param User $user Object user that modify + * @param int<0,1> $notrigger 1=Does not execute triggers, 0=Execute triggers + * @return int<-1,1> Return integer <0 if KO, 0=Nothing done, >0 if OK + */ + public function reopen($user, $notrigger = 0) + { + // Protection + if ($this->status == self::STATUS_VALIDATED) { + return 0; + } + + /*if (! ((!getDolGlobalInt('MAIN_USE_ADVANCED_PERMS') && $user->hasRight('diffusionplans','write')) + || (getDolGlobalInt('MAIN_USE_ADVANCED_PERMS') && $user->hasRight('diffusionplans','diffusionplans_advance','validate')))) + { + $this->error='Permission denied'; + return -1; + }*/ + + return $this->setStatusCommon($user, self::STATUS_VALIDATED, $notrigger, 'DIFFUSIONPLANS_MYOBJECT_REOPEN'); + } + + /** + * getTooltipContentArray + * + * @param array $params Params to construct tooltip data + * @since v18 + * @return array{optimize?:string,picto?:string,ref?:string} + */ + public function getTooltipContentArray($params) + { + global $langs; + + $datas = []; + + if (getDolGlobalInt('MAIN_OPTIMIZEFORTEXTBROWSER')) { + return ['optimize' => $langs->trans("ShowDiffusionContact")]; + } + $datas['picto'] = img_picto('', $this->picto).' '.$langs->trans("DiffusionContact").''; + if (isset($this->status)) { + $datas['picto'] .= ' '.$this->getLibStatut(5); + } + if (property_exists($this, 'ref')) { + $datas['ref'] = '
'.$langs->trans('Ref').': '.$this->ref; + } + if (property_exists($this, 'label')) { + $datas['ref'] = '
'.$langs->trans('Label').': '.$this->label; + } + + return $datas; + } + + /** + * Return a link to the object card (with optionally the picto) + * + * @param int $withpicto Include picto in link (0=No picto, 1=Include picto into link, 2=Only picto) + * @param string $option On what the link point to ('nolink', ...) + * @param int $notooltip 1=Disable tooltip + * @param string $morecss Add more css on link + * @param int $save_lastsearch_value -1=Auto, 0=No save of lastsearch_values when clicking, 1=Save lastsearch_values whenclicking + * @return string String with URL + */ + public function getNomUrl($withpicto = 0, $option = '', $notooltip = 0, $morecss = '', $save_lastsearch_value = -1) + { + global $conf, $langs, $hookmanager; + + if (!empty($conf->dol_no_mouse_hover)) { + $notooltip = 1; // Force disable tooltips + } + + $result = ''; + $params = [ + 'id' => $this->id, + 'objecttype' => $this->element.($this->module ? '@'.$this->module : ''), + 'option' => $option, + ]; + $classfortooltip = 'classfortooltip'; + $dataparams = ''; + if (getDolGlobalInt('MAIN_ENABLE_AJAX_TOOLTIP')) { + $classfortooltip = 'classforajaxtooltip'; + $dataparams = ' data-params="'.dol_escape_htmltag(json_encode($params)).'"'; + $label = ''; + } else { + $label = implode($this->getTooltipContentArray($params)); + } + + $url = dol_buildpath('/diffusionplans/diffusioncontact_card.php', 1).'?id='.$this->id; + + if ($option !== 'nolink') { + // Add param to save lastsearch_values or not + $add_save_lastsearch_values = ($save_lastsearch_value == 1 ? 1 : 0); + if ($save_lastsearch_value == -1 && isset($_SERVER["PHP_SELF"]) && preg_match('/list\.php/', $_SERVER["PHP_SELF"])) { + $add_save_lastsearch_values = 1; + } + if ($url && $add_save_lastsearch_values) { + $url .= '&save_lastsearch_values=1'; + } + } + + $linkclose = ''; + if (empty($notooltip)) { + if (getDolGlobalInt('MAIN_OPTIMIZEFORTEXTBROWSER')) { + $label = $langs->trans("ShowDiffusionContact"); + $linkclose .= ' alt="'.dolPrintHTMLForAttribute($label).'"'; + } + $linkclose .= ($label ? ' title="'.dolPrintHTMLForAttribute($label).'"' : ' title="tocomplete"'); + $linkclose .= $dataparams.' class="'.$classfortooltip.($morecss ? ' '.$morecss : '').'"'; + } else { + $linkclose = ($morecss ? ' class="'.$morecss.'"' : ''); + } + + if ($option == 'nolink' || empty($url)) { + $linkstart = ''; + if ($option == 'nolink' || empty($url)) { + $linkend = ''; + } else { + $linkend = ''; + } + + $result .= $linkstart; + + if (empty($this->showphoto_on_popup)) { + if ($withpicto) { + $result .= img_object(($notooltip ? '' : $label), ($this->picto ? $this->picto : 'generic'), (($withpicto != 2) ? 'class="paddingright"' : ''), 0, 0, $notooltip ? 0 : 1); + } + } else { + if ($withpicto) { + require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php'; + + list($class, $module) = explode('@', $this->picto); + $upload_dir = $conf->$module->multidir_output[$conf->entity]."/$class/".dol_sanitizeFileName($this->ref); + $filearray = dol_dir_list($upload_dir, "files"); + $filename = $filearray[0]['name']; + if (!empty($filename)) { + $pospoint = strpos($filearray[0]['name'], '.'); + + $pathtophoto = $class.'/'.$this->ref.'/thumbs/'.substr($filename, 0, $pospoint).'_mini'.substr($filename, $pospoint); + if (!getDolGlobalString(strtoupper($module.'_'.$class).'_FORMATLISTPHOTOSASUSERS')) { + $result .= '
No photo
'; + } else { + $result .= '
No photo
'; + } + + $result .= ''; + } else { + $result .= img_object(($notooltip ? '' : $label), ($this->picto ? $this->picto : 'generic'), ($notooltip ? (($withpicto != 2) ? 'class="paddingright"' : '') : 'class="'.(($withpicto != 2) ? 'paddingright ' : '').'"'), 0, 0, $notooltip ? 0 : 1); + } + } + } + + if ($withpicto != 2) { + $result .= $this->ref; + } + + $result .= $linkend; + //if ($withpicto != 2) $result.=(($addlabel && $this->label) ? $sep . dol_trunc($this->label, ($addlabel > 1 ? $addlabel : 0)) : ''); + + global $action, $hookmanager; + $hookmanager->initHooks(array($this->element.'dao')); + $parameters = array('id' => $this->id, 'getnomurl' => &$result); + $reshook = $hookmanager->executeHooks('getNomUrl', $parameters, $this, $action); // Note that $action and $object may have been modified by some hooks + if ($reshook > 0) { + $result = $hookmanager->resPrint; + } else { + $result .= $hookmanager->resPrint; + } + + return $result; + } + + /** + * Return a thumb for kanban views + * + * @param string $option Where point the link (0=> main card, 1,2 => shipment, 'nolink'=>No link) + * @param ?array $arraydata Array of data + * @return string HTML Code for Kanban thumb. + */ + public function getKanbanView($option = '', $arraydata = null) + { + global $conf, $langs; + + $selected = (empty($arraydata['selected']) ? 0 : $arraydata['selected']); + + $return = '
'; + $return .= '
'; + $return .= ''; + $return .= img_picto('', $this->picto); + $return .= ''; + $return .= '
'; + $return .= ''.(method_exists($this, 'getNomUrl') ? $this->getNomUrl() : $this->ref).''; + if ($selected >= 0) { + $return .= ''; + } + if (property_exists($this, 'label')) { + $return .= '
'.$this->label.'
'; + } + if (property_exists($this, 'thirdparty') && is_object($this->thirdparty)) { + $return .= '
'.$this->thirdparty->getNomUrl(1).'
'; + } + if (property_exists($this, 'amount')) { + $return .= '
'; + $return .= ''.price($this->amount, 0, $langs, 1, -1, -1, $conf->currency).''; + } + if (method_exists($this, 'getLibStatut')) { + $return .= '
'.$this->getLibStatut(3).'
'; + } + $return .= '
'; + $return .= '
'; + $return .= '
'; + + return $return; + } + + /** + * Return the label of the status + * + * @param int<0,6> $mode 0=long label, 1=short label, 2=Picto + short label, 3=Picto, 4=Picto + long label, 5=Short label + Picto, 6=Long label + Picto + * @return string Label of status + */ + public function getLabelStatus($mode = 0) + { + return $this->LibStatut($this->status, $mode); + } + + /** + * Return the label of the status + * + * @param int<0,6> $mode 0=long label, 1=short label, 2=Picto + short label, 3=Picto, 4=Picto + long label, 5=Short label + Picto, 6=Long label + Picto + * @return string Label of status + */ + public function getLibStatut($mode = 0) + { + return $this->LibStatut($this->status, $mode); + } + + // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps + /** + * Return the label of a given status + * + * @param int $status Id status + * @param int<0,6> $mode 0=long label, 1=short label, 2=Picto + short label, 3=Picto, 4=Picto + long label, 5=Short label + Picto, 6=Long label + Picto + * @return string Label of status + */ + public function LibStatut($status, $mode = 0) + { + // phpcs:enable + if (is_null($status)) { + return ''; + } + + if (empty($this->labelStatus) || empty($this->labelStatusShort)) { + global $langs; + //$langs->load("diffusionplans@diffusionplans"); + $this->labelStatus[self::STATUS_DRAFT] = $langs->transnoentitiesnoconv('Draft'); + $this->labelStatus[self::STATUS_VALIDATED] = $langs->transnoentitiesnoconv('Enabled'); + $this->labelStatus[self::STATUS_CANCELED] = $langs->transnoentitiesnoconv('Disabled'); + $this->labelStatusShort[self::STATUS_DRAFT] = $langs->transnoentitiesnoconv('Draft'); + $this->labelStatusShort[self::STATUS_VALIDATED] = $langs->transnoentitiesnoconv('Enabled'); + $this->labelStatusShort[self::STATUS_CANCELED] = $langs->transnoentitiesnoconv('Disabled'); + } + + $statusType = 'status'.$status; + //if ($status == self::STATUS_VALIDATED) $statusType = 'status1'; + if ($status == self::STATUS_CANCELED) { + $statusType = 'status6'; + } + + return dolGetStatus($this->labelStatus[$status], $this->labelStatusShort[$status], '', $statusType, $mode); + } + + /** + * Load the info information in the object + * + * @param int $id Id of object + * @return void + */ + public function info($id) + { + $sql = "SELECT rowid,"; + $sql .= " date_creation as datec, tms as datem"; + if (!empty($this->fields['date_validation'])) { + $sql .= ", date_validation as datev"; + } + if (!empty($this->fields['fk_user_creat'])) { + $sql .= ", fk_user_creat"; + } + if (!empty($this->fields['fk_user_modif'])) { + $sql .= ", fk_user_modif"; + } + if (!empty($this->fields['fk_user_valid'])) { + $sql .= ", fk_user_valid"; + } + $sql .= " FROM ".MAIN_DB_PREFIX.$this->table_element." as t"; + $sql .= " WHERE t.rowid = ".((int) $id); + + $result = $this->db->query($sql); + if ($result) { + if ($this->db->num_rows($result)) { + $obj = $this->db->fetch_object($result); + + $this->id = $obj->rowid; + + if (!empty($this->fields['fk_user_creat'])) { + $this->user_creation_id = $obj->fk_user_creat; + } + if (!empty($this->fields['fk_user_modif'])) { + $this->user_modification_id = $obj->fk_user_modif; + } + if (!empty($this->fields['fk_user_valid'])) { + $this->user_validation_id = $obj->fk_user_valid; + } + $this->date_creation = $this->db->jdate($obj->datec); + $this->date_modification = empty($obj->datem) ? '' : $this->db->jdate($obj->datem); + if (!empty($obj->datev)) { + $this->date_validation = empty($obj->datev) ? '' : $this->db->jdate($obj->datev); + } + } + + $this->db->free($result); + } else { + dol_print_error($this->db); + } + } + + /** + * Initialize object with example values + * Id must be 0 if object instance is a specimen + * + * @return int + */ + public function initAsSpecimen() + { + // Set here init that are not commonf fields + // $this->property1 = ... + // $this->property2 = ... + + return $this->initAsSpecimenCommon(); + } + + /** + * Create an array of lines + * + * @return CommonObjectLine[]|int array of lines if OK, <0 if KO + */ + public function getLinesArray() + { + $this->lines = array(); + + $objectline = new DiffusionContactLine($this->db); + $result = $objectline->fetchAll('ASC', 'position', 0, 0, '(fk_diffusioncontact:=:'.((int) $this->id).')'); + + if (is_numeric($result)) { + $this->setErrorsFromObject($objectline); + return $result; + } else { + $this->lines = $result; + return $this->lines; + } + } + + /** + * Returns the reference to the following non used object depending on the active numbering module. + * + * @return string Object free reference + */ + public function getNextNumRef() + { + global $langs, $conf; + $langs->load("diffusionplans@diffusionplans"); + + if (!getDolGlobalString('DIFFUSIONPLANS_MYOBJECT_ADDON')) { + $conf->global->DIFFUSIONPLANS_MYOBJECT_ADDON = 'mod_diffusioncontact_standard'; + } + + if (getDolGlobalString('DIFFUSIONPLANS_MYOBJECT_ADDON')) { + $mybool = false; + + $file = getDolGlobalString('DIFFUSIONPLANS_MYOBJECT_ADDON').".php"; + $classname = getDolGlobalString('DIFFUSIONPLANS_MYOBJECT_ADDON'); + + // Include file with class + $dirmodels = array_merge(array('/'), (array) $conf->modules_parts['models']); + foreach ($dirmodels as $reldir) { + $dir = dol_buildpath($reldir."core/modules/diffusionplans/"); + + // Load file with numbering class (if found) + $mybool = $mybool || @include_once $dir.$file; + } + + if (!$mybool) { + dol_print_error(null, "Failed to include file ".$file); + return ''; + } + + if (class_exists($classname)) { + $obj = new $classname(); + '@phan-var-force ModeleNumRefDiffusionContact $obj'; + $numref = $obj->getNextValue($this); + + if ($numref != '' && $numref != '-1') { + return $numref; + } else { + $this->error = $obj->error; + //dol_print_error($this->db,get_class($this)."::getNextNumRef ".$obj->error); + return ""; + } + } else { + print $langs->trans("Error")." ".$langs->trans("ClassNotFound").' '.$classname; + return ""; + } + } else { + print $langs->trans("ErrorNumberingModuleNotSetup", $this->element); + return ""; + } + } + + /** + * Create a document onto disk according to template module. + * + * @param string $modele Force template to use ('' to not force) + * @param Translate $outputlangs object lang a utiliser pour traduction + * @param int<0,1> $hidedetails Hide details of lines + * @param int<0,1> $hidedesc Hide description + * @param int<0,1> $hideref Hide ref + * @param ?array $moreparams Array to provide more information + * @return int 0 if KO, 1 if OK + */ + public function generateDocument($modele, $outputlangs, $hidedetails = 0, $hidedesc = 0, $hideref = 0, $moreparams = null) + { + global $langs; + + $result = 0; + $includedocgeneration = 1; + + $langs->load("diffusionplans@diffusionplans"); + + if (!dol_strlen($modele)) { + $modele = 'standard_diffusioncontact'; + + if (!empty($this->model_pdf)) { + $modele = $this->model_pdf; + } elseif (getDolGlobalString('MYOBJECT_ADDON_PDF')) { + $modele = getDolGlobalString('MYOBJECT_ADDON_PDF'); + } + } + + $modelpath = "core/modules/diffusionplans/doc/"; + + if ($includedocgeneration && !empty($modele)) { + $result = $this->commonGenerateDocument($modelpath, $modele, $outputlangs, $hidedetails, $hidedesc, $hideref, $moreparams); + } + + return $result; + } + + /** + * Return validation test result for a field. + * Need MAIN_ACTIVATE_VALIDATION_RESULT to be called. + * + * @param array|string,position:int,notnull?:int,visible:int<-2,5>|string,noteditable?:int<0,1>,default?:int<0,1>|string,index?:int,foreignkey?:string,searchall?:int<0,1>,isameasure?:int<0,1>,css?:string,csslist?:string,help?:string,showoncombobox?:int<0,2>,disabled?:int<0,1>,arrayofkeyval?:array,comment?:string,validate?:int<0,1>}> $fields Array of properties of field to show + * @param string $fieldKey Key of attribute + * @param string $fieldValue value of attribute + * @return bool Return false if fail, true on success, set $this->error for error message + */ + public function validateField($fields, $fieldKey, $fieldValue) + { + // Add your own validation rules here. + // ... + + return parent::validateField($fields, $fieldKey, $fieldValue); + } + + /** + * Action executed by scheduler + * CAN BE A CRON TASK. In such a case, parameters come from the schedule job setup field 'Parameters' + * Use public function doScheduledJob($param1, $param2, ...) to get parameters + * + * @return int 0 if OK, <>0 if KO (this function is used also by cron so only 0 is OK) + */ + public function doScheduledJob() + { + //global $conf, $langs; + + //$conf->global->SYSLOG_FILE = 'DOL_DATA_ROOT/dolibarr_mydedicatedlogfile.log'; + + $error = 0; + $this->output = ''; + $this->error = ''; + + dol_syslog(__METHOD__." start", LOG_INFO); + + $now = dol_now(); + + $this->db->begin(); + + // ... + + $this->db->commit(); + + dol_syslog(__METHOD__." end", LOG_INFO); + + return $error; + } +} + + +require_once DOL_DOCUMENT_ROOT.'/core/class/commonobjectline.class.php'; + +/** + * Class DiffusionContactLine. You can also remove this and generate a CRUD class for lines objects. + */ +class DiffusionContactLine extends CommonObjectLine +{ + // To complete with content of an object DiffusionContactLine + // We should have a field rowid, fk_diffusioncontact and position + + /** + * To overload + * @see CommonObjectLine + */ + public $parent_element = ''; // Example: '' or 'diffusioncontact' + + /** + * To overload + * @see CommonObjectLine + */ + public $fk_parent_attribute = ''; // Example: '' or 'fk_diffusioncontact' + + /** + * Constructor + * + * @param DoliDB $db Database handler + */ + public function __construct(DoliDB $db) + { + $this->db = $db; + + $this->isextrafieldmanaged = 0; + } +} diff --git a/core/modules/diffusionplans/doc/pdf_standard_diffusion.modules.php b/core/modules/diffusionplans/doc/pdf_standard_diffusion.modules.php index 7368a35..a8dff88 100644 --- a/core/modules/diffusionplans/doc/pdf_standard_diffusion.modules.php +++ b/core/modules/diffusionplans/doc/pdf_standard_diffusion.modules.php @@ -11,7 +11,7 @@ * Copyright (C) 2018-2024 Frédéric France * Copyright (C) 2024 MDW * Copyright (C) 2024 Alexandre Spangaro - * Copyright (C) 2025 Pierre ARDOIN + * Copyright (C) 2025 Pierre Ardoin * * 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 @@ -39,6 +39,9 @@ require_once DOL_DOCUMENT_ROOT.'/societe/class/societe.class.php'; require_once DOL_DOCUMENT_ROOT.'/contact/class/contact.class.php'; require_once DOL_DOCUMENT_ROOT.'/user/class/user.class.php'; +// FR: Charge le gestionnaire de liens de contacts pour réutiliser les données préparées. +// EN: Load the contact link manager to reuse the preloaded contact data. +dol_include_once('/diffusionplans/class/diffusioncontact.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'; @@ -187,9 +190,9 @@ public function write_file($object, $outputlangs, $srctemplatepath = '', $hidede } // Load translation files required by the page - $langfiles = array("main", "bills", "products", "dict", "companies", "compta"); - $outputlangs->loadLangs($langfiles); - $outputlangs->loadLangs(array('diffusionplans@diffusionplans')); + $langfiles = array("main", "bills", "products", "dict", "companies", "compta"); + $outputlangs->loadLangs($langfiles); + $outputlangs->loadLangs(array('diffusionplans@diffusionplans')); // Show Draft Watermark if (getDolGlobalString('DIFFUSION_DRAFT_WATERMARK') && $object->status == $object::STATUS_DRAFT) { @@ -267,36 +270,36 @@ public function write_file($object, $outputlangs, $srctemplatepath = '', $hidede } */ - //if (count($realpatharray) == 0) $this->posxpicture=$this->posxtva; + //if (count($realpatharray) == 0) $this->posxpicture=$this->posxtva; - $contactSummaries = array(); - $attachmentSummaries = array(); - $objectref = ''; - $currentPdfName = ''; + $contactSummaries = array(); + $attachmentSummaries = array(); + $objectref = ''; + $currentPdfName = ''; - if (getMultidirOutput($object)) { + if (getMultidirOutput($object)) { $object->fetch_thirdparty(); - $paths = $this->prepareDocumentPaths($object); - if ($paths === null) { - $this->error = $langs->transnoentities("ErrorConstantNotDefined", "FAC_OUTPUTDIR"); - return 0; - } - $dir = $paths['dir']; - $file = $paths['file']; - $objectref = $paths['ref']; - $currentPdfName = basename($file); - - if (!file_exists($dir)) { - if (dol_mkdir($dir) < 0) { - $this->error = $langs->transnoentities("ErrorCanNotCreateDir", $dir); - return 0; - } - } - - if (file_exists($dir)) { - $contactSummaries = $this->loadDiffusionContacts($object, $outputlangs); - $attachmentSummaries = $this->loadDiffusionAttachments($dir, $currentPdfName); + $paths = $this->prepareDocumentPaths($object); + if ($paths === null) { + $this->error = $langs->transnoentities("ErrorConstantNotDefined", "FAC_OUTPUTDIR"); + return 0; + } + $dir = $paths['dir']; + $file = $paths['file']; + $objectref = $paths['ref']; + $currentPdfName = basename($file); + + if (!file_exists($dir)) { + if (dol_mkdir($dir) < 0) { + $this->error = $langs->transnoentities("ErrorCanNotCreateDir", $dir); + return 0; + } + } + + if (file_exists($dir)) { + $contactSummaries = $this->loadDiffusionContacts($object, $outputlangs); + $attachmentSummaries = $this->loadDiffusionAttachments($dir, $currentPdfName); // Add pdfgeneration hook if (!is_object($hookmanager)) { include_once DOL_DOCUMENT_ROOT.'/core/class/hookmanager.class.php'; @@ -316,7 +319,7 @@ public function write_file($object, $outputlangs, $srctemplatepath = '', $hidede $default_font_size = pdf_getPDFFontSize($outputlangs); // Must be after pdf_getInstance $pdf->SetAutoPageBreak(1, 0); - $heightforinfotot = $this->estimateSummaryHeight($contactSummaries, $attachmentSummaries); + $heightforinfotot = $this->estimateSummaryHeight($contactSummaries, $attachmentSummaries); $heightforfreetext = getDolGlobalInt('MAIN_PDF_FREETEXT_HEIGHT', 5); // Height reserved to output the free text on last page $heightforfooter = $this->marge_basse + (getDolGlobalInt('MAIN_GENERATE_DOCUMENTS_SHOW_FOOT_DETAILS') ? 12 : 22); // Height reserved to output the footer (value include bottom margin) @@ -549,11 +552,11 @@ public function write_file($object, $outputlangs, $srctemplatepath = '', $hidede $bottomlasttab = $tab_top; } - // Display diffusion contacts and attachments summary - $summaryStartY = max($pdf->GetY(), $bottomlasttab + 2); - $availableWidth = $this->page_largeur - $this->marge_gauche - $this->marge_droite; - $afterContactsY = $this->renderContactsSection($pdf, $object, $contactSummaries, $outputlangs, $summaryStartY, $availableWidth); - $this->renderAttachmentsSection($pdf, $attachmentSummaries, $outputlangs, $afterContactsY + 4, $availableWidth); + // Display diffusion contacts and attachments summary + $summaryStartY = max($pdf->GetY(), $bottomlasttab + 2); + $availableWidth = $this->page_largeur - $this->marge_gauche - $this->marge_droite; + $afterContactsY = $this->renderContactsSection($pdf, $object, $contactSummaries, $outputlangs, $summaryStartY, $availableWidth); + $this->renderAttachmentsSection($pdf, $attachmentSummaries, $outputlangs, $afterContactsY + 4, $availableWidth); // Display payment area /* @@ -665,128 +668,150 @@ protected function loadDiffusionContacts($object, $outputlangs) return $result; } - $statusMap = $this->fetchDiffusionContactStatuses($object); - $companystatic = new Societe($this->db); $contactstatic = new Contact($this->db); $userstatic = new User($this->db); - foreach (array('internal', 'external') as $source) { - $contactlist = $object->liste_contact(-1, $source); - if (empty($contactlist)) { + $contactLinks = array(); + if (!empty($object->pdf_contact_links) && is_array($object->pdf_contact_links)) { + // FR: Utilise les liens déjà collectés sur la fiche pour éviter une requête supplémentaire. + // EN: Reuse the links gathered on the card to avoid running an extra query. + $contactLinks = $object->pdf_contact_links; + } else { + // FR: Récupère les liens en base si la fiche n'a pas préparé la liste. + // EN: Load the links from database when the card did not preload them. + $contactLinkLoader = new DiffusionContact($this->db); + $contactLinks = $contactLinkLoader->fetchDiffusionContactLinks($object->id); + } + + foreach ($contactLinks as $contactRow) { + $contactData = is_array($contactRow) ? $contactRow : (array) $contactRow; + $source = isset($contactData['contact_source']) ? (string) $contactData['contact_source'] : ''; + $contactId = isset($contactData['fk_contact']) ? (int) $contactData['fk_contact'] : 0; + + if ($contactId <= 0 || $source === '') { continue; } - - foreach ($contactlist as $contact) { - if (empty($contact['id'])) { - continue; + + // FR: Exploite prioritairement les informations préparées dans llx_diffusionplans_diffusioncontact. + // EN: Use the data prepared in llx_diffusionplans_diffusioncontact as the primary source. + $thirdpartyName = !empty($contactData['company_name']) ? (string) $contactData['company_name'] : ''; + $contactName = ''; + $email = ''; + $phone = ''; + $mobile = ''; + if ($source === 'internal') { + // FR: Récupère les informations internes issues directement de llx_diffusionplans_diffusioncontact. + // EN: Populate internal contact details directly from llx_diffusionplans_diffusioncontact. + $firstname = isset($contactData['user_firstname']) ? (string) $contactData['user_firstname'] : ''; + $lastname = isset($contactData['user_lastname']) ? (string) $contactData['user_lastname'] : ''; + $login = isset($contactData['user_login']) ? (string) $contactData['user_login'] : ''; + $contactName = trim($firstname.' '.($lastname !== '' ? $lastname : '')); + if ($contactName === '') { + $contactName = $login; } - - $contactId = (int) $contact['id']; - $key = $source.'-'.$contactId; - $status = isset($statusMap[$key]) ? $statusMap[$key] : array('mail_status' => 0, 'letter_status' => 0, 'hand_status' => 0); - - $thirdpartyName = ''; - $contactName = ''; - $email = ''; - $phone = ''; - $mobile = ''; - - if ($source === 'internal') { - if ($userstatic->fetch($contactId) > 0) { - $contactName = $userstatic->getFullName($outputlangs); - $email = $userstatic->email; - $phone = $userstatic->office_phone; - $mobile = $userstatic->user_mobile; - } - if (!empty($mysoc->name)) { - $thirdpartyName = $mysoc->name; + $email = isset($contactData['user_email']) ? (string) $contactData['user_email'] : ''; + $phone = isset($contactData['user_office_phone']) ? (string) $contactData['user_office_phone'] : ''; + $mobile = isset($contactData['user_mobile']) ? (string) $contactData['user_mobile'] : ''; + + if ($contactName === '' || ($email === '' && $phone === '' && $mobile === '')) { + $userclone = clone $userstatic; + if ($userclone->fetch($contactId) > 0) { + if ($contactName === '') { + $contactName = $userclone->getFullName($outputlangs); + } + if ($email === '') { + $email = (string) $userclone->email; + } + if ($phone === '') { + $phone = (string) $userclone->office_phone; + } + if ($mobile === '') { + $mobile = (string) $userclone->user_mobile; + } } - } else { - if ($contactstatic->fetch($contactId) > 0) { - $contactName = $contactstatic->getFullName($outputlangs); - $email = $contactstatic->email; - $phone = $contactstatic->phone_pro; - if (empty($phone) && !empty($contactstatic->phone_perso)) { - $phone = $contactstatic->phone_perso; + } + + if ($thirdpartyName === '' && !empty($mysoc->name)) { + $thirdpartyName = (string) $mysoc->name; + } + } else { + // FR: Utilise les données externes stockées dans la table dédiée, puis complète si besoin via les fiches Dolibarr. + // EN: Use external contact data stored in the dedicated table, then complete it from Dolibarr cards if required. + $firstname = isset($contactData['contact_firstname']) ? (string) $contactData['contact_firstname'] : ''; + $lastname = isset($contactData['contact_lastname']) ? (string) $contactData['contact_lastname'] : ''; + $contactName = trim($firstname.' '.($lastname !== '' ? $lastname : '')); + $email = isset($contactData['contact_email']) ? (string) $contactData['contact_email'] : ''; + if (!empty($contactData['contact_phone_pro'])) { + $phone = (string) $contactData['contact_phone_pro']; + } elseif (!empty($contactData['contact_phone_perso'])) { + $phone = (string) $contactData['contact_phone_perso']; + } + $mobile = isset($contactData['contact_phone_mobile']) ? (string) $contactData['contact_phone_mobile'] : ''; + + if ($contactName === '' || $email === '' || ($phone === '' && $mobile === '')) { + $contactclone = clone $contactstatic; + if ($contactclone->fetch($contactId) > 0) { + if ($contactName === '') { + $contactName = $contactclone->getFullName($outputlangs); } - $mobile = $contactstatic->phone_mobile; - - if (!empty($contactstatic->socid) && $contactstatic->socid > 0) { - if ($companystatic->fetch($contactstatic->socid) > 0) { - $thirdpartyName = $companystatic->name; + if ($email === '') { + $email = (string) $contactclone->email; + } + if ($phone === '') { + $phone = !empty($contactclone->phone_pro) ? (string) $contactclone->phone_pro : (string) $contactclone->phone_perso; + } + if ($mobile === '') { + $mobile = (string) $contactclone->phone_mobile; + } + if ($thirdpartyName === '' && !empty($contactclone->socid) && $contactclone->socid > 0) { + $companyclone = clone $companystatic; + if ($companyclone->fetch($contactclone->socid) > 0) { + $thirdpartyName = (string) $companyclone->name; } } } - - if (empty($thirdpartyName) && !empty($contact['socid']) && (int) $contact['socid'] < 0 && !empty($mysoc->name)) { - $thirdpartyName = $mysoc->name; - } } - - if (empty($thirdpartyName) && !empty($contact['socid']) && (int) $contact['socid'] > 0) { - if ($companystatic->fetch((int) $contact['socid']) > 0) { - $thirdpartyName = $companystatic->name; + + if ($thirdpartyName === '' && !empty($contactData['contact_fk_soc'])) { + $companyclone = clone $companystatic; + if ($companyclone->fetch((int) $contactData['contact_fk_soc']) > 0) { + $thirdpartyName = (string) $companyclone->name; } } - - if (empty($phone) && !empty($mobile)) { - $phone = $mobile; + + if ($thirdpartyName === '' && !empty($mysoc->name)) { + $thirdpartyName = (string) $mysoc->name; } - - $result[] = array( - 'id' => $contactId, - 'source' => $source, - 'type_label' => isset($contact['libelle']) ? $contact['libelle'] : '', - 'thirdparty_name' => $thirdpartyName, - 'contact_name' => $contactName, - 'email' => $email, - 'phone' => $phone, - 'mobile' => $mobile, - 'mail_status' => (int) (!empty($status['mail_status']) ? $status['mail_status'] : 0), - 'letter_status' => (int) (!empty($status['letter_status']) ? $status['letter_status'] : 0), - 'hand_status' => (int) (!empty($status['hand_status']) ? $status['hand_status'] : 0), - ); } - } - - return $result; - } - - /** - * Get statuses for diffusion contacts. - * - * @param Diffusion $object Diffusion object - * @return array> - */ - protected function fetchDiffusionContactStatuses($object) - { - $statuses = array(); - - if (empty($object->id)) { - return $statuses; - } - - $sql = 'SELECT fk_contact, contact_source, mail_status, letter_status, hand_status'; - $sql .= ' FROM '.MAIN_DB_PREFIX."diffusionplans_diffusioncontact"; - $sql .= ' WHERE fk_diffusion = '.((int) $object->id); - - $resql = $this->db->query($sql); - if ($resql) { - while ($obj = $this->db->fetch_object($resql)) { - $key = $obj->contact_source.'-'.((int) $obj->fk_contact); - $statuses[$key] = array( - 'mail_status' => (int) $obj->mail_status, - 'letter_status' => (int) $obj->letter_status, - 'hand_status' => (int) $obj->hand_status, - ); + + if ($phone === '' && $mobile !== '') { + $phone = $mobile; } - $this->db->free($resql); - } else { - dol_syslog(__METHOD__.' sql='.$sql.' '.$this->db->lasterror(), LOG_ERR); + + $typeLabel = ''; + $typeLabelKey = isset($contactData['type_label']) ? (string) $contactData['type_label'] : ''; + if ($typeLabelKey !== '') { + $translated = $outputlangs->transnoentitiesnoconv($typeLabelKey); + $typeLabel = !empty($translated) ? (string) $translated : $typeLabelKey; + } + + $result[] = array( + 'id' => $contactId, + 'source' => $source, + 'type_label' => $typeLabel, + 'thirdparty_name' => $thirdpartyName, + 'contact_name' => $contactName, + 'email' => $email, + 'phone' => $phone, + 'mobile' => $mobile, + 'mail_status' => isset($contactData['mail_status']) ? (int) $contactData['mail_status'] : 0, + 'letter_status' => isset($contactData['letter_status']) ? (int) $contactData['letter_status'] : 0, + 'hand_status' => isset($contactData['hand_status']) ? (int) $contactData['hand_status'] : 0, + ); } - return $statuses; + return $result; } /** @@ -816,7 +841,8 @@ protected function loadDiffusionAttachments($dir, $currentPdfName) } /** - * Estimate height reserved to contacts and attachments blocks. + * FR: Estime la hauteur réservée aux blocs contacts et pièces jointes. + * EN: Estimate height reserved to the contacts and attachments blocks. * * @param array> $contacts * @param array> $attachments @@ -824,95 +850,120 @@ protected function loadDiffusionAttachments($dir, $currentPdfName) */ protected function estimateSummaryHeight(array $contacts, array $attachments) { + // FR: Valeurs de base utilisées pour calculer la hauteur des tableaux. + // EN: Base metrics used to compute the height of the tables. $lineHeight = 5; $headerHeight = 6; $padding = 8; + // FR: Au moins une ligne est conservée pour afficher le message d'absence de contact. + // EN: Keep at least one row to display the "no contact" message when needed. $contactRows = count($contacts); if ($contactRows === 0) { $contactRows = 1; } $contactsHeight = $headerHeight + ($contactRows * $lineHeight) + 4; + // FR: Même logique appliquée pour les pièces jointes listées. + // EN: Apply the same logic for the listed attachments. $attachmentRows = count($attachments); if ($attachmentRows === 0) { $attachmentRows = 1; } $attachmentsHeight = $headerHeight + ($attachmentRows * $lineHeight); + // FR: Retourne une hauteur minimale confortable pour les deux sections combinées. + // EN: Return a comfortable minimal height for the combined sections. return max(50, $contactsHeight + $attachmentsHeight + $padding); } - /** - * Render the contacts table for the diffusion. - * - * @param TCPDF|TCPDI $pdf PDF handler - * @param Diffusion $object Diffusion object - * @param array> $contacts Contacts data - * @param Translate $outputlangs Output language handler - * @param float $startY Initial vertical position - * @param float $width Available width - * @return float - */ - protected function renderContactsSection(&$pdf, $object, array $contacts, $outputlangs, $startY, $width) - { - unset($object); - $defaultFontSize = pdf_getPDFFontSize($outputlangs); - - $pdf->SetFont('', 'B', $defaultFontSize); - $pdf->SetXY($this->marge_gauche, $startY); - $pdf->MultiCell($width, 6, $outputlangs->transnoentities('DiffusionContactsTitle'), 0, 'L'); - $y = $pdf->GetY() + 1; - + /** + * FR: Affiche le tableau des contacts liés à la diffusion. + * EN: Render the contacts table for the diffusion. + * + * @param TCPDF|TCPDI $pdf PDF handler + * @param Diffusion $object Diffusion object + * @param array> $contacts Contacts data + * @param Translate $outputlangs Output language handler + * @param float $startY Initial vertical position + * @param float $width Available width + * @return float + */ + protected function renderContactsSection(&$pdf, $object, array $contacts, $outputlangs, $startY, $width) + { + unset($object); + $defaultFontSize = pdf_getPDFFontSize($outputlangs); + + // FR: Insère le titre de la section contacts dans le document PDF. + // EN: Insert the contacts section title into the PDF document. + $pdf->SetFont('', 'B', $defaultFontSize); + $pdf->SetXY($this->marge_gauche, $startY); + $pdf->MultiCell($width, 6, $outputlangs->transnoentities('DiffusionContactsTitle'), 0, 'L'); + $y = $pdf->GetY() + 1; + + // FR: Calcule des largeurs équilibrées pour la colonne Contact restaurée et les indicateurs de diffusion. + // EN: Compute balanced widths for the restored Contact column and the delivery status indicators. + $statusColumnWidth = $width * 0.07; + $contactColumnWidth = $width * 0.33; + $thirdpartyColumnWidth = $width - ($contactColumnWidth + (3 * $statusColumnWidth)); + + // FR: Déclare les colonnes alignées sur la fiche diffusion tout en supprimant la nature du contact. + // EN: Declare columns aligned with the diffusion card while dropping the contact nature column. $columns = array( - array('key' => 'thirdparty_name', 'label' => 'ThirdParty', 'width' => $width * 0.18, 'align' => 'L'), - array('key' => 'contact_name', 'label' => 'Contact', 'width' => $width * 0.22, 'align' => 'L'), - array('key' => 'type_label', 'label' => 'ContactType', 'width' => $width * 0.14, 'align' => 'L'), - array('key' => 'email', 'label' => 'Email', 'width' => $width * 0.22, 'align' => 'L'), - array('key' => 'phone', 'label' => 'Phone', 'width' => $width * 0.12, 'align' => 'L'), - array('key' => 'mail_status', 'label' => 'methodMail', 'width' => $width * 0.04, 'align' => 'C', 'status' => true), - array('key' => 'letter_status', 'label' => 'methodLetter', 'width' => $width * 0.04, 'align' => 'C', 'status' => true), - array('key' => 'hand_status', 'label' => 'methodHand', 'width' => $width * 0.04, 'align' => 'C', 'status' => true), + array('key' => 'thirdparty_name', 'label' => 'ThirdParty', 'width' => $thirdpartyColumnWidth, 'align' => 'L'), + array('key' => 'contact_name', 'label' => 'Contact', 'width' => $contactColumnWidth, 'align' => 'L'), + array('key' => 'mail_status', 'label' => 'methodMail', 'width' => $statusColumnWidth, 'align' => 'C', 'status' => true), + array('key' => 'letter_status', 'label' => 'methodLetter', 'width' => $statusColumnWidth, 'align' => 'C', 'status' => true), + array('key' => 'hand_status', 'label' => 'methodHand', 'width' => $statusColumnWidth, 'align' => 'C', 'status' => true), ); $pdf->SetFont('', 'B', $defaultFontSize - 1); $x = $this->marge_gauche; for ($i = 0; $i < count($columns); $i++) { $column = $columns[$i]; + // FR: Affiche l'en-tête de colonne avec la traduction appropriée. + // EN: Output the column header with the proper translation. + $label = $outputlangs->transnoentities($column['label']); $pdf->SetXY($x, $y); - $pdf->MultiCell($column['width'], 5, $outputlangs->transnoentities($column['label']), 0, $column['align'], 0, 0); + $pdf->MultiCell($column['width'], 5, $label, 0, $column['align'], 0, 0); $x += $column['width']; } $y += 5; $pdf->SetDrawColor(200, 200, 200); $pdf->line($this->marge_gauche, $y, $this->marge_gauche + $width, $y); $y += 1; - $pdf->SetFont('', '', $defaultFontSize - 1); - - if (empty($contacts)) { - $pdf->SetXY($this->marge_gauche, $y); - $pdf->MultiCell($width, 5, $outputlangs->transnoentities('DiffusionNoContacts'), 0, 'L'); - return $pdf->GetY(); - } - - for ($i = 0; $i < count($contacts); $i++) { - $contact = $contacts[$i]; - $rowHeight = 5; - for ($j = 0; $j < count($columns); $j++) { - $column = $columns[$j]; - $text = $this->formatContactColumnValue($contact, $column, $outputlangs); - $numLines = $pdf->getNumLines($outputlangs->convToOutputCharset($text), $column['width']); - $rowHeight = max($rowHeight, $numLines * 4.5); - } - - $x = $this->marge_gauche; - for ($j = 0; $j < count($columns); $j++) { - $column = $columns[$j]; - $text = $this->formatContactColumnValue($contact, $column, $outputlangs); - $pdf->SetXY($x, $y); - $pdf->MultiCell($column['width'], $rowHeight, $outputlangs->convToOutputCharset($text), 0, $column['align'], 0, 0); - $x += $column['width']; - } + $pdf->SetFont('', '', $defaultFontSize - 1); + + if (empty($contacts)) { + // FR: Message affiché lorsqu'aucun contact n'est lié à la diffusion. + // EN: Message displayed when no contact is linked to the diffusion. + $pdf->SetXY($this->marge_gauche, $y); + $pdf->MultiCell($width, 5, $outputlangs->transnoentities('DiffusionNoContacts'), 0, 'L'); + return $pdf->GetY(); + } + + for ($i = 0; $i < count($contacts); $i++) { + $contact = $contacts[$i]; + $rowHeight = 5; + for ($j = 0; $j < count($columns); $j++) { + $column = $columns[$j]; + $text = $this->formatContactColumnValue($contact, $column, $outputlangs); + // FR: Calcule la hauteur nécessaire pour gérer les textes multilignes. + // EN: Compute the row height required to handle multi-line text. + $numLines = $pdf->getNumLines($outputlangs->convToOutputCharset($text), $column['width']); + $rowHeight = max($rowHeight, $numLines * 4.5); + } + + $x = $this->marge_gauche; + for ($j = 0; $j < count($columns); $j++) { + $column = $columns[$j]; + $text = $this->formatContactColumnValue($contact, $column, $outputlangs); + // FR: Écrit chaque cellule en respectant l'alignement prévu. + // EN: Write each cell while respecting the expected alignment. + $pdf->SetXY($x, $y); + $pdf->MultiCell($column['width'], $rowHeight, $outputlangs->convToOutputCharset($text), 0, $column['align'], 0, 0); + $x += $column['width']; + } $y += $rowHeight; $pdf->line($this->marge_gauche, $y, $this->marge_gauche + $width, $y); $y += 0.5; @@ -921,60 +972,106 @@ protected function renderContactsSection(&$pdf, $object, array $contacts, $outpu return $y; } - /** - * Format value displayed in the contacts table. - * - * @param array $contact Contact data - * @param array $column Column definition - * @param Translate $outputlangs Output language handler - * @return string - */ - protected function formatContactColumnValue(array $contact, array $column, $outputlangs) - { + /** + * FR: Formate les valeurs affichées dans le tableau des contacts. + * EN: Format value displayed in the contacts table. + * + * @param array $contact Contact data + * @param array $column Column definition + * @param Translate $outputlangs Output language handler + * @return string + */ + protected function formatContactColumnValue(array $contact, array $column, $outputlangs) + { $key = $column['key']; - if (!empty($column['status'])) { - return !empty($contact[$key]) ? $outputlangs->transnoentities('Yes') : $outputlangs->transnoentities('No'); + if ($key === 'thirdparty_name') { + // FR: Affiche uniquement la raison sociale pour refléter la colonne « Tiers ». + // EN: Display only the third-party name to mirror the "Third party" column. + return !empty($contact[$key]) ? (string) $contact[$key] : ''; } - - return isset($contact[$key]) ? (string) $contact[$key] : ''; - } - - /** - * Render the attachments list. - * - * @param TCPDF|TCPDI $pdf PDF handler - * @param array> $attachments Attachments data - * @param Translate $outputlangs Output language handler - * @param float $startY Initial vertical position - * @param float $width Available width - * @return float - */ - protected function renderAttachmentsSection(&$pdf, array $attachments, $outputlangs, $startY, $width) - { - $defaultFontSize = pdf_getPDFFontSize($outputlangs); - - $pdf->SetFont('', 'B', $defaultFontSize); - $pdf->SetXY($this->marge_gauche, $startY); - $pdf->MultiCell($width, 6, $outputlangs->transnoentities('DiffusionAttachmentsTitle'), 0, 'L'); - $y = $pdf->GetY() + 1; - - $pdf->SetFont('', '', $defaultFontSize - 1); - - if (empty($attachments)) { - $pdf->SetXY($this->marge_gauche, $y); - $pdf->MultiCell($width, 5, $outputlangs->transnoentities('DiffusionNoDocuments'), 0, 'L'); - return $pdf->GetY(); + if ($key === 'contact_name') { + // FR: Assemble le nom du contact et ses coordonnées principales. + // EN: Combine the contact name with their primary contact details. + $lines = array(); + if (!empty($contact[$key])) { + $lines[] = (string) $contact[$key]; + } + $details = array(); + if (!empty($contact['email'])) { + $details[] = (string) $contact['email']; + } + $primaryPhone = ''; + if (!empty($contact['phone'])) { + $primaryPhone = (string) $contact['phone']; + } elseif (!empty($contact['mobile'])) { + $primaryPhone = (string) $contact['mobile']; + } + if ($primaryPhone !== '') { + $details[] = $primaryPhone; + } + if (!empty($details)) { + $lines[] = implode(' - ', $details); + } + return implode("\n", $lines); } - for ($i = 0; $i < count($attachments); $i++) { - $fileinfo = $attachments[$i]; - $sizeLabel = dol_print_size(isset($fileinfo['size']) ? $fileinfo['size'] : 0, 1, 1, 0, $outputlangs); - $lineLabel = $outputlangs->transnoentities('DiffusionAttachmentLine', $fileinfo['name'], $sizeLabel); - $pdf->SetXY($this->marge_gauche, $y); - $pdf->MultiCell($width, 5, '- '.$outputlangs->convToOutputCharset($lineLabel), 0, 'L'); - $y = $pdf->GetY(); + if (!empty($column['status'])) { + // FR: Affiche une coche lorsque la méthode est activée. + // EN: Show a check mark when the delivery method is enabled. + return !empty($contact[$key]) ? '✓' : ''; } + + // FR: Retourne la valeur textuelle si elle existe, sinon une chaîne vide. + // EN: Return the textual value when it exists, otherwise an empty string. + return isset($contact[$key]) ? (string) $contact[$key] : ''; + } + + /** + * FR: Affiche la liste des pièces jointes de la diffusion. + * EN: Render the attachments list. + * + * @param TCPDF|TCPDI $pdf PDF handler + * @param array> $attachments Attachments data + * @param Translate $outputlangs Output language handler + * @param float $startY Initial vertical position + * @param float $width Available width + * @return float + */ + protected function renderAttachmentsSection(&$pdf, array $attachments, $outputlangs, $startY, $width) + { + $defaultFontSize = pdf_getPDFFontSize($outputlangs); + + // FR: Ajoute le titre de la section consacrée aux documents joints. + // EN: Add the title for the attachments section. + $pdf->SetFont('', 'B', $defaultFontSize); + $pdf->SetXY($this->marge_gauche, $startY); + $pdf->MultiCell($width, 6, $outputlangs->transnoentities('DiffusionAttachmentsTitle'), 0, 'L'); + $y = $pdf->GetY() + 1; + + $pdf->SetFont('', '', $defaultFontSize - 1); + + if (empty($attachments)) { + // FR: Indique clairement l'absence de documents joints. + // EN: Clearly state that no documents are attached. + $pdf->SetXY($this->marge_gauche, $y); + $pdf->MultiCell($width, 5, $outputlangs->transnoentities('DiffusionNoDocuments'), 0, 'L'); + return $pdf->GetY(); + } + + for ($i = 0; $i < count($attachments); $i++) { + $fileinfo = $attachments[$i]; + // FR: Construit une description avec le nom du fichier et sa taille formatée. + // EN: Build a description containing the file name and its formatted size. + $sizeLabel = dol_print_size(isset($fileinfo['size']) ? $fileinfo['size'] : 0, 1, 1, 0, $outputlangs); + $lineLabel = $outputlangs->transnoentities('DiffusionAttachmentLine', $fileinfo['name'], $sizeLabel); + $pdf->SetXY($this->marge_gauche, $y); + // FR: Préfixe chaque élément avec une puce pour faciliter la lecture. + // EN: Prefix each entry with a bullet to ease readability. + $pdf->MultiCell($width, 5, '- '.$outputlangs->convToOutputCharset($lineLabel), 0, 'L'); + $y = $pdf->GetY(); + } + return $y; } diff --git a/diffusion_card.php b/diffusion_card.php index 585b5ab..c82a334 100644 --- a/diffusion_card.php +++ b/diffusion_card.php @@ -1,7 +1,7 @@ * Copyright (C) 2024 Frédéric France - * Copyright (C) 2025 Pierre ARDOIN + * Copyright (C) 2025 Pierre Ardoin * * 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 @@ -227,11 +227,18 @@ // Actions when printing a doc from card include DOL_DOCUMENT_ROOT.'/core/actions_printing.inc.php'; - // Action to move up and down lines of object - //include DOL_DOCUMENT_ROOT.'/core/actions_lineupdown.inc.php'; + if (!empty($object->id)) { + // FR: Précharge les liens de contacts pour alimenter le rendu PDF. + // EN: Preload contact links so the PDF renderer receives the prepared data. + $diffusioncontactloader = new DiffusionContact($db); + $object->pdf_contact_links = $diffusioncontactloader->fetchDiffusionContactLinks($object->id); + } + +// Action to move up and down lines of object +//include DOL_DOCUMENT_ROOT.'/core/actions_lineupdown.inc.php'; - // Action to build doc - include DOL_DOCUMENT_ROOT.'/core/actions_builddoc.inc.php'; +// Action to build doc +include DOL_DOCUMENT_ROOT.'/core/actions_builddoc.inc.php'; if ($action == 'set_thirdparty' && $permissiontoadd) { $object->setValueFrom('fk_soc', GETPOSTINT('fk_soc'), '', null, 'date', '', $user, $triggermodname); @@ -254,22 +261,35 @@ if ($action == 'addcontact' && $permissiontoadd) { $contactid = (GETPOST('userid') ? GETPOSTINT('userid') : GETPOSTINT('contactid')); $typeid = (GETPOST('typecontact') ? GETPOST('typecontact') : GETPOST('type')); - $result = $object->add_contact($contactid, $typeid, GETPOST("source", 'aZ09')); - if ($result >= 0) { - $diffusioncontactstatic = new DiffusionContact($db); - - $resql = $diffusioncontactstatic->create($object->id, $contactid, GETPOST("source", 'aZ09')); - //var_dump("Contact ID : ".$result); - header("Location: ".$_SERVER['PHP_SELF']."?id=".$object->id); - exit; - } else { - if ($object->error == 'DB_ERROR_RECORD_ALREADY_EXISTS') { - $langs->load("errors"); - setEventMessages($langs->trans("ErrorThisContactIsAlreadyDefinedAsThisType"), null, 'errors'); - } else { - setEventMessages($object->error, $object->errors, 'errors'); - } - } + $contactSource = GETPOST('source', 'aZ09'); + $result = $object->add_contact($contactid, $typeid, $contactSource); + if ($result >= 0) { + $diffusioncontactstatic = new DiffusionContact($db); + // FR: Synchronise la table dédiée afin d'offrir au PDF toutes les métadonnées nécessaires. + // EN: Synchronise the dedicated table so the PDF gets all required metadata. + $syncResult = $diffusioncontactstatic->syncLink($object->id, $contactid, $contactSource); + + if ($syncResult < 0) { + setEventMessages($diffusioncontactstatic->error, $diffusioncontactstatic->errors, 'errors'); + } else { + header('Location: '.$_SERVER['PHP_SELF'].'?id='.$object->id); + exit; + } + } else { + if ($object->error == 'DB_ERROR_RECORD_ALREADY_EXISTS') { + $langs->load('errors'); + // FR: Même en cas de doublon sur le lien Dolibarr, on s'assure que la table diffusion soit cohérente. + // EN: Even when Dolibarr reports a duplicate link, keep the diffusion table consistent. + $diffusioncontactstatic = new DiffusionContact($db); + $syncResult = $diffusioncontactstatic->syncLink($object->id, $contactid, $contactSource); + if ($syncResult < 0) { + setEventMessages($diffusioncontactstatic->error, $diffusioncontactstatic->errors, 'errors'); + } + setEventMessages($langs->trans('ErrorThisContactIsAlreadyDefinedAsThisType'), null, 'errors'); + } else { + setEventMessages($object->error, $object->errors, 'errors'); + } + } } elseif ($action == 'swapstatut' && $permissiontoadd) { // Toggle the status of a contact $result = $object->swapContactStatus(GETPOSTINT('ligne')); @@ -277,19 +297,24 @@ // Deletes a contact $contactid = (GETPOST('userid') ? GETPOSTINT('userid') : GETPOSTINT('contactid')); $typeid = (GETPOST('typecontact') ? GETPOST('typecontact') : GETPOST('type')); - $result = $object->delete_contact($lineid); - - if ($result >= 0) { - - $diffusioncontactstatic = new DiffusionContact($db); - - $deletediffusioncontact = $diffusioncontactstatic->deleteLine($object->id, $contactid, GETPOST("source", 'aZ09')); - - header("Location: ".$_SERVER['PHP_SELF']."?id=".$object->id); - exit; - } else { - dol_print_error($db); - } + $contactSource = GETPOST('source', 'aZ09'); + $result = $object->delete_contact($lineid); + + if ($result >= 0) { + $diffusioncontactstatic = new DiffusionContact($db); + // FR: Nettoie également la table spécifique pour éviter des reliquats côté génération PDF. + // EN: Also clean the specific table to avoid leftovers when generating the PDF. + $removeResult = $diffusioncontactstatic->removeLink($object->id, $contactid, $contactSource); + + if ($removeResult < 0) { + setEventMessages($diffusioncontactstatic->error, $diffusioncontactstatic->errors, 'errors'); + } else { + header('Location: '.$_SERVER['PHP_SELF'].'?id='.$object->id); + exit; + } + } else { + dol_print_error($db); + } } elseif ($action == 'add' && $usercancreate) { //$db->begin(); $object->ref = GETPOST('ref'); @@ -553,55 +578,55 @@ print '
'; print '
'; print '
'; - print ''."\n"; - - $fieldsBackup = $object->fields; - $labelFieldDef = isset($object->fields['label']) ? $object->fields['label'] : null; - $descriptionFieldDef = isset($object->fields['description']) ? $object->fields['description'] : null; - if ($labelFieldDef !== null) { - unset($object->fields['label']); - } - if ($descriptionFieldDef !== null) { - unset($object->fields['description']); - } - - $inlineEditable = ($permissiontoadd && $object->status == $object::STATUS_DRAFT); - - if ($labelFieldDef !== null) { - $valueClasses = array('valuefield'); - if (!empty($labelFieldDef['cssview'])) { - $valueClasses[] = $labelFieldDef['cssview']; - } - $valueClassAttr = implode(' ', array_unique(array_filter($valueClasses))); - - print ''; // Label row - print ''; - print ''; - print ''; - } - - if ($descriptionFieldDef !== null) { - $descValueClasses = array('valuefield', 'wordbreak'); - if (!empty($descriptionFieldDef['cssview'])) { - $descValueClasses[] = $descriptionFieldDef['cssview']; - } - $descValueClassAttr = implode(' ', array_unique(array_filter($descValueClasses))); - - print ''; - print ''; - print ''; - print ''; - } - - // Common attributes + print '
'.$form->editfieldkey($labelFieldDef['label'], 'label', '', $object, $inlineEditable, 'string').''.$form->editfieldval($labelFieldDef['label'], 'label', $object->label, $object, $inlineEditable, 'string', '', null, null, '', 1).'
'.$form->editfieldkey($descriptionFieldDef['label'], 'description', '', $object, $inlineEditable, 'textarea').''.$form->editfieldval($descriptionFieldDef['label'], 'description', $object->description, $object, $inlineEditable, 'textarea:100:6', '', null, null, '', 1).'
'."\n"; + + $fieldsBackup = $object->fields; + $labelFieldDef = isset($object->fields['label']) ? $object->fields['label'] : null; + $descriptionFieldDef = isset($object->fields['description']) ? $object->fields['description'] : null; + if ($labelFieldDef !== null) { + unset($object->fields['label']); + } + if ($descriptionFieldDef !== null) { + unset($object->fields['description']); + } + + $inlineEditable = ($permissiontoadd && $object->status == $object::STATUS_DRAFT); + + if ($labelFieldDef !== null) { + $valueClasses = array('valuefield'); + if (!empty($labelFieldDef['cssview'])) { + $valueClasses[] = $labelFieldDef['cssview']; + } + $valueClassAttr = implode(' ', array_unique(array_filter($valueClasses))); + + print ''; // Label row + print ''; + print ''; + print ''; + } + + if ($descriptionFieldDef !== null) { + $descValueClasses = array('valuefield', 'wordbreak'); + if (!empty($descriptionFieldDef['cssview'])) { + $descValueClasses[] = $descriptionFieldDef['cssview']; + } + $descValueClassAttr = implode(' ', array_unique(array_filter($descValueClasses))); + + print ''; + print ''; + print ''; + print ''; + } + + // Common attributes //$keyforbreak='fieldkeytoswitchonsecondcolumn'; // We change column just before this field //unset($object->fields['fk_project']); // Hide field already shown in banner //unset($object->fields['fk_soc']); // Hide field already shown in banner - include DOL_DOCUMENT_ROOT.'/core/tpl/commonfields_view.tpl.php'; - - $object->fields = $fieldsBackup; - - // Other attributes. Fields from hook formObjectOptions and Extrafields. + include DOL_DOCUMENT_ROOT.'/core/tpl/commonfields_view.tpl.php'; + + $object->fields = $fieldsBackup; + + // Other attributes. Fields from hook formObjectOptions and Extrafields. include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_view.tpl.php'; print '
'.$form->editfieldkey($labelFieldDef['label'], 'label', '', $object, $inlineEditable, 'string').''.$form->editfieldval($labelFieldDef['label'], 'label', $object->label, $object, $inlineEditable, 'string', '', null, null, '', 1).'
'.$form->editfieldkey($descriptionFieldDef['label'], 'description', '', $object, $inlineEditable, 'textarea').''.$form->editfieldval($descriptionFieldDef['label'], 'description', $object->description, $object, $inlineEditable, 'textarea:100:6', '', null, null, '', 1).'
'; diff --git a/langs/en_US/diffusionplans.lang b/langs/en_US/diffusionplans.lang index f6a2200..dd231c3 100644 --- a/langs/en_US/diffusionplans.lang +++ b/langs/en_US/diffusionplans.lang @@ -19,6 +19,7 @@ ConfirmClone = Confirm cloning Contact = Contact ContactType = Contact type Contacts = Contacts +ContactSource = Contact source CopyOf = Copy of Currency = Currency CustomerAccountancyCode = Customer accountancy code @@ -30,11 +31,15 @@ Default = Default Delete = Delete Description = Description Diffusion = Diffusion +# FR: Chaînes utilisées pour les sections PDF contacts et pièces jointes. +# EN: Strings used for the PDF contacts and attachments sections. DiffusionAttachmentLine = %s (%s) DiffusionAttachmentsTitle = Attached documents DiffusionContact = Diffusion contact DiffusionContacts = Diffusion contacts DiffusionContactsTitle = Diffusion contacts +DiffusionContactRemoveError = Unable to remove the contact link for this diffusion. +DiffusionContactSyncError = Unable to synchronise the contact for this diffusion. DiffusionNoContacts = No contact is linked to this diffusion. DiffusionNoDocuments = No document is attached to this diffusion. DiffusionPlansArea = DiffusionPlans area @@ -81,6 +86,7 @@ Id = Id Link = Link ListOfDirectories = List of directories ListOfDirectoriesForModelGenODT = List of directories for ODT models +List Diffusion = Diffusions list Logo = Logo Mask = Mask Method = Method @@ -94,6 +100,7 @@ NatureOfContact = Nature of contact NbOfAttachedFiles = Number of attached files NewAttribute = New attribute NewDiffusion = New diffusion +New Diffusion = New diffusion NewObject = New object NextValue = Next value No = No diff --git a/langs/fr_FR/diffusionplans.lang b/langs/fr_FR/diffusionplans.lang index c3bea5c..50086d3 100644 --- a/langs/fr_FR/diffusionplans.lang +++ b/langs/fr_FR/diffusionplans.lang @@ -19,6 +19,7 @@ ConfirmClone = Confirmer le clonage Contact = Contact ContactType = Type de contact Contacts = Contacts +ContactSource = Source du contact CopyOf = Copie de Currency = Devise CustomerAccountancyCode = Code comptable client @@ -30,11 +31,15 @@ Default = Par défaut Delete = Supprimer Description = Description Diffusion = Diffusion +# FR: Chaînes utilisées pour les sections PDF contacts et pièces jointes. +# EN: Strings used for the PDF contacts and attachments sections. DiffusionAttachmentLine = %s (%s) DiffusionAttachmentsTitle = Documents joints DiffusionContact = Contact de diffusion DiffusionContacts = Contacts de diffusion DiffusionContactsTitle = Contacts de la diffusion +DiffusionContactRemoveError = Impossible de supprimer le lien du contact pour cette diffusion. +DiffusionContactSyncError = Impossible de synchroniser le contact pour cette diffusion. DiffusionNoContacts = Aucun contact n'est lié à cette diffusion. DiffusionNoDocuments = Aucun document n'est joint à cette diffusion. DiffusionPlansArea = Accueil DiffusionPlans @@ -81,6 +86,7 @@ Id = Id Link = Lien ListOfDirectories = Liste des répertoires ListOfDirectoriesForModelGenODT = Liste des répertoires pour les modèles ODT +List Diffusion = Liste des diffusions Logo = Logo Mask = Masque Method = Méthode @@ -94,6 +100,7 @@ NatureOfContact = Nature du contact NbOfAttachedFiles = Nombre de fichiers joints NewAttribute = Nouvel attribut NewDiffusion = Nouvelle diffusion +New Diffusion = Nouvelle diffusion NewObject = Nouvel objet NextValue = Valeur suivante No = Non