diff --git a/bordereaudoc_card.php b/bordereaudoc_card.php
new file mode 100644
index 0000000..70082b4
--- /dev/null
+++ b/bordereaudoc_card.php
@@ -0,0 +1,213 @@
+
+*
+* 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 bordereaudoc_card.php
+* \ingroup diffusionplans
+* \brief Card page for Bordereaudoc object.
+*/
+
+// Load Dolibarr environment
+$res = 0;
+if (!$res && !empty($_SERVER["CONTEXT_DOCUMENT_ROOT"])) {
+ $res = @include $_SERVER["CONTEXT_DOCUMENT_ROOT"]."/main.inc.php";
+}
+$tmp = empty($_SERVER['SCRIPT_FILENAME']) ? '' : $_SERVER['SCRIPT_FILENAME'];
+$tmp2 = realpath(__FILE__);
+$i = strlen($tmp) - 1;
+$j = strlen($tmp2) - 1;
+while ($i > 0 && $j > 0 && isset($tmp[$i]) && isset($tmp2[$j]) && $tmp[$i] == $tmp2[$j]) {
+ $i--;
+ $j--;
+}
+if (!$res && $i > 0 && file_exists(substr($tmp, 0, ($i + 1))."/main.inc.php")) {
+ $res = @include substr($tmp, 0, ($i + 1))."/main.inc.php";
+}
+if (!$res && $i > 0 && file_exists(dirname(substr($tmp, 0, ($i + 1)))."/main.inc.php")) {
+ $res = @include dirname(substr($tmp, 0, ($i + 1)))."/main.inc.php";
+}
+if (!$res && file_exists("../main.inc.php")) {
+ $res = @include "../main.inc.php";
+}
+if (!$res && file_exists("../../main.inc.php")) {
+ $res = @include "../../main.inc.php";
+}
+if (!$res && file_exists("../../../main.inc.php")) {
+ $res = @include "../../../main.inc.php";
+}
+if (!$res) {
+ die("Include of main fails");
+}
+
+require_once DOL_DOCUMENT_ROOT.'/core/class/html.form.class.php';
+require_once DOL_DOCUMENT_ROOT.'/core/class/html.formprojet.class.php';
+require_once DOL_DOCUMENT_ROOT.'/core/lib/functions2.lib.php';
+require_once DOL_DOCUMENT_ROOT.'/core/lib/project.lib.php';
+require_once DOL_DOCUMENT_ROOT.'/core/class/doleditor.class.php';
+dol_include_once('/diffusionplans/class/bordereaudoc.class.php');
+
+// Load translations
+$langs->loadLangs(array('diffusionplans@diffusionplans', 'other', 'projects'));
+
+// Get parameters
+$id = GETPOSTINT('id');
+$ref = GETPOST('ref', 'alpha');
+$action = GETPOST('action', 'aZ09');
+$backtopage = GETPOST('backtopage', 'alpha');
+$cancel = GETPOST('cancel', 'alpha');
+$contextpage = GETPOST('contextpage', 'aZ') ? GETPOST('contextpage', 'aZ') : 'bordereaudoccard';
+$optioncss = GETPOST('optioncss', 'aZ');
+
+// Objects
+$object = new Bordereaudoc($db);
+$form = new Form($db);
+$formproject = new FormProjets($db);
+
+// Permissions
+$permissiontoread = $user->hasRight('diffusionplans', 'bordereaudoc', 'read');
+$permissiontoadd = $user->hasRight('diffusionplans', 'bordereaudoc', 'write');
+$permissiondelete = $user->hasRight('diffusionplans', 'bordereaudoc', 'delete');
+
+if (!$permissiontoread) {
+ accessforbidden();
+}
+
+// Fetch object
+if (!empty($id) || !empty($ref)) {
+ $object->fetch($id, $ref);
+}
+
+// Actions
+if ($cancel && $backtopage) {
+ header("Location: ".$backtopage);
+ exit;
+}
+
+if ($action === 'add' && $permissiontoadd) {
+ $object->ref = GETPOST('ref', 'alpha');
+ $object->title = GETPOST('title', 'alpha');
+ $object->description = dol_htmlcleanlastbr(GETPOST('description', 'restricthtml'));
+ $object->fk_project = GETPOSTINT('fk_project');
+
+ $result = $object->create($user);
+ if ($result > 0) {
+ if (!empty($backtopage)) {
+ header('Location: '.$backtopage);
+ exit;
+ }
+ header('Location: '.dol_buildpath('/diffusionplans/bordereaudoc_card.php', 1).'?id='.$object->id);
+ exit;
+ } else {
+ setEventMessages($object->error, $object->errors, 'errors');
+ $action = 'create';
+ }
+}
+
+if ($action === 'update' && $permissiontoadd && $object->id > 0) {
+ $object->title = GETPOST('title', 'alpha');
+ $object->description = dol_htmlcleanlastbr(GETPOST('description', 'restricthtml'));
+ $object->fk_project = GETPOSTINT('fk_project');
+ $object->fk_user_modif = $user->id;
+ $result = $object->update($user);
+ if ($result > 0) {
+ setEventMessages($langs->trans('RecordModifiedSuccessfully'), null, 'mesgs');
+ $action = 'view';
+ } else {
+ setEventMessages($object->error, $object->errors, 'errors');
+ $action = 'edit';
+ }
+}
+
+if ($action === 'confirm_delete' && GETPOST('confirm', 'alpha') === 'yes' && $permissiondelete && $object->id > 0) {
+ $result = $object->delete($user);
+ if ($result > 0) {
+ header('Location: '.dol_buildpath('/diffusionplans/diffusion_list.php', 1));
+ exit;
+ }
+ setEventMessages($object->error, $object->errors, 'errors');
+}
+
+// View
+$help_url = '';
+llxHeader('', $langs->trans('BordereaudocCard'), $help_url);
+
+if ($action === 'create') {
+ print load_fiche_titre($langs->trans('BordereaudocNew'), '', 'fa fa-paper-plane');
+ print '
- * 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 diffusion_card.php
- * \ingroup diffusionplans
- * \brief Page to create/edit/view diffusion
- */
-
-
-// General defined Options
-//if (! defined('CSRFCHECK_WITH_TOKEN')) define('CSRFCHECK_WITH_TOKEN', '1'); // Force use of CSRF protection with tokens even for GET
-//if (! defined('MAIN_AUTHENTICATION_MODE')) define('MAIN_AUTHENTICATION_MODE', 'aloginmodule'); // Force authentication handler
-//if (! defined('MAIN_LANG_DEFAULT')) define('MAIN_LANG_DEFAULT', 'auto'); // Force LANG (language) to a particular value
-//if (! defined('MAIN_SECURITY_FORCECSP')) define('MAIN_SECURITY_FORCECSP', 'none'); // Disable all Content Security Policies
-//if (! defined('NOBROWSERNOTIF')) define('NOBROWSERNOTIF', '1'); // Disable browser notification
-//if (! defined('NOIPCHECK')) define('NOIPCHECK', '1'); // Do not check IP defined into conf $dolibarr_main_restrict_ip
-//if (! defined('NOLOGIN')) define('NOLOGIN', '1'); // Do not use login - if this page is public (can be called outside logged session). This includes the NOIPCHECK too.
-//if (! defined('NOREQUIREAJAX')) define('NOREQUIREAJAX', '1'); // Do not load ajax.lib.php library
-//if (! defined('NOREQUIREDB')) define('NOREQUIREDB', '1'); // Do not create database handler $db
-//if (! defined('NOREQUIREHTML')) define('NOREQUIREHTML', '1'); // Do not load html.form.class.php
-//if (! defined('NOREQUIREMENU')) define('NOREQUIREMENU', '1'); // Do not load and show top and left menu
-//if (! defined('NOREQUIRESOC')) define('NOREQUIRESOC', '1'); // Do not load object $mysoc
-//if (! defined('NOREQUIRETRAN')) define('NOREQUIRETRAN', '1'); // Do not load object $langs
-//if (! defined('NOREQUIREUSER')) define('NOREQUIREUSER', '1'); // Do not load object $user
-//if (! defined('NOSCANGETFORINJECTION')) define('NOSCANGETFORINJECTION', '1'); // Do not check injection attack on GET parameters
-//if (! defined('NOSCANPOSTFORINJECTION')) define('NOSCANPOSTFORINJECTION', '1'); // Do not check injection attack on POST parameters
-//if (! defined('NOSESSION')) define('NOSESSION', '1'); // On CLI mode, no need to use web sessions
-//if (! defined('NOSTYLECHECK')) define('NOSTYLECHECK', '1'); // Do not check style html tag into posted data
-//if (! defined('NOTOKENRENEWAL')) define('NOTOKENRENEWAL', '1'); // Do not roll the Anti CSRF token (used if MAIN_SECURITY_CSRF_WITH_TOKEN is on)
-
-
-// Load Dolibarr environment
-$res = 0;
-// Try main.inc.php into web root known defined into CONTEXT_DOCUMENT_ROOT (not always defined)
-if (!$res && !empty($_SERVER["CONTEXT_DOCUMENT_ROOT"])) {
- $res = @include $_SERVER["CONTEXT_DOCUMENT_ROOT"]."/main.inc.php";
-}
-// Try main.inc.php into web root detected using web root calculated from SCRIPT_FILENAME
-$tmp = empty($_SERVER['SCRIPT_FILENAME']) ? '' : $_SERVER['SCRIPT_FILENAME'];
-$tmp2 = realpath(__FILE__);
-$i = strlen($tmp) - 1;
-$j = strlen($tmp2) - 1;
-while ($i > 0 && $j > 0 && isset($tmp[$i]) && isset($tmp2[$j]) && $tmp[$i] == $tmp2[$j]) {
- $i--;
- $j--;
-}
-if (!$res && $i > 0 && file_exists(substr($tmp, 0, ($i + 1))."/main.inc.php")) {
- $res = @include substr($tmp, 0, ($i + 1))."/main.inc.php";
-}
-if (!$res && $i > 0 && file_exists(dirname(substr($tmp, 0, ($i + 1)))."/main.inc.php")) {
- $res = @include dirname(substr($tmp, 0, ($i + 1)))."/main.inc.php";
-}
-// Try main.inc.php using relative path
-if (!$res && file_exists("../main.inc.php")) {
- $res = @include "../main.inc.php";
-}
-if (!$res && file_exists("../../main.inc.php")) {
- $res = @include "../../main.inc.php";
-}
-if (!$res && file_exists("../../../main.inc.php")) {
- $res = @include "../../../main.inc.php";
-}
-if (!$res) {
- die("Include of main fails");
-}
-
-require_once DOL_DOCUMENT_ROOT.'/core/class/html.formcompany.class.php';
-require_once DOL_DOCUMENT_ROOT.'/core/class/html.formfile.class.php';
-require_once DOL_DOCUMENT_ROOT.'/core/class/html.formprojet.class.php';
-require_once DOL_DOCUMENT_ROOT.'/projet/class/project.class.php';
-require_once DOL_DOCUMENT_ROOT.'/core/class/doleditor.class.php';
-
-
-dol_include_once('/diffusionplans/class/diffusion.class.php');
-dol_include_once('/diffusionplans/class/diffusioncontact.class.php');
-dol_include_once('/diffusionplans/lib/diffusionplans_diffusion.lib.php');
-
-/**
- * @var Conf $conf
- * @var DoliDB $db
- * @var HookManager $hookmanager
- * @var Societe $mysoc
- * @var Translate $langs
- * @var User $user
- */
-
-// Load translation files required by the page
-$langs->loadLangs(array("diffusionplans@diffusionplans", "other"));
-
-// Get parameters
-$id = GETPOSTINT('id');
-$ref = GETPOST('ref', 'alpha');
-$lineid = GETPOSTINT('lineid');
-
-$action = GETPOST('action', 'aZ09');
-$confirm = GETPOST('confirm', 'alpha');
-$cancel = GETPOST('cancel', 'aZ09');
-$contextpage = GETPOST('contextpage', 'aZ') ? GETPOST('contextpage', 'aZ') : str_replace('_', '', basename(dirname(__FILE__)).basename(__FILE__, '.php')); // To manage different context of search
-$backtopage = GETPOST('backtopage', 'alpha'); // if not set, a default page will be used
-$backtopageforcancel = GETPOST('backtopageforcancel', 'alpha'); // if not set, $backtopage will be used
-$backtopagejsfields = GETPOST('backtopagejsfields', 'alpha');
-$optioncss = GETPOST('optioncss', 'aZ'); // Option for the css output (always '' except when 'print')
-$dol_openinpopup = GETPOST('dol_openinpopup', 'aZ09');
-
-
-if (!empty($backtopagejsfields)) {
- $tmpbacktopagejsfields = explode(':', $backtopagejsfields);
- $dol_openinpopup = preg_replace('/[^a-z0-9_]/i', '', $tmpbacktopagejsfields[0]);
-}
-
-// Initialize a technical objects
-$object = new Diffusion($db);
-
-$diffusion_project = new Project($db);
-
-$extrafields = new ExtraFields($db);
-
-$object->dir_output = $conf->monmodule->dir_output . '/' . dol_sanitizeFileName($object->ref);
-$diroutputmassaction = $conf->diffusionplans->dir_output.'/temp/massgeneration/'.$user->id;
-$hookmanager->initHooks(array($object->element.'card', 'globalcard')); // Note that conf->hooks_modules contains array
-$soc = null;
-
-// Fetch optionals attributes and labels
-$extrafields->fetch_name_optionals_label($object->table_element);
-
-
-$search_array_options = $extrafields->getOptionalsFromPost($object->table_element, '', 'search_');
-
-// Initialize array of search criteria
-$search_all = trim(GETPOST("search_all", 'alpha'));
-$search = array();
-foreach ($object->fields as $key => $val) {
- if (GETPOST('search_'.$key, 'alpha')) {
- $search[$key] = GETPOST('search_'.$key, 'alpha');
- }
-}
-
-if (empty($action) && empty($id) && empty($ref)) {
- $action = 'view';
-}
-
-// Load object
-include DOL_DOCUMENT_ROOT.'/core/actions_fetchobject.inc.php'; // Must be 'include', not 'include_once'.
-
-// There is several ways to check permission.
-// Set $enablepermissioncheck to 1 to enable a minimum low level of checks
-$enablepermissioncheck = getDolGlobalInt('DIFFUSIONPLANS_ENABLE_PERMISSION_CHECK');
-if ($enablepermissioncheck) {
- $permissiontoread = $user->hasRight('diffusionplans', 'diffusion', 'read');
- $permissiontoadd = $user->hasRight('diffusionplans', 'diffusion', 'write'); // Used by the include of actions_addupdatedelete.inc.php and actions_lineupdown.inc.php
- $permissiontodelete = $user->hasRight('diffusionplans', 'diffusion', 'delete') || ($permissiontoadd && isset($object->status) && $object->status == $object::STATUS_DRAFT);
- $permissionnote = $user->hasRight('diffusionplans', 'diffusion', 'write'); // Used by the include of actions_setnotes.inc.php
- $permissiondellink = $user->hasRight('diffusionplans', 'diffusion', 'write'); // Used by the include of actions_dellink.inc.php
-} else {
- $permissiontoread = 1;
- $permissiontoadd = 1; // Used by the include of actions_addupdatedelete.inc.php and actions_lineupdown.inc.php
- $permissiontodelete = 1;
- $permissionnote = 1;
- $permissiondellink = 1;
-}
-
-$upload_dir = $conf->diffusionplans->multidir_output[isset($object->entity) ? $object->entity : 1].'/diffusion';
-
-// Security check (enable the most restrictive one)
-//if ($user->socid > 0) accessforbidden();
-//if ($user->socid > 0) $socid = $user->socid;
-$isdraft = (isset($object->status) && ($object->status == $object::STATUS_DRAFT) ? 1 : 0);
-//restrictedArea($user, $object->module, $object, $object->table_element, $object->element, 'fk_soc', 'rowid', $isdraft);
-if (!isModEnabled($object->module)) {
- accessforbidden("Module ".$object->module." not enabled");
-}
-if (!$permissiontoread) {
- accessforbidden();
-}
-
-$error = 0;
-
-
-/*
- * Actions
- */
-
-$parameters = array();
-$reshook = $hookmanager->executeHooks('doActions', $parameters, $object, $action); // Note that $action and $object may have been modified by some hooks
-if ($reshook < 0) {
- setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
-}
-
-if (empty($reshook)) {
- $backurlforlist = dol_buildpath('/diffusionplans/diffusion_list.php', 1);
-
- if (empty($backtopage) || ($cancel && empty($id))) {
- if (empty($backtopage) || ($cancel && strpos($backtopage, '__ID__'))) {
- if (empty($id) && (($action != 'add' && $action != 'create') || $cancel)) {
- $backtopage = $backurlforlist;
- } else {
- $backtopage = dol_buildpath('/diffusionplans/diffusion_card.php', 1).'?id='.((!empty($id) && $id > 0) ? $id : '__ID__');
- }
- }
- }
-
- $triggermodname = 'DIFFUSIONPLANS_DIFFUSION_MODIFY'; // Name of trigger action code to execute when we modify record
-
- // Actions cancel, add, update, update_extras, confirm_validate, confirm_delete, confirm_deleteline, confirm_clone, confirm_close, confirm_setdraft, confirm_reopen
- include DOL_DOCUMENT_ROOT.'/core/actions_addupdatedelete.inc.php';
-
- // Actions when linking object each other
- include DOL_DOCUMENT_ROOT.'/core/actions_dellink.inc.php';
-
- // 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';
-
- // 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);
- }
- if ($action == 'classin' && $permissiontoadd) {
- $object->setProject(GETPOSTINT('projectid'));
- }
-
- // Actions to send emails
- $triggersendname = 'DIFFUSIONPLANS_DIFFUSION_SENTBYMAIL';
- $autocopy = 'MAIN_MAIL_AUTOCOPY_DIFFUSION_TO';
- $trackid = 'diffusion'.$object->id;
- include DOL_DOCUMENT_ROOT.'/core/actions_sendmails.inc.php';
-}
-
-/*
- * Add a new contact
- */
-
-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');
- }
- }
-} elseif ($action == 'swapstatut' && $permissiontoadd) {
- // Toggle the status of a contact
- $result = $object->swapContactStatus(GETPOSTINT('ligne'));
-} elseif ($action == 'deletecontact' && $permissiontoadd) { // Permission to add on object because this is an update of a link of object, not a deletion of data
- // 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);
- }
-} elseif ($action == 'add' && $usercancreate) {
- //$db->begin();
- $object->ref = GETPOST('ref');
- $object->label = GETPOST('label');
- $object->fk_project = GETPOSTINT('projectid');
- $object->description = GETPOST('description', 'restricthtml');
-
- var_dump($object->fk_project);
- //$id = $object->create($user, $db);
-}
-
-/*
- * View
- */
-
-$form = new Form($db);
-$formfile = new FormFile($db);
-$formproject = new FormProjets($db);
-
-//$title = $langs->trans("Diffusion")." - ".$langs->trans('Card');
-$title = $object->ref." - ".$langs->trans('Card');
-if ($action == 'create') {
- $title = $langs->trans("NewDiffusion", $langs->transnoentitiesnoconv("Diffusion"));
-}
-$help_url = '';
-
-llxHeader('', $title, $help_url, '', 0, 0, '', '', '', 'mod-diffusionplans page-card');
-
-// Example : Adding jquery code
-// print '';
-
-
-// Part to create
-if ($action == 'create') {
- if (empty($permissiontoadd)) {
- accessforbidden('NotEnoughPermissions', 0, 1);
- }
-
- print load_fiche_titre($title, '', $object->picto);
-
- print '';
-
- //dol_set_focus('input[name="ref"]');
-}
-
-// Part to edit record
-if (($id || $ref) && $action == 'edit') {
- print load_fiche_titre($langs->trans("Diffusion"), '', $object->picto);
-
- print '';
-}
-
-// Part to show record
-if ($object->id > 0 && (empty($action) || ($action != 'edit' && $action != 'create'))) {
- $head = diffusionPrepareHead($object);
-
- print dol_get_fiche_head($head, 'card', $langs->trans("Diffusion"), -1, $object->picto, 0, '', '', 0, '', 1);
-
- $formconfirm = '';
-
- // Confirmation to delete (using preloaded confirm popup)
- if ($action == 'delete' || ($conf->use_javascript_ajax && empty($conf->dol_use_jmobile))) {
- $formconfirm = $form->formconfirm($_SERVER["PHP_SELF"].'?id='.$object->id, $langs->trans('DeleteDiffusion'), $langs->trans('ConfirmDeleteObject'), 'confirm_delete', '', 0, 'action-delete');
- }
- // Confirmation to delete line
- if ($action == 'deleteline') {
- $formconfirm = $form->formconfirm($_SERVER["PHP_SELF"].'?id='.$object->id.'&lineid='.$lineid, $langs->trans('DeleteLine'), $langs->trans('ConfirmDeleteLine'), 'confirm_deleteline', '', 0, 1);
- }
-
- // Clone confirmation
- if ($action == 'clone') {
- // Create an array for form
- $formquestion = array();
- $formconfirm = $form->formconfirm($_SERVER["PHP_SELF"].'?id='.$object->id, $langs->trans('ToClone'), $langs->trans('ConfirmCloneAsk', $object->ref), 'confirm_clone', $formquestion, 'yes', 1);
- }
-
- // Confirmation of action xxxx (You can use it for xxx = 'close', xxx = 'reopen', ...)
- if ($action == 'xxx') {
- $text = $langs->trans('ConfirmActionXxx', $object->ref);
- /*if (isModEnabled('notification'))
- {
- require_once DOL_DOCUMENT_ROOT . '/core/class/notify.class.php';
- $notify = new Notify($db);
- $text .= '
';
- $text .= $notify->confirmMessage('DIFFUSION_CLOSE', $object->socid, $object);
- }*/
-
- $formquestion = array();
-
- /*
- $forcecombo=0;
- if ($conf->browser->name == 'ie') $forcecombo = 1; // There is a bug in IE10 that make combo inside popup crazy
- $formquestion = array(
- // 'text' => $langs->trans("ConfirmClone"),
- // array('type' => 'checkbox', 'name' => 'clone_content', 'label' => $langs->trans("CloneMainAttributes"), 'value' => 1),
- // array('type' => 'checkbox', 'name' => 'update_prices', 'label' => $langs->trans("PuttingPricesUpToDate"), 'value' => 1),
- // array('type' => 'other', 'name' => 'idwarehouse', 'label' => $langs->trans("SelectWarehouseForStockDecrease"), 'value' => $formproduct->selectWarehouses(GETPOST('idwarehouse')?GETPOST('idwarehouse'):'ifone', 'idwarehouse', '', 1, 0, 0, '', 0, $forcecombo))
- );
- */
- $formconfirm = $form->formconfirm($_SERVER["PHP_SELF"].'?id='.$object->id, $langs->trans('XXX'), $text, 'confirm_xxx', $formquestion, 0, 1, 220);
- }
-
- // Call Hook formConfirm
- $parameters = array('formConfirm' => $formconfirm, 'lineid' => $lineid);
- $reshook = $hookmanager->executeHooks('formConfirm', $parameters, $object, $action); // Note that $action and $object may have been modified by hook
- if (empty($reshook)) {
- $formconfirm .= $hookmanager->resPrint;
- } elseif ($reshook > 0) {
- $formconfirm = $hookmanager->resPrint;
- }
-
- // Print form confirm
- print $formconfirm;
-
-
- // Object card
- // ------------------------------------------------------------
- $linkback = ''.$langs->trans("BackToList").'';
-
- $morehtmlref = '';
- /*
- // Ref customer
- $morehtmlref .= $form->editfieldkey("RefCustomer", 'ref_client', $object->ref_client, $object, $usercancreate, 'string', '', 0, 1);
- $morehtmlref .= $form->editfieldval("RefCustomer", 'ref_client', $object->ref_client, $object, $usercancreate, 'string'.(getDolGlobalInt('THIRDPARTY_REF_INPUT_SIZE') ? ':'.getDolGlobalInt('THIRDPARTY_REF_INPUT_SIZE') : ''), '', null, null, '', 1);
- // Thirdparty
- $morehtmlref .= '
'.$object->thirdparty->getNomUrl(1, 'customer');
- if (!getDolGlobalInt('MAIN_DISABLE_OTHER_LINK') && $object->thirdparty->id > 0) {
- $morehtmlref .= ' (
'.$langs->trans("OtherOrders").')';
- }
- // Project
- if (isModEnabled('project')) {
- $langs->load("projects");
- $morehtmlref .= '
';
- if ($permissiontoadd) {
- $morehtmlref .= img_picto($langs->trans("Project"), 'project', 'class="pictofixedwidth"');
- if ($action != 'classify') {
- $morehtmlref .= '
'.img_edit($langs->transnoentitiesnoconv('SetProject')).' ';
- }
- $morehtmlref .= $form->form_project($_SERVER['PHP_SELF'].'?id='.$object->id, $object->socid, $object->fk_project, ($action == 'classify' ? 'projectid' : 'none'), 0, 0, 0, 1, '', 'maxwidth300');
- } else {
- if (!empty($object->fk_project)) {
- $proj = new Project($db);
- $proj->fetch($object->fk_project);
- $morehtmlref .= $proj->getNomUrl(1);
- if ($proj->title) {
- $morehtmlref .= '
- '.dol_escape_htmltag($proj->title).'';
- }
- }
- }
- }
- */
- $morehtmlref .= '
';
-
-
- dol_banner_tab($object, 'ref', $linkback, 1, 'ref', 'ref', $morehtmlref);
-
-
- 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 '| '.$form->editfieldkey($labelFieldDef['label'], 'label', '', $object, $inlineEditable, 'string').' | ';
- print ''.$form->editfieldval($labelFieldDef['label'], 'label', $object->label, $object, $inlineEditable, 'string', '', null, null, '', 1).' | ';
- print '
';
- }
-
- if ($descriptionFieldDef !== null) {
- $descValueClasses = array('valuefield', 'wordbreak');
- if (!empty($descriptionFieldDef['cssview'])) {
- $descValueClasses[] = $descriptionFieldDef['cssview'];
- }
- $descValueClassAttr = implode(' ', array_unique(array_filter($descValueClasses)));
-
- print '';
- print '| '.$form->editfieldkey($descriptionFieldDef['label'], 'description', '', $object, $inlineEditable, 'textarea').' | ';
- print ''.$form->editfieldval($descriptionFieldDef['label'], 'description', $object->description, $object, $inlineEditable, 'textarea:100:6', '', null, null, '', 1).' | ';
- 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/extrafields_view.tpl.php';
-
- print '
';
- print '
';
- print '
';
-
- print '';
-
- print dol_get_fiche_end();
-
-
- /*
- * Lines
- */
-
- include './tpl/diffusion_contacts.tpl.php';
-
- if (!empty($object->table_element_line)) {
- // Show object lines
- $result = $object->getLinesArray();
-
- print ' \n";
- }
-
-
- // Buttons for actions
-
- if ($action != 'presend' && $action != 'editline') {
- print ''."\n";
- $parameters = array();
- $reshook = $hookmanager->executeHooks('addMoreActionsButtons', $parameters, $object, $action); // Note that $action and $object may have been modified by hook
- if ($reshook < 0) {
- setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
- }
-
- if (empty($reshook)) {
- // Send
- if (empty($user->socid) && $object->status == $object::STATUS_VALIDATED) {
- print dolGetButtonAction('', $langs->trans('SendMail'), 'default', $_SERVER["PHP_SELF"].'?id='.$object->id.'&action=presend&token='.newToken().'&mode=init#formmailbeforetitle');
- }
-
- // Back to draft
- if ($object->status == $object::STATUS_VALIDATED) {
- print dolGetButtonAction('', $langs->trans('SetToDraft'), 'default', $_SERVER["PHP_SELF"].'?id='.$object->id.'&action=confirm_setdraft&confirm=yes&token='.newToken(), '', $permissiontoadd);
- }
-
- // Modify
- //print dolGetButtonAction('', $langs->trans('Modify'), 'default', $_SERVER["PHP_SELF"].'?id='.$object->id.'&action=edit&token='.newToken(), '', $permissiontoadd);
-
- // Validate
- if ($object->status == $object::STATUS_DRAFT) {
- if (empty($object->table_element_line) || (is_array($object->lines) && count($object->lines) > 0)) {
- print dolGetButtonAction('', $langs->trans('Validate'), 'default', $_SERVER['PHP_SELF'].'?id='.$object->id.'&action=confirm_validate&confirm=yes&token='.newToken(), '', $permissiontoadd);
- } else {
- $langs->load("errors");
- print dolGetButtonAction($langs->trans("ErrorAddAtLeastOneLineFirst"), $langs->trans("Validate"), 'default', '#', '', 0);
- }
- }
-
- // Clone
- if ($permissiontoadd) {
- print dolGetButtonAction('', $langs->trans('ToClone'), 'default', $_SERVER['PHP_SELF'].'?id='.$object->id.(!empty($object->socid) ? '&socid='.$object->socid : '').'&action=clone&token='.newToken(), '', $permissiontoadd);
- }
-
- /*
- // Disable / Enable
- if ($permissiontoadd) {
- if ($object->status == $object::STATUS_ENABLED) {
- print dolGetButtonAction('', $langs->trans('Disable'), 'default', $_SERVER['PHP_SELF'].'?id='.$object->id.'&action=disable&token='.newToken(), '', $permissiontoadd);
- } else {
- print dolGetButtonAction('', $langs->trans('Enable'), 'default', $_SERVER['PHP_SELF'].'?id='.$object->id.'&action=enable&token='.newToken(), '', $permissiontoadd);
- }
- }
- if ($permissiontoadd) {
- if ($object->status == $object::STATUS_VALIDATED) {
- print dolGetButtonAction('', $langs->trans('Cancel'), 'default', $_SERVER['PHP_SELF'].'?id='.$object->id.'&action=close&token='.newToken(), '', $permissiontoadd);
- } else {
- print dolGetButtonAction('', $langs->trans('Re-Open'), 'default', $_SERVER['PHP_SELF'].'?id='.$object->id.'&action=reopen&token='.newToken(), '', $permissiontoadd);
- }
- }
- */
-
- // Delete (with preloaded confirm popup)
- $deleteUrl = $_SERVER["PHP_SELF"].'?id='.$object->id.'&action=delete&token='.newToken();
- $buttonId = 'action-delete-no-ajax';
- if ($conf->use_javascript_ajax && empty($conf->dol_use_jmobile)) { // We can use preloaded confirm if not jmobile
- $deleteUrl = '';
- $buttonId = 'action-delete';
- }
- $params = array();
- print dolGetButtonAction('', $langs->trans("Delete"), 'delete', $deleteUrl, $buttonId, $permissiontodelete, $params);
- }
- print '
'."\n";
- }
-
-
- // Select mail models is same action as presend
- if (GETPOST('modelselected')) {
- $action = 'presend';
- }
-
- if ($action != 'presend') {
- print '';
- print '
'; // ancre
-
- $includedocgeneration = 1;
-
- // Documents
-
- $object->element = "diffusion";
- if ($includedocgeneration) {
- $objref = dol_sanitizeFileName($object->ref);
- $relativepath = $objref.'/'.$objref.'.pdf';
- $filedir = $conf->diffusionplans->dir_output.'/'.$object->element.'/'.$objref;
- $urlsource = $_SERVER["PHP_SELF"]."?id=".$object->id;
- $genallowed = $permissiontoread; // If you can read, you can build the PDF to read content
- $delallowed = $permissiontoadd; // If you can create/edit, you can remove a file on card
- print $formfile->showdocuments('diffusionplans:Diffusion', $object->element.'/'.$objref, $filedir, $urlsource, $genallowed, $delallowed, $object->model_pdf, 1, 0, 0, 28, 0, '', '', '', $langs->defaultlang);
- }
- /*
- // Show links to link elements
- $object->element = "diffusion";
- $tmparray = $form->showLinkToObjectBlock($object, array(), array('diffusion'), 1);
- if (is_array($tmparray)) {
- $linktoelem = $tmparray['linktoelem'];
- $htmltoenteralink = $tmparray['htmltoenteralink'];
- print $htmltoenteralink;
- $somethingshown = $form->showLinkedObjectBlock($object, $linktoelem);
- } else {
- // backward compatibility
- $somethingshown = $form->showLinkedObjectBlock($object, $tmparray);
- }
- */
- print '
';
-
- $MAXEVENT = 10;
-
- $morehtmlcenter = dolGetButtonTitle($langs->trans('SeeAll'), '', 'fa fa-bars imgforviewmode', dol_buildpath('/diffusionplans/diffusion_agenda.php', 1).'?id='.$object->id);
-
- $includeeventlist = 0;
-
- // List of actions on element
- if ($includeeventlist) {
- include_once DOL_DOCUMENT_ROOT.'/core/class/html.formactions.class.php';
- $formactions = new FormActions($db);
- $somethingshown = $formactions->showactions($object, $object->element.'@'.$object->module, (is_object($object->thirdparty) ? $object->thirdparty->id : 0), 1, '', $MAXEVENT, '', $morehtmlcenter);
- }
-
- print '
';
- }
-
- //Select mail models is same action as presend
- if (GETPOST('modelselected')) {
- $action = 'presend';
- }
-
- // Presend form
- $modelmail = 'diffusion';
- $defaulttopic = 'InformationMessage';
- $diroutput = $conf->diffusionplans->dir_output;
- $trackid = 'diffusion'.$object->id;
-
- include DOL_DOCUMENT_ROOT.'/core/tpl/card_presend.tpl.php';
-}
-
-// End of page
-llxFooter();
-$db->close();
diff --git a/diffusion_list.php b/diffusion_list.php
index 7219fa3..60d39ab 100644
--- a/diffusion_list.php
+++ b/diffusion_list.php
@@ -462,7 +462,7 @@
if ($num == 1 && getDolGlobalInt('MAIN_SEARCH_DIRECT_OPEN_IF_ONLY_ONE') && $search_all && !$page) {
$obj = $db->fetch_object($resql);
$id = $obj->rowid;
- header("Location: ".dol_buildpath('/diffusionplans/diffusion_card.php', 1).'?id='.((int) $id));
+header("Location: ".dol_buildpath('/diffusionplans/bordereaudoc_card.php', 1).'?id='.((int) $id));
exit;
}
@@ -561,7 +561,7 @@
$newcardbutton .= dolGetButtonTitle($langs->trans('ViewList'), '', 'fa fa-bars imgforviewmode', $_SERVER["PHP_SELF"].'?mode=common'.preg_replace('/(&|\?)*mode=[^&]+/', '', $param), '', ((empty($mode) || $mode == 'common') ? 2 : 1), array('morecss' => 'reposition'));
$newcardbutton .= dolGetButtonTitle($langs->trans('ViewKanban'), '', 'fa fa-th-list imgforviewmode', $_SERVER["PHP_SELF"].'?mode=kanban'.preg_replace('/(&|\?)*mode=[^&]+/', '', $param), '', ($mode == 'kanban' ? 2 : 1), array('morecss' => 'reposition'));
$newcardbutton .= dolGetButtonTitleSeparator();
-$newcardbutton .= dolGetButtonTitle($langs->trans('New'), '', 'fa fa-plus-circle', dol_buildpath('/diffusionplans/diffusion_card.php', 1).'?action=create&backtopage='.urlencode($_SERVER['PHP_SELF']), '', $permissiontoadd);
+$newcardbutton .= dolGetButtonTitle($langs->trans('New'), '', 'fa fa-plus-circle', dol_buildpath('/diffusionplans/bordereaudoc_card.php', 1).'?action=create&backtopage='.urlencode($_SERVER['PHP_SELF']), '', $permissiontoadd);
print_barre_liste($title, $page, $_SERVER["PHP_SELF"], $param, $sortfield, $sortorder, $massactionbutton, $num, $nbtotalofrecords, $object->picto, 0, $newcardbutton, '', $limit, 0, 0, 1);
diff --git a/langs/en_US/diffusionplans.lang b/langs/en_US/diffusionplans.lang
index f6a2200..678df5d 100644
--- a/langs/en_US/diffusionplans.lang
+++ b/langs/en_US/diffusionplans.lang
@@ -151,3 +151,17 @@ methodHand = Hand delivered
methodLetter = Send by letter
methodMail = Send by email
or = or
+Bordereaudoc = Delivery slip
+Bordereaudocs = Delivery slips
+BordereaudocCard = Delivery slip card
+BordereaudocNew = New delivery slip
+BordereaudocList = List of delivery slips
+BordereaudocTitle = Title
+BordereaudocRecipients = Recipients
+BordereaudocSendEmail = Send by email
+BordereaudocSendMail = Send by mail
+BordereaudocSendHand = Hand delivery
+BordereaudocActive = Attached
+BordereaudocProjectRequired = A project is mandatory to validate the delivery slip.
+BordereaudocAddRecipients = Add project recipients
+BordereaudocFiles = Delivery slip files
diff --git a/langs/fr_FR/diffusionplans.lang b/langs/fr_FR/diffusionplans.lang
index c3bea5c..fc68a29 100644
--- a/langs/fr_FR/diffusionplans.lang
+++ b/langs/fr_FR/diffusionplans.lang
@@ -151,3 +151,17 @@ methodHand = Remis en main propre
methodLetter = Envoyer par courrier
methodMail = Envoyer par e-mail
or = ou
+Bordereaudoc = Bordereau d'envoi
+Bordereaudocs = Bordereaux d'envoi
+BordereaudocCard = Fiche bordereau d'envoi
+BordereaudocNew = Nouveau bordereau d'envoi
+BordereaudocList = Liste des bordereaux d'envoi
+BordereaudocTitle = Titre
+BordereaudocRecipients = Destinataires
+BordereaudocSendEmail = Envoi par e-mail
+BordereaudocSendMail = Envoi par courrier
+BordereaudocSendHand = Remis en main propre
+BordereaudocActive = Lié au bordereau
+BordereaudocProjectRequired = Un projet est obligatoire pour valider le bordereau.
+BordereaudocAddRecipients = Ajouter les contacts du projet
+BordereaudocFiles = Fichiers du bordereau
diff --git a/lib/diffusionplans_diffusion.lib.php b/lib/diffusionplans_diffusion.lib.php
index 01dbc9a..7bd7c5e 100644
--- a/lib/diffusionplans_diffusion.lib.php
+++ b/lib/diffusionplans_diffusion.lib.php
@@ -41,7 +41,7 @@ function diffusionPrepareHead($object)
$h = 0;
$head = array();
- $head[$h][0] = dol_buildpath("/diffusionplans/diffusion_card.php", 1).'?id='.$object->id;
+$head[$h][0] = dol_buildpath("/diffusionplans/bordereaudoc_card.php", 1).'?id='.$object->id;
$head[$h][1] = $langs->trans("Diffusion");
$head[$h][2] = 'card';
$h++;
diff --git a/sql/llx_bordereaudoc.key.sql b/sql/llx_bordereaudoc.key.sql
new file mode 100644
index 0000000..a690529
--- /dev/null
+++ b/sql/llx_bordereaudoc.key.sql
@@ -0,0 +1,7 @@
+-- Copyright (C) 2025 Pierre ARDOIN
+--
+-- GNU GPL v3
+
+ALTER TABLE llx_bordereaudoc ADD INDEX idx_bordereaudoc_entity (entity);
+ALTER TABLE llx_bordereaudoc ADD INDEX idx_bordereaudoc_project (fk_project);
+ALTER TABLE llx_bordereaudoc ADD UNIQUE INDEX uk_bordereaudoc_ref (ref, entity);
diff --git a/sql/llx_bordereaudoc.sql b/sql/llx_bordereaudoc.sql
new file mode 100644
index 0000000..fd819e0
--- /dev/null
+++ b/sql/llx_bordereaudoc.sql
@@ -0,0 +1,31 @@
+-- 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 https://www.gnu.org/licenses/.
+
+CREATE TABLE llx_bordereaudoc(
+rowid integer AUTO_INCREMENT PRIMARY KEY NOT NULL,
+ref varchar(128) DEFAULT '(PROV)' NOT NULL,
+title varchar(255),
+description longtext,
+fk_project integer NOT NULL,
+statut integer NOT NULL DEFAULT 0,
+entity integer NOT NULL DEFAULT 1,
+datec datetime,
+tms timestamp DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
+fk_user_creat integer,
+fk_user_modif integer,
+import_key varchar(14),
+last_main_doc varchar(255),
+model_pdf varchar(255)
+) ENGINE=innodb;
diff --git a/sql/llx_bordereaudoc_contact.key.sql b/sql/llx_bordereaudoc_contact.key.sql
new file mode 100644
index 0000000..c5c74ca
--- /dev/null
+++ b/sql/llx_bordereaudoc_contact.key.sql
@@ -0,0 +1,7 @@
+-- Copyright (C) 2025 Pierre ARDOIN
+--
+-- GNU GPL v3
+
+ALTER TABLE llx_bordereaudoc_contact ADD INDEX idx_bordereaudoc_contact_entity (entity);
+ALTER TABLE llx_bordereaudoc_contact ADD INDEX idx_bordereaudoc_contact_parent (fk_bordereaudoc);
+ALTER TABLE llx_bordereaudoc_contact ADD INDEX idx_bordereaudoc_contact_contact (fk_contact);
diff --git a/sql/llx_bordereaudoc_contact.sql b/sql/llx_bordereaudoc_contact.sql
new file mode 100644
index 0000000..261795b
--- /dev/null
+++ b/sql/llx_bordereaudoc_contact.sql
@@ -0,0 +1,31 @@
+-- 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 https://www.gnu.org/licenses/.
+
+CREATE TABLE llx_bordereaudoc_contact(
+rowid integer AUTO_INCREMENT PRIMARY KEY NOT NULL,
+fk_bordereaudoc integer NOT NULL,
+fk_soc integer,
+fk_contact integer,
+nature_contact varchar(64),
+type_contact varchar(64),
+send_email integer NOT NULL DEFAULT 1,
+send_mail integer NOT NULL DEFAULT 0,
+send_hand integer NOT NULL DEFAULT 0,
+active integer NOT NULL DEFAULT 1,
+entity integer NOT NULL DEFAULT 1,
+datec datetime,
+tms timestamp DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
+fk_user_creat integer
+) ENGINE=innodb;
diff --git a/sql/llx_bordereaudoc_file.key.sql b/sql/llx_bordereaudoc_file.key.sql
new file mode 100644
index 0000000..bcf9dd1
--- /dev/null
+++ b/sql/llx_bordereaudoc_file.key.sql
@@ -0,0 +1,7 @@
+-- Copyright (C) 2025 Pierre ARDOIN
+--
+-- GNU GPL v3
+
+ALTER TABLE llx_bordereaudoc_file ADD INDEX idx_bordereaudoc_file_entity (entity);
+ALTER TABLE llx_bordereaudoc_file ADD INDEX idx_bordereaudoc_file_parent (fk_bordereaudoc);
+ALTER TABLE llx_bordereaudoc_file ADD UNIQUE INDEX uk_bordereaudoc_file_hash (hash, entity);
diff --git a/sql/llx_bordereaudoc_file.sql b/sql/llx_bordereaudoc_file.sql
new file mode 100644
index 0000000..6b77445
--- /dev/null
+++ b/sql/llx_bordereaudoc_file.sql
@@ -0,0 +1,27 @@
+-- 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 https://www.gnu.org/licenses/.
+
+CREATE TABLE llx_bordereaudoc_file(
+rowid integer AUTO_INCREMENT PRIMARY KEY NOT NULL,
+fk_bordereaudoc integer NOT NULL,
+filename varchar(255) NOT NULL,
+filepath varchar(255) NOT NULL,
+hash varchar(64) NOT NULL,
+is_visible integer NOT NULL DEFAULT 1,
+entity integer NOT NULL DEFAULT 1,
+datec datetime,
+tms timestamp DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
+fk_user_creat integer
+) ENGINE=innodb;