<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
	<id>https://wiki.dolibarr.org/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=TanguyP</id>
	<title>Dolibarr ERP CRM Wiki - User contributions [en]</title>
	<link rel="self" type="application/atom+xml" href="https://wiki.dolibarr.org/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=TanguyP"/>
	<link rel="alternate" type="text/html" href="https://wiki.dolibarr.org/index.php/Special:Contributions/TanguyP"/>
	<updated>2026-10-25T11:03:42Z</updated>
	<subtitle>User contributions</subtitle>
	<generator>MediaWiki 1.39.17</generator>
	<entry>
		<id>https://wiki.dolibarr.org/index.php?title=Module_development&amp;diff=63072</id>
		<title>Module development</title>
		<link rel="alternate" type="text/html" href="https://wiki.dolibarr.org/index.php?title=Module_development&amp;diff=63072"/>
		<updated>2025-04-18T17:48:39Z</updated>

		<summary type="html">&lt;p&gt;TanguyP: Improve troubleshooting for SQL scripts (based on my personal experience)&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;!-- BEGIN origin interlang links --&amp;gt;&lt;br /&gt;
&amp;lt;!-- You can edit this section but do NOT remove these comments&lt;br /&gt;
     Links below will be automatically replicated on translated pages by PolyglotBot --&amp;gt;&lt;br /&gt;
[[fr:Développement_module]]&lt;br /&gt;
[[es:Desarrollo_de_un_módulo]]&lt;br /&gt;
[[de:Modul_Entwicklung]]&lt;br /&gt;
[[zh:模块开发]]&lt;br /&gt;
[[ja:モジュール_開発]]&lt;br /&gt;
&amp;lt;!-- END interlang links --&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Category:Core]]&lt;br /&gt;
{{TemplateDocDevEn}}&lt;br /&gt;
&lt;br /&gt;
To create a new module/addon for Dolibarr, there are several steps. This tutorial will describe each of them to let you build a module that extends Dolibarr features, such as:&lt;br /&gt;
&lt;br /&gt;
*Add new tables in database.&lt;br /&gt;
*Add your own menu entries.&lt;br /&gt;
*Add new screens to edit new tables.&lt;br /&gt;
*Add or remove tabs on object view (invoice, product, order, event, ...).&lt;br /&gt;
*Add predefined exports for the internal export tool.&lt;br /&gt;
*Add new information widget in the home page.&lt;br /&gt;
*Add new substitutions variables.&lt;br /&gt;
*Define new permissions.&lt;br /&gt;
*Execute code automatically triggered by a particular Dolibarr action.&lt;br /&gt;
*Insert your code inside Dolibarr hooks positions.&lt;br /&gt;
*Add your numbering rule to generate the reference of objects&lt;br /&gt;
*Add a new document template.&lt;br /&gt;
*Add a new skin.&lt;br /&gt;
&lt;br /&gt;
etc...&lt;br /&gt;
&lt;br /&gt;
The following chapters explain how to do all of this manually in an easy way.&lt;br /&gt;
&lt;br /&gt;
=Module creation with the module builder=&lt;br /&gt;
From Dolibarr v. 12.0 it is possible to create the main pages of your module with the Module Builder. To activate it:&lt;br /&gt;
&lt;br /&gt;
Go into the list of modules and enable the &amp;quot;Module Builder&amp;quot; module:&lt;br /&gt;
[[File:Module Builder.png|alt=Module Builder|thumb|none]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Then click on the &amp;quot;bug&amp;quot; image in the top right of screen.[[File:Module Builder icon.png|alt=Module Builder icon|left|thumb]]&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
=Template of an External Module=&lt;br /&gt;
A good model to start development of external module can be found here : [https://github.com/Dolibarr/dolibarr/tree/develop/htdocs/modulebuilder/template GitHub Dolibarr Module Template]&lt;br /&gt;
&lt;br /&gt;
=Create your module=&lt;br /&gt;
==Create a Module descriptor for your Module (required)==&lt;br /&gt;
&#039;&#039;&#039;When it is required&#039;&#039;&#039;: Required as soon as an addon is developed, whatever its goal is (only adding a skin does not require a module descriptor file).&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Since Dolibarr 9.0, you should use the ModuleBuilder module provided as a standard module to generate the module descriptor&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
===Create your module descriptor===&lt;br /&gt;
The first step is to create a file descriptor for the module. &lt;br /&gt;
&lt;br /&gt;
*Create directory &#039;&#039;&#039;/htdocs/custom/&#039;&#039;mymodule&#039;&#039;/core/modules&#039;&#039;&#039; (for an external module) or &#039;&#039;&#039;/htdocs/&#039;&#039;mymodule&#039;&#039;/core/modules&#039;&#039;&#039; if you plan to have this module an official core module of Dolibarr. Then copy the file &amp;lt;code&amp;gt;modMyModule.class.php&amp;lt;/code&amp;gt; from the directory &#039;&#039;&#039;htdocs/modulebuilder/template&#039;&#039;&#039; into this directory. Change the name of the file &amp;lt;code&amp;gt;modMyModule.class.php&amp;lt;/code&amp;gt; to the name corresponding to the purpose of your module. Name of the file must start with &amp;lt;code&amp;gt;mod&amp;lt;/code&amp;gt; and end with &amp;lt;code&amp;gt;.class.php&amp;lt;/code&amp;gt; (for example if you want to give the name &#039;NewName&#039; to this file, then the name should be &amp;lt;code&amp;gt;modNewName.class.php&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
Then, modify the contents of this file as follows:&lt;br /&gt;
&lt;br /&gt;
*Replace all occurrences of &amp;quot;modMyModule&amp;quot; with a value which corresponds to the purpose of your module. This value must always start with &#039;mod&#039; and contain only alpha characters (again, if the name given to the file was &#039;NewName&#039;, then replace all &amp;quot;modMyModule&amp;quot; with &amp;quot;modNewName&amp;quot;).&lt;br /&gt;
*Change the number in: $this-&amp;gt;numero = 100000 by a number that designates your module id. To avoid conflicts with other modules, you can consult the page that lists already reserved id numbers: [[List of modules id|List of module IDs]].&lt;br /&gt;
*Modify any other variables defined in the constructor (see comment in the code skeleton for their meaning).&lt;br /&gt;
&lt;br /&gt;
Your file descriptor for your module is ready. See the next step to activate it.&lt;br /&gt;
&lt;br /&gt;
===Test your descriptor===&lt;br /&gt;
&lt;br /&gt;
Launch Dolibarr and go to page &#039;&#039;&#039;Setup-&amp;gt;module&#039;&#039;&#039;? &lt;br /&gt;
If you set the property version in the module description you should see a new line with your new module and the possibility to activate it or not. If you set the property version to &amp;quot;develop&amp;quot; or &amp;quot;experiental&amp;quot;, to see your module, you must first go into &#039;&#039;&#039;Setup-Others&#039;&#039;&#039; and set MAIN_FEATURES_LEVEL to 1 to see &amp;quot;experimental&amp;quot; modules or 2 to see &amp;quot;development&amp;quot; modules.&lt;br /&gt;
&lt;br /&gt;
==Tree of path for new module files (required)==&lt;br /&gt;
This is how your files must be organized when building a new module (the zip file must also match this rule).&lt;br /&gt;
Note: Only the second line is mandatory.&lt;br /&gt;
&lt;br /&gt;
{{TemplateModuleTreeSimple}}&lt;br /&gt;
&lt;br /&gt;
==Create your SQL tables and the PHP DAO class (optional)==&lt;br /&gt;
&#039;&#039;&#039;When&#039;&#039;&#039;: If your module needs to manage data of its own&lt;br /&gt;
&lt;br /&gt;
===Create your .sql file===&lt;br /&gt;
If your module is designed to manage data of its own, which are not available in the standard version of Dolibarr, it is necessary to define SQL tables to store the data.&lt;br /&gt;
&lt;br /&gt;
Scripts for creating tables and loading data by your own module are saved into a subdirectory sql (&#039;&#039;&#039;&amp;quot;mymodule/sql&amp;quot;&#039;&#039;&#039;) of your module. (With ModuleBuilder, the directory and all sql files will be created automatically when you will create a new Object from tab Object).&lt;br /&gt;
&lt;br /&gt;
Then check into your descriptor file, into function &#039;&#039;&#039;init&#039;&#039;&#039; that the line&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;PHP&amp;quot;&amp;gt;$this-&amp;gt;_load_tables(&#039;/mymodule/sql/&#039;);&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
is not commented.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Rules to follow:&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
*Add the files about creating tables commands on the principle of an &#039;&#039;&#039;llx_mytable.sql&#039;&#039;&#039; file per table, with an optional &#039;&#039;&#039;llx_mytable.key.sql&#039;&#039;&#039; file (see existing files in &#039;&#039;&#039;install/mysql/tables&#039;&#039;&#039; for examples).&lt;br /&gt;
*The recommended type and name for SQL fields are defined into page [[Language_and_development_rules#Table_and_fields_structures]].&lt;br /&gt;
*To manage data, you must create a file called &#039;&#039;&#039;data.sql&#039;&#039;&#039; inside directory &#039;&#039;&#039;/mymodule/sql/&#039;&#039;&#039; that contains SQL command to add/edit/delete data.&lt;br /&gt;
*Don&#039;t use the double quote for strings (eg &#039;chaine&#039; not &amp;quot;chaine&amp;quot;) because the double quote have a specific meaning in PostGreSQL&lt;br /&gt;
&lt;br /&gt;
Example of content of a file data.sql&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;sql&amp;quot;&amp;gt;&lt;br /&gt;
 delete from llx_const where name=&#039;MYMODULE_IT_WORKS&#039; and entity=&#039;__ENTITY__&#039;;&lt;br /&gt;
 insert into llx_const (name, value, type, note, visible, entity) values (&#039;MYMODULE_IT_WORKS&#039;,&#039;1&#039;,&#039;chaine&#039;,&#039;A constant vor my module&#039;,1,&#039;__ENTITY__&#039;);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Files must be operational for the database mysql. Note: The files of other databases are not maintained. They will be read and converted on the fly by the driver of the other database.&lt;br /&gt;
&lt;br /&gt;
===Test your .sql files===&lt;br /&gt;
&lt;br /&gt;
Once the files ready, you can return to the page to enable Dolibarr modules and disable the module, drop those tables in the database (if they already exist) and reactivate the module. The tables should be recreated by the activation of the module. If this is not the case, check the Dolibarr logs, or as a first step try running your scripts manually on your database (because SQL errors from your scripts may not show up in the Dolibarr logs).&lt;br /&gt;
&lt;br /&gt;
===Generate the PHP DAO class===&lt;br /&gt;
The DAO PHP files should have been generated by ModuleBuilder after creating an object.&lt;br /&gt;
&lt;br /&gt;
You can however create them manually by copying existing object however using ModuleBuilder is highly recommended. You should find examples into &#039;&#039;&#039;htdocs/modulebuilder/templates/class/myobject.class.php&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
In this class, there are already operational CRUD (Create/Read/Update/Delete) methods to perform an insert, a fetch (select), an update, a delete of a table row. Edit the file to use the correct module name, tables and place this file in the class subdirectory of the module. The Module Builder allows you to do this with just a few mouse clicks.&lt;br /&gt;
&lt;br /&gt;
==The tab management (optional)==&lt;br /&gt;
&lt;br /&gt;
===Add or remove your own tabs on object sheets===&lt;br /&gt;
&#039;&#039;&#039;When&#039;&#039;&#039;: To add a tab on an object (invoices, orders, proposals, member ...)&lt;br /&gt;
&lt;br /&gt;
To do this go into the file descriptor of module previously created and edit the $this-&amp;gt;tabs array:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;PHP&amp;quot;&amp;gt;&lt;br /&gt;
	// Array to add new pages in new tabs or remove existing one&lt;br /&gt;
	$this-&amp;gt;tabs = array(&#039;objecttype:+tabname1:Title1:mylangfile@mymodule:$user-&amp;gt;rights-&amp;gt;mymodule-&amp;gt;read:/mymodule/mypagetab1.php?id=__ID__&#039;    // To add a new tab identified by code tabname1&lt;br /&gt;
                            &#039;objecttype:+tabname2:Title2:mylangfile@mymodule:$user-&amp;gt;rights-&amp;gt;mymodule-&amp;gt;read:/mymodule/mypagetab2.php?id=__ID__&#039;,   // To add a new tab identified by code tabname2&lt;br /&gt;
                            &#039;objecttype:-tabname&#039;);                                                     // To remove an existing tab identified by code tabname&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The table should contain a list of strings, each string representing a new tab. &lt;br /&gt;
The format of the string consisting of 5 parts separated by &amp;quot;:&amp;quot;&lt;br /&gt;
&lt;br /&gt;
*Part 1: The element type (object type) where the tab should appear is a value from the following:&lt;br /&gt;
{{TemplateModuleTabs}}&lt;br /&gt;
&lt;br /&gt;
*Part 2: A code to identify tab to add (start with +tabname1) or to remove (start with -tabname1)&lt;br /&gt;
*Part 3: The title of the tab(Title1). This can be a hardcoded read or better a code translation in module lang file .&lt;br /&gt;
*Part 4: The name of the file &amp;quot;*.lang&amp;quot; (mylangfile@mymodule) which contains correspondence between the code translation and language to display. If this name is followed with @mymodule, Dolibarr will search translation file &amp;quot;*.lang&amp;quot; within the module in htdocs/custom/mymodule/langs/code_CODE/mylangfile.lang, otherwise Dolibarr will look for file in htdocs/langs/code_CODE/mylangfile.lang&lt;br /&gt;
*Part 5: A condition to test if tab must be visible($user-&amp;gt;rights-&amp;gt;mymodule-&amp;gt;read) &#039;&#039;&#039;or&#039;&#039;&#039; put 1 to be always visible.&lt;br /&gt;
*Part 6: The URL of the page to display when you click on the tab (/mymodule/mypagetab1.php). The __ID__ string will be replaced automatically by the Id of the element concerned.&lt;br /&gt;
&lt;br /&gt;
To feed the contents of the tab with data from the database, see the next chapter.&lt;br /&gt;
&lt;br /&gt;
In order to get the names  &#039;tabname&#039; of existing tabs, you have to check the names used in the function &#039;product_prepare_head&#039; of the file  &#039;core/lib/module.lib.php&#039; corresponding to section &#039;$head[$h][2]&#039;.&lt;br /&gt;
&lt;br /&gt;
===Show tabs navigation into your own pages===&lt;br /&gt;
&#039;&#039;&#039;When&#039;&#039;&#039;: To show all standard tabs of an object (product, tiers, etc.) on your page.&lt;br /&gt;
&lt;br /&gt;
You must follow these steps :&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;1. Include files you need into your file&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
For each object type, there are two files to include with line&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;PHP&amp;quot;&amp;gt;require_once($url_fichier) ;&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This is example of files to include (DOL_DOCUMENT_ROOT is often dolibarr/htdocs/) :&lt;br /&gt;
&lt;br /&gt;
*Object thirdparty (thirdparty) :&lt;br /&gt;
**DOL_DOCUMENT_ROOT/societe/class/societe.class.php&lt;br /&gt;
**DOL_DOCUMENT_ROOT/core/lib/company.lib.php&lt;br /&gt;
*Object product (product) :&lt;br /&gt;
**DOL_DOCUMENT_ROOT/product/class/product.class.php&lt;br /&gt;
**DOL_DOCUMENT_ROOT/core/lib/product.lib.php&lt;br /&gt;
*Object invoice (invoice) :&lt;br /&gt;
**DOL_DOCUMENT_ROOT/compta/facture/class/facture.class.php&lt;br /&gt;
**DOL_DOCUMENT_ROOT/core/lib/invoice.lib.php&lt;br /&gt;
&lt;br /&gt;
...&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;2. Create and load the object to show into your tab&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Create an instance of an object of the correct class and load object from the database by using the fetch method of an object in providing to this method the id you get from URL (ie : /mytab.php?id=1).&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Example :&#039;&#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;PHP&amp;quot;&amp;gt;&lt;br /&gt;
$id=GETPOST(&#039;id&#039;,&#039;int&#039;);&lt;br /&gt;
$ref=GETPOST(&#039;ref&#039;,&#039;alpha&#039;);&lt;br /&gt;
$product = new Product($db) ;&lt;br /&gt;
$result = $product-&amp;gt;fetch($id,$ref) ; // Test $result to check the database read is ok&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;3. Get a list of all tabs to show for your object type&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Use function XXX_prepare_head($obj), where XXX is name of object. This will return an array with all definition of tab entries to show. The parameter to put into this method is the instance of an object you want tabs.&lt;br /&gt;
&lt;br /&gt;
The resulting array has the following structure&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;PHP&amp;quot;&amp;gt;&lt;br /&gt;
$head        // Array of tabs&lt;br /&gt;
$head[$h]    // Element to describe one tab.&lt;br /&gt;
$head[$h][0] // Url of page to show when you click on tab&lt;br /&gt;
$head[$h][1] // Title of tab&lt;br /&gt;
$head[$h][2] // Code name to identify the tab&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Example :&#039;&#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;PHP&amp;quot;&amp;gt;&lt;br /&gt;
$head = product_prepare_head($product, $user) ; // parameter $user is present for some function anly&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;4. show tabs on your page&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Use the &amp;lt;code&amp;gt;dol_fiche_head()&amp;lt;/code&amp;gt; function to show all tabs defined in the &amp;lt;code&amp;gt;$head&amp;lt;/code&amp;gt; array returned by &amp;lt;code&amp;gt;XX_prepare_head()&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;PHP&amp;quot;&amp;gt;&lt;br /&gt;
dol_fiche_head($links, $active=&#039;0&#039;, $title=&#039;&#039;, $notab=0, $picto=&#039;&#039;)&lt;br /&gt;
//$links  // Tableau des onglets, appelé $head plus haut.&lt;br /&gt;
//$active // Onglet actif (mettre le nom de l&#039;onglet défini dans votre fichier de module, ou un nom contenu dans $head[$h][2]). Cet onglet sera mis en surbrillance&lt;br /&gt;
//$title  // Title to show (shown into a special tab that you can&#039;t click)&lt;br /&gt;
//$notab&lt;br /&gt;
//$picto  // Name of image to show into title. Possible values are:&lt;br /&gt;
//            product&lt;br /&gt;
//            service&lt;br /&gt;
//            company&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This function will show required tabs and open an html element &#039;&#039;&amp;lt; div class=&amp;quot;&amp;quot; &amp;gt;&#039;&#039; that correspond to the area under the tabs. To close area of a tab, just use &#039;&#039;&amp;lt; /div &amp;gt;&#039;&#039; into your PHP page.&lt;br /&gt;
&lt;br /&gt;
==Create or modify PHP screens (optional)==&lt;br /&gt;
&#039;&#039;&#039;When&#039;&#039;&#039;: If the purpose of your module is to add features that require new or modified screens.&lt;br /&gt;
&lt;br /&gt;
===Create a new PHP screen===&lt;br /&gt;
You must then create your PHP pages that will show/edit data from tables using the skeleton templates provided as an example in the directory &#039;&#039;&#039;modulebuilder/myobject_page.php&#039;&#039;&#039; (For the development of a script from the command line, see [[Script development]]).&lt;br /&gt;
&lt;br /&gt;
To create a new user screen, create a subdirectory of &#039;&#039;&#039;htdocs&#039;&#039;&#039; (if not already done) for your module (in &#039;&#039;&#039;htdocs/mymodule&#039;&#039;&#039; for example) to store the pages you will create.&lt;br /&gt;
&lt;br /&gt;
Copy, into that directory, the file &#039;&#039;&#039;myobject_page.php&#039;&#039;&#039; that will serve as a starting point for your page file.&lt;br /&gt;
Edit the file to have a correct relative path to the main.inc.php file. &lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;PHP&amp;quot;&amp;gt;&lt;br /&gt;
// Load Dolibarr environment&lt;br /&gt;
$res=0;&lt;br /&gt;
// Try main.inc.php into web root known defined into CONTEXT_DOCUMENT_ROOT (not always defined)&lt;br /&gt;
if (! $res &amp;amp;&amp;amp; ! empty($_SERVER[&amp;quot;CONTEXT_DOCUMENT_ROOT&amp;quot;])) $res=@include($_SERVER[&amp;quot;CONTEXT_DOCUMENT_ROOT&amp;quot;].&amp;quot;/main.inc.php&amp;quot;);&lt;br /&gt;
// Try main.inc.php into web root detected using web root calculated from SCRIPT_FILENAME&lt;br /&gt;
$tmp=empty($_SERVER[&#039;SCRIPT_FILENAME&#039;])?&#039;&#039;:$_SERVER[&#039;SCRIPT_FILENAME&#039;];$tmp2=realpath(__FILE__); $i=strlen($tmp)-1; $j=strlen($tmp2)-1;&lt;br /&gt;
while($i &amp;gt; 0 &amp;amp;&amp;amp; $j &amp;gt; 0 &amp;amp;&amp;amp; isset($tmp[$i]) &amp;amp;&amp;amp; isset($tmp2[$j]) &amp;amp;&amp;amp; $tmp[$i]==$tmp2[$j]) { $i--; $j--; }&lt;br /&gt;
if (! $res &amp;amp;&amp;amp; $i &amp;gt; 0 &amp;amp;&amp;amp; file_exists(substr($tmp, 0, ($i+1)).&amp;quot;/main.inc.php&amp;quot;)) $res=@include(substr($tmp, 0, ($i+1)).&amp;quot;/main.inc.php&amp;quot;);&lt;br /&gt;
if (! $res &amp;amp;&amp;amp; $i &amp;gt; 0 &amp;amp;&amp;amp; file_exists(dirname(substr($tmp, 0, ($i+1))).&amp;quot;/main.inc.php&amp;quot;)) $res=@include(dirname(substr($tmp, 0, ($i+1))).&amp;quot;/main.inc.php&amp;quot;);&lt;br /&gt;
// Try main.inc.php using relative path&lt;br /&gt;
if (! $res &amp;amp;&amp;amp; file_exists(&amp;quot;../main.inc.php&amp;quot;)) $res=@include(&amp;quot;../main.inc.php&amp;quot;);&lt;br /&gt;
if (! $res &amp;amp;&amp;amp; file_exists(&amp;quot;../../main.inc.php&amp;quot;)) $res=@include(&amp;quot;../../main.inc.php&amp;quot;);&lt;br /&gt;
if (! $res &amp;amp;&amp;amp; file_exists(&amp;quot;../../../main.inc.php&amp;quot;)) $res=@include(&amp;quot;../../../main.inc.php&amp;quot;);&lt;br /&gt;
if (! $res) die(&amp;quot;Include of main fails&amp;quot;);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
As you can see, there are several tries to load the main.inc.php (or master.inc.php). The goal is to succeed in the most cases as possible. The minimum is 2 lines: one to try to load the master/main.inc.php into the dolibarr root directory and another one to try to load the file to support the case when the module is deployed into the &amp;quot;custom&amp;quot; directory. But you can have more to deal more situation. The provided example should be able to load the file main/master.inc.php in nearly all situation/setups.&lt;br /&gt;
&lt;br /&gt;
Note that you may add more &amp;quot;../&amp;quot; depending on the depth of the file relative to your module directory tree.&lt;br /&gt;
&lt;br /&gt;
It&#039;s in the main.inc.php file that is loaded technical environment variables and permissions. The following variables are objects positioned in this file:&lt;br /&gt;
&lt;br /&gt;
*$user    Object that contains the characteristics of the user + his permissions.&lt;br /&gt;
*$conf    Object that contains Dolibarr configuration.&lt;br /&gt;
*$db      Object that contains an opened connection handler to the database.&lt;br /&gt;
*$langs   Object that contains the user&#039;s language.&lt;br /&gt;
&lt;br /&gt;
Then enter your code to display the page.&lt;br /&gt;
&lt;br /&gt;
*To include a class or library dedicated to the module is done using a Dolibarr function (and not using directly include_once):&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Example :&#039;&#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;PHP&amp;quot;&amp;gt;&lt;br /&gt;
dol_include_once(&#039;/mymodule/class/myclass.class.php&#039;, &#039;MyClass&#039;);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
*To include classes provided with Dolibarr, use the following syntax:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Example :&#039;&#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;PHP&amp;quot;&amp;gt;&lt;br /&gt;
require_once DOL_DOCUMENT_ROOT.&#039;/core/class/doli.class.php&#039;;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Add some fields into existing forms===&lt;br /&gt;
You may want to provide a module that adds more fields into forms (input and view) of some elements. &lt;br /&gt;
&lt;br /&gt;
A heavy solution (but not so bad) may be to replace all pages used to create element (this means disabling the &amp;quot;New element&amp;quot; menu entry and adding yours, and disabling the tab that shows the element to replace with a tab that is your own full page (copied/pasted from original) to do same than original page but modified to add your fields and stored added data into your own table). Go to menu [[#Define your entries in the menu (optional)]] and [[#The tab management (optional)]] if this solution suits you (this solution is more powerful since you can change everything you want into the page). &lt;br /&gt;
&lt;br /&gt;
We will describe here another solution, that works only to &amp;quot;add fields&amp;quot; at end of existing fields, using the element &amp;quot;category&amp;quot; as an example but you can convert this tutorial for invoice, proposal ...&lt;br /&gt;
&lt;br /&gt;
*First thing is to add a table, owned by your module, to store the value of new fields. This table will only have one column called &amp;lt;code&amp;gt;rowid&amp;lt;/code&amp;gt; (will contain the same value as the &amp;lt;code&amp;gt;rowid&amp;lt;/code&amp;gt; column in the element table) + one column for each new field you want to add. Then, create a class with CRUD (Create/Read/Update/Delete) methods for this new table. For those two tasks, go back to the previous chapter [[#Create your SQL tables and the PHP DAO class (optional)]].&lt;br /&gt;
*Next step is to add a hook into your module to add the new fields into the form. See chapter [[Hooks_system#Implement_the_Hook]] for generic documentation to use hooks.&lt;br /&gt;
&lt;br /&gt;
If you follow this tutorial, to be able to add fields into category forms, you must do:&lt;br /&gt;
{{ToComplete}}&lt;br /&gt;
&lt;br /&gt;
===Add/replace part of fields supported by hooks===&lt;br /&gt;
See chapter [[Hooks_system#Implement_the_Hook]] to know how to use Dolibarr existing hooks to add/replace code at Dolibarr hooks place.&lt;br /&gt;
&lt;br /&gt;
===Database access===&lt;br /&gt;
If you need to edit some data in the database inside your own table, use the PHP class generated before.&lt;br /&gt;
&lt;br /&gt;
If you to make access to tables with no dedicated PHP class available, this is always possible (for example if you want to get a list of records with a particular join or filter). In this case, this is a code samples to follow:&lt;br /&gt;
&lt;br /&gt;
To make an insert, update or delete:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;PHP&amp;quot;&amp;gt;&lt;br /&gt;
$db-&amp;gt;begin();   // Start transaction&lt;br /&gt;
$db-&amp;gt;query(&amp;quot;My SQL request insert, update or delete&amp;quot;);&lt;br /&gt;
$db-&amp;gt;commit();       // Validate transaction&lt;br /&gt;
or $db-&amp;gt;rollback()  // Cancel transaction&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
To read:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;PHP&amp;quot;&amp;gt;&lt;br /&gt;
$resql=$db-&amp;gt;query(&amp;quot;My select request&amp;quot;);&lt;br /&gt;
if ($resql)&lt;br /&gt;
{&lt;br /&gt;
	$num = $db-&amp;gt;num_rows($resql);&lt;br /&gt;
	$i = 0;&lt;br /&gt;
	if ($num)&lt;br /&gt;
	{&lt;br /&gt;
		while ($i &amp;lt; $num)&lt;br /&gt;
		{&lt;br /&gt;
			$obj = $db-&amp;gt;fetch_object($resql);&lt;br /&gt;
			if ($obj)&lt;br /&gt;
			{&lt;br /&gt;
				// You can use here results&lt;br /&gt;
				print $obj-&amp;gt;field1;&lt;br /&gt;
				print $obj-&amp;gt;field2;&lt;br /&gt;
			}&lt;br /&gt;
			$i++;&lt;br /&gt;
		}&lt;br /&gt;
	}&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Define style of your pages===&lt;br /&gt;
To have the look of your own pages to match the Dolibarr theme, it is necessary to use the Dolibarr CSS styles.&lt;br /&gt;
&lt;br /&gt;
You can use for example:&lt;br /&gt;
&lt;br /&gt;
*class=&amp;quot;&#039;&#039;&#039;liste_titre&#039;&#039;&#039;&amp;quot; on tags &#039;&#039;tr&#039;&#039; and &#039;&#039;td&#039;&#039; for the head row of a table.&lt;br /&gt;
*class=&amp;quot;&#039;&#039;&#039;pair&#039;&#039;&#039;&amp;quot; or class=&amp;quot;&#039;&#039;&#039;impair&#039;&#039;&#039;&amp;quot; on tags &#039;&#039;tr&#039;&#039; and &#039;&#039;td&#039;&#039; of other rows of a table.&lt;br /&gt;
*class=&amp;quot;&#039;&#039;&#039;flat&#039;&#039;&#039;&amp;quot; on all input fields (&#039;&#039;input, select, textarea&#039;&#039;...).&lt;br /&gt;
*class=&amp;quot;&#039;&#039;&#039;button&#039;&#039;&#039;&amp;quot; on HTML fields with type &#039;&#039;input type=&amp;quot;submit&amp;quot;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
===Use the Dolibarr date picker===&lt;br /&gt;
If you want to use the Dolibarr date selector (with its calendar popup) into your pages, use the following line:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;PHP&amp;quot;&amp;gt;&lt;br /&gt;
 $form=new Form($db);&lt;br /&gt;
 $form-&amp;gt;select_date(&#039;&#039;,&#039;mykey&#039;,0,0,0,&amp;quot;myform&amp;quot;);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
The string mykey will identify the date selector in the form. You must use different values if you use several date selectors in same page.&lt;br /&gt;
The string myform is the name of the FORM in which the selector is included (value found in the form name=&amp;quot;myform&amp;quot; in HTML page).&lt;br /&gt;
This means a date selector must be included necessarily into an html FORM.&lt;br /&gt;
&lt;br /&gt;
To get value after the POST of your form, the command is:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;PHP&amp;quot;&amp;gt;&lt;br /&gt;
$mydate = dol_mktime(12, 0 , 0, $GETPOST(&#039;mykeymonth&#039;, &#039;int&#039;), GETPOST(&#039;mykeyday&#039;, &#039;int&#039;), GETPOST(&#039;mykeyyear&#039;, &#039;int&#039;));&lt;br /&gt;
print strftime(&#039;%A %d %B %Y&#039;, $mydate);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Overwrite template file (tpl)===&lt;br /&gt;
If you want to overwrite tpl file on your module, you need to declare it on the module_parts :&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;PHP&amp;quot;&amp;gt;&lt;br /&gt;
&#039;tpl&#039; =&amp;gt; 1,&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Then you can put any tpl file on &#039;&#039;&#039;mymodule/core/tpl&#039;&#039;&#039;&lt;br /&gt;
as soon as the module is activate, the tpl will be overwrited&lt;br /&gt;
&lt;br /&gt;
==Add your own setup page (optional)==&lt;br /&gt;
&#039;&#039;&#039;When&#039;&#039;&#039;: If your module needs parameters, which are to be provided by the user, for proper setting up of the module.&lt;br /&gt;
&lt;br /&gt;
===Create your page to edit parameters===&lt;br /&gt;
If your module needs several parameters to be setup, you must create a page to edit options (these options will be saved in the [[Table llx_const|table &#039;&#039;&#039;llx_const&#039;&#039;&#039;]]).&lt;br /&gt;
Create a page named &#039;&#039;&#039;mymodule_setuppage.php&#039;&#039;&#039; that shows a form for possible options to update them into the above-mentioned table.&lt;br /&gt;
It is necessary to take an example from a page of the directory &#039;&#039;&#039;/admin&#039;&#039;&#039; that will show you the way to read/save your parameters.&lt;br /&gt;
Put this PHP page into the directory &#039;&#039;&#039;/admin&#039;&#039;&#039; of your module (e.g. mymodule/admin/mymodule_setuppage.php).&lt;br /&gt;
&lt;br /&gt;
===Modify the descriptor file of your module===&lt;br /&gt;
Then, within the descriptor file of your module, modify the variable &#039;&#039;&#039;config_page_url&#039;&#039;&#039; to set the name of this PHP page.&lt;br /&gt;
If the page is in the directory &#039;&#039;&#039;admin/&#039;&#039;&#039;, then the path is not required, e.g. like this:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;PHP&amp;quot;&amp;gt;&lt;br /&gt;
$this-&amp;gt;config_page_url = array(&amp;quot;mymodule_setuppage.php&amp;quot;);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
If the page is in the directory &#039;&#039;&#039;mymodule/admin/&#039;&#039;&#039;, then like this:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;PHP&amp;quot;&amp;gt;&lt;br /&gt;
$this-&amp;gt;config_page_url = array(&amp;quot;mymodule_setuppage.php@mymodule&amp;quot;);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Test your page===&lt;br /&gt;
Go into page &#039;&#039;&#039;Home-&amp;gt;Setup-&amp;gt;Modules&#039;&#039;&#039;, you should see a picture at the end of the line of your module to reach your setup page. Click on it, you should be able to view/edit parameters from your page.&lt;br /&gt;
&lt;br /&gt;
==Define your entries in the menu (optional)==&lt;br /&gt;
&#039;&#039;&#039;When&#039;&#039;&#039;: If you have created PHP pages, it is necessary that those pages can be reached from menu entries in Dolibarr menu.&lt;br /&gt;
&lt;br /&gt;
===Define your menu entries===&lt;br /&gt;
For this, you must define into the module descriptor, the array this-&amp;gt;menu that declares all menus added by your module.&lt;br /&gt;
This array contains entries that will appear once your module is activated.&lt;br /&gt;
The example module descriptor file &#039;&#039;&#039;modMyModule.class.php&#039;&#039;&#039; contains an example to declare a top menu and also its left menu entries.&lt;br /&gt;
&lt;br /&gt;
This is the example of code to declare your own menu entries in a module descriptor file:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;PHP&amp;quot;&amp;gt;&lt;br /&gt;
// Main menu entries&lt;br /&gt;
$this-&amp;gt;menu = array();			// List of menus to add&lt;br /&gt;
$r=0;&lt;br /&gt;
&lt;br /&gt;
// Add here entries to declare new menus&lt;br /&gt;
// Example to declare the Top Menu entry:&lt;br /&gt;
$this-&amp;gt;menu[$r]=array(	&#039;fk_menu&#039;=&amp;gt;0,			// Put 0 if this is a top menu&lt;br /&gt;
			&#039;type&#039;=&amp;gt;&#039;top&#039;,			// This is a Top menu entry&lt;br /&gt;
			&#039;titre&#039;=&amp;gt;&#039;MyModule top menu&#039;,&lt;br /&gt;
			&#039;mainmenu&#039;=&amp;gt;&#039;mymodule&#039;,&lt;br /&gt;
			&#039;leftmenu&#039;=&amp;gt;&#039;mymodule&#039;,&lt;br /&gt;
			&#039;url&#039;=&amp;gt;&#039;/mymodule/pagetop.php&#039;,&lt;br /&gt;
			&#039;langs&#039;=&amp;gt;&#039;mylangfile&#039;,	// Lang file to use (without .lang) by module. File must be in langs/code_CODE/ directory.&lt;br /&gt;
			&#039;position&#039;=&amp;gt;100,&lt;br /&gt;
			&#039;enabled&#039;=&amp;gt;&#039;1&#039;,			// Define condition to show or hide menu entry. Use &#039;$conf-&amp;gt;mymodule-&amp;gt;enabled&#039; if entry must be visible if module is enabled.&lt;br /&gt;
			&#039;perms&#039;=&amp;gt;&#039;1&#039;,			// Use &#039;perms&#039;=&amp;gt;&#039;$user-&amp;gt;rights-&amp;gt;mymodule-&amp;gt;level1-&amp;gt;level2&#039; if you want your menu with a permission rules&lt;br /&gt;
			&#039;target&#039;=&amp;gt;&#039;&#039;,&lt;br /&gt;
			&#039;user&#039;=&amp;gt;2);				// 0=Menu for internal users, 1=external users, 2=both&lt;br /&gt;
$r++;&lt;br /&gt;
&lt;br /&gt;
// Example to declare a Left Menu entry:&lt;br /&gt;
$this-&amp;gt;menu[$r]=array(	&#039;fk_menu&#039;=&amp;gt;&#039;fk_mainmenu=xxx&#039;,		    // Use &#039;fk_mainmenu=xxx&#039; or &#039;fk_mainmenu=xxx,fk_leftmenu=yyy&#039; where xxx is mainmenucode and yyy is a leftmenucode of parent menu&lt;br /&gt;
			&#039;type&#039;=&amp;gt;&#039;left&#039;,			        // This is a Left menu entry&lt;br /&gt;
			&#039;titre&#039;=&amp;gt;&#039;MyModule left menu 1&#039;,&lt;br /&gt;
			&#039;mainmenu&#039;=&amp;gt;&#039;xxx&#039;,&lt;br /&gt;
			&#039;leftmenu&#039;=&amp;gt;&#039;yyy&#039;,&lt;br /&gt;
			&#039;url&#039;=&amp;gt;&#039;/mymodule/pagelevel1.php&#039;,&lt;br /&gt;
			&#039;langs&#039;=&amp;gt;&#039;mylangfile&#039;,	// Lang file to use (without .lang) by module. File must be in langs/code_CODE/ directory.&lt;br /&gt;
			&#039;position&#039;=&amp;gt;100,&lt;br /&gt;
			&#039;enabled&#039;=&amp;gt;&#039;1&#039;,			// Define condition to show or hide menu entry. Use &#039;$conf-&amp;gt;mymodule-&amp;gt;enabled&#039; if entry must be visible if module is enabled.&lt;br /&gt;
			&#039;perms&#039;=&amp;gt;&#039;1&#039;,			// Use &#039;perms&#039;=&amp;gt;&#039;$user-&amp;gt;rights-&amp;gt;mymodule-&amp;gt;level1-&amp;gt;level2&#039; if you want your menu with a permission rules&lt;br /&gt;
			&#039;target&#039;=&amp;gt;&#039;&#039;,&lt;br /&gt;
			&#039;user&#039;=&amp;gt;2);				// 0=Menu for internal users,1=external users, 2=both&lt;br /&gt;
$r++;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
To show the menu or not depending on a permission, modify property &#039;&#039;&#039;perms&#039;&#039;&#039; in the array. See chapter on permissions later to see how to add permissions.&lt;br /&gt;
&lt;br /&gt;
===Test your menu entries===&lt;br /&gt;
Disable and re-enable your module under the Dolibarr module setup page, menus entries must appear (if property &#039;enabled&#039; is declaration array is ok).&lt;br /&gt;
&lt;br /&gt;
==Add your own permissions (optional)==&lt;br /&gt;
&#039;&#039;&#039;When&#039;&#039;&#039;: If you want to add new permissions.&lt;br /&gt;
&lt;br /&gt;
The way to define permissions that will manage your module is done inside the module descriptor created previously.&lt;br /&gt;
Modify line &lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;PHP&amp;quot;&amp;gt;&lt;br /&gt;
$this-&amp;gt;rights_class = &#039;mymodule&#039;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
with correct value for mymodule.&lt;br /&gt;
&lt;br /&gt;
Then you must fill the array $this-&amp;gt;rights with as many entries than different permissions you need to manage.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;PHP&amp;quot;&amp;gt;&lt;br /&gt;
$this-&amp;gt;rights[$r][0] = 10001;&lt;br /&gt;
$this-&amp;gt;rights[$r][1] = &#039;Label by default of permission&#039;;&lt;br /&gt;
$this-&amp;gt;rights[$r][2] = &#039;r&#039;;&lt;br /&gt;
$this-&amp;gt;rights[$r][3] = 1;&lt;br /&gt;
$this-&amp;gt;rights[$r][4] = &#039;action&#039;;&lt;br /&gt;
$this-&amp;gt;rights[$r][5] = &#039;subaction&#039;;&lt;br /&gt;
$r++;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Into $this-&amp;gt;rights[$r][0], put a permission id not already used (See into menu &#039;&#039;&#039;System info&#039;&#039;&#039; on a working installation of Dolibarr to know list of id already used by standard modules.&lt;br /&gt;
Into $this-&amp;gt;rights[$r][1], put a label by default for permission (This label will be used if no translation can be found into the file &#039;&#039;&#039;admin.lang&#039;&#039;&#039; Translation key should be &amp;quot;Permission10001=My permission Label&amp;quot;).&lt;br /&gt;
Into $this-&amp;gt;rights[$r][2], types of the permission. There are three type of permission, &#039;r&#039; for read, list or expert permission, &#039;w&#039; for write or update permission and &#039;d&#039; for delete permission.&lt;br /&gt;
Into $this-&amp;gt;rights[$r][3], put 1 if this permission must be granted automatically by default to any newly created user.&lt;br /&gt;
Into $this-&amp;gt;rights[$r][4] and $this-&amp;gt;rights[$r][5], put an action and subaction string without spaces. You will be able to test if a user has the permission in your PHP source code with the sequence:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;PHP&amp;quot;&amp;gt;&lt;br /&gt;
if ($user-&amp;gt;rights-&amp;gt;mymodule-&amp;gt;action-&amp;gt;subaction) ...&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Define your own box (optional)==&lt;br /&gt;
&#039;&#039;&#039;When&#039;&#039;&#039;: If your module needs to provide one or several new boxes to show on home page.&lt;br /&gt;
&lt;br /&gt;
===Define your box===&lt;br /&gt;
For this, modify the array $this-&amp;gt;boxes into the module descriptor file.&lt;br /&gt;
All you have to do is to add 2 lines for each box file you will create into directory &#039;&#039;&#039;htdocs/mymodule/core/boxes&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Example:&#039;&#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;PHP&amp;quot;&amp;gt;&lt;br /&gt;
$this-&amp;gt;boxes[0][&#039;file&#039;]=&#039;mybox0.php@mymodule&#039;&lt;br /&gt;
$this-&amp;gt;boxes[0][&#039;note&#039;]=&#039;My box 0&#039;&lt;br /&gt;
 ...&lt;br /&gt;
$this-&amp;gt;boxes[n][&#039;file&#039;]=&#039;myboxn.php@mymodule&#039;&lt;br /&gt;
$this-&amp;gt;boxes[n][&#039;note&#039;]=&#039;My box n&#039;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Then create files &#039;&#039;&#039;htdocs/mymodule/core/boxes/mybox0.php&#039;&#039;&#039;, &#039;&#039;&#039;htdocs/mymodule/core/boxes/mybox1.php&#039;&#039;&#039;... by copying an example from an existing box file (found into directory &#039;&#039;&#039;htdocs/core/boxes&#039;&#039;&#039;).&lt;br /&gt;
&lt;br /&gt;
===Test if your box is detected by Dolibarr===&lt;br /&gt;
Disable and enabled module.&lt;br /&gt;
&lt;br /&gt;
Go into menu &#039;&#039;&#039;Home - Setup - Boxes&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Your boxes must appear in the list of boxes you can activate. Activate the box and go on the home page to see if the box is showing correctly.&lt;br /&gt;
&lt;br /&gt;
==Define your own export (optional)==&lt;br /&gt;
&#039;&#039;&#039;When&#039;&#039;&#039;: If your module provides new predefined database export profiles (for its own tables or for already existing tables of another module).&lt;br /&gt;
&lt;br /&gt;
===Define export===&lt;br /&gt;
For this uncomment and modify arrays $this-&amp;gt;export_xxx in your module descriptor file.&lt;br /&gt;
&lt;br /&gt;
===Test your export===&lt;br /&gt;
Go into menu Tools -&amp;gt; Export. Your export will appear in the list of available predefined exports (if your module is enabled).&lt;br /&gt;
Choose it, you must see a list of all possible fields defined in the export arrays.&lt;br /&gt;
Choose on field and try to build an export file. If ok, try again with all fields.&lt;br /&gt;
&lt;br /&gt;
==Define your CSS styles (optional)==&lt;br /&gt;
&#039;&#039;&#039;When&#039;&#039;&#039;: If in your PHP pages, you use class styles that are not defined inside Dolibarr themes CSS (not recommended).&lt;br /&gt;
&lt;br /&gt;
===Create and declare your style sheet===&lt;br /&gt;
Create a style sheet CSS named &#039;&#039;&#039;mymodule.css&#039;&#039;&#039; or &#039;&#039;&#039;mymodule.css.php&#039;&#039;&#039; and put it into directory &#039;&#039;&#039;htdocs/mymodule&#039;&#039;&#039;. You can have several CSS files per module.&lt;br /&gt;
Remember it&#039;s better to use existing styles already available by default into Dolibarr (The CSS file used by Dolibarr is file &#039;&#039;&#039;themes/mytheme/&#039;&#039;themename&#039;&#039;.css.php&#039;&#039;&#039;. Create your own CSS files only if you need absolutely to add not already existing styles.&lt;br /&gt;
&lt;br /&gt;
Once your style sheets are ready, declare them into your module descriptor file by modifying the property &#039;&#039;&#039;$this-&amp;gt;modules_parts&#039;&#039;&#039;.&lt;br /&gt;
Value to put here must be an array of relative URLs of your CSS files.&lt;br /&gt;
For example&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;PHP&amp;quot;&amp;gt;&lt;br /&gt;
$this-&amp;gt;module_parts = array(&#039;css&#039; =&amp;gt; array(&#039;/mymodule/css/mymodule.css.php&#039;,&#039;/mymodule/css/myother.css&#039;));&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Test your style sheet===&lt;br /&gt;
Disable and enable your module.&lt;br /&gt;
&lt;br /&gt;
Go on the home page (index.php). Show the HTML source of the page.&lt;br /&gt;
&lt;br /&gt;
In the HTML header, you should see a line that declares your style sheet.&lt;br /&gt;
&lt;br /&gt;
==Add your JavaScript functions (optional)==&lt;br /&gt;
&#039;&#039;&#039;When&#039;&#039;&#039;: If in your PHP pages, you use javascript functions not available in Dolibarr (in file lib_head.js)&lt;br /&gt;
&lt;br /&gt;
If you need to use your own JavaScript functions inside your PHP pages, it is necessary to define your functions in your JavaScript file &#039;&#039;&#039;htdocs/mymodule/js/mymodule.js&#039;&#039;&#039;, included in the HTML &amp;lt;code&amp;gt;&amp;amp;lt;head/&amp;amp;gt;&amp;lt;/code&amp;gt; section.&lt;br /&gt;
Dolibarr is responsible for building that HTML section. In order to ask it to include your JavaScript file, you just need to provide it to the llxHeader() function called by your page.&lt;br /&gt;
&lt;br /&gt;
Example for page /htdocs/mymodule/mypage.php :&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;PHP&amp;quot;&amp;gt;&lt;br /&gt;
$morejs=array(&amp;quot;/mymodule/js/mymodule.js&amp;quot;);&lt;br /&gt;
llxHeader(&#039;&#039;,&#039;Titre&#039;,&#039;&#039;,&#039;&#039;,&#039;&#039;,&#039;&#039;,$morejs,&#039;&#039;,0,0); &lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Run your own code on any Dolibarr event (optional)==&lt;br /&gt;
&#039;&#039;&#039;When&#039;&#039;&#039;: If you want to execute your own code once a common Dolibarr event has occurred (example: I want to update a table in my module when an invoice is created into Dolibarr), you must create a &#039;&#039;&#039;trigger&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
See also [[Interfaces_Dolibarr_toward_foreign_systems]]&lt;br /&gt;
and [[Interfaces_from_foreign_systems_toward_Dolibarr]]&lt;br /&gt;
&lt;br /&gt;
==Insert your code inside Dolibarr hooks positions (optional)==&lt;br /&gt;
&#039;&#039;&#039;When&#039;&#039;&#039;: When you want to add code or replace Dolibarr code into another situation than a business event (See the previous chapter for adding code during a business event).&lt;br /&gt;
&lt;br /&gt;
See page [[Hooks_system]].&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Add your own numbering rules==&lt;br /&gt;
&#039;&#039;&#039;When&#039;&#039;&#039;: When you need a new rule for generated ref of elements that are not covered by existing rules.&lt;br /&gt;
&lt;br /&gt;
See page [[Create numbering module]].&lt;br /&gt;
&lt;br /&gt;
==Add your document template (optional)==&lt;br /&gt;
&#039;&#039;&#039;When&#039;&#039;&#039;: When you want to personalize your own generated PDF or ODT documents.&lt;br /&gt;
&lt;br /&gt;
Note: To add this feature, you don&#039;t need to create a module descriptor.&lt;br /&gt;
&lt;br /&gt;
Documentation to add your own template is available on page [[Create_a_PDF_document_template]] or [[Create_an_ODT_document_template]].&lt;br /&gt;
&lt;br /&gt;
==Add your skin (optional)==&lt;br /&gt;
&#039;&#039;&#039;When&#039;&#039;&#039;: When you want to personalized your colors/fonts/images.&lt;br /&gt;
&lt;br /&gt;
Note: To add this feature, you don&#039;t need to create a module descriptor.&lt;br /&gt;
&lt;br /&gt;
To add your own skin, read page [[Skins]].&lt;br /&gt;
&lt;br /&gt;
=Some coding rules and predefined functions=&lt;br /&gt;
The coding rules to be followed are defined in the [[Developer documentation]], under section &amp;quot;General Information - Language and standards development&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
A lot of predefined features for developers are also available and described into page [[Developer documentation]] under section &amp;quot;Technical components of Dolibarr&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
=Create a package to distribute and install your module=&lt;br /&gt;
This process must be used to generate a package to submit it on the http://www.dolistore.com marketplace.&lt;br /&gt;
But you can use it to have a package easy to distribute on your own network.&lt;br /&gt;
&lt;br /&gt;
*Go into the directory &#039;&#039;&#039;/build&#039;&#039;&#039; and copy the file &#039;&#039;&#039;makepack-dolibarrmodules.conf&#039;&#039;&#039; into &#039;&#039;&#039;makepack-mymodule.conf&#039;&#039;&#039;. Warning, this directory may not be provided in some packages of stable versions. If so, it can be retrieved from the snapshot available for download on the Dolibarr website in area &amp;quot;Development version&amp;quot; (taken in this case the whole build directory which is autonomous and independent directory).&lt;br /&gt;
&lt;br /&gt;
Edit this file to add a list of file names for all new files you created for your module (module descriptor, new sql tables files, php page, images, etc...)&lt;br /&gt;
&lt;br /&gt;
*Run the script via Perl (need the Perl version 5.0 or later):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
perl makepack-dolibarrmodule.pl&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
The script asks you the name of your module, its major and minor version. A file &#039;&#039;&#039;mymodule.zip &#039;&#039;&#039; will then be manufactured containing your module ready to be deployed.&lt;br /&gt;
&lt;br /&gt;
*The person who receives your module must then place the file in the root directory of a Dolibarr installation and perform the command:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
tar -xvf mymodule.zip&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
*If you want your module to be public, you can submit it (the zip file) on the Dolibarr marketplace website: {{LinkToPluginDownload}} (you must first create an account and be logged in to use the &amp;quot;Submit a module/product&amp;quot; link).&lt;br /&gt;
**If your module was built correctly, the file will be validated later.&lt;br /&gt;
**If quality is sufficient and license permits it, the code might be added inside main Dolibarr sources (except if you disagree for that).&lt;br /&gt;
&lt;br /&gt;
=Enabling/activation condition of external module on DoliStore=&lt;br /&gt;
&lt;br /&gt;
See [[Module_Dolistore_Validation_Rules|Validation Rules]]&lt;br /&gt;
[[Category:Development]]&lt;/div&gt;</summary>
		<author><name>TanguyP</name></author>
	</entry>
	<entry>
		<id>https://wiki.dolibarr.org/index.php?title=Module_development&amp;diff=63068</id>
		<title>Module development</title>
		<link rel="alternate" type="text/html" href="https://wiki.dolibarr.org/index.php?title=Module_development&amp;diff=63068"/>
		<updated>2025-04-17T18:20:27Z</updated>

		<summary type="html">&lt;p&gt;TanguyP: Improve wording; Fix links&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;!-- BEGIN origin interlang links --&amp;gt;&lt;br /&gt;
&amp;lt;!-- You can edit this section but do NOT remove these comments&lt;br /&gt;
     Links below will be automatically replicated on translated pages by PolyglotBot --&amp;gt;&lt;br /&gt;
[[fr:Développement_module]]&lt;br /&gt;
[[es:Desarrollo_de_un_módulo]]&lt;br /&gt;
[[de:Modul_Entwicklung]]&lt;br /&gt;
[[zh:模块开发]]&lt;br /&gt;
[[ja:モジュール_開発]]&lt;br /&gt;
&amp;lt;!-- END interlang links --&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Category:Core]]&lt;br /&gt;
{{TemplateDocDevEn}}&lt;br /&gt;
&lt;br /&gt;
To create a new module/addon for Dolibarr, there are several steps. This tutorial will describe each of them to let you build a module that extends Dolibarr features, such as:&lt;br /&gt;
&lt;br /&gt;
*Add new tables in database.&lt;br /&gt;
*Add your own menu entries.&lt;br /&gt;
*Add new screens to edit new tables.&lt;br /&gt;
*Add or remove tabs on object view (invoice, product, order, event, ...).&lt;br /&gt;
*Add predefined exports for the internal export tool.&lt;br /&gt;
*Add new information widget in the home page.&lt;br /&gt;
*Add new substitutions variables.&lt;br /&gt;
*Define new permissions.&lt;br /&gt;
*Execute code automatically triggered by a particular Dolibarr action.&lt;br /&gt;
*Insert your code inside Dolibarr hooks positions.&lt;br /&gt;
*Add your numbering rule to generate the reference of objects&lt;br /&gt;
*Add a new document template.&lt;br /&gt;
*Add a new skin.&lt;br /&gt;
&lt;br /&gt;
etc...&lt;br /&gt;
&lt;br /&gt;
The following chapters explain how to do all of this manually in an easy way.&lt;br /&gt;
&lt;br /&gt;
=Module creation with the module builder=&lt;br /&gt;
From Dolibarr v. 12.0 it is possible to create the main pages of your module with the Module Builder. To activate it:&lt;br /&gt;
&lt;br /&gt;
Go into the list of modules and enable the &amp;quot;Module Builder&amp;quot; module:&lt;br /&gt;
[[File:Module Builder.png|alt=Module Builder|thumb|none]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Then click on the &amp;quot;bug&amp;quot; image in the top right of screen.[[File:Module Builder icon.png|alt=Module Builder icon|left|thumb]]&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
=Template of an External Module=&lt;br /&gt;
A good model to start development of external module can be found here : [https://github.com/Dolibarr/dolibarr/tree/develop/htdocs/modulebuilder/template GitHub Dolibarr Module Template]&lt;br /&gt;
&lt;br /&gt;
=Create your module=&lt;br /&gt;
==Create a Module descriptor for your Module (required)==&lt;br /&gt;
&#039;&#039;&#039;When it is required&#039;&#039;&#039;: Required as soon as an addon is developed, whatever its goal is (only adding a skin does not require a module descriptor file).&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Since Dolibarr 9.0, you should use the ModuleBuilder module provided as a standard module to generate the module descriptor&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
===Create your module descriptor===&lt;br /&gt;
The first step is to create a file descriptor for the module. &lt;br /&gt;
&lt;br /&gt;
*Create directory &#039;&#039;&#039;/htdocs/custom/&#039;&#039;mymodule&#039;&#039;/core/modules&#039;&#039;&#039; (for an external module) or &#039;&#039;&#039;/htdocs/&#039;&#039;mymodule&#039;&#039;/core/modules&#039;&#039;&#039; if you plan to have this module an official core module of Dolibarr. Then copy the file &amp;lt;code&amp;gt;modMyModule.class.php&amp;lt;/code&amp;gt; from the directory &#039;&#039;&#039;htdocs/modulebuilder/template&#039;&#039;&#039; into this directory. Change the name of the file &amp;lt;code&amp;gt;modMyModule.class.php&amp;lt;/code&amp;gt; to the name corresponding to the purpose of your module. Name of the file must start with &amp;lt;code&amp;gt;mod&amp;lt;/code&amp;gt; and end with &amp;lt;code&amp;gt;.class.php&amp;lt;/code&amp;gt; (for example if you want to give the name &#039;NewName&#039; to this file, then the name should be &amp;lt;code&amp;gt;modNewName.class.php&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
Then, modify the contents of this file as follows:&lt;br /&gt;
&lt;br /&gt;
*Replace all occurrences of &amp;quot;modMyModule&amp;quot; with a value which corresponds to the purpose of your module. This value must always start with &#039;mod&#039; and contain only alpha characters (again, if the name given to the file was &#039;NewName&#039;, then replace all &amp;quot;modMyModule&amp;quot; with &amp;quot;modNewName&amp;quot;).&lt;br /&gt;
*Change the number in: $this-&amp;gt;numero = 100000 by a number that designates your module id. To avoid conflicts with other modules, you can consult the page that lists already reserved id numbers: [[List of modules id|List of module IDs]].&lt;br /&gt;
*Modify any other variables defined in the constructor (see comment in the code skeleton for their meaning).&lt;br /&gt;
&lt;br /&gt;
Your file descriptor for your module is ready. See the next step to activate it.&lt;br /&gt;
&lt;br /&gt;
===Test your descriptor===&lt;br /&gt;
&lt;br /&gt;
Launch Dolibarr and go to page &#039;&#039;&#039;Setup-&amp;gt;module&#039;&#039;&#039;? &lt;br /&gt;
If you set the property version in the module description you should see a new line with your new module and the possibility to activate it or not. If you set the property version to &amp;quot;develop&amp;quot; or &amp;quot;experiental&amp;quot;, to see your module, you must first go into &#039;&#039;&#039;Setup-Others&#039;&#039;&#039; and set MAIN_FEATURES_LEVEL to 1 to see &amp;quot;experimental&amp;quot; modules or 2 to see &amp;quot;development&amp;quot; modules.&lt;br /&gt;
&lt;br /&gt;
==Tree of path for new module files (required)==&lt;br /&gt;
This is how your files must be organized when building a new module (the zip file must also match this rule).&lt;br /&gt;
Note: Only the second line is mandatory.&lt;br /&gt;
&lt;br /&gt;
{{TemplateModuleTreeSimple}}&lt;br /&gt;
&lt;br /&gt;
==Create your SQL tables and the PHP DAO class (optional)==&lt;br /&gt;
&#039;&#039;&#039;When&#039;&#039;&#039;: If your module needs to manage data of its own&lt;br /&gt;
&lt;br /&gt;
===Create your .sql file===&lt;br /&gt;
If your module is designed to manage data of its own, which are not available in the standard version of Dolibarr, it is necessary to define SQL tables to store the data.&lt;br /&gt;
&lt;br /&gt;
Scripts for creating tables and loading data by your own module are saved into a subdirectory sql (&#039;&#039;&#039;&amp;quot;mymodule/sql&amp;quot;&#039;&#039;&#039;) of your module. (With ModuleBuilder, the directory and all sql files will be created automatically when you will create a new Object from tab Object).&lt;br /&gt;
&lt;br /&gt;
Then check into your descriptor file, into function &#039;&#039;&#039;init&#039;&#039;&#039; that the line&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;PHP&amp;quot;&amp;gt;$this-&amp;gt;_load_tables(&#039;/mymodule/sql/&#039;);&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
is not commented.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Rules to follow:&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
*Add the files about creating tables commands on the principle of an &#039;&#039;&#039;llx_mytable.sql&#039;&#039;&#039; file per table, with an optional &#039;&#039;&#039;llx_mytable.key.sql&#039;&#039;&#039; file (see existing files in &#039;&#039;&#039;install/mysql/tables&#039;&#039;&#039; for examples).&lt;br /&gt;
*The recommended type and name for SQL fields are defined into page [[Language_and_development_rules#Table_and_fields_structures]].&lt;br /&gt;
*To manage data, you must create a file called &#039;&#039;&#039;data.sql&#039;&#039;&#039; inside directory &#039;&#039;&#039;/mymodule/sql/&#039;&#039;&#039; that contains SQL command to add/edit/delete data.&lt;br /&gt;
*Don&#039;t use the double quote for strings (eg &#039;chaine&#039; not &amp;quot;chaine&amp;quot;) because the double quote have a specific meaning in PostGreSQL&lt;br /&gt;
&lt;br /&gt;
Example of content of a file data.sql&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;sql&amp;quot;&amp;gt;&lt;br /&gt;
 delete from llx_const where name=&#039;MYMODULE_IT_WORKS&#039; and entity=&#039;__ENTITY__&#039;;&lt;br /&gt;
 insert into llx_const (name, value, type, note, visible, entity) values (&#039;MYMODULE_IT_WORKS&#039;,&#039;1&#039;,&#039;chaine&#039;,&#039;A constant vor my module&#039;,1,&#039;__ENTITY__&#039;);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Files must be operational for the database mysql. Note: The files of other databases are not maintained. They will be read and converted on the fly by the driver of the other database.&lt;br /&gt;
&lt;br /&gt;
===Test your .sql files===&lt;br /&gt;
&lt;br /&gt;
Once the files ready, you can return to the page to enable Dolibarr modules and disable the module, drop those tables in the database (if they already exist) and reactivate the module. The tables should be recreated by the activation of the module. If this is not the case, check your scripts by passing them by hand, or check the Dolibarr logs.&lt;br /&gt;
&lt;br /&gt;
===Generate the PHP DAO class===&lt;br /&gt;
The DAO PHP files should have been generated by ModuleBuilder after creating an object.&lt;br /&gt;
&lt;br /&gt;
You can however create them manually by copying existing object however using ModuleBuilder is highly recommended. You should find examples into &#039;&#039;&#039;htdocs/modulebuilder/templates/class/myobject.class.php&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
In this class, there are already operational CRUD (Create/Read/Update/Delete) methods to perform an insert, a fetch (select), an update, a delete of a table row. Edit the file to use the correct module name, tables and place this file in the class subdirectory of the module. The Module Builder allows you to do this with just a few mouse clicks.&lt;br /&gt;
&lt;br /&gt;
==The tab management (optional)==&lt;br /&gt;
&lt;br /&gt;
===Add or remove your own tabs on object sheets===&lt;br /&gt;
&#039;&#039;&#039;When&#039;&#039;&#039;: To add a tab on an object (invoices, orders, proposals, member ...)&lt;br /&gt;
&lt;br /&gt;
To do this go into the file descriptor of module previously created and edit the $this-&amp;gt;tabs array:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;PHP&amp;quot;&amp;gt;&lt;br /&gt;
	// Array to add new pages in new tabs or remove existing one&lt;br /&gt;
	$this-&amp;gt;tabs = array(&#039;objecttype:+tabname1:Title1:mylangfile@mymodule:$user-&amp;gt;rights-&amp;gt;mymodule-&amp;gt;read:/mymodule/mypagetab1.php?id=__ID__&#039;    // To add a new tab identified by code tabname1&lt;br /&gt;
                            &#039;objecttype:+tabname2:Title2:mylangfile@mymodule:$user-&amp;gt;rights-&amp;gt;mymodule-&amp;gt;read:/mymodule/mypagetab2.php?id=__ID__&#039;,   // To add a new tab identified by code tabname2&lt;br /&gt;
                            &#039;objecttype:-tabname&#039;);                                                     // To remove an existing tab identified by code tabname&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The table should contain a list of strings, each string representing a new tab. &lt;br /&gt;
The format of the string consisting of 5 parts separated by &amp;quot;:&amp;quot;&lt;br /&gt;
&lt;br /&gt;
*Part 1: The element type (object type) where the tab should appear is a value from the following:&lt;br /&gt;
{{TemplateModuleTabs}}&lt;br /&gt;
&lt;br /&gt;
*Part 2: A code to identify tab to add (start with +tabname1) or to remove (start with -tabname1)&lt;br /&gt;
*Part 3: The title of the tab(Title1). This can be a hardcoded read or better a code translation in module lang file .&lt;br /&gt;
*Part 4: The name of the file &amp;quot;*.lang&amp;quot; (mylangfile@mymodule) which contains correspondence between the code translation and language to display. If this name is followed with @mymodule, Dolibarr will search translation file &amp;quot;*.lang&amp;quot; within the module in htdocs/custom/mymodule/langs/code_CODE/mylangfile.lang, otherwise Dolibarr will look for file in htdocs/langs/code_CODE/mylangfile.lang&lt;br /&gt;
*Part 5: A condition to test if tab must be visible($user-&amp;gt;rights-&amp;gt;mymodule-&amp;gt;read) &#039;&#039;&#039;or&#039;&#039;&#039; put 1 to be always visible.&lt;br /&gt;
*Part 6: The URL of the page to display when you click on the tab (/mymodule/mypagetab1.php). The __ID__ string will be replaced automatically by the Id of the element concerned.&lt;br /&gt;
&lt;br /&gt;
To feed the contents of the tab with data from the database, see the next chapter.&lt;br /&gt;
&lt;br /&gt;
In order to get the names  &#039;tabname&#039; of existing tabs, you have to check the names used in the function &#039;product_prepare_head&#039; of the file  &#039;core/lib/module.lib.php&#039; corresponding to section &#039;$head[$h][2]&#039;.&lt;br /&gt;
&lt;br /&gt;
===Show tabs navigation into your own pages===&lt;br /&gt;
&#039;&#039;&#039;When&#039;&#039;&#039;: To show all standard tabs of an object (product, tiers, etc.) on your page.&lt;br /&gt;
&lt;br /&gt;
You must follow these steps :&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;1. Include files you need into your file&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
For each object type, there are two files to include with line&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;PHP&amp;quot;&amp;gt;require_once($url_fichier) ;&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This is example of files to include (DOL_DOCUMENT_ROOT is often dolibarr/htdocs/) :&lt;br /&gt;
&lt;br /&gt;
*Object thirdparty (thirdparty) :&lt;br /&gt;
**DOL_DOCUMENT_ROOT/societe/class/societe.class.php&lt;br /&gt;
**DOL_DOCUMENT_ROOT/core/lib/company.lib.php&lt;br /&gt;
*Object product (product) :&lt;br /&gt;
**DOL_DOCUMENT_ROOT/product/class/product.class.php&lt;br /&gt;
**DOL_DOCUMENT_ROOT/core/lib/product.lib.php&lt;br /&gt;
*Object invoice (invoice) :&lt;br /&gt;
**DOL_DOCUMENT_ROOT/compta/facture/class/facture.class.php&lt;br /&gt;
**DOL_DOCUMENT_ROOT/core/lib/invoice.lib.php&lt;br /&gt;
&lt;br /&gt;
...&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;2. Create and load the object to show into your tab&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Create an instance of an object of the correct class and load object from the database by using the fetch method of an object in providing to this method the id you get from URL (ie : /mytab.php?id=1).&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Example :&#039;&#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;PHP&amp;quot;&amp;gt;&lt;br /&gt;
$id=GETPOST(&#039;id&#039;,&#039;int&#039;);&lt;br /&gt;
$ref=GETPOST(&#039;ref&#039;,&#039;alpha&#039;);&lt;br /&gt;
$product = new Product($db) ;&lt;br /&gt;
$result = $product-&amp;gt;fetch($id,$ref) ; // Test $result to check the database read is ok&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;3. Get a list of all tabs to show for your object type&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Use function XXX_prepare_head($obj), where XXX is name of object. This will return an array with all definition of tab entries to show. The parameter to put into this method is the instance of an object you want tabs.&lt;br /&gt;
&lt;br /&gt;
The resulting array has the following structure&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;PHP&amp;quot;&amp;gt;&lt;br /&gt;
$head        // Array of tabs&lt;br /&gt;
$head[$h]    // Element to describe one tab.&lt;br /&gt;
$head[$h][0] // Url of page to show when you click on tab&lt;br /&gt;
$head[$h][1] // Title of tab&lt;br /&gt;
$head[$h][2] // Code name to identify the tab&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Example :&#039;&#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;PHP&amp;quot;&amp;gt;&lt;br /&gt;
$head = product_prepare_head($product, $user) ; // parameter $user is present for some function anly&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;4. show tabs on your page&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Use the &amp;lt;code&amp;gt;dol_fiche_head()&amp;lt;/code&amp;gt; function to show all tabs defined in the &amp;lt;code&amp;gt;$head&amp;lt;/code&amp;gt; array returned by &amp;lt;code&amp;gt;XX_prepare_head()&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;PHP&amp;quot;&amp;gt;&lt;br /&gt;
dol_fiche_head($links, $active=&#039;0&#039;, $title=&#039;&#039;, $notab=0, $picto=&#039;&#039;)&lt;br /&gt;
//$links  // Tableau des onglets, appelé $head plus haut.&lt;br /&gt;
//$active // Onglet actif (mettre le nom de l&#039;onglet défini dans votre fichier de module, ou un nom contenu dans $head[$h][2]). Cet onglet sera mis en surbrillance&lt;br /&gt;
//$title  // Title to show (shown into a special tab that you can&#039;t click)&lt;br /&gt;
//$notab&lt;br /&gt;
//$picto  // Name of image to show into title. Possible values are:&lt;br /&gt;
//            product&lt;br /&gt;
//            service&lt;br /&gt;
//            company&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This function will show required tabs and open an html element &#039;&#039;&amp;lt; div class=&amp;quot;&amp;quot; &amp;gt;&#039;&#039; that correspond to the area under the tabs. To close area of a tab, just use &#039;&#039;&amp;lt; /div &amp;gt;&#039;&#039; into your PHP page.&lt;br /&gt;
&lt;br /&gt;
==Create or modify PHP screens (optional)==&lt;br /&gt;
&#039;&#039;&#039;When&#039;&#039;&#039;: If the purpose of your module is to add features that require new or modified screens.&lt;br /&gt;
&lt;br /&gt;
===Create a new PHP screen===&lt;br /&gt;
You must then create your PHP pages that will show/edit data from tables using the skeleton templates provided as an example in the directory &#039;&#039;&#039;modulebuilder/myobject_page.php&#039;&#039;&#039; (For the development of a script from the command line, see [[Script development]]).&lt;br /&gt;
&lt;br /&gt;
To create a new user screen, create a subdirectory of &#039;&#039;&#039;htdocs&#039;&#039;&#039; (if not already done) for your module (in &#039;&#039;&#039;htdocs/mymodule&#039;&#039;&#039; for example) to store the pages you will create.&lt;br /&gt;
&lt;br /&gt;
Copy, into that directory, the file &#039;&#039;&#039;myobject_page.php&#039;&#039;&#039; that will serve as a starting point for your page file.&lt;br /&gt;
Edit the file to have a correct relative path to the main.inc.php file. &lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;PHP&amp;quot;&amp;gt;&lt;br /&gt;
// Load Dolibarr environment&lt;br /&gt;
$res=0;&lt;br /&gt;
// Try main.inc.php into web root known defined into CONTEXT_DOCUMENT_ROOT (not always defined)&lt;br /&gt;
if (! $res &amp;amp;&amp;amp; ! empty($_SERVER[&amp;quot;CONTEXT_DOCUMENT_ROOT&amp;quot;])) $res=@include($_SERVER[&amp;quot;CONTEXT_DOCUMENT_ROOT&amp;quot;].&amp;quot;/main.inc.php&amp;quot;);&lt;br /&gt;
// Try main.inc.php into web root detected using web root calculated from SCRIPT_FILENAME&lt;br /&gt;
$tmp=empty($_SERVER[&#039;SCRIPT_FILENAME&#039;])?&#039;&#039;:$_SERVER[&#039;SCRIPT_FILENAME&#039;];$tmp2=realpath(__FILE__); $i=strlen($tmp)-1; $j=strlen($tmp2)-1;&lt;br /&gt;
while($i &amp;gt; 0 &amp;amp;&amp;amp; $j &amp;gt; 0 &amp;amp;&amp;amp; isset($tmp[$i]) &amp;amp;&amp;amp; isset($tmp2[$j]) &amp;amp;&amp;amp; $tmp[$i]==$tmp2[$j]) { $i--; $j--; }&lt;br /&gt;
if (! $res &amp;amp;&amp;amp; $i &amp;gt; 0 &amp;amp;&amp;amp; file_exists(substr($tmp, 0, ($i+1)).&amp;quot;/main.inc.php&amp;quot;)) $res=@include(substr($tmp, 0, ($i+1)).&amp;quot;/main.inc.php&amp;quot;);&lt;br /&gt;
if (! $res &amp;amp;&amp;amp; $i &amp;gt; 0 &amp;amp;&amp;amp; file_exists(dirname(substr($tmp, 0, ($i+1))).&amp;quot;/main.inc.php&amp;quot;)) $res=@include(dirname(substr($tmp, 0, ($i+1))).&amp;quot;/main.inc.php&amp;quot;);&lt;br /&gt;
// Try main.inc.php using relative path&lt;br /&gt;
if (! $res &amp;amp;&amp;amp; file_exists(&amp;quot;../main.inc.php&amp;quot;)) $res=@include(&amp;quot;../main.inc.php&amp;quot;);&lt;br /&gt;
if (! $res &amp;amp;&amp;amp; file_exists(&amp;quot;../../main.inc.php&amp;quot;)) $res=@include(&amp;quot;../../main.inc.php&amp;quot;);&lt;br /&gt;
if (! $res &amp;amp;&amp;amp; file_exists(&amp;quot;../../../main.inc.php&amp;quot;)) $res=@include(&amp;quot;../../../main.inc.php&amp;quot;);&lt;br /&gt;
if (! $res) die(&amp;quot;Include of main fails&amp;quot;);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
As you can see, there are several tries to load the main.inc.php (or master.inc.php). The goal is to succeed in the most cases as possible. The minimum is 2 lines: one to try to load the master/main.inc.php into the dolibarr root directory and another one to try to load the file to support the case when the module is deployed into the &amp;quot;custom&amp;quot; directory. But you can have more to deal more situation. The provided example should be able to load the file main/master.inc.php in nearly all situation/setups.&lt;br /&gt;
&lt;br /&gt;
Note that you may add more &amp;quot;../&amp;quot; depending on the depth of the file relative to your module directory tree.&lt;br /&gt;
&lt;br /&gt;
It&#039;s in the main.inc.php file that is loaded technical environment variables and permissions. The following variables are objects positioned in this file:&lt;br /&gt;
&lt;br /&gt;
*$user    Object that contains the characteristics of the user + his permissions.&lt;br /&gt;
*$conf    Object that contains Dolibarr configuration.&lt;br /&gt;
*$db      Object that contains an opened connection handler to the database.&lt;br /&gt;
*$langs   Object that contains the user&#039;s language.&lt;br /&gt;
&lt;br /&gt;
Then enter your code to display the page.&lt;br /&gt;
&lt;br /&gt;
*To include a class or library dedicated to the module is done using a Dolibarr function (and not using directly include_once):&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Example :&#039;&#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;PHP&amp;quot;&amp;gt;&lt;br /&gt;
dol_include_once(&#039;/mymodule/class/myclass.class.php&#039;, &#039;MyClass&#039;);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
*To include classes provided with Dolibarr, use the following syntax:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Example :&#039;&#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;PHP&amp;quot;&amp;gt;&lt;br /&gt;
require_once DOL_DOCUMENT_ROOT.&#039;/core/class/doli.class.php&#039;;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Add some fields into existing forms===&lt;br /&gt;
You may want to provide a module that adds more fields into forms (input and view) of some elements. &lt;br /&gt;
&lt;br /&gt;
A heavy solution (but not so bad) may be to replace all pages used to create element (this means disabling the &amp;quot;New element&amp;quot; menu entry and adding yours, and disabling the tab that shows the element to replace with a tab that is your own full page (copied/pasted from original) to do same than original page but modified to add your fields and stored added data into your own table). Go to menu [[#Define your entries in the menu (optional)]] and [[#The tab management (optional)]] if this solution suits you (this solution is more powerful since you can change everything you want into the page). &lt;br /&gt;
&lt;br /&gt;
We will describe here another solution, that works only to &amp;quot;add fields&amp;quot; at end of existing fields, using the element &amp;quot;category&amp;quot; as an example but you can convert this tutorial for invoice, proposal ...&lt;br /&gt;
&lt;br /&gt;
*First thing is to add a table, owned by your module, to store the value of new fields. This table will only have one column called &amp;lt;code&amp;gt;rowid&amp;lt;/code&amp;gt; (will contain the same value as the &amp;lt;code&amp;gt;rowid&amp;lt;/code&amp;gt; column in the element table) + one column for each new field you want to add. Then, create a class with CRUD (Create/Read/Update/Delete) methods for this new table. For those two tasks, go back to the previous chapter [[#Create your SQL tables and the PHP DAO class (optional)]].&lt;br /&gt;
*Next step is to add a hook into your module to add the new fields into the form. See chapter [[Hooks_system#Implement_the_Hook]] for generic documentation to use hooks.&lt;br /&gt;
&lt;br /&gt;
If you follow this tutorial, to be able to add fields into category forms, you must do:&lt;br /&gt;
{{ToComplete}}&lt;br /&gt;
&lt;br /&gt;
===Add/replace part of fields supported by hooks===&lt;br /&gt;
See chapter [[Hooks_system#Implement_the_Hook]] to know how to use Dolibarr existing hooks to add/replace code at Dolibarr hooks place.&lt;br /&gt;
&lt;br /&gt;
===Database access===&lt;br /&gt;
If you need to edit some data in the database inside your own table, use the PHP class generated before.&lt;br /&gt;
&lt;br /&gt;
If you to make access to tables with no dedicated PHP class available, this is always possible (for example if you want to get a list of records with a particular join or filter). In this case, this is a code samples to follow:&lt;br /&gt;
&lt;br /&gt;
To make an insert, update or delete:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;PHP&amp;quot;&amp;gt;&lt;br /&gt;
$db-&amp;gt;begin();   // Start transaction&lt;br /&gt;
$db-&amp;gt;query(&amp;quot;My SQL request insert, update or delete&amp;quot;);&lt;br /&gt;
$db-&amp;gt;commit();       // Validate transaction&lt;br /&gt;
or $db-&amp;gt;rollback()  // Cancel transaction&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
To read:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;PHP&amp;quot;&amp;gt;&lt;br /&gt;
$resql=$db-&amp;gt;query(&amp;quot;My select request&amp;quot;);&lt;br /&gt;
if ($resql)&lt;br /&gt;
{&lt;br /&gt;
	$num = $db-&amp;gt;num_rows($resql);&lt;br /&gt;
	$i = 0;&lt;br /&gt;
	if ($num)&lt;br /&gt;
	{&lt;br /&gt;
		while ($i &amp;lt; $num)&lt;br /&gt;
		{&lt;br /&gt;
			$obj = $db-&amp;gt;fetch_object($resql);&lt;br /&gt;
			if ($obj)&lt;br /&gt;
			{&lt;br /&gt;
				// You can use here results&lt;br /&gt;
				print $obj-&amp;gt;field1;&lt;br /&gt;
				print $obj-&amp;gt;field2;&lt;br /&gt;
			}&lt;br /&gt;
			$i++;&lt;br /&gt;
		}&lt;br /&gt;
	}&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Define style of your pages===&lt;br /&gt;
To have the look of your own pages to match the Dolibarr theme, it is necessary to use the Dolibarr CSS styles.&lt;br /&gt;
&lt;br /&gt;
You can use for example:&lt;br /&gt;
&lt;br /&gt;
*class=&amp;quot;&#039;&#039;&#039;liste_titre&#039;&#039;&#039;&amp;quot; on tags &#039;&#039;tr&#039;&#039; and &#039;&#039;td&#039;&#039; for the head row of a table.&lt;br /&gt;
*class=&amp;quot;&#039;&#039;&#039;pair&#039;&#039;&#039;&amp;quot; or class=&amp;quot;&#039;&#039;&#039;impair&#039;&#039;&#039;&amp;quot; on tags &#039;&#039;tr&#039;&#039; and &#039;&#039;td&#039;&#039; of other rows of a table.&lt;br /&gt;
*class=&amp;quot;&#039;&#039;&#039;flat&#039;&#039;&#039;&amp;quot; on all input fields (&#039;&#039;input, select, textarea&#039;&#039;...).&lt;br /&gt;
*class=&amp;quot;&#039;&#039;&#039;button&#039;&#039;&#039;&amp;quot; on HTML fields with type &#039;&#039;input type=&amp;quot;submit&amp;quot;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
===Use the Dolibarr date picker===&lt;br /&gt;
If you want to use the Dolibarr date selector (with its calendar popup) into your pages, use the following line:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;PHP&amp;quot;&amp;gt;&lt;br /&gt;
 $form=new Form($db);&lt;br /&gt;
 $form-&amp;gt;select_date(&#039;&#039;,&#039;mykey&#039;,0,0,0,&amp;quot;myform&amp;quot;);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
The string mykey will identify the date selector in the form. You must use different values if you use several date selectors in same page.&lt;br /&gt;
The string myform is the name of the FORM in which the selector is included (value found in the form name=&amp;quot;myform&amp;quot; in HTML page).&lt;br /&gt;
This means a date selector must be included necessarily into an html FORM.&lt;br /&gt;
&lt;br /&gt;
To get value after the POST of your form, the command is:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;PHP&amp;quot;&amp;gt;&lt;br /&gt;
$mydate = dol_mktime(12, 0 , 0, $GETPOST(&#039;mykeymonth&#039;, &#039;int&#039;), GETPOST(&#039;mykeyday&#039;, &#039;int&#039;), GETPOST(&#039;mykeyyear&#039;, &#039;int&#039;));&lt;br /&gt;
print strftime(&#039;%A %d %B %Y&#039;, $mydate);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Overwrite template file (tpl)===&lt;br /&gt;
If you want to overwrite tpl file on your module, you need to declare it on the module_parts :&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;PHP&amp;quot;&amp;gt;&lt;br /&gt;
&#039;tpl&#039; =&amp;gt; 1,&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Then you can put any tpl file on &#039;&#039;&#039;mymodule/core/tpl&#039;&#039;&#039;&lt;br /&gt;
as soon as the module is activate, the tpl will be overwrited&lt;br /&gt;
&lt;br /&gt;
==Add your own setup page (optional)==&lt;br /&gt;
&#039;&#039;&#039;When&#039;&#039;&#039;: If your module needs parameters, which are to be provided by the user, for proper setting up of the module.&lt;br /&gt;
&lt;br /&gt;
===Create your page to edit parameters===&lt;br /&gt;
If your module needs several parameters to be setup, you must create a page to edit options (these options will be saved in the [[Table llx_const|table &#039;&#039;&#039;llx_const&#039;&#039;&#039;]]).&lt;br /&gt;
Create a page named &#039;&#039;&#039;mymodule_setuppage.php&#039;&#039;&#039; that shows a form for possible options to update them into the above-mentioned table.&lt;br /&gt;
It is necessary to take an example from a page of the directory &#039;&#039;&#039;/admin&#039;&#039;&#039; that will show you the way to read/save your parameters.&lt;br /&gt;
Put this PHP page into the directory &#039;&#039;&#039;/admin&#039;&#039;&#039; of your module (e.g. mymodule/admin/mymodule_setuppage.php).&lt;br /&gt;
&lt;br /&gt;
===Modify the descriptor file of your module===&lt;br /&gt;
Then, within the descriptor file of your module, modify the variable &#039;&#039;&#039;config_page_url&#039;&#039;&#039; to set the name of this PHP page.&lt;br /&gt;
If the page is in the directory &#039;&#039;&#039;admin/&#039;&#039;&#039;, then the path is not required, e.g. like this:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;PHP&amp;quot;&amp;gt;&lt;br /&gt;
$this-&amp;gt;config_page_url = array(&amp;quot;mymodule_setuppage.php&amp;quot;);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
If the page is in the directory &#039;&#039;&#039;mymodule/admin/&#039;&#039;&#039;, then like this:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;PHP&amp;quot;&amp;gt;&lt;br /&gt;
$this-&amp;gt;config_page_url = array(&amp;quot;mymodule_setuppage.php@mymodule&amp;quot;);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Test your page===&lt;br /&gt;
Go into page &#039;&#039;&#039;Home-&amp;gt;Setup-&amp;gt;Modules&#039;&#039;&#039;, you should see a picture at the end of the line of your module to reach your setup page. Click on it, you should be able to view/edit parameters from your page.&lt;br /&gt;
&lt;br /&gt;
==Define your entries in the menu (optional)==&lt;br /&gt;
&#039;&#039;&#039;When&#039;&#039;&#039;: If you have created PHP pages, it is necessary that those pages can be reached from menu entries in Dolibarr menu.&lt;br /&gt;
&lt;br /&gt;
===Define your menu entries===&lt;br /&gt;
For this, you must define into the module descriptor, the array this-&amp;gt;menu that declares all menus added by your module.&lt;br /&gt;
This array contains entries that will appear once your module is activated.&lt;br /&gt;
The example module descriptor file &#039;&#039;&#039;modMyModule.class.php&#039;&#039;&#039; contains an example to declare a top menu and also its left menu entries.&lt;br /&gt;
&lt;br /&gt;
This is the example of code to declare your own menu entries in a module descriptor file:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;PHP&amp;quot;&amp;gt;&lt;br /&gt;
// Main menu entries&lt;br /&gt;
$this-&amp;gt;menu = array();			// List of menus to add&lt;br /&gt;
$r=0;&lt;br /&gt;
&lt;br /&gt;
// Add here entries to declare new menus&lt;br /&gt;
// Example to declare the Top Menu entry:&lt;br /&gt;
$this-&amp;gt;menu[$r]=array(	&#039;fk_menu&#039;=&amp;gt;0,			// Put 0 if this is a top menu&lt;br /&gt;
			&#039;type&#039;=&amp;gt;&#039;top&#039;,			// This is a Top menu entry&lt;br /&gt;
			&#039;titre&#039;=&amp;gt;&#039;MyModule top menu&#039;,&lt;br /&gt;
			&#039;mainmenu&#039;=&amp;gt;&#039;mymodule&#039;,&lt;br /&gt;
			&#039;leftmenu&#039;=&amp;gt;&#039;mymodule&#039;,&lt;br /&gt;
			&#039;url&#039;=&amp;gt;&#039;/mymodule/pagetop.php&#039;,&lt;br /&gt;
			&#039;langs&#039;=&amp;gt;&#039;mylangfile&#039;,	// Lang file to use (without .lang) by module. File must be in langs/code_CODE/ directory.&lt;br /&gt;
			&#039;position&#039;=&amp;gt;100,&lt;br /&gt;
			&#039;enabled&#039;=&amp;gt;&#039;1&#039;,			// Define condition to show or hide menu entry. Use &#039;$conf-&amp;gt;mymodule-&amp;gt;enabled&#039; if entry must be visible if module is enabled.&lt;br /&gt;
			&#039;perms&#039;=&amp;gt;&#039;1&#039;,			// Use &#039;perms&#039;=&amp;gt;&#039;$user-&amp;gt;rights-&amp;gt;mymodule-&amp;gt;level1-&amp;gt;level2&#039; if you want your menu with a permission rules&lt;br /&gt;
			&#039;target&#039;=&amp;gt;&#039;&#039;,&lt;br /&gt;
			&#039;user&#039;=&amp;gt;2);				// 0=Menu for internal users, 1=external users, 2=both&lt;br /&gt;
$r++;&lt;br /&gt;
&lt;br /&gt;
// Example to declare a Left Menu entry:&lt;br /&gt;
$this-&amp;gt;menu[$r]=array(	&#039;fk_menu&#039;=&amp;gt;&#039;fk_mainmenu=xxx&#039;,		    // Use &#039;fk_mainmenu=xxx&#039; or &#039;fk_mainmenu=xxx,fk_leftmenu=yyy&#039; where xxx is mainmenucode and yyy is a leftmenucode of parent menu&lt;br /&gt;
			&#039;type&#039;=&amp;gt;&#039;left&#039;,			        // This is a Left menu entry&lt;br /&gt;
			&#039;titre&#039;=&amp;gt;&#039;MyModule left menu 1&#039;,&lt;br /&gt;
			&#039;mainmenu&#039;=&amp;gt;&#039;xxx&#039;,&lt;br /&gt;
			&#039;leftmenu&#039;=&amp;gt;&#039;yyy&#039;,&lt;br /&gt;
			&#039;url&#039;=&amp;gt;&#039;/mymodule/pagelevel1.php&#039;,&lt;br /&gt;
			&#039;langs&#039;=&amp;gt;&#039;mylangfile&#039;,	// Lang file to use (without .lang) by module. File must be in langs/code_CODE/ directory.&lt;br /&gt;
			&#039;position&#039;=&amp;gt;100,&lt;br /&gt;
			&#039;enabled&#039;=&amp;gt;&#039;1&#039;,			// Define condition to show or hide menu entry. Use &#039;$conf-&amp;gt;mymodule-&amp;gt;enabled&#039; if entry must be visible if module is enabled.&lt;br /&gt;
			&#039;perms&#039;=&amp;gt;&#039;1&#039;,			// Use &#039;perms&#039;=&amp;gt;&#039;$user-&amp;gt;rights-&amp;gt;mymodule-&amp;gt;level1-&amp;gt;level2&#039; if you want your menu with a permission rules&lt;br /&gt;
			&#039;target&#039;=&amp;gt;&#039;&#039;,&lt;br /&gt;
			&#039;user&#039;=&amp;gt;2);				// 0=Menu for internal users,1=external users, 2=both&lt;br /&gt;
$r++;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
To show the menu or not depending on a permission, modify property &#039;&#039;&#039;perms&#039;&#039;&#039; in the array. See chapter on permissions later to see how to add permissions.&lt;br /&gt;
&lt;br /&gt;
===Test your menu entries===&lt;br /&gt;
Disable and re-enable your module under the Dolibarr module setup page, menus entries must appear (if property &#039;enabled&#039; is declaration array is ok).&lt;br /&gt;
&lt;br /&gt;
==Add your own permissions (optional)==&lt;br /&gt;
&#039;&#039;&#039;When&#039;&#039;&#039;: If you want to add new permissions.&lt;br /&gt;
&lt;br /&gt;
The way to define permissions that will manage your module is done inside the module descriptor created previously.&lt;br /&gt;
Modify line &lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;PHP&amp;quot;&amp;gt;&lt;br /&gt;
$this-&amp;gt;rights_class = &#039;mymodule&#039;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
with correct value for mymodule.&lt;br /&gt;
&lt;br /&gt;
Then you must fill the array $this-&amp;gt;rights with as many entries than different permissions you need to manage.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;PHP&amp;quot;&amp;gt;&lt;br /&gt;
$this-&amp;gt;rights[$r][0] = 10001;&lt;br /&gt;
$this-&amp;gt;rights[$r][1] = &#039;Label by default of permission&#039;;&lt;br /&gt;
$this-&amp;gt;rights[$r][2] = &#039;r&#039;;&lt;br /&gt;
$this-&amp;gt;rights[$r][3] = 1;&lt;br /&gt;
$this-&amp;gt;rights[$r][4] = &#039;action&#039;;&lt;br /&gt;
$this-&amp;gt;rights[$r][5] = &#039;subaction&#039;;&lt;br /&gt;
$r++;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Into $this-&amp;gt;rights[$r][0], put a permission id not already used (See into menu &#039;&#039;&#039;System info&#039;&#039;&#039; on a working installation of Dolibarr to know list of id already used by standard modules.&lt;br /&gt;
Into $this-&amp;gt;rights[$r][1], put a label by default for permission (This label will be used if no translation can be found into the file &#039;&#039;&#039;admin.lang&#039;&#039;&#039; Translation key should be &amp;quot;Permission10001=My permission Label&amp;quot;).&lt;br /&gt;
Into $this-&amp;gt;rights[$r][2], types of the permission. There are three type of permission, &#039;r&#039; for read, list or expert permission, &#039;w&#039; for write or update permission and &#039;d&#039; for delete permission.&lt;br /&gt;
Into $this-&amp;gt;rights[$r][3], put 1 if this permission must be granted automatically by default to any newly created user.&lt;br /&gt;
Into $this-&amp;gt;rights[$r][4] and $this-&amp;gt;rights[$r][5], put an action and subaction string without spaces. You will be able to test if a user has the permission in your PHP source code with the sequence:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;PHP&amp;quot;&amp;gt;&lt;br /&gt;
if ($user-&amp;gt;rights-&amp;gt;mymodule-&amp;gt;action-&amp;gt;subaction) ...&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Define your own box (optional)==&lt;br /&gt;
&#039;&#039;&#039;When&#039;&#039;&#039;: If your module needs to provide one or several new boxes to show on home page.&lt;br /&gt;
&lt;br /&gt;
===Define your box===&lt;br /&gt;
For this, modify the array $this-&amp;gt;boxes into the module descriptor file.&lt;br /&gt;
All you have to do is to add 2 lines for each box file you will create into directory &#039;&#039;&#039;htdocs/mymodule/core/boxes&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Example:&#039;&#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;PHP&amp;quot;&amp;gt;&lt;br /&gt;
$this-&amp;gt;boxes[0][&#039;file&#039;]=&#039;mybox0.php@mymodule&#039;&lt;br /&gt;
$this-&amp;gt;boxes[0][&#039;note&#039;]=&#039;My box 0&#039;&lt;br /&gt;
 ...&lt;br /&gt;
$this-&amp;gt;boxes[n][&#039;file&#039;]=&#039;myboxn.php@mymodule&#039;&lt;br /&gt;
$this-&amp;gt;boxes[n][&#039;note&#039;]=&#039;My box n&#039;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Then create files &#039;&#039;&#039;htdocs/mymodule/core/boxes/mybox0.php&#039;&#039;&#039;, &#039;&#039;&#039;htdocs/mymodule/core/boxes/mybox1.php&#039;&#039;&#039;... by copying an example from an existing box file (found into directory &#039;&#039;&#039;htdocs/core/boxes&#039;&#039;&#039;).&lt;br /&gt;
&lt;br /&gt;
===Test if your box is detected by Dolibarr===&lt;br /&gt;
Disable and enabled module.&lt;br /&gt;
&lt;br /&gt;
Go into menu &#039;&#039;&#039;Home - Setup - Boxes&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Your boxes must appear in the list of boxes you can activate. Activate the box and go on the home page to see if the box is showing correctly.&lt;br /&gt;
&lt;br /&gt;
==Define your own export (optional)==&lt;br /&gt;
&#039;&#039;&#039;When&#039;&#039;&#039;: If your module provides new predefined database export profiles (for its own tables or for already existing tables of another module).&lt;br /&gt;
&lt;br /&gt;
===Define export===&lt;br /&gt;
For this uncomment and modify arrays $this-&amp;gt;export_xxx in your module descriptor file.&lt;br /&gt;
&lt;br /&gt;
===Test your export===&lt;br /&gt;
Go into menu Tools -&amp;gt; Export. Your export will appear in the list of available predefined exports (if your module is enabled).&lt;br /&gt;
Choose it, you must see a list of all possible fields defined in the export arrays.&lt;br /&gt;
Choose on field and try to build an export file. If ok, try again with all fields.&lt;br /&gt;
&lt;br /&gt;
==Define your CSS styles (optional)==&lt;br /&gt;
&#039;&#039;&#039;When&#039;&#039;&#039;: If in your PHP pages, you use class styles that are not defined inside Dolibarr themes CSS (not recommended).&lt;br /&gt;
&lt;br /&gt;
===Create and declare your style sheet===&lt;br /&gt;
Create a style sheet CSS named &#039;&#039;&#039;mymodule.css&#039;&#039;&#039; or &#039;&#039;&#039;mymodule.css.php&#039;&#039;&#039; and put it into directory &#039;&#039;&#039;htdocs/mymodule&#039;&#039;&#039;. You can have several CSS files per module.&lt;br /&gt;
Remember it&#039;s better to use existing styles already available by default into Dolibarr (The CSS file used by Dolibarr is file &#039;&#039;&#039;themes/mytheme/&#039;&#039;themename&#039;&#039;.css.php&#039;&#039;&#039;. Create your own CSS files only if you need absolutely to add not already existing styles.&lt;br /&gt;
&lt;br /&gt;
Once your style sheets are ready, declare them into your module descriptor file by modifying the property &#039;&#039;&#039;$this-&amp;gt;modules_parts&#039;&#039;&#039;.&lt;br /&gt;
Value to put here must be an array of relative URLs of your CSS files.&lt;br /&gt;
For example&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;PHP&amp;quot;&amp;gt;&lt;br /&gt;
$this-&amp;gt;module_parts = array(&#039;css&#039; =&amp;gt; array(&#039;/mymodule/css/mymodule.css.php&#039;,&#039;/mymodule/css/myother.css&#039;));&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Test your style sheet===&lt;br /&gt;
Disable and enable your module.&lt;br /&gt;
&lt;br /&gt;
Go on the home page (index.php). Show the HTML source of the page.&lt;br /&gt;
&lt;br /&gt;
In the HTML header, you should see a line that declares your style sheet.&lt;br /&gt;
&lt;br /&gt;
==Add your JavaScript functions (optional)==&lt;br /&gt;
&#039;&#039;&#039;When&#039;&#039;&#039;: If in your PHP pages, you use javascript functions not available in Dolibarr (in file lib_head.js)&lt;br /&gt;
&lt;br /&gt;
If you need to use your own JavaScript functions inside your PHP pages, it is necessary to define your functions in your JavaScript file &#039;&#039;&#039;htdocs/mymodule/js/mymodule.js&#039;&#039;&#039;, included in the HTML &amp;lt;code&amp;gt;&amp;amp;lt;head/&amp;amp;gt;&amp;lt;/code&amp;gt; section.&lt;br /&gt;
Dolibarr is responsible for building that HTML section. In order to ask it to include your JavaScript file, you just need to provide it to the llxHeader() function called by your page.&lt;br /&gt;
&lt;br /&gt;
Example for page /htdocs/mymodule/mypage.php :&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;PHP&amp;quot;&amp;gt;&lt;br /&gt;
$morejs=array(&amp;quot;/mymodule/js/mymodule.js&amp;quot;);&lt;br /&gt;
llxHeader(&#039;&#039;,&#039;Titre&#039;,&#039;&#039;,&#039;&#039;,&#039;&#039;,&#039;&#039;,$morejs,&#039;&#039;,0,0); &lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Run your own code on any Dolibarr event (optional)==&lt;br /&gt;
&#039;&#039;&#039;When&#039;&#039;&#039;: If you want to execute your own code once a common Dolibarr event has occurred (example: I want to update a table in my module when an invoice is created into Dolibarr), you must create a &#039;&#039;&#039;trigger&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
See also [[Interfaces_Dolibarr_toward_foreign_systems]]&lt;br /&gt;
and [[Interfaces_from_foreign_systems_toward_Dolibarr]]&lt;br /&gt;
&lt;br /&gt;
==Insert your code inside Dolibarr hooks positions (optional)==&lt;br /&gt;
&#039;&#039;&#039;When&#039;&#039;&#039;: When you want to add code or replace Dolibarr code into another situation than a business event (See the previous chapter for adding code during a business event).&lt;br /&gt;
&lt;br /&gt;
See page [[Hooks_system]].&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Add your own numbering rules==&lt;br /&gt;
&#039;&#039;&#039;When&#039;&#039;&#039;: When you need a new rule for generated ref of elements that are not covered by existing rules.&lt;br /&gt;
&lt;br /&gt;
See page [[Create numbering module]].&lt;br /&gt;
&lt;br /&gt;
==Add your document template (optional)==&lt;br /&gt;
&#039;&#039;&#039;When&#039;&#039;&#039;: When you want to personalize your own generated PDF or ODT documents.&lt;br /&gt;
&lt;br /&gt;
Note: To add this feature, you don&#039;t need to create a module descriptor.&lt;br /&gt;
&lt;br /&gt;
Documentation to add your own template is available on page [[Create_a_PDF_document_template]] or [[Create_an_ODT_document_template]].&lt;br /&gt;
&lt;br /&gt;
==Add your skin (optional)==&lt;br /&gt;
&#039;&#039;&#039;When&#039;&#039;&#039;: When you want to personalized your colors/fonts/images.&lt;br /&gt;
&lt;br /&gt;
Note: To add this feature, you don&#039;t need to create a module descriptor.&lt;br /&gt;
&lt;br /&gt;
To add your own skin, read page [[Skins]].&lt;br /&gt;
&lt;br /&gt;
=Some coding rules and predefined functions=&lt;br /&gt;
The coding rules to be followed are defined in the [[Developer documentation]], under section &amp;quot;General Information - Language and standards development&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
A lot of predefined features for developers are also available and described into page [[Developer documentation]] under section &amp;quot;Technical components of Dolibarr&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
=Create a package to distribute and install your module=&lt;br /&gt;
This process must be used to generate a package to submit it on the http://www.dolistore.com marketplace.&lt;br /&gt;
But you can use it to have a package easy to distribute on your own network.&lt;br /&gt;
&lt;br /&gt;
*Go into the directory &#039;&#039;&#039;/build&#039;&#039;&#039; and copy the file &#039;&#039;&#039;makepack-dolibarrmodules.conf&#039;&#039;&#039; into &#039;&#039;&#039;makepack-mymodule.conf&#039;&#039;&#039;. Warning, this directory may not be provided in some packages of stable versions. If so, it can be retrieved from the snapshot available for download on the Dolibarr website in area &amp;quot;Development version&amp;quot; (taken in this case the whole build directory which is autonomous and independent directory).&lt;br /&gt;
&lt;br /&gt;
Edit this file to add a list of file names for all new files you created for your module (module descriptor, new sql tables files, php page, images, etc...)&lt;br /&gt;
&lt;br /&gt;
*Run the script via Perl (need the Perl version 5.0 or later):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
perl makepack-dolibarrmodule.pl&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
The script asks you the name of your module, its major and minor version. A file &#039;&#039;&#039;mymodule.zip &#039;&#039;&#039; will then be manufactured containing your module ready to be deployed.&lt;br /&gt;
&lt;br /&gt;
*The person who receives your module must then place the file in the root directory of a Dolibarr installation and perform the command:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
tar -xvf mymodule.zip&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
*If you want your module to be public, you can submit it (the zip file) on the Dolibarr marketplace website: {{LinkToPluginDownload}} (you must first create an account and be logged in to use the &amp;quot;Submit a module/product&amp;quot; link).&lt;br /&gt;
**If your module was built correctly, the file will be validated later.&lt;br /&gt;
**If quality is sufficient and license permits it, the code might be added inside main Dolibarr sources (except if you disagree for that).&lt;br /&gt;
&lt;br /&gt;
=Enabling/activation condition of external module on DoliStore=&lt;br /&gt;
&lt;br /&gt;
See [[Module_Dolistore_Validation_Rules|Validation Rules]]&lt;br /&gt;
[[Category:Development]]&lt;/div&gt;</summary>
		<author><name>TanguyP</name></author>
	</entry>
	<entry>
		<id>https://wiki.dolibarr.org/index.php?title=Module_development&amp;diff=63024</id>
		<title>Module development</title>
		<link rel="alternate" type="text/html" href="https://wiki.dolibarr.org/index.php?title=Module_development&amp;diff=63024"/>
		<updated>2025-04-16T19:33:42Z</updated>

		<summary type="html">&lt;p&gt;TanguyP: Fix some language mistakes, improve some style&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;!-- BEGIN origin interlang links --&amp;gt;&lt;br /&gt;
&amp;lt;!-- You can edit this section but do NOT remove these comments&lt;br /&gt;
     Links below will be automatically replicated on translated pages by PolyglotBot --&amp;gt;&lt;br /&gt;
[[fr:Développement_module]]&lt;br /&gt;
[[es:Desarrollo_de_un_módulo]]&lt;br /&gt;
[[de:Modul_Entwicklung]]&lt;br /&gt;
[[zh:模块开发]]&lt;br /&gt;
[[ja:モジュール_開発]]&lt;br /&gt;
&amp;lt;!-- END interlang links --&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Category:Core]]&lt;br /&gt;
{{TemplateDocDevEn}}&lt;br /&gt;
&lt;br /&gt;
To create a new module/addon for Dolibarr, there are several steps. This tutorial will describe each of them to let you build a module that extends Dolibarr features, such as:&lt;br /&gt;
&lt;br /&gt;
*Add new tables in database.&lt;br /&gt;
*Add your own menu entries.&lt;br /&gt;
*Add new screens to edit new tables.&lt;br /&gt;
*Add or remove tabs on object view (invoice, product, order, event, ...).&lt;br /&gt;
*Add predefined exports for the internal export tool.&lt;br /&gt;
*Add new information widget in the home page.&lt;br /&gt;
*Add new substitutions variables.&lt;br /&gt;
*Define new permissions.&lt;br /&gt;
*Execute code automatically triggered by a particular Dolibarr action.&lt;br /&gt;
*Insert your code inside Dolibarr hooks positions.&lt;br /&gt;
*Add your numbering rule to generate the reference of objects&lt;br /&gt;
*Add a new document template.&lt;br /&gt;
*Add a new skin.&lt;br /&gt;
&lt;br /&gt;
etc...&lt;br /&gt;
&lt;br /&gt;
The following chapters explain how to do all of this manually in an easy way.&lt;br /&gt;
&lt;br /&gt;
=Module creation with the module builder=&lt;br /&gt;
From Dolibarr v. 12.0 it is possible to create the main pages of your module with the Module Builder. To activate it:&lt;br /&gt;
&lt;br /&gt;
Go into the list of modules and enable the &amp;quot;Module Builder&amp;quot; module:&lt;br /&gt;
[[File:Module Builder.png|alt=Module Builder|thumb|none]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Then click on the &amp;quot;bug&amp;quot; image in the top right of screen.[[File:Module Builder icon.png|alt=Module Builder icon|left|thumb]]&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
=Template of an External Module=&lt;br /&gt;
A good model to start development of external module can be found here : [https://github.com/Dolibarr/dolibarr/tree/develop/htdocs/modulebuilder/template GitHub Dolibarr Module Template]&lt;br /&gt;
&lt;br /&gt;
=Create your module=&lt;br /&gt;
==Create a Module descriptor for your Module (required)==&lt;br /&gt;
&#039;&#039;&#039;When it is required&#039;&#039;&#039;: Required as soon as an addon is developed, whatever its goal is (only adding a skin does not require a module descriptor file).&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Since Dolibarr 9.0, you should use the ModuleBuilder module provided as a standard module to generate the module descriptor&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
===Create your module descriptor===&lt;br /&gt;
The first step is to create a file descriptor for the module. &lt;br /&gt;
&lt;br /&gt;
*Create directory &#039;&#039;&#039;/htdocs/custom/&#039;&#039;mymodule&#039;&#039;/core/modules&#039;&#039;&#039; (for an external module) or &#039;&#039;&#039;/htdocs/&#039;&#039;mymodule&#039;&#039;/core/modules&#039;&#039;&#039; if you plan to have this module an official core module of Dolibarr. Then copy the file &amp;lt;code&amp;gt;modMyModule.class.php&amp;lt;/code&amp;gt; from the directory &#039;&#039;&#039;htdocs/modulebuilder/template&#039;&#039;&#039; into this directory. Change the name of the file &amp;lt;code&amp;gt;modMyModule.class.php&amp;lt;/code&amp;gt; to the name corresponding to the purpose of your module. Name of the file must start with &amp;lt;code&amp;gt;mod&amp;lt;/code&amp;gt; and end with &amp;lt;code&amp;gt;.class.php&amp;lt;/code&amp;gt; (for example if you want to give the name &#039;NewName&#039; to this file, then the name should be &amp;lt;code&amp;gt;modNewName.class.php&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
Then, modify the contents of this file as follows:&lt;br /&gt;
&lt;br /&gt;
*Replace all occurrences of &amp;quot;modMyModule&amp;quot; with a value which corresponds to the purpose of your module. This value must always start with &#039;mod&#039; and contain only alpha characters (again, if the name given to the file was &#039;NewName&#039;, then replace all &amp;quot;modMyModule&amp;quot; with &amp;quot;modNewName&amp;quot;).&lt;br /&gt;
*Change the number in: $this-&amp;gt;numero = 100000 by a number that designates your module id. To avoid conflicts with other modules, you can consult the page that lists already reserved id numbers: [[List of modules id|List of modules id]].&lt;br /&gt;
*Modify any other variables defined in the constructor (see comment in the code skeleton for their meaning).&lt;br /&gt;
&lt;br /&gt;
Your file descriptor for your module is ready. See the next step to activate it.&lt;br /&gt;
&lt;br /&gt;
===Test your descriptor===&lt;br /&gt;
&lt;br /&gt;
Launch Dolibarr and go to page &#039;&#039;&#039;Setup-&amp;gt;module&#039;&#039;&#039;? &lt;br /&gt;
If you set the property version in the module description you should see a new line with your new module and the possibility to activate it or not. If you set the property version to &amp;quot;develop&amp;quot; or &amp;quot;experiental&amp;quot;, to see your module, you must first go into &#039;&#039;&#039;Setup-Others&#039;&#039;&#039; and set MAIN_FEATURES_LEVEL to 1 to see &amp;quot;experimental&amp;quot; modules or 2 to see &amp;quot;development&amp;quot; modules.&lt;br /&gt;
&lt;br /&gt;
==Tree of path for new module files (required)==&lt;br /&gt;
This is how your files must be organized when building a new module (the zip file must also match this rule).&lt;br /&gt;
Note: Only the second line is mandatory.&lt;br /&gt;
&lt;br /&gt;
{{TemplateModuleTreeSimple}}&lt;br /&gt;
&lt;br /&gt;
==Create your SQL tables and the PHP DAO class (optional)==&lt;br /&gt;
&#039;&#039;&#039;When&#039;&#039;&#039;: If your module needs to manage data of its own&lt;br /&gt;
&lt;br /&gt;
===Create your .sql file===&lt;br /&gt;
If your module is designed to manage data of its own, which are not available in the standard version of Dolibarr, it is necessary to define SQL tables to store the data.&lt;br /&gt;
&lt;br /&gt;
Scripts for creating tables and loading data by your own module are saved into a subdirectory sql (&#039;&#039;&#039;&amp;quot;mymodule/sql&amp;quot;&#039;&#039;&#039;) of your module. (With ModuleBuilder, the directory and all sql files will be created automatically when you will create a new Object from tab Object).&lt;br /&gt;
&lt;br /&gt;
Then check into your descriptor file, into function &#039;&#039;&#039;init&#039;&#039;&#039; that the line&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;PHP&amp;quot;&amp;gt;$this-&amp;gt;_load_tables(&#039;/mymodule/sql/&#039;);&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
is not commented.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Rules to follow:&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
*Add the files about creating tables commands on the principle of an &#039;&#039;&#039;llx_mytable.sql&#039;&#039;&#039; file per table, with an optional &#039;&#039;&#039;llx_mytable.key.sql&#039;&#039;&#039; file (see existing files in &#039;&#039;&#039;install/mysql/tables&#039;&#039;&#039; for examples).&lt;br /&gt;
*The recommended type and name for SQL fields are defined into page [[Language_and_development_rules#Table_and_fields_structures]].&lt;br /&gt;
*To manage data, you must create a file called &#039;&#039;&#039;data.sql&#039;&#039;&#039; inside directory &#039;&#039;&#039;/mymodule/sql/&#039;&#039;&#039; that contains SQL command to add/edit/delete data.&lt;br /&gt;
*Don&#039;t use the double quote for strings (eg &#039;chaine&#039; not &amp;quot;chaine&amp;quot;) because the double quote have a specific meaning in PostGreSQL&lt;br /&gt;
&lt;br /&gt;
Example of content of a file data.sql&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;sql&amp;quot;&amp;gt;&lt;br /&gt;
 delete from llx_const where name=&#039;MYMODULE_IT_WORKS&#039; and entity=&#039;__ENTITY__&#039;;&lt;br /&gt;
 insert into llx_const (name, value, type, note, visible, entity) values (&#039;MYMODULE_IT_WORKS&#039;,&#039;1&#039;,&#039;chaine&#039;,&#039;A constant vor my module&#039;,1,&#039;__ENTITY__&#039;);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Files must be operational for the database mysql. Note: The files of other databases are not maintained. They will be read and converted on the fly by the driver of the other database.&lt;br /&gt;
&lt;br /&gt;
===Test your .sql files===&lt;br /&gt;
&lt;br /&gt;
Once the files ready, you can return to the page to enable Dolibarr modules and disable the module, drop those tables in the database (if they already exist) and reactivate the module. The tables should be recreated by the activation of the module. If this is not the case, check your scripts by passing them by hand, or check the Dolibarr logs.&lt;br /&gt;
&lt;br /&gt;
===Generate the PHP DAO class===&lt;br /&gt;
The DAO PHP files should have been generated by ModuleBuilder after creating an object.&lt;br /&gt;
&lt;br /&gt;
You can however create them manually by copying existing object however using ModuleBuilder is highly recommended. You should find examples into &#039;&#039;&#039;htdocs/modulebuilder/templates/class/myobject.class.php&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
In this class, there are already operational CRUD (Create/Read/Update/Delete) methods to perform an insert, a fetch (select), an update, a delete of a table row. Edit the file to use the correct module name, tables and place this file in the class subdirectory of the module. The Module Builder allows you to do this with just a few mouse clicks.&lt;br /&gt;
&lt;br /&gt;
==The tab management (optional)==&lt;br /&gt;
&lt;br /&gt;
===Add or remove your own tabs on object sheets===&lt;br /&gt;
&#039;&#039;&#039;When&#039;&#039;&#039;: To add a tab on an object (invoices, orders, proposals, member ...)&lt;br /&gt;
&lt;br /&gt;
To do this go into the file descriptor of module previously created and edit the $this-&amp;gt;tabs array:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;PHP&amp;quot;&amp;gt;&lt;br /&gt;
	// Array to add new pages in new tabs or remove existing one&lt;br /&gt;
	$this-&amp;gt;tabs = array(&#039;objecttype:+tabname1:Title1:mylangfile@mymodule:$user-&amp;gt;rights-&amp;gt;mymodule-&amp;gt;read:/mymodule/mypagetab1.php?id=__ID__&#039;    // To add a new tab identified by code tabname1&lt;br /&gt;
                            &#039;objecttype:+tabname2:Title2:mylangfile@mymodule:$user-&amp;gt;rights-&amp;gt;mymodule-&amp;gt;read:/mymodule/mypagetab2.php?id=__ID__&#039;,   // To add a new tab identified by code tabname2&lt;br /&gt;
                            &#039;objecttype:-tabname&#039;);                                                     // To remove an existing tab identified by code tabname&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The table should contain a list of strings, each string representing a new tab. &lt;br /&gt;
The format of the string consisting of 5 parts separated by &amp;quot;:&amp;quot;&lt;br /&gt;
&lt;br /&gt;
*Part 1: The element type (object type) where the tab should appear is a value from the following:&lt;br /&gt;
{{TemplateModuleTabs}}&lt;br /&gt;
&lt;br /&gt;
*Part 2: A code to identify tab to add (start with +tabname1) or to remove (start with -tabname1)&lt;br /&gt;
*Part 3: The title of the tab(Title1). This can be a hardcoded read or better a code translation in module lang file .&lt;br /&gt;
*Part 4: The name of the file &amp;quot;*.lang&amp;quot; (mylangfile@mymodule) which contains correspondence between the code translation and language to display. If this name is followed with @mymodule, Dolibarr will search translation file &amp;quot;*.lang&amp;quot; within the module in htdocs/custom/mymodule/langs/code_CODE/mylangfile.lang, otherwise Dolibarr will look for file in htdocs/langs/code_CODE/mylangfile.lang&lt;br /&gt;
*Part 5: A condition to test if tab must be visible($user-&amp;gt;rights-&amp;gt;mymodule-&amp;gt;read) &#039;&#039;&#039;or&#039;&#039;&#039; put 1 to be always visible.&lt;br /&gt;
*Part 6: The URL of the page to display when you click on the tab (/mymodule/mypagetab1.php). The __ID__ string will be replaced automatically by the Id of the element concerned.&lt;br /&gt;
&lt;br /&gt;
To feed the contents of the tab with data from the database, see the next chapter.&lt;br /&gt;
&lt;br /&gt;
In order to get the names  &#039;tabname&#039; of existing tabs, you have to check the names used in the function &#039;product_prepare_head&#039; of the file  &#039;core/lib/module.lib.php&#039; corresponding to section &#039;$head[$h][2]&#039;.&lt;br /&gt;
&lt;br /&gt;
===Show tabs navigation into your own pages===&lt;br /&gt;
&#039;&#039;&#039;When&#039;&#039;&#039;: To show all standard tabs of an object (product, tiers, etc.) on your page.&lt;br /&gt;
&lt;br /&gt;
You must follow these steps :&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;1. Include files you need into your file&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
For each object type, there are two files to include with line&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;PHP&amp;quot;&amp;gt;require_once($url_fichier) ;&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This is example of files to include (DOL_DOCUMENT_ROOT is often dolibarr/htdocs/) :&lt;br /&gt;
&lt;br /&gt;
*Object thirdparty (thirdparty) :&lt;br /&gt;
**DOL_DOCUMENT_ROOT/societe/class/societe.class.php&lt;br /&gt;
**DOL_DOCUMENT_ROOT/core/lib/company.lib.php&lt;br /&gt;
*Object product (product) :&lt;br /&gt;
**DOL_DOCUMENT_ROOT/product/class/product.class.php&lt;br /&gt;
**DOL_DOCUMENT_ROOT/core/lib/product.lib.php&lt;br /&gt;
*Object invoice (invoice) :&lt;br /&gt;
**DOL_DOCUMENT_ROOT/compta/facture/class/facture.class.php&lt;br /&gt;
**DOL_DOCUMENT_ROOT/core/lib/invoice.lib.php&lt;br /&gt;
&lt;br /&gt;
...&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;2. Create and load the object to show into your tab&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Create an instance of an object of the correct class and load object from the database by using the fetch method of an object in providing to this method the id you get from URL (ie : /mytab.php?id=1).&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Example :&#039;&#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;PHP&amp;quot;&amp;gt;&lt;br /&gt;
$id=GETPOST(&#039;id&#039;,&#039;int&#039;);&lt;br /&gt;
$ref=GETPOST(&#039;ref&#039;,&#039;alpha&#039;);&lt;br /&gt;
$product = new Product($db) ;&lt;br /&gt;
$result = $product-&amp;gt;fetch($id,$ref) ; // Test $result to check the database read is ok&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;3. Get a list of all tabs to show for your object type&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Use function XXX_prepare_head($obj), where XXX is name of object. This will return an array with all definition of tab entries to show. The parameter to put into this method is the instance of an object you want tabs.&lt;br /&gt;
&lt;br /&gt;
The resulting array has the following structure&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;PHP&amp;quot;&amp;gt;&lt;br /&gt;
$head        // Array of tabs&lt;br /&gt;
$head[$h]    // Element to describe one tab.&lt;br /&gt;
$head[$h][0] // Url of page to show when you click on tab&lt;br /&gt;
$head[$h][1] // Title of tab&lt;br /&gt;
$head[$h][2] // Code name to identify the tab&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Example :&#039;&#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;PHP&amp;quot;&amp;gt;&lt;br /&gt;
$head = product_prepare_head($product, $user) ; // parameter $user is present for some function anly&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;4. show tabs into your page&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Use function dol_fiche_head() to show all tabs defined into array $head returned by XX_prepare_head().&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;PHP&amp;quot;&amp;gt;&lt;br /&gt;
dol_fiche_head($links, $active=&#039;0&#039;, $title=&#039;&#039;, $notab=0, $picto=&#039;&#039;)&lt;br /&gt;
//$links  // Tableau des onglets, appelé $head plus haut.&lt;br /&gt;
//$active // Onglet actif (mettre le nom de l&#039;onglet défini dans votre fichier de module, ou un nom contenu dans $head[$h][2]). Cet onglet sera mis en surbrillance&lt;br /&gt;
//$title  // Title to show (shown into a special tab that you can&#039;t click)&lt;br /&gt;
//$notab&lt;br /&gt;
//$picto  // Name of image to show into title. Possible values are:&lt;br /&gt;
//            product&lt;br /&gt;
//            service&lt;br /&gt;
//            company&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This function will show required tabs and open an html element &#039;&#039;&amp;lt; div class=&amp;quot;&amp;quot; &amp;gt;&#039;&#039; that correspond to the area under the tabs. To close area of a tab, just use &#039;&#039;&amp;lt; /div &amp;gt;&#039;&#039; into your PHP page.&lt;br /&gt;
&lt;br /&gt;
==Create or modify PHP screens (optional)==&lt;br /&gt;
&#039;&#039;&#039;When&#039;&#039;&#039;: If the purpose of your module is to add features that require new or modified screens.&lt;br /&gt;
&lt;br /&gt;
===Create a new PHP screen===&lt;br /&gt;
You must then create your PHP pages that will show/edit data from tables using the skeleton templates provided as an example in the directory &#039;&#039;&#039;modulebuilder/myobject_page.php&#039;&#039;&#039; (For the development of a script from the command line, see [[Script development]]).&lt;br /&gt;
&lt;br /&gt;
To create a new user screen, create a subdirectory of &#039;&#039;&#039;htdocs&#039;&#039;&#039; (if not already done) for your module (in &#039;&#039;&#039;htdocs/mymodule&#039;&#039;&#039; for example) to store the pages you will create.&lt;br /&gt;
&lt;br /&gt;
Copy, into that directory, the file &#039;&#039;&#039;myobject_page.php&#039;&#039;&#039; that will serve as a starting point for your page file.&lt;br /&gt;
Edit the file to have a correct relative path to the main.inc.php file. &lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;PHP&amp;quot;&amp;gt;&lt;br /&gt;
// Load Dolibarr environment&lt;br /&gt;
$res=0;&lt;br /&gt;
// Try main.inc.php into web root known defined into CONTEXT_DOCUMENT_ROOT (not always defined)&lt;br /&gt;
if (! $res &amp;amp;&amp;amp; ! empty($_SERVER[&amp;quot;CONTEXT_DOCUMENT_ROOT&amp;quot;])) $res=@include($_SERVER[&amp;quot;CONTEXT_DOCUMENT_ROOT&amp;quot;].&amp;quot;/main.inc.php&amp;quot;);&lt;br /&gt;
// Try main.inc.php into web root detected using web root calculated from SCRIPT_FILENAME&lt;br /&gt;
$tmp=empty($_SERVER[&#039;SCRIPT_FILENAME&#039;])?&#039;&#039;:$_SERVER[&#039;SCRIPT_FILENAME&#039;];$tmp2=realpath(__FILE__); $i=strlen($tmp)-1; $j=strlen($tmp2)-1;&lt;br /&gt;
while($i &amp;gt; 0 &amp;amp;&amp;amp; $j &amp;gt; 0 &amp;amp;&amp;amp; isset($tmp[$i]) &amp;amp;&amp;amp; isset($tmp2[$j]) &amp;amp;&amp;amp; $tmp[$i]==$tmp2[$j]) { $i--; $j--; }&lt;br /&gt;
if (! $res &amp;amp;&amp;amp; $i &amp;gt; 0 &amp;amp;&amp;amp; file_exists(substr($tmp, 0, ($i+1)).&amp;quot;/main.inc.php&amp;quot;)) $res=@include(substr($tmp, 0, ($i+1)).&amp;quot;/main.inc.php&amp;quot;);&lt;br /&gt;
if (! $res &amp;amp;&amp;amp; $i &amp;gt; 0 &amp;amp;&amp;amp; file_exists(dirname(substr($tmp, 0, ($i+1))).&amp;quot;/main.inc.php&amp;quot;)) $res=@include(dirname(substr($tmp, 0, ($i+1))).&amp;quot;/main.inc.php&amp;quot;);&lt;br /&gt;
// Try main.inc.php using relative path&lt;br /&gt;
if (! $res &amp;amp;&amp;amp; file_exists(&amp;quot;../main.inc.php&amp;quot;)) $res=@include(&amp;quot;../main.inc.php&amp;quot;);&lt;br /&gt;
if (! $res &amp;amp;&amp;amp; file_exists(&amp;quot;../../main.inc.php&amp;quot;)) $res=@include(&amp;quot;../../main.inc.php&amp;quot;);&lt;br /&gt;
if (! $res &amp;amp;&amp;amp; file_exists(&amp;quot;../../../main.inc.php&amp;quot;)) $res=@include(&amp;quot;../../../main.inc.php&amp;quot;);&lt;br /&gt;
if (! $res) die(&amp;quot;Include of main fails&amp;quot;);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
As you can see, there are several tries to load the main.inc.php (or master.inc.php). The goal is to succeed in the most cases as possible. The minimum is 2 lines: one to try to load the master/main.inc.php into the dolibarr root directory and another one to try to load the file to support the case when the module is deployed into the &amp;quot;custom&amp;quot; directory. But you can have more to deal more situation. The provided example should be able to load the file main/master.inc.php in nearly all situation/setups.&lt;br /&gt;
&lt;br /&gt;
Note that you may add more &amp;quot;../&amp;quot; depending on the depth of the file relative to your module directory tree.&lt;br /&gt;
&lt;br /&gt;
It&#039;s in the main.inc.php file that is loaded technical environment variables and permissions. The following variables are objects positioned in this file:&lt;br /&gt;
&lt;br /&gt;
*$user    Object that contains the characteristics of the user + his permissions.&lt;br /&gt;
*$conf    Object that contains Dolibarr configuration.&lt;br /&gt;
*$db      Object that contains an opened connection handler to the database.&lt;br /&gt;
*$langs   Object that contains the user&#039;s language.&lt;br /&gt;
&lt;br /&gt;
Then enter your code to display the page.&lt;br /&gt;
&lt;br /&gt;
*To include a class or library dedicated to the module is done using a Dolibarr function (and not using directly include_once):&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Example :&#039;&#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;PHP&amp;quot;&amp;gt;&lt;br /&gt;
dol_include_once(&#039;/mymodule/class/myclass.class.php&#039;, &#039;MyClass&#039;);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
*To include classes provided with Dolibarr, use the following syntax:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Example :&#039;&#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;PHP&amp;quot;&amp;gt;&lt;br /&gt;
require_once DOL_DOCUMENT_ROOT.&#039;/core/class/doli.class.php&#039;;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Add some fields into existing forms===&lt;br /&gt;
You may want to provide a module that adds more fields into forms (input and view) of some elements. &lt;br /&gt;
&lt;br /&gt;
A heavy solution (but not so bad) may be to replace all pages used to create element (this means to disable the &amp;quot;New element&amp;quot; menu entry and adding yours, and disable tab that shows element to replace with a tab that is your own full page (copied/pasted from original) to do same than original page but modified to add your fields and stored added data into your own table). Go to menu [[#Define your entries in the menu (optional)]] and [[#The tab management (optional)]] if this solution suits you (this solution is more powerful since you can change everything you want into the page). &lt;br /&gt;
&lt;br /&gt;
We will describe here another solution, that works only to &amp;quot;add fields&amp;quot; at end of existing fields, using the element &amp;quot;category&amp;quot; as an example but you can convert this tutorial for invoice, proposal ...&lt;br /&gt;
&lt;br /&gt;
*First thing is to add a table, owned by your module, to store the value of new fields. This table will have only one column called &amp;quot;rowid&amp;quot; (will contain the same value than field rowid of element table) + one column for each new field you want to add. Then create a class with CRUD (Create/Read/Update/Delete) methods for this new table. For this two tasks, go back to previous chapter [[#Create your SQL tables and the PHP DAO class]].&lt;br /&gt;
*Next step is to add a hook into your module to add the new fields into the form. See chapter [[Hooks_system#Implement_the_Hook]] for generic documentation to use hooks.&lt;br /&gt;
&lt;br /&gt;
If you follow this tutorial, to be able to add fields into category forms, you must do:&lt;br /&gt;
{{ToComplete}}&lt;br /&gt;
&lt;br /&gt;
===Add/replace part of fields supported by hooks===&lt;br /&gt;
See chapter [[Hooks_system#Implement_the_Hook]] to know how to use Dolibarr existing hooks to add/replace code at Dolibarr hooks place.&lt;br /&gt;
&lt;br /&gt;
===Database access===&lt;br /&gt;
If you need to edit some data in the database inside your own table, use the PHP class generated before.&lt;br /&gt;
&lt;br /&gt;
If you to make access to tables with no dedicated PHP class available, this is always possible (for example if you want to get a list of records with a particular join or filter). In this case, this is a code samples to follow:&lt;br /&gt;
&lt;br /&gt;
To make an insert, update or delete:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;PHP&amp;quot;&amp;gt;&lt;br /&gt;
$db-&amp;gt;begin();   // Start transaction&lt;br /&gt;
$db-&amp;gt;query(&amp;quot;My SQL request insert, update or delete&amp;quot;);&lt;br /&gt;
$db-&amp;gt;commit();       // Validate transaction&lt;br /&gt;
or $db-&amp;gt;rollback()  // Cancel transaction&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
To read:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;PHP&amp;quot;&amp;gt;&lt;br /&gt;
$resql=$db-&amp;gt;query(&amp;quot;My select request&amp;quot;);&lt;br /&gt;
if ($resql)&lt;br /&gt;
{&lt;br /&gt;
	$num = $db-&amp;gt;num_rows($resql);&lt;br /&gt;
	$i = 0;&lt;br /&gt;
	if ($num)&lt;br /&gt;
	{&lt;br /&gt;
		while ($i &amp;lt; $num)&lt;br /&gt;
		{&lt;br /&gt;
			$obj = $db-&amp;gt;fetch_object($resql);&lt;br /&gt;
			if ($obj)&lt;br /&gt;
			{&lt;br /&gt;
				// You can use here results&lt;br /&gt;
				print $obj-&amp;gt;field1;&lt;br /&gt;
				print $obj-&amp;gt;field2;&lt;br /&gt;
			}&lt;br /&gt;
			$i++;&lt;br /&gt;
		}&lt;br /&gt;
	}&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Define style of your pages===&lt;br /&gt;
To have the look of your own pages to match the Dolibarr theme, it is necessary to use the Dolibarr CSS styles.&lt;br /&gt;
&lt;br /&gt;
You can use for example:&lt;br /&gt;
&lt;br /&gt;
*class=&amp;quot;&#039;&#039;&#039;liste_titre&#039;&#039;&#039;&amp;quot; on tags &#039;&#039;tr&#039;&#039; and &#039;&#039;td&#039;&#039; for the head row of a table.&lt;br /&gt;
*class=&amp;quot;&#039;&#039;&#039;pair&#039;&#039;&#039;&amp;quot; or class=&amp;quot;&#039;&#039;&#039;impair&#039;&#039;&#039;&amp;quot; on tags &#039;&#039;tr&#039;&#039; and &#039;&#039;td&#039;&#039; of other rows of a table.&lt;br /&gt;
*class=&amp;quot;&#039;&#039;&#039;flat&#039;&#039;&#039;&amp;quot; on all input fields (&#039;&#039;input, select, textarea&#039;&#039;...).&lt;br /&gt;
*class=&amp;quot;&#039;&#039;&#039;button&#039;&#039;&#039;&amp;quot; on HTML fields with type &#039;&#039;input type=&amp;quot;submit&amp;quot;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
===Use the Dolibarr date picker===&lt;br /&gt;
If you want to use the Dolibarr date selector (with its calendar popup) into your pages, use the following line:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;PHP&amp;quot;&amp;gt;&lt;br /&gt;
 $form=new Form($db);&lt;br /&gt;
 $form-&amp;gt;select_date(&#039;&#039;,&#039;mykey&#039;,0,0,0,&amp;quot;myform&amp;quot;);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
The string mykey will identify the date selector in the form. You must use different values if you use several date selectors in same page.&lt;br /&gt;
The string myform is the name of the FORM in which the selector is included (value found in the form name=&amp;quot;myform&amp;quot; in HTML page).&lt;br /&gt;
This means a date selector must be included necessarily into an html FORM.&lt;br /&gt;
&lt;br /&gt;
To get value after the POST of your form, the command is:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;PHP&amp;quot;&amp;gt;&lt;br /&gt;
$mydate = dol_mktime(12, 0 , 0, $GETPOST(&#039;mykeymonth&#039;, &#039;int&#039;), GETPOST(&#039;mykeyday&#039;, &#039;int&#039;), GETPOST(&#039;mykeyyear&#039;, &#039;int&#039;));&lt;br /&gt;
print strftime(&#039;%A %d %B %Y&#039;, $mydate);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Overwrite template file (tpl)===&lt;br /&gt;
If you want to overwrite tpl file on your module, you need to declare it on the module_parts :&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;PHP&amp;quot;&amp;gt;&lt;br /&gt;
&#039;tpl&#039; =&amp;gt; 1,&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Then you can put any tpl file on &#039;&#039;&#039;mymodule/core/tpl&#039;&#039;&#039;&lt;br /&gt;
as soon as the module is activate, the tpl will be overwrited&lt;br /&gt;
&lt;br /&gt;
==Add your own setup page (optional)==&lt;br /&gt;
&#039;&#039;&#039;When&#039;&#039;&#039;: If your module needs parameters, which are to be provided by the user, for proper setting up of the module.&lt;br /&gt;
&lt;br /&gt;
===Create your page to edit parameters===&lt;br /&gt;
If your module needs several parameters to be setup, you must create a page to edit options (these options will be saved in the [[Table llx_const|table &#039;&#039;&#039;llx_const&#039;&#039;&#039;]]).&lt;br /&gt;
Create a page named &#039;&#039;&#039;mymodule_setuppage.php&#039;&#039;&#039; that shows a form for possible options to update them into the above-mentioned table.&lt;br /&gt;
It is necessary to take an example from a page of the directory &#039;&#039;&#039;/admin&#039;&#039;&#039; that will show you the way to read/save your parameters.&lt;br /&gt;
Put this PHP page into the directory &#039;&#039;&#039;/admin&#039;&#039;&#039; of your module (e.g. mymodule/admin/mymodule_setuppage.php).&lt;br /&gt;
&lt;br /&gt;
===Modify the descriptor file of your module===&lt;br /&gt;
Then, within the descriptor file of your module, modify the variable &#039;&#039;&#039;config_page_url&#039;&#039;&#039; to set the name of this PHP page.&lt;br /&gt;
If the page is in the directory &#039;&#039;&#039;admin/&#039;&#039;&#039;, then the path is not required, e.g. like this:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;PHP&amp;quot;&amp;gt;&lt;br /&gt;
$this-&amp;gt;config_page_url = array(&amp;quot;mymodule_setuppage.php&amp;quot;);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
If the page is in the directory &#039;&#039;&#039;mymodule/admin/&#039;&#039;&#039;, then like this:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;PHP&amp;quot;&amp;gt;&lt;br /&gt;
$this-&amp;gt;config_page_url = array(&amp;quot;mymodule_setuppage.php@mymodule&amp;quot;);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Test your page===&lt;br /&gt;
Go into page &#039;&#039;&#039;Home-&amp;gt;Setup-&amp;gt;Modules&#039;&#039;&#039;, you should see a picture at the end of the line of your module to reach your setup page. Click on it, you should be able to view/edit parameters from your page.&lt;br /&gt;
&lt;br /&gt;
==Define your entries in menu (optional)==&lt;br /&gt;
&#039;&#039;&#039;When&#039;&#039;&#039;: If you have created PHP pages, it is necessary that those pages can be reached from menu entries in Dolibarr menu.&lt;br /&gt;
&lt;br /&gt;
===Define your menu entries===&lt;br /&gt;
For this, you must define into the module descriptor, the array this-&amp;gt;menu that declares all menus added by your module.&lt;br /&gt;
This array contains entries that will appear once your module is activated.&lt;br /&gt;
The example module descriptor file &#039;&#039;&#039;modMyModule.class.php&#039;&#039;&#039; contains an example to declare a top menu and also its left menu entries.&lt;br /&gt;
&lt;br /&gt;
This is the example of code to declare your own menu entries in a module descriptor file:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;PHP&amp;quot;&amp;gt;&lt;br /&gt;
// Main menu entries&lt;br /&gt;
$this-&amp;gt;menu = array();			// List of menus to add&lt;br /&gt;
$r=0;&lt;br /&gt;
&lt;br /&gt;
// Add here entries to declare new menus&lt;br /&gt;
// Example to declare the Top Menu entry:&lt;br /&gt;
$this-&amp;gt;menu[$r]=array(	&#039;fk_menu&#039;=&amp;gt;0,			// Put 0 if this is a top menu&lt;br /&gt;
			&#039;type&#039;=&amp;gt;&#039;top&#039;,			// This is a Top menu entry&lt;br /&gt;
			&#039;titre&#039;=&amp;gt;&#039;MyModule top menu&#039;,&lt;br /&gt;
			&#039;mainmenu&#039;=&amp;gt;&#039;mymodule&#039;,&lt;br /&gt;
			&#039;leftmenu&#039;=&amp;gt;&#039;mymodule&#039;,&lt;br /&gt;
			&#039;url&#039;=&amp;gt;&#039;/mymodule/pagetop.php&#039;,&lt;br /&gt;
			&#039;langs&#039;=&amp;gt;&#039;mylangfile&#039;,	// Lang file to use (without .lang) by module. File must be in langs/code_CODE/ directory.&lt;br /&gt;
			&#039;position&#039;=&amp;gt;100,&lt;br /&gt;
			&#039;enabled&#039;=&amp;gt;&#039;1&#039;,			// Define condition to show or hide menu entry. Use &#039;$conf-&amp;gt;mymodule-&amp;gt;enabled&#039; if entry must be visible if module is enabled.&lt;br /&gt;
			&#039;perms&#039;=&amp;gt;&#039;1&#039;,			// Use &#039;perms&#039;=&amp;gt;&#039;$user-&amp;gt;rights-&amp;gt;mymodule-&amp;gt;level1-&amp;gt;level2&#039; if you want your menu with a permission rules&lt;br /&gt;
			&#039;target&#039;=&amp;gt;&#039;&#039;,&lt;br /&gt;
			&#039;user&#039;=&amp;gt;2);				// 0=Menu for internal users, 1=external users, 2=both&lt;br /&gt;
$r++;&lt;br /&gt;
&lt;br /&gt;
// Example to declare a Left Menu entry:&lt;br /&gt;
$this-&amp;gt;menu[$r]=array(	&#039;fk_menu&#039;=&amp;gt;&#039;fk_mainmenu=xxx&#039;,		    // Use &#039;fk_mainmenu=xxx&#039; or &#039;fk_mainmenu=xxx,fk_leftmenu=yyy&#039; where xxx is mainmenucode and yyy is a leftmenucode of parent menu&lt;br /&gt;
			&#039;type&#039;=&amp;gt;&#039;left&#039;,			        // This is a Left menu entry&lt;br /&gt;
			&#039;titre&#039;=&amp;gt;&#039;MyModule left menu 1&#039;,&lt;br /&gt;
			&#039;mainmenu&#039;=&amp;gt;&#039;xxx&#039;,&lt;br /&gt;
			&#039;leftmenu&#039;=&amp;gt;&#039;yyy&#039;,&lt;br /&gt;
			&#039;url&#039;=&amp;gt;&#039;/mymodule/pagelevel1.php&#039;,&lt;br /&gt;
			&#039;langs&#039;=&amp;gt;&#039;mylangfile&#039;,	// Lang file to use (without .lang) by module. File must be in langs/code_CODE/ directory.&lt;br /&gt;
			&#039;position&#039;=&amp;gt;100,&lt;br /&gt;
			&#039;enabled&#039;=&amp;gt;&#039;1&#039;,			// Define condition to show or hide menu entry. Use &#039;$conf-&amp;gt;mymodule-&amp;gt;enabled&#039; if entry must be visible if module is enabled.&lt;br /&gt;
			&#039;perms&#039;=&amp;gt;&#039;1&#039;,			// Use &#039;perms&#039;=&amp;gt;&#039;$user-&amp;gt;rights-&amp;gt;mymodule-&amp;gt;level1-&amp;gt;level2&#039; if you want your menu with a permission rules&lt;br /&gt;
			&#039;target&#039;=&amp;gt;&#039;&#039;,&lt;br /&gt;
			&#039;user&#039;=&amp;gt;2);				// 0=Menu for internal users,1=external users, 2=both&lt;br /&gt;
$r++;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
To show the menu or not depending on a permission, modify property &#039;&#039;&#039;perms&#039;&#039;&#039; in the array. See chapter on permissions later to see how to add permissions.&lt;br /&gt;
&lt;br /&gt;
===Test your menu entries===&lt;br /&gt;
Disable and re-enable your module under the Dolibarr module setup page, menus entries must appear (if property &#039;enabled&#039; is declaration array is ok).&lt;br /&gt;
&lt;br /&gt;
==Add your own permissions (optional)==&lt;br /&gt;
&#039;&#039;&#039;When&#039;&#039;&#039;: If you want to add new permissions.&lt;br /&gt;
&lt;br /&gt;
The way to define permissions that will manage your module is done inside the module descriptor created previously.&lt;br /&gt;
Modify line &lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;PHP&amp;quot;&amp;gt;&lt;br /&gt;
$this-&amp;gt;rights_class = &#039;mymodule&#039;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
with correct value for mymodule.&lt;br /&gt;
&lt;br /&gt;
Then you must fill the array $this-&amp;gt;rights with as many entries than different permissions you need to manage.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;PHP&amp;quot;&amp;gt;&lt;br /&gt;
$this-&amp;gt;rights[$r][0] = 10001;&lt;br /&gt;
$this-&amp;gt;rights[$r][1] = &#039;Label by default of permission&#039;;&lt;br /&gt;
$this-&amp;gt;rights[$r][2] = &#039;r&#039;;&lt;br /&gt;
$this-&amp;gt;rights[$r][3] = 1;&lt;br /&gt;
$this-&amp;gt;rights[$r][4] = &#039;action&#039;;&lt;br /&gt;
$this-&amp;gt;rights[$r][5] = &#039;subaction&#039;;&lt;br /&gt;
$r++;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Into $this-&amp;gt;rights[$r][0], put a permission id not already used (See into menu &#039;&#039;&#039;System info&#039;&#039;&#039; on a working installation of Dolibarr to know list of id already used by standard modules.&lt;br /&gt;
Into $this-&amp;gt;rights[$r][1], put a label by default for permission (This label will be used if no translation can be found into the file &#039;&#039;&#039;admin.lang&#039;&#039;&#039; Translation key should be &amp;quot;Permission10001=My permission Label&amp;quot;).&lt;br /&gt;
Into $this-&amp;gt;rights[$r][2], types of the permission. There are three type of permission, &#039;r&#039; for read, list or expert permission, &#039;w&#039; for write or update permission and &#039;d&#039; for delete permission.&lt;br /&gt;
Into $this-&amp;gt;rights[$r][3], put 1 if this permission must be granted automatically by default to any newly created user.&lt;br /&gt;
Into $this-&amp;gt;rights[$r][4] and $this-&amp;gt;rights[$r][5], put an action and subaction string without spaces. You will be able to test if a user has the permission in your PHP source code with the sequence:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;PHP&amp;quot;&amp;gt;&lt;br /&gt;
if ($user-&amp;gt;rights-&amp;gt;mymodule-&amp;gt;action-&amp;gt;subaction) ...&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Define your own box (optional)==&lt;br /&gt;
&#039;&#039;&#039;When&#039;&#039;&#039;: If your module needs to provide one or several new boxes to show on home page.&lt;br /&gt;
&lt;br /&gt;
===Define your box===&lt;br /&gt;
For this, modify the array $this-&amp;gt;boxes into the module descriptor file.&lt;br /&gt;
All you have to do is to add 2 lines for each box file you will create into directory &#039;&#039;&#039;htdocs/mymodule/core/boxes&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Example:&#039;&#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;PHP&amp;quot;&amp;gt;&lt;br /&gt;
$this-&amp;gt;boxes[0][&#039;file&#039;]=&#039;mybox0.php@mymodule&#039;&lt;br /&gt;
$this-&amp;gt;boxes[0][&#039;note&#039;]=&#039;My box 0&#039;&lt;br /&gt;
 ...&lt;br /&gt;
$this-&amp;gt;boxes[n][&#039;file&#039;]=&#039;myboxn.php@mymodule&#039;&lt;br /&gt;
$this-&amp;gt;boxes[n][&#039;note&#039;]=&#039;My box n&#039;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Then create files &#039;&#039;&#039;htdocs/mymodule/core/boxes/mybox0.php&#039;&#039;&#039;, &#039;&#039;&#039;htdocs/mymodule/core/boxes/mybox1.php&#039;&#039;&#039;... by copying an example from an existing box file (found into directory &#039;&#039;&#039;htdocs/core/boxes&#039;&#039;&#039;).&lt;br /&gt;
&lt;br /&gt;
===Test if your box is detected by Dolibarr===&lt;br /&gt;
Disable and enabled module.&lt;br /&gt;
&lt;br /&gt;
Go into menu &#039;&#039;&#039;Home - Setup - Boxes&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Your boxes must appear in the list of boxes you can activate. Activate the box and go on the home page to see if the box is showing correctly.&lt;br /&gt;
&lt;br /&gt;
==Define your own export (optional)==&lt;br /&gt;
&#039;&#039;&#039;When&#039;&#039;&#039;: If your module provides new predefined database export profiles (for its own tables or for already existing tables of another module).&lt;br /&gt;
&lt;br /&gt;
===Define export===&lt;br /&gt;
For this uncomment and modify arrays $this-&amp;gt;export_xxx in your module descriptor file.&lt;br /&gt;
&lt;br /&gt;
===Test your export===&lt;br /&gt;
Go into menu Tools -&amp;gt; Export. Your export will appear in the list of available predefined exports (if your module is enabled).&lt;br /&gt;
Choose it, you must see a list of all possible fields defined in the export arrays.&lt;br /&gt;
Choose on field and try to build an export file. If ok, try again with all fields.&lt;br /&gt;
&lt;br /&gt;
==Define your CSS styles (optional)==&lt;br /&gt;
&#039;&#039;&#039;When&#039;&#039;&#039;: If in your PHP pages, you use class styles that are not defined inside Dolibarr themes CSS (not recommanded).&lt;br /&gt;
&lt;br /&gt;
===Create and declare your style sheet===&lt;br /&gt;
Create a style sheet CSS named &#039;&#039;&#039;mymodule.css&#039;&#039;&#039; or &#039;&#039;&#039;mymodule.css.php&#039;&#039;&#039; and put it into directory &#039;&#039;&#039;htdocs/mymodule&#039;&#039;&#039;. You can have several CSS files per module.&lt;br /&gt;
Remember it&#039;s better to use existing styles already available by default into Dolibarr (The CSS file used by Dolibarr is file &#039;&#039;&#039;themes/mytheme/&#039;&#039;themename&#039;&#039;.css.php&#039;&#039;&#039;. Create your own CSS files only if you need absolutely to add not already existing styles.&lt;br /&gt;
&lt;br /&gt;
Once your style sheets are ready, declare them into your module descriptor file by modifying the property &#039;&#039;&#039;$this-&amp;gt;modules_parts&#039;&#039;&#039;.&lt;br /&gt;
Value to put here must be an array of relative URLs to your CSS files.&lt;br /&gt;
For example&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;PHP&amp;quot;&amp;gt;&lt;br /&gt;
$this-&amp;gt;module_parts = array(&#039;css&#039; =&amp;gt; array(&#039;/mymodule/css/mymodule.css.php&#039;,&#039;/mymodule/css/myother.css&#039;));&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Test your style sheet===&lt;br /&gt;
Disable and enable your module.&lt;br /&gt;
&lt;br /&gt;
Go on the home page (index.php). Show the HTML source of the page.&lt;br /&gt;
&lt;br /&gt;
You should see into the HTML header, a line that declares your style sheet.&lt;br /&gt;
&lt;br /&gt;
==Add your Javascript functions (optional)==&lt;br /&gt;
&#039;&#039;&#039;When&#039;&#039;&#039;: If in your PHP pages, you use javascript functions not available in Dolibarr (in file lib_head.js)&lt;br /&gt;
&lt;br /&gt;
If you need to use your own javascript functions inside your PHP pages, it is necessary to have your functions, defined into your javascript file &#039;&#039;&#039;htdocs/mymodule/js/mymodule.js&#039;&#039;&#039;, included into the HTML HEAD section.&lt;br /&gt;
To ask Dolibarr that forge this header to include your own javascript file, you must just provide it to the llxHeader() function called by your page.&lt;br /&gt;
&lt;br /&gt;
Example for page /htdocs/mymodule/mypage.php :&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;PHP&amp;quot;&amp;gt;&lt;br /&gt;
$morejs=array(&amp;quot;/mymodule/js/mymodule.js&amp;quot;);&lt;br /&gt;
llxHeader(&#039;&#039;,&#039;Titre&#039;,&#039;&#039;,&#039;&#039;,&#039;&#039;,&#039;&#039;,$morejs,&#039;&#039;,0,0); &lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Run your own code on any Dolibarr event (optional)==&lt;br /&gt;
&#039;&#039;&#039;When&#039;&#039;&#039;: If you want to execute your own code once a common Dolibarr event has occurred (example: I want to update a table in my module when an invoice is created into Dolibarr), you must create a &#039;&#039;&#039;triggers&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
See also [[Interfaces_Dolibarr_toward_foreign_systems]]&lt;br /&gt;
and [[Interfaces_from_foreign_systems_toward_Dolibarr]]&lt;br /&gt;
&lt;br /&gt;
==Insert your code inside Dolibarr hooks positions (optional)==&lt;br /&gt;
&#039;&#039;&#039;When&#039;&#039;&#039;: When you want to add code or replace Dolibarr code into another situation than a business event (See the previous chapter for adding code during a business event).&lt;br /&gt;
&lt;br /&gt;
See page [[Hooks_system]].&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Add your own numbering rules==&lt;br /&gt;
&#039;&#039;&#039;When&#039;&#039;&#039;: When you need a new rule for generated ref of elements that are not covered by existing rules.&lt;br /&gt;
&lt;br /&gt;
See page [[Create numbering module]].&lt;br /&gt;
&lt;br /&gt;
==Add your document template (optional)==&lt;br /&gt;
&#039;&#039;&#039;When&#039;&#039;&#039;: When you want to personalized your own generated PDF or ODT documents.&lt;br /&gt;
&lt;br /&gt;
Note: To add this feature you don&#039;t need to create a module descriptor.&lt;br /&gt;
&lt;br /&gt;
Documentation to add your own template is available on page [[Create_a_PDF_document_template]] or [[Create_an_ODT_document_template]].&lt;br /&gt;
&lt;br /&gt;
==Add your skin (optional)==&lt;br /&gt;
&#039;&#039;&#039;When&#039;&#039;&#039;: When you want to personalized your colors/fonts/images.&lt;br /&gt;
&lt;br /&gt;
Note: To add this feature you don&#039;t need to create a module descriptor.&lt;br /&gt;
&lt;br /&gt;
To add your own skin, read page [[Skins]].&lt;br /&gt;
&lt;br /&gt;
=Some coding rules and predefined functions=&lt;br /&gt;
The coding rules to be followed are defined in the [[Developer documentation]], under section &amp;quot;General Information - Language and standards development&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
A lot of predefined features for developers are also available and described into page [[Developer documentation]] under section &amp;quot;Technical components of Dolibarr&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
=Create a package to distribute and install your module=&lt;br /&gt;
This process must be used to generate a package to submit it on the http://www.dolistore.com marketplace.&lt;br /&gt;
But you can use it to have a package easy to distribute on your own network.&lt;br /&gt;
&lt;br /&gt;
*Go into the directory &#039;&#039;&#039;/build&#039;&#039;&#039; and copy the file &#039;&#039;&#039;makepack-dolibarrmodules.conf&#039;&#039;&#039; into &#039;&#039;&#039;makepack-mymodule.conf&#039;&#039;&#039;. Warning, this directory may not be provided in some packages of stable versions. If so, it can be retrieved from the snapshot available for download on the Dolibarr website in area &amp;quot;Development version&amp;quot; (taken in this case the whole build directory which is autonomous and independent directory).&lt;br /&gt;
&lt;br /&gt;
Edit this file to add a list of file names for all new files you created for your module (module descriptor, new sql tables files, php page, images, etc...)&lt;br /&gt;
&lt;br /&gt;
*Run the script via Perl (need the Perl version 5.0 or later):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
perl makepack-dolibarrmodule.pl&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
The script asks you the name of your module, its major and minor version. A file &#039;&#039;&#039;mymodule.zip &#039;&#039;&#039; will then be manufactured containing your module ready to be deployed.&lt;br /&gt;
&lt;br /&gt;
*The person who receives your module must then place the file in the root directory of a Dolibarr installation and perform the command:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
tar -xvf mymodule.zip&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
*If you want your module to be public, you can submit it (the zip file) on Dolibarr marketplace website: {{LinkToPluginDownload}} (you must create an account first and be logged to use the link &amp;quot;Submit a module/product&amp;quot;).&lt;br /&gt;
**If your module was built correctly, the file will be validated later.&lt;br /&gt;
**If quality is enough and license permits it, the code might be added inside main Dolibarr sources (except if you disagree for that).&lt;br /&gt;
&lt;br /&gt;
=Enabling/activation condition of external module on DoliStore=&lt;br /&gt;
&lt;br /&gt;
See [[Module_Dolistore_Validation_Rules|Validation Rules]]&lt;br /&gt;
[[Category:Development]]&lt;/div&gt;</summary>
		<author><name>TanguyP</name></author>
	</entry>
	<entry>
		<id>https://wiki.dolibarr.org/index.php?title=Triggers_system&amp;diff=58831</id>
		<title>Triggers system</title>
		<link rel="alternate" type="text/html" href="https://wiki.dolibarr.org/index.php?title=Triggers_system&amp;diff=58831"/>
		<updated>2023-11-23T10:45:55Z</updated>

		<summary type="html">&lt;p&gt;TanguyP: Update class name as per Dolibarr 18.0.2&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;!-- BEGIN origin interlang links --&amp;gt;&lt;br /&gt;
&amp;lt;!-- You can edit this section but do NOT remove these comments&lt;br /&gt;
     Links below will be automatically replicated on translated pages by PolyglotBot --&amp;gt;&lt;br /&gt;
[[fr:Système de Triggers]]&lt;br /&gt;
[[es:Triggers-acciones]]&lt;br /&gt;
[[zh:触发系统]]&lt;br /&gt;
&amp;lt;!-- END interlang links --&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{{TemplateDocDevEn}}&lt;br /&gt;
&lt;br /&gt;
=Execute your own code on a Dolibarr business event=&lt;br /&gt;
To execute personalized code after a Dolibarr event (create/modify/remove a third party/invoice/product or other), Dolibarr offers a mechanism of business triggers. This mechanism allows you to personalize a work-flow to have Dolibarr business events being synchronized into another application for example.&lt;br /&gt;
You can also use triggers to modify the behavior of Dolibarr itself: for example, to create a contract automatically when an invoice is validated, a fill a log file when a record is deleted, ...&lt;br /&gt;
&lt;br /&gt;
Note that triggers is a feature for developers that is limited to business CRUD events (Create | Read | Update | Delete). There is another feature for developers to inject custom code in the application called the [[Hooks system]].&lt;br /&gt;
&lt;br /&gt;
So, to add your own code that will be triggered by a Dolibarr trigger, this is the process:&lt;br /&gt;
&lt;br /&gt;
1) Copy the template trigger file &#039;&#039;&#039;htdocs/modulebuilder/template/core/triggers/interface_99_modMyModule_MyModuleTriggers.class.php&#039;&#039;&#039; under the new name:&lt;br /&gt;
&lt;br /&gt;
*&#039;&#039;&#039;interface_99_all_&#039;&#039;Xxx&#039;&#039;.class.php&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
or&lt;br /&gt;
&lt;br /&gt;
*&#039;&#039;&#039;interface_99_mod&#039;&#039;MyModule_Xxx&#039;&#039;.class.php&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
where &#039;&#039;Xxx&#039;&#039; is a string of your choice starting with uppercase character, &#039;&#039;99&#039;&#039; is the priority number for the execution of your trigger (1 being the top priority) and &#039;&#039;MyModule&#039;&#039; is the name of a module if you want that trigger is activated only if module MyModule is activated. If you want the trigger to be always active, use &#039;&#039;all&#039;&#039; instead of  modMyModule.&lt;br /&gt;
This new file must be saved inside same directory.&lt;br /&gt;
&lt;br /&gt;
Note: Value you can use for mod MyModule are values found in directory&lt;br /&gt;
&#039;&#039;htdocs/includes/modules&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;WARNING&#039;&#039;&#039;: All those parameters are necessary for the trigger to be detected and executed! Eg: if you forget the priority number, your trigger won&#039;t be detected!&lt;br /&gt;
&lt;br /&gt;
For example, you can name your new trigger file: &lt;br /&gt;
&#039;&#039;htdocs/includes/triggers/interface_99_modFacture_Myworkflow.class.php&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
By creating such a file with a name like the example, your new trigger file will be executed each time a Dolibarr business event occurs but only if the module Facture is enabled.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Note&#039;&#039;&#039;: If you develop a full module, you can also place the trigger file in your own module&#039;s subdirectly. Eg: if your module resides in htdocs/mymodule/, then you can place your triggers inside htdocs/mymodule/core/triggers/. But for this, you must declare the trigger into your module descriptor file (eg: &#039;&#039;&#039;/mymodule/core/modules/modMyModule.class.php&#039;&#039;&#039;). For this, add into this file triggers-&amp;gt;1 into module_parts array:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;PHP&amp;quot;&amp;gt;&lt;br /&gt;
// Defined all module parts (triggers, login, substitutions, menus, etc...) (0=disable,1=enable)&lt;br /&gt;
$this-&amp;gt;module_parts = array(&#039;triggers&#039; =&amp;gt; 1);&lt;br /&gt;
//$this-&amp;gt;module_parts = array(&#039;triggers&#039; =&amp;gt; 1,&lt;br /&gt;
//              &#039;login&#039; =&amp;gt; 0,&lt;br /&gt;
//              &#039;substitutions&#039; =&amp;gt; 0,&lt;br /&gt;
//              &#039;menus&#039; =&amp;gt; 0);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Then disable and reenable your module. This will add a record into [[Table llx_const]] to tell Dolibarr that a trigger file must be searched in the module directory &#039;&#039;&#039;htdocs/mymodule/core/triggers/&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
2) Edit the file &#039;&#039;interface_99_modMyModule_Myworkflow.class.php&#039;&#039; to rename class &#039;&#039;InterfaceMyModuleTriggers&#039;&#039; by &#039;&#039;InterfaceMyworkflow&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Then go on page Home -&amp;gt; Admin Tools -&amp;gt; About Dolibarr -&amp;gt;Triggers.&lt;br /&gt;
Your new trigger file must appears in the list without any error message. This means preceding actions have been done successfully.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
3) Return now to edition of file to add your own code inside function  &#039;&#039;run_trigger&#039;&#039;.&lt;br /&gt;
This function is called at each Dolibarr business event. Put your code according to events on which you want to run. Each event is identified by a code (see following chapter to get full list of codes). So you can react or no after an event by doing just a test on variable &#039;&#039;&#039;$action&#039;&#039;&#039;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;PHP&amp;quot;&amp;gt;&lt;br /&gt;
  function run_trigger($action,$object,$user,$langs,$conf)&lt;br /&gt;
  {&lt;br /&gt;
        // Put here code to execute after an action&lt;br /&gt;
        // The type of Dolibarr business event is stored into $action&lt;br /&gt;
        // Data of action are stored into object $object&lt;br /&gt;
        // Setup, user and language are saved into $conf, $user and $lang&lt;br /&gt;
        if ($action == &#039;COMPANY_CREATE&#039;)&lt;br /&gt;
        {&lt;br /&gt;
            dol_syslog(&amp;quot;Trigger for action &#039;$action&#039; launched. id=&amp;quot;.$object-&amp;gt;id);&lt;br /&gt;
        }&lt;br /&gt;
        elseif ($action == &#039;COMPANY_MODIFY&#039;)&lt;br /&gt;
        {        &lt;br /&gt;
            dol_syslog(&amp;quot;Trigger for action &#039;$action&#039; launched. id=&amp;quot;.$object-&amp;gt;id);&lt;br /&gt;
        }&lt;br /&gt;
        elseif ($action == &#039;COMPANY_DELETE&#039;)&lt;br /&gt;
        ...&lt;br /&gt;
  }&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
You can do what you want into this coding part, if you check that function run_trigger returns a return code according to following rule:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;0 if KO, 0 if nothing is done, &amp;gt;0 if OK&lt;br /&gt;
&lt;br /&gt;
You can also use, inside this function, the following preinitialized variables:&lt;br /&gt;
&lt;br /&gt;
*&#039;&#039;&#039;$object&#039;&#039;&#039; is the object on which action is done (see next chapter)&lt;br /&gt;
*&#039;&#039;&#039;$user&#039;&#039;&#039; is the object containing all information of Dolibarr user that realizes the business event.&lt;br /&gt;
*&#039;&#039;&#039;$langs&#039;&#039;&#039; is the object that contains the user language and translations strings&lt;br /&gt;
*&#039;&#039;&#039;$conf&#039;&#039;&#039; is the object that contains all the Dolibarr configuration.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
4) Once your trigger file has been developed, last action is to test by using Dolibarr to execute the business event that should trigger your code. Warning, call of function &#039;&#039;&#039;run_trigger&#039;&#039;&#039; is encapsulated into a transaction. If your code return a KO code, the calling function may rollback the transaction (this depends on calling function).&lt;br /&gt;
Add log information inside your function &#039;&#039;&#039;run_trigger&#039;&#039;&#039; to know if your code is correctly triggered and runs correctly. For this, you can use the function&lt;br /&gt;
dol_syslog(&amp;quot;my log message&amp;quot;, LOG_DEBUG);&lt;br /&gt;
&lt;br /&gt;
=List of known triggers actions=&lt;br /&gt;
&lt;br /&gt;
Here is a quick view of the events that cause triggers to be searched and executed. An event is characterized by the value of the code &#039;&#039;$action&#039;&#039;, with the type of the object received in &#039;&#039;$object&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Note: The [[Module Agenda En|Module Agenda]] and [[Module Notification]] use the table [[Table llx c action trigger]] as a list of known triggers. This avoid scanning the disk for this information, but this table is just a very limited list.&lt;br /&gt;
&lt;br /&gt;
In general, the trigger action code begins with the name of the module followed by the character _.&lt;br /&gt;
&lt;br /&gt;
{{TemplateListOfTriggers}}&lt;br /&gt;
This list may be not complete.&lt;br /&gt;
&lt;br /&gt;
=Manage and create a new trigger&#039;s action=&lt;br /&gt;
&lt;br /&gt;
To manage events other than those above, you must modify the Dolibarr code to add the following sequence in the business methods of the classes of the objects handled:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;PHP&amp;quot;&amp;gt;&lt;br /&gt;
// Call trigger&lt;br /&gt;
$result = $this-&amp;gt;call_trigger(&#039;CODE_TRIGGER&#039;, $user);&lt;br /&gt;
if ($result &amp;lt;0) $error++;&lt;br /&gt;
// End call triggers&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
To add context information (for example to dissociate 2 different cases called with the same Trigger code), it is possible to place this information in the properties -&amp;gt;context of the object on which the trigger is called. Example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;PHP&amp;quot;&amp;gt;&lt;br /&gt;
// Call trigger&lt;br /&gt;
$this-&amp;gt;context = array(&#039;paramX&#039;=&amp;gt;$valueX, &#039;anyparamofyourchoice&#039;=&amp;gt;$anyvalue);&lt;br /&gt;
$result = $this-&amp;gt;call_trigger(&#039;CODE_TRIGGER&#039;,$user);&lt;br /&gt;
if ($result &amp;lt; 0) $error++;          &lt;br /&gt;
// End call triggers&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
It will then be possible to add in the run_trigger method of any trigger file, an if which allows you to manage this code. The run_trigger method would then be of the form:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;PHP&amp;quot;&amp;gt;&lt;br /&gt;
function run_trigger($action,$object,$user,$lang,$conf)&lt;br /&gt;
{&lt;br /&gt;
      // Put here code to execute after an action&lt;br /&gt;
      // The type of Dolibarr business event is stored into $action&lt;br /&gt;
      // Data of action are stored into object $object&lt;br /&gt;
      // Setup, user and language are saved into $conf, $user and $lang&lt;br /&gt;
      if ($action == &#039;XXXXX_YYYYY&#039;)&lt;br /&gt;
      {&lt;br /&gt;
          dol_syslog(&amp;quot;Trigger for action &#039;$action&#039; launched. id=&amp;quot;.$object-&amp;gt;id);&lt;br /&gt;
      }&lt;br /&gt;
      elseif ($action == &#039;COMPANY_CREATE&#039;)&lt;br /&gt;
      {&lt;br /&gt;
          dol_syslog(&amp;quot;Trigger for action &#039;$action&#039; launched. id=&amp;quot;.$object-&amp;gt;id);&lt;br /&gt;
      }&lt;br /&gt;
      elseif ($action == &#039;COMPANY_MODIFY&#039;)&lt;br /&gt;
      {        &lt;br /&gt;
          dol_syslog(&amp;quot;Trigger for action &#039;$action&#039; launched. id=&amp;quot;.$object-&amp;gt;id);&lt;br /&gt;
      }&lt;br /&gt;
      elseif ($action == &#039;COMPANY_DELETE&#039;)&lt;br /&gt;
      ...&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Please note the following before adding additional calls to triggers:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
The rule is to have only 1 trigger call per business CRUD event, even when several actions are done in the same transaction.&lt;br /&gt;
As an example: When a new ticket is created with an already assigned user, only the TICKET_CREATE trigger is called, not additionally the TICKET_ASSIGNED trigger. It is the job of the trigger to intercept also this case to scan if an assignment is done directly during creation and to execute its custom code.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=Conclusion=&lt;br /&gt;
You can in few minutes, add an interface from Dolibarr towards another system (or why not towards Dolibarr itself), with no risk since you don&#039;t touch anything to Dolibarr files. You only &amp;quot;added&amp;quot; a new trigger file inside the trigger directory.&lt;br /&gt;
If this new interface can serve a lot of other users, you can package it into a tgz file (see page [[Module_development#Create_a_package_to_distribute_and_install_your_module]]) and submit it on the download area in section external contributions on official Dolibarr web site.&lt;br /&gt;
&lt;br /&gt;
=See also=&lt;br /&gt;
&lt;br /&gt;
*[[Hooks system]]&lt;br /&gt;
*[[Interfaces Dolibarr toward foreign systems]]&lt;br /&gt;
*[[Interfaces from foreign systems toward Dolibarr]]&lt;/div&gt;</summary>
		<author><name>TanguyP</name></author>
	</entry>
	<entry>
		<id>https://wiki.dolibarr.org/index.php?title=Module_development&amp;diff=58640</id>
		<title>Module development</title>
		<link rel="alternate" type="text/html" href="https://wiki.dolibarr.org/index.php?title=Module_development&amp;diff=58640"/>
		<updated>2023-11-05T08:52:32Z</updated>

		<summary type="html">&lt;p&gt;TanguyP: /* Create your SQL tables and the PHP DAO class (optional) */ Language&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;!-- BEGIN origin interlang links --&amp;gt;&lt;br /&gt;
&amp;lt;!-- You can edit this section but do NOT remove these comments&lt;br /&gt;
     Links below will be automatically replicated on translated pages by PolyglotBot --&amp;gt;&lt;br /&gt;
[[fr:Développement_module]]&lt;br /&gt;
[[es:Desarrollo_de_un_módulo]]&lt;br /&gt;
[[de:Modul_Entwicklung]]&lt;br /&gt;
[[zh:模块开发]]&lt;br /&gt;
[[ja:モジュール_開発]]&lt;br /&gt;
&amp;lt;!-- END interlang links --&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Category:Core]]&lt;br /&gt;
{{TemplateDocDevEn}}&lt;br /&gt;
&lt;br /&gt;
To create a new module/addon for Dolibarr, there is several steps. This tutorial will describe you each of them to build a module to extend Dolibarr features, like one or several of the following :&lt;br /&gt;
&lt;br /&gt;
*Add new tables in database.&lt;br /&gt;
*Add your own menu entries.&lt;br /&gt;
*Add new screens to edit new tables.&lt;br /&gt;
*Add or remove tabs on object view (invoice, product, order, event, ...).&lt;br /&gt;
*Add predefined exports for the internal export tool.&lt;br /&gt;
*Add new information widget in the home page.&lt;br /&gt;
*Add new substitutions variables.&lt;br /&gt;
*Define new permissions.&lt;br /&gt;
*Execute code automatically triggered by a particular Dolibarr action.&lt;br /&gt;
*Insert your code inside Dolibarr hooks positions.&lt;br /&gt;
*Add your numbering rule to generate the reference of objects&lt;br /&gt;
*Add a new document template.&lt;br /&gt;
*Add a new skin.&lt;br /&gt;
&lt;br /&gt;
etc...&lt;br /&gt;
&lt;br /&gt;
Following chapters presents how to do all of this manually with an easy way.&lt;br /&gt;
&lt;br /&gt;
=Module creation with the module builder=&lt;br /&gt;
From Dolibarr 9.0 it is possible to create the main pages of your module with the Module Builder. To activate it:&lt;br /&gt;
&lt;br /&gt;
*Go into the list of module and enable the module &amp;quot;Module Builder&amp;quot;,&lt;br /&gt;
&lt;br /&gt;
[[File:Mod_builder_2.png|400px]]&lt;br /&gt;
&lt;br /&gt;
*Then click on the &amp;quot;bug&amp;quot; image in the top right of screen.&lt;br /&gt;
&lt;br /&gt;
[[File:Mod_builder_3.png|400px]]&lt;br /&gt;
&lt;br /&gt;
=Example of Template External Module=&lt;br /&gt;
A good model to start development of external module can be found here : [https://github.com/Dolibarr/dolibarr/tree/develop/htdocs/modulebuilder/template GitHub Dolibarr Module Modèle]&lt;br /&gt;
&lt;br /&gt;
=Create your module=&lt;br /&gt;
==Create a Module descriptor for your Module (required)==&lt;br /&gt;
&#039;&#039;&#039;When it is required&#039;&#039;&#039;: Required as soon as an addon is developed, whatever its goal is (except for adding a skin).&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Since Dolibarr 9.0, you should use the ModuleBuilder module provided as a standard module to generate the module descriptor&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
===Create your module descriptor===&lt;br /&gt;
The first step is to create a file descriptor for the module. &lt;br /&gt;
&lt;br /&gt;
*Create directory &#039;&#039;&#039;/htdocs/custom/&#039;&#039;mymodule&#039;&#039;/core/modules&#039;&#039;&#039; (for an external module) or &#039;&#039;&#039;/htdocs/&#039;&#039;mymodule&#039;&#039;/core/modules&#039;&#039;&#039; if you plan to have this module an official core module of Dolibarr. Then copy the file modMyModule.class.php from the directory &#039;&#039;&#039;htdocs/modulebuilder/template&#039;&#039;&#039; into this directory. Change the name of the file modMyModule.class.php to the name corresponding to the purpose of your module. Name of the file must start with initial &#039;mod&#039; and end with .class.php (for example if you want to give the name &#039;NewName&#039; to this file, then the name should be &#039;modNewName.class.php&#039;).&lt;br /&gt;
&lt;br /&gt;
Next modify the contents of this file as follows:&lt;br /&gt;
&lt;br /&gt;
*Replace all &amp;quot;modMyModule&amp;quot; with a value which corresponds to the purpose of your module. This value must always start with &#039;mod&#039; and contain only alpha characters (again, if the name given to the file was &#039;NewName&#039;, then replace all &amp;quot;modMyModule&amp;quot; with &amp;quot;modNewName&amp;quot;).&lt;br /&gt;
*Change the number in: $this-&amp;gt;numero = 100000 by a number that designates your module id. To avoid conflicts with other modules, you can consult the page that lists already reserved id numbers: [[List of modules id|List of modules id]].&lt;br /&gt;
*Modify any other variables defined in the constructor (see comment in the code skeleton for their meaning).&lt;br /&gt;
&lt;br /&gt;
Your file descriptor for your module is ready. See the next step to activate it.&lt;br /&gt;
&lt;br /&gt;
===Test your descriptor===&lt;br /&gt;
&lt;br /&gt;
Launch Dolibarr and go to page &#039;&#039;&#039;Setup-&amp;gt;module&#039;&#039;&#039;? &lt;br /&gt;
If you set the property version in the module description you should see a new line with your new module and the possibility to activate it or not. If you set the property version to &amp;quot;develop&amp;quot; or &amp;quot;experiental&amp;quot;, to see your module, you must first go into &#039;&#039;&#039;Setup-Others&#039;&#039;&#039; and set MAIN_FEATURES_LEVEL to 1 to see &amp;quot;experimental&amp;quot; modules or 2 to see &amp;quot;development&amp;quot; modules.&lt;br /&gt;
&lt;br /&gt;
==Tree of path for new module files (required)==&lt;br /&gt;
This is how your files must be organized when building a new module (the zip file must also match this rule).&lt;br /&gt;
Note: Only the second line is mandatory.&lt;br /&gt;
&lt;br /&gt;
{{TemplateModuleTreeSimple}}&lt;br /&gt;
&lt;br /&gt;
==Create your SQL tables and the PHP DAO class (optional)==&lt;br /&gt;
&#039;&#039;&#039;When&#039;&#039;&#039;: If your module needs to manage data of its own&lt;br /&gt;
&lt;br /&gt;
===Create your .sql file===&lt;br /&gt;
If your module is designed to manage data of its own, which are not available in the standard version of Dolibarr, it is necessary to define SQL tables to store the data.&lt;br /&gt;
&lt;br /&gt;
Scripts for creating tables and loading data by your own module are saved into a subdirectory sql (&#039;&#039;&#039;&amp;quot;mymodule/sql&amp;quot;&#039;&#039;&#039;) of your module. (With ModuleBuilder, the directory and all sql files will be created automatically when you will create a new Object from tab Object).&lt;br /&gt;
&lt;br /&gt;
Then check into your descriptor file, into function &#039;&#039;&#039;init&#039;&#039;&#039; that the line&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;PHP&amp;quot;&amp;gt;$this-&amp;gt;_load_tables(&#039;/mymodule/sql/&#039;);&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
is not commented.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Rules to follow:&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
*Add the files about creating tables commands on the principle of an &#039;&#039;&#039;llx_mytable.sql&#039;&#039;&#039; file per table, with an optional &#039;&#039;&#039;llx_mytable.key.sql&#039;&#039;&#039; file (see existing files in &#039;&#039;&#039;install/mysql/tables&#039;&#039;&#039; for examples).&lt;br /&gt;
*The recommended type and name for SQL fields are defined into page [[Language_and_development_rules#Table_and_fields_structures]].&lt;br /&gt;
*To manage data, you must create a file called &#039;&#039;&#039;data.sql&#039;&#039;&#039; inside directory &#039;&#039;&#039;/mymodule/sql/&#039;&#039;&#039; that contains SQL command to add/edit/delete data.&lt;br /&gt;
*Don&#039;t use the double quote for strings (eg &#039;chaine&#039; not &amp;quot;chaine&amp;quot;) because the double quote have a specific meaning in PostGreSQL&lt;br /&gt;
&lt;br /&gt;
Example of content of a file data.sql&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;sql&amp;quot;&amp;gt;&lt;br /&gt;
 delete from llx_const where name=&#039;MYMODULE_IT_WORKS&#039; and entity=&#039;__ENTITY__&#039;;&lt;br /&gt;
 insert into llx_const (name, value, type, note, visible, entity) values (&#039;MYMODULE_IT_WORKS&#039;,&#039;1&#039;,&#039;chaine&#039;,&#039;A constant vor my module&#039;,1,&#039;__ENTITY__&#039;);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Files must be operational for the database mysql. Rem: The files of other databases are not maintained. They will be read and converted on the fly by the driver of the other database.&lt;br /&gt;
&lt;br /&gt;
===Test your .sql files===&lt;br /&gt;
&lt;br /&gt;
Once the files ready, you can return to the page to enable Dolibarr modules and disable the module, drop those tables in the database (if they already exists) and reactivate the module. The tables should be recreated by the activation of the module. If this is not the case, check your scripts by passing them by hand, or check the Dolibarr logs.&lt;br /&gt;
&lt;br /&gt;
===Generate the PHP DAO class===&lt;br /&gt;
The DAO PHP files should have been generated by ModuleBuilder after creating an object.&lt;br /&gt;
&lt;br /&gt;
You can however create them manually by copying existing object however using ModuleBuilder is highly recommended. You should find examples into &#039;&#039;&#039;htdocs/modulebuilder/templates/class/myobject.class.php&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
In this class, there are already operational CRUD (Create/Read/Update/Delete) methods to perform an insert, a fetch (select), an update, a delete of a table row. Edit the file to use the correct module name, tables and place this file in the class subdirectory of the module. The Module Builder allows you to do this with just a few mouse clicks.&lt;br /&gt;
&lt;br /&gt;
==The tab management (optional)==&lt;br /&gt;
&lt;br /&gt;
===Add or remove your own tabs on object sheets===&lt;br /&gt;
&#039;&#039;&#039;When&#039;&#039;&#039;: To add a tab on an object (invoices, orders, proposals, member ...)&lt;br /&gt;
&lt;br /&gt;
To do this go into the file descriptor of module previously created and edit the $this-&amp;gt;tabs array:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;PHP&amp;quot;&amp;gt;&lt;br /&gt;
	// Array to add new pages in new tabs or remove existing one&lt;br /&gt;
	$this-&amp;gt;tabs = array(&#039;objecttype:+tabname1:Title1:mylangfile@mymodule:$user-&amp;gt;rights-&amp;gt;mymodule-&amp;gt;read:/mymodule/mypagetab1.php?id=__ID__&#039;    // To add a new tab identified by code tabname1&lt;br /&gt;
                            &#039;objecttype:+tabname2:Title2:mylangfile@mymodule:$user-&amp;gt;rights-&amp;gt;mymodule-&amp;gt;read:/mymodule/mypagetab2.php?id=__ID__&#039;,   // To add a new tab identified by code tabname2&lt;br /&gt;
                            &#039;objecttype:-tabname&#039;);                                                     // To remove an existing tab identified by code tabname&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The table should contain a list of strings, each string representing a new tab. &lt;br /&gt;
The format of the string consisting of 5 parts separated by &amp;quot;:&amp;quot;&lt;br /&gt;
&lt;br /&gt;
*Part 1: The element type (object type) where the tab should appear is a value from the following:&lt;br /&gt;
{{TemplateModuleTabs}}&lt;br /&gt;
&lt;br /&gt;
*Part 2: A code to identify tab to add (start with +) or to remove (start with -)&lt;br /&gt;
*Part 3: The title of the tab. This can be a hard read or better code translation in a file lang.&lt;br /&gt;
*Part 4: The name of the file &amp;quot;*.lang&amp;quot; which contains correspondence between the code translation and language to display. If this name is followed with @mymodule, Dolibarr will search translation file &amp;quot;*.lang&amp;quot; within the module, so htdocs/mymodule/langs/code_CODE/mylangfile.lang, otherwise Dolibarr will look for file htdocs/langs/code_CODE/mylangfile.lang&lt;br /&gt;
*Part 5: A condition to test if tab must be visible. Put 1 to be always visible.&lt;br /&gt;
*Part 6: The URL of the page to display when you click on the tab. The __ID__ string will be replaced automatically by the Id of the element concerned.&lt;br /&gt;
&lt;br /&gt;
To feed the contents of the tab with data from the database, see the next chapter.&lt;br /&gt;
&lt;br /&gt;
In order to get the names  &#039;tabname&#039; of existing tabs, you have to check the names used in the function &#039;product_prepare_head&#039; of the file  &#039;core/lib/module.lib.php&#039; corresponding to section &#039;$head[$h][2]&#039;.&lt;br /&gt;
&lt;br /&gt;
===Show tabs navigation into your own pages===&lt;br /&gt;
&#039;&#039;&#039;When&#039;&#039;&#039;: To show all standard tabs of an object (product, tiers, etc.) on your page.&lt;br /&gt;
&lt;br /&gt;
You must follow these steps :&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;1. Include files you need into your file&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
For each object type, there are two files to include with line&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;PHP&amp;quot;&amp;gt;require_once($url_fichier) ;&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This is example of files to include (DOL_DOCUMENT_ROOT is often dolibarr/htdocs/) :&lt;br /&gt;
&lt;br /&gt;
*Object thirdparty (thirdparty) :&lt;br /&gt;
**DOL_DOCUMENT_ROOT/societe/class/societe.class.php&lt;br /&gt;
**DOL_DOCUMENT_ROOT/core/lib/company.lib.php&lt;br /&gt;
*Object product (product) :&lt;br /&gt;
**DOL_DOCUMENT_ROOT/product/class/product.class.php&lt;br /&gt;
**DOL_DOCUMENT_ROOT/core/lib/product.lib.php&lt;br /&gt;
*Object invoice (invoice) :&lt;br /&gt;
**DOL_DOCUMENT_ROOT/compta/facture/class/facture.class.php&lt;br /&gt;
**DOL_DOCUMENT_ROOT/core/lib/invoice.lib.php&lt;br /&gt;
&lt;br /&gt;
...&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;2. Create and load the object to show into your tab&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Create an instance of an object of the correct class and load object from the database by using the fetch method of an object in providing to this method the id you get from URL (ie : /mytab.php?id=1).&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Example :&#039;&#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;PHP&amp;quot;&amp;gt;&lt;br /&gt;
$id=GETPOST(&#039;id&#039;,&#039;int&#039;);&lt;br /&gt;
$ref=GETPOST(&#039;ref&#039;,&#039;alpha&#039;);&lt;br /&gt;
$product = new Product($db) ;&lt;br /&gt;
$result = $product-&amp;gt;fetch($id,$ref) ; // Test $result to check the database read is ok&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;3. Get a list of all tabs to show for your object type&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Use function XXX_prepare_head($obj), where XXX is name of object. This will return an array with all definition of tab entries to show. The parameter to put into this method is the instance of an object you want tabs.&lt;br /&gt;
&lt;br /&gt;
The resulting array has the following structure&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;PHP&amp;quot;&amp;gt;&lt;br /&gt;
$head        // Array of tabs&lt;br /&gt;
$head[$h]    // Element to describe one tab.&lt;br /&gt;
$head[$h][0] // Url of page to show when you click on tab&lt;br /&gt;
$head[$h][1] // Title of tab&lt;br /&gt;
$head[$h][2] // Code name to identify the tab&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Example :&#039;&#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;PHP&amp;quot;&amp;gt;&lt;br /&gt;
$head = product_prepare_head($product, $user) ; // parameter $user is present for some function anly&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;4. show tabs into your page&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Use function dol_fiche_head() to show all tabs defined into array $head returned by XX_prepare_head().&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;PHP&amp;quot;&amp;gt;&lt;br /&gt;
dol_fiche_head($links, $active=&#039;0&#039;, $title=&#039;&#039;, $notab=0, $picto=&#039;&#039;)&lt;br /&gt;
//$links  // Tableau des onglets, appelé $head plus haut.&lt;br /&gt;
//$active // Onglet actif (mettre le nom de l&#039;onglet défini dans votre fichier de module, ou un nom contenu dans $head[$h][2]). Cet onglet sera mis en surbrillance&lt;br /&gt;
//$title  // Title to show (shown into a special tab that you can&#039;t click)&lt;br /&gt;
//$notab&lt;br /&gt;
//$picto  // Name of image to show into title. Possible values are:&lt;br /&gt;
//            product&lt;br /&gt;
//            service&lt;br /&gt;
//            company&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This function will show required tabs and open an html element &#039;&#039;&amp;lt; div class=&amp;quot;&amp;quot; &amp;gt;&#039;&#039; that correspond to the area under the tabs. To close area of a tab, just use &#039;&#039;&amp;lt; /div &amp;gt;&#039;&#039; into your PHP page.&lt;br /&gt;
&lt;br /&gt;
==Create or modify PHP screens (optional)==&lt;br /&gt;
&#039;&#039;&#039;When&#039;&#039;&#039;: If the purpose of your module is to add features that require new or modified screens.&lt;br /&gt;
&lt;br /&gt;
===Create a new PHP screen===&lt;br /&gt;
You must then create your PHP pages that will show/edit data from tables using the skeleton templates provided as an example in the directory &#039;&#039;&#039;modulebuilder/myobject_page.php&#039;&#039;&#039; (For the development of a script from the command line, see [[Script development]]).&lt;br /&gt;
&lt;br /&gt;
To create a new user screen, create a subdirectory of &#039;&#039;&#039;htdocs&#039;&#039;&#039; (if not already done) for your module (in &#039;&#039;&#039;htdocs/mymodule&#039;&#039;&#039; for example) to store the pages you will create.&lt;br /&gt;
&lt;br /&gt;
Copy, into that directory, the file &#039;&#039;&#039;myobject_page.phpp&#039;&#039;&#039; that will serve as a starting point for your page file.&lt;br /&gt;
Edit the file to have a correct relative path to the main.inc.php file. &lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;PHP&amp;quot;&amp;gt;&lt;br /&gt;
// Load Dolibarr environment&lt;br /&gt;
$res=0;&lt;br /&gt;
// Try main.inc.php into web root known defined into CONTEXT_DOCUMENT_ROOT (not always defined)&lt;br /&gt;
if (! $res &amp;amp;&amp;amp; ! empty($_SERVER[&amp;quot;CONTEXT_DOCUMENT_ROOT&amp;quot;])) $res=@include($_SERVER[&amp;quot;CONTEXT_DOCUMENT_ROOT&amp;quot;].&amp;quot;/main.inc.php&amp;quot;);&lt;br /&gt;
// Try main.inc.php into web root detected using web root calculated from SCRIPT_FILENAME&lt;br /&gt;
$tmp=empty($_SERVER[&#039;SCRIPT_FILENAME&#039;])?&#039;&#039;:$_SERVER[&#039;SCRIPT_FILENAME&#039;];$tmp2=realpath(__FILE__); $i=strlen($tmp)-1; $j=strlen($tmp2)-1;&lt;br /&gt;
while($i &amp;gt; 0 &amp;amp;&amp;amp; $j &amp;gt; 0 &amp;amp;&amp;amp; isset($tmp[$i]) &amp;amp;&amp;amp; isset($tmp2[$j]) &amp;amp;&amp;amp; $tmp[$i]==$tmp2[$j]) { $i--; $j--; }&lt;br /&gt;
if (! $res &amp;amp;&amp;amp; $i &amp;gt; 0 &amp;amp;&amp;amp; file_exists(substr($tmp, 0, ($i+1)).&amp;quot;/main.inc.php&amp;quot;)) $res=@include(substr($tmp, 0, ($i+1)).&amp;quot;/main.inc.php&amp;quot;);&lt;br /&gt;
if (! $res &amp;amp;&amp;amp; $i &amp;gt; 0 &amp;amp;&amp;amp; file_exists(dirname(substr($tmp, 0, ($i+1))).&amp;quot;/main.inc.php&amp;quot;)) $res=@include(dirname(substr($tmp, 0, ($i+1))).&amp;quot;/main.inc.php&amp;quot;);&lt;br /&gt;
// Try main.inc.php using relative path&lt;br /&gt;
if (! $res &amp;amp;&amp;amp; file_exists(&amp;quot;../main.inc.php&amp;quot;)) $res=@include(&amp;quot;../main.inc.php&amp;quot;);&lt;br /&gt;
if (! $res &amp;amp;&amp;amp; file_exists(&amp;quot;../../main.inc.php&amp;quot;)) $res=@include(&amp;quot;../../main.inc.php&amp;quot;);&lt;br /&gt;
if (! $res &amp;amp;&amp;amp; file_exists(&amp;quot;../../../main.inc.php&amp;quot;)) $res=@include(&amp;quot;../../../main.inc.php&amp;quot;);&lt;br /&gt;
if (! $res) die(&amp;quot;Include of main fails&amp;quot;);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
As you can see, there are several tries to load the main.inc.php (or master.inc.php). The goal is to succeed in the most cases as possible. The minimum is 2 lines: one to try to load the master/main.inc.php into the dolibarr root directory and another one to try to load the file to support the case when the module is deployed into the &amp;quot;custom&amp;quot; directory. But you can have more to deal more situation. The provided example should be able to load the file main/master.inc.php in nearly all situation/setups.&lt;br /&gt;
&lt;br /&gt;
Note that you may add more &amp;quot;../&amp;quot; depending on the depth of the file relative to your module directory tree.&lt;br /&gt;
&lt;br /&gt;
It&#039;s in the main.inc.php file that is loaded technical environment variables and permissions. The following variables are objects positioned in this file:&lt;br /&gt;
&lt;br /&gt;
*$user    Object that contains the characteristics of the user + his permissions.&lt;br /&gt;
*$conf    Object that contains Dolibarr configuration.&lt;br /&gt;
*$db      Object that contains an opened connection handler to the database.&lt;br /&gt;
*$langs   Object that contains the user&#039;s language.&lt;br /&gt;
&lt;br /&gt;
Then enter your code to display the page.&lt;br /&gt;
&lt;br /&gt;
*To include a class or library dedicated to the module is done using a Dolibarr function (and not using directly include_once):&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Example :&#039;&#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;PHP&amp;quot;&amp;gt;&lt;br /&gt;
dol_include_once(&#039;/mymodule/class/myclass.class.php&#039;, &#039;MyClass&#039;);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
*To include classes provided with Dolibarr, use the following syntax:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Example :&#039;&#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;PHP&amp;quot;&amp;gt;&lt;br /&gt;
require_once DOL_DOCUMENT_ROOT.&#039;/core/class/doli.class.php&#039;;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Add some fields into existing forms===&lt;br /&gt;
You may want to provide a module that adds more fields into forms (input and view) of some elements. &lt;br /&gt;
&lt;br /&gt;
A heavy solution (but not so bad) may be to replace all pages used to create element (this means to disable the &amp;quot;New element&amp;quot; menu entry and adding yours, and disable tab that shows element to replace with a tab that is your own full page (copied/pasted from original) to do same than original page but modified to add your fields and stored added data into your own table). Go to menu [[#Define your entries in the menu (optional)]] and [[#The tab management (optional)]] if this solution suits you (this solution is more powerful since you can change everything you want into the page). &lt;br /&gt;
&lt;br /&gt;
We will describe here another solution, that works only to &amp;quot;add fields&amp;quot; at end of existing fields, using the element &amp;quot;category&amp;quot; as an example but you can convert this tutorial for invoice, proposal ...&lt;br /&gt;
&lt;br /&gt;
*First thing is to add a table, owned by your module, to store the value of new fields. This table will have only one column called &amp;quot;rowid&amp;quot; (will contain the same value than field rowid of element table) + one column for each new field you want to add. Then create a class with CRUD (Create/Read/Update/Delete) methods for this new table. For this two tasks, go back to previous chapter [[#Create your SQL tables and the PHP DAO class]].&lt;br /&gt;
*Next step is to add a hook into your module to add the new fields into the form. See chapter [[Hooks_system#Implement_the_Hook]] for generic documentation to use hooks.&lt;br /&gt;
&lt;br /&gt;
If you follow this tutorial, to be able to add fields into category forms, you must do:&lt;br /&gt;
{{ToComplete}}&lt;br /&gt;
&lt;br /&gt;
===Add/replace part of fields supported by hooks===&lt;br /&gt;
See chapter [[Hooks_system#Implement_the_Hook]] to know how to use Dolibarr existing hooks to add/replace code at Dolibarr hooks place.&lt;br /&gt;
&lt;br /&gt;
===Database access===&lt;br /&gt;
If you need to edit some data in the database inside your own table, use the PHP class generated before.&lt;br /&gt;
&lt;br /&gt;
If you to make access to tables with no dedicated PHP class available, this is always possible (for example if you want to get a list of records with a particular join or filter). In this case, this is a code samples to follow:&lt;br /&gt;
&lt;br /&gt;
To make an insert, update or delete:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;PHP&amp;quot;&amp;gt;&lt;br /&gt;
$db-&amp;gt;begin();   // Start transaction&lt;br /&gt;
$db-&amp;gt;query(&amp;quot;My SQL request insert, update or delete&amp;quot;);&lt;br /&gt;
$db-&amp;gt;commit();       // Validate transaction&lt;br /&gt;
or $db-&amp;gt;rollback()  // Cancel transaction&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
To read:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;PHP&amp;quot;&amp;gt;&lt;br /&gt;
$resql=$db-&amp;gt;query(&amp;quot;My select request&amp;quot;);&lt;br /&gt;
if ($resql)&lt;br /&gt;
{&lt;br /&gt;
	$num = $db-&amp;gt;num_rows($resql);&lt;br /&gt;
	$i = 0;&lt;br /&gt;
	if ($num)&lt;br /&gt;
	{&lt;br /&gt;
		while ($i &amp;lt; $num)&lt;br /&gt;
		{&lt;br /&gt;
			$obj = $db-&amp;gt;fetch_object($resql);&lt;br /&gt;
			if ($obj)&lt;br /&gt;
			{&lt;br /&gt;
				// You can use here results&lt;br /&gt;
				print $obj-&amp;gt;field1;&lt;br /&gt;
				print $obj-&amp;gt;field2;&lt;br /&gt;
			}&lt;br /&gt;
			$i++;&lt;br /&gt;
		}&lt;br /&gt;
	}&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Define style of your pages===&lt;br /&gt;
To have the look of your own pages to match the Dolibarr theme, it is necessary to use the Dolibarr CSS styles.&lt;br /&gt;
&lt;br /&gt;
You can use for example:&lt;br /&gt;
&lt;br /&gt;
*class=&amp;quot;&#039;&#039;&#039;liste_titre&#039;&#039;&#039;&amp;quot; on tags &#039;&#039;tr&#039;&#039; and &#039;&#039;td&#039;&#039; for the head row of a table.&lt;br /&gt;
*class=&amp;quot;&#039;&#039;&#039;pair&#039;&#039;&#039;&amp;quot; or class=&amp;quot;&#039;&#039;&#039;impair&#039;&#039;&#039;&amp;quot; on tags &#039;&#039;tr&#039;&#039; and &#039;&#039;td&#039;&#039; of other rows of a table.&lt;br /&gt;
*class=&amp;quot;&#039;&#039;&#039;flat&#039;&#039;&#039;&amp;quot; on all input fields (&#039;&#039;input, select, textarea&#039;&#039;...).&lt;br /&gt;
*class=&amp;quot;&#039;&#039;&#039;button&#039;&#039;&#039;&amp;quot; on HTML fields with type &#039;&#039;input type=&amp;quot;submit&amp;quot;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
===Use the Dolibarr date picker===&lt;br /&gt;
If you want to use the Dolibarr date selector (with its calendar popup) into your pages, use the following line:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;PHP&amp;quot;&amp;gt;&lt;br /&gt;
 $form=new Form($db);&lt;br /&gt;
 $form-&amp;gt;select_date(&#039;&#039;,&#039;mykey&#039;,0,0,0,&amp;quot;myform&amp;quot;);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
The string mykey will identify the date selector in the form. You must use different values if you use several date selectors in same page.&lt;br /&gt;
The string myform is the name of the FORM in which the selector is included (value found in the form name=&amp;quot;myform&amp;quot; in HTML page).&lt;br /&gt;
This means a date selector must be included necessarily into an html FORM.&lt;br /&gt;
&lt;br /&gt;
To get value after the POST of your form, the command is:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;PHP&amp;quot;&amp;gt;&lt;br /&gt;
$mydate = dol_mktime(12, 0 , 0, $GETPOST(&#039;mykeymonth&#039;, &#039;int&#039;), GETPOST(&#039;mykeyday&#039;, &#039;int&#039;), GETPOST(&#039;mykeyyear&#039;, &#039;int&#039;));&lt;br /&gt;
print strftime(&#039;%A %d %B %Y&#039;, $mydate);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Overwrite template file (tpl)===&lt;br /&gt;
If you want to overwrite tpl file on your module, you need to declare it on the module_parts :&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;PHP&amp;quot;&amp;gt;&lt;br /&gt;
&#039;tpl&#039; =&amp;gt; 1,&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Then you can put any tpl file on &#039;&#039;&#039;mymodule/core/tpl&#039;&#039;&#039;&lt;br /&gt;
as soon as the module is activate, the tpl will be overwrited&lt;br /&gt;
&lt;br /&gt;
==Add your own setup page (optional)==&lt;br /&gt;
&#039;&#039;&#039;When&#039;&#039;&#039;: If your module needs parameters, which are to be provided by the user, for proper setting up of the module.&lt;br /&gt;
&lt;br /&gt;
===Create your page to edit parameters===&lt;br /&gt;
If your module needs several parameters to be setup, you must create a page to edit options (these options will be saved in the [[Table llx_const|table &#039;&#039;&#039;llx_const&#039;&#039;&#039;]]).&lt;br /&gt;
Create a page named &#039;&#039;&#039;mymodule_setuppage.php&#039;&#039;&#039; that shows a form for possible options to update them into the above-mentioned table.&lt;br /&gt;
It is necessary to take an example from a page of the directory &#039;&#039;&#039;/admin&#039;&#039;&#039; that will show you the way to read/save your parameters.&lt;br /&gt;
Put this PHP page into the directory &#039;&#039;&#039;/admin&#039;&#039;&#039; of your module (e.g. mymodule/admin/mymodule_setuppage.php).&lt;br /&gt;
&lt;br /&gt;
===Modify the descriptor file of your module===&lt;br /&gt;
Then, within the descriptor file of your module, modify the variable &#039;&#039;&#039;config_page_url&#039;&#039;&#039; to set the name of this PHP page.&lt;br /&gt;
If the page is in the directory &#039;&#039;&#039;admin/&#039;&#039;&#039;, then the path is not required, e.g. like this:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;PHP&amp;quot;&amp;gt;&lt;br /&gt;
$this-&amp;gt;config_page_url = array(&amp;quot;mymodule_setuppage.php&amp;quot;);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
If the page is in the directory &#039;&#039;&#039;mymodule/admin/&#039;&#039;&#039;, then like this:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;PHP&amp;quot;&amp;gt;&lt;br /&gt;
$this-&amp;gt;config_page_url = array(&amp;quot;mymodule_setuppage.php@mymodule&amp;quot;);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Test your page===&lt;br /&gt;
Go into page &#039;&#039;&#039;Home-&amp;gt;Setup-&amp;gt;Modules&#039;&#039;&#039;, you should see a picture at the end of the line of your module to reach your setup page. Click on it, you should be able to view/edit parameters from your page.&lt;br /&gt;
&lt;br /&gt;
==Define your entries in menu (optional)==&lt;br /&gt;
&#039;&#039;&#039;When&#039;&#039;&#039;: If you have created PHP pages, it is necessary that those pages can be reached from menu entries in Dolibarr menu.&lt;br /&gt;
&lt;br /&gt;
===Define your menu entries===&lt;br /&gt;
For this, you must define into the module descriptor, the array this-&amp;gt;menu that declares all menus added by your module.&lt;br /&gt;
This array contains entries that will appear once your module is activated.&lt;br /&gt;
The example module descriptor file &#039;&#039;&#039;modMyModule.class.php&#039;&#039;&#039; contains an example to declare a top menu and also its left menu entries.&lt;br /&gt;
&lt;br /&gt;
This is the example of code to declare your own menu entries in a module descriptor file:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;PHP&amp;quot;&amp;gt;&lt;br /&gt;
// Main menu entries&lt;br /&gt;
$this-&amp;gt;menu = array();			// List of menus to add&lt;br /&gt;
$r=0;&lt;br /&gt;
&lt;br /&gt;
// Add here entries to declare new menus&lt;br /&gt;
// Example to declare the Top Menu entry:&lt;br /&gt;
$this-&amp;gt;menu[$r]=array(	&#039;fk_menu&#039;=&amp;gt;0,			// Put 0 if this is a top menu&lt;br /&gt;
			&#039;type&#039;=&amp;gt;&#039;top&#039;,			// This is a Top menu entry&lt;br /&gt;
			&#039;titre&#039;=&amp;gt;&#039;MyModule top menu&#039;,&lt;br /&gt;
			&#039;mainmenu&#039;=&amp;gt;&#039;mymodule&#039;,&lt;br /&gt;
			&#039;leftmenu&#039;=&amp;gt;&#039;mymodule&#039;,&lt;br /&gt;
			&#039;url&#039;=&amp;gt;&#039;/mymodule/pagetop.php&#039;,&lt;br /&gt;
			&#039;langs&#039;=&amp;gt;&#039;mylangfile&#039;,	// Lang file to use (without .lang) by module. File must be in langs/code_CODE/ directory.&lt;br /&gt;
			&#039;position&#039;=&amp;gt;100,&lt;br /&gt;
			&#039;enabled&#039;=&amp;gt;&#039;1&#039;,			// Define condition to show or hide menu entry. Use &#039;$conf-&amp;gt;mymodule-&amp;gt;enabled&#039; if entry must be visible if module is enabled.&lt;br /&gt;
			&#039;perms&#039;=&amp;gt;&#039;1&#039;,			// Use &#039;perms&#039;=&amp;gt;&#039;$user-&amp;gt;rights-&amp;gt;mymodule-&amp;gt;level1-&amp;gt;level2&#039; if you want your menu with a permission rules&lt;br /&gt;
			&#039;target&#039;=&amp;gt;&#039;&#039;,&lt;br /&gt;
			&#039;user&#039;=&amp;gt;2);				// 0=Menu for internal users, 1=external users, 2=both&lt;br /&gt;
$r++;&lt;br /&gt;
&lt;br /&gt;
// Example to declare a Left Menu entry:&lt;br /&gt;
$this-&amp;gt;menu[$r]=array(	&#039;fk_menu&#039;=&amp;gt;&#039;fk_mainmenu=xxx&#039;,		    // Use &#039;fk_mainmenu=xxx&#039; or &#039;fk_mainmenu=xxx,fk_leftmenu=yyy&#039; where xxx is mainmenucode and yyy is a leftmenucode of parent menu&lt;br /&gt;
			&#039;type&#039;=&amp;gt;&#039;left&#039;,			        // This is a Left menu entry&lt;br /&gt;
			&#039;titre&#039;=&amp;gt;&#039;MyModule left menu 1&#039;,&lt;br /&gt;
			&#039;mainmenu&#039;=&amp;gt;&#039;xxx&#039;,&lt;br /&gt;
			&#039;leftmenu&#039;=&amp;gt;&#039;yyy&#039;,&lt;br /&gt;
			&#039;url&#039;=&amp;gt;&#039;/mymodule/pagelevel1.php&#039;,&lt;br /&gt;
			&#039;langs&#039;=&amp;gt;&#039;mylangfile&#039;,	// Lang file to use (without .lang) by module. File must be in langs/code_CODE/ directory.&lt;br /&gt;
			&#039;position&#039;=&amp;gt;100,&lt;br /&gt;
			&#039;enabled&#039;=&amp;gt;&#039;1&#039;,			// Define condition to show or hide menu entry. Use &#039;$conf-&amp;gt;mymodule-&amp;gt;enabled&#039; if entry must be visible if module is enabled.&lt;br /&gt;
			&#039;perms&#039;=&amp;gt;&#039;1&#039;,			// Use &#039;perms&#039;=&amp;gt;&#039;$user-&amp;gt;rights-&amp;gt;mymodule-&amp;gt;level1-&amp;gt;level2&#039; if you want your menu with a permission rules&lt;br /&gt;
			&#039;target&#039;=&amp;gt;&#039;&#039;,&lt;br /&gt;
			&#039;user&#039;=&amp;gt;2);				// 0=Menu for internal users,1=external users, 2=both&lt;br /&gt;
$r++;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
To show the menu or not depending on a permission, modify property &#039;&#039;&#039;perms&#039;&#039;&#039; in the array. See chapter on permissions later to see how to add permissions.&lt;br /&gt;
&lt;br /&gt;
===Test your menu entries===&lt;br /&gt;
Disable and re-enable your module under the Dolibarr module setup page, menus entries must appear (if property &#039;enabled&#039; is declaration array is ok).&lt;br /&gt;
&lt;br /&gt;
==Add your own permissions (optional)==&lt;br /&gt;
&#039;&#039;&#039;When&#039;&#039;&#039;: If you want to add new permissions.&lt;br /&gt;
&lt;br /&gt;
The way to define permissions that will manage your module is done inside the module descriptor created previously.&lt;br /&gt;
Modify line &lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;PHP&amp;quot;&amp;gt;&lt;br /&gt;
$this-&amp;gt;rights_class = &#039;mymodule&#039;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
with correct value for mymodule.&lt;br /&gt;
&lt;br /&gt;
Then you must fill the array $this-&amp;gt;rights with as many entries than different permissions you need to manage.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;PHP&amp;quot;&amp;gt;&lt;br /&gt;
$this-&amp;gt;rights[$r][0] = 10001;&lt;br /&gt;
$this-&amp;gt;rights[$r][1] = &#039;Label by default of permission&#039;;&lt;br /&gt;
$this-&amp;gt;rights[$r][2] = &#039;r&#039;;&lt;br /&gt;
$this-&amp;gt;rights[$r][3] = 1;&lt;br /&gt;
$this-&amp;gt;rights[$r][4] = &#039;action&#039;;&lt;br /&gt;
$this-&amp;gt;rights[$r][5] = &#039;subaction&#039;;&lt;br /&gt;
$r++;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Into $this-&amp;gt;rights[$r][0], put a permission id not already used (See into menu &#039;&#039;&#039;System info&#039;&#039;&#039; on a working installation of Dolibarr to know list of id already used by standard modules.&lt;br /&gt;
Into $this-&amp;gt;rights[$r][1], put a label by default for permission (This label will be used if no translation can be found into the file &#039;&#039;&#039;admin.lang&#039;&#039;&#039; Translation key should be &amp;quot;Permission10001=My permission Label&amp;quot;).&lt;br /&gt;
Into $this-&amp;gt;rights[$r][2], types of the permission. There are three type of permission, &#039;r&#039; for read, list or expert permission, &#039;w&#039; for write or update permission and &#039;d&#039; for delete permission.&lt;br /&gt;
Into $this-&amp;gt;rights[$r][3], put 1 if this permission must be granted automatically by default to any newly created user.&lt;br /&gt;
Into $this-&amp;gt;rights[$r][4] and $this-&amp;gt;rights[$r][5], put an action and subaction string without spaces. You will be able to test if a user has the permission in your PHP source code with the sequence:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;PHP&amp;quot;&amp;gt;&lt;br /&gt;
if ($user-&amp;gt;rights-&amp;gt;mymodule-&amp;gt;action-&amp;gt;subaction) ...&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Define your own box (optional)==&lt;br /&gt;
&#039;&#039;&#039;When&#039;&#039;&#039;: If your module needs to provide one or several new boxes to show on home page.&lt;br /&gt;
&lt;br /&gt;
===Define your box===&lt;br /&gt;
For this, modify the array $this-&amp;gt;boxes into the module descriptor file.&lt;br /&gt;
All you have to do is to add 2 lines for each box file you will create into directory &#039;&#039;&#039;htdocs/mymodule/core/boxes&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Example:&#039;&#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;PHP&amp;quot;&amp;gt;&lt;br /&gt;
$this-&amp;gt;boxes[0][&#039;file&#039;]=&#039;mybox0.php@mymodule&#039;&lt;br /&gt;
$this-&amp;gt;boxes[0][&#039;note&#039;]=&#039;My box 0&#039;&lt;br /&gt;
 ...&lt;br /&gt;
$this-&amp;gt;boxes[n][&#039;file&#039;]=&#039;myboxn.php@mymodule&#039;&lt;br /&gt;
$this-&amp;gt;boxes[n][&#039;note&#039;]=&#039;My box n&#039;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Then create files &#039;&#039;&#039;htdocs/mymodule/core/boxes/mybox0.php&#039;&#039;&#039;, &#039;&#039;&#039;htdocs/mymodule/core/boxes/mybox1.php&#039;&#039;&#039;... by copying an example from an existing box file (found into directory &#039;&#039;&#039;htdocs/core/boxes&#039;&#039;&#039;).&lt;br /&gt;
&lt;br /&gt;
===Test if your box is detected by Dolibarr===&lt;br /&gt;
Disable and enabled module.&lt;br /&gt;
&lt;br /&gt;
Go into menu &#039;&#039;&#039;Home - Setup - Boxes&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Your boxes must appear in the list of boxes you can activate. Activate the box and go on the home page to see if the box is showing correctly.&lt;br /&gt;
&lt;br /&gt;
==Define your own export (optional)==&lt;br /&gt;
&#039;&#039;&#039;When&#039;&#039;&#039;: If your module provides new predefined database export profiles (for its own tables or for already existing tables of another module).&lt;br /&gt;
&lt;br /&gt;
===Define export===&lt;br /&gt;
For this uncomment and modify arrays $this-&amp;gt;export_xxx in your module descriptor file.&lt;br /&gt;
&lt;br /&gt;
===Test your export===&lt;br /&gt;
Go into menu Tools -&amp;gt; Export. Your export will appear in the list of available predefined exports (if your module is enabled).&lt;br /&gt;
Choose it, you must see a list of all possible fields defined in the export arrays.&lt;br /&gt;
Choose on field and try to build an export file. If ok, try again with all fields.&lt;br /&gt;
&lt;br /&gt;
==Define your CSS styles (optional)==&lt;br /&gt;
&#039;&#039;&#039;When&#039;&#039;&#039;: If in your PHP pages, you use class styles that are not defined inside Dolibarr themes CSS (not recommanded).&lt;br /&gt;
&lt;br /&gt;
===Create and declare your style sheet===&lt;br /&gt;
Create a style sheet CSS named &#039;&#039;&#039;mymodule.css&#039;&#039;&#039; or &#039;&#039;&#039;mymodule.css.php&#039;&#039;&#039; and put it into directory &#039;&#039;&#039;htdocs/mymodule&#039;&#039;&#039;. You can have several CSS files per module.&lt;br /&gt;
Remember it&#039;s better to use existing styles already available by default into Dolibarr (The CSS file used by Dolibarr is file &#039;&#039;&#039;themes/mytheme/&#039;&#039;themename&#039;&#039;.css.php&#039;&#039;&#039;. Create your own CSS files only if you need absolutely to add not already existing styles.&lt;br /&gt;
&lt;br /&gt;
Once your style sheets are ready, declare them into your module descriptor file by modifying the property &#039;&#039;&#039;$this-&amp;gt;modules_parts&#039;&#039;&#039;.&lt;br /&gt;
Value to put here must be an array of relative URLs to your CSS files.&lt;br /&gt;
For example&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;PHP&amp;quot;&amp;gt;&lt;br /&gt;
$this-&amp;gt;module_parts = array(&#039;css&#039; =&amp;gt; array(&#039;/mymodule/css/mymodule.css.php&#039;,&#039;/mymodule/css/myother.css&#039;));&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Test your style sheet===&lt;br /&gt;
Disable and enable your module.&lt;br /&gt;
&lt;br /&gt;
Go on the home page (index.php). Show the HTML source of the page.&lt;br /&gt;
&lt;br /&gt;
You should see into the HTML header, a line that declares your style sheet.&lt;br /&gt;
&lt;br /&gt;
==Add your Javascript functions (optional)==&lt;br /&gt;
&#039;&#039;&#039;When&#039;&#039;&#039;: If in your PHP pages, you use javascript functions not available in Dolibarr (in file lib_head.js)&lt;br /&gt;
&lt;br /&gt;
If you need to use your own javascript functions inside your PHP pages, it is necessary to have your functions, defined into your javascript file &#039;&#039;&#039;htdocs/mymodule/js/mymodule.js&#039;&#039;&#039;, included into the HTML HEAD section.&lt;br /&gt;
To ask Dolibarr that forge this header to include your own javascript file, you must just provide it to the llxHeader() function called by your page.&lt;br /&gt;
&lt;br /&gt;
Example for page /htdocs/mymodule/mypage.php :&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;PHP&amp;quot;&amp;gt;&lt;br /&gt;
$morejs=array(&amp;quot;/mymodule/js/mymodule.js&amp;quot;);&lt;br /&gt;
llxHeader(&#039;&#039;,&#039;Titre&#039;,&#039;&#039;,&#039;&#039;,&#039;&#039;,&#039;&#039;,$morejs,&#039;&#039;,0,0); &lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Run your own code on any Dolibarr event (optional)==&lt;br /&gt;
&#039;&#039;&#039;When&#039;&#039;&#039;: If you want to execute your own code once a common Dolibarr event has occurred (example: I want to update a table in my module when an invoice is created into Dolibarr), you must create a &#039;&#039;&#039;triggers&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
See also [[Interfaces_Dolibarr_toward_foreign_systems]]&lt;br /&gt;
and [[Interfaces_from_foreign_systems_toward_Dolibarr]]&lt;br /&gt;
&lt;br /&gt;
==Insert your code inside Dolibarr hooks positions (optional)==&lt;br /&gt;
&#039;&#039;&#039;When&#039;&#039;&#039;: When you want to add code or replace Dolibarr code into another situation than a business event (See the previous chapter for adding code during a business event).&lt;br /&gt;
&lt;br /&gt;
See page [[Hooks_system]].&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Add your own numbering rules==&lt;br /&gt;
&#039;&#039;&#039;When&#039;&#039;&#039;: When you need a new rule for generated ref of elements that are not covered by existing rules.&lt;br /&gt;
&lt;br /&gt;
See page [[Create numbering module]].&lt;br /&gt;
&lt;br /&gt;
==Add your document template (optional)==&lt;br /&gt;
&#039;&#039;&#039;When&#039;&#039;&#039;: When you want to personalized your own generated PDF or ODT documents.&lt;br /&gt;
&lt;br /&gt;
Note: To add this feature you don&#039;t need to create a module descriptor.&lt;br /&gt;
&lt;br /&gt;
Documentation to add your own template is available on page [[Create_a_PDF_document_template]] or [[Create_an_ODT_document_template]].&lt;br /&gt;
&lt;br /&gt;
==Add your skin (optional)==&lt;br /&gt;
&#039;&#039;&#039;When&#039;&#039;&#039;: When you want to personalized your colors/fonts/images.&lt;br /&gt;
&lt;br /&gt;
Note: To add this feature you don&#039;t need to create a module descriptor.&lt;br /&gt;
&lt;br /&gt;
To add your own skin, read page [[Skins]].&lt;br /&gt;
&lt;br /&gt;
=Some coding rules and predefined functions=&lt;br /&gt;
The coding rules to be followed are defined in the [[Developer documentation]], under section &amp;quot;General Information - Language and standards development&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
A lot of predefined features for developers are also available and described into page [[Developer documentation]] under section &amp;quot;Technical components of Dolibarr&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
=Create a package to distribute and install your module=&lt;br /&gt;
This process must be used to generate a package to submit it on the http://www.dolistore.com marketplace.&lt;br /&gt;
But you can use it to have a package easy to distribute on your own network.&lt;br /&gt;
&lt;br /&gt;
*Go into the directory &#039;&#039;&#039;/build&#039;&#039;&#039; and copy the file &#039;&#039;&#039;makepack-dolibarrmodules.conf&#039;&#039;&#039; into &#039;&#039;&#039;makepack-mymodule.conf&#039;&#039;&#039;. Warning, this directory may not be provided in some packages of stable versions. If so, it can be retrieved from the snapshot available for download on the Dolibarr website in area &amp;quot;Development version&amp;quot; (taken in this case the whole build directory which is autonomous and independent directory).&lt;br /&gt;
&lt;br /&gt;
Edit this file to add a list of file names for all new files you created for your module (module descriptor, new sql tables files, php page, images, etc...)&lt;br /&gt;
&lt;br /&gt;
*Run the script via Perl (need the Perl version 5.0 or later):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
perl makepack-dolibarrmodule.pl&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
The script asks you the name of your module, its major and minor version. A file &#039;&#039;&#039;mymodule.zip &#039;&#039;&#039; will then be manufactured containing your module ready to be deployed.&lt;br /&gt;
&lt;br /&gt;
*The person who receives your module must then place the file in the root directory of a Dolibarr installation and perform the command:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
tar -xvf mymodule.zip&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
*If you want your module to be public, you can submit it (the zip file) on Dolibarr marketplace website: {{LinkToPluginDownload}} (you must create an account first and be logged to use the link &amp;quot;Submit a module/product&amp;quot;).&lt;br /&gt;
**If your module was built correctly, the file will be validated later.&lt;br /&gt;
**If quality is enough and license permits it, the code might be added inside main Dolibarr sources (except if you disagree for that).&lt;br /&gt;
&lt;br /&gt;
=Enabling/activation condition of external module on DoliStore=&lt;br /&gt;
&lt;br /&gt;
See [[Module_Dolistore_Validation_Rules|Validation Rules]]&lt;br /&gt;
[[Category:Development]]&lt;/div&gt;</summary>
		<author><name>TanguyP</name></author>
	</entry>
	<entry>
		<id>https://wiki.dolibarr.org/index.php?title=D%C3%A9veloppement_module&amp;diff=58523</id>
		<title>Développement module</title>
		<link rel="alternate" type="text/html" href="https://wiki.dolibarr.org/index.php?title=D%C3%A9veloppement_module&amp;diff=58523"/>
		<updated>2023-10-25T13:58:00Z</updated>

		<summary type="html">&lt;p&gt;TanguyP: Orthographe et typographie&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;!-- BEGIN interlang links --&amp;gt;&lt;br /&gt;
&amp;lt;!-- Do NOT edit this section&lt;br /&gt;
     Links below are automatically managed by PolyglotBot&lt;br /&gt;
     You can edit links on the English source page : Module_development --&amp;gt;&lt;br /&gt;
[[en:Module_development]]&lt;br /&gt;
[[es:Desarrollo_de_un_módulo]]&lt;br /&gt;
[[de:Modul_Entwicklung]]&lt;br /&gt;
[[zh:模块开发]]&lt;br /&gt;
[[ja:モジュール_開発]]&lt;br /&gt;
&amp;lt;!-- END interlang links --&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Category:Noyau]]&lt;br /&gt;
{{TemplateDocDev}}&lt;br /&gt;
Pour créer un nouveau module, il existe plusieurs étapes. Ce didacticiel a pour but de vous décrire chacune d&#039;elles afin d&#039;ajouter un module permettant d&#039;étendre les possibilités de Dolibarr, comme par exemple ajouter une ou plusieurs des fonctionnalités suivantes:&lt;br /&gt;
&lt;br /&gt;
*Ajouter de nouvelles tables en base.&lt;br /&gt;
*Ajouter vos propres entrées dans les menus.&lt;br /&gt;
*Ajouter des objets et des écrans de saisie/consultation de nouvelle tables.&lt;br /&gt;
*Ajouter ou supprimer des onglets sur les pages de vues/édition des objets (facture, produit, commande, événement, ...)&lt;br /&gt;
*Ajouter des exports prédéfinis pour la fonction export.&lt;br /&gt;
*Ajouter de nouvelles boites/widgets pour la home page.&lt;br /&gt;
*Ajouter des variables de substitution.&lt;br /&gt;
*Définir de nouvelles permissions.&lt;br /&gt;
*Déclencher du code automatiquement sur une action Dolibarr particulière.&lt;br /&gt;
*Insérer votre code aux emplacements hooks de Dolibarr&lt;br /&gt;
*Ajouter un modèle de numérotation de la référence des objets créés.&lt;br /&gt;
*Ajouter un modèle de document PDF.&lt;br /&gt;
*Ajouter un nouveau thème.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Les chapitres suivants vous présentent comment réaliser tout cela en manuel de manière simple.&lt;br /&gt;
&lt;br /&gt;
=[[File:Art.png]] Création de Module avec le générateur de module=&lt;br /&gt;
Depuis Dolibarr 9.0 il est possible de créer les fichiers principaux de votre module avec le &amp;quot;Générateur de module&amp;quot; (aussi appelé &amp;quot;Module Builder&amp;quot;). Pour l&#039;activer :&lt;br /&gt;
&lt;br /&gt;
*Activez le module &amp;quot;Générateur de Module&amp;quot; (ou &amp;quot;Module builder&amp;quot;) dans la section &amp;quot;Outils multi-modules&amp;quot; de Configuration &amp;gt; Modules/Applications&lt;br /&gt;
&lt;br /&gt;
[[File:Mod_builder_2.png|400px]]&lt;br /&gt;
&lt;br /&gt;
*Puis cliquez sur l’icône &amp;quot;bug&amp;quot; qui est apparue dans la barre de menu en haut à droite&lt;br /&gt;
&lt;br /&gt;
[[File:Mod_builder_3.png|400px]]&lt;br /&gt;
&lt;br /&gt;
=[[File:Art.png]] Exemple de modèle de module externe=&lt;br /&gt;
Un bon modèle/squelette de module externe Dolibarr est disponible ici : [https://github.com/Dolibarr/dolibarr/tree/develop/htdocs/modulebuilder/template GitHub Dolibarr Module Modèle]&lt;br /&gt;
&lt;br /&gt;
=[[File:Art.png]] Créer un module=&lt;br /&gt;
Les sous chapitres suivant décrivent les actions à faire pour créer un module Dolibarr. Les premiers chapitres sont obligatoires quelle que soit la vocation du module, les suivants dépendront de ce que doit faire le module.&lt;br /&gt;
&lt;br /&gt;
==Créer un descripteur de Module (obligatoire)==&lt;br /&gt;
&#039;&#039;&#039;Quand&#039;&#039;&#039; : Obligatoire dès qu&#039;une extension est développée, quelle que soit sa vocation.&lt;br /&gt;
&#039;&#039;&#039;Depuis Dolibarr 9.0, il est possible de créer le descripteur de votre module avec le &amp;quot;Générateur de module&amp;quot;&#039;&#039;&#039;. Cet outil est encore encours de développement et de maturité mais peut d&#039;ores et déjà être utilisé.&lt;br /&gt;
&lt;br /&gt;
===Créer votre descripteur avec le générateur de module===&lt;br /&gt;
&lt;br /&gt;
*Lancez le générateur de module en cliquant sur l’icône &amp;quot;bug&amp;quot;&lt;br /&gt;
&lt;br /&gt;
[[File:Mod_builder_3.png|400px]]&lt;br /&gt;
&lt;br /&gt;
*Entrez le nom de votre module sans espaces (le nom de votre module NE DOIT PAS CONTENIR le caractère underscore ou tiret bas : _) et cliquez sur Créer.&lt;br /&gt;
&lt;br /&gt;
[[File:Mod_builder_4.png|400px]]&lt;br /&gt;
&lt;br /&gt;
*Un module avec ses premiers fichiers a été initialisé. Vous pouvez alors modifier les paramètres du descripteur du module :&lt;br /&gt;
&lt;br /&gt;
[[File:Mod_builder_5.png|400px]]&lt;br /&gt;
&lt;br /&gt;
===Alternative : créer votre descripteur manuellement (sans utiliser le générateur de module)===&lt;br /&gt;
La première étape est donc de créer un fichier de description du module (descripteur). Pour cela:&lt;br /&gt;
&lt;br /&gt;
*Créez le répertoire &#039;&#039;&#039;/htdocs/&#039;&#039;monmodule&#039;&#039;/core/modules&#039;&#039;&#039;. Puis, allez dans le répertoire &#039;&#039;&#039;dev/skeletons&#039;&#039;&#039; et recopiez le fichier modMyModule.class.php dans ce répertoire &#039;&#039;&#039;htdocs/&#039;&#039;monmodule&#039;&#039;/core/modules&#039;&#039;&#039;.&lt;br /&gt;
*Renommez le fichier mod&#039;&#039;&#039;MyModule&#039;&#039;&#039;.class.php en modifiant seulement la partie &#039;&#039;&#039;MyModule&#039;&#039;&#039; (le fichier doit commencer par mod)&lt;br /&gt;
&lt;br /&gt;
Ensuite, modifiez le contenu de ce fichier afin de remplacer :&lt;br /&gt;
&lt;br /&gt;
*les &#039;&#039;modMyModule&#039;&#039; en une valeur qui corresponde à la vocation de votre module. Cette valeur doit toujours commencer par &#039;&amp;lt;nowiki/&amp;gt;&#039;&#039;&#039;mod&#039;&#039;&#039;&#039; et ne contenir que des &#039;&#039;&#039;caractères alphabétiques&#039;&#039;&#039;.&lt;br /&gt;
*$this-&amp;gt;numero = &#039;&#039;100000&#039;&#039; par un numéro de module libre. Pour éviter tout conflit, vous pouvez consulter la page suivante pour retrouver les numéros déjà alloués : [[List of modules id|Liste des id de modules]].&lt;br /&gt;
*Modifier éventuellement les autres variables définies dans le constructeurs (Voir le commentaire dans le code du squelette pour leur signification).&lt;br /&gt;
&lt;br /&gt;
Le descripteur de votre module est alors en place.&lt;br /&gt;
&lt;br /&gt;
===Tester votre descripteur===&lt;br /&gt;
&lt;br /&gt;
Lancez Dolibarr et allez sur la page &#039;&#039;&#039;Configuration-&amp;gt;module&#039;&#039;&#039;, vous devez voir apparaître une nouvelle ligne avec votre nouveau module et la possibilité de l&#039;activer ou non (parcourez tous les onglets de chaque catégories de modules jusqu&#039;à le retrouver).&lt;br /&gt;
C&#039;est la valeur de $this-&amp;gt;special qui détermine dans quel onglet se trouve votre module.&lt;br /&gt;
&lt;br /&gt;
===Nom de module===&lt;br /&gt;
&lt;br /&gt;
Le nom de votre module NE DOIT PAS CONTENIR le caractère underscore ou tiret bas : _&lt;br /&gt;
&lt;br /&gt;
==Arborescence d&#039;un nouveau module==&lt;br /&gt;
Voici l&#039;arborescence à respecter pour l&#039;organisation des fichiers d&#039;un module (cette arborescence sera celle prise d&#039;office si vous générer les fichiers à l&#039;aide de ModuleBuilder).&lt;br /&gt;
&lt;br /&gt;
{{TemplateModuleTreeSimple}}&lt;br /&gt;
&lt;br /&gt;
Un bon modèle/squelette de module externe Dolibarr est disponible ici : [https://github.com/Dolibarr/dolibarr/tree/develop/htdocs/modulebuilder/template GitHub Dolibarr Module Modèle]&lt;br /&gt;
&lt;br /&gt;
==Créer vos tables SQL et les classes PHP DAO (optionnel)==&lt;br /&gt;
&#039;&#039;&#039;Quand&#039;&#039;&#039; : Si votre module a besoin de gérer des données qui lui sont propres&lt;br /&gt;
&lt;br /&gt;
===Créer vos fichiers .sql===&lt;br /&gt;
Si votre module a vocation à gérer des données bien à lui, qui n&#039;existent pas en base dans la version standard de Dolibarr, il est nécessaire de définir des tables SQL pour stocker ces données.&lt;br /&gt;
&lt;br /&gt;
Créer un sous-répertoire &#039;&#039;&#039;sql&#039;&#039;&#039; dans le répertoire de votre module (&#039;&#039;&#039;monmodule/sql&#039;&#039;&#039;) afin d&#039;y placer les scripts sql que vous allez créer (Avec ModuleBuilder cette étape sera réalisée automatiquement suite à la création d&#039;un nouvel Objet depuis l&#039;onglet Objet).&lt;br /&gt;
&lt;br /&gt;
Ensuite, vérifiez dans votre fichier descripteur de module, dans la fonction &#039;&#039;&#039;init&#039;&#039;&#039; que la ligne&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;php&amp;quot;&amp;gt;$this-&amp;gt;_load_tables(&#039;/mymodule/sql/&#039;);&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
n&#039;est pas commentée.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Règles à respecter:&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
*Ajoutez les fichiers d&#039;ordre de création de vos tables sur le principe de 1 fichier par table, nommé &#039;&#039;&#039;llx_matable.sql&#039;&#039;&#039; (pour la table), accompagné éventuellement du fichier &#039;&#039;&#039;llx_matable.key.sql&#039;&#039;&#039; (pour les index ou clé étrangères). Voir les exemples dans les fichiers existants dans &#039;&#039;&#039;install/mysql/tables&#039;&#039;&#039; pour exemple.&lt;br /&gt;
*Les types et noms recommandés pour les champs SQL sont définis sur la page [[https://wiki.dolibarr.org/index.php/Langages_et_normes#R.C3.A8gles_de_codage_SQL]].&lt;br /&gt;
*Pour ce qui est des commandes permettant d&#039;ajouter/manipuler des données, elles doivent toutes se trouver dans un fichier nommé &#039;&#039;&#039;data.sql&#039;&#039;&#039; situé dans le même répertoire &#039;&#039;&#039;/monmodule/sql/&#039;&#039;&#039;.&lt;br /&gt;
*N&#039;utilisez pas &amp;quot;chaine&amp;quot; mais &#039;chaine&#039; car les guillemets doubles (&amp;quot;) ont une signification particulière en PostGreSQL&lt;br /&gt;
&lt;br /&gt;
Exemple de contenu de fichier data.sql&lt;br /&gt;
&amp;lt;source lang=&amp;quot;sql&amp;quot;&amp;gt;&lt;br /&gt;
 delete from llx_const where name=&#039;MONMODULE_IT_WORKS&#039; and entity=&#039;__ENTITY__&#039;;&lt;br /&gt;
 insert into llx_const (name, value, type, note, visible, entity) values (&#039;MONMODULE_IT_WORKS&#039;,&#039;1&#039;,&#039;chaine&#039;,&#039;A constant for my module&#039;,1,&#039;__ENTITY__&#039;);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Les ordres SQL des fichiers doivent être opérationnels pour la base de données &#039;&#039;&#039;mysql&#039;&#039;&#039;.&lt;br /&gt;
Rem: Les fichiers des autres types de bases ne sont pas à maintenir. Ils sont lus et convertis à la volée par le driver de la base de données.&lt;br /&gt;
&lt;br /&gt;
===Tester vos fichiers .sql===&lt;br /&gt;
&lt;br /&gt;
Une fois les fichiers prêts, vous pouvez retourner dans l&#039;écran de gestion des modules de Dolibarr puis désactiver le module, dropper les tables en base (si elles existent déjà) et réactiver le module.&lt;br /&gt;
Les tables doivent alors être recréées par l&#039;activation du module.&lt;br /&gt;
Si tel n&#039;est pas le cas, vérifiez vos scripts en les passant à la main, ou consultez les logs Dolibarr.&lt;br /&gt;
&lt;br /&gt;
===Générer la classe PHP DAO d&#039;accès aux tables===&lt;br /&gt;
&lt;br /&gt;
Le fichier de classe DAO PHP d&#039;un object est généré automatiquement avec ModuleBuilder lors de la création d&#039;un Object.&lt;br /&gt;
&lt;br /&gt;
À défaut d&#039;utiliser le générateur de module, vous trouverez des exemples dans le squelette de module, fichier &#039;&#039;&#039;htdocs/modulebuilder/templates/class/myobject.class.php&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Dans cette classe, se trouvent des méthodes CRUD (Create/Read/Update/Delete) déjà opérationnelles pour faire un insert, un fetch (select), un update, un delete d&#039;une ligne de la table. Éditer le fichier pour utiliser le bon nom de module, de tables et placer ce fichier dans le sous-répertoire de &#039;&#039;&#039;class&#039;&#039;&#039; du module. Le Module Builder permet de faire cela en quelques clics de souris.&lt;br /&gt;
&lt;br /&gt;
==Affichage des onglets (optionnel)==&lt;br /&gt;
&lt;br /&gt;
===Ajouter ou supprimer des onglets sur les fiches objets===&lt;br /&gt;
&#039;&#039;&#039;Quand&#039;&#039;&#039; : Pour ajouter votre propre onglet parmi les onglets d&#039;un object standard (facture, commande, proposition commercial, adhérent...)&lt;br /&gt;
&lt;br /&gt;
Pour cela, allez dans le fichier descripteur de module précédemment créé et modifiez le tableau $this-&amp;gt;tabs:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
	// Array to add new pages in new tabs or remove existing one&lt;br /&gt;
	$this-&amp;gt;tabs = array(&#039;objecttype:+tabname1:Title1:mylangfile@monmodule:$user-&amp;gt;rights-&amp;gt;monmodule-&amp;gt;read:/monmodule/mapagetab1.php?id=__ID__&#039;    // To add a new tab identified by code tabname1&lt;br /&gt;
                            &#039;objecttype:+tabname2:Title2:mylangfile@monmodule:$user-&amp;gt;rights-&amp;gt;monmodule-&amp;gt;read:/monmodule/mapagetab2.php?id=__ID__&#039;,   // To add a new tab identified by code tabname2&lt;br /&gt;
                            &#039;objecttype:-tabname&#039;);                                                     // To remove an existing tab identified by code tabname&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Le tableau doit contenir une liste de chaîne, chaque chaîne représentant un nouvel onglet.&lt;br /&gt;
Le format de la chaîne étant composé de 6 parties séparées par &amp;quot;:&amp;quot;&lt;br /&gt;
&lt;br /&gt;
*Partie 1 : le type d&#039;élément (objecttype) dans lequel doit apparaître l&#039;onglet qui est une valeur parmi celle-ci:&lt;br /&gt;
{{TemplateModuleTabs-fr}}&lt;br /&gt;
&lt;br /&gt;
*Partie 2 : nom de code pour l&#039;onglet à ajouter (commence par +) ou à enlever (commence par -)&lt;br /&gt;
*Partie 3 : le titre de l&#039;onglet. Cela peut être un libellé en dur ou mieux un code traduction présent dans un fichier lang.&lt;br /&gt;
*Partie 4 : le nom du fichier .lang (sans l&#039;extension .lang) qui contient la correspondance entre le code traduction et le libellé à afficher. Si ce com est suivi de @monmodule, Dolibarr cherche le fichier dans le répertoire lang propre au module, c&#039;est à dire htdocs/monmodule/langs/code_CODE/monmodule.lang, sinon Dolibarr cherche le fichier traduction dans htdocs/langs/code_CODE/mylangfile.lang&lt;br /&gt;
*Partie 5 : une condition à tester pour savoir si l&#039;onglet doit être visible ou pas. Mettre &#039;1&#039; pour qu&#039;il soit toujours visible.&lt;br /&gt;
*Partie 6 : l&#039;url de la page à afficher quand on clique sur l&#039;onglet. La chaine __ID__ sera remplacée automatiquement par l&#039;Id de l&#039;entité concernée.&lt;br /&gt;
&lt;br /&gt;
Pour que la déclaration soit effective, il faut désactiver et réactiver le module.&lt;br /&gt;
&lt;br /&gt;
Pour alimenter le contenu de l&#039;onglet avec des données issues de la base, voir le chapitre suivant.&lt;br /&gt;
&lt;br /&gt;
===Ajouter les onglets standard d&#039;un objet sur sa propre page d&#039;onglet===&lt;br /&gt;
&#039;&#039;&#039;Quand&#039;&#039;&#039; : Pour afficher les onglets existant d&#039;un objet standard (produit, tiers, etc.) sur votre nouvelle page onglet.&lt;br /&gt;
&lt;br /&gt;
Il faut appliquer la procédure suivante :&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;1. Inclure les fichiers définissant les fonctions utiles dans vos fichiers&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Pour chaque fiche entité, il y a deux fichiers à inclure avec l&#039;instruction&lt;br /&gt;
&amp;lt;source lang=&amp;quot;php&amp;quot;&amp;gt;require_once($url_fichier) ;&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Voici quelques exemples de fichiers à inclure (DOL_DOCUMENT_ROOT correspond au dossier dolibarr/htdocs/) :&lt;br /&gt;
&lt;br /&gt;
*Entité tiers (thirdparty) :&lt;br /&gt;
**DOL_DOCUMENT_ROOT/societe/class/societe.class.php&lt;br /&gt;
**DOL_DOCUMENT_ROOT/core/lib/company.lib.php&lt;br /&gt;
*Entité produit (product) :&lt;br /&gt;
**DOL_DOCUMENT_ROOT/product/class/product.class.php&lt;br /&gt;
**DOL_DOCUMENT_ROOT/core/lib/product.lib.php&lt;br /&gt;
*Entité facture (invoice) :&lt;br /&gt;
**DOL_DOCUMENT_ROOT/compta/facture/facture.class.php&lt;br /&gt;
**DOL_DOCUMENT_ROOT/core/lib/invoice.lib.php&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;2. Créer et charger l&#039;objet à afficher dans votre onglet&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Créez l&#039;objet de la classe voulue, et récupérez les données de l&#039;objet à partir de la base de données. Pour cela il faut utiliser les fonctions fetch() de la classe correspondante, en passant en paramètre l&#039;identifiant de l&#039;objet que vous récupérez depuis l&#039;url (ex : /mononglet.php?id=1).&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Exemple :&#039;&#039;&lt;br /&gt;
&amp;lt;source lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
$id=GETPOST(&#039;id&#039;,&#039;int&#039;);&lt;br /&gt;
$ref=GETPOST(&#039;ref&#039;,&#039;alpha&#039;);&lt;br /&gt;
$product = new Product($db) ;&lt;br /&gt;
$result = $product-&amp;gt;fetch($id, $ref) ; //Tester $result pour vérifier que l&#039;accès à la base s&#039;est bien passée&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;3. Récupérer la liste des onglets correspondant à l&#039;entité choisie&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Utilisez la fonction XXX_prepare_head($obj), ou XXX est le nom de l&#039;entité, permettant de créer un tableau contenant les définitions des onglets à afficher. Le paramètre à passer est l&#039;objet pour lequel vous voulez afficher les onglets.&lt;br /&gt;
&lt;br /&gt;
Le tableau retourné est composé de la façon suivante :&lt;br /&gt;
&amp;lt;source lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
$head        // Tableau des onglets&lt;br /&gt;
$head[$h]    // Élément décrivant un onglet. Il y aura autant de $h que d&#039;onglets à afficher&lt;br /&gt;
$head[$h][0] // Url de la page affichée quand on clique sur l&#039;onglet&lt;br /&gt;
$head[$h][1] // Titre de l’onglet&lt;br /&gt;
$head[$h][2] // Code de l&#039;onglet, à utiliser pour choisir quel onglet sera &#039;actif&#039; (voir paragraphe suivant)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Exemple :&#039;&#039;&lt;br /&gt;
&amp;lt;source lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
$head = product_prepare_head($product, $user) ; //le paramètre $user n&#039;est pas présent sur certaines fonctions&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;4. Afficher les onglets sur votre page onglet&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Utilisez la fonction dol_fiche_head() qui affiche les onglets contenus dans le tableau $head retourné par XX_prepare_head().&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
dol_fiche_head($links, $active=&#039;0&#039;, $title=&#039;&#039;, $notab=0, $picto=&#039;&#039;)&lt;br /&gt;
//$links  // Tableau des onglets, appelé $head plus haut.&lt;br /&gt;
//$active // Onglet actif (mettre le nom de l&#039;onglet défini dans votre fichier de module, ou un nom contenu dans $head[$h][2]). Cet onglet sera mis en surbrillance&lt;br /&gt;
//$title  // ?&lt;br /&gt;
//$notab  // Mettre ce paramètre à 1 permet de ne pas afficher de zone bleue en dessous des onglets.&lt;br /&gt;
//$picto  // Nom de l&#039;image à utiliser au début de la barre des onglet. Les choix suivant sont possibles :&lt;br /&gt;
//            product&lt;br /&gt;
//            service&lt;br /&gt;
//            company&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Cette fonction affiche les onglets voulus et ouvre un élément &#039;&#039;&amp;lt; div class=&amp;quot;&amp;quot; &amp;gt;&#039;&#039; qui correspond à la zone bleue sous les onglets (si paramètre $notab = 0). Pour fermer la zone bleue, il suffit de fermer l&#039;élément &#039;&#039;&amp;lt; /div &amp;gt;&#039;&#039; dans le code PHP.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Remarque&#039;&#039; :&lt;br /&gt;
Pour plus de détail, se référer à la [http://www.dolibarr.fr/doxygen/ documentation Doxygen] ou directement au code de Dolibarr.&lt;br /&gt;
&lt;br /&gt;
==Créer vos pages écran PHP (optionnel)==&lt;br /&gt;
&#039;&#039;&#039;Quand&#039;&#039;&#039; : Si l&#039;objet de votre module est d&#039;ajouter des fonctionnalités qui nécessitent de nouveaux écrans.&lt;br /&gt;
&lt;br /&gt;
===Créer une page écran PHP brute===&lt;br /&gt;
Vous pouvez ensuite créer vos pages PHP, qui se basent sur les données de vos tables, en utilisant les squelettes fournis comme exemple dans le répertoire &#039;&#039;&#039;modulebuilder&#039;&#039;&#039; (Pour le développement d&#039;un script en ligne de commande, voir [[Développement de scripts]]). La encore, si vous avez utilisez ModuleBuilder, des cas de pages (liste, page de création, onglet notes, etc...) auront été créés automatiquement lors de l&#039;initialisation de l&#039;objet.&lt;br /&gt;
&lt;br /&gt;
Pour créer une nouvelle page écran utilisateur, créez un sous-répertoire de &#039;&#039;&#039;htdocs&#039;&#039;&#039; (si non déjà fait) propre à votre module (Dans &#039;&#039;&#039;htdocs/monmodule&#039;&#039;&#039; par exemple) afin d&#039;y placer les pages que vous allez créer.&lt;br /&gt;
&lt;br /&gt;
Y recopier le fichier &#039;&#039;&#039;myobject_page.php&#039;&#039;&#039; qui va servir de point de départ.&lt;br /&gt;
Modifiez le fichier afin que le main.inc.php soit trouvé&lt;br /&gt;
&amp;lt;source lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
// Load Dolibarr environment&lt;br /&gt;
$res=0;&lt;br /&gt;
// Try main.inc.php into web root known defined into CONTEXT_DOCUMENT_ROOT (not always defined)&lt;br /&gt;
if (! $res &amp;amp;&amp;amp; ! empty($_SERVER[&amp;quot;CONTEXT_DOCUMENT_ROOT&amp;quot;])) $res=@include($_SERVER[&amp;quot;CONTEXT_DOCUMENT_ROOT&amp;quot;].&amp;quot;/main.inc.php&amp;quot;);&lt;br /&gt;
// Try main.inc.php into web root detected using web root calculated from SCRIPT_FILENAME&lt;br /&gt;
$tmp=empty($_SERVER[&#039;SCRIPT_FILENAME&#039;])?&#039;&#039;:$_SERVER[&#039;SCRIPT_FILENAME&#039;];$tmp2=realpath(__FILE__); $i=strlen($tmp)-1; $j=strlen($tmp2)-1;&lt;br /&gt;
while($i &amp;gt; 0 &amp;amp;&amp;amp; $j &amp;gt; 0 &amp;amp;&amp;amp; isset($tmp[$i]) &amp;amp;&amp;amp; isset($tmp2[$j]) &amp;amp;&amp;amp; $tmp[$i]==$tmp2[$j]) { $i--; $j--; }&lt;br /&gt;
if (! $res &amp;amp;&amp;amp; $i &amp;gt; 0 &amp;amp;&amp;amp; file_exists(substr($tmp, 0, ($i+1)).&amp;quot;/main.inc.php&amp;quot;)) $res=@include(substr($tmp, 0, ($i+1)).&amp;quot;/main.inc.php&amp;quot;);&lt;br /&gt;
if (! $res &amp;amp;&amp;amp; $i &amp;gt; 0 &amp;amp;&amp;amp; file_exists(dirname(substr($tmp, 0, ($i+1))).&amp;quot;/main.inc.php&amp;quot;)) $res=@include(dirname(substr($tmp, 0, ($i+1))).&amp;quot;/main.inc.php&amp;quot;);&lt;br /&gt;
// Try main.inc.php using relative path&lt;br /&gt;
if (! $res &amp;amp;&amp;amp; file_exists(&amp;quot;../main.inc.php&amp;quot;)) $res=@include(&amp;quot;../main.inc.php&amp;quot;);&lt;br /&gt;
if (! $res &amp;amp;&amp;amp; file_exists(&amp;quot;../../main.inc.php&amp;quot;)) $res=@include(&amp;quot;../../main.inc.php&amp;quot;);&lt;br /&gt;
if (! $res &amp;amp;&amp;amp; file_exists(&amp;quot;../../../main.inc.php&amp;quot;)) $res=@include(&amp;quot;../../../main.inc.php&amp;quot;);&lt;br /&gt;
if (! $res) die(&amp;quot;Include of main fails&amp;quot;);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Comme vous pouvez le constater, plusieurs tentatives de chargement du fichier main.inc.php (ou master.inc.php) ont été tentées. Le but est de réussir dans le plus grand nombre de cas possibles. Le minimum est de 2 lignes: une pour essayer de charger le fichier master / main.inc.php dans le répertoire racine de dolibarr et une autre pour essayer de charger le fichier afin de prendre en charge le cas où le module est déployé dans le répertoire &amp;quot;custom&amp;quot;. Mais vous pouvez avoir à gérer plus de situations. L&#039;exemple fourni devrait pouvoir charger le fichier main / master.inc.php dans presque toutes les situations / configurations.&lt;br /&gt;
&lt;br /&gt;
Notez que vous pouvez ajouter plus &amp;quot;../&amp;quot; en fonction de la profondeur du fichier par rapport à l&#039;arborescence de votre module.&lt;br /&gt;
&lt;br /&gt;
C&#039;est dans le main qu&#039;est chargé l&#039;environnement technique ainsi que les habilitations. Les variables objets suivantes sont alors positionnées:&lt;br /&gt;
&lt;br /&gt;
*$user    L&#039;objet qui contient les caractéristiques de l&#039;utilisateur + ses droits.&lt;br /&gt;
*$conf    L&#039;objet qui contient la configuration de Dolibarr.&lt;br /&gt;
*$db      L&#039;objet qui contient le handler de connexion à la base de données.&lt;br /&gt;
*$langs   L&#039;objet qui contient la langue de l&#039;utilisateur.&lt;br /&gt;
&lt;br /&gt;
*L&#039;inclusion d&#039;une classe ou librairie dédiée au module, sans savoir d&#039;où le fichier sera appelé, se fait en utilisant une fonction de Dolibarr (et non en utilisant directement le include_once)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Exemple :&#039;&#039;&lt;br /&gt;
&amp;lt;source lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
dol_include_once(&#039;/monmodule/class/maclasse.class.php&#039;, &#039;MaClasse&#039;);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
*L&#039;appel des classes fournies en standard avec Dolibarr se fera par contre par le require_once directe avec la syntaxe suivante:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Exemple :&#039;&#039;&lt;br /&gt;
&amp;lt;source lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
require_once DOL_DOCUMENT_ROOT.&#039;/core/class/doli.class.php&#039;;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
La raison est que si le dol_include_once est pratique car il scanne chaque répertoire de chemin alternatif pour trouver le fichier, il est aussi moins performant car génère des accès et recherches disque à chaque appel (en effet, PHP intègre un cache des fichiers lus mais n&#039;intègre pas un cache des fichiers &amp;quot;non trouvés&amp;quot;. Et comme un fichier donné n&#039;est que dans une seule arborescence, il y a toujours une arborescence alternative où il ne se trouve pas et qui génère des accès superflus au disque dur, pénalisant en terme de performance. Comme pour les fichiers internes à Dolibarr, on connait toujours le chemin exacte, le require_once avec ce chemin direct doit être préféré).&lt;br /&gt;
&lt;br /&gt;
===Accès à la base===&lt;br /&gt;
Si vous avez besoin de réaliser des modifications en base dans votre propre table ajoutée, utilisez la classe générée plus haut qui contient les méthodes pour cela.&lt;br /&gt;
&lt;br /&gt;
Si toutefois vous voulez faire des accès dans des tables sans objet PHP dédié, ceci reste possible (par exemple pour récupérer une liste d&#039;enregistrement). Dans ce cas, pensez à suivre ces exemples:&lt;br /&gt;
&lt;br /&gt;
Pour un insert, update ou delete :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
$db-&amp;gt;begin();   // Debut transaction&lt;br /&gt;
$db-&amp;gt;query(&amp;quot;Ma requete insert, update ou delete&amp;quot;);&lt;br /&gt;
$db-&amp;gt;commit();       // Valide&lt;br /&gt;
ou $db-&amp;gt;rollback()  // Annule&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Pour une lecture :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
$resql=$db-&amp;gt;query(&amp;quot;Ma requete select&amp;quot;);&lt;br /&gt;
if ($resql)&lt;br /&gt;
{&lt;br /&gt;
	$num = $db-&amp;gt;num_rows($resql);&lt;br /&gt;
	$i = 0;&lt;br /&gt;
	if ($num)&lt;br /&gt;
	{&lt;br /&gt;
		while ($i &amp;lt; $num)&lt;br /&gt;
		{&lt;br /&gt;
			$obj = $db-&amp;gt;fetch_object($resql);&lt;br /&gt;
			if ($obj)&lt;br /&gt;
			{&lt;br /&gt;
				// You can use here results&lt;br /&gt;
				print $obj-&amp;gt;field1;&lt;br /&gt;
				print $obj-&amp;gt;field2;&lt;br /&gt;
			}&lt;br /&gt;
			$i++;&lt;br /&gt;
		}&lt;br /&gt;
	}&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Définition du style===&lt;br /&gt;
Pour que le look de la page soit aligné avec le thème Dolibarr, il est nécessaire d&#039;utiliser les styles des CSS de Dolibarr.&lt;br /&gt;
&lt;br /&gt;
Par exemple :&lt;br /&gt;
&lt;br /&gt;
*class=&amp;quot;&#039;&#039;&#039;liste_titre&#039;&#039;&#039;&amp;quot; sur les balises &#039;&#039;tr&#039;&#039; et &#039;&#039;td&#039;&#039; pour une ligne de titre de tableau.&lt;br /&gt;
*class=&amp;quot;&#039;&#039;&#039;pair&#039;&#039;&#039;&amp;quot; ou class=&amp;quot;&#039;&#039;&#039;impair&#039;&#039;&#039;&amp;quot; sur les balises &#039;&#039;tr&#039;&#039; et &#039;&#039;td&#039;&#039; des lignes de données de tableau.&lt;br /&gt;
*class=&amp;quot;&#039;&#039;&#039;flat&#039;&#039;&#039;&amp;quot; sur tous les champs de saisie (&#039;&#039;input, select, textarea&#039;&#039;...).&lt;br /&gt;
*class=&amp;quot;&#039;&#039;&#039;button&#039;&#039;&#039;&amp;quot; sur les objets de type &#039;&#039;input type=&amp;quot;submit&amp;quot;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Utilisez le sélecteur de date de Dolibarr===&lt;br /&gt;
Si vous le désirez, vous pouvez profiter du sélecteur de date dans des écrans Dolibarr. Pour cela, utilisez la ligne suivante:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
$form=new Form($db);&lt;br /&gt;
$form-&amp;gt;select_date(&#039;&#039;,&#039;mykey&#039;,0,0,0,&amp;quot;myform&amp;quot;);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
La chaîne mykey identifie la zone date. Il faut y mettre une valeur différente s&#039;il y a plusieurs zones.&lt;br /&gt;
La chaine myform est le nom de la zone FORM (dans form name=&amp;quot;myform&amp;quot; de la page HTML).&lt;br /&gt;
L&#039;affichage d&#039;un sélecteur de date doit donc être intégré dans une zone FORM Html.&lt;br /&gt;
&lt;br /&gt;
Pour récupérer la valeur, à l&#039;issu du POST, la commande est:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
$mydate = dol_mktime(12, 0 , 0, GETPOST(&#039;mykeymonth&#039;, &#039;int&#039;), GETPOST(&#039;mykeyday&#039;, &#039;int&#039;), GETPOST(&#039;mykeyyear&#039;, &#039;int&#039;));&lt;br /&gt;
print strftime(&#039;%A %d %B %Y&#039;, $mydate);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Définir votre page de configuration (optionnel)==&lt;br /&gt;
&#039;&#039;&#039;Quand&#039;&#039;&#039; : si votre module offre plusieurs options paramétrables.&lt;br /&gt;
&lt;br /&gt;
===Créez votre page d&#039;édition de configuration===&lt;br /&gt;
Si votre module offre plusieurs options paramétrables, il est nécessaire de créer une page PHP pour éditer les options (qui sont stockées dans la [[Table llx_const|table &#039;&#039;&#039;llx_const&#039;&#039;&#039;]]).&lt;br /&gt;
Créez une page PHP nommée &#039;&#039;&#039;monmodule_setupapage.php&#039;&#039;&#039; qui affiche les options possibles et les met à jour.&lt;br /&gt;
Il est nécessaire de prendre exemple sur une page dans &#039;&#039;&#039;/admin&#039;&#039;&#039; qui vous montre la méthode pour lire ou sauvegarder en base votre option.&lt;br /&gt;
Placez cette page de configuration dans le répertoire &#039;&#039;&#039;/admin&#039;&#039;&#039; également.&lt;br /&gt;
Ensuite dans le descripteur de module, modifiez la variable pour indiquer le nom de cette page PHP (sans le chemin qui n&#039;est pas nécessaire, la page étant forcément dans le rep admin).&lt;br /&gt;
&amp;lt;source lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
$this-&amp;gt;config_page_url = array(&amp;quot;setup.php@mymodule&amp;quot;);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Testez votre page===&lt;br /&gt;
Allez sur la page &#039;&#039;&#039;Configuration-&amp;gt;module&#039;&#039;&#039;, vous devez voir apparaître une icône qui permet d&#039;accéder à la page de configuration et vous devez être capable de modifier ces options et les voir conservées en base.&lt;br /&gt;
&lt;br /&gt;
==Définir vos entrées de menu (optionnel)==&lt;br /&gt;
&#039;&#039;&#039;Quand&#039;&#039;&#039; : si vous avez créé des pages PHP, il est nécessaire que ces écrans soient accessibles depuis le menu Dolibarr.&lt;br /&gt;
&lt;br /&gt;
===Définissez vos entrées menus===&lt;br /&gt;
Pour cela, il vous faut définir dans le fichier descripteur de module, le tableau this-&amp;gt;menu qui déclare les menus.&lt;br /&gt;
Ce tableau contient toutes les entrées qui apparaîtront dans les menus une fois le module activé.&lt;br /&gt;
Le fichier de descripteur de module exemple &#039;&#039;&#039;modMonModule.class.php&#039;&#039;&#039; possède un exemple de déclaration de menu haut ainsi que de ses entrées menu gauche associées.&lt;br /&gt;
&lt;br /&gt;
Voici un exemple de déclaration d&#039;entrées de menu dans le fichier descripteur:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
// Main menu entries&lt;br /&gt;
$this-&amp;gt;menu = array();			// List of menus to add&lt;br /&gt;
$r=0;&lt;br /&gt;
&lt;br /&gt;
// Add here entries to declare new menus&lt;br /&gt;
// Example to declare the Top Menu entry:&lt;br /&gt;
$this-&amp;gt;menu[$r]=array(	&#039;fk_menu&#039;=&amp;gt;0,			// Put 0 if this is a top menu&lt;br /&gt;
			&#039;type&#039;=&amp;gt;&#039;top&#039;,			// This is a Top menu entry&lt;br /&gt;
			&#039;titre&#039;=&amp;gt;&#039;MonModule top menu&#039;,&lt;br /&gt;
			&#039;mainmenu&#039;=&amp;gt;&#039;monmodule&#039;,&lt;br /&gt;
			&#039;leftmenu&#039;=&amp;gt;&#039;monmodule&#039;,&lt;br /&gt;
			&#039;url&#039;=&amp;gt;&#039;/monmodule/pagetop.php&#039;,&lt;br /&gt;
			&#039;langs&#039;=&amp;gt;&#039;mylangfile&#039;,	// Lang file to use (without .lang) by module. File must be in langs/code_CODE/ directory.&lt;br /&gt;
			&#039;position&#039;=&amp;gt;100,&lt;br /&gt;
			&#039;enabled&#039;=&amp;gt;&#039;1&#039;,			// Define condition to show or hide menu entry. Use &#039;$conf-&amp;gt;monmodule-&amp;gt;enabled&#039; if entry must be visible if module is enabled.&lt;br /&gt;
			&#039;perms&#039;=&amp;gt;&#039;1&#039;,			// Use &#039;perms&#039;=&amp;gt;&#039;$user-&amp;gt;rights-&amp;gt;monmodule-&amp;gt;level1-&amp;gt;level2&#039; if you want your menu with a permission rules&lt;br /&gt;
			&#039;target&#039;=&amp;gt;&#039;&#039;,&lt;br /&gt;
			&#039;user&#039;=&amp;gt;2);				// 0=Menu for internal users, 1=external users, 2=both&lt;br /&gt;
$r++;&lt;br /&gt;
&lt;br /&gt;
// Example to declare a Left Menu entry:&lt;br /&gt;
$this-&amp;gt;menu[$r]=array(	&#039;fk_menu&#039;=&amp;gt;&#039;fk_mainmenu=xxx&#039;,	// Use &#039;fk_mainmenu=xxx&#039; or &#039;fk_mainmenu=xxx,fk_leftmenu=yyy&#039; where xxx is mainmenucode and yyy is a leftmenucode of parent menu&lt;br /&gt;
			&#039;type&#039;=&amp;gt;&#039;left&#039;,			// This is a Left menu entry&lt;br /&gt;
			&#039;titre&#039;=&amp;gt;&#039;MonModule left menu 1&#039;,&lt;br /&gt;
			&#039;mainmenu&#039;=&amp;gt;&#039;xxx&#039;,&lt;br /&gt;
                        &#039;leftmenu&#039;=&amp;gt;&#039;yyy&#039;,&lt;br /&gt;
			&#039;url&#039;=&amp;gt;&#039;/monmodule/pagelevel1.php&#039;,&lt;br /&gt;
			&#039;langs&#039;=&amp;gt;&#039;mylangfile&#039;,	// Lang file to use (without .lang) by module. File must be in langs/code_CODE/ directory.&lt;br /&gt;
			&#039;position&#039;=&amp;gt;100,&lt;br /&gt;
			&#039;enabled&#039;=&amp;gt;&#039;1&#039;,			// Define condition to show or hide menu entry. Use &#039;$conf-&amp;gt;monmodule-&amp;gt;enabled&#039; if entry must be visible if module is enabled.&lt;br /&gt;
			&#039;perms&#039;=&amp;gt;&#039;1&#039;,			// Use &#039;perms&#039;=&amp;gt;&#039;$user-&amp;gt;rights-&amp;gt;monmodule-&amp;gt;level1-&amp;gt;level2&#039; if you want your menu with a permission rules&lt;br /&gt;
			&#039;target&#039;=&amp;gt;&#039;&#039;,&lt;br /&gt;
			&#039;user&#039;=&amp;gt;2);				// 0=Menu for internal users,1=external users, 2=both&lt;br /&gt;
$r++;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Pour conditionner l&#039;accès au menu selon des permission, modifier la propriété &#039;&#039;&#039;perms&#039;&#039;&#039; du tableau. Voir le chapitre sur les permissions un peu plus loin pour savoir comment ajouter des permissions.&lt;br /&gt;
&lt;br /&gt;
===Testez vos entrées menus===&lt;br /&gt;
Désactiver et réactiver votre module sous Dolibarr, les entrées menus doivent alors apparaître (si la condition dans &#039;enabled&#039; est vraie).&lt;br /&gt;
&lt;br /&gt;
==Définir vos propres permissions (optionnel)==&lt;br /&gt;
&#039;&#039;&#039;Quand&#039;&#039;&#039; : Si vous voulez ajouter de nouvelles permissions.&lt;br /&gt;
&lt;br /&gt;
La définition des permissions que gérera votre module se fait dans le fichier descripteur créé dans la première étape.&lt;br /&gt;
Modifier la ligne &lt;br /&gt;
&amp;lt;source lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
$this-&amp;gt;rights_class = &#039;monmodule&#039;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
pour y mettre la bonne valeur de monmodule.&lt;br /&gt;
&lt;br /&gt;
Ensuite remplissez le tableau $this-&amp;gt;rights avec autant d&#039;entrées que de permissions différentes à gérer.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
$this-&amp;gt;rights[$r][0] = 10001;&lt;br /&gt;
$this-&amp;gt;rights[$r][1] = &#039;Libelle par défaut de ma permission&#039;;&lt;br /&gt;
$this-&amp;gt;rights[$r][3] = 1;&lt;br /&gt;
$this-&amp;gt;rights[$r][4] = &#039;action&#039;;&lt;br /&gt;
$this-&amp;gt;rights[$r][5] = &#039;sousaction&#039;;&lt;br /&gt;
$r++;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Dans $this-&amp;gt;rights[$r][0], mettre un id de permission non déjà pris (Voir dans le menu &#039;&#039;&#039;Infos Système&#039;&#039;&#039; sur une installation de Dolibarr opérationnelle pour connaître les id déjà utilisés.&lt;br /&gt;
Dans $this-&amp;gt;rights[$r][3], mettre 1 si cette permission est attribué d&#039;office par défaut quand un utilisateur est créé.&lt;br /&gt;
Dans $this-&amp;gt;rights[$r][1], mettre un libellé par défaut (il sera affiché si aucune traduction n&#039;est trouvé pour votre permission dans le fichier &#039;&#039;&#039;admin.lang&#039;&#039;&#039;. La clé de traduction dit être &amp;quot;Permission10001=Description de ma super permission&#039;&#039;&#039;&amp;quot;&#039;&#039;&#039;).&lt;br /&gt;
Dans $this-&amp;gt;rights[$r][4] et $this-&amp;gt;rights[$r][5], mettre une chaîne action et sous action sans espace. Vous pourrez alors tester dans le code PHP si un utilisateurs a bien les droits par la séquence suivante :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
if ($user-&amp;gt;rights-&amp;gt;monmodule-&amp;gt;action-&amp;gt;sousaction) ...&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Définir vos propres box (optionnel)==&lt;br /&gt;
&#039;&#039;&#039;Quand&#039;&#039;&#039; : si votre module amène avec lui une ou plusieurs Boxes.&lt;br /&gt;
&lt;br /&gt;
===Définissez vos box===&lt;br /&gt;
Pour cela, modifiez les tableaux $this-&amp;gt;boxes du fichier descripteur de module.&lt;br /&gt;
Il suffit d&#039;ajouter 2 lignes par fichier box que vous allez créer dans le répertoire &#039;&#039;&#039;htdocs/monmodule/core/boxes&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Exemple :&#039;&#039;&lt;br /&gt;
&amp;lt;source lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
$this-&amp;gt;boxes[0][&#039;file&#039;]=&#039;mabox0.php@monmodule&#039;&lt;br /&gt;
$this-&amp;gt;boxes[0][&#039;note&#039;]=&#039;Ma box 0&#039;&lt;br /&gt;
 ...&lt;br /&gt;
$this-&amp;gt;boxes[n][&#039;file&#039;]=&#039;maboxn.php@monmodule&#039;&lt;br /&gt;
$this-&amp;gt;boxes[n][&#039;note&#039;]=&#039;Ma box n&#039;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Ensuite créez les fichiers &#039;&#039;&#039;htdocs/monmodule/core/boxes/mabox0.php&#039;&#039;&#039;, &#039;&#039;&#039;htdocs/monmodule/core/boxes/mabox1.php&#039;&#039;&#039;... en prenant exemple sur des box existantes (exemple dans le répertoire &#039;&#039;&#039;htdocs/core/boxes&#039;&#039;&#039;)&lt;br /&gt;
&lt;br /&gt;
===Testez la présence de vos box dans Dolibarr===&lt;br /&gt;
Désactivez et réactivez le module.&lt;br /&gt;
&lt;br /&gt;
Allez dans le menu &#039;&#039;&#039;Accueil - Configuration - Boite&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Vos box doivent apparaître dans la liste des box activables. Activez les puis allez sur la page d&#039;accueil et vérifiez qu&#039;elles s&#039;affichent correctement.&lt;br /&gt;
&lt;br /&gt;
==Définir vos propres exports (optionnel)==&lt;br /&gt;
&#039;&#039;&#039;Quand&#039;&#039;&#039; : si votre module amène avec lui des exports prédéfinis de données (pour ces propres tables ou des tables déjà existantes d&#039;un autre module de Dolibarr).&lt;br /&gt;
&lt;br /&gt;
===Définissez l&#039;export===&lt;br /&gt;
Pour cela, décommentez et modifiez les tableaux $this-&amp;gt;export_xxx du votre fichier descripteur de module.&lt;br /&gt;
&lt;br /&gt;
===Testez votre export===&lt;br /&gt;
Allez dans le menu outils -&amp;gt; export de Dolibarr. Votre export doit apparaitre dans la liste des exports prédéfinis disponibles (si votre module est bien activé).&lt;br /&gt;
Le choisir, vous devez alors voir les champs possibles définis dans le tableau à l&#039;étape précédente.&lt;br /&gt;
Choissez quelques champs et tentez une génération du fichier export.&lt;br /&gt;
&lt;br /&gt;
==Définir vos styles CSS (optionnel)==&lt;br /&gt;
&#039;&#039;&#039;Quand&#039;&#039;&#039; : lorsque dans vos écrans PHP, vous utiliser des classes de styles qui ne sont pas celle des thèmes de Dolibarr (non recommandé).&lt;br /&gt;
&lt;br /&gt;
Cette fonctionnalité est décrite mais pas encore opérationnel en 2.4&lt;br /&gt;
&lt;br /&gt;
===Créez et déclarez votre feuille de style===&lt;br /&gt;
Créez un fichier de style css nommé &#039;&#039;&#039;monmodule.css&#039;&#039;&#039; ou &#039;&#039;&#039;monmodule.css.php&#039;&#039;&#039; et placez le dans le répertoire &#039;&#039;&#039;&#039;&#039;monmodule&#039;&#039;&#039;&#039;&#039; dans &#039;&#039;&#039;htdocs&#039;&#039;&#039;. Il ne peut y avoir qu&#039;un fichier css propre à chaque module.&lt;br /&gt;
Rappelons qu&#039;il vaut mieux utiliser les styles déjà existant de Dolibarr (le fichier css utilisé par Dolibarr étant le fichier &#039;&#039;&#039;themes/nomtheme/&#039;&#039;nomtheme&#039;&#039;.css.php&#039;&#039;&#039;). Ne créez un fichier css propre à votre module que si vous devez absolument gérer des styles non déjà existants.&lt;br /&gt;
Une fois votre feuille de style prête, déclarez la dans votre fichier descripteur de module en modifiant la propriété &#039;&#039;&#039;$this-&amp;gt;module_parts&#039;&#039;&#039;.&lt;br /&gt;
La valeur à renseigner ici doit être le chemin relatif de l&#039;URL de votre fichier css.&lt;br /&gt;
Par exemple&lt;br /&gt;
&amp;lt;source lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
$this-&amp;gt;module_parts = array(&#039;css&#039; =&amp;gt; array(&#039;/monmodule/css/monmodule.css.php&#039;));&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Testez votre feuille de style===&lt;br /&gt;
Désactivez et réactivez votre module.&lt;br /&gt;
&lt;br /&gt;
Appelez la page d&#039;accueil de Dolibarr. Affichez la source de la page HTML.&lt;br /&gt;
&lt;br /&gt;
Vous devriez voir dans l&#039;entête HTML, une ligne déclarant votre feuille de style.&lt;br /&gt;
&lt;br /&gt;
==Définir vos fonctions Javascript (optionnel)==&lt;br /&gt;
&#039;&#039;&#039;Quand&#039;&#039;&#039; : lorsque dans vos écrans PHP, vous utiliser des fonctions javascript non dispo en standard (fichier lib_head.js)&lt;br /&gt;
&lt;br /&gt;
Si dans vos écrans PHP, vous utilisez des fonctions javascript, il est nécessaire de faire en sorte que vos fonctions déclarées dans un fichier javascript &#039;&#039;&#039;htdocs/monmodule/js/monmodule.js&#039;&#039;&#039; soit chargées dans l&#039;entête head html.&lt;br /&gt;
Pour demander à Dolibarr qui gère la génération de la section header d&#039;inclure un de vos fichiers javascript, il est nécessaire de fournir en paramètre de la fonction llxHeader() appelée au début de votre page, d&#039;inclure le paramètre qui contient l&#039;URL vers le js à inclure.&lt;br /&gt;
&lt;br /&gt;
Exemple pour la page /htdocs/monmodule/mapage.php :&lt;br /&gt;
&amp;lt;source lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
require(&#039;../main.inc.php&#039;);&lt;br /&gt;
$morejs=array(&amp;quot;/monmodule/js/monmodule.js&amp;quot;);&lt;br /&gt;
llxHeader(&#039;&#039;,&#039;Titre&#039;,&#039;&#039;,&#039;&#039;,&#039;&#039;,&#039;&#039;,$morejs,&#039;&#039;,0,0); &lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Déclencher du code sur un évènement Dolibarr (optionnel)==&lt;br /&gt;
&#039;&#039;&#039;Quand&#039;&#039;&#039; : lorsque vous voulez que des actions particulières s&#039;exécutent suite au déclenchement d&#039;actions standards de Dolibarr (exemple : je veux mettre à jour une table de mon module quand une facture se crée dans Dolibarr), il vous faut créer un fichier de &#039;&#039;&#039;triggers&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Voir aussi [[Interfaces_Dolibarr_vers_exterieur|Interfaces de Dolibarr vers l&#039;exterieur]]&lt;br /&gt;
et [[Interfaces_Exterieur_vers_Dolibarr|Interfaces exterieures vers Dolibarr]]&lt;br /&gt;
&lt;br /&gt;
==Insérer votre code aux emplacement hooks de Dolibarr (optionnel)==&lt;br /&gt;
&#039;&#039;&#039;Quand&#039;&#039;&#039; : lorsque vous voulez modifier ou ajouter du code autrement que lors d&#039;un événement métier (voir le chapitre précédent pour cela).&lt;br /&gt;
&lt;br /&gt;
Voir la page [[Système de Hooks]].&lt;br /&gt;
&lt;br /&gt;
==Ajouter un module de numérotation (optionnel)==&lt;br /&gt;
&#039;&#039;&#039;Quand&#039;&#039;&#039; : lorsque vous voulez ajouter une règle de numérotation non couverte par les modules par défaut.&lt;br /&gt;
&lt;br /&gt;
Voir la page [[Créer un module de numérotation]].&lt;br /&gt;
&lt;br /&gt;
==Ajouter un nouveau modèle de document (optionnel)==&lt;br /&gt;
&#039;&#039;&#039;Quand&#039;&#039;&#039; : lorsque vous voulez ajouter un nouveau modèle de document.&lt;br /&gt;
&lt;br /&gt;
La documentation au sujet de la génération de documents depuis des modèles est disponible sur la page [[Créer un modèle de document PDF]] ou [[Créer un modèle de document ODT]].&lt;br /&gt;
&lt;br /&gt;
==Ajouter un thème (optionnel)==&lt;br /&gt;
&#039;&#039;&#039;Quand&#039;&#039;&#039;: Lorsque vous voulez une interface aux couleurs personnalisées à votre cas.&lt;br /&gt;
&lt;br /&gt;
Voir la page [[Themes]].&lt;br /&gt;
&lt;br /&gt;
=[[File:Art.png]] Quelques règles de codage et fonctions pour développeurs=&lt;br /&gt;
Les règles de codage à suivre sont définis dans la [[Documentation Développeur|Documentation développeur]], rubrique &amp;quot;Informations Générales - Langage et normes de développement&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
De nombreuses fonctions prédéfinies pour les développeurs sont disponibles et décrites sur la page [[Documentation Développeur|Documentation développeur]] sous la section &amp;quot;Les couches techniques de Dolibarr&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
=[[File:Art.png]] Créer un package pour livrer et installer votre module=&lt;br /&gt;
Cette procédure doit être utilisée pour fabriquer un package afin de le soumettre sur la place de marché http://www.dolistore.com.&lt;br /&gt;
Mais vous pouvez aussi l&#039;utiliser pour distribuer facillement votre module via votre propre réseau de distribution.&lt;br /&gt;
&lt;br /&gt;
*Allez dans le répertoire &#039;&#039;&#039;/build&#039;&#039;&#039; et recopiez le fichier &#039;&#039;&#039;makepack-dolibarrmodules.conf&#039;&#039;&#039; en &#039;&#039;&#039;makepack-monmodule.conf&#039;&#039;&#039;. Attention, ce répertoire peut ne pas être fourni dans les packages de versions stables. Si c&#039;est le cas, il peut être récupéré dans le snapshot disponible en téléchargement sur le site web Dolibarr dans la rubrique Version de développement (prenez dans ce cas tout le répertoire build qui est un répertoire autonome et indépendant de la version).&lt;br /&gt;
&lt;br /&gt;
Saisissez dans ce fichier la liste des noms des nouveaux fichiers que vous avez créé pour votre module (descripteur de module, nouveaux fichiers sql de tables, page php, images, etc...)&lt;br /&gt;
&lt;br /&gt;
*Lancer le script via Perl (besoin de la version Perl 5.0 ou +):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
perl makepack-dolibarrmodule.pl&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Le script vous demande le nom de votre module, sa version majeure et mineure.&lt;br /&gt;
Un fichier &#039;&#039;&#039;monmodule.zip&#039;&#039;&#039; va alors être fabriqué contenant votre module prêt pour être déployé.&lt;br /&gt;
&lt;br /&gt;
*La personne qui reçoit votre module doit alors placer le fichier dans son répertoire racine d&#039;installation de Dolibarr et réaliser la commande :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
tar -xvf monmodule.zip&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
*Si vous désirez que votre module profite à tous, vous pouvez le soumettre (le fichier zip) sur la place de marché des modules complémentaires: {{LinkToPluginDownload}} (vous devez avoir créé un compte auparavant et utiliser le lien &amp;quot;Soumettre un module/produit&amp;quot;).&lt;br /&gt;
**Si votre module a été fabriqué correctement, le fichier sera validé rapidement.&lt;br /&gt;
**Si la qualité est suffisante, que la licence le permet et que la fonctionnalité du module s&#039;avère être d&#039;un intérêt général, le code pourra être ajouté au code source de Dolibarr (sauf si vous ne le désirez pas).&lt;br /&gt;
&lt;br /&gt;
=[[File:Art.png]] Dépôt et validation du module externe sur Dolistore=&lt;br /&gt;
&lt;br /&gt;
Voir [[Module_Dolistore_Validation_Regles|Règles de Validation]]&lt;/div&gt;</summary>
		<author><name>TanguyP</name></author>
	</entry>
	<entry>
		<id>https://wiki.dolibarr.org/index.php?title=D%C3%A9veloppement_module&amp;diff=58522</id>
		<title>Développement module</title>
		<link rel="alternate" type="text/html" href="https://wiki.dolibarr.org/index.php?title=D%C3%A9veloppement_module&amp;diff=58522"/>
		<updated>2023-10-25T13:48:32Z</updated>

		<summary type="html">&lt;p&gt;TanguyP: /*  Création de Module avec le générateur de module */ Décrire plus précisément l&amp;#039;activation du générateur de modules. MàJ basée sur Dolibarr 18.0.2&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;!-- BEGIN interlang links --&amp;gt;&lt;br /&gt;
&amp;lt;!-- Do NOT edit this section&lt;br /&gt;
     Links below are automatically managed by PolyglotBot&lt;br /&gt;
     You can edit links on the English source page : Module_development --&amp;gt;&lt;br /&gt;
[[en:Module_development]]&lt;br /&gt;
[[es:Desarrollo_de_un_módulo]]&lt;br /&gt;
[[de:Modul_Entwicklung]]&lt;br /&gt;
[[zh:模块开发]]&lt;br /&gt;
[[ja:モジュール_開発]]&lt;br /&gt;
&amp;lt;!-- END interlang links --&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Category:Noyau]]&lt;br /&gt;
{{TemplateDocDev}}&lt;br /&gt;
Pour créer un nouveau module, il existe plusieurs étapes. Ce didacticiel a pour but de vous décrire chacune d&#039;elles afin d&#039;ajouter un module permettant d&#039;étendre les possibilités de Dolibarr, comme par exemple ajouter une ou plusieurs des fonctionnalités suivantes:&lt;br /&gt;
&lt;br /&gt;
*Ajouter de nouvelles tables en base.&lt;br /&gt;
*Ajouter vos propres entrées dans les menus.&lt;br /&gt;
*Ajouter des objets et des écrans de saisie/consultation de nouvelle tables.&lt;br /&gt;
*Ajouter ou supprimer des onglets sur les pages de vues/édition des objets (facture, produit, commande, événement, ...)&lt;br /&gt;
*Ajouter des exports prédéfinis pour la fonction export.&lt;br /&gt;
*Ajouter de nouvelles boites/widgets pour la home page.&lt;br /&gt;
*Ajouter des variables de substitution.&lt;br /&gt;
*Définir de nouvelles permissions.&lt;br /&gt;
*Déclencher du code automatiquement sur une action Dolibarr particulière.&lt;br /&gt;
*Insérer votre code aux emplacements hooks de Dolibarr&lt;br /&gt;
*Ajouter un modèle de numérotation de la référence des objets créés.&lt;br /&gt;
*Ajouter un modèle de document PDF.&lt;br /&gt;
*Ajouter un nouveau thème.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Les chapitres suivants vous présentent comment réaliser tout cela en manuel de manière simple.&lt;br /&gt;
&lt;br /&gt;
=[[File:Art.png]] Création de Module avec le générateur de module=&lt;br /&gt;
Depuis Dolibarr 9.0 il est possible de créer les fichiers principaux de votre module avec le &amp;quot;Générateur de module&amp;quot; (aussi appelé &amp;quot;Module Builder&amp;quot;). Pour l&#039;activer :&lt;br /&gt;
&lt;br /&gt;
*Activez le module &amp;quot;Générateur de Module&amp;quot; (ou &amp;quot;Module builder&amp;quot;) dans la section &amp;quot;Outils multi-modules&amp;quot; de Configuration &amp;gt; Modules/Applications&lt;br /&gt;
&lt;br /&gt;
[[File:Mod_builder_2.png|400px]]&lt;br /&gt;
&lt;br /&gt;
*Puis cliquez sur l’icône &amp;quot;bug&amp;quot; qui est apparue dans la barre de menu en haut à droite&lt;br /&gt;
&lt;br /&gt;
[[File:Mod_builder_3.png|400px]]&lt;br /&gt;
&lt;br /&gt;
=[[File:Art.png]] Exemple de modèle de module externe=&lt;br /&gt;
Un bon modèle/squelette de module externe Dolibarr est disponible ici : [https://github.com/Dolibarr/dolibarr/tree/develop/htdocs/modulebuilder/template GitHub Dolibarr Module Modèle]&lt;br /&gt;
&lt;br /&gt;
=[[File:Art.png]] Créer un module=&lt;br /&gt;
Les sous chapitres suivant décrivent les actions à faire pour créer un module Dolibarr. Les premiers chapitres sont obligatoires quelle que soit la vocation du module, les suivants dépendront de ce que doit faire le module.&lt;br /&gt;
&lt;br /&gt;
==Créer un descripteur de Module (obligatoire)==&lt;br /&gt;
&#039;&#039;&#039;Quand&#039;&#039;&#039; : Obligatoire dès qu&#039;une extension est développée, quelle que soit sa vocation.&lt;br /&gt;
&#039;&#039;&#039;Depuis Dolibarr 9.0, il est possible de créer le descripteur de votre module avec le &amp;quot;Générateur de module&amp;quot;&#039;&#039;&#039;. Cet outil est encore encours de développement et de maturité mais peut dors et déjà être utilisé.&lt;br /&gt;
&lt;br /&gt;
===Créer votre descripteur avec le générateur de module===&lt;br /&gt;
&lt;br /&gt;
*Lancez le générateur de module en cliquant sur l’icône &amp;quot;bug&amp;quot;&lt;br /&gt;
&lt;br /&gt;
[[File:Mod_builder_3.png|400px]]&lt;br /&gt;
&lt;br /&gt;
*Entrez le nom de votre module sans espaces (le nom de votre module NE DOIT PAS CONTENIR le caractère underscore ou tiret bas : _) et cliquez sur Créer.&lt;br /&gt;
&lt;br /&gt;
[[File:Mod_builder_4.png|400px]]&lt;br /&gt;
&lt;br /&gt;
*Un module avec ses premiers fichiers a été initialisé. Vous pouvez alors modifier les paramètres du descripteur du module :&lt;br /&gt;
&lt;br /&gt;
[[File:Mod_builder_5.png|400px]]&lt;br /&gt;
&lt;br /&gt;
===Alternative : créer votre descripteur manuellement (sans utiliser le générateur de module)===&lt;br /&gt;
La première étape est donc de créer un fichier de description du module (descripteur). Pour cela:&lt;br /&gt;
&lt;br /&gt;
*Créez le répertoire &#039;&#039;&#039;/htdocs/&#039;&#039;monmodule&#039;&#039;/core/modules&#039;&#039;&#039;. Puis, allez dans le répertoire &#039;&#039;&#039;dev/skeletons&#039;&#039;&#039; et recopiez le fichier modMyModule.class.php dans ce répertoire &#039;&#039;&#039;htdocs/&#039;&#039;monmodule&#039;&#039;/core/modules&#039;&#039;&#039;.&lt;br /&gt;
*Renommez le fichier mod&#039;&#039;&#039;MyModule&#039;&#039;&#039;.class.php en modifiant seulement la partie &#039;&#039;&#039;MyModule&#039;&#039;&#039; (le fichier doit commencer par mod)&lt;br /&gt;
&lt;br /&gt;
Ensuite, modifiez le contenu de ce fichier afin de remplacer :&lt;br /&gt;
&lt;br /&gt;
*les &#039;&#039;modMyModule&#039;&#039; en une valeur qui corresponde à la vocation de votre module. Cette valeur doit toujours commencer par &#039;&amp;lt;nowiki/&amp;gt;&#039;&#039;&#039;mod&#039;&#039;&#039;&#039; et ne contenir que des &#039;&#039;&#039;caractères alphabétiques&#039;&#039;&#039;.&lt;br /&gt;
*$this-&amp;gt;numero = &#039;&#039;100000&#039;&#039; par un numéro de module libre. Pour éviter tout conflit, vous pouvez consulter la page suivante pour retrouver les numéros déjà alloués : [[List of modules id|Liste des id de modules]].&lt;br /&gt;
*Modifier éventuellement les autres variables définies dans le constructeurs (Voir le commentaire dans le code du squelette pour leur signification).&lt;br /&gt;
&lt;br /&gt;
Le descripteur de votre module est alors en place.&lt;br /&gt;
&lt;br /&gt;
===Tester votre descripteur===&lt;br /&gt;
&lt;br /&gt;
Lancez Dolibarr et allez sur la page &#039;&#039;&#039;Configuration-&amp;gt;module&#039;&#039;&#039;, vous devez voir apparaître une nouvelle ligne avec votre nouveau module et la possibilité de l&#039;activer ou non (parcourez tous les onglets de chaque catégories de modules jusqu&#039;à le retrouver).&lt;br /&gt;
C&#039;est la valeur de $this-&amp;gt;special qui détermine dans quel onglet se trouve votre module.&lt;br /&gt;
&lt;br /&gt;
===Nom de module===&lt;br /&gt;
&lt;br /&gt;
Le nom de votre module NE DOIT PAS CONTENIR le caractère underscore ou tiret bas : _&lt;br /&gt;
&lt;br /&gt;
==Arborescence d&#039;un nouveau module==&lt;br /&gt;
Voici l&#039;arborescence à respecter pour l&#039;organisation des fichiers d&#039;un module (cette arborescence sera celle prise d&#039;office si vous générer les fichiers à l&#039;aide de ModuleBuilder).&lt;br /&gt;
&lt;br /&gt;
{{TemplateModuleTreeSimple}}&lt;br /&gt;
&lt;br /&gt;
Un bon modèle/squelette de module externe Dolibarr est disponible ici : [https://github.com/Dolibarr/dolibarr/tree/develop/htdocs/modulebuilder/template GitHub Dolibarr Module Modèle]&lt;br /&gt;
&lt;br /&gt;
==Créer vos tables SQL et les classes PHP DAO (optionnel)==&lt;br /&gt;
&#039;&#039;&#039;Quand&#039;&#039;&#039;: Si votre module a besoin de gérer des données qui lui sont propres&lt;br /&gt;
&lt;br /&gt;
===Créer vos fichiers .sql===&lt;br /&gt;
Si votre module a vocation à gérer des données bien à lui, qui n&#039;existent pas en base dans la version standard de Dolibarr, il est nécessaire de définir des tables SQL pour stocker ces données.&lt;br /&gt;
&lt;br /&gt;
Créer un sous-répertoire &#039;&#039;&#039;sql&#039;&#039;&#039; dans le répertoire de votre module (&#039;&#039;&#039;monmodule/sql&#039;&#039;&#039;) afin d&#039;y placer les scripts sql que vous allez créer (Avec ModuleBuilder cette étape sera réalisée automatiquement suite à la création d&#039;un nouvel Objet depuis l&#039;onglet Objet).&lt;br /&gt;
&lt;br /&gt;
Ensuite, vérifiez dans votre fichier descripteur de module, dans la fonction &#039;&#039;&#039;init&#039;&#039;&#039; que la ligne&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;php&amp;quot;&amp;gt;$this-&amp;gt;_load_tables(&#039;/mymodule/sql/&#039;);&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
n&#039;est pas commentée.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Règles à respecter:&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
*Ajoutez les fichiers d&#039;ordre de création de vos tables sur le principe de 1 fichier par table, nommé &#039;&#039;&#039;llx_matable.sql&#039;&#039;&#039; (pour la table), accompagné éventuellement du fichier &#039;&#039;&#039;llx_matable.key.sql&#039;&#039;&#039; (pour les index ou clé étrangères). Voir les exemples dans les fichiers existants dans &#039;&#039;&#039;install/mysql/tables&#039;&#039;&#039; pour exemple.&lt;br /&gt;
*Les types et noms recommandés pour les champs SQL sont définis sur la page [[https://wiki.dolibarr.org/index.php/Langages_et_normes#R.C3.A8gles_de_codage_SQL]].&lt;br /&gt;
*Pour ce qui est des commandes permettant d&#039;ajouter/manipuler des données, elles doivent toutes se trouver dans un fichier nommé &#039;&#039;&#039;data.sql&#039;&#039;&#039; situé dans le même répertoire &#039;&#039;&#039;/monmodule/sql/&#039;&#039;&#039;.&lt;br /&gt;
*N&#039;utilisez pas &amp;quot;chaine&amp;quot; mais &#039;chaine&#039; car les guillemets doubles (&amp;quot;) ont une signification particulière en PostGreSQL&lt;br /&gt;
&lt;br /&gt;
Exemple de contenu de fichier data.sql&lt;br /&gt;
&amp;lt;source lang=&amp;quot;sql&amp;quot;&amp;gt;&lt;br /&gt;
 delete from llx_const where name=&#039;MONMODULE_IT_WORKS&#039; and entity=&#039;__ENTITY__&#039;;&lt;br /&gt;
 insert into llx_const (name, value, type, note, visible, entity) values (&#039;MONMODULE_IT_WORKS&#039;,&#039;1&#039;,&#039;chaine&#039;,&#039;A constant for my module&#039;,1,&#039;__ENTITY__&#039;);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Les ordres SQL des fichiers doivent être opérationnels pour la base de données &#039;&#039;&#039;mysql&#039;&#039;&#039;.&lt;br /&gt;
Rem: Les fichiers des autres types de bases ne sont pas à maintenir. Ils sont lus et convertis à la volée par le driver de la base de données.&lt;br /&gt;
&lt;br /&gt;
===Tester vos fichiers .sql===&lt;br /&gt;
&lt;br /&gt;
Une fois les fichiers prêts, vous pouvez retourner dans l&#039;écran de gestion des modules de Dolibarr puis désactiver le module, dropper les tables en base (si elles existe déjà) et réactiver le module.&lt;br /&gt;
Les tables doivent alors être recréées par l&#039;activation du module.&lt;br /&gt;
Si tel n&#039;est pas le cas, vérifiez vos scripts en les passant à la main, ou consultez les logs Dolibarr.&lt;br /&gt;
&lt;br /&gt;
===Générer la classe PHP DAO d&#039;accès aux tables===&lt;br /&gt;
&lt;br /&gt;
Le fichier de classe DAO PHP d&#039;un object est généré automatiquement avec ModuleBuilder lors de la création d&#039;un Object.&lt;br /&gt;
&lt;br /&gt;
A défaut d&#039;utiliser le générateur de module, vous trouverez des exemples dans le squelette de module, fichier &#039;&#039;&#039;htdocs/modulebuilder/templates/class/myobject.class.php&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Dans cette classe, se trouve des méthodes CRUD (Create/Read/Update/Delete) déjà opérationnelles pour faire un insert, un fetch (select), un update, un delete d&#039;une ligne de la table. Editer le fichier pour utiliser le bon nom de module, de tables et placer ce fichier dans le sous-répertoire de &#039;&#039;&#039;class&#039;&#039;&#039; du module. Le Module Builder permet de faire cela en quelques clics de souris.&lt;br /&gt;
&lt;br /&gt;
==Affichage des onglets (optionnel)==&lt;br /&gt;
&lt;br /&gt;
===Ajouter ou supprimer des onglets sur les fiches objets===&lt;br /&gt;
&#039;&#039;&#039;Quand&#039;&#039;&#039; : Pour ajouter votre propre onglet parmi les onglets d&#039;un object standard (facture, commande, proposition commercial, adhérent...)&lt;br /&gt;
&lt;br /&gt;
Pour cela, allez dans le fichier descripteur de module précédemment créé et modifiez le tableau $this-&amp;gt;tabs:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
	// Array to add new pages in new tabs or remove existing one&lt;br /&gt;
	$this-&amp;gt;tabs = array(&#039;objecttype:+tabname1:Title1:mylangfile@monmodule:$user-&amp;gt;rights-&amp;gt;monmodule-&amp;gt;read:/monmodule/mapagetab1.php?id=__ID__&#039;    // To add a new tab identified by code tabname1&lt;br /&gt;
                            &#039;objecttype:+tabname2:Title2:mylangfile@monmodule:$user-&amp;gt;rights-&amp;gt;monmodule-&amp;gt;read:/monmodule/mapagetab2.php?id=__ID__&#039;,   // To add a new tab identified by code tabname2&lt;br /&gt;
                            &#039;objecttype:-tabname&#039;);                                                     // To remove an existing tab identified by code tabname&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Le tableau doit contenir une liste de chaîne, chaque chaîne représentant un nouvel onglet.&lt;br /&gt;
Le format de la chaîne étant composé de 6 parties séparées par &amp;quot;:&amp;quot;&lt;br /&gt;
&lt;br /&gt;
*Partie 1 : le type d&#039;élément (objecttype) dans lequel doit apparaître l&#039;onglet qui est une valeur parmi celle-ci:&lt;br /&gt;
{{TemplateModuleTabs-fr}}&lt;br /&gt;
&lt;br /&gt;
*Partie 2 : nom de code pour l&#039;onglet à ajouter (commence par +) ou à enlever (commence par -)&lt;br /&gt;
*Partie 3 : le titre de l&#039;onglet. Cela peut être un libellé en dur ou mieux un code traduction présent dans un fichier lang.&lt;br /&gt;
*Partie 4 : le nom du fichier .lang (sans l&#039;extension .lang) qui contient la correspondance entre le code traduction et le libellé à afficher. Si ce com est suivi de @monmodule, Dolibarr cherche le fichier dans le répertoire lang propre au module, c&#039;est à dire htdocs/monmodule/langs/code_CODE/monmodule.lang, sinon Dolibarr cherche le fichier traduction dans htdocs/langs/code_CODE/mylangfile.lang&lt;br /&gt;
*Partie 5 : une condition à tester pour savoir si l&#039;onglet doit être visible ou pas. Mettre &#039;1&#039; pour qu&#039;il soit toujours visible.&lt;br /&gt;
*Partie 6 : l&#039;url de la page à afficher quand on clique sur l&#039;onglet. La chaine __ID__ sera remplacée automatiquement par l&#039;Id de l&#039;entité concernée.&lt;br /&gt;
&lt;br /&gt;
Pour que la déclaration soit effective, il faut désactiver et réactiver le module.&lt;br /&gt;
&lt;br /&gt;
Pour alimenter le contenu de l&#039;onglet avec des données issues de la base, voir le chapitre suivant.&lt;br /&gt;
&lt;br /&gt;
===Ajouter les onglets standard d&#039;un objet sur sa propre page d&#039;onglet===&lt;br /&gt;
&#039;&#039;&#039;Quand&#039;&#039;&#039; : Pour afficher les onglets existant d&#039;un objet standard (produit, tiers, etc.) sur votre nouvelle page onglet.&lt;br /&gt;
&lt;br /&gt;
Il faut appliquer la procédure suivante :&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;1. Inclure les fichiers définissant les fonctions utiles dans vos fichiers&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Pour chaque fiche entité, il y a deux fichiers à inclure avec l&#039;instruction&lt;br /&gt;
&amp;lt;source lang=&amp;quot;php&amp;quot;&amp;gt;require_once($url_fichier) ;&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Voici quelques exemples de fichiers à inclure (DOL_DOCUMENT_ROOT correspond au dossier dolibarr/htdocs/) :&lt;br /&gt;
&lt;br /&gt;
*Entité tiers (thirdparty) :&lt;br /&gt;
**DOL_DOCUMENT_ROOT/societe/class/societe.class.php&lt;br /&gt;
**DOL_DOCUMENT_ROOT/core/lib/company.lib.php&lt;br /&gt;
*Entité produit (product) :&lt;br /&gt;
**DOL_DOCUMENT_ROOT/product/class/product.class.php&lt;br /&gt;
**DOL_DOCUMENT_ROOT/core/lib/product.lib.php&lt;br /&gt;
*Entité facture (invoice) :&lt;br /&gt;
**DOL_DOCUMENT_ROOT/compta/facture/facture.class.php&lt;br /&gt;
**DOL_DOCUMENT_ROOT/core/lib/invoice.lib.php&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;2. Créer et charger l&#039;objet à afficher dans votre onglet&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Créez l&#039;objet de la classe voulue, et récupérez les données de l&#039;objet à partir de la base de données. Pour cela il faut utiliser les fonctions fetch() de la classe correspondante, en passant en paramètre l&#039;identifiant de l&#039;objet que vous récupérez depuis l&#039;url (ex : /mononglet.php?id=1).&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Exemple :&#039;&#039;&lt;br /&gt;
&amp;lt;source lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
$id=GETPOST(&#039;id&#039;,&#039;int&#039;);&lt;br /&gt;
$ref=GETPOST(&#039;ref&#039;,&#039;alpha&#039;);&lt;br /&gt;
$product = new Product($db) ;&lt;br /&gt;
$result = $product-&amp;gt;fetch($id, $ref) ; //Tester $result pour vérifier que l&#039;accès à la base s&#039;est bien passée&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;3. Récupérer la liste des onglets correspondants à l&#039;entité choisie&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Utilisez la fonction XXX_prepare_head($obj), ou XXX est le nom de l&#039;entité, permettant de créer un tableau contenant les définitions des onglets à afficher. Le paramètre à passer est l&#039;objet pour lequel vous voulez afficher les onglets.&lt;br /&gt;
&lt;br /&gt;
Le tableau retourné est composé de la façon suivante :&lt;br /&gt;
&amp;lt;source lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
$head        // Tableau des onglets&lt;br /&gt;
$head[$h]    // Élément décrivant un onglet. Il y aura autant de $h que d&#039;onglets à afficher&lt;br /&gt;
$head[$h][0] // Url de la page affichée quand on clique sur l&#039;onglet&lt;br /&gt;
$head[$h][1] // Titre de l’onglet&lt;br /&gt;
$head[$h][2] // Code de l&#039;onglet, à utiliser pour choisir quel onglet sera &#039;actif&#039; (voir paragraphe suivant)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Exemple :&#039;&#039;&lt;br /&gt;
&amp;lt;source lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
$head = product_prepare_head($product, $user) ; //le paramètre $user n&#039;est pas présent sur certaines fonctions&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;4. Afficher les onglets sur votre page onglet&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Utilisez la fonction dol_fiche_head() qui affiche les onglets contenus dans le tableau $head retourné par XX_prepare_head().&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
dol_fiche_head($links, $active=&#039;0&#039;, $title=&#039;&#039;, $notab=0, $picto=&#039;&#039;)&lt;br /&gt;
//$links  // Tableau des onglets, appelé $head plus haut.&lt;br /&gt;
//$active // Onglet actif (mettre le nom de l&#039;onglet défini dans votre fichier de module, ou un nom contenu dans $head[$h][2]). Cet onglet sera mis en surbrillance&lt;br /&gt;
//$title  // ?&lt;br /&gt;
//$notab  // Mettre ce paramètre à 1 permet de ne pas afficher de zone bleue en dessous des onglets.&lt;br /&gt;
//$picto  // Nom de l&#039;image à utiliser au début de la barre des onglet. Les choix suivant sont possibles :&lt;br /&gt;
//            product&lt;br /&gt;
//            service&lt;br /&gt;
//            company&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Cette fonction affiche les onglets voulus et ouvre un élément &#039;&#039;&amp;lt; div class=&amp;quot;&amp;quot; &amp;gt;&#039;&#039; qui correspond à la zone bleue sous les onglets (si paramètre $notab = 0). Pour fermer la zone bleue, il suffit de fermer l&#039;élément &#039;&#039;&amp;lt; /div &amp;gt;&#039;&#039; dans le code PHP.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Remarque&#039;&#039; :&lt;br /&gt;
Pour plus de détail, se référer à la [http://www.dolibarr.fr/doxygen/ documentation Doxygen] ou directement au code de Dolibarr.&lt;br /&gt;
&lt;br /&gt;
==Créer vos pages écran PHP (optionnel)==&lt;br /&gt;
&#039;&#039;&#039;Quand&#039;&#039;&#039; : Si l&#039;objet de votre module est d&#039;ajouter des fonctionnalités qui nécessitent de nouveaux écrans.&lt;br /&gt;
&lt;br /&gt;
===Créer une page écran PHP brute===&lt;br /&gt;
Vous pouvez ensuite créer vos pages PHP, qui se basent sur les données de vos tables, en utilisant les squelettes fournis comme exemple dans le répertoire &#039;&#039;&#039;modulebuilder&#039;&#039;&#039; (Pour le développement d&#039;un script en ligne de commande, voir [[Développement de scripts]]). La encore, si vous avez utilisez ModuleBuilder, des cas de pages (liste, page de création, onglet notes, etc...) auront été créés automatiquement lors de l&#039;initialisation de l&#039;objet.&lt;br /&gt;
&lt;br /&gt;
Pour créer une nouvelle page écran utilisateur, créez un sous-répertoire de &#039;&#039;&#039;htdocs&#039;&#039;&#039; (si non déjà fait) propre à votre module (Dans &#039;&#039;&#039;htdocs/monmodule&#039;&#039;&#039; par exemple) afin d&#039;y placer les pages que vous allez créer.&lt;br /&gt;
&lt;br /&gt;
Y recopier le fichier &#039;&#039;&#039;myobject_page.php&#039;&#039;&#039; qui va servir de point de départ.&lt;br /&gt;
Modifiez le fichier afin que le main.inc.php soit trouvé&lt;br /&gt;
&amp;lt;source lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
// Load Dolibarr environment&lt;br /&gt;
$res=0;&lt;br /&gt;
// Try main.inc.php into web root known defined into CONTEXT_DOCUMENT_ROOT (not always defined)&lt;br /&gt;
if (! $res &amp;amp;&amp;amp; ! empty($_SERVER[&amp;quot;CONTEXT_DOCUMENT_ROOT&amp;quot;])) $res=@include($_SERVER[&amp;quot;CONTEXT_DOCUMENT_ROOT&amp;quot;].&amp;quot;/main.inc.php&amp;quot;);&lt;br /&gt;
// Try main.inc.php into web root detected using web root calculated from SCRIPT_FILENAME&lt;br /&gt;
$tmp=empty($_SERVER[&#039;SCRIPT_FILENAME&#039;])?&#039;&#039;:$_SERVER[&#039;SCRIPT_FILENAME&#039;];$tmp2=realpath(__FILE__); $i=strlen($tmp)-1; $j=strlen($tmp2)-1;&lt;br /&gt;
while($i &amp;gt; 0 &amp;amp;&amp;amp; $j &amp;gt; 0 &amp;amp;&amp;amp; isset($tmp[$i]) &amp;amp;&amp;amp; isset($tmp2[$j]) &amp;amp;&amp;amp; $tmp[$i]==$tmp2[$j]) { $i--; $j--; }&lt;br /&gt;
if (! $res &amp;amp;&amp;amp; $i &amp;gt; 0 &amp;amp;&amp;amp; file_exists(substr($tmp, 0, ($i+1)).&amp;quot;/main.inc.php&amp;quot;)) $res=@include(substr($tmp, 0, ($i+1)).&amp;quot;/main.inc.php&amp;quot;);&lt;br /&gt;
if (! $res &amp;amp;&amp;amp; $i &amp;gt; 0 &amp;amp;&amp;amp; file_exists(dirname(substr($tmp, 0, ($i+1))).&amp;quot;/main.inc.php&amp;quot;)) $res=@include(dirname(substr($tmp, 0, ($i+1))).&amp;quot;/main.inc.php&amp;quot;);&lt;br /&gt;
// Try main.inc.php using relative path&lt;br /&gt;
if (! $res &amp;amp;&amp;amp; file_exists(&amp;quot;../main.inc.php&amp;quot;)) $res=@include(&amp;quot;../main.inc.php&amp;quot;);&lt;br /&gt;
if (! $res &amp;amp;&amp;amp; file_exists(&amp;quot;../../main.inc.php&amp;quot;)) $res=@include(&amp;quot;../../main.inc.php&amp;quot;);&lt;br /&gt;
if (! $res &amp;amp;&amp;amp; file_exists(&amp;quot;../../../main.inc.php&amp;quot;)) $res=@include(&amp;quot;../../../main.inc.php&amp;quot;);&lt;br /&gt;
if (! $res) die(&amp;quot;Include of main fails&amp;quot;);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Comme vous pouvez le constater, plusieurs tentatives de chargement du fichier main.inc.php (ou master.inc.php) ont été tentées. Le but est de réussir dans le plus grand nombre de cas possibles. Le minimum est de 2 lignes: une pour essayer de charger le fichier master / main.inc.php dans le répertoire racine de dolibarr et une autre pour essayer de charger le fichier afin de prendre en charge le cas où le module est déployé dans le répertoire &amp;quot;custom&amp;quot;. Mais vous pouvez avoir à gérer plus de situations. L&#039;exemple fourni devrait pouvoir charger le fichier main / master.inc.php dans presque toutes les situations / configurations.&lt;br /&gt;
&lt;br /&gt;
Notez que vous pouvez ajouter plus &amp;quot;../&amp;quot; en fonction de la profondeur du fichier par rapport à l&#039;arborescence de votre module.&lt;br /&gt;
&lt;br /&gt;
C&#039;est dans le main qu&#039;est chargé l&#039;environnement technique ainsi que les habilitations. Les variables objets suivantes sont alors positionnées:&lt;br /&gt;
&lt;br /&gt;
*$user    L&#039;objet qui contient les caractéristiques de l&#039;utilisateur + ses droits.&lt;br /&gt;
*$conf    L&#039;objet qui contient la configuration de Dolibarr.&lt;br /&gt;
*$db      L&#039;objet qui contient le handler de connexion à la base de données.&lt;br /&gt;
*$langs   L&#039;objet qui contient la langue de l&#039;utilisateur.&lt;br /&gt;
&lt;br /&gt;
*L&#039;inclusion d&#039;une classe ou librairie dédiée au module, sans savoir d&#039;où le fichier sera appelé, se fait en utilisant une fonction de Dolibarr (et non en utilisant directement le include_once)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Exemple :&#039;&#039;&lt;br /&gt;
&amp;lt;source lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
dol_include_once(&#039;/monmodule/class/maclasse.class.php&#039;, &#039;MaClasse&#039;);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
*L&#039;appel des classes fournies en standard avec Dolibarr se fera par contre par le require_once directe avec la syntaxe suivante:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Exemple :&#039;&#039;&lt;br /&gt;
&amp;lt;source lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
require_once DOL_DOCUMENT_ROOT.&#039;/core/class/doli.class.php&#039;;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
La raison est que si le dol_include_once est pratique car il scanne chaque répertoire de chemin alternatif pour trouver le fichier, il est aussi moins performant car génère des accès et recherches disque à chaque appel (en effet, PHP intègre un cache des fichiers lus mais n&#039;intègre pas un cache des fichiers &amp;quot;non trouvés&amp;quot;. Et comme un fichier donné n&#039;est que dans une seule arborescence, il y a toujours une arborescence alternative où il ne se trouve pas et qui génère des accès superflus au disque dur, pénalisant en terme de performance. Comme pour les fichiers internes à Dolibarr, on connait toujours le chemin exacte, le require_once avec ce chemin direct doit être préféré).&lt;br /&gt;
&lt;br /&gt;
===Accès à la base===&lt;br /&gt;
Si vous avez besoin de réaliser des modifications en base dans votre propre table ajoutée, utilisez la classe générée plus haut qui contient les méthodes pour cela.&lt;br /&gt;
&lt;br /&gt;
Si toutefois vous voulez faire des accès dans des tables sans objet PHP dédié, ceci reste possible (par exemple pour récupérer une liste d&#039;enregistrement). Dans ce cas, pensez à suivre ces exemples:&lt;br /&gt;
&lt;br /&gt;
Pour un insert, update ou delete :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
$db-&amp;gt;begin();   // Debut transaction&lt;br /&gt;
$db-&amp;gt;query(&amp;quot;Ma requete insert, update ou delete&amp;quot;);&lt;br /&gt;
$db-&amp;gt;commit();       // Valide&lt;br /&gt;
ou $db-&amp;gt;rollback()  // Annule&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Pour une lecture :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
$resql=$db-&amp;gt;query(&amp;quot;Ma requete select&amp;quot;);&lt;br /&gt;
if ($resql)&lt;br /&gt;
{&lt;br /&gt;
	$num = $db-&amp;gt;num_rows($resql);&lt;br /&gt;
	$i = 0;&lt;br /&gt;
	if ($num)&lt;br /&gt;
	{&lt;br /&gt;
		while ($i &amp;lt; $num)&lt;br /&gt;
		{&lt;br /&gt;
			$obj = $db-&amp;gt;fetch_object($resql);&lt;br /&gt;
			if ($obj)&lt;br /&gt;
			{&lt;br /&gt;
				// You can use here results&lt;br /&gt;
				print $obj-&amp;gt;field1;&lt;br /&gt;
				print $obj-&amp;gt;field2;&lt;br /&gt;
			}&lt;br /&gt;
			$i++;&lt;br /&gt;
		}&lt;br /&gt;
	}&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Définition du style===&lt;br /&gt;
Pour que le look de la page soit aligné avec le thème Dolibarr, il est nécessaire d&#039;utiliser les styles des CSS de Dolibarr.&lt;br /&gt;
&lt;br /&gt;
Par exemple :&lt;br /&gt;
&lt;br /&gt;
*class=&amp;quot;&#039;&#039;&#039;liste_titre&#039;&#039;&#039;&amp;quot; sur les balises &#039;&#039;tr&#039;&#039; et &#039;&#039;td&#039;&#039; pour une ligne de titre de tableau.&lt;br /&gt;
*class=&amp;quot;&#039;&#039;&#039;pair&#039;&#039;&#039;&amp;quot; ou class=&amp;quot;&#039;&#039;&#039;impair&#039;&#039;&#039;&amp;quot; sur les balises &#039;&#039;tr&#039;&#039; et &#039;&#039;td&#039;&#039; des lignes de données de tableau.&lt;br /&gt;
*class=&amp;quot;&#039;&#039;&#039;flat&#039;&#039;&#039;&amp;quot; sur tous les champs de saisie (&#039;&#039;input, select, textarea&#039;&#039;...).&lt;br /&gt;
*class=&amp;quot;&#039;&#039;&#039;button&#039;&#039;&#039;&amp;quot; sur les objets de type &#039;&#039;input type=&amp;quot;submit&amp;quot;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Utilisez le sélecteur de date de Dolibarr===&lt;br /&gt;
Si vous le désirez, vous pouvez profiter du sélecteur de date dans des écrans Dolibarr. Pour cela, utilisez la ligne suivante:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
$form=new Form($db);&lt;br /&gt;
$form-&amp;gt;select_date(&#039;&#039;,&#039;mykey&#039;,0,0,0,&amp;quot;myform&amp;quot;);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
La chaîne mykey identifie la zone date. Il faut y mettre une valeur différente s&#039;il y a plusieurs zones.&lt;br /&gt;
La chaine myform est le nom de la zone FORM (dans form name=&amp;quot;myform&amp;quot; de la page HTML).&lt;br /&gt;
L&#039;affichage d&#039;un sélecteur de date doit donc être intégré dans une zone FORM Html.&lt;br /&gt;
&lt;br /&gt;
Pour récupérer la valeur, à l&#039;issu du POST, la commande est:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
$mydate = dol_mktime(12, 0 , 0, GETPOST(&#039;mykeymonth&#039;, &#039;int&#039;), GETPOST(&#039;mykeyday&#039;, &#039;int&#039;), GETPOST(&#039;mykeyyear&#039;, &#039;int&#039;));&lt;br /&gt;
print strftime(&#039;%A %d %B %Y&#039;, $mydate);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Définir votre page de configuration (optionnel)==&lt;br /&gt;
&#039;&#039;&#039;Quand&#039;&#039;&#039; : si votre module offre plusieurs options paramétrables.&lt;br /&gt;
&lt;br /&gt;
===Créez votre page d&#039;édition de configuration===&lt;br /&gt;
Si votre module offre plusieurs options paramétrables, il est nécessaire de créer une page PHP pour éditer les options (qui sont stockées dans la [[Table llx_const|table &#039;&#039;&#039;llx_const&#039;&#039;&#039;]]).&lt;br /&gt;
Créez une page PHP nommée &#039;&#039;&#039;monmodule_setupapage.php&#039;&#039;&#039; qui affiche les options possibles et les met à jour.&lt;br /&gt;
Il est nécessaire de prendre exemple sur une page dans &#039;&#039;&#039;/admin&#039;&#039;&#039; qui vous montre la méthode pour lire ou sauvegarder en base votre option.&lt;br /&gt;
Placez cette page de configuration dans le répertoire &#039;&#039;&#039;/admin&#039;&#039;&#039; également.&lt;br /&gt;
Ensuite dans le descripteur de module, modifiez la variable pour indiquer le nom de cette page PHP (sans le chemin qui n&#039;est pas nécessaire, la page étant forcément dans le rep admin).&lt;br /&gt;
&amp;lt;source lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
$this-&amp;gt;config_page_url = array(&amp;quot;setup.php@mymodule&amp;quot;);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Testez votre page===&lt;br /&gt;
Allez sur la page &#039;&#039;&#039;Configuration-&amp;gt;module&#039;&#039;&#039;, vous devez voir apparaître une icône qui permet d&#039;accéder à la page de configuration et vous devez être capable de modifier ces options et les voir conservées en base.&lt;br /&gt;
&lt;br /&gt;
==Définir vos entrées de menu (optionnel)==&lt;br /&gt;
&#039;&#039;&#039;Quand&#039;&#039;&#039; : si vous avez créé des pages PHP, il est nécessaire que ces écrans soient accessibles depuis le menu Dolibarr.&lt;br /&gt;
&lt;br /&gt;
===Définissez vos entrées menus===&lt;br /&gt;
Pour cela, il vous faut définir dans le fichier descripteur de module, le tableau this-&amp;gt;menu qui déclare les menus.&lt;br /&gt;
Ce tableau contient toutes les entrées qui apparaîtront dans les menus une fois le module activé.&lt;br /&gt;
Le fichier de descripteur de module exemple &#039;&#039;&#039;modMonModule.class.php&#039;&#039;&#039; possède un exemple de déclaration de menu haut ainsi que de ses entrées menu gauche associées.&lt;br /&gt;
&lt;br /&gt;
Voici un exemple de déclaration d&#039;entrées de menu dans le fichier descripteur:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
// Main menu entries&lt;br /&gt;
$this-&amp;gt;menu = array();			// List of menus to add&lt;br /&gt;
$r=0;&lt;br /&gt;
&lt;br /&gt;
// Add here entries to declare new menus&lt;br /&gt;
// Example to declare the Top Menu entry:&lt;br /&gt;
$this-&amp;gt;menu[$r]=array(	&#039;fk_menu&#039;=&amp;gt;0,			// Put 0 if this is a top menu&lt;br /&gt;
			&#039;type&#039;=&amp;gt;&#039;top&#039;,			// This is a Top menu entry&lt;br /&gt;
			&#039;titre&#039;=&amp;gt;&#039;MonModule top menu&#039;,&lt;br /&gt;
			&#039;mainmenu&#039;=&amp;gt;&#039;monmodule&#039;,&lt;br /&gt;
			&#039;leftmenu&#039;=&amp;gt;&#039;monmodule&#039;,&lt;br /&gt;
			&#039;url&#039;=&amp;gt;&#039;/monmodule/pagetop.php&#039;,&lt;br /&gt;
			&#039;langs&#039;=&amp;gt;&#039;mylangfile&#039;,	// Lang file to use (without .lang) by module. File must be in langs/code_CODE/ directory.&lt;br /&gt;
			&#039;position&#039;=&amp;gt;100,&lt;br /&gt;
			&#039;enabled&#039;=&amp;gt;&#039;1&#039;,			// Define condition to show or hide menu entry. Use &#039;$conf-&amp;gt;monmodule-&amp;gt;enabled&#039; if entry must be visible if module is enabled.&lt;br /&gt;
			&#039;perms&#039;=&amp;gt;&#039;1&#039;,			// Use &#039;perms&#039;=&amp;gt;&#039;$user-&amp;gt;rights-&amp;gt;monmodule-&amp;gt;level1-&amp;gt;level2&#039; if you want your menu with a permission rules&lt;br /&gt;
			&#039;target&#039;=&amp;gt;&#039;&#039;,&lt;br /&gt;
			&#039;user&#039;=&amp;gt;2);				// 0=Menu for internal users, 1=external users, 2=both&lt;br /&gt;
$r++;&lt;br /&gt;
&lt;br /&gt;
// Example to declare a Left Menu entry:&lt;br /&gt;
$this-&amp;gt;menu[$r]=array(	&#039;fk_menu&#039;=&amp;gt;&#039;fk_mainmenu=xxx&#039;,	// Use &#039;fk_mainmenu=xxx&#039; or &#039;fk_mainmenu=xxx,fk_leftmenu=yyy&#039; where xxx is mainmenucode and yyy is a leftmenucode of parent menu&lt;br /&gt;
			&#039;type&#039;=&amp;gt;&#039;left&#039;,			// This is a Left menu entry&lt;br /&gt;
			&#039;titre&#039;=&amp;gt;&#039;MonModule left menu 1&#039;,&lt;br /&gt;
			&#039;mainmenu&#039;=&amp;gt;&#039;xxx&#039;,&lt;br /&gt;
                        &#039;leftmenu&#039;=&amp;gt;&#039;yyy&#039;,&lt;br /&gt;
			&#039;url&#039;=&amp;gt;&#039;/monmodule/pagelevel1.php&#039;,&lt;br /&gt;
			&#039;langs&#039;=&amp;gt;&#039;mylangfile&#039;,	// Lang file to use (without .lang) by module. File must be in langs/code_CODE/ directory.&lt;br /&gt;
			&#039;position&#039;=&amp;gt;100,&lt;br /&gt;
			&#039;enabled&#039;=&amp;gt;&#039;1&#039;,			// Define condition to show or hide menu entry. Use &#039;$conf-&amp;gt;monmodule-&amp;gt;enabled&#039; if entry must be visible if module is enabled.&lt;br /&gt;
			&#039;perms&#039;=&amp;gt;&#039;1&#039;,			// Use &#039;perms&#039;=&amp;gt;&#039;$user-&amp;gt;rights-&amp;gt;monmodule-&amp;gt;level1-&amp;gt;level2&#039; if you want your menu with a permission rules&lt;br /&gt;
			&#039;target&#039;=&amp;gt;&#039;&#039;,&lt;br /&gt;
			&#039;user&#039;=&amp;gt;2);				// 0=Menu for internal users,1=external users, 2=both&lt;br /&gt;
$r++;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Pour conditionner l&#039;accès au menu selon des permission, modifier la propriété &#039;&#039;&#039;perms&#039;&#039;&#039; du tableau. Voir le chapitre sur les permissions un peu plus loin pour savoir comment ajouter des permissions.&lt;br /&gt;
&lt;br /&gt;
===Testez vos entrées menus===&lt;br /&gt;
Désactiver et réactiver votre module sous Dolibarr, les entrées menus doivent alors apparaître (si la condition dans &#039;enabled&#039; est vraie).&lt;br /&gt;
&lt;br /&gt;
==Définir vos propres permissions (optionnel)==&lt;br /&gt;
&#039;&#039;&#039;Quand&#039;&#039;&#039; : Si vous voulez ajouter de nouvelles permissions.&lt;br /&gt;
&lt;br /&gt;
La définition des permissions que gérera votre module se fait dans le fichier descripteur créé dans la première étape.&lt;br /&gt;
Modifier la ligne &lt;br /&gt;
&amp;lt;source lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
$this-&amp;gt;rights_class = &#039;monmodule&#039;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
pour y mettre la bonne valeur de monmodule.&lt;br /&gt;
&lt;br /&gt;
Ensuite remplissez le tableau $this-&amp;gt;rights avec autant d&#039;entrées que de permissions différentes à gérer.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
$this-&amp;gt;rights[$r][0] = 10001;&lt;br /&gt;
$this-&amp;gt;rights[$r][1] = &#039;Libelle par défaut de ma permission&#039;;&lt;br /&gt;
$this-&amp;gt;rights[$r][3] = 1;&lt;br /&gt;
$this-&amp;gt;rights[$r][4] = &#039;action&#039;;&lt;br /&gt;
$this-&amp;gt;rights[$r][5] = &#039;sousaction&#039;;&lt;br /&gt;
$r++;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Dans $this-&amp;gt;rights[$r][0], mettre un id de permission non déjà pris (Voir dans le menu &#039;&#039;&#039;Infos Système&#039;&#039;&#039; sur une installation de Dolibarr opérationnelle pour connaître les id déjà utilisés.&lt;br /&gt;
Dans $this-&amp;gt;rights[$r][3], mettre 1 si cette permission est attribué d&#039;office par défaut quand un utilisateur est créé.&lt;br /&gt;
Dans $this-&amp;gt;rights[$r][1], mettre un libellé par défaut (il sera affiché si aucune traduction n&#039;est trouvé pour votre permission dans le fichier &#039;&#039;&#039;admin.lang&#039;&#039;&#039;. La clé de traduction dit être &amp;quot;Permission10001=Description de ma super permission&#039;&#039;&#039;&amp;quot;&#039;&#039;&#039;).&lt;br /&gt;
Dans $this-&amp;gt;rights[$r][4] et $this-&amp;gt;rights[$r][5], mettre une chaîne action et sous action sans espace. Vous pourrez alors tester dans le code PHP si un utilisateurs a bien les droits par la séquence suivante :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
if ($user-&amp;gt;rights-&amp;gt;monmodule-&amp;gt;action-&amp;gt;sousaction) ...&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Définir vos propres box (optionnel)==&lt;br /&gt;
&#039;&#039;&#039;Quand&#039;&#039;&#039; : si votre module amène avec lui une ou plusieurs Boxes.&lt;br /&gt;
&lt;br /&gt;
===Définissez vos box===&lt;br /&gt;
Pour cela, modifiez les tableaux $this-&amp;gt;boxes du fichier descripteur de module.&lt;br /&gt;
Il suffit d&#039;ajouter 2 lignes par fichier box que vous allez créer dans le répertoire &#039;&#039;&#039;htdocs/monmodule/core/boxes&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Exemple :&#039;&#039;&lt;br /&gt;
&amp;lt;source lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
$this-&amp;gt;boxes[0][&#039;file&#039;]=&#039;mabox0.php@monmodule&#039;&lt;br /&gt;
$this-&amp;gt;boxes[0][&#039;note&#039;]=&#039;Ma box 0&#039;&lt;br /&gt;
 ...&lt;br /&gt;
$this-&amp;gt;boxes[n][&#039;file&#039;]=&#039;maboxn.php@monmodule&#039;&lt;br /&gt;
$this-&amp;gt;boxes[n][&#039;note&#039;]=&#039;Ma box n&#039;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Ensuite créez les fichiers &#039;&#039;&#039;htdocs/monmodule/core/boxes/mabox0.php&#039;&#039;&#039;, &#039;&#039;&#039;htdocs/monmodule/core/boxes/mabox1.php&#039;&#039;&#039;... en prenant exemple sur des box existantes (exemple dans le répertoire &#039;&#039;&#039;htdocs/core/boxes&#039;&#039;&#039;)&lt;br /&gt;
&lt;br /&gt;
===Testez la présence de vos box dans Dolibarr===&lt;br /&gt;
Désactivez et réactivez le module.&lt;br /&gt;
&lt;br /&gt;
Allez dans le menu &#039;&#039;&#039;Accueil - Configuration - Boite&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Vos box doivent apparaître dans la liste des box activables. Activez les puis allez sur la page d&#039;accueil et vérifiez qu&#039;elles s&#039;affichent correctement.&lt;br /&gt;
&lt;br /&gt;
==Définir vos propres exports (optionnel)==&lt;br /&gt;
&#039;&#039;&#039;Quand&#039;&#039;&#039; : si votre module amène avec lui des exports prédéfinis de données (pour ces propres tables ou des tables déjà existantes d&#039;un autre module de Dolibarr).&lt;br /&gt;
&lt;br /&gt;
===Définissez l&#039;export===&lt;br /&gt;
Pour cela, décommentez et modifiez les tableaux $this-&amp;gt;export_xxx du votre fichier descripteur de module.&lt;br /&gt;
&lt;br /&gt;
===Testez votre export===&lt;br /&gt;
Allez dans le menu outils -&amp;gt; export de Dolibarr. Votre export doit apparaitre dans la liste des exports prédéfinis disponibles (si votre module est bien activé).&lt;br /&gt;
Le choisir, vous devez alors voir les champs possibles définis dans le tableau à l&#039;étape précédente.&lt;br /&gt;
Choissez quelques champs et tentez une génération du fichier export.&lt;br /&gt;
&lt;br /&gt;
==Définir vos styles CSS (optionnel)==&lt;br /&gt;
&#039;&#039;&#039;Quand&#039;&#039;&#039; : lorsque dans vos écrans PHP, vous utiliser des classes de styles qui ne sont pas celle des thèmes de Dolibarr (non recommandé).&lt;br /&gt;
&lt;br /&gt;
Cette fonctionnalité est décrite mais pas encore opérationnel en 2.4&lt;br /&gt;
&lt;br /&gt;
===Créez et déclarez votre feuille de style===&lt;br /&gt;
Créez un fichier de style css nommé &#039;&#039;&#039;monmodule.css&#039;&#039;&#039; ou &#039;&#039;&#039;monmodule.css.php&#039;&#039;&#039; et placez le dans le répertoire &#039;&#039;&#039;&#039;&#039;monmodule&#039;&#039;&#039;&#039;&#039; dans &#039;&#039;&#039;htdocs&#039;&#039;&#039;. Il ne peut y avoir qu&#039;un fichier css propre à chaque module.&lt;br /&gt;
Rappelons qu&#039;il vaut mieux utiliser les styles déjà existant de Dolibarr (le fichier css utilisé par Dolibarr étant le fichier &#039;&#039;&#039;themes/nomtheme/&#039;&#039;nomtheme&#039;&#039;.css.php&#039;&#039;&#039;). Ne créez un fichier css propre à votre module que si vous devez absolument gérer des styles non déjà existants.&lt;br /&gt;
Une fois votre feuille de style prête, déclarez la dans votre fichier descripteur de module en modifiant la propriété &#039;&#039;&#039;$this-&amp;gt;module_parts&#039;&#039;&#039;.&lt;br /&gt;
La valeur à renseigner ici doit être le chemin relatif de l&#039;URL de votre fichier css.&lt;br /&gt;
Par exemple&lt;br /&gt;
&amp;lt;source lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
$this-&amp;gt;module_parts = array(&#039;css&#039; =&amp;gt; array(&#039;/monmodule/css/monmodule.css.php&#039;));&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Testez votre feuille de style===&lt;br /&gt;
Désactivez et réactivez votre module.&lt;br /&gt;
&lt;br /&gt;
Appelez la page d&#039;accueil de Dolibarr. Affichez la source de la page HTML.&lt;br /&gt;
&lt;br /&gt;
Vous devriez voir dans l&#039;entête HTML, une ligne déclarant votre feuille de style.&lt;br /&gt;
&lt;br /&gt;
==Définir vos fonctions Javascript (optionnel)==&lt;br /&gt;
&#039;&#039;&#039;Quand&#039;&#039;&#039; : lorsque dans vos écrans PHP, vous utiliser des fonctions javascript non dispo en standard (fichier lib_head.js)&lt;br /&gt;
&lt;br /&gt;
Si dans vos écrans PHP, vous utilisez des fonctions javascript, il est nécessaire de faire en sorte que vos fonctions déclarées dans un fichier javascript &#039;&#039;&#039;htdocs/monmodule/js/monmodule.js&#039;&#039;&#039; soit chargées dans l&#039;entête head html.&lt;br /&gt;
Pour demander à Dolibarr qui gère la génération de la section header d&#039;inclure un de vos fichiers javascript, il est nécessaire de fournir en paramètre de la fonction llxHeader() appelée au début de votre page, d&#039;inclure le paramètre qui contient l&#039;URL vers le js à inclure.&lt;br /&gt;
&lt;br /&gt;
Exemple pour la page /htdocs/monmodule/mapage.php :&lt;br /&gt;
&amp;lt;source lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
require(&#039;../main.inc.php&#039;);&lt;br /&gt;
$morejs=array(&amp;quot;/monmodule/js/monmodule.js&amp;quot;);&lt;br /&gt;
llxHeader(&#039;&#039;,&#039;Titre&#039;,&#039;&#039;,&#039;&#039;,&#039;&#039;,&#039;&#039;,$morejs,&#039;&#039;,0,0); &lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Déclencher du code sur un évènement Dolibarr (optionnel)==&lt;br /&gt;
&#039;&#039;&#039;Quand&#039;&#039;&#039; : lorsque vous voulez que des actions particulières s&#039;exécutent suite au déclenchement d&#039;actions standards de Dolibarr (exemple : je veux mettre à jour une table de mon module quand une facture se crée dans Dolibarr), il vous faut créer un fichier de &#039;&#039;&#039;triggers&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Voir aussi [[Interfaces_Dolibarr_vers_exterieur|Interfaces de Dolibarr vers l&#039;exterieur]]&lt;br /&gt;
et [[Interfaces_Exterieur_vers_Dolibarr|Interfaces exterieures vers Dolibarr]]&lt;br /&gt;
&lt;br /&gt;
==Insérer votre code aux emplacement hooks de Dolibarr (optionnel)==&lt;br /&gt;
&#039;&#039;&#039;Quand&#039;&#039;&#039; : lorsque vous voulez modifier ou ajouter du code autrement que lors d&#039;un événement métier (voir le chapitre précédent pour cela).&lt;br /&gt;
&lt;br /&gt;
Voir la page [[Système de Hooks]].&lt;br /&gt;
&lt;br /&gt;
==Ajouter un module de numérotation (optionnel)==&lt;br /&gt;
&#039;&#039;&#039;Quand&#039;&#039;&#039; : lorsque vous voulez ajouter une règle de numérotation non couverte par les modules par défaut.&lt;br /&gt;
&lt;br /&gt;
Voir la page [[Créer un module de numérotation]].&lt;br /&gt;
&lt;br /&gt;
==Ajouter un nouveau modèle de document (optionnel)==&lt;br /&gt;
&#039;&#039;&#039;Quand&#039;&#039;&#039; : lorsque vous voulez ajouter un nouveau modèle de document.&lt;br /&gt;
&lt;br /&gt;
La documentation au sujet de la génération de documents depuis des modèles est disponible sur la page [[Créer un modèle de document PDF]] ou [[Créer un modèle de document ODT]].&lt;br /&gt;
&lt;br /&gt;
==Ajouter un thème (optionnel)==&lt;br /&gt;
&#039;&#039;&#039;Quand&#039;&#039;&#039;: Lorsque vous voulez une interface aux couleurs personnalisées à votre cas.&lt;br /&gt;
&lt;br /&gt;
Voir la page [[Themes]].&lt;br /&gt;
&lt;br /&gt;
=[[File:Art.png]] Quelques règles de codage et fonctions pour développeurs=&lt;br /&gt;
Les règles de codage à suivre sont définis dans la [[Documentation Développeur|Documentation développeur]], rubrique &amp;quot;Informations Générales - Langage et normes de développement&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
De nombreuses fonctions prédéfinies pour les développeurs sont disponibles et décrites sur la page [[Documentation Développeur|Documentation développeur]] sous la section &amp;quot;Les couches techniques de Dolibarr&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
=[[File:Art.png]] Créer un package pour livrer et installer votre module=&lt;br /&gt;
Cette procédure doit être utilisée pour fabriquer un package afin de le soumettre sur la place de marché http://www.dolistore.com.&lt;br /&gt;
Mais vous pouvez aussi l&#039;utiliser pour distribuer facillement votre module via votre propre réseau de distribution.&lt;br /&gt;
&lt;br /&gt;
*Allez dans le répertoire &#039;&#039;&#039;/build&#039;&#039;&#039; et recopiez le fichier &#039;&#039;&#039;makepack-dolibarrmodules.conf&#039;&#039;&#039; en &#039;&#039;&#039;makepack-monmodule.conf&#039;&#039;&#039;. Attention, ce répertoire peut ne pas être fourni dans les packages de versions stables. Si c&#039;est le cas, il peut être récupéré dans le snapshot disponible en téléchargement sur le site web Dolibarr dans la rubrique Version de développement (prenez dans ce cas tout le répertoire build qui est un répertoire autonome et indépendant de la version).&lt;br /&gt;
&lt;br /&gt;
Saisissez dans ce fichier la liste des noms des nouveaux fichiers que vous avez créé pour votre module (descripteur de module, nouveaux fichiers sql de tables, page php, images, etc...)&lt;br /&gt;
&lt;br /&gt;
*Lancer le script via Perl (besoin de la version Perl 5.0 ou +):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
perl makepack-dolibarrmodule.pl&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Le script vous demande le nom de votre module, sa version majeure et mineure.&lt;br /&gt;
Un fichier &#039;&#039;&#039;monmodule.zip&#039;&#039;&#039; va alors être fabriqué contenant votre module prêt pour être déployé.&lt;br /&gt;
&lt;br /&gt;
*La personne qui reçoit votre module doit alors placer le fichier dans son répertoire racine d&#039;installation de Dolibarr et réaliser la commande :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
tar -xvf monmodule.zip&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
*Si vous désirez que votre module profite à tous, vous pouvez le soumettre (le fichier zip) sur la place de marché des modules complémentaires: {{LinkToPluginDownload}} (vous devez avoir créé un compte auparavant et utiliser le lien &amp;quot;Soumettre un module/produit&amp;quot;).&lt;br /&gt;
**Si votre module a été fabriqué correctement, le fichier sera validé rapidement.&lt;br /&gt;
**Si la qualité est suffisante, que la licence le permet et que la fonctionnalité du module s&#039;avère être d&#039;un intérêt général, le code pourra être ajouté au code source de Dolibarr (sauf si vous ne le désirez pas).&lt;br /&gt;
&lt;br /&gt;
=[[File:Art.png]] Dépôt et validation du module externe sur Dolistore=&lt;br /&gt;
&lt;br /&gt;
Voir [[Module_Dolistore_Validation_Regles|Règles de Validation]]&lt;/div&gt;</summary>
		<author><name>TanguyP</name></author>
	</entry>
	<entry>
		<id>https://wiki.dolibarr.org/index.php?title=List_of_modules_id&amp;diff=58521</id>
		<title>List of modules id</title>
		<link rel="alternate" type="text/html" href="https://wiki.dolibarr.org/index.php?title=List_of_modules_id&amp;diff=58521"/>
		<updated>2023-10-25T13:44:50Z</updated>

		<summary type="html">&lt;p&gt;TanguyP: Add range of 50 module IDs reserved for myself&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{TemplateDocDevEn}}&lt;br /&gt;
{{TemplateDocDevEs}}&lt;br /&gt;
{{TemplateDocDevFr}}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
{{Flag en}}&lt;br /&gt;
This page list all reserved modules numbers / ID. If you build or want to build your own modules (like this [[:Category:Complementary_modules|complementary module]]), you should take an ID range here. Please pick range into existing holes first.&lt;br /&gt;
&lt;br /&gt;
{{Flag fr}}&lt;br /&gt;
Cette page recense tous les numéros / ID réservés de modules. Si vous avez réalisé ou voulez réaliser vos propres modules (comme les [[:Category:Modules complémentaires|modules complémentaires suivant]]), vous devriez prendre une plage d&#039;ID ici. Merci de prendre dans les trous existant en priorité !&lt;br /&gt;
&lt;br /&gt;
{{Flag sp}}&lt;br /&gt;
Esta página contiene un listado de todos los id reservados para los módulos. Si ha creado o quiere realizar sus propios módulos, (como estos [[:Category:Módulos_complementarios|módulos complementarios]]), deberá reservarse un rango de ID aquí.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=ID 0 - 99999=&lt;br /&gt;
{{Flag en}}&lt;br /&gt;
Reserved for Dolibarr&#039;s internal modules.&lt;br /&gt;
&lt;br /&gt;
{{Flag fr}}&lt;br /&gt;
Réservé aux modules internes de Dolibarr.&lt;br /&gt;
&lt;br /&gt;
{{Flag sp}}&lt;br /&gt;
Reservado a los módulos internos de Dolibarr.&lt;br /&gt;
&lt;br /&gt;
=ID 100000 - 499999=&lt;br /&gt;
{{Flag en}} &lt;br /&gt;
&#039;&#039;&#039;Reserved area for editors in need for an ID range. You can edit this page to add your own range (take a range of 50 numbers only the first time, ask us for more)&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{{Flag fr}}Zone réservée aux éditeurs qui ont besoin d&#039;une plage d&#039;ID spécifiques. Vous pouvez modifier cette page pour réserver votre plage (limitée à 50 valeurs la première fois, demandez nous pour plus)&lt;br /&gt;
&lt;br /&gt;
{{Flag sp}}&lt;br /&gt;
Área reservada para los partners que necesiten un rango de ID. Puede modificar esta página para reservar su rango (limitado a 50 valores por editor)&lt;br /&gt;
&lt;br /&gt;
[[File:Warning.png]] If you reserve more than 50, we may automatically change your reservation range without information and you may experience conflicts with other modules in a future, so please follow the rules!&lt;br /&gt;
&lt;br /&gt;
*ID 100000 - 100999: OpenThink (http://www.openthink.be)&lt;br /&gt;
*ID 101000 - 101999: NLTechno (https://www.nltechno.com)&lt;br /&gt;
*ID 102000 - 102999: Tiaris (http://www.tiaris.fr)&lt;br /&gt;
*ID 103000 - 103999: Open-concept.pro (http://www.open-concept.pro)&lt;br /&gt;
*ID 104000 - 104999: ATM Consulting (http://www.atm-consulting.fr)&lt;br /&gt;
*ID 105000 - 105999: GPC.solutions&lt;br /&gt;
*ID 106000 - 106999: PHPASSO&lt;br /&gt;
*ID 107000 - 107999: TecLib (http://www.teclib.com) / Auguria (http://www.auguria.net)&lt;br /&gt;
*ID 108000 - 108999: ETHICWEB&lt;br /&gt;
*ID 109000 - 109999: Aplose ([http://www.aplose.fr https://www.aplose.fr])&lt;br /&gt;
*ID 110000 - 110999: Librethic (https://librethic.io)&lt;br /&gt;
*ID 111000 - 111999: Asset IT (www.assetit.ch)&lt;br /&gt;
*ID 112000 - 112999: Aarboard AG (www.aarboard.ch)&lt;br /&gt;
*ID 113000 - 113999: Asilib - Alexandre Spangaro&lt;br /&gt;
*ID 114000 - 114999: Iceleaf OÜ&lt;br /&gt;
*ID 115000 - 115999: 2A2C Conseil - Cyril ZEKSER&lt;br /&gt;
*ID 116000 - 116999: Wolftec GmbH&lt;br /&gt;
*ID 117000 - 117999: Oscim (http://www.oscim.fr)&lt;br /&gt;
*ID 118000 - 118999: Oarces Web (dev.oarces.com)&lt;br /&gt;
*ID 119000 - 119999: Manuel Berrocal - Absolacom&lt;br /&gt;
*ID 120000 - 120999: Régis Houssin (http://www.inodbox.com)&lt;br /&gt;
*ID 121000 - 121999: Oscss - Shop&lt;br /&gt;
*ID 122000 - 122999: MrSof - la Nation du Web&lt;br /&gt;
*ID 123000 - 123999: Bruno Généré (webiseasy.org)&lt;br /&gt;
*ID 124000 - 124999: backbone internet service (www.backbone.co.at)&lt;br /&gt;
*ID 125000 - 125999: ProgSI (www.progsi.ma)&lt;br /&gt;
*ID 126000 - 126999: Catalanet&lt;br /&gt;
*ID 127000 - 127999: Virgilio Filho pt-BR Brasil (@dolibarr.br)&lt;br /&gt;
*ID 128000 - 128999: Nicolas Frappé France (www.sospc.info)&lt;br /&gt;
*ID 129000 - 129999: Adeo-Informatique&lt;br /&gt;
*ID 130000 - 130999: Technicks ICT (http://www.technicks.eu)&lt;br /&gt;
*ID 131000 - 131999: Joan Louis (itaca.fr)&lt;br /&gt;
*ID 132000 - 132999: Jean-Marie Arsac (https://azimut.fr)&lt;br /&gt;
*ID 133000 - 133999: Oriel Systems Ltd, UK. (www.orielsystems.com)&lt;br /&gt;
*ID 134000 - 134999: ALSOFT PVT. LTD. (https://www.alsoft.org)&lt;br /&gt;
*ID 135000 - 135999: Net-Logic (https://netlogic.fr)&lt;br /&gt;
*ID 136000 - 136050: MONA.RE - France&lt;br /&gt;
*ID 136051 - 136099: La Vida Marketing&lt;br /&gt;
*ID 136100 - 136149: Synergies-Tech France. (https://www.synergies-france.fr/)&lt;br /&gt;
*ID 136150 - 136199: Lyta&lt;br /&gt;
*ID 136200 - 136219: Maison Théophile Leclerc&lt;br /&gt;
*ID 136220 - 139999: &#039;&#039;&#039;Free (take ranges of 50 only please at once, ask us for more)&#039;&#039;&#039;&lt;br /&gt;
*ID 140000 - 140999: Altairis (http://altairis.fr)&lt;br /&gt;
*ID 141000 - 141050: Projet2Team (https://www.projet2team.fr)&lt;br /&gt;
*ID 141051 - 141099: Elistair (http://elistair.com)&lt;br /&gt;
*ID 141100 - 141149: Blue Networks Technologies (https://www.blnt.fr)&lt;br /&gt;
*ID 141150 - 141199: Mainlab S.r.l. (https://www.mainlabonline.it)&lt;br /&gt;
*ID 141150 - 141199: Florian DUFOURG - France&lt;br /&gt;
*ID 142000 - 142049: ITANéA (https://www.itanea.fr)&lt;br /&gt;
*ID 142050 - 142099: ERP Consulting NZ ([https://www.erpconsulting.co.nz www.erpconsulting.co.nz])&lt;br /&gt;
*ID 142100 - 142149: Bloxera GmbH (https://www.bloxera.com)&lt;br /&gt;
*ID 142150 - 142199: Evangelos Souglakos - Greece&lt;br /&gt;
*ID 142200 - 142249: Luc CALARESU - France&lt;br /&gt;
*ID 142250 - 142299: OmnIT Services - Belgique (https://www.omnitservices.biz)&lt;br /&gt;
*ID 142300 - 142349: Gwadeyes - Guadeloupe (https://www.gwadeyes-informatique.com/)&lt;br /&gt;
*ID 142350 - 142399: Solution Libre (https://www.solution-libre.fr/)&lt;br /&gt;
*ID 142400 - 142449: Res Digital (https://res.digital)&lt;br /&gt;
*ID 149000 - 149999: SydTech - America Central (https://www.sydtech.io/)&lt;br /&gt;
*ID 150000 - 150999: Jeffinfo&lt;br /&gt;
*ID 151000 - 151999: Konverseo (https://konverseo.com)&lt;br /&gt;
*ID 152000 - 152049: Tanguy Pénet (http://tanguype.net)&lt;br /&gt;
*ID 160000 - 160999: Charles-François BENKE (http://www.patas-monkey.com)&lt;br /&gt;
*ID 161000 - 161999: Abbes Bahfir (http://dolipar.org)&lt;br /&gt;
*ID 162000 - 162999: Jacques Rébiscoul&lt;br /&gt;
*ID 163000 - 163999: Open-DSI (https://www.open-dsi.fr)&lt;br /&gt;
*ID 164000 - 164999: Pixelada S. Coop. And. (https://pixelada.org)&lt;br /&gt;
*ID 165000 - 165049: DovConnect&lt;br /&gt;
*ID 165050 - 165099: Mind Operated Systems (https://www.mosystems.biz)&lt;br /&gt;
*ID 165100 - 165150: SD-Formation (https://sdformation.fr)&lt;br /&gt;
*ID 165151 - 165199: NUM&#039;X (https://www.numx-sets.eu)&lt;br /&gt;
*ID 165200 - 165249: Benjam Préjent (https://www.benjam-prejent.fr)&lt;br /&gt;
*ID 165250 - 165299: Dhi Loka Private Limited, India (https://www.dhiloka.com)&lt;br /&gt;
*ID 170000 - 170999: TRIDENT CONSULTING LTD (www.tridentdxb.com)&lt;br /&gt;
*ID 171000 - 171999: LVSInformatique (www.lvsinformatique.com)&lt;br /&gt;
*ID 172000 - 172299: Ray Soft-Systems (https://www.ray-soft-systems.com)&lt;br /&gt;
*ID 172300 - 172349: Günter Lukas Consulting (https://gl.co.at)&lt;br /&gt;
*ID 172350 - 172399: MB Informatique (https://www.mb-informatique.fr)&lt;br /&gt;
*ID 172400 - 172449: Professional Structures Limited (https://pstructures.com)&lt;br /&gt;
*ID 172450 - 172699: IT-BS (https://www.it-bs.fr)&lt;br /&gt;
*ID 172700 - 172749: Indelog (https://www.indelog.fr)&lt;br /&gt;
*ID 172750 - 172799: NS-INFO90 (https://www.ns-info90.fr)&lt;br /&gt;
*ID 180000 - 180999: Triangle Ingénierie&lt;br /&gt;
*ID 181000 - 181999: TI Sin Problemas (https://www.tisinproblemas.com)&lt;br /&gt;
*ID 182000 - 182049: Chipserv Pawel Wlizlo (https://www.testware.it)&lt;br /&gt;
*ID 183000 - 183999: BB2A Anthony Berton (https://www.bb2a.fr)&lt;br /&gt;
*ID 184000 - 184999: DPS PRINTING &amp;amp; DOCUMENTS SOCIEDAD ANONIMA (https://www.dps-lat.com)&lt;br /&gt;
*ID 190000 - 190999: Diciannove (http://19.coop)&lt;br /&gt;
*ID 191000 - 191999: Elonet (https://elonet.fr)&lt;br /&gt;
*ID 199000 - 199999: RFMS&lt;br /&gt;
*ID 200000 - 200999: Noxiome&lt;br /&gt;
*ID 201000 - 201999: Sasa Ostrouska (saxa)&lt;br /&gt;
*ID 202000 - 202999: Z-Application&lt;br /&gt;
*ID 203000 - 203099: Elidee - elidee.com&lt;br /&gt;
*ID 203100 - 203999: Garcia MICHEL (soamichel.fr)&lt;br /&gt;
*ID 204000 - 204999: Ari Elbaz elarifr - accedinfo.com&lt;br /&gt;
*ID 205000 - 205999: Kreiz IT&lt;br /&gt;
*ID 206000 - 206999: GBINFO (www.gbinfo.fr)&lt;br /&gt;
*ID 207000 - 207099: MacroProg (https://www.macroprog.com)&lt;br /&gt;
*ID 207100 - 207149: Reactiva Software&lt;br /&gt;
*ID 207150 - 207199: Ndejje University Water Research and Development Centre ([https://github.com/NDUWRDC/LIMS/])&lt;br /&gt;
*ID 207200 - 207299: Massaoud Bouzenad ([https://www.dzprod.net dzprod.net])&lt;br /&gt;
*ID 207300 - 207349: Ksar&lt;br /&gt;
*ID 207350 - 207399: Easylinux (www.easylinux.fr)&lt;br /&gt;
*ID 222000 - 222999:  dolibit  (https://www.dolibit.de)&lt;br /&gt;
*ID 230000 - 230049: Unareil (https://www.unareil.eu)&lt;br /&gt;
*ID 230050 - 230099: Lyra Network (https://www.lyra.com/)&lt;br /&gt;
*ID 230100 - 230149: Gheorghe Iftimi - CTW - RO&lt;br /&gt;
*ID 230150 - 230199: MEMA Machinery &amp;amp; Tools (https://www.mema.be)&lt;br /&gt;
*ID 230200 - 230249: Teleassist&lt;br /&gt;
*ID 230250 - 230299: Nh Developer&lt;br /&gt;
*ID 230300 - 230499: Chickenforce/code-chicken, IT Services Hahn (https://github.com/code-chicken [http://itservices-hahn.de/ https://itservices-hahn.de])&lt;br /&gt;
*ID 230500 - 230549: Hidup Consulting (https://consulting.hidup.io)&lt;br /&gt;
*ID 230550 - 230599 : CMR Conseil (https://www.weblockup.fr)&lt;br /&gt;
*ID 230600 - 230649 : aFreeMind Studio&lt;br /&gt;
*ID 230650 - 230699 : Unideal (https://www.uni-deal.com)&lt;br /&gt;
*ID 230700 - 230749 : DevLansdes (https://devlandes.com/)&lt;br /&gt;
*ID 262700 - 262799: Scopen (https://www.scopen.fr)&lt;br /&gt;
*ID 274250 - 274299: Nerv Project (www.nerv-project.eu)&lt;br /&gt;
*ID 274300 - 274349: Knowhere Consulting S.L. (https://www.knowhere-consulting.eu)&lt;br /&gt;
*ID 274350 - 274399: Milen karaganski (https://blacktiehost.com)&lt;br /&gt;
*ID 274400 - 274449: Vincent MAURY ([https://www.timgroup.fr www.timgroup.fr])&lt;br /&gt;
*ID 274450 - 274499: Daraelmin&lt;br /&gt;
*ID 274500 - 274550: Emilie LAFORET (http://www.ermvallon.com)&lt;br /&gt;
*ID 279000 - 279049: VSDigital Electronics (https://vsdigital.ar) - Argentina&lt;br /&gt;
*ID 280000 - 280050: Bingroup (https://www.beinng.com)&lt;br /&gt;
*ID 280051 - 280100: Medialta (https://medialta.com)&lt;br /&gt;
*ID 290000 - 290099: BNS - Project doliBRA ([https://www.beinng.com https://www.bns.net.br]) - Brasil&lt;br /&gt;
*ID 300000 - 300049: RapidProgress (https://www.rapidprogress.eu) - Bulgaria&lt;br /&gt;
*ID 300050 : 300099: M@ Solution (https://www.ma-solution.fr/)&lt;br /&gt;
*ID 300100 : 300149: LAVA RUN (https://www.lavarun.re)&lt;br /&gt;
*ID 300200 : 300249 : Computences (https://www.computences.com/)&lt;br /&gt;
*ID 300250 : 300299 : LEVEL IT (https://levelit.com.ar)&lt;br /&gt;
*ID 300300 : 300349 : Progiseize (https://progiseize.fr)&lt;br /&gt;
*ID 300350 - 300399: MB Informatique (https://www.mb-informatique.fr)&lt;br /&gt;
*ID 300400 - 300449: Anouar Touati&lt;br /&gt;
*ID 300450 - 300499: Martin Danger&lt;br /&gt;
*ID 300500 - 301499: Whale Blows&lt;br /&gt;
*ID 301500 - 301549: Tom Trust - International&lt;br /&gt;
*ID 302500 - 302549: Diamubi (https://diamubi.com)&lt;br /&gt;
*ID 302550 - 302599: Datolab (https://www.datolab.com)&lt;br /&gt;
*ID 302600 - 302649: DuMaCo (https://www.dumaco.de)&lt;br /&gt;
*ID 302650 - 302699: Resilio SA&lt;br /&gt;
*ID 302700 - 302749: Aroga&lt;br /&gt;
*ID 302750 - 302799: Productivix (https://www.productivix.com)&lt;br /&gt;
*ID 302800 - 302849: Slibzz&lt;br /&gt;
*ID 302850 - 302899: idea design (https://ideadesign.dz)&lt;br /&gt;
*ID 302900 - 302949: AL MISBAH INFORMATIQUE (https://www.almisbah.ma)&lt;br /&gt;
*ID 302950 - 302999: Atis Solutions - France&lt;br /&gt;
*ID 303000 - 303499: Obixav - Nigeria&lt;br /&gt;
*ID 303500 - 303550: buschler plus GmbH, Germany (https://buschler.plus)&lt;br /&gt;
*ID 303551 - 303599: Prestalidaire - France (https://prestalidaire.com)&lt;br /&gt;
*ID 314000 - 314049: Ruemmler IT Solutions (https://www.ruemmler.net)&lt;br /&gt;
*ID 320000 - 320999: Novus Studios (www.novusstudios.it)&lt;br /&gt;
*ID 321000 - 321999: AtooNet (http://www.atoo-net.com)&lt;br /&gt;
*ID 332000 - 332099: Gecka (https://gecka.nc)&lt;br /&gt;
*ID 332100 - 332149: Agence Milkshake (http://agencemilkshake.com)&lt;br /&gt;
*ID 332150 - 332199: Daniel Prowald IT – Service (https://prowald-it.de)&lt;br /&gt;
*ID 332200 - 332249: UNITICE (https://unitice.com)&lt;br /&gt;
*ID 332250 - 332299: Sidonie Moulart&lt;br /&gt;
*ID 332300 - 332349: LTDJ (Antonin MARCHAL - Le Temple du Jeu)&lt;br /&gt;
*ID 330000 - 330049: XTEC Industries (www.xtec-ind.com)&lt;br /&gt;
*ID 330050 - 330099: 10100 S.R.L. - (www.10100.to)&lt;br /&gt;
*ID 330100 - 330149: AES Dana SRL (https://aes-dana.be)&lt;br /&gt;
*ID 330150 - 330199: Freshcore (https://www.freshcore.fr)&lt;br /&gt;
*ID 330200 - 399999: (take ranges of 50 only please, ask us for more)&lt;br /&gt;
*ID 333300 - 333349: Sense Africa (http://sense.africa)&lt;br /&gt;
*ID 350000 - 350049: SOUNDOU &amp;amp; MIDAS (https://www.soundou.org/)&lt;br /&gt;
*ID 400000 - 400999: 2byte.es (http://www.2byte.es)&lt;br /&gt;
*ID 401000 - 401999: B&amp;amp;D Informática&lt;br /&gt;
*ID 402000 - 402999: Marcos García de La Fuente (marcosgdf)&lt;br /&gt;
*ID 403000 - 403999: Sergibyte&lt;br /&gt;
*ID 404000 - 404999: Aikhan&lt;br /&gt;
*ID 405000 - 405999: AIME (http://www.aime.mx)&lt;br /&gt;
*ID 406000 - 406999: Som Núvol (https://somnuvol.coop)&lt;br /&gt;
*ID 409000 - 409999: LliureTIC (https://www.lliuretic.cat)&lt;br /&gt;
*ID 410000 - 410999: DoliGov&lt;br /&gt;
*ID 420000 - 420099: BBS Concept&lt;br /&gt;
*ID 420100 - 420199: LeMousticProduction (www.lemousticproduction.info) -&amp;lt; module DoliRH&lt;br /&gt;
*ID 420200 - 421199: VatCheck (www.abnc.be)&lt;br /&gt;
*ID 422200 - 422999: Artaban (http://artaban.fr)&lt;br /&gt;
*ID 423000 - 423050: cyberesprit&lt;br /&gt;
*ID 423051 - 423099: R.Bossard&lt;br /&gt;
*ID 423100 - 423199: Joliciel (www.joliciel.fr)&lt;br /&gt;
*ID 424000 - 424049: A3sys - Mon-Dolibarr (http://www.mon-dolibarr.fr) by Philazerty&lt;br /&gt;
*ID 424050 - 424099: Pragma-tech (www.pragma-tech.fr)&lt;br /&gt;
*ID 424100 - 424149: Ohoo Solutions (http://www.ohoosolutions.com)&lt;br /&gt;
*ID 424150 - 424199: DAGARCAM Informática (https://www.dagarcam.com/)&lt;br /&gt;
*ID 424200 - 424999: Lab51 (https://github.com/lab51org)&lt;br /&gt;
*ID 425000 - 425999: Sébastien SERRE Thivinfo (www.thivinfo.com)&lt;br /&gt;
*ID 426000 - 426099: Arkesis-Solution&lt;br /&gt;
*ID 426100 - 426149: GetLandy (www.getlandy.com)&lt;br /&gt;
*ID 426150 - 426649: OOB Software&lt;br /&gt;
*ID 426650 - 426849: Soft-Task Serviços e Sistemas (www.soft-task.com.br)&lt;br /&gt;
*ID 426850 - 427000: Bruno Caldas (https://github.com/BCaldas)&lt;br /&gt;
*ID 427001 - 427999: Kevin GUERRIER (alias xcl.saian)&lt;br /&gt;
*ID 428000 - 428099: af83&lt;br /&gt;
*ID 428100 - 428199: Arnaud Serrut - Adalon&lt;br /&gt;
*ID 428200 - 428249: imschweiler consulting (http://www.imschweiler-consulting.de&#039;&#039;&#039;&amp;lt;nowiki/&amp;gt;&#039;&#039;&#039;)&lt;br /&gt;
*ID 428250 - 428299: AL1FO&lt;br /&gt;
*ID 428300 - 428349: Federico García-Patiño Barbolani (&amp;lt;federico.garcia.patino@gmail.com&amp;gt;)&lt;br /&gt;
*ID 428350 - 428399: INTM Groupe - France (www.intm.com)&lt;br /&gt;
*ID 428400 - 428449: Nick Fragoulis - Greece&lt;br /&gt;
*ID 428450 - 428499: Letusgeek - France&lt;br /&gt;
*id 428500 - 428549 hkwhitten - USA&lt;br /&gt;
*ID 428550 - 428999 SmartOne&lt;br /&gt;
*ID 429000 - 429999: induslab&lt;br /&gt;
*ID 430000 - 430099: Mixity sprl (www.mixity.be)&lt;br /&gt;
*ID 430100 - 430199: sgiraud&lt;br /&gt;
*ID 430200 - 430299: Merlion TI (www.merlion-si.com.br)&lt;br /&gt;
*ID 430300 - 431299: Libre Expert (www.libre-expert.com)&lt;br /&gt;
*ID 431300 - 431399: ptibogxiv (www.ptibogxiv.net)&lt;br /&gt;
*ID 431400 - 431499: Befox (www.befox.fr)&lt;br /&gt;
*ID 431500 - 431599: rue Béjo (www.ruebejo.fr)&lt;br /&gt;
*ID 431600 - 431699: Avizzeo (www.avizzeo.com)&lt;br /&gt;
*ID 431700 - 432199: Multisistemas (www.multisistemas.com.sv)&lt;br /&gt;
*ID 432200 - 432399: Burbuja - Chile (www.burbuja.cl)&lt;br /&gt;
*ID 432400 - 433399: INOVEA CONSEIL (https://www.inovea-conseil.com)&lt;br /&gt;
*ID 433400 - 434399: Rachid HRICH - Maroc (HricH ServiceS.)&lt;br /&gt;
*ID 434400 - 435399: Lance Bleakley - LanceIT (www.lanceit.net)&lt;br /&gt;
*ID 436000 - 436099: SOWEBIO (www.soweb.io)&lt;br /&gt;
*ID 436100 - 436199: CAP-REL (www.cap-rel.fr)&lt;br /&gt;
*ID 436200 - 436300: TDE-INFORMATIQUE (www.tde-informatique.fr)&lt;br /&gt;
*ID 436301 - 436349: Evarisk ([https://www.evarisk.com/id-module-dolibarr/ www.evarisk.com])&lt;br /&gt;
*ID 436350 - 436399: Eoxia ([https://www.eoxia.com/dolibarr/modules/ www.eoxia.com])&lt;br /&gt;
*ID 436400 - 437399: Mohamed AHERDANE - Morocco - IT Consultant ( www.wave.ma )&lt;br /&gt;
*ID 437400 - 437449: Martin Neubauer - Germany&lt;br /&gt;
*ID 437450 - 437599: Club1click (www.club1click.es)&lt;br /&gt;
*ID 437600 - 437629: Coulon Vincent (https://github.com/HoverEpic)&lt;br /&gt;
*ID 437630 - 437649: Aytechnet (https://www.aytechnet.fr/) - François Pons&lt;br /&gt;
*ID 437650 - 437699: LibreMaster (https://libremaster.com) - Christophe T.&lt;br /&gt;
*ID 437700 - 437749: STELLAR Broadband (https://www.stellarbb.com) - U.S.A. - Philip Laycock&lt;br /&gt;
*ID 437750 - 437799: DIGITA.LU Ajous Solutions&lt;br /&gt;
*ID 437800 - 437850: iProspective (https://iprospective.fr) - Mathieu Moulin&lt;br /&gt;
*ID 437851 - 437900: Theobald Groupe.&lt;br /&gt;
*ID 437901 - 437950: Neuronnexion (http://neuronnexion.coop)&lt;br /&gt;
*ID 437951 - 437952: jmbc - APIA-ASSO (https://www.apia-asso.fr)&lt;br /&gt;
*ID 437953 - 438002: IPCZEN SARL (https://www.ipczeninformatique.fr/)&lt;br /&gt;
*ID 438003 - 438052: FESF IT Department (https://fesf.org.pk)&lt;br /&gt;
*ID 438053 - 438399: &#039;&#039;&#039;Free (take ranges of 50 only please at once, ask us for more)&#039;&#039;&#039;&lt;br /&gt;
*ID 438400 - 439399: Tetras Libre - France - Développement logiciels libres (www.tetras-libre.fr)&lt;br /&gt;
*ID 439400 - 440399: Dolibarr-pro - France - Développement Dolibarr (www.dolibarr-pro.com)&lt;br /&gt;
*ID 440400 - 441399: Quidlab Co., Ltd - Thailand - ( www.quidlab.com )&lt;br /&gt;
*ID 441400 - 442399: Ide@log - France - (https://www.idealog-info.net) - Laurent Leblanc&lt;br /&gt;
*ID 442400 - 443399: Valerio Bianchi (www.valeriobianchi.com)&lt;br /&gt;
*ID 443400 - 444399: delassalle - France - (www.delassalle.fr) - Joseph Delassalle&lt;br /&gt;
*ID 444400 - 445399: Webartis - Maroc - (www.webartis.net) - François Dry&lt;br /&gt;
*ID 445400 - 445499: SCOP Au-delà des nuages - France&lt;br /&gt;
*ID 446000 - 446999: iouston (http://www.iouston.com) - France - Julien Marchand&lt;br /&gt;
*ID 447000 - 447999: rSanjoSEO - Rafael San José Tovar (www.rsanjoseo.com) - Spain&lt;br /&gt;
*ID 448000 - 448999: Code 42 (www.code42.fr)&lt;br /&gt;
*ID 449000 - 449999: TakePOS (www.takepos.com)&lt;br /&gt;
*ID 450000 - 450999: Pierre ARDOIN&lt;br /&gt;
*ID 451000 - 451999: Éditeur depordi.fr&lt;br /&gt;
*ID 452000 - 452999: Dylan NAKONG&lt;br /&gt;
*ID 453000 - 453999: Menahd Ouchenir - France - menahd-ouchenir.com&lt;br /&gt;
*ID 454000 - 454999: Withheld - Canada&lt;br /&gt;
*ID 455000 - 455999: Gaëtan MAISON - Info Libre @ Dom - France (https://www.infolibreadom.com)&lt;br /&gt;
*ID 456000 - 456999: Laurent LEBLEU - B.L.C. - Blue Line Company - Lille - France (www.bluelinecompany.fr/dolibarr)&lt;br /&gt;
*ID 457000 - 457999: Sébastien BOUCHER&lt;br /&gt;
*ID 458000 - 458999: Lester HERNÁNDEZ - Argentina - (freelancerlrhd@gmail.com)&lt;br /&gt;
*ID 459000 - 459999: Infopen - France&lt;br /&gt;
*ID 460000 - 460050: torvista - Spain&lt;br /&gt;
*ID 461000 - 461999: MEGALOGI - Maroc (www.erpcloud.ma)&lt;br /&gt;
*ID 462000 - 462999: Making Digital (www.making-digital.fr) - France&lt;br /&gt;
*ID 463000 - 463999: linx s.r.l.s.&lt;br /&gt;
*ID 464000 - 464999: NimbleCubed Inc. (www.nimblecubed.com)&lt;br /&gt;
*ID 465000 - 465999: Artefacts - CourantAlternatif&lt;br /&gt;
*ID 466000 - 466999: CDM Consultores - (www.cdm.guru)&lt;br /&gt;
*ID 467000 - 467999: M71 Service GmbH - (www.m71-service.de)&lt;br /&gt;
*ID 468000 - 468049: Clément Segonzac - France (clement.segonzac@gmail.com)&lt;br /&gt;
*ID 468050 - 468099: Flavien Belli - France (https://github.com/Marshlyin || belliflaviencontactpro@gmail.com)&lt;br /&gt;
*ID 468100 - 468119: Chl (https://code.bugness.org/Dolibarr)&lt;br /&gt;
*ID 468120 - 468170: Commotron GmbH (https://www.commotron.com/)&lt;br /&gt;
*ID 468171 - 468220: Infans Group (franck.lauby@infans.fr)&lt;br /&gt;
*ID 468221 - 468174 &#039;&#039;&#039;Free (take ranges of 50 only please at once, ask us for more)&#039;&#039;&#039;&lt;br /&gt;
*ID 468175 - 468199: Gaëlle Rauffet - France (kiwiscan.net)&lt;br /&gt;
*ID 468200 - 468250: Paulo Oliveira - Brasil (paulorcdo@gmail.com)&lt;br /&gt;
*ID 468251 - 468270:  CD-Systems - France (https://www.cd-systems.fr)&lt;br /&gt;
*ID 468300 - 468349: Uvensys - Germany (https://uvensys.de)&lt;br /&gt;
*ID 468350 - 468399 : Laudeco - Belgium (http://github.com/laudeco)&lt;br /&gt;
*ID 468400 - 468449 : Alexis LAURIER - France (https://www.alexislaurier.fr)&lt;br /&gt;
*ID 468450 - 468499 : Mehdi Belkhayat - Maroc (https://opensi.ma)&lt;br /&gt;
*ID 468500 - 468599 : InvIT GmbH - Germany (https://invit.sh)&lt;br /&gt;
*ID 468600 - 468649 : Ricardo Sequeira - Portugal (https://ricardo-sequeira.com)&lt;br /&gt;
*ID 468650 - 468699 : J-IT - Belgique (https://www.j-it.be)&lt;br /&gt;
*ID 468700 - 468749 : Fidesio - France (https://www.fidesio.com/)&lt;br /&gt;
*ID 468750 - 468799 : Sgestion - Spain (http://www.sgestion.net/)&lt;br /&gt;
*ID 468800 - 468849 : Denis JULIEN - Brasil (matrinxa@free.fr)&lt;br /&gt;
*ID 468850 - 468900: Mmariko - Module GED - Effios&lt;br /&gt;
*ID 468901 - 468950: Maazou Amadou Abdoul aziz - Maroc (yaronfada@gmail.com)&lt;br /&gt;
*ID 468951 - 469000: Alexis LAURIER - France (https://www.alexislaurier.fr)&lt;br /&gt;
*ID 469001 - 469050: John Livingston (https://github.com/JohnXLivingston/)&lt;br /&gt;
*ID 469051 - 469100: Macrorom ICT-services (https://macrorom.nl/)&lt;br /&gt;
*ID 469101 - 469150: HABOT IT - France (https://habot.it)&lt;br /&gt;
*ID 469151 - 469160: CaribbeanConsult.Com CCC - France Guadeloupe (https://dolibarr.ccc.gp)&lt;br /&gt;
*ID 469161 - 469171: GMBG - Portugal&lt;br /&gt;
*ID 469172 - 469192: BGi Lda - Portugal&lt;br /&gt;
*ID 469949 - 469999: Goldoweb (http://goldoweb.com)&lt;br /&gt;
*ID 470000 - 470999: Reindeer Digital (https://rdeer.cz)&lt;br /&gt;
*ID 471000 - 471099: CAP-REL (www.cap-rel.fr)&lt;br /&gt;
*ID 471100 - 471199: M. Morillon&lt;br /&gt;
*ID 471200 - 471209: Pablo Nuñez&lt;br /&gt;
*ID 481000 - 482000: Alhaidab-ITIS (https://alhaidab.dolibarr.sd)&lt;br /&gt;
*ID 482001 - 483000: Basix IT (https://www.basix.de)&lt;br /&gt;
*ID 483001 - 483050: SASCO SpA (https://www.sasco.cl)&lt;br /&gt;
*ID 483051 - 483100: WIP Engineering (https://www.wip-gmbh.com)&lt;br /&gt;
*ID 483101 - 483150: J.Kaiser&lt;br /&gt;
*ID 483151 - 483201: CodLines (https://www.codlines.com)&lt;br /&gt;
*ID 485000 - 485049: Gest Info Service Plus (contact@gest-plus.fr)&lt;br /&gt;
*ID 490000 - 490050: VOLD (https://vold.lu)&lt;br /&gt;
*ID 491000 - 491050: NORD ERP CRM (https://www.nord-erp-crm.fr/)&lt;br /&gt;
*ID 491051 - 491100: KJR-online (https://kjr-online.fr/)&lt;br /&gt;
*ID 491101 - 491149: eNova&lt;br /&gt;
*ID 491150 - 491200: App 4 Business&lt;br /&gt;
*ID 491201 - 491250: Mil24 (http://www.mil24.com.py)&lt;br /&gt;
*ID 491251 - 491301: M2AM&lt;br /&gt;
&lt;br /&gt;
DO NOT ADD RECORD HERE, PLEASE FILL HOLES FIRST !!!!&lt;br /&gt;
...&lt;br /&gt;
&lt;br /&gt;
=ID &amp;gt; 500000=&lt;br /&gt;
&lt;br /&gt;
This range can&#039;t be reserved. It is a common range. If you don&#039;t plan to distribute your module, you can use an ID in this range with no need to reserve it.&lt;br /&gt;
&lt;br /&gt;
{{Flag en}}&lt;br /&gt;
If you don&#039;t already have reserved ids and need some, please don&#039;t use hazardous number and use a number higher than 500000, but it is better to ask a wiki account, and reserve your own range by editing the  100000 - 499999 range (50 ids at once, 1000 ids maximum per partner).&lt;br /&gt;
&lt;br /&gt;
{{Flag fr}}&lt;br /&gt;
Si vous n&#039;avez pas de numéros réservés et en avez besoin, n&#039;utilisez pas de chiffres au hasard et utilisez une valeur supérieure à 500000, toutefois, il est préférable d&#039;obtenir un compte wiki, et  réserver vous-même votre plage en ajoutant votre entrée dans la zone 100000 - 499999 (par lot de 50 d&#039;abord, pas plus de 1000 numéros par partenaire).&lt;br /&gt;
&lt;br /&gt;
{{Flag sp}}&lt;br /&gt;
Si no dispone de número reservado y necesita, no use cifras redondeadas y usa un valor superior a 500000. Si tiene una cuenta wiki, puede reservarse usted mismo sus id añadiendo su entrada en la zona 100000 - 499999 (no más de 1000 id por partner).&lt;/div&gt;</summary>
		<author><name>TanguyP</name></author>
	</entry>
</feed>