<?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=OPCoach</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=OPCoach"/>
	<link rel="alternate" type="text/html" href="https://wiki.dolibarr.org/index.php/Special:Contributions/OPCoach"/>
	<updated>2026-11-09T09:22:11Z</updated>
	<subtitle>User contributions</subtitle>
	<generator>MediaWiki 1.39.17</generator>
	<entry>
		<id>https://wiki.dolibarr.org/index.php?title=Create_an_ODT_or_ODS_document_template&amp;diff=56476</id>
		<title>Create an ODT or ODS document template</title>
		<link rel="alternate" type="text/html" href="https://wiki.dolibarr.org/index.php?title=Create_an_ODT_or_ODS_document_template&amp;diff=56476"/>
		<updated>2023-05-10T10:26:17Z</updated>

		<summary type="html">&lt;p&gt;OPCoach: As mentionned in issue (https://github.com/Dolibarr/dolibarr/issues/22364) I put the warning in red and bold&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{TemplateDocUser}}&lt;br /&gt;
This page describe how to build an ODT document template to build documents using ODT generation.&lt;br /&gt;
&lt;br /&gt;
To know how to build a PDF template, see page [[Create a PDF document template]]. Building a PDF template require PHP development knowledge, but not building an ODT template.&lt;br /&gt;
&lt;br /&gt;
==Prerequisite==&lt;br /&gt;
&lt;br /&gt;
*Dolibarr: 3.1+&lt;br /&gt;
*OpenOffice: 3.2+, LibreOffice, ...&lt;br /&gt;
&lt;br /&gt;
==Create your document==&lt;br /&gt;
&lt;br /&gt;
*Create from scratch an empty OpenOffice document and take a provided example. You may find them installed into a subdirectory of directory &#039;&#039;&#039;documents/doctemplates&#039;&#039;&#039;&lt;br /&gt;
*Edit your document using all your Office suite features.&lt;br /&gt;
&lt;br /&gt;
Include in your document the tags you want to see. Tags will be replaced during generation of document automatically by Dolibarr. List of all available tags are provided in next chapter.&lt;br /&gt;
&lt;br /&gt;
[[File:Warning.png]] &amp;lt;span style=&amp;quot;color:#FE0000&amp;quot;&amp;gt;&#039;&#039;&#039;Warning, tags must be rounded with {} or [] for arrays (see later) and must be typed with no stop using Office suite (with no backspace and no copy-paste). If not doing that, Office suite adds some invisible information makes detection/replacement impossible. With LibreOffice you can also use the Ctrl+M to remove direct formatting from Tags&#039;&#039;&#039;&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Tags==&lt;br /&gt;
This is a list of tags that will be replaced with your informations:&lt;br /&gt;
&lt;br /&gt;
===Company/foundation information===&lt;br /&gt;
{{TagsOdtMyCompany}}&lt;br /&gt;
&lt;br /&gt;
===Customers, prospects or suppliers information===&lt;br /&gt;
{{TagsOdtThirdParty}}&lt;br /&gt;
&lt;br /&gt;
===Contacts===&lt;br /&gt;
It is the tags for contact of invoice for invoices (type BILLING), contact of proposal for proposals (type CUSTOMER), contact of order for sale orders (type CUSTOMER). There is not tags for delivery contact.&lt;br /&gt;
{{TagsOdtContact}}&lt;br /&gt;
&lt;br /&gt;
===User information===&lt;br /&gt;
{{TagsOdtUser}}&lt;br /&gt;
&lt;br /&gt;
===Other information===&lt;br /&gt;
{{TagsOdtOther}}&lt;br /&gt;
&lt;br /&gt;
===Object information (invoice, commercial proposal, order, ...)===&lt;br /&gt;
Note: When you find _locale at end of the name of a tag, it means the output value will be in the locale and language of the targetted language for generation instead of the default format or language.&lt;br /&gt;
&lt;br /&gt;
{{TagsOdtObjects}}&lt;br /&gt;
&lt;br /&gt;
[[File:Info.png]] &lt;br /&gt;
&lt;br /&gt;
For the tag {object_total_..._x}, if there is no amount for the vat rate x, the key is not replaced. So you can use the condition syntax to show 0 instead of the key when value is not defined:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
[!-- IF {object_total_..._x} --]&lt;br /&gt;
0&lt;br /&gt;
[!-- ELSE {object_total_..._x} --]&lt;br /&gt;
{object_total_..._x}&lt;br /&gt;
[!-- ENDIF {object_total_..._x} --]&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
[[File:Warning.png]] To be sure this part of code does not contains hidden text (added silently by LibreOffice for versioning/tracking change purpose), you must select all the code section, make a right click an  select the feature &amp;quot;Remove direct formatting&amp;quot; (not doing this may make the code section not working).&lt;br /&gt;
&lt;br /&gt;
===Lines of object===&lt;br /&gt;
This is how to use arrays for lines of objects (invoices, commercial proposal, orders, etc...). You must create your array in the document and use a begin and end tag to define a line of the array. The line will then be repeated as much as required during generation.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
[!-- BEGIN row.lines --]&lt;br /&gt;
...&lt;br /&gt;
[!-- END row.lines --]&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If you want to display it not in tables row but in block lines :&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
[!-- BEGIN lines --]&lt;br /&gt;
...&lt;br /&gt;
[!-- END lines --]&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Then, you can use the following tags into your line (in addition to any other tags of the document):&lt;br /&gt;
{{TagsOdtLines}}&lt;br /&gt;
&lt;br /&gt;
This an example of what you may have in your office suite:&lt;br /&gt;
[[File:Line for document generation.png|500px]]&lt;br /&gt;
&lt;br /&gt;
===For project documents===&lt;br /&gt;
For document about projects and task, you also have&lt;br /&gt;
{{TagsOdtProject}}&lt;br /&gt;
&lt;br /&gt;
===Conditional substitution===&lt;br /&gt;
&lt;br /&gt;
Starting from Dolibarr v3.3, you can use conditional substitutions, which in layman terms means that you can decide to print something if a variable is true, or print something else if it&#039;s false (or nothing at all) - including text but also any more complex structures like tables and images.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
[!-- IF {my_var} --]&lt;br /&gt;
Print this text if {my_var} is true (can be any value but null/0/empty string)&lt;br /&gt;
[!-- ELSE {my_var} --]&lt;br /&gt;
Or print this if it&#039;s false (null/0/empty string)&lt;br /&gt;
[!-- ENDIF {my_var} --]&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note: of course, the ELSE tag and block is optional, you can just use IF/ENDIF if you prefer.&lt;br /&gt;
&lt;br /&gt;
*[[File:Warning.png]] Warning: the format of this special tag is very precise and picky, be careful to &#039;&#039;&#039;put one space&#039;&#039;&#039; between:&lt;br /&gt;
**[!--&lt;br /&gt;
**IF/ELSE/ENDIF&lt;br /&gt;
**{my var}&lt;br /&gt;
**--]&lt;br /&gt;
*[[File:Warning.png]] Warning: String must be typed with no stop using Office suite (with no backward and no copy-paste). If not doing that, Office suite add some invisible information making detection/replacement of text not possible.&lt;br /&gt;
&lt;br /&gt;
===Other personalized tags===&lt;br /&gt;
If you want to add a field that is not predefined, this is the solution:&lt;br /&gt;
&lt;br /&gt;
*Create a file into the location:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;htdocs/mymodule/core/substitutions/functions_mymodule.lib.php&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
*Inside this file, just write one function like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;PHP&amp;quot;&amp;gt;&lt;br /&gt;
/** 		Function called to complete substitution array (before generating on ODT, or a personalized email)&lt;br /&gt;
 * 		functions xxx_completesubstitutionarray are called by make_substitutions() if file&lt;br /&gt;
 * 		is inside directory htdocs/core/substitutions&lt;br /&gt;
 * &lt;br /&gt;
 *		@param	array		$substitutionarray	Array with substitution key=&amp;gt;val&lt;br /&gt;
 *		@param	Translate	$langs			Output langs&lt;br /&gt;
 *		@param	Object		$object			Object to use to get values&lt;br /&gt;
 * 		@return	void					The entry parameter $substitutionarray is modified&lt;br /&gt;
 */&lt;br /&gt;
function mymodule_completesubstitutionarray(&amp;amp;$substitutionarray,$langs,$object)&lt;br /&gt;
{&lt;br /&gt;
   global $conf,$db;&lt;br /&gt;
&lt;br /&gt;
   $myvalue=&#039;Put here calculated value to insert&#039;;&lt;br /&gt;
   $substitutionarray[&#039;myowntag&#039;]=$myvalue;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Function will be called before generating document to complete the array used for substitution and to replace tag myowntag with value $myvalue. You can add as many tags as you need and put all personalized code you want to define values (search into database, into files, calculation, from received parameters or from global variables)... &lt;br /&gt;
&lt;br /&gt;
Warning: First parameter in function parameter declaration must start with &amp;amp; as value is modified by your code and must be returned modified.&lt;br /&gt;
&lt;br /&gt;
To have your substitution function be called,  if you have to :&lt;br /&gt;
&lt;br /&gt;
*Check your substitution file is inside subdirectory module called htdocs/mymodule/core/substitutions.&lt;br /&gt;
*Build your own module (See page [[Module development]]) with its descriptor file.&lt;br /&gt;
*Check your module descriptor file contains an entry to declare this module has a substitutions file&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;PHP&amp;quot;&amp;gt;&lt;br /&gt;
$this-&amp;gt;module_parts = array(&#039;substitutions&#039; =&amp;gt; 1) &lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
*Enable your module (module must be enabled and disabled each time you change the descriptor).&lt;br /&gt;
&lt;br /&gt;
Note2: this only allows to define global, static ODT variables (ie: to make dynamic variables that changes for every line of product, please see the next chapter).&lt;br /&gt;
&lt;br /&gt;
===Other personalized tags for lines===&lt;br /&gt;
&lt;br /&gt;
This function is available since Dolibarr v3.3 (future development version).&lt;br /&gt;
&lt;br /&gt;
Similarly to the previous chapter, you have to define a function, and it works about the same, but with a few twists:&lt;br /&gt;
&lt;br /&gt;
*Create or edit the same file as before (see the previous chapter).&lt;br /&gt;
*Here are the twists: in the file, write another function with almost the same name but with &#039;_lines&#039; appended, and also add a new $lines variable:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;PHP&amp;quot;&amp;gt;&lt;br /&gt;
/** 		Function called to complete substitution array for lines (before generating on ODT, or a personalized email)&lt;br /&gt;
 * 		functions xxx_completesubstitutionarray_lines are called by make_substitutions() if file&lt;br /&gt;
 * 		is inside directory htdocs/core/substitutions&lt;br /&gt;
 * &lt;br /&gt;
 *		@param	array		$substitutionarray	Array with substitution key=&amp;gt;val&lt;br /&gt;
 *		@param	Translate	$langs			Output langs&lt;br /&gt;
 *		@param	Object		$object			Object to use to get values&lt;br /&gt;
 *              @param  Object          $line                   Current line being processed, use this object to get values&lt;br /&gt;
 * 		@return	void					The entry parameter $substitutionarray is modified&lt;br /&gt;
 */&lt;br /&gt;
function mymodule_completesubstitutionarray_lines(&amp;amp;$substitutionarray,$langs,$object,$line) {&lt;br /&gt;
{&lt;br /&gt;
   global $conf,$db;&lt;br /&gt;
&lt;br /&gt;
   $myvalue=&#039;Put here calculated value to insert&#039;;&lt;br /&gt;
   $substitutionarray[&#039;myowntag&#039;]=$myvalue;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Contrary to the previous function which was called only once, this function will be called everytime a line of product will be processed, giving you each time a new $line object that you can process. This allows you to do different substitutions for each product.&lt;br /&gt;
&lt;br /&gt;
==Store your document==&lt;br /&gt;
To have your document to appear in list of available documents, put it into correct subdirectory found into&lt;br /&gt;
directory &#039;&#039;&#039;documents/doctemplates&#039;&#039;&#039;&lt;/div&gt;</summary>
		<author><name>OPCoach</name></author>
	</entry>
</feed>