diff --git a/.travis.yml b/.travis.yml index 4b17ebaf0c8..96a238e6ad4 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,7 +2,7 @@ # from Dolibarr GitHub repository. # For syntax, see http://about.travis-ci.org/docs/user/languages/php/ -# We use dist: trusty to have php 5.4+ available +# We use dist: trusty to have php 5.4+ available dist: trusty sudo: required diff --git a/ChangeLog b/ChangeLog index e516382f62f..f61d3a4820d 100644 --- a/ChangeLog +++ b/ChangeLog @@ -284,6 +284,68 @@ Following changes may create regressions for some external modules, but were nec where {TYPE} is contact type code (BILLING, SHIPPING, CUSTOMER, ... see contact type dictionnary). + +***** ChangeLog for 7.0.4 compared to 7.0.3 ***** +FIX: #8984 button create expense report +FIX: #9032 +FIX: #9161 +FIX: #9328 +FIX: According to french law, if seller is in France and buyer isn't in UE and isn't a company, TVA used = TVA product +FIX: Add calls to fetchComments function +FIX: better compatibility with multicompany +FIX: case when we valid form with keyboard +FIX: character making error on bill list +FIX: check !empty exclude select element +FIX: combo into popup become crazy with IE10 +FIX: combo of stock in popup are crazy in IE +FIX: Deletion of files in migration +FIX: exclude element of the select +FIX: extrafieldkey +FIX: Fetch function will fetch comments +FIX: Fetch task will now fetch comments +FIX: filter supplier invoice list by societe name. +FIX: $fk_account is always empty, must be $soc->fk_account +FIX: Force stripe api version to avoid trouble if we update stripe api +FIX: getEntity project and not projet +FIX: Get templates in a forced language +FIX: global $mysoc missing (to avoid php notice on lines 279, 280 & 281) +FIX: Injection +FIX: invoice stats: situation invoices were not counted +FIX: keep context filter on contact list on change column displayed +FIX: Keep same project when creating shipping from order +FIX: langs fr +FIX: Lose filter on payment type or category after a sort on invoice list +FIX: Missing behavior +FIX: missing hook to edit sql +FIX: multicompany compatibility ! +FIX: need to filter on current entity on replenish +FIX: Option MAIN_DISABLE_NOTES_TAB #9611 +FIX: page must always be 0 when we search (to avoid case : when we're on page 3 and we're looking for a precise thirdparty, we stay on page 3 and nothing's displaied) +FIX: Pagination on related item pages +FIX: Pagination on withdraw request list +FIX: PDF address: handle when contact thirdparty different from document thirdparty +FIX: PHP warning, undefined index notnull +FIX: Product marge tabs on product card +FIX: Product margin tab and credit note +FIX: propal: correctly preset project when creating with origin/originid +FIX: remain to pay for credit note was wrong on invoice list +FIX: remove debug +FIX: Remove fetchComments from project and task fetch function +FIX: remove rowid for multicompany compatibility +FIX: Search on Ref project on order list +FIX: search on ref project on propal list +FIX: showOptionals: column mismatches +FIX: SQL Injections reported by mu shcor (ADLab of Venustech) +FIX: stock replenish with multientity +FIX: table llx_chargessociales doesn't exists +FIX: we must see number of all shared projects +FIX: when stock is empty for current entity but > 0 in other entity, until this commit product wasn't displaied on replenishment, it must depends on multientity stock sharing +FIX: when we're just admin and not super admin, if we create new user with transverse mode, we don't see it then we can't add him in usergroup +FIX: wrong function name +FIX: Wrong position of firstname lastname +FIX: wrong value for module part and return access denied +FIX: Wrong variable and trigger name + ***** ChangeLog for 7.0.3 compared to 7.0.2 ***** FIX: 7.0 task contact card without withproject parameters FIX: #8722 @@ -766,6 +828,32 @@ Following changes may create regressions for some external modules, but were nec multicompany module to a version that support Dolibarr v7, everything should work as expected. +***** ChangeLog for 6.0.8 compared to 6.0.7 ***** +FIX: #8762 +FIX: #9032 +FIX: case when we valid form with keyboard +FIX: clause must not be there +FIX: dol_delete_file must work in a context without db handler loaded +FIX: entity test must be on product_fourn_price table and not product table +FIX: Fetch shipping will now fetch project id +FIX: $fk_account is always empty, must be $soc->fk_account +FIX: getEntity project and not projet +FIX: If we enable 3 steps for supplier order approbation, we must not delete all fourn rights def. +FIX: Keep supplier proposal price for supplier order +FIX: langs fr +FIX: missing filters during reordering +FIX: need to filter on aa.entity for same accounting accounts available in several entities +FIX: page must always be 0 when we search (to avoid case : when we're on page 3 and we're looking for a precise thirdparty, we stay on page 3 and nothing's displaied) +FIX: PDF address: handle when contact thirdparty different from document thirdparty +FIX: propal: correctly preset project when creating with origin/originid +FIX: pu_ht_devise was not converted to numeric so decimals were lost when calculating total_ht_devise +FIX: remain to pay for credit note was wrong on invoice list +FIX: shipment: fk_proje(c)t not handled in fetch() and update() methods +FIX: showOptionals: column mismatches +FIX: sometimes amounts are identical but php find them different. +FIX: test is_erasable() must be done before call function delete() too to avoid delete invoice with &action=delete in url +FIX: we must see number of all shared projects +FIX: wrong var name ***** ChangeLog for 6.0.7 compared to 6.0.6 ***** FIX: #8023 diff --git a/README-FR.md b/README-FR.md index a9745bb8dbb..19d4ae25df9 100644 --- a/README-FR.md +++ b/README-FR.md @@ -16,8 +16,8 @@ Dolibarr est distribué sous les termes de la licence GNU General Public License ## INSTALLER DOLIBARR Si vous n'avez pas de connaissances techniques, et que vous recherchez -un programme d'installation qui install Dolibarr ERP/CRM en quelques clics, -vous devez vous réorienter vers DoliWamp (la version tout-en-un +un programme d'installation qui installe Dolibarr ERP/CRM en quelques clics, +vous devez vous ré-orienter vers DoliWamp (la version tout-en-un de Dolibarr pour Windows), DoliDeb (la version tout-en-un pour Debian ou Ubuntu) ou DoliRpm (la version tout-en-un de Dolibarr pour Fedora, Redhat, OpenSuse, Mandriva ou Mageia). @@ -25,39 +25,39 @@ OpenSuse, Mandriva ou Mageia). Vous pouvez les télécharger depuis la rubrique *download* du portail officiel: https://www.dolibarr.org/ -Si vous avez déjà installé un serveur Web avec PHP et une base de donnée (MariaDb/MySql/PostgreSql), +Si vous avez déjà installé un serveur Web avec PHP et une base de données (MariaDb/MySql/PostgreSql), vous pouvez installer Dolibarr avec cette version de la manière suivante: -- Copier le répertoire "dolibarr" et son contenu dans la racine de votre serveur - web, ou bien copier le répertoire sur le serveur et configurer ce serveur pour +- Copiez le répertoire "dolibarr" et son contenu dans la racine de votre serveur + web, ou bien copiez le répertoire sur le serveur et configurez ce serveur pour utiliser "dolibarr/htdocs" comme racine d'un nouveau virtual host (ce second choix requiert des compétences et habilitations en administration du serveur web). -- Créer un fichier vide "htdocs/conf/conf.php" et attribuer les permissions +- Créez un fichier vide "htdocs/conf/conf.php" et attribuez les permissions en lecture et écriture pour le user du serveur web (les permissions en écriture seront supprimées une fois l'installation terminée). -- Depuis votre navigateur, appeler la page "install/" de dolibarr. L'url dépend - du choix fait à la première etape: +- Depuis votre navigateur, appelez la page "install/" de dolibarr. L'url dépend + du choix fait à la première étape: http://localhost/dolibarr/htdocs/install/ ou http://yourdolibarrvirtualhost/install/ -- Suivez les instructions fournies par l'installeur... +- Suivez les instructions fournies par l'installateur... ## METTRE A JOUR DOLIBARR -Pour mettre a jour Dolibarr depuis une vieille version vers celle ci: -- Ecraser les vieux fichiers dans le vieux repertoire 'dolibarr' par les fichiers +Pour mettre à jour Dolibarr depuis une vieille version vers celle ci: +- Ecrasez les vieux fichiers dans le vieux répertoire 'dolibarr' par les fichiers fournis dans ce nouveau package. -- Au prochain accès, Dolibarr proposera la page de "mise a jour" des données (si necessaire). - Si un fichier install.lock existe pour vérouiller le processus de mise à jour, il sera demandé de le supprimer manuellement (vous devriez trouver le fichier install.lock dans le répertoire utilisé pour stocker les documents générés ou transféré sur le serveur. Dans la plupart des cas, c'est le répertoire appelé "documents") - -*Note: Le processus de migration peut etre lancé manuellement et plusieurs fois, sans risque, en appelant la page /install/* +- Au prochain accès, Dolibarr proposera la page de "mise à jour" des données (si nécessaire). + Si un fichier install.lock existe pour verrouiller le processus de mise à jour, il sera demandé de le supprimer manuellement (vous devriez trouver le fichier install.lock dans le répertoire utilisé pour stocker les documents générés ou transférés sur le serveur. Dans la plupart des cas, c'est le répertoire appelé "documents") + +*Note: Le processus de migration peut être lancé manuellement et plusieurs fois, sans risque, en appelant la page /install/* ## CE QUI EST NOUVEAU @@ -94,14 +94,15 @@ Voir fichier ChangeLog. - Gestion de marque-pages - Gestion des promesses de dons -- Gestion de la TVA NPR (non perçue récupérable - pour les utilisateurs français des DOM-TOM) - Rapports - Imports/Exports des données +- Support des codes barres +- Calcul des marges - Connectivité LDAP - Intégratn de ClickToDial - Intégration RSS - Intégation Skype -- Intégration de système de paiements (Paypal, Strip, Paybox...) +- Intégration de système de paiements (Paypal, Stripe, Paybox...) - … ### Divers: @@ -114,9 +115,18 @@ Voir fichier ChangeLog. - Application simple à utiliser. - Requiert PHP et MariaDb, Mysql ou Postgresql (Voir versions exactes sur https://wiki.dolibarr.org/index.php/Prérequis). - Compatible avec toutes les offres Cloud du marché respectant les prérequis de base de données et PHP. -- Code simple et facilement personnalisable (pas de framework lourd; mécanisme de hook et triggers). - APIs. - Génération PDF et ODT des éléments (factures, propositions commerciales, commandes, bons expéditions, etc...) +- Code simple et facilement personnalisable (pas de framework lourd; mécanisme de hook et triggers). +- Support natif de nombreuses fonctions spécifiques aux pays comme: + - La tax espagnole TE et ISPF + - Gestion de la TVA NPR (non perçue récupérable - pour les utilisateurs français des DOM-TOM) + - La loi française Finance 2016 et logiciels de caisse + - La double taxe canadienne + - Le timbre fiscal tunisien + - Numérotation de facture de l'argentines (avec type A,B,C...) + - Compatible avec vos processus RGPD + - ... - … ### Extension @@ -126,7 +136,7 @@ Dolibarr peut aussi être étendu à volonté avec l'ajout de module/application ## CE QUE DOLIBARR NE PEUT PAS (ENCORE) FAIRE -Voici un liste de fonctionnalites pas encore gérées par Dolibarr: +Voici un liste de fonctionnalités pas encore gérées par Dolibarr: - Dolibarr ne contient pas de module de Gestion de la paie. - Les tâches du module de gestion de projets n'ont pas de dépendances entre elle. - Dolibarr n'embarque pas de Webmail intégré nativement. @@ -135,7 +145,7 @@ Voici un liste de fonctionnalites pas encore gérées par Dolibarr: ## DOCUMENTATION -Les documentations utilisateur, développeur et traducteur sont disponible sous forme de ressources de la communautés via la site [Wiki](https://wiki.dolibarr.org). +La documentation utilisateur, développeur et traducteur est disponible sous forme de ressources de la communauté via le site [Wiki](https://wiki.dolibarr.org). ## CONTRIBUER diff --git a/README.md b/README.md index dfd9d70ab7c..c38d0ca7dd1 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,7 @@ # DOLIBARR ERP & CRM ![Downloads per day](https://img.shields.io/sourceforge/dm/dolibarr.svg) +[![Reviewed by Hound](https://img.shields.io/badge/Reviewed_by-Hound-8E64B0.svg)](https://houndci.com) |6|7|8|develop| |----------|----------|----------|----------| @@ -129,7 +130,6 @@ See the [ChangeLog](https://github.com/Dolibarr/dolibarr/blob/develop/ChangeLog) - Donations management - Reporting - Data export/import -- Thirdparties and/or products categories - Barcodes support - Margin calculations - LDAP connectivity @@ -151,13 +151,15 @@ See the [ChangeLog](https://github.com/Dolibarr/dolibarr/blob/develop/ChangeLog) - Compatible with all Cloud solutions that match MySQL, PHP or PostgreSQL prerequisites. - APIs. - An easy to understand, maintain and develop code (PHP with no heavy framework; trigger and hook architecture) -- Support for country specific features: +- Support a lot of country specific features: - Spanish Tax RE and ISPF - French NPR VAT rate (VAT called "Non Perçue Récupérable" for DOM-TOM) - Canadian double taxes (federal/province) and other countries using cumulative VAT - Tunisian tax stamp - Argentina invoice numbering using A,B,C... - Compatible with [European directives](http://europa.eu/legislation_summaries/taxation/l31057_en.htm) (2006/112/CE ... 2010/45/UE) + - Compatible with European GDPR rules + - ... - PDF or ODT generation for invoice, proposals, orders... - … diff --git a/build/aps/APP-META-1.1.xml b/build/aps/APP-META-1.1.xml deleted file mode 100644 index 1394da4d4be..00000000000 --- a/build/aps/APP-META-1.1.xml +++ /dev/null @@ -1,123 +0,0 @@ - - - - Dolibarr ERP-CRM - __VERSION__ - __RELEASE__ - http://www.dolibarr.org/ - - Dolibarr - http://www.dolibarr.org/ - - - - Laurent Destailleur - http://www.nltechno.com - uuid:e743ee30-9fe8-11e0-a32e-0025115d642c - - - Dolibarr ERP-CRM, the easy to use software to manage small or medium companies, freelancers or foundations - -Dolibarr is a free modular software (you see only -features you need) to manage small and medium companies, freelancers -or foundations. -This OpenSource software is designed to provide all features you need to -manage information on many aspects of your business -into an intuitive and user-friendly graphical interface -It's an OpenSource software you can install on a web server or as a -standalone software. Dolibarr is designed to provide simplicity to end-user. - - - - Screenshot 1 - - - - See http://www.dolibarr.org/files/ChangeLog - - - - Back office/Billing - Back office/Accounting and Financial - Back office/Customer Relationship Management - Back office/Enterprise Resource Planning - - - en - fr - es - de - pt - - - - - - - - - GPL-3.0+ - COPYING - - - - Dolibarr instance - Dolibarr services - - - - - - - - - - - - - - mysql - mbstring - false - - main - dolibarr - false - mysql - 4.3.1 - - - - - - dolibarr - 35000000 - - - php - - - - - - php - - - - - \ No newline at end of file diff --git a/build/aps/APP-META-1.2.xml b/build/aps/APP-META-1.2.xml deleted file mode 100644 index 1ce51207dd8..00000000000 --- a/build/aps/APP-META-1.2.xml +++ /dev/null @@ -1,121 +0,0 @@ - - - - dolibarr - Dolibarr - __VERSION__ - __RELEASE__ - http://www.dolibarr.org/ - - Dolibarr - http://www.dolibarr.org/ - - - - Laurent Destailleur - http://www.nltechno.com - uuid:e743ee30-9fe8-11e0-a32e-0025115d642c - - - Dolibarr ERP - CRM, the easy to use software to manage small or medium companies, freelancers or foundations - -Dolibarr is a free modular software (you see only -features you need) to manage small and medium companies, freelancers -or foundations. -This OpenSource software is designed to provide all features you need to -manage information on many aspects of your business -into an intuitive and user-friendly graphical interface -It's an OpenSource software you can install on a web server or as a -standalone software. Dolibarr is designed to provide simplicity to end-user. - - - - Screenshot 1 - - - - See http://www.dolibarr.org/files/ChangeLog - - - - Back office/Billing - Back office/Accounting and Financial - Back office/Customer Relationship Management - Back office/Enterprise Resource Planning - - - en - fr - es - de - pt - - - - - - - - - GPL-3.0+ - COPYING - - - - Dolibarr instance - - - - - - - - - - Administrator's preferences - - Administrator's login - -Please make sure the text you entered starts with a letter and continues with either numbers, letters, underscores or hyphens. - - - - Password - - - - - - - mysql - mbstring - false - - main - dolibarr - false - mysql - 4.3.1 - - - - - - dolibarr - 35000000 - - - php - - - - - - php - - - - - \ No newline at end of file diff --git a/build/aps/Limitations of APS Support in the Panel.html b/build/aps/Limitations of APS Support in the Panel.html deleted file mode 100644 index 51ba8e18378..00000000000 --- a/build/aps/Limitations of APS Support in the Panel.html +++ /dev/null @@ -1,89 +0,0 @@ - - Limitations of APS Support in the Panel - - - - - - - - -

Limitations of APS Support in the Panel

-

About This Document

-

This document is addressed to independent software -vendors who plan to distribute web applications among the Panel users. -The aim of the document is to help vendors find out whether they can -package their applications to APS to make them available through the -Panel.

-

The document does not contain information about -Application Packaging Standard itself or give application packaging -instructions. It focuses on how the Panel implements APS and what APS -packages are not supported by this implementation.

-

-

APS Support in the Panel

-

Application Packaging Standard (APS) - is a set of rules that defines a web application packaging format. This - standard is designed to ease the integration of applications in a -service provider's infrastructure. It covers provisioning, management, -and integration of cloud-based services and applications.

-

The Panel uses APS to offer third-party applications to hosting customers. These applications are presented in APS catalog, where the customers can buy or download them.

-

Currently, the Panel does not support all aspects of - APS. Therefore, customers may have problems trying to install certain -applications. To find out whether your application is compatible with -the Panel, see section Plesk Panel Restrictions.

-

You can find more information about APS at http://www.apsstandard.org/.

-

APS specification and supporting documents are available at http://www.apsstandard.org/isv/documentation/.

-

-

Restrictions on Packages Processing

-

The current Panel version has restrictions on APS -applications processing. If an application requires performing -restricted actions, the Panel will not install it. Particularly, these -actions are the following:

-

If - you need you application to perform these actions, consider other ways -of integration with the Panel: API RPC, modules or Panel Notifications.

-

Also, the Panel does not support the following actions defined in the application package:

- - \ No newline at end of file diff --git a/build/aps/Limitations of APS Support in the Panel_fichiers/highlight.js b/build/aps/Limitations of APS Support in the Panel_fichiers/highlight.js deleted file mode 100644 index 10056e95fd4..00000000000 --- a/build/aps/Limitations of APS Support in the Panel_fichiers/highlight.js +++ /dev/null @@ -1,64 +0,0 @@ -function last(href) -{ - var ret = href.split("/"); - return ret[ret.length-1]; -} - -function StopProcess() -{ -LeftFrame = parent.TOC.document.location.href; -LeftFrame = last(LeftFrame); -if (LeftFrame == "dhtml_search.htm") return 1 -else return 0; -} - - - -function highlightTOC(str) { - - - - - - if (StopProcess()) return; - try { - - str = str || parent.BODY.document.location.href; - uri = last(str); - list = parent.TOC.document.getElementsByTagName("a"); - for(i=0; i - * - * For a fairly comprehensive set of languages see the - * README - * file that came with this source. At a minimum, the lexer should work on a - * number of languages including C and friends, Java, Python, Bash, SQL, HTML, - * XML, CSS, Javascript, and Makefiles. It works passably on Ruby, PHP and Awk - * and a subset of Perl, but, because of commenting conventions, doesn't work on - * Smalltalk, Lisp-like, or CAML-like languages without an explicit lang class. - *

- * Usage:

    - *
  1. include this source file in an html page via - * {@code } - *
  2. define style rules. See the example page for examples. - *
  3. mark the {@code
    } and {@code } tags in your source with
    - *    {@code class=prettyprint.}
    - *    You can also use the (html deprecated) {@code } tag, but the pretty
    - *    printer needs to do more substantial DOM manipulations to support that, so
    - *    some css styles may not be preserved.
    - * </ol>
    - * That's it.  I wanted to keep the API as simple as possible, so there's no
    - * need to specify which language the code is in, but if you wish, you can add
    - * another class to the {@code <pre>} or {@code <code>} element to specify the
    - * language, as in {@code <pre class="prettyprint lang-java">}.  Any class that
    - * starts with "lang-" followed by a file extension, specifies the file type.
    - * See the "lang-*.js" files in this directory for code that implements
    - * per-language file handlers.
    - * <p>
    - * Change log:<br>
    - * cbeust, 2006/08/22
    - * <blockquote>
    - *   Java annotations (start with "@") are now captured as literals ("lit")
    - * </blockquote>
    - * @requires console
    - */
    -
    -// JSLint declarations
    -/*global console, document, navigator, setTimeout, window */
    -
    -/**
    - * Split {@code prettyPrint} into multiple timeouts so as not to interfere with
    - * UI events.
    - * If set to {@code false}, {@code prettyPrint()} is synchronous.
    - */
    -window['PR_SHOULD_USE_CONTINUATION'] = true;
    -
    -/** the number of characters between tab columns */
    -window['PR_TAB_WIDTH'] = 8;
    -
    -/** Walks the DOM returning a properly escaped version of innerHTML.
    -  * @param {Node} node
    -  * @param {Array.<string>} out output buffer that receives chunks of HTML.
    -  */
    -window['PR_normalizedHtml']
    -
    -/** Contains functions for creating and registering new language handlers.
    -  * @type {Object}
    -  */
    -  = window['PR']
    -
    -/** Pretty print a chunk of code.
    -  *
    -  * @param {string} sourceCodeHtml code as html
    -  * @return {string} code as html, but prettier
    -  */
    -  = window['prettyPrintOne']
    -/** Find all the {@code <pre>} and {@code <code>} tags in the DOM with
    -  * {@code class=prettyprint} and prettify them.
    -  * @param {Function?} opt_whenDone if specified, called when the last entry
    -  *     has been finished.
    -  */
    -  = window['prettyPrint'] = void 0;
    -
    -/** browser detection. @extern @returns false if not IE, otherwise the major version. */
    -window['_pr_isIE6'] = function () {
    -  var ieVersion = navigator && navigator.userAgent &&
    -      navigator.userAgent.match(/\bMSIE ([678])\./);
    -  ieVersion = ieVersion ? +ieVersion[1] : false;
    -  window['_pr_isIE6'] = function () { return ieVersion; };
    -  return ieVersion;
    -};
    -
    -
    -(function () {
    -  // Keyword lists for various languages.
    -  var FLOW_CONTROL_KEYWORDS =
    -      "break continue do else for if return while ";
    -  var C_KEYWORDS = FLOW_CONTROL_KEYWORDS + "auto case char const default " +
    -      "double enum extern float goto int long register short signed sizeof " +
    -      "static struct switch typedef union unsigned void volatile ";
    -  var COMMON_KEYWORDS = C_KEYWORDS + "catch class delete false import " +
    -      "new operator private protected public this throw true try typeof ";
    -  var CPP_KEYWORDS = COMMON_KEYWORDS + "alignof align_union asm axiom bool " +
    -      "concept concept_map const_cast constexpr decltype " +
    -      "dynamic_cast explicit export friend inline late_check " +
    -      "mutable namespace nullptr reinterpret_cast static_assert static_cast " +
    -      "template typeid typename using virtual wchar_t where ";
    -  var JAVA_KEYWORDS = COMMON_KEYWORDS +
    -      "abstract boolean byte extends final finally implements import " +
    -      "instanceof null native package strictfp super synchronized throws " +
    -      "transient ";
    -  var CSHARP_KEYWORDS = JAVA_KEYWORDS +
    -      "as base by checked decimal delegate descending event " +
    -      "fixed foreach from group implicit in interface internal into is lock " +
    -      "object out override orderby params partial readonly ref sbyte sealed " +
    -      "stackalloc string select uint ulong unchecked unsafe ushort var ";
    -  var JSCRIPT_KEYWORDS = COMMON_KEYWORDS +
    -      "debugger eval export function get null set undefined var with " +
    -      "Infinity NaN ";
    -  var PERL_KEYWORDS = "caller delete die do dump elsif eval exit foreach for " +
    -      "goto if import last local my next no our print package redo require " +
    -      "sub undef unless until use wantarray while BEGIN END ";
    -  var PYTHON_KEYWORDS = FLOW_CONTROL_KEYWORDS + "and as assert class def del " +
    -      "elif except exec finally from global import in is lambda " +
    -      "nonlocal not or pass print raise try with yield " +
    -      "False True None ";
    -  var RUBY_KEYWORDS = FLOW_CONTROL_KEYWORDS + "alias and begin case class def" +
    -      " defined elsif end ensure false in module next nil not or redo rescue " +
    -      "retry self super then true undef unless until when yield BEGIN END ";
    -  var SH_KEYWORDS = FLOW_CONTROL_KEYWORDS + "case done elif esac eval fi " +
    -      "function in local set then until ";
    -  var ALL_KEYWORDS = (
    -      CPP_KEYWORDS + CSHARP_KEYWORDS + JSCRIPT_KEYWORDS + PERL_KEYWORDS +
    -      PYTHON_KEYWORDS + RUBY_KEYWORDS + SH_KEYWORDS);
    -
    -  // token style names.  correspond to css classes
    -  /** token style for PHP variables */
    -  var PR_VAR = 'vr';
    -  /** token style for a string literal */
    -  var PR_STRING = 'str';
    -  /** token style for a keyword */
    -  var PR_KEYWORD = 'kwd';
    -  /** token style for a comment */
    -  var PR_COMMENT = 'com';
    -  /** token style for a type */
    -  var PR_TYPE = 'typ';
    -  /** token style for a literal value.  e.g. 1, null, true. */
    -  var PR_LITERAL = 'lit';
    -  /** token style for a punctuation string. */
    -  var PR_PUNCTUATION = 'pun';
    -  /** token style for a punctuation string. */
    -  var PR_PLAIN = 'pln';
    -
    -  /** token style for an sgml tag. */
    -  var PR_TAG = 'tag';
    -  /** token style for a markup declaration such as a DOCTYPE. */
    -  var PR_DECLARATION = 'dec';
    -  /** token style for embedded source. */
    -  var PR_SOURCE = 'src';
    -  /** token style for an sgml attribute name. */
    -  var PR_ATTRIB_NAME = 'atn';
    -  /** token style for an sgml attribute value. */
    -  var PR_ATTRIB_VALUE = 'atv';
    -
    -  /**
    -   * A class that indicates a section of markup that is not code, e.g. to allow
    -   * embedding of line numbers within code listings.
    -   */
    -  var PR_NOCODE = 'nocode';
    -
    -  /** A set of tokens that can precede a regular expression literal in
    -    * javascript.
    -    * http://www.mozilla.org/js/language/js20/rationale/syntax.html has the full
    -    * list, but I've removed ones that might be problematic when seen in
    -    * languages that don't support regular expression literals.
    -    *
    -    * <p>Specifically, I've removed any keywords that can't precede a regexp
    -    * literal in a syntactically legal javascript program, and I've removed the
    -    * "in" keyword since it's not a keyword in many languages, and might be used
    -    * as a count of inches.
    -    *
    -    * <p>The link a above does not accurately describe EcmaScript rules since
    -    * it fails to distinguish between (a=++/b/i) and (a++/b/i) but it works
    -    * very well in practice.
    -    *
    -    * @private
    -    */
    -  var REGEXP_PRECEDER_PATTERN = function () {
    -      var preceders = [
    -          "!", "!=", "!==", "#", "%", "%=", "&", "&&", "&&=",
    -          "&=", "(", "*", "*=", /* "+", */ "+=", ",", /* "-", */ "-=",
    -          "->", /*".", "..", "...", handled below */ "/", "/=", ":", "::", ";",
    -          "<", "<<", "<<=", "<=", "=", "==", "===", ">",
    -          ">=", ">>", ">>=", ">>>", ">>>=", "?", "@", "[",
    -          "^", "^=", "^^", "^^=", "{", "|", "|=", "||",
    -          "||=", "~" /* handles =~ and !~ */,
    -          "break", "case", "continue", "delete",
    -          "do", "else", "finally", "instanceof",
    -          "return", "throw", "try", "typeof"
    -          ];
    -      var pattern = '(?:^^|[+-]';
    -      for (var i = 0; i < preceders.length; ++i) {
    -        pattern += '|' + preceders[i].replace(/([^=<>:&a-z])/g, '\\$1');
    -      }
    -      pattern += ')\\s*';  // matches at end, and matches empty string
    -      return pattern;
    -      // CAVEAT: this does not properly handle the case where a regular
    -      // expression immediately follows another since a regular expression may
    -      // have flags for case-sensitivity and the like.  Having regexp tokens
    -      // adjacent is not valid in any language I'm aware of, so I'm punting.
    -      // TODO: maybe style special characters inside a regexp as punctuation.
    -    }();
    -
    -  // Define regexps here so that the interpreter doesn't have to create an
    -  // object each time the function containing them is called.
    -  // The language spec requires a new object created even if you don't access
    -  // the $1 members.
    -  var pr_amp = /&/g;
    -  var pr_lt = /</g;
    -  var pr_gt = />/g;
    -  var pr_quot = /\"/g;
    -  /** like textToHtml but escapes double quotes to be attribute safe. */
    -  function attribToHtml(str) {
    -    return str.replace(pr_amp, '&amp;')
    -        .replace(pr_lt, '&lt;')
    -        .replace(pr_gt, '&gt;')
    -        .replace(pr_quot, '&quot;');
    -  }
    -
    -  /** escapest html special characters to html. */
    -  function textToHtml(str) {
    -    return str.replace(pr_amp, '&amp;')
    -        .replace(pr_lt, '&lt;')
    -        .replace(pr_gt, '&gt;');
    -  }
    -
    -
    -  var pr_ltEnt = /&lt;/g;
    -  var pr_gtEnt = /&gt;/g;
    -  var pr_aposEnt = /&apos;/g;
    -  var pr_quotEnt = /&quot;/g;
    -  var pr_ampEnt = /&amp;/g;
    -  var pr_nbspEnt = /&nbsp;/g;
    -  /** unescapes html to plain text. */
    -  function htmlToText(html) {
    -    var pos = html.indexOf('&');
    -    if (pos < 0) { return html; }
    -    // Handle numeric entities specially.  We can't use functional substitution
    -    // since that doesn't work in older versions of Safari.
    -    // These should be rare since most browsers convert them to normal chars.
    -    for (--pos; (pos = html.indexOf('&#', pos + 1)) >= 0;) {
    -      var end = html.indexOf(';', pos);
    -      if (end >= 0) {
    -        var num = html.substring(pos + 3, end);
    -        var radix = 10;
    -        if (num && num.charAt(0) === 'x') {
    -          num = num.substring(1);
    -          radix = 16;
    -        }
    -        var codePoint = parseInt(num, radix);
    -        if (!isNaN(codePoint)) {
    -          html = (html.substring(0, pos) + String.fromCharCode(codePoint) +
    -                  html.substring(end + 1));
    -        }
    -      }
    -    }
    -
    -    return html.replace(pr_ltEnt, '<')
    -        .replace(pr_gtEnt, '>')
    -        .replace(pr_aposEnt, "'")
    -        .replace(pr_quotEnt, '"')
    -        .replace(pr_nbspEnt, ' ')
    -        .replace(pr_ampEnt, '&');
    -  }
    -
    -  /** is the given node's innerHTML normally unescaped? */
    -  function isRawContent(node) {
    -    return 'XMP' === node.tagName;
    -  }
    -
    -  var newlineRe = /[\r\n]/g;
    -  /**
    -   * Are newlines and adjacent spaces significant in the given node's innerHTML?
    -   */
    -  function isPreformatted(node, content) {
    -    // PRE means preformatted, and is a very common case, so don't create
    -    // unnecessary computed style objects.
    -    if ('PRE' === node.tagName) { return true; }
    -    if (!newlineRe.test(content)) { return true; }  // Don't care
    -    var whitespace = '';
    -    // For disconnected nodes, IE has no currentStyle.
    -    if (node.currentStyle) {
    -      whitespace = node.currentStyle.whiteSpace;
    -    } else if (window.getComputedStyle) {
    -      // Firefox makes a best guess if node is disconnected whereas Safari
    -      // returns the empty string.
    -      whitespace = window.getComputedStyle(node, null).whiteSpace;
    -    }
    -    return !whitespace || whitespace === 'pre';
    -  }
    -
    -  function normalizedHtml(node, out, opt_sortAttrs) {
    -    switch (node.nodeType) {
    -      case 1:  // an element
    -        var name = node.tagName.toLowerCase();
    -
    -        out.push('<', name);
    -        var attrs = node.attributes;
    -        var n = attrs.length;
    -        if (n) {
    -          if (opt_sortAttrs) {
    -            var sortedAttrs = [];
    -            for (var i = n; --i >= 0;) { sortedAttrs[i] = attrs[i]; }
    -            sortedAttrs.sort(function (a, b) {
    -                return (a.name < b.name) ? -1 : a.name === b.name ? 0 : 1;
    -              });
    -            attrs = sortedAttrs;
    -          }
    -          for (var i = 0; i < n; ++i) {
    -            var attr = attrs[i];
    -            if (!attr.specified) { continue; }
    -            out.push(' ', attr.name.toLowerCase(),
    -                     '="', attribToHtml(attr.value), '"');
    -          }
    -        }
    -        out.push('>');
    -        for (var child = node.firstChild; child; child = child.nextSibling) {
    -          normalizedHtml(child, out, opt_sortAttrs);
    -        }
    -        if (node.firstChild || !/^(?:br|link|img)$/.test(name)) {
    -          out.push('<\/', name, '>');
    -        }
    -        break;
    -      case 3: case 4: // text
    -        out.push(textToHtml(node.nodeValue));
    -        break;
    -    }
    -  }
    -
    -  /**
    -   * Given a group of {@link RegExp}s, returns a {@code RegExp} that globally
    -   * matches the union o the sets o strings matched d by the input RegExp.
    -   * Since it matches globally, if the input strings have a start-of-input
    -   * anchor (/^.../), it is ignored for the purposes of unioning.
    -   * @param {Array.<RegExp>} regexs non multiline, non-global regexs.
    -   * @return {RegExp} a global regex.
    -   */
    -  function combinePrefixPatterns(regexs) {
    -    var capturedGroupIndex = 0;
    -
    -    var needToFoldCase = false;
    -    var ignoreCase = false;
    -    for (var i = 0, n = regexs.length; i < n; ++i) {
    -      var regex = regexs[i];
    -      if (regex.ignoreCase) {
    -        ignoreCase = true;
    -      } else if (/[a-z]/i.test(regex.source.replace(
    -                     /\\u[0-9a-f]{4}|\\x[0-9a-f]{2}|\\[^ux]/gi, ''))) {
    -        needToFoldCase = true;
    -        ignoreCase = false;
    -        break;
    -      }
    -    }
    -
    -    function decodeEscape(charsetPart) {
    -      if (charsetPart.charAt(0) !== '\\') { return charsetPart.charCodeAt(0); }
    -      switch (charsetPart.charAt(1)) {
    -        case 'b': return 8;
    -        case 't': return 9;
    -        case 'n': return 0xa;
    -        case 'v': return 0xb;
    -        case 'f': return 0xc;
    -        case 'r': return 0xd;
    -        case 'u': case 'x':
    -          return parseInt(charsetPart.substring(2), 16)
    -              || charsetPart.charCodeAt(1);
    -        case '0': case '1': case '2': case '3': case '4':
    -        case '5': case '6': case '7':
    -          return parseInt(charsetPart.substring(1), 8);
    -        default: return charsetPart.charCodeAt(1);
    -      }
    -    }
    -
    -    function encodeEscape(charCode) {
    -      if (charCode < 0x20) {
    -        return (charCode < 0x10 ? '\\x0' : '\\x') + charCode.toString(16);
    -      }
    -      var ch = String.fromCharCode(charCode);
    -      if (ch === '\\' || ch === '-' || ch === '[' || ch === ']') {
    -        ch = '\\' + ch;
    -      }
    -      return ch;
    -    }
    -
    -    function caseFoldCharset(charSet) {
    -      var charsetParts = charSet.substring(1, charSet.length - 1).match(
    -          new RegExp(
    -              '\\\\u[0-9A-Fa-f]{4}'
    -              + '|\\\\x[0-9A-Fa-f]{2}'
    -              + '|\\\\[0-3][0-7]{0,2}'
    -              + '|\\\\[0-7]{1,2}'
    -              + '|\\\\[\\s\\S]'
    -              + '|-'
    -              + '|[^-\\\\]',
    -              'g'));
    -      var groups = [];
    -      var ranges = [];
    -      var inverse = charsetParts[0] === '^';
    -      for (var i = inverse ? 1 : 0, n = charsetParts.length; i < n; ++i) {
    -        var p = charsetParts[i];
    -        switch (p) {
    -          case '\\B': case '\\b':
    -          case '\\D': case '\\d':
    -          case '\\S': case '\\s':
    -          case '\\W': case '\\w':
    -            groups.push(p);
    -            continue;
    -        }
    -        var start = decodeEscape(p);
    -        var end;
    -        if (i + 2 < n && '-' === charsetParts[i + 1]) {
    -          end = decodeEscape(charsetParts[i + 2]);
    -          i += 2;
    -        } else {
    -          end = start;
    -        }
    -        ranges.push([start, end]);
    -        // If the range might intersect letters, then expand it.
    -        if (!(end < 65 || start > 122)) {
    -          if (!(end < 65 || start > 90)) {
    -            ranges.push([Math.max(65, start) | 32, Math.min(end, 90) | 32]);
    -          }
    -          if (!(end < 97 || start > 122)) {
    -            ranges.push([Math.max(97, start) & ~32, Math.min(end, 122) & ~32]);
    -          }
    -        }
    -      }
    -
    -      // [[1, 10], [3, 4], [8, 12], [14, 14], [16, 16], [17, 17]]
    -      // -> [[1, 12], [14, 14], [16, 17]]
    -      ranges.sort(function (a, b) { return (a[0] - b[0]) || (b[1]  - a[1]); });
    -      var consolidatedRanges = [];
    -      var lastRange = [NaN, NaN];
    -      for (var i = 0; i < ranges.length; ++i) {
    -        var range = ranges[i];
    -        if (range[0] <= lastRange[1] + 1) {
    -          lastRange[1] = Math.max(lastRange[1], range[1]);
    -        } else {
    -          consolidatedRanges.push(lastRange = range);
    -        }
    -      }
    -
    -      var out = ['['];
    -      if (inverse) { out.push('^'); }
    -      out.push.apply(out, groups);
    -      for (var i = 0; i < consolidatedRanges.length; ++i) {
    -        var range = consolidatedRanges[i];
    -        out.push(encodeEscape(range[0]));
    -        if (range[1] > range[0]) {
    -          if (range[1] + 1 > range[0]) { out.push('-'); }
    -          out.push(encodeEscape(range[1]));
    -        }
    -      }
    -      out.push(']');
    -      return out.join('');
    -    }
    -
    -    function allowAnywhereFoldCaseAndRenumberGroups(regex) {
    -      // Split into character sets, escape sequences, punctuation strings
    -      // like ('(', '(?:', ')', '^'), and runs of characters that do not
    -      // include any of the above.
    -      var parts = regex.source.match(
    -          new RegExp(
    -              '(?:'
    -              + '\\[(?:[^\\x5C\\x5D]|\\\\[\\s\\S])*\\]'  // a character set
    -              + '|\\\\u[A-Fa-f0-9]{4}'  // a unicode escape
    -              + '|\\\\x[A-Fa-f0-9]{2}'  // a hex escape
    -              + '|\\\\[0-9]+'  // a back-reference or octal escape
    -              + '|\\\\[^ux0-9]'  // other escape sequence
    -              + '|\\(\\?[:!=]'  // start of a non-capturing group
    -              + '|[\\(\\)\\^]'  // start/emd of a group, or line start
    -              + '|[^\\x5B\\x5C\\(\\)\\^]+'  // run of other characters
    -              + ')',
    -              'g'));
    -      var n = parts.length;
    -
    -      // Maps captured group numbers to the number they will occupy in
    -      // the output or to -1 if that has not been determined, or to
    -      // undefined if they need not be capturing in the output.
    -      var capturedGroups = [];
    -
    -      // Walk over and identify back references to build the capturedGroups
    -      // mapping.
    -      for (var i = 0, groupIndex = 0; i < n; ++i) {
    -        var p = parts[i];
    -        if (p === '(') {
    -          // groups are 1-indexed, so max group index is count of '('
    -          ++groupIndex;
    -        } else if ('\\' === p.charAt(0)) {
    -          var decimalValue = +p.substring(1);
    -          if (decimalValue && decimalValue <= groupIndex) {
    -            capturedGroups[decimalValue] = -1;
    -          }
    -        }
    -      }
    -
    -      // Renumber groups and reduce capturing groups to non-capturing groups
    -      // where possible.
    -      for (var i = 1; i < capturedGroups.length; ++i) {
    -        if (-1 === capturedGroups[i]) {
    -          capturedGroups[i] = ++capturedGroupIndex;
    -        }
    -      }
    -      for (var i = 0, groupIndex = 0; i < n; ++i) {
    -        var p = parts[i];
    -        if (p === '(') {
    -          ++groupIndex;
    -          if (capturedGroups[groupIndex] === undefined) {
    -            parts[i] = '(?:';
    -          }
    -        } else if ('\\' === p.charAt(0)) {
    -          var decimalValue = +p.substring(1);
    -          if (decimalValue && decimalValue <= groupIndex) {
    -            parts[i] = '\\' + capturedGroups[groupIndex];
    -          }
    -        }
    -      }
    -
    -      // Remove any prefix anchors so that the output will match anywhere.
    -      // ^^ really does mean an anchored match though.
    -      for (var i = 0, groupIndex = 0; i < n; ++i) {
    -        if ('^' === parts[i] && '^' !== parts[i + 1]) { parts[i] = ''; }
    -      }
    -
    -      // Expand letters to groupts to handle mixing of case-sensitive and
    -      // case-insensitive patterns if necessary.
    -      if (regex.ignoreCase && needToFoldCase) {
    -        for (var i = 0; i < n; ++i) {
    -          var p = parts[i];
    -          var ch0 = p.charAt(0);
    -          if (p.length >= 2 && ch0 === '[') {
    -            parts[i] = caseFoldCharset(p);
    -          } else if (ch0 !== '\\') {
    -            // TODO: handle letters in numeric escapes.
    -            parts[i] = p.replace(
    -                /[a-zA-Z]/g,
    -                function (ch) {
    -                  var cc = ch.charCodeAt(0);
    -                  return '[' + String.fromCharCode(cc & ~32, cc | 32) + ']';
    -                });
    -          }
    -        }
    -      }
    -
    -      return parts.join('');
    -    }
    -
    -    var rewritten = [];
    -    for (var i = 0, n = regexs.length; i < n; ++i) {
    -      var regex = regexs[i];
    -      if (regex.global || regex.multiline) { throw new Error('' + regex); }
    -      rewritten.push(
    -          '(?:' + allowAnywhereFoldCaseAndRenumberGroups(regex) + ')');
    -    }
    -
    -    return new RegExp(rewritten.join('|'), ignoreCase ? 'gi' : 'g');
    -  }
    -
    -  var PR_innerHtmlWorks = null;
    -  function getInnerHtml(node) {
    -    // inner html is hopelessly broken in Safari 2.0.4 when the content is
    -    // an html description of well formed XML and the containing tag is a PRE
    -    // tag, so we detect that case and emulate innerHTML.
    -    if (null === PR_innerHtmlWorks) {
    -      var testNode = document.createElement('PRE');
    -      testNode.appendChild(
    -          document.createTextNode('<!DOCTYPE foo PUBLIC "foo bar">\n<foo />'));
    -      PR_innerHtmlWorks = !/</.test(testNode.innerHTML);
    -    }
    -
    -    if (PR_innerHtmlWorks) {
    -      var content = node.innerHTML;
    -      // XMP tags contain unescaped entities so require special handling.
    -      if (isRawContent(node)) {
    -        content = textToHtml(content);
    -      } else if (!isPreformatted(node, content)) {
    -        content = content.replace(/(<br\s*\/?>)[\r\n]+/g, '$1')
    -            .replace(/(?:[\r\n]+[ \t]*)+/g, ' ');
    -      }
    -      return content;
    -    }
    -
    -    var out = [];
    -    for (var child = node.firstChild; child; child = child.nextSibling) {
    -      normalizedHtml(child, out);
    -    }
    -    return out.join('');
    -  }
    -
    -  /** returns a function that expand tabs to spaces.  This function can be fed
    -    * successive chunks of text, and will maintain its own internal state to
    -    * keep track of how tabs are expanded.
    -    * @return {function (string) : string} a function that takes
    -    *   plain text and return the text with tabs expanded.
    -    * @private
    -    */
    -  function makeTabExpander(tabWidth) {
    -    var SPACES = '                ';
    -    var charInLine = 0;
    -
    -    return function (plainText) {
    -      // walk over each character looking for tabs and newlines.
    -      // On tabs, expand them.  On newlines, reset charInLine.
    -      // Otherwise increment charInLine
    -      var out = null;
    -      var pos = 0;
    -      for (var i = 0, n = plainText.length; i < n; ++i) {
    -        var ch = plainText.charAt(i);
    -
    -        switch (ch) {
    -          case '\t':
    -            if (!out) { out = []; }
    -            out.push(plainText.substring(pos, i));
    -            // calculate how much space we need in front of this part
    -            // nSpaces is the amount of padding -- the number of spaces needed
    -            // to move us to the next column, where columns occur at factors of
    -            // tabWidth.
    -            var nSpaces = tabWidth - (charInLine % tabWidth);
    -            charInLine += nSpaces;
    -            for (; nSpaces >= 0; nSpaces -= SPACES.length) {
    -              out.push(SPACES.substring(0, nSpaces));
    -            }
    -            pos = i + 1;
    -            break;
    -          case '\n':
    -            charInLine = 0;
    -            break;
    -          default:
    -            ++charInLine;
    -        }
    -      }
    -      if (!out) { return plainText; }
    -      out.push(plainText.substring(pos));
    -      return out.join('');
    -    };
    -  }
    -
    -  var pr_chunkPattern = new RegExp(
    -      '[^<]+'  // A run of characters other than '<'
    -      + '|<\!--[\\s\\S]*?--\>'  // an HTML comment
    -      + '|<!\\[CDATA\\[[\\s\\S]*?\\]\\]>'  // a CDATA section
    -      // a probable tag that should not be highlighted
    -      + '|<\/?[a-zA-Z](?:[^>\"\']|\'[^\']*\'|\"[^\"]*\")*>'
    -      + '|<',  // A '<' that does not begin a larger chunk
    -      'g');
    -  var pr_commentPrefix = /^<\!--/;
    -  var pr_cdataPrefix = /^<!\[CDATA\[/;
    -  var pr_brPrefix = /^<br\b/i;
    -  var pr_tagNameRe = /^<(\/?)([a-zA-Z][a-zA-Z0-9]*)/;
    -
    -  /** split markup into chunks of html tags (style null) and
    -    * plain text (style {@link #PR_PLAIN}), converting tags which are
    -    * significant for tokenization (<br>) into their textual equivalent.
    -    *
    -    * @param {string} s html where whitespace is considered significant.
    -    * @return {Object} source code and extracted tags.
    -    * @private
    -    */
    -  function extractTags(s) {
    -    // since the pattern has the 'g' modifier and defines no capturing groups,
    -    // this will return a list of all chunks which we then classify and wrap as
    -    // PR_Tokens
    -    var matches = s.match(pr_chunkPattern);
    -    var sourceBuf = [];
    -    var sourceBufLen = 0;
    -    var extractedTags = [];
    -    if (matches) {
    -      for (var i = 0, n = matches.length; i < n; ++i) {
    -        var match = matches[i];
    -        if (match.length > 1 && match.charAt(0) === '<') {
    -          if (pr_commentPrefix.test(match)) { continue; }
    -          if (pr_cdataPrefix.test(match)) {
    -            // strip CDATA prefix and suffix.  Don't unescape since it's CDATA
    -            sourceBuf.push(match.substring(9, match.length - 3));
    -            sourceBufLen += match.length - 12;
    -          } else if (pr_brPrefix.test(match)) {
    -            // <br> tags are lexically significant so convert them to text.
    -            // This is undone later.
    -            sourceBuf.push('\n');
    -            ++sourceBufLen;
    -          } else {
    -            if (match.indexOf(PR_NOCODE) >= 0 && isNoCodeTag(match)) {
    -              // A <span class="nocode"> will start a section that should be
    -              // ignored.  Continue walking the list until we see a matching end
    -              // tag.
    -              var name = match.match(pr_tagNameRe)[2];
    -              var depth = 1;
    -              var j;
    -              end_tag_loop:
    -              for (j = i + 1; j < n; ++j) {
    -                var name2 = matches[j].match(pr_tagNameRe);
    -                if (name2 && name2[2] === name) {
    -                  if (name2[1] === '/') {
    -                    if (--depth === 0) { break end_tag_loop; }
    -                  } else {
    -                    ++depth;
    -                  }
    -                }
    -              }
    -              if (j < n) {
    -                extractedTags.push(
    -                    sourceBufLen, matches.slice(i, j + 1).join(''));
    -                i = j;
    -              } else {  // Ignore unclosed sections.
    -                extractedTags.push(sourceBufLen, match);
    -              }
    -            } else {
    -              extractedTags.push(sourceBufLen, match);
    -            }
    -          }
    -        } else {
    -          var literalText = htmlToText(match);
    -          sourceBuf.push(literalText);
    -          sourceBufLen += literalText.length;
    -        }
    -      }
    -    }
    -    return { source: sourceBuf.join(''), tags: extractedTags };
    -  }
    -
    -  /** True if the given tag contains a class attribute with the nocode class. */
    -  function isNoCodeTag(tag) {
    -    return !!tag
    -        // First canonicalize the representation of attributes
    -        .replace(/\s(\w+)\s*=\s*(?:\"([^\"]*)\"|'([^\']*)'|(\S+))/g,
    -                 ' $1="$2$3$4"')
    -        // Then look for the attribute we want.
    -        .match(/[cC][lL][aA][sS][sS]=\"[^\"]*\bnocode\b/);
    -  }
    -
    -  /**
    -   * Apply the given language handler to sourceCode and add the resulting
    -   * decorations to out.
    -   * @param {number} basePos the index of sourceCode within the chunk of source
    -   *    whose decorations are already present on out.
    -   */
    -  function appendDecorations(basePos, sourceCode, langHandler, out) {
    -    if (!sourceCode) { return; }
    -    var job = {
    -      source: sourceCode,
    -      basePos: basePos
    -    };
    -    langHandler(job);
    -    out.push.apply(out, job.decorations);
    -  }
    -
    -  /** Given triples of [style, pattern, context] returns a lexing function,
    -    * The lexing function interprets the patterns to find token boundaries and
    -    * returns a decoration list of the form
    -    * [index_0, style_0, index_1, style_1, ..., index_n, style_n]
    -    * where index_n is an index into the sourceCode, and style_n is a style
    -    * constant like PR_PLAIN.  index_n-1 <= index_n, and style_n-1 applies to
    -    * all characters in sourceCode[index_n-1:index_n].
    -    *
    -    * The stylePatterns is a list whose elements have the form
    -    * [style : string, pattern : RegExp, DEPRECATED, shortcut : string].
    -    *
    -    * Style is a style constant like PR_PLAIN, or can be a string of the
    -    * form 'lang-FOO', where FOO is a language extension describing the
    -    * language of the portion of the token in $1 after pattern executes.
    -    * E.g., if style is 'lang-lisp', and group 1 contains the text
    -    * '(hello (world))', then that portion of the token will be passed to the
    -    * registered lisp handler for formatting.
    -    * The text before and after group 1 will be restyled using this decorator
    -    * so decorators should take care that this doesn't result in infinite
    -    * recursion.  For example, the HTML lexer rule for SCRIPT elements looks
    -    * something like ['lang-js', /<[s]cript>(.+?)<\/script>/].  This may match
    -    * '<script>foo()<\/script>', which would cause the current decorator to
    -    * be called with '<script>' which would not match the same rule since
    -    * group 1 must not be empty, so it would be instead styled as PR_TAG by
    -    * the generic tag rule.  The handler registered for the 'js' extension would
    -    * then be called with 'foo()', and finally, the current decorator would
    -    * be called with '<\/script>' which would not match the original rule and
    -    * so the generic tag rule would identify it as a tag.
    -    *
    -    * Pattern must only match prefixes, and if it matches a prefix, then that
    -    * match is considered a token with the same style.
    -    *
    -    * Context is applied to the last non-whitespace, non-comment token
    -    * recognized.
    -    *
    -    * Shortcut is an optional string of characters, any of which, if the first
    -    * character, gurantee that this pattern and only this pattern matches.
    -    *
    -    * @param {Array} shortcutStylePatterns patterns that always start with
    -    *   a known character.  Must have a shortcut string.
    -    * @param {Array} fallthroughStylePatterns patterns that will be tried in
    -    *   order if the shortcut ones fail.  May have shortcuts.
    -    *
    -    * @return {function (Object)} a
    -    *   function that takes source code and returns a list of decorations.
    -    */
    -  function createSimpleLexer(shortcutStylePatterns, fallthroughStylePatterns) {
    -    var shortcuts = {};
    -    var tokenizer;
    -    (function () {
    -      var allPatterns = shortcutStylePatterns.concat(fallthroughStylePatterns);
    -      var allRegexs = [];
    -      var regexKeys = {};
    -      for (var i = 0, n = allPatterns.length; i < n; ++i) {
    -        var patternParts = allPatterns[i];
    -        var shortcutChars = patternParts[3];
    -        if (shortcutChars) {
    -          for (var c = shortcutChars.length; --c >= 0;) {
    -            shortcuts[shortcutChars.charAt(c)] = patternParts;
    -          }
    -        }
    -        var regex = patternParts[1];
    -        var k = '' + regex;
    -        if (!regexKeys.hasOwnProperty(k)) {
    -          allRegexs.push(regex);
    -          regexKeys[k] = null;
    -        }
    -      }
    -      allRegexs.push(/[\0-\uffff]/);
    -      tokenizer = combinePrefixPatterns(allRegexs);
    -    })();
    -
    -    var nPatterns = fallthroughStylePatterns.length;
    -    var notWs = /\S/;
    -
    -    /**
    -     * Lexes job.source and produces an output array job.decorations of style
    -     * classes preceded by the position at which they start in job.source in
    -     * order.
    -     *
    -     * @param {Object} job an object like {@code
    -     *    source: {string} sourceText plain text,
    -     *    basePos: {int} position of job.source in the larger chunk of
    -     *        sourceCode.
    -     * }
    -     */
    -    var decorate = function (job) {
    -      var sourceCode = job.source, basePos = job.basePos;
    -      /** Even entries are positions in source in ascending order.  Odd enties
    -        * are style markers (e.g., PR_COMMENT) that run from that position until
    -        * the end.
    -        * @type {Array.<number|string>}
    -        */
    -      var decorations = [basePos, PR_PLAIN];
    -      var pos = 0;  // index into sourceCode
    -      var tokens = sourceCode.match(tokenizer) || [];
    -      var styleCache = {};
    -
    -      for (var ti = 0, nTokens = tokens.length; ti < nTokens; ++ti) {
    -        var token = tokens[ti];
    -        var style = styleCache[token];
    -        var match = void 0;
    -
    -        var isEmbedded;
    -        if (typeof style === 'string') {
    -          isEmbedded = false;
    -        } else {
    -          var patternParts = shortcuts[token.charAt(0)];
    -          if (patternParts) {
    -            match = token.match(patternParts[1]);
    -            style = patternParts[0];
    -          } else {
    -            for (var i = 0; i < nPatterns; ++i) {
    -              patternParts = fallthroughStylePatterns[i];
    -              match = token.match(patternParts[1]);
    -              if (match) {
    -                style = patternParts[0];
    -                break;
    -              }
    -            }
    -
    -            if (!match) {  // make sure that we make progress
    -              style = PR_PLAIN;
    -            }
    -          }
    -
    -          isEmbedded = style.length >= 5 && 'lang-' === style.substring(0, 5);
    -          if (isEmbedded && !(match && typeof match[1] === 'string')) {
    -            isEmbedded = false;
    -            style = PR_SOURCE;
    -          }
    -
    -          if (!isEmbedded) { styleCache[token] = style; }
    -        }
    -
    -        var tokenStart = pos;
    -        pos += token.length;
    -
    -        if (!isEmbedded) {
    -          decorations.push(basePos + tokenStart, style);
    -        } else {  // Treat group 1 as an embedded block of source code.
    -          var embeddedSource = match[1];
    -          var embeddedSourceStart = token.indexOf(embeddedSource);
    -          var embeddedSourceEnd = embeddedSourceStart + embeddedSource.length;
    -          if (match[2]) {
    -            // If embeddedSource can be blank, then it would match at the
    -            // beginning which would cause us to infinitely recurse on the
    -            // entire token, so we catch the right context in match[2].
    -            embeddedSourceEnd = token.length - match[2].length;
    -            embeddedSourceStart = embeddedSourceEnd - embeddedSource.length;
    -          }
    -          var lang = style.substring(5);
    -          // Decorate the left of the embedded source
    -          appendDecorations(
    -              basePos + tokenStart,
    -              token.substring(0, embeddedSourceStart),
    -              decorate, decorations);
    -          // Decorate the embedded source
    -          appendDecorations(
    -              basePos + tokenStart + embeddedSourceStart,
    -              embeddedSource,
    -              langHandlerForExtension(lang, embeddedSource),
    -              decorations);
    -          // Decorate the right of the embedded section
    -          appendDecorations(
    -              basePos + tokenStart + embeddedSourceEnd,
    -              token.substring(embeddedSourceEnd),
    -              decorate, decorations);
    -        }
    -      }
    -      job.decorations = decorations;
    -    };
    -    return decorate;
    -  }
    -
    -  /** returns a function that produces a list of decorations from source text.
    -    *
    -    * This code treats ", ', and ` as string delimiters, and \ as a string
    -    * escape.  It does not recognize perl's qq() style strings.
    -    * It has no special handling for double delimiter escapes as in basic, or
    -    * the tripled delimiters used in python, but should work on those regardless
    -    * although in those cases a single string literal may be broken up into
    -    * multiple adjacent string literals.
    -    *
    -    * It recognizes C, C++, and shell style comments.
    -    *
    -    * @param {Object} options a set of optional parameters.
    -    * @return {function (Object)} a function that examines the source code
    -    *     in the input job and builds the decoration list.
    -    */
    -  function sourceDecorator(options) {
    -    var shortcutStylePatterns = [], fallthroughStylePatterns = [];
    -    if (options['tripleQuotedStrings']) {
    -      // '''multi-line-string''', 'single-line-string', and double-quoted
    -      shortcutStylePatterns.push(
    -          [PR_STRING,  /^(?:\'\'\'(?:[^\'\\]|\\[\s\S]|\'{1,2}(?=[^\']))*(?:\'\'\'|$)|\"\"\"(?:[^\"\\]|\\[\s\S]|\"{1,2}(?=[^\"]))*(?:\"\"\"|$)|\'(?:[^\\\']|\\[\s\S])*(?:\'|$)|\"(?:[^\\\"]|\\[\s\S])*(?:\"|$))/,
    -           null, '\'"']);
    -    } else if (options['multiLineStrings']) {
    -      // 'multi-line-string', "multi-line-string"
    -      shortcutStylePatterns.push(
    -          [PR_STRING,  /^(?:\'(?:[^\\\']|\\[\s\S])*(?:\'|$)|\"(?:[^\\\"]|\\[\s\S])*(?:\"|$)|\`(?:[^\\\`]|\\[\s\S])*(?:\`|$))/,
    -           null, '\'"`']);
    -    } else {
    -      // 'single-line-string', "single-line-string"
    -      shortcutStylePatterns.push(
    -          [PR_STRING,
    -           /^(?:\'(?:[^\\\'\r\n]|\\.)*(?:\'|$)|\"(?:[^\\\"\r\n]|\\.)*(?:\"|$))/,
    -           null, '"\'']);
    -    }
    -    if (options['verbatimStrings']) {
    -      // verbatim-string-literal production from the C# grammar.  See issue 93.
    -      fallthroughStylePatterns.push(
    -          [PR_STRING, /^@\"(?:[^\"]|\"\")*(?:\"|$)/, null]);
    -    }
    -    if (options['hashComments']) {
    -      if (options['cStyleComments']) {
    -        // Stop C preprocessor declarations at an unclosed open comment
    -        shortcutStylePatterns.push(
    -            [PR_COMMENT, /^#(?:(?:define|elif|else|endif|error|ifdef|include|ifndef|line|pragma|undef|warning)\b|[^\r\n]*)/,
    -             null, '#']);
    -        fallthroughStylePatterns.push(
    -            [PR_STRING,
    -             /^<(?:(?:(?:\.\.\/)*|\/?)(?:[\w-]+(?:\/[\w-]+)+)?[\w-]+\.h|[a-z]\w*)>/,
    -             null]);
    -      } else {
    -        shortcutStylePatterns.push([PR_COMMENT, /^#[^\r\n]*/, null, '#']);
    -      }
    -    }
    -    if (options['cStyleComments']) {
    -      fallthroughStylePatterns.push([PR_COMMENT, /^\/\/[^\r\n]*/, null]);
    -      fallthroughStylePatterns.push(
    -          [PR_COMMENT, /^\/\*[\s\S]*?(?:\*\/|$)/, null]);
    -    }
    -    if (options['regexLiterals']) {
    -      var REGEX_LITERAL = (
    -          // A regular expression literal starts with a slash that is
    -          // not followed by * or / so that it is not confused with
    -          // comments.
    -          '/(?=[^/*])'
    -          // and then contains any number of raw characters,
    -          + '(?:[^/\\x5B\\x5C]'
    -          // escape sequences (\x5C),
    -          +    '|\\x5C[\\s\\S]'
    -          // or non-nesting character sets (\x5B\x5D);
    -          +    '|\\x5B(?:[^\\x5C\\x5D]|\\x5C[\\s\\S])*(?:\\x5D|$))+'
    -          // finally closed by a /.
    -          + '/');
    -      fallthroughStylePatterns.push(
    -          ['lang-regex',
    -           new RegExp('^' + REGEXP_PRECEDER_PATTERN + '(' + REGEX_LITERAL + ')')
    -           ]);
    -    }
    -
    -    var keywords = options['keywords'].replace(/^\s+|\s+$/g, '');
    -    if (keywords.length) {
    -      fallthroughStylePatterns.push(
    -          [PR_KEYWORD,
    -           new RegExp('^(?:' + keywords.replace(/\s+/g, '|') + ')\\b'), null]);
    -    }
    -
    -    shortcutStylePatterns.push([PR_PLAIN,       /^\s+/, null, ' \r\n\t\xA0']);
    -    fallthroughStylePatterns.push(
    -        // TODO(mikesamuel): recognize non-latin letters and numerals in idents
    -        [PR_COMMENT,     /^.*?\*.*/],
    -		[PR_VAR, /^\$[a-z]{1}[a-z_]+/i, null],
    -		[PR_LITERAL,     /^@[a-z_$][a-z_$@0-9]*/i, null],
    -        [PR_TYPE,        /^@?[A-Z]+[a-z][A-Za-z_$@0-9]*/, null],
    -        [PR_PLAIN,       /^[a-z_$][a-z_$@0-9]*/i, null],
    -        [PR_LITERAL,
    -         new RegExp(
    -             '^(?:'
    -             // A hex number
    -             + '0x[a-f0-9]+'
    -             // or an octal or decimal number,
    -             + '|(?:\\d(?:_\\d+)*\\d*(?:\\.\\d*)?|\\.\\d\\+)'
    -             // possibly in scientific notation
    -             + '(?:e[+\\-]?\\d+)?'
    -             + ')'
    -             // with an optional modifier like UL for unsigned long
    -             + '[a-z]*', 'i'),
    -         null, '0123456789'],
    -        [PR_PUNCTUATION, /^.[^\s\w\.$@\'\"\`\/\#]*/, null]);
    -
    -    return createSimpleLexer(shortcutStylePatterns, fallthroughStylePatterns);
    -  }
    -
    -  var decorateSource = sourceDecorator({
    -        'keywords': ALL_KEYWORDS,
    -        'hashComments': true,
    -        'cStyleComments': true,
    -        'multiLineStrings': true,
    -        'regexLiterals': true
    -      });
    -
    -  /** Breaks {@code job.source} around style boundaries in
    -    * {@code job.decorations} while re-interleaving {@code job.extractedTags},
    -    * and leaves the result in {@code job.prettyPrintedHtml}.
    -    * @param {Object} job like {
    -    *    source: {string} source as plain text,
    -    *    extractedTags: {Array.<number|string>} extractedTags chunks of raw
    -    *                   html preceded by their position in {@code job.source}
    -    *                   in order
    -    *    decorations: {Array.<number|string} an array of style classes preceded
    -    *                 by the position at which they start in job.source in order
    -    * }
    -    * @private
    -    */
    -  function recombineTagsAndDecorations(job) {
    -    var sourceText = job.source;
    -    var extractedTags = job.extractedTags;
    -    var decorations = job.decorations;
    -
    -    var html = [];
    -    // index past the last char in sourceText written to html
    -    var outputIdx = 0;
    -
    -    var openDecoration = null;
    -    var currentDecoration = null;
    -    var tagPos = 0;  // index into extractedTags
    -    var decPos = 0;  // index into decorations
    -    var tabExpander = makeTabExpander(window['PR_TAB_WIDTH']);
    -
    -    var adjacentSpaceRe = /([\r\n ]) /g;
    -    var startOrSpaceRe = /(^| ) /gm;
    -    var newlineRe = /\r\n?|\n/g;
    -    var trailingSpaceRe = /[ \r\n]$/;
    -    var lastWasSpace = true;  // the last text chunk emitted ended with a space.
    -
    -    // See bug 71 and http://stackoverflow.com/questions/136443/why-doesnt-ie7-
    -    var isIE678 = window['_pr_isIE6']();
    -    var lineBreakHtml = (
    -        isIE678
    -        ? (job.sourceNode.tagName === 'PRE'
    -           // Use line feeds instead of <br>s so that copying and pasting works
    -           // on IE.
    -           // Doing this on other browsers breaks lots of stuff since \r\n is
    -           // treated as two newlines on Firefox.
    -           ? (isIE678 === 6 ? '&#160;\r\n' :
    -              isIE678 === 7 ? '&#160;<br>\r' : '&#160;\r')
    -           // IE collapses multiple adjacent <br>s into 1 line break.
    -           // Prefix every newline with '&#160;' to prevent such behavior.
    -           // &nbsp; is the same as &#160; but works in XML as well as HTML.
    -           : '&#160;<br />')
    -        : '<br />');
    -
    -    // Look for a class like linenums or linenums:<n> where <n> is the 1-indexed
    -    // number of the first line.
    -    var numberLines = job.sourceNode.className.match(/\blinenums\b(?::(\d+))?/);
    -    var lineBreaker;
    -    if (numberLines) {
    -      var lineBreaks = [];
    -      for (var i = 0; i < 10; ++i) {
    -        lineBreaks[i] = lineBreakHtml + '</li><li class="L' + i + '">';
    -      }
    -      var lineNum = numberLines[1] && numberLines[1].length
    -          ? numberLines[1] - 1 : 0;  // Lines are 1-indexed
    -      html.push('<ol class="linenums"><li class="L', (lineNum) % 10, '"');
    -      if (lineNum) {
    -        html.push(' value="', lineNum + 1, '"');
    -      }
    -      html.push('>');
    -      lineBreaker = function () {
    -        var lb = lineBreaks[++lineNum % 10];
    -        // If a decoration is open, we need to close it before closing a list-item
    -        // and reopen it on the other side of the list item.
    -        return openDecoration
    -            ? ('</span>' + lb + '<span class="' + openDecoration + '">') : lb;
    -      };
    -    } else {
    -      lineBreaker = lineBreakHtml;
    -    }
    -
    -    // A helper function that is responsible for opening sections of decoration
    -    // and outputing properly escaped chunks of source
    -    function emitTextUpTo(sourceIdx) {
    -      if (sourceIdx > outputIdx) {
    -        if (openDecoration && openDecoration !== currentDecoration) {
    -          // Close the current decoration
    -          html.push('</span>');
    -          openDecoration = null;
    -        }
    -        if (!openDecoration && currentDecoration) {
    -          openDecoration = currentDecoration;
    -          html.push('<span class="', openDecoration, '">');
    -        }
    -        // This interacts badly with some wikis which introduces paragraph tags
    -        // into pre blocks for some strange reason.
    -        // It's necessary for IE though which seems to lose the preformattedness
    -        // of <pre> tags when their innerHTML is assigned.
    -        // http://stud3.tuwien.ac.at/~e0226430/innerHtmlQuirk.html
    -        // and it serves to undo the conversion of <br>s to newlines done in
    -        // chunkify.
    -        var htmlChunk = textToHtml(
    -            tabExpander(sourceText.substring(outputIdx, sourceIdx)))
    -            .replace(lastWasSpace
    -                     ? startOrSpaceRe
    -                     : adjacentSpaceRe, '$1&#160;');
    -        // Keep track of whether we need to escape space at the beginning of the
    -        // next chunk.
    -        lastWasSpace = trailingSpaceRe.test(htmlChunk);
    -        html.push(htmlChunk.replace(newlineRe, lineBreaker));
    -        outputIdx = sourceIdx;
    -      }
    -    }
    -
    -    while (true) {
    -      // Determine if we're going to consume a tag this time around.  Otherwise
    -      // we consume a decoration or exit.
    -      var outputTag;
    -      if (tagPos < extractedTags.length) {
    -        if (decPos < decorations.length) {
    -          // Pick one giving preference to extractedTags since we shouldn't open
    -          // a new style that we're going to have to immediately close in order
    -          // to output a tag.
    -          outputTag = extractedTags[tagPos] <= decorations[decPos];
    -        } else {
    -          outputTag = true;
    -        }
    -      } else {
    -        outputTag = false;
    -      }
    -      // Consume either a decoration or a tag or exit.
    -      if (outputTag) {
    -        emitTextUpTo(extractedTags[tagPos]);
    -        if (openDecoration) {
    -          // Close the current decoration
    -          html.push('</span>');
    -          openDecoration = null;
    -        }
    -        html.push(extractedTags[tagPos + 1]);
    -        tagPos += 2;
    -      } else if (decPos < decorations.length) {
    -        emitTextUpTo(decorations[decPos]);
    -        currentDecoration = decorations[decPos + 1];
    -        decPos += 2;
    -      } else {
    -        break;
    -      }
    -    }
    -    emitTextUpTo(sourceText.length);
    -    if (openDecoration) {
    -      html.push('</span>');
    -    }
    -    if (numberLines) { html.push('</li></ol>'); }
    -    job.prettyPrintedHtml = html.join('');
    -  }
    -
    -  /** Maps language-specific file extensions to handlers. */
    -  var langHandlerRegistry = {};
    -  /** Register a language handler for the given file extensions.
    -    * @param {function (Object)} handler a function from source code to a list
    -    *      of decorations.  Takes a single argument job which describes the
    -    *      state of the computation.   The single parameter has the form
    -    *      {@code {
    -    *        source: {string} as plain text.
    -    *        decorations: {Array.<number|string>} an array of style classes
    -    *                     preceded by the position at which they start in
    -    *                     job.source in order.
    -    *                     The language handler should assigned this field.
    -    *        basePos: {int} the position of source in the larger source chunk.
    -    *                 All positions in the output decorations array are relative
    -    *                 to the larger source chunk.
    -    *      } }
    -    * @param {Array.<string>} fileExtensions
    -    */
    -  function registerLangHandler(handler, fileExtensions) {
    -    for (var i = fileExtensions.length; --i >= 0;) {
    -      var ext = fileExtensions[i];
    -      if (!langHandlerRegistry.hasOwnProperty(ext)) {
    -        langHandlerRegistry[ext] = handler;
    -      } else if ('console' in window) {
    -        console['warn']('cannot override language handler %s', ext);
    -      }
    -    }
    -  }
    -  function langHandlerForExtension(extension, source) {
    -    if (!(extension && langHandlerRegistry.hasOwnProperty(extension))) {
    -      // Treat it as markup if the first non whitespace character is a < and
    -      // the last non-whitespace character is a >.
    -      extension = /^\s*</.test(source)
    -          ? 'default-markup'
    -          : 'default-code';
    -    }
    -    return langHandlerRegistry[extension];
    -  }
    -  registerLangHandler(decorateSource, ['default-code']);
    -  registerLangHandler(
    -      createSimpleLexer(
    -          [],
    -          [
    -		   [PR_PLAIN,       /^[^<?]+/],
    -           [PR_DECLARATION, /^<!\w[^>]*(?:>|$)/],
    -           [PR_COMMENT,     /^<\!--[\s\S]*?(?:-\->|$)/],
    -           // Unescaped content in an unknown language
    -           ['lang-',        /^<\?([\s\S]+?)(?:\?>|$)/],
    -           ['lang-',        /^<%([\s\S]+?)(?:%>|$)/],
    -           [PR_PUNCTUATION, /^(?:<[%?]|[%?]>)/],
    -           ['lang-',        /^<xmp\b[^>]*>([\s\S]+?)<\/xmp\b[^>]*>/i],
    -           // Unescaped content in javascript.  (Or possibly vbscript).
    -           ['lang-js',      /^<script\b[^>]*>([\s\S]*?)(<\/script\b[^>]*>)/i],
    -           // Contains unescaped stylesheet content
    -           ['lang-css',     /^<style\b[^>]*>([\s\S]*?)(<\/style\b[^>]*>)/i],
    -           ['lang-in.tag',  /^(<\/?[a-z][^<>]*>)/i]
    -          ]),
    -      ['default-markup', 'htm', 'html', 'mxml', 'xhtml', 'xml', 'xsl']);
    -  registerLangHandler(
    -      createSimpleLexer(
    -          [
    -		   [PR_PLAIN,        /^[\s]+/, null, ' \t\r\n'],
    -           [PR_ATTRIB_VALUE, /^(?:\"[^\"]*\"?|\'[^\']*\'?)/, null, '\"\'']
    -           ],
    -          [
    -		  [PR_TAG,          /^^<\/?[a-z](?:[\w.:-]*\w)?|\/?>$/i],
    -           [PR_ATTRIB_NAME,  /^(?!style[\s=]|on)[a-z](?:[\w:-]*\w)?/i],
    -           ['lang-uq.val',   /^=\s*([^>\'\"\s]*(?:[^>\'\"\s\/]|\/(?=\s)))/],
    -           [PR_PUNCTUATION,  /^[=<>\/]+/],
    -           ['lang-js',       /^on\w+\s*=\s*\"([^\"]+)\"/i],
    -           ['lang-js',       /^on\w+\s*=\s*\'([^\']+)\'/i],
    -           ['lang-js',       /^on\w+\s*=\s*([^\"\'>\s]+)/i],
    -           ['lang-css',      /^style\s*=\s*\"([^\"]+)\"/i],
    -           ['lang-css',      /^style\s*=\s*\'([^\']+)\'/i],
    -           ['lang-css',      /^style\s*=\s*([^\"\'>\s]+)/i]
    -           ]),
    -      ['in.tag']);
    -  registerLangHandler(
    -      createSimpleLexer([], [[PR_ATTRIB_VALUE, /^[\s\S]+/]]), ['uq.val']);
    -  registerLangHandler(sourceDecorator({
    -          'keywords': CPP_KEYWORDS,
    -          'hashComments': true,
    -          'cStyleComments': true
    -        }), ['c', 'cc', 'cpp', 'cxx', 'cyc', 'm']);
    -  registerLangHandler(sourceDecorator({
    -          'keywords': 'null true false'
    -        }), ['json']);
    -  registerLangHandler(sourceDecorator({
    -          'keywords': CSHARP_KEYWORDS,
    -          'hashComments': true,
    -          'cStyleComments': true,
    -          'verbatimStrings': true
    -        }), ['cs']);
    -  registerLangHandler(sourceDecorator({
    -          'keywords': JAVA_KEYWORDS,
    -          'cStyleComments': true
    -        }), ['java']);
    -  registerLangHandler(sourceDecorator({
    -          'keywords': SH_KEYWORDS,
    -          'hashComments': true,
    -          'multiLineStrings': true
    -        }), ['bsh', 'csh', 'sh']);
    -  registerLangHandler(sourceDecorator({
    -          'keywords': PYTHON_KEYWORDS,
    -          'hashComments': true,
    -          'multiLineStrings': true,
    -          'tripleQuotedStrings': true
    -        }), ['cv', 'py']);
    -  registerLangHandler(sourceDecorator({
    -          'keywords': PERL_KEYWORDS,
    -          'hashComments': true,
    -          'multiLineStrings': true,
    -          'regexLiterals': true
    -        }), ['perl', 'pl', 'pm']);
    -  registerLangHandler(sourceDecorator({
    -          'keywords': RUBY_KEYWORDS,
    -          'hashComments': true,
    -          'multiLineStrings': true,
    -          'regexLiterals': true
    -        }), ['rb']);
    -  registerLangHandler(sourceDecorator({
    -          'keywords': JSCRIPT_KEYWORDS,
    -          'cStyleComments': true,
    -          'regexLiterals': true
    -        }), ['js']);
    -  registerLangHandler(
    -      createSimpleLexer([], [[PR_STRING, /^[\s\S]+/]]), ['regex']);
    -
    -  function applyDecorator(job) {
    -    var sourceCodeHtml = job.sourceCodeHtml;
    -    var opt_langExtension = job.langExtension;
    -
    -    // Prepopulate output in case processing fails with an exception.
    -    job.prettyPrintedHtml = sourceCodeHtml;
    -
    -    try {
    -      // Extract tags, and convert the source code to plain text.
    -      var sourceAndExtractedTags = extractTags(sourceCodeHtml);
    -      /** Plain text. @type {string} */
    -      var source = sourceAndExtractedTags.source;
    -      job.source = source;
    -      job.basePos = 0;
    -
    -      /** Even entries are positions in source in ascending order.  Odd entries
    -        * are tags that were extracted at that position.
    -        * @type {Array.<number|string>}
    -        */
    -      job.extractedTags = sourceAndExtractedTags.tags;
    -
    -      // Apply the appropriate language handler
    -      langHandlerForExtension(opt_langExtension, source)(job);
    -      // Integrate the decorations and tags back into the source code to produce
    -      // a decorated html string which is left in job.prettyPrintedHtml.
    -      recombineTagsAndDecorations(job);
    -    } catch (e) {
    -      if ('console' in window) {
    -        console['log'](e && e['stack'] ? e['stack'] : e);
    -      }
    -    }
    -  }
    -
    -  function prettyPrintOne(sourceCodeHtml, opt_langExtension) {
    -    var job = {
    -      sourceCodeHtml: sourceCodeHtml,
    -      langExtension: opt_langExtension
    -    };
    -    applyDecorator(job);
    -    return job.prettyPrintedHtml;
    -  }
    -
    -  function prettyPrint(opt_whenDone) {
    -    function byTagName(tn) { return document.getElementsByTagName(tn); }
    -    // fetch a list of nodes to rewrite
    -    var codeSegments = [byTagName('pre'), byTagName('code'), byTagName('xmp')];
    -    var elements = [];
    -    for (var i = 0; i < codeSegments.length; ++i) {
    -      for (var j = 0, n = codeSegments[i].length; j < n; ++j) {
    -        elements.push(codeSegments[i][j]);
    -      }
    -    }
    -    codeSegments = null;
    -
    -    var clock = Date;
    -    if (!clock['now']) {
    -      clock = { 'now': function () { return (new Date).getTime(); } };
    -    }
    -
    -    // The loop is broken into a series of continuations to make sure that we
    -    // don't make the browser unresponsive when rewriting a large page.
    -    var k = 0;
    -    var prettyPrintingJob;
    -
    -    function doWork() {
    -      var endTime = (window['PR_SHOULD_USE_CONTINUATION'] ?
    -                     clock.now() + 250 /* ms */ :
    -                     Infinity);
    -      for (; k < elements.length && clock.now() < endTime; k++) {
    -        var cs = elements[k];
    -        if (cs.className && cs.className.indexOf('preformatted') >= 0) {
    -          // If the classes includes a language extensions, use it.
    -          // Language extensions can be specified like
    -          //     <pre class="prettyprint lang-cpp">
    -          // the language extension "cpp" is used to find a language handler as
    -          // passed to PR_registerLangHandler.
    -          var langExtension = cs.className.match(/\blang-(\w+)\b/);
    -          if (langExtension) { langExtension = langExtension[1]; }
    -
    -          // make sure this is not nested in an already prettified element
    -          var nested = false;
    -          for (var p = cs.parentNode; p; p = p.parentNode) {
    -            if ((p.tagName === 'pre' || p.tagName === 'code' ||
    -                 p.tagName === 'xmp') &&
    -                p.className && p.className.indexOf('preformatted') >= 0) {
    -              nested = true;
    -              break;
    -            }
    -          }
    -          if (!nested) {
    -            // fetch the content as a snippet of properly escaped HTML.
    -            // Firefox adds newlines at the end.
    -            var content = getInnerHtml(cs);
    -            content = content.replace(/(?:\r\n?|\n)$/, '');
    -
    -            // do the pretty printing
    -            prettyPrintingJob = {
    -              sourceCodeHtml: content,
    -              langExtension: langExtension,
    -              sourceNode: cs
    -            };
    -            applyDecorator(prettyPrintingJob);
    -            replaceWithPrettyPrintedHtml();
    -          }
    -        }
    -      }
    -      if (k < elements.length) {
    -        // finish up in a continuation
    -        setTimeout(doWork, 250);
    -      } else if (opt_whenDone) {
    -        opt_whenDone();
    -      }
    -    }
    -
    -    function replaceWithPrettyPrintedHtml() {
    -      var newContent = prettyPrintingJob.prettyPrintedHtml;
    -      if (!newContent) { return; }
    -      var cs = prettyPrintingJob.sourceNode;
    -
    -      // push the prettified html back into the tag.
    -      if (!isRawContent(cs)) {
    -        // just replace the old html with the new
    -        cs.innerHTML = newContent;
    -      } else {
    -        // we need to change the tag to a <pre> since <xmp>s do not allow
    -        // embedded tags such as the span tags used to attach styles to
    -        // sections of source code.
    -        var pre = document.createElement('PRE');
    -        for (var i = 0; i < cs.attributes.length; ++i) {
    -          var a = cs.attributes[i];
    -          if (a.specified) {
    -            var aname = a.name.toLowerCase();
    -            if (aname === 'class') {
    -              pre.className = a.value;  // For IE 6
    -            } else {
    -              pre.setAttribute(a.name, a.value);
    -            }
    -          }
    -        }
    -        pre.innerHTML = newContent;
    -
    -        // remove the old
    -        cs.parentNode.replaceChild(pre, cs);
    -        cs = pre;
    -      }
    -    }
    -
    -    doWork();
    -  }
    -
    -  window['PR_normalizedHtml'] = normalizedHtml;
    -  window['prettyPrintOne'] = prettyPrintOne;
    -  window['prettyPrint'] = prettyPrint;
    -  window['PR'] = {
    -        'combinePrefixPatterns': combinePrefixPatterns,
    -        'createSimpleLexer': createSimpleLexer,
    -        'registerLangHandler': registerLangHandler,
    -        'sourceDecorator': sourceDecorator,
    -        'PR_ATTRIB_NAME': PR_ATTRIB_NAME,
    -        'PR_ATTRIB_VALUE': PR_ATTRIB_VALUE,
    -        'PR_COMMENT': PR_COMMENT,
    -        'PR_DECLARATION': PR_DECLARATION,
    -        'PR_KEYWORD': PR_KEYWORD,
    -        'PR_LITERAL': PR_LITERAL,
    -        'PR_NOCODE': PR_NOCODE,
    -        'PR_PLAIN': PR_PLAIN,
    -        'PR_PUNCTUATION': PR_PUNCTUATION,
    -        'PR_SOURCE': PR_SOURCE,
    -        'PR_STRING': PR_STRING,
    -        'PR_TAG': PR_TAG,
    -        'PR_TYPE': PR_TYPE
    -      };
    -})();
    diff --git a/build/aps/Limitations of APS Support in the Panel_fichiers/stylesheet.css b/build/aps/Limitations of APS Support in the Panel_fichiers/stylesheet.css
    deleted file mode 100644
    index b7ce63f17b3..00000000000
    --- a/build/aps/Limitations of APS Support in the Panel_fichiers/stylesheet.css	
    +++ /dev/null
    @@ -1,1571 +0,0 @@
    -body
    -{
    -background: #FFFFFF
    -}
    -
    -/*ol.listalfa
    -{
    -        list-style-type: lower-alpha;
    -        list-style-position: outside;
    -        margin-top: 7pt;
    -        margin-bottom: 0pt;
    -        }*/
    -li.listalpha {
    -        list-style-type: lower-alpha;
    -		font-family: verdana, tahoma, arial, helvetica, sans-serif;
    -        font-style: normal;
    -        font-variant: normal;
    -        font-weight: normal;
    -        font-size: 8pt;
    -        color: #000000;
    -        background-color: inherit;
    -        word-spacing: normal;
    -        letter-spacing: normal;
    -        vertical-align: baseline;
    -        text-decoration: none;
    -        text-transform: none;
    -        line-height: 10pt;
    -        margin: 0px;
    -        padding: 0 0 6px 0;
    -        float: none;
    -        clear: none;
    -        text-align: left;
    -        text-indent: 0cm;
    -        width: auto;
    -        height: auto;
    -        white-space: normal;
    -       }
    -
    -/*ol.listalfa2
    -{
    -        list-style-type: lower-alpha;
    -        list-style-position: outside;
    -        margin-top: 7pt;
    -        margin-bottom: 0pt;
    -        }*/
    -li.listalpha2 {
    -        list-style-type: lower-alpha;
    -		font-family: verdana, tahoma, arial, helvetica, sans-serif;
    -        font-style: normal;
    -        font-variant: normal;
    -        font-weight: normal;
    -        font-size: 8pt;
    -        color: #13152d;
    -        background-color: inherit;
    -        word-spacing: normal;
    -        letter-spacing: normal;
    -        vertical-align: baseline;
    -        text-decoration: none;
    -        text-transform: none;
    -		  line-height: 10pt;
    -        margin: 0px;
    -        padding: 0 0 6px 0;
    -        float: none;
    -        clear: none;
    -        text-align: left;
    -        text-indent: 0cm;
    -        width: auto;
    -        height: auto;
    -        white-space: normal;
    -       }
    -
    -/*ol.listalfa3
    -{
    -        list-style-type: lower-alpha;
    -        list-style-position: outside;
    -        margin-top: 7pt;
    -        margin-bottom: 0pt;
    -        }*/
    -li.listalpha3 {
    -        list-style-type: lower-alpha;
    -		font-family: verdana, tahoma, arial, helvetica, sans-serif;
    -        font-style: normal;
    -        font-variant: normal;
    -        font-weight: normal;
    -        font-size: 8pt;
    -        color: #13152d;
    -        background-color: inherit;
    -        word-spacing: normal;
    -        letter-spacing: normal;
    -        vertical-align: baseline;
    -        text-decoration: none;
    -        text-transform: none;
    -        line-height: normal;
    -        margin: 0px;
    -        padding: 0 0 6px 0;
    -        float: none;
    -        clear: none;
    -        text-align: left;
    -        text-indent: 0cm;
    -        width: auto;
    -        height: auto;
    -        white-space: normal;
    -       }
    -
    -/*li.listalpha2, li.listalpha, li.listalpha3
    -{
    -list-style-type: lower-alpha;
    -} */
    -
    -
    -li.tablelistbullet {
    -        font-family: verdana, tahoma, arial, helvetica, sans-serif;
    -        font-style: normal;
    -        font-variant: normal;
    -        font-weight: normal;
    -        font-size: 8pt;
    -        color: #000000;
    -        background-color: inherit;
    -        word-spacing: normal;
    -        letter-spacing: normal;
    -        text-decoration: none;
    -        text-transform: none;
    -        line-height: 10pt;
    -        margin: 0px;
    -        padding: 5px;
    -	vertical-align: top;
    -        float: none;
    -        clear: none;
    -        text-align: left;
    -        text-indent: 0cm;
    -        width: auto;
    -        height: auto;
    -        white-space: normal;
    -       }
    -
    -
    -p.centered {
    -
    -        text-align: center;
    -}
    -
    -p.listcontinue3 {
    -    margin-left: 30pt;
    -  }
    -
    -.preformattedbold2ndlvl {
    -  display: block;
    -        font-family: "Courier New", verdana, arial, helvetica, sans-serif;
    -        font-style: normal;
    -        font-variant: normal;
    -        font-weight: bold;
    -        font-size: 10pt;
    -        color: #000000;
    -        background-color: #f4f4f4;
    -        word-spacing: normal;
    -        letter-spacing: normal;
    -        vertical-align: baseline;
    -        text-decoration: none;
    -        text-transform: none;
    -        line-height: normal;
    -        margin-top: 0pt;
    -        margin-bottom: 0pt;
    -        margin-left: 20pt;
    -        margin-right: 6pt;
    -        padding-top: 1pt;
    -        padding-bottom: 1pt;
    -        padding-left: 5pt;
    -        padding-right: 5pt;
    -        float: none;
    -        clear: none;
    -        text-align: left;
    -        text-indent: 0cm;
    -        width: auto;
    -        height: auto;
    -
    -}
    -
    -
    -.preformattedseclevel {
    -        display: block;
    -        font-family: "Courier New", verdana, arial, helvetica, sans-serif;
    -        font-style: normal;
    -        font-variant: normal;
    -        font-weight: normal;
    -        font-size: 10pt;
    -        color: #000000;
    -        background-color: #f4f4f4;
    -        word-spacing: normal;
    -        letter-spacing: normal;
    -        vertical-align: baseline;
    -        text-decoration: none;
    -        text-transform: none;
    -        line-height: normal;
    -        margin-top: 0pt;
    -        margin-bottom: 0pt;
    -        margin-left: 20pt;
    -        margin-right: 6pt;
    -        padding-top: 1pt;
    -        padding-bottom: 1pt;
    -        padding-left: 5pt;
    -        padding-right: 5pt;
    -        float: none;
    -        clear: none;
    -        text-align: left;
    -        text-indent: 0cm;
    -        width: auto;
    -        height: auto;
    -}
    -
    -.prcontinuous
    -{font-family: "Courier New", verdana, arial, helvetica, sans-serif;
    -        font-style: normal;
    -        font-variant: normal;
    -        font-weight: normal;
    -        font-size: 10pt;
    -        color: #000000;
    -        background-color: #f4f4f4;
    -        word-spacing: normal;
    -        letter-spacing: normal;
    -        vertical-align: baseline;
    -        text-decoration: none;
    -        text-transform: none;
    -        line-height: normal;
    -        margin-top: 0pt;
    -        margin-bottom: 0pt;
    -        margin-left: 0pt;
    -        margin-right: 6pt;
    -        padding-top: 1pt;
    -        padding-bottom: 1pt;
    -        padding-left: 5pt;
    -        padding-right: 5pt;
    -        float: none;
    -        clear: none;
    -        text-align: left;
    -        text-indent: 0cm;
    -        width: auto;
    -        height: auto;
    -       }
    -
    -.prefblue
    -{display: inline;
    -        font-family: "Courier New", verdana, arial, helvetica, sans-serif;
    -        font-size: 10pt;
    -        color: #0000FF;
    -        background-color: #f4f4f4;
    -        vertical-align: baseline;
    -        margin-top: 6pt;
    -        margin-bottom: 6pt;
    -        margin-left: 0pt;
    -        margin-right: 0pt;
    -        padding-top: 0pt;
    -        padding-bottom: 0pt;
    -        padding-left: 0pt;
    -        padding-right: 0pt;
    -       }
    -.prefred
    -{display: inline;
    -        font-family: "Courier New", verdana, arial, helvetica, sans-serif;
    -        font-size: 10pt;
    -        color: #FF0000;
    -        background-color: #f4f4f4;
    -        vertical-align: baseline;
    -        margin-top: 6pt;
    -        margin-bottom: 6pt;
    -        margin-left: 0pt;
    -        margin-right: 0pt;
    -        padding-top: 0pt;
    -        padding-bottom: 0pt;
    -        padding-left: 0pt;
    -        padding-right: 0pt;
    -       }
    -.prefdarkblue
    -{display: inline;
    -        font-family: "Courier New", verdana, arial, helvetica, sans-serif;
    -        font-weight: bold;
    -        font-size: 10pt;
    -        color: #000080;
    -        background-color: #f4f4f4;
    -        vertical-align: baseline;
    -        margin-top: 6pt;
    -        margin-bottom: 6pt;
    -        margin-left: 0pt;
    -        margin-right: 0pt;
    -        padding-top: 0pt;
    -        padding-bottom: 0pt;
    -        padding-left: 0pt;
    -        padding-right: 0pt;
    -       }
    -.prefgrey
    -{display: inline;
    -        font-family: "Courier New", verdana, arial, helvetica, sans-serif;
    -        font-size: 10pt;
    -        color: #EA8110;
    -        background-color: #f4f4f4;
    -        vertical-align: baseline;
    -        margin-top: 6pt;
    -        margin-bottom: 6pt;
    -        margin-left: 0pt;
    -        margin-right: 0pt;
    -        padding-top: 0pt;
    -        padding-bottom: 0pt;
    -        padding-left: 0pt;
    -        padding-right: 0pt;
    -       }
    -
    -.expandingblock
    -{font-family: "Tahoma", verdana, arial, helvetica, sans-serif;
    -        border-color: #AFAFAF;
    -        border-top-style: dotted;
    -        border-top-width: 1px;
    -        border-top-color: #AFAFAF;
    -        border-bottom-style: dotted;
    -        border-bottom-width: 1px;
    -        border-bottom-color: #AFAFAF;
    -        border-left-style: dotted;
    -        border-left-width: 1px;
    -        border-left-color: #AFAFAF;
    -        border-right-style: dotted;
    -        border-right-width: 1px;
    -        border-right-color: #AFAFAF;
    -        float: none;
    -        clear: none;
    -        text-align: left;
    -        text-indent: 0cm;
    -        width: auto;
    -        height: auto;
    -        white-space: normal;
    -	padding-left: 3px;
    -	padding-right: 3px;
    -	padding-top: 3px;
    -	padding-bottom: 3px;
    -
    -       }
    -
    -
    -
    -.copyright {
    -        font-family: verdana, tahoma, arial, helvetica, sans-serif;
    -        font-size: 8pt;
    -        font-style: italic;
    -        color: #000000;
    -        margin: 9px 0px 9px 0px;
    -        padding: 0px;
    -}
    -
    -/* Nov-14 begin */
    -
    -.pagenavigation {
    -	font-family: tahoma, verdana, arial, helvetica, sans-serif;
    -	font-size: 8pt;
    -	white-space: nowrap;
    -	vertical-align: middle;
    -	margin: 0px;
    -	margin-right: 2px;
    -	padding: 3px;
    -	padding-right: 4px;
    -	background-color: #f0f1f5;
    -}
    -*html .pagenavigation {
    -	margin-top: -7px;
    -	position: relative;
    -}
    -
    -.pagenavigation a, .pagenavigation a:link, .pagenavigation a:visited {
    -	color: #000000;
    -	text-decoration: none;
    -}
    -.pagenavigation a:hover {
    -	text-decoration: none;
    -	color: #666666;
    -}
    -
    -/* end */
    -
    -
    -
    -.topBody {
    -	background: #eeeeee;
    -}
    -.nav {
    -	vertical-align: middle;
    -	font-family: tahoma, verdana, arial, helvetica, sans-serif;
    -	font-size: 8pt;
    -	padding-left: 7px;
    -	padding-right: 5px;
    -	padding-top: 4px;
    -}
    -.nav a, .nav a:link, .nav a:visited {
    -	color: #000000;
    -	text-decoration: none;
    -}
    -.nav a:hover {
    -	text-decoration: none;
    -	color: #666666;
    -}
    -
    -td.navTabActive {
    -	color: #1f202c;
    -	text-decoration: none;
    -	vertical-align: middle;
    -	font-family: tahoma, verdana, arial, helvetica, sans-serif;
    -	font-size: 8pt;
    -	padding-top: 4px;
    -	padding-bottom: 0px;
    -	padding-left: 8px;
    -	padding-right: 8px;
    -	font-weight: bold;
    -	background-image: url('nav_bg_active.gif');
    -	background-repeat: repeat-x;
    -}
    -td.navTab {
    -	padding-top: 3px;
    -}
    -.navTab a, .navTab a:link, .navTab a:visited {
    -	color: #000000;
    -	text-decoration: none;
    -	vertical-align: middle;
    -	font-family: tahoma, verdana, arial, helvetica, sans-serif;
    -	font-size: 8pt;
    -	padding-top: 4px;
    -	padding-bottom: 0px;
    -	padding-left: 8px;
    -	padding-right: 8px;
    -}
    -.navTab a:hover {
    -	color: #1f202c;
    -	text-decoration: none;
    -	vertical-align: middle;
    -	font-family: tahoma, verdana, arial, helvetica, sans-serif;
    -	font-size: 8pt;
    -	padding-top: 5px;
    -	padding-bottom: 7px;
    -	padding-left: 8px;
    -	padding-right: 8px;
    -	background-image: url('nav_bg_active.gif');
    -	background-repeat: repeat-x;
    -}
    -
    -.navDiv {
    -	vertical-align: middle;
    -}
    -
    -.topFrameTable {
    -	width: 100%;
    -	/*height: 23px;*/
    -	margin: 0px;
    -	padding: 0px;
    -	border-bottom: 2px solid #d6d6d6;
    -   background-image: url('nav_bg.gif');
    -	background-repeat: repeat-x;
    -}
    -.topFrameTabs {
    -	margin-left: 3px;
    -	margin-top: 0px;
    -}
    -
    -.headerTable {
    -	width: 100%;
    -	vertical-align: top;
    -	height: 23px;
    -	background: #588cc7;
    -}
    -.headerTd {
    -	vertical-align: middle;
    -	font-family: verdana, tahoma, arial, helvetica, sans-serif;
    -	color: #ffffff;
    -	font-size: 12px;
    -	padding-top: 2px;
    -	padding-bottom: 3px;
    -	padding-left: 7px;
    -	padding-right: 5px;
    -}
    -
    -.tocTable {
    -	width: 100%;
    -	vertical-align: top;
    -}
    -.tocLevel1 {
    -	margin: -14px 0 0 0;
    -	padding: 0px;
    -}
    -
    -a.itemActive,
    -a.itemActive:link,
    -a.itemActive:visited,
    -a.itemActive:active {
    -	color: #ffffff;
    -	line-height: 16px;
    -	padding-top: 1px;
    -	padding-bottom: 2px;
    -	padding-left: 3px;
    -	padding-right: 3px;
    -	background-color:#6697cc;
    -}
    -
    -a, a:link,
    -.relateditem a, .relateditem a:link,
    -.tocLevel1 a, .tocLevel1 a:link {
    -	color: #0049b7;
    -	text-decoration: none;
    -}
    -a:hover,
    -.relateditem a:hover,
    -.tocLevel1 a:hover {
    -	text-decoration: underline;
    -}
    -a:visited,
    -.relateditem a:visited,
    -.tocLevel1 a:visited {
    -	color: #003380;
    -}
    -.relateditem a {
    -	text-decoration: none;
    -}
    -
    -.table {
    -	margin-top: 5px;
    -}
    -.tableDescription {
    -        font-family: tahoma, verdana, arial, helvetica, sans-serif;
    -        font-size: 8pt;
    -		  font-weight: bold;
    -        color: #444444;
    -        margin-top: 15px;
    -        margin-bottom: 7px;
    -        margin-left: 0px;
    -        margin-right: 0px;
    -        padding: 0px;
    -		  text-align: left;
    -}
    -
    -.relatedheading {
    -        font-family: tahoma, verdana, arial, helvetica, sans-serif;
    -        font-weight: bold;
    -        font-size: 8pt;
    -        color: #ffffff;
    -        background-color: #729ecf;
    -        margin-top: 25px;
    -        margin-bottom: 2px;
    -        margin-left: 0px;
    -        margin-right: 0px;
    -        padding-top: 2px;
    -        padding-bottom: 2px;
    -        padding-left: 4px;
    -        padding-right: 4px;
    -        border-color: #FFFFFF;
    -        border-right-style: solid;
    -        border-right-width: 1px;
    -        border-right-color: #FFFFFF;
    -}
    -.relateditem {
    -        font-family: tahoma, verdana, arial, helvetica, sans-serif;
    -        font-size: 8pt;
    -        color: #000000;
    -        background-color: #f3f8fc;
    -        margin-top: 0px;
    -        margin-bottom: 0px;
    -        margin-left: 0px;
    -        margin-right: 0px;
    -        padding-top: 2px;
    -        padding-bottom: 3px;
    -        padding-left: 12px;
    -        padding-right: 15px;
    -        border-color: #FFFFFF;
    -        border-right-style: solid;
    -        border-right-width: 1px;
    -        border-right-color: #FFFFFF;
    -	     border-bottom-style: solid;
    -        border-bottom-width: 2px;
    -        border-bottom-color: #ffffff;
    -}
    -.bodytext {
    -        font-family: verdana, tahoma, arial, helvetica, sans-serif;
    -        font-size: 8pt;
    -        color: #000000;
    -        margin: 9px 0px 9px 0px;
    -        padding: 0px;
    -}
    -
    -.tableheading {
    -        font-family: tahoma, verdana, arial, helvetica, sans-serif;
    -		  font-weight: bold;
    -        font-size: 8pt;
    -		  line-height: 12px;
    -        color: #2f739b;
    -		  line-height: 11px;
    -        margin: 0px;
    -        padding: 3px;
    -        text-align: center;
    -		  background-color: #f5f8fc;/*eef2f9;*/
    -}
    -.tablebodytext {
    -        font-family: verdana, tahoma, arial, helvetica, sans-serif;
    -        font-size: 8pt;
    -        color: #000000;
    -        padding: 5px;
    -		  padding-top: 7px;
    -		  vertical-align: top;
    -}
    -
    -.preformatted {
    -        display: block;
    -        font-family: "Courier New", verdana, arial, helvetica, sans-serif;
    -        font-style: normal;
    -        font-variant: normal;
    -        font-weight: normal;
    -        font-size: 10pt;
    -        color: #000000;
    -        background-color: #f4f4f4;
    -        word-spacing: normal;
    -        letter-spacing: normal;
    -        vertical-align: baseline;
    -        text-decoration: none;
    -        text-transform: none;
    -        line-height: normal;
    -        margin-top: 0pt;
    -        margin-bottom: 0pt;
    -        margin-left: 0pt;
    -        margin-right: 6pt;
    -        padding-top: 1pt;
    -        padding-bottom: 1pt;
    -        padding-left: 5pt;
    -        padding-right: 5pt;
    -        float: none;
    -        clear: none;
    -        text-align: left;
    -        text-indent: 0cm;
    -        width: auto;
    -        height: auto;
    -}
    -
    -
    -.prefcleanxml {
    -        display: block;
    -        font-family: "Courier New", verdana, arial, helvetica, sans-serif;
    -        font-style: normal;
    -        font-variant: normal;
    -        font-weight: normal;
    -        font-size: 10pt;
    -        color: #000000;
    -        background-color: #f4f4f4;
    -        word-spacing: normal;
    -        letter-spacing: normal;
    -        vertical-align: baseline;
    -        text-decoration: none;
    -        text-transform: none;
    -        line-height: normal;
    -        margin-top: 0pt;
    -        margin-bottom: 0pt;
    -        margin-left: 0pt;
    -        margin-right: 6pt;
    -        padding-top: 1pt;
    -        padding-bottom: 1pt;
    -        padding-left: 5pt;
    -        padding-right: 5pt;
    -        float: none;
    -        clear: none;
    -        text-align: left;
    -        text-indent: 0cm;
    -        width: auto;
    -        height: auto;
    -}
    -
    -
    -
    -
    -.preformatedbold2ndlvl, .preformattedbold {
    -        display: block;
    -        font-family: "Courier New", verdana, arial, helvetica, sans-serif;
    -        font-style: normal;
    -        font-variant: normal;
    -        font-weight: bold;
    -        font-size: 10pt;
    -        color: #000000;
    -        background-color: #f4f4f4;
    -        word-spacing: normal;
    -        letter-spacing: normal;
    -        vertical-align: baseline;
    -        text-decoration: none;
    -        text-transform: none;
    -        line-height: normal;
    -        margin-top: 0pt;
    -        margin-bottom: 0pt;
    -        margin-left: 0pt;
    -        margin-right: 6pt;
    -        padding-top: 1pt;
    -        padding-bottom: 1pt;
    -        padding-left: 5pt;
    -        padding-right: 5pt;
    -        float: none;
    -        clear: none;
    -        text-align: left;
    -        text-indent: 0cm;
    -        width: auto;
    -        height: auto;
    -        white-space: normal;
    -}
    -.specialbold {
    -        display: inline;
    -        font-family: tahoma, verdana, arial, helvetica, sans-serif;
    -        font-weight: bold;
    -        font-size: 8pt;
    -        color: #e64a00;
    -        background-color: inherit;
    -        word-spacing: 0pt;
    -        vertical-align: baseline;
    -        padding-top: 0pt;
    -        padding-bottom: 0pt;
    -        padding-left: 0pt;
    -        padding-right: 0pt;
    -        }
    -.emphasis {
    -        display: inline;
    -        font-style: italic;
    -        color: inherit;
    -        background-color: inherit;
    -        vertical-align: baseline;
    -        padding-top: 0pt;
    -        padding-bottom: 0pt;
    -        padding-left: 0pt;
    -        padding-right: 0pt;
    -       }
    -.monospace {
    -        display: inline;
    -        font-family: "Courier New", verdana, arial, helvetica, sans-serif;
    -        color: inherit;
    -		  font-size: 10pt;
    -        background-color: inherit;
    -        vertical-align: baseline;
    -        padding-top: 0pt;
    -        padding-bottom: 0pt;
    -        padding-left: 0pt;
    -        padding-right: 0pt;
    -       }
    -.monospaceitalics {
    -        display: inline;
    -        font-family: "Courier New", verdana, arial, helvetica, sans-serif;
    -        font-style: italic;
    -        color: inherit;
    -		  font-size: 10pt;
    -        background-color: inherit;
    -        vertical-align: baseline;
    -        padding-top: 0pt;
    -        padding-bottom: 0pt;
    -        padding-left: 0pt;
    -        padding-right: 0pt;
    -       }
    -ul.listbullet {
    -        list-style-type: disk;
    -        list-style-image: none;
    -        list-style-position: outside;
    -        margin-top: 7px;
    -        margin-bottom: 0px;
    -        }
    -li.listbullet {
    -        font-family: verdana, tahoma, arial, helvetica, sans-serif;
    -        font-style: normal;
    -        font-variant: normal;
    -        font-weight: normal;
    -        font-size: 8pt;
    -        color: #000000;
    -        background-color: inherit;
    -        word-spacing: normal;
    -        letter-spacing: normal;
    -        vertical-align: baseline;
    -        text-decoration: none;
    -        text-transform: none;
    -        line-height: 10pt;
    -        margin: 0px;
    -        padding: 0 0 6px 0;
    -        float: none;
    -        clear: none;
    -        text-align: left;
    -        text-indent: 0cm;
    -        width: auto;
    -        height: auto;
    -        white-space: normal;
    -       }
    -.note {
    -        font-family: verdana, tahoma, arial, helvetica, sans-serif;
    -        font-style: normal;
    -        font-variant: normal;
    -        font-weight: normal;
    -        font-size: 8pt;
    -        color: #000000;
    -        background-color: #fffdec;
    -        word-spacing: normal;
    -        letter-spacing: normal;
    -        vertical-align: baseline;
    -        text-decoration: none;
    -        text-transform: none;
    -        line-height: normal;
    -        margin-top: 6pt;
    -        margin-bottom: 6pt;
    -        margin-left: 0cm;
    -        margin-right: 0pt;
    -        padding-top: 4pt;
    -        padding-bottom: 4pt;
    -        padding-left: 4pt;
    -        padding-right: 4pt;
    -        border: 2px solid #f8c701;
    -        float: none;
    -        clear: none;
    -        text-align: left;
    -        text-indent: 0cm;
    -        width: 97%;
    -        height: auto;
    -        white-space: normal;
    -       }
    -.buttons {
    -        display: inline;
    -        font-weight: bold;
    -        color: #444444;
    -        background-color: inherit;
    -        vertical-align: baseline;
    -        padding-top: 0pt;
    -        padding-bottom: 0pt;
    -        padding-left: 0pt;
    -        padding-right: 0pt;
    -       }
    -ol.listnumber {
    -        list-style-type: Decimal;
    -        list-style-position: outside;
    -        margin-top: 7pt;
    -        margin-bottom: 0pt;
    -        }
    -li.listnumber {
    -        font-family: verdana, tahoma, arial, helvetica, sans-serif;
    -        font-style: normal;
    -        font-variant: normal;
    -        font-weight: normal;
    -        font-size: 8pt;
    -        color: #000000;
    -        background-color: inherit;
    -        word-spacing: normal;
    -        letter-spacing: normal;
    -        vertical-align: baseline;
    -        text-decoration: none;
    -        text-transform: none;
    -        line-height: normal;
    -        margin-top: 6pt;
    -        margin-bottom: 0pt;
    -        margin-left: 0pt;
    -        margin-right: 0pt;
    -        padding-top: 0pt;
    -        padding-bottom: 0pt;
    -        padding-left: 0pt;
    -        padding-right: 0pt;
    -        float: none;
    -        clear: none;
    -        text-align: left;
    -        text-indent: 0cm;
    -        width: auto;
    -        height: auto;
    -        white-space: normal;
    -       }
    -.procedureheading {
    -        font-family: verdana, tahoma, arial, helvetica, sans-serif;
    -        font-variant: normal;
    -        font-weight: bold;
    -        font-size: 9pt;
    -        color: #266fa4; /* 266fa4 1b64a0 */
    -        background-color: inherit;
    -        word-spacing: normal;
    -        letter-spacing: normal;
    -        vertical-align: baseline;
    -        text-decoration: none;
    -        text-transform: none;
    -        line-height: normal;
    -        margin-top: 12pt;
    -        margin-bottom: 0px;
    -        margin-left: 0px;
    -        margin-right: 0px;
    -        padding-top: 0px;
    -        padding-bottom: 5px;
    -        padding-left: 0px;
    -        padding-right: 0px;
    -        float: none;
    -        clear: none;
    -        text-align: left;
    -        text-indent: 0cm;
    -        width: auto;
    -        height: auto;
    -        white-space: normal;
    -       }
    -ol.procedurelistnumber {
    -        list-style-type: Decimal;
    -        list-style-position: outside;
    -        margin-top: 7px;
    -        margin-bottom: 10px;
    -        }
    -li.procedurelistnumber {
    -        font-family: verdana, tahoma, arial, helvetica, sans-serif;
    -        font-style: normal;
    -        font-variant: normal;
    -        font-weight: normal;
    -        font-size: 8pt;
    -        color: #000000;
    -        background-color: inherit;
    -        word-spacing: normal;
    -        vertical-align: baseline;
    -        text-decoration: none;
    -        text-transform: none;
    -        line-height: normal;
    -        margin-top: 6px;
    -        margin-bottom: 0px;
    -        margin-left: 0px;
    -        margin-right: 0pxt;
    -        padding: 0px;
    -        float: none;
    -        clear: none;
    -        text-align: left;
    -        text-indent: 0cm;
    -        width: auto;
    -        height: auto;
    -        white-space: normal;
    -       }
    -.listcontinue {
    -        display: block;
    -        font-family: verdana, tahoma, arial, helvetica, sans-serif;
    -        font-style: normal;
    -        font-variant: normal;
    -        font-weight: normal;
    -        font-size: 8pt;
    -        color: #000000;
    -        background-color: inherit;
    -        word-spacing: normal;
    -        letter-spacing: normal;
    -        vertical-align: baseline;
    -        text-decoration: none;
    -        text-transform: none;
    -        line-height: normal;
    -        margin-top: 6pt;
    -        margin-bottom: 0pt;
    -        margin-left: 0pt;
    -        margin-right: 0pt;
    -        padding-top: 0pt;
    -        padding-bottom: 5pt;
    -        padding-left: 0pt;
    -        padding-right: 0pt;
    -        float: none;
    -        clear: none;
    -        text-align: left;
    -        text-indent: 0cm;
    -        width: auto;
    -        height: auto;
    -        white-space: normal;
    -       }
    -ul.listbullet2 {
    -        list-style-type: disk;
    -        list-style-image: none;
    -        list-style-position: outside;
    -        margin-top: 7px;
    -        margin-bottom: 0px;
    -        }
    -li.listbullet2 {
    -        font-family: verdana, tahoma, arial, helvetica, sans-serif;
    -        font-style: normal;
    -        font-variant: normal;
    -        font-weight: normal;
    -        font-size: 8pt;
    -        color: #13152d;
    -        background-color: inherit;
    -        word-spacing: normal;
    -        letter-spacing: normal;
    -        vertical-align: baseline;
    -        text-decoration: none;
    -        text-transform: none;
    -		  line-height: 10pt;
    -        margin: 0px;
    -        padding: 0 0 6px 0;
    -        float: none;
    -        clear: none;
    -        text-align: left;
    -        text-indent: 0cm;
    -        width: auto;
    -        height: auto;
    -        white-space: normal;
    -       }
    -.listnote {
    -        display: block;
    -        font-family: verdana, tahoma, arial, helvetica, sans-serif;
    -        font-style: normal;
    -        font-variant: normal;
    -        font-weight: normal;
    -        font-size: 8pt;
    -        color: #000000;
    -        background-color: #fffdec;
    -        word-spacing: normal;
    -        letter-spacing: normal;
    -        vertical-align: baseline;
    -        text-decoration: none;
    -        text-transform: none;
    -        line-height: normal;
    -        margin-top: 6pt;
    -        margin-bottom: 6pt;
    -        margin-left: 0pt;
    -        margin-right: 6pt;
    -        padding-top: 4pt;
    -        padding-bottom: 4pt;
    -        padding-left: 4pt;
    -        padding-right: 4pt;
    -        border: 2px solid #f8c701;
    -        float: none;
    -        clear: none;
    -        text-align: left;
    -        text-indent: 0cm;
    -        width: 97%;
    -        height: auto;
    -        white-space: normal;
    -       }
    -.widegraphic {
    -        display: block;
    -        font-family: verdana, tahoma, arial, helvetica, sans-serif;
    -        font-style: normal;
    -        font-variant: normal;
    -        font-weight: normal;
    -        font-size: 8pt;
    -        color: #000000;
    -        background-color: inherit;
    -        word-spacing: normal;
    -        letter-spacing: normal;
    -        vertical-align: baseline;
    -        text-decoration: none;
    -        text-transform: none;
    -        line-height: normal;
    -        margin-top: 6pt;
    -        margin-bottom: 6pt;
    -        margin-left: 0cm;
    -        margin-right: 0cm;
    -        padding-top: 0pt;
    -        padding-bottom: 0pt;
    -        padding-left: 0pt;
    -        padding-right: 0pt;
    -        float: none;
    -        clear: none;
    -        text-align: center;
    -        text-indent: 0cm;
    -        width: auto;
    -        height: auto;
    -        white-space: normal;
    -       }
    -.listcontinue2 {
    -        display: block;
    -        font-family: verdana, tahoma, arial, helvetica, sans-serif;
    -        font-style: normal;
    -        font-variant: normal;
    -        font-weight: normal;
    -        font-size: 8pt;
    -        color: #000000;
    -        background-color: inherit;
    -        word-spacing: normal;
    -        letter-spacing: normal;
    -        vertical-align: baseline;
    -        text-decoration: none;
    -        text-transform: none;
    -        line-height: normal;
    -        margin-top: 6pt;
    -        margin-bottom: 0pt;
    -        margin-left: 0pt;
    -        margin-right: 0cm;
    -        padding-top: 0pt;
    -        padding-bottom: 0pt;
    -        padding-left: 10pt;
    -        padding-right: 0pt;
    -        float: none;
    -        clear: none;
    -        text-align: left;
    -        text-indent: 0cm;
    -        width: auto;
    -        height: auto;
    -        white-space: normal;
    -       }
    -
    -.listcontinue3 {
    -        display: block;
    -        font-family: verdana, tahoma, arial, helvetica, sans-serif;
    -        font-style: normal;
    -        font-variant: normal;
    -        font-weight: normal;
    -        font-size: 8pt;
    -        color: #000000;
    -        background-color: inherit;
    -        word-spacing: normal;
    -        letter-spacing: normal;
    -        vertical-align: baseline;
    -        text-decoration: none;
    -        text-transform: none;
    -        line-height: normal;
    -        margin-top: 6pt;
    -        margin-bottom: 0pt;
    -        margin-left: 0pt;
    -        margin-right: 0cm;
    -        padding-top: 0pt;
    -        padding-bottom: 0pt;
    -        padding-left: 10pt;
    -        padding-right: 0pt;
    -        float: none;
    -        clear: none;
    -        text-align: left;
    -        text-indent: 0cm;
    -        width: auto;
    -        height: auto;
    -        white-space: normal;
    -       }
    -
    -ul.listbullet3 {
    -        list-style-type: Square;
    -        list-style-image: none;
    -        list-style-position: outside;
    -        margin-top: 7px;
    -        margin-bottom: 0px;
    -        }
    -li.listbullet3 {
    -	     font-family: verdana, tahoma, arial, helvetica, sans-serif;
    -        font-style: normal;
    -        font-variant: normal;
    -        font-weight: normal;
    -        font-size: 8pt;
    -        color: #13152d;
    -        background-color: inherit;
    -        word-spacing: normal;
    -        letter-spacing: normal;
    -        vertical-align: baseline;
    -        text-decoration: none;
    -        text-transform: none;
    -        line-height: normal;
    -        margin: 0px;
    -        padding: 0 0 6px 0;
    -        float: none;
    -        clear: none;
    -        text-align: left;
    -        text-indent: 0cm;
    -        width: auto;
    -        height: auto;
    -        white-space: normal;
    -       }
    -ol.procedurelistnumber2 {
    -        list-style-type: lower-alpha;
    -        list-style-position: outside;
    -        margin-top: 7pt;
    -        margin-bottom: 0pt;
    -        }
    -li.procedurelistnumber2 {
    -        font-family: verdana, tahoma, arial, helvetica, sans-serif;
    -        font-style: normal;
    -        font-variant: normal;
    -        font-weight: normal;
    -        font-size: 8pt;
    -        color: #000000;
    -        background-color: inherit;
    -        word-spacing: normal;
    -        letter-spacing: normal;
    -        vertical-align: baseline;
    -        text-decoration: none;
    -        text-transform: none;
    -        line-height: normal;
    -        margin-top: 6pt;
    -        margin-bottom: 0pt;
    -        margin-left: 0pt;
    -        margin-right: 0pt;
    -        padding: 0px;
    -        float: none;
    -        clear: none;
    -        text-align: left;
    -        text-indent: 0cm;
    -        width: auto;
    -        height: auto;
    -        white-space: normal;
    -       }
    -.listnote2 {
    -        display: block;
    -        font-family: verdana, tahoma, arial, helvetica, sans-serif;
    -        font-style: normal;
    -        font-variant: normal;
    -        font-weight: normal;
    -        font-size: 8pt;
    -        color: #000000;
    -        background-color: #fffdec;
    -        word-spacing: normal;
    -        letter-spacing: normal;
    -        vertical-align: baseline;
    -        text-decoration: none;
    -        text-transform: none;
    -        line-height: normal;
    -        margin-top: 6pt;
    -        margin-bottom: 6pt;
    -        margin-left: 0pt;
    -        margin-right: 6pt;
    -        padding-top: 4pt;
    -        padding-bottom: 4pt;
    -        padding-left: 4pt;
    -        padding-right: 4pt;
    -        border: 2px solid #f8c701;
    -        float: none;
    -        clear: none;
    -        text-align: left;
    -        text-indent: 0cm;
    -        width: 97%;
    -        height: auto;
    -        white-space: normal;
    -       }
    -ol.listnumber2 {
    -        list-style-type: Decimal;
    -        list-style-position: outside;
    -        margin-top: 7pt;
    -        margin-bottom: 0pt;
    -        }
    -li.listnumber2 {
    -        font-family: verdana, tahoma, arial, helvetica, sans-serif;
    -        font-style: normal;
    -        font-variant: normal;
    -        font-weight: normal;
    -        font-size: 8pt;
    -        color: #000000;
    -        background-color: inherit;
    -        word-spacing: normal;
    -        letter-spacing: normal;
    -        vertical-align: baseline;
    -        text-decoration: none;
    -        text-transform: none;
    -        line-height: normal;
    -        margin-top: 6pt;
    -        margin-bottom: 0pt;
    -        margin-left: 0pt;
    -        margin-right: 0pt;
    -        padding-top: 0pt;
    -        padding-bottom: 0pt;
    -        padding-left: 0pt;
    -        padding-right: 0pt;
    -        float: none;
    -        clear: none;
    -        text-align: left;
    -        text-indent: 0cm;
    -        width: auto;
    -        height: auto;
    -        white-space: normal;
    -       }
    -.warning {
    -        font-family: verdana, tahoma, arial, helvetica, sans-serif;
    -        font-style: normal;
    -        font-variant: normal;
    -        font-weight: normal;
    -        font-size: 8pt;
    -        color: #000000;
    -        background-color: #fff5f0;
    -        word-spacing: normal;
    -        letter-spacing: normal;
    -        vertical-align: baseline;
    -        text-decoration: none;
    -        text-transform: none;
    -        line-height: normal;
    -        margin-top: 6pt;
    -        margin-bottom: 6pt;
    -        margin-left: 0cm;
    -        margin-right: 6pt;
    -        padding-top: 4pt;
    -        padding-bottom: 4pt;
    -        padding-left: 4pt;
    -        padding-right: 4pt;
    -        border: 2px solid #e64a00;
    -        float: none;
    -        clear: none;
    -        text-align: left;
    -        text-indent: 0cm;
    -        width: auto;
    -        height: auto;
    -        white-space: normal;
    -       }
    -
    -.heading1 {
    -        font-family: arial, helvetica, sans-serif, tahoma, verdana;
    -        font-style: normal;
    -        font-variant: normal;
    -        font-size: 12pt;
    -        color: #6a6a6a;
    -        background-color: inherit;
    -        word-spacing: normal;
    -        letter-spacing: normal;
    -        vertical-align: baseline;
    -        text-decoration: none;
    -        text-transform: none;
    -        line-height: normal;
    -        margin-top: 18px;
    -        margin-bottom: 18px;
    -        margin-left: 0cm;
    -        margin-right: 0cm;
    -        padding-top: 0pt;
    -        padding-bottom: 0pt;
    -        padding-left: 0pt;
    -        padding-right: 0pt;
    -        float: none;
    -        clear: none;
    -        text-align: left;
    -        text-indent: 0cm;
    -        width: auto;
    -        height: auto;
    -        white-space: normal;
    -       }
    -
    -.heading2 {
    -        font-family: arial, helvetica, sans-serif, tahoma, verdana;
    -        font-style: normal;
    -        font-variant: normal;
    -		  font-size: 12pt;
    -        color: #5c5b64;
    -        background-color: inherit;
    -        word-spacing: normal;
    -        letter-spacing: normal;
    -        vertical-align: baseline;
    -        text-decoration: none;
    -        text-transform: none;
    -        line-height: normal;
    -        margin-top: 18px;
    -        margin-bottom: 18px;
    -        margin-left: 0cm;
    -        margin-right: 0cm;
    -        padding-top: 0pt;
    -        padding-bottom: 0pt;
    -        padding-left: 0pt;
    -        padding-right: 0pt;
    -        float: none;
    -        clear: none;
    -        text-align: left;
    -        text-indent: 0cm;
    -        width: auto;
    -        height: auto;
    -        white-space: normal;
    -       }
    -.heading3 {
    -        font-family: arial, helvetica, sans-serif, tahoma, verdana;
    -        font-style: normal;
    -        font-variant: normal;
    -        font-size: 12pt;
    -        color: #6a6a6a;
    -        background-color: inherit;
    -        word-spacing: normal;
    -        letter-spacing: normal;
    -        vertical-align: baseline;
    -        text-decoration: none;
    -        text-transform: none;
    -        line-height: normal;
    -        margin-top: 18px;
    -        margin-bottom: 18px;
    -        margin-left: 0cm;
    -        margin-right: 0cm;
    -        padding-top: 0pt;
    -        padding-bottom: 0pt;
    -        padding-left: 0pt;
    -        padding-right: 0pt;
    -        float: none;
    -        clear: none;
    -        text-align: left;
    -        text-indent: 0cm;
    -        width: auto;
    -        height: auto;
    -        white-space: normal;
    -       }
    -.heading4 {
    -        font-family: arial, helvetica, sans-serif, tahoma, verdana;
    -        font-style: normal;
    -        font-variant: normal;
    -		  font-size: 12pt;
    -        color: #6a6a6a;
    -        background-color: inherit;
    -        word-spacing: normal;
    -        letter-spacing: normal;
    -        vertical-align: baseline;
    -        text-decoration: none;
    -        text-transform: none;
    -        line-height: normal;
    -        margin-top: 18px;
    -        margin-bottom: 18px;
    -        margin-left: 0cm;
    -        margin-right: 0cm;
    -        padding-top: 0pt;
    -        padding-bottom: 0pt;
    -        padding-left: 0pt;
    -        padding-right: 0pt;
    -        float: none;
    -        clear: none;
    -        text-align: left;
    -        text-indent: 0cm;
    -        width: auto;
    -        height: auto;
    -        white-space: normal;
    -       }
    -.heading5 {
    -        font-family: arial, helvetica, sans-serif, tahoma, verdana;
    -        font-style: normal;
    -        font-variant: normal;
    -		  font-size: 12pt;
    -        color: #6a6a6a;
    -        background-color: inherit;
    -        word-spacing: normal;
    -        letter-spacing: normal;
    -        vertical-align: baseline;
    -        text-decoration: none;
    -        text-transform: none;
    -        line-height: normal;
    -        margin-top: 18px;
    -        margin-bottom: 18px;
    -        margin-left: 0cm;
    -        margin-right: 0cm;
    -        padding-top: 0pt;
    -        padding-bottom: 0pt;
    -        padding-left: 0pt;
    -        padding-right: 0pt;
    -        float: none;
    -        clear: none;
    -        text-align: left;
    -        text-indent: 0cm;
    -        width: auto;
    -        height: auto;
    -        white-space: normal;
    -       }
    -.heading6 {
    -        font-family: arial, helvetica, sans-serif, tahoma, verdana;
    -        font-variant: normal;
    - 		  font-size: 12pt;
    -        color: #6a6a6a;
    -        background-color: inherit;
    -        word-spacing: normal;
    -        letter-spacing: normal;
    -        vertical-align: baseline;
    -        text-decoration: none;
    -        text-transform: none;
    -        line-height: normal;
    -        margin-top: 18px;
    -        margin-bottom: 18px;
    -        margin-left: 0cm;
    -        margin-right: 0cm;
    -        padding-top: 0pt;
    -        padding-bottom: 0pt;
    -        padding-left: 0pt;
    -        padding-right: 0pt;
    -        float: none;
    -        clear: none;
    -        text-align: left;
    -        text-indent: 0cm;
    -        width: auto;
    -        height: auto;
    -        white-space: normal;
    -       }
    -.indexatoz {
    -        font-family: arial, helvetica, sans-serif, tahoma, verdana;
    -        font-style: normal;
    -        font-weight: bold;
    -        font-size: 12px;
    -        color: #adadad;
    -        background-color: #f4f4f4;
    -        border: 1px solid #CFCFCF;
    -        margin: -15px -2px 0 -2px;
    -        padding: 6px;
    -		  position: relative;
    -		  z-index:99;
    -       }
    -
    -.indexatoz a:hover {
    -      background-color: #6697cc;
    -      text-decoration: none;
    -      color: #ffffff;
    -      padding: 1px 0;
    -}
    -.indexLetter {
    -	 	  padding-left: 2px;
    -}
    -
    -.indexheading, .indexheading a {
    -        font-family: arial, helvetica, sans-serif, tahoma, verdana;
    -        font-weight: bold;
    -        font-size: 12pt;
    -        color: #e64a00;
    -		  text-decoration: none;
    -        margin: 0px;
    -        padding: 0px;
    -		  padding-top: 10px;
    -		  margin-top: 12px;
    -		  margin-bottom: 2px;
    -		  margin-right: 2px;
    -		  border-bottom: 1px solid #cfcfcf;
    -}
    -.index1, .index2, .index3 {
    -        font-family: tahoma, verdana, arial, helvetica, sans-serif;
    -        font-size: 8pt;
    -        color: #000000;
    -        text-decoration: none;
    -        margin: 0px;
    -        padding-top: 3px;
    -        padding-bottom: 0px;
    -        padding-left: 0px;
    -        padding-right: 0px;
    -}
    -.indexlink, .index1link {
    -        padding: 0px;
    -		  padding-top: 3px;
    -		  margin: 0px;
    -}
    -.index1link {
    -		  padding-left: 18px;
    -}
    -.toc {
    -        font-family: tahoma, verdana, arial, helvetica, sans-serif;
    -        font-style: normal;
    -        font-variant: normal;
    -        font-weight: normal;
    -        font-size: 8pt;
    -		  padding-left: 8px;
    -		  padding-right: 5px;
    -        vertical-align: top;
    -       }
    -span.toc {
    -	line-height: 19px;
    -}
    -
    -.searchDetails {
    -        font-family: tahoma, verdana, arial, helvetica, sans-serif;
    -        font-size: 11px;
    -        color: #666666;
    -        background-color: #ffffff;
    -		  border: 1px solid #CFCFCF;
    -        margin: 5px;
    -		  padding-left: 10px;
    - 		  padding-right: 10px;
    -		  padding-top: 3px;
    -		  padding-bottom: 9px;
    -		  line-height: 20px;
    -}
    -.inputText {
    -		  width: 60%;
    -		  height: 16px;
    -        font-family: tahoma, verdana, arial, helvetica, sans-serif;
    -        font-size: 12px;
    -        color: #000000;
    -}
    -form {
    -	margin: 0px;
    -}
    -.search {
    -        font-family: tahoma, verdana, arial, helvetica, sans-serif;
    -        font-size: 8pt;
    -        color: #000000;
    -        vertical-align: top;
    -        margin: 0px;
    -        padding: 0px 10px;
    -       }
    -.searchFound {
    -	font-weight: bold;
    -	color: #1f202c;
    -	padding-top: 5px;
    -	padding-bottom: 10px;
    -	margin: 0px;
    -}
    -.searchResults {
    -	padding-bottom: 10px;
    -	padding-top: 5px;
    -	margin: 0px;
    -	border-top: 1px solid #cfcfcf;
    -}
    -.searchResults a {
    -	font-weight: bold;
    -}
    -.searchFoundWord {
    -	background-color: #fffdce;
    -}
    -.searchToTop {
    -	text-align: left;
    -	border-top: 1px solid #cfcfcf;
    -	padding: 7px 0px 15px 0px;
    -	margin: 0px;
    -}
    diff --git a/build/aps/README b/build/aps/README
    deleted file mode 100644
    index 6d9b8098977..00000000000
    --- a/build/aps/README
    +++ /dev/null
    @@ -1,20 +0,0 @@
    -README (English)
    -##################################################
    -This directory is dedicated to APS package building
    -##################################################
    -
    -Docs for APS format 1.1:
    -http://www.apsstandard.org/r/doc/aps-format-1.1-packaging-guide/index.htm
    -
    -Docs for APS format 1.2 (need APP-LIST.xml):
    -http://www.apsstandard.org/r/doc/aps-format-1.2-packaging-guide/index.htm
    -
    -
    -To check an APS package on Debian:
    -* Install libgdiplus with 
    -apt-get install libgdiplus
    -* Install apslint.exe (http://www.apsstandard.org/r/doc/aps-format-1.2-packaging-guide/57414.htm)
    -tar -xvf xxxx.tgz 
    -* Go into directory of apslint and run command
    -mono ./apslint.exe '/media/DATA/Mes Developpements/dolibarr/build/dolibarr-3.1.0-dev.app.zip' 
    -
    diff --git a/build/aps/configure.php b/build/aps/configure.php
    deleted file mode 100755
    index 1b2565e3dc8..00000000000
    --- a/build/aps/configure.php
    +++ /dev/null
    @@ -1,151 +0,0 @@
    -#!/usr/bin/env php
    -<?php
    -/*-----------------------------------------------------
    - *
    - *----------------------------------------------------- */
    -
    -// This is list of predefined variables when script is ran
    -// We have to set them manually to run script outside context.
    -/*putenv('SETTINGS_admin_name=admin');
    -putenv('SETTINGS_admin_password=admin-ad');
    -putenv('BASE_URL_SCHEME=http');
    -putenv('BASE_URL_HOST=localhost');
    -putenv('BASE_URL_PORT=0');
    -putenv('BASE_URL_PATH=/');
    -//putenv('WEB___DIR=/var/wwww/dolibarr/htdocs');      // WEB___DIR is dir to htdocs
    -putenv('WEB___DIR=../htdocs');      // WEB___DIR is dir to htdocs
    -putenv('DB_main_NAME=dolibarr');
    -putenv('DB_main_HOST=localhost');
    -putenv('DB_main_PORT=3306');
    -putenv('DB_main_LOGIN=root');
    -putenv('DB_main_PASSWORD=root');
    -*/
    -
    -// Check parameters
    -if(count($_SERVER['argv']) < 2)
    -{
    -    print "Usage: configure.php (install | upgrade <version> | configure | remove)\n";
    -    exit(1);
    -}
    -$command = $_SERVER['argv'][1]; //$command stores the argument with which the script was invoked.
    -
    -
    -if($command == "install")
    -{
    -    $db_id = 'main';
    -
    -    $rootdir = getenv("WEB___DIR");
    -    if ($rootdir != '/') $rootdir = preg_replace('/\/$/','',$rootdir);  // Remove last /
    -    $datadir = $rootdir.'/dolibarr_documents';
    -
    -    //List of database-related variables that are passed to the configuration
    -    //script. See the 6.3.1.1.1. Environment variables section of the
    -    //Specification for details.
    -    $db_address = getenv("DB_${db_id}_HOST");
    -    $db_port = getenv("DB_${db_id}_PORT");
    -    $dblogin = getenv("DB_${db_id}_LOGIN");
    -    $dbpassword = getenv("DB_${db_id}_PASSWORD");
    -    $dbname = getenv("DB_${db_id}_NAME");
    -
    -
    -    //PHP functions for connecting to the mysql server and
    -    //executing SQL queries.
    -    //mysql_connect($dbaddress, $dblogin, $dbpassword);
    -    //mysql_select_db($dbname);
    -    /*
    -     $sql_queries = file($query_file);
    -     foreach ($sql_queries as $query) mysql_query($query);
    -     */
    -
    -
    -    //Other code to be executed on invoking configure with
    -    //the install argument.
    -
    -    // Create empty config file
    -    $file=$rootdir.'/conf/conf.php';
    -    print "Create conf file ".$file."\n";
    -    $fp = fopen($file, 'wb');
    -    if ($fp)
    -    {
    -        fclose($fp);
    -        chmod($file,0775);
    -    }
    -    else
    -    {
    -        print "configure.php install: Unable to write file $file.\n";
    -        exit(1);
    -    }
    -
    -    // Create empty directory that will be used by software to store uploaded documents
    -    print "Create directory ".$datadir."\n";
    -    @mkdir($datadir);
    -    chmod($datadir,0775);
    -
    -    // Create install.forced.php into htdocs/install directory with value.
    -    // This will set parameters of install for web installer wizard.
    -    $file_source=$rootdir.'/../build/aps/install.forced.php.install';
    -    $file=$rootdir.'/install/install.forced.php';
    -    print "Create file ".$file.' from '.$file_source."\n";
    -
    -    $modify_hash=array(
    -    'WEB___DIR'=>$rootdir,
    -    'DB_'.$db_id.'_HOST'=>$db_address,
    -    'DB_'.$db_id.'_PORT'=>$db_port,
    -    'DB_'.$db_id.'_LOGIN'=>$dblogin,
    -    'DB_'.$db_id.'_PASSWORD'=>$dbpassword,
    -    'DB_'.$db_id.'_NAME'=>$dbname
    -    );
    -
    -    $file_content = fread(fopen($file_source, 'r'), filesize($file_source));
    -    foreach($modify_hash as $param => $val){
    -        $file_content = str_replace($param, php_quote($val), $file_content);
    -    }
    -    $fp = fopen($file, 'wb');
    -    if ($fp)
    -    {
    -        fputs($fp, $file_content);
    -        fputs($fp, "\n");
    -        fclose($fp);
    -        chmod($file,0775);
    -    }
    -    else
    -    {
    -        print "configure.php install: Unable to write file $file.\n";
    -        exit(2);
    -    }
    -
    -    exit(0);
    -}
    -
    -if($command == "remove")
    -{
    -    //Code to be executed on invoking configure with the remove argument
    -    exit(0);
    -}
    -
    -if($command == "upgrade")
    -{
    -    //Code to be executed on invoking configure with the upgrade argument
    -    exit(0);
    -}
    -
    -if($command == "configure")
    -{
    -    //Code to be executed on invoking configure with the configure argument
    -    exit(0);
    -}
    -
    -print "configure.php: Error: unknown command $command.\n";
    -exit(1);
    -
    -
    -
    -// Content of file-util.php we need
    -
    -function php_quote($val)
    -{
    -    $res_val = str_replace("\\", "\\\\", $val);
    -    $res_val = str_replace("'", "\\'", $res_val);
    -    return $res_val;
    -}
    -
    diff --git a/build/aps/install.forced.php.install b/build/aps/install.forced.php.install
    deleted file mode 100644
    index a7a3f03c14c..00000000000
    --- a/build/aps/install.forced.php.install
    +++ /dev/null
    @@ -1,23 +0,0 @@
    -<?php
    -// File to force Dolibarr wizard installer choices.
    -//
    -// This file must be present into htdocs/install directory
    -// during install process to be used.
    -//
    -//
    -$force_install_noedit=1;
    -$force_install_message='KeepDefaultValuesDeb';
    -$force_install_main_data_root='WEB___DIR/dolibarr_documents';
    -$force_install_type='mysqli';
    -$force_install_dbserver='DB_main_HOST';
    -$force_install_port='DB_main_PORT';
    -$force_install_database='DB_main_NAME';
    -$force_install_createdatabase='0';
    -$force_install_databaselogin='DB_main_LOGIN';
    -$force_install_databasepass='DB_main_PASSWORD';
    -$force_install_createuser='0';
    -$force_install_databaserootlogin='';
    -$force_install_databaserootpass='';
    -$force_install_dolibarrlogin='admin';
    -$force_install_nophpinfo='1';
    -$force_install_lockinstall='444';
    diff --git a/build/flatpack/org.flatpak.Dolibarr.json b/build/flatpack/org.flatpak.Dolibarr.json
    new file mode 100644
    index 00000000000..9e2135cf0a3
    --- /dev/null
    +++ b/build/flatpack/org.flatpak.Dolibarr.json
    @@ -0,0 +1 @@
    +Help wanted...
    \ No newline at end of file
    diff --git a/build/makepack-dolibarr.pl b/build/makepack-dolibarr.pl
    index 1ab3269d0de..01e282aa492 100755
    --- a/build/makepack-dolibarr.pl
    +++ b/build/makepack-dolibarr.pl
    @@ -22,7 +22,7 @@ $PUBLISHSTABLE="eldy,dolibarr\@frs.sourceforge.net:/home/frs/project/dolibarr";
     $PUBLISHBETARC="dolibarr\@vmprod1.dolibarr.org:/home/dolibarr/dolibarr.org/httpdocs/files";
     
     
    -#@LISTETARGET=("TGZ","ZIP","RPM_GENERIC","RPM_FEDORA","RPM_MANDRIVA","RPM_OPENSUSE","DEB","APS","EXEDOLIWAMP","SNAPSHOT");   # Possible packages
    +#@LISTETARGET=("TGZ","ZIP","RPM_GENERIC","RPM_FEDORA","RPM_MANDRIVA","RPM_OPENSUSE","DEB","EXEDOLIWAMP","SNAPSHOT");   # Possible packages
     @LISTETARGET=("TGZ","ZIP","RPM_GENERIC","RPM_FEDORA","RPM_MANDRIVA","RPM_OPENSUSE","DEB","EXEDOLIWAMP","SNAPSHOT");   # Possible packages
     %REQUIREMENTPUBLISH=(
     "SF"=>"git ssh rsync",
    @@ -37,7 +37,7 @@ $PUBLISHBETARC="dolibarr\@vmprod1.dolibarr.org:/home/dolibarr/dolibarr.org/httpd
     "RPM_MANDRIVA"=>"rpmbuild",
     "RPM_OPENSUSE"=>"rpmbuild",
     "DEB"=>"dpkg",
    -"APS"=>"zip",
    +"FLATPACK"=>"flatpack",
     "EXEDOLIWAMP"=>"ISCC.exe",
     "SNAPSHOT"=>"tar"
     );
    @@ -142,7 +142,6 @@ $FILENAMETGZ         = "$PROJECT-$MAJOR.$MINOR.$BUILD";
     $FILENAMEZIP         = "$PROJECT-$MAJOR.$MINOR.$BUILD";
     $FILENAMEXZ          = "$PROJECT-$MAJOR.$MINOR.$BUILD";
     $FILENAMEDEB         = "see later";
    -$FILENAMEAPS         = "$PROJECT-$MAJOR.$MINOR.$BUILD.app";
     $FILENAMEEXEDOLIWAMP = "DoliWamp-$MAJOR.$MINOR.$BUILD";
     # For RPM
     $ARCH='noarch';
    @@ -692,7 +691,7 @@ if ($nboftargetok) {
     			print "Go to directory $BUILDROOT\n";
     			$olddir=getcwd();
     			chdir("$BUILDROOT");
    -			$cmd= "xz -9 -r $BUILDROOT/$FILENAMEAPS.xz \*";
    +			$cmd= "xz -9 -r $BUILDROOT/$FILENAMEXZ.xz \*";
     			print $cmd."\n";
     			$ret= `$cmd`;
     			chdir("$olddir");
    @@ -1033,92 +1032,6 @@ if ($nboftargetok) {
     			next;
     		}
     		
    -		if ($target eq 'APS') 
    -		{
    -			$NEWDESTI=$DESTI;
    -			if ($NEWDESTI =~ /stable/)
    -			{
    -				mkdir($DESTI.'/package_aps');
    -				if (-d $DESTI.'/package_aps') { $NEWDESTI=$DESTI.'/package_aps'; }
    -			} 
    -			
    -			$newbuild = $BUILD;
    -			$newbuild =~ s/(dev|alpha)/0/gi;                # dev
    -			$newbuild =~ s/beta/1/gi;                       # beta
    -			$newbuild =~ s/rc./2/gi;                        # rc
    -			if ($newbuild !~ /-/) { $newbuild.='-3'; }      # finale
    -			# now newbuild is 0-0 or 0-3 for example
    -			$REL1 = $newbuild; $REL1 =~ s/-.*$//gi;
    -			if ($RPMSUBVERSION eq 'auto') { $RPMSUBVERSION = $newbuild; $RPMSUBVERSION =~ s/^.*-//gi; }
    -			print "Version is $MAJOR.$MINOR.$REL1-$RPMSUBVERSION\n";
    -			
    -			print "Remove target $FILENAMEAPS.zip...\n";
    -			unlink "$NEWDESTI/$FILENAMEAPS.zip";
    -
    -			#rmdir "$BUILDROOT/$PROJECT.tmp";
    -			$ret=`rm -fr $BUILDROOT/$PROJECT.tmp`;
    -			print "Create directory $BUILDROOT/$PROJECT.tmp\n";
    -			$ret=`mkdir -p "$BUILDROOT/$PROJECT.tmp"`;
    -			print "Copy $BUILDROOT/$PROJECT to $BUILDROOT/$PROJECT.tmp\n";
    -			$cmd="cp -pr \"$BUILDROOT/$PROJECT\" \"$BUILDROOT/$PROJECT.tmp\"";
    -			$ret=`$cmd`;
    -
    -			print "Remove other files\n";
    -			$ret=`rm -fr $BUILDROOT/$PROJECT.tmp/$PROJECT/build/deb`;
    -			$ret=`rm -fr $BUILDROOT/$PROJECT.tmp/$PROJECT/build/dmg`;
    -			$ret=`rm -fr $BUILDROOT/$PROJECT.tmp/$PROJECT/build/doap`;
    -			$ret=`rm -fr $BUILDROOT/$PROJECT.tmp/$PROJECT/build/exe`;
    -			$ret=`rm -fr $BUILDROOT/$PROJECT.tmp/$PROJECT/build/live`;
    -			$ret=`rm -fr $BUILDROOT/$PROJECT.tmp/$PROJECT/build/patch`;
    -			$ret=`rm -fr $BUILDROOT/$PROJECT.tmp/$PROJECT/build/rpm`;
    -			$ret=`rm -fr $BUILDROOT/$PROJECT.tmp/$PROJECT/build/zip`;
    -			$ret=`rm -fr $BUILDROOT/$PROJECT.tmp/$PROJECT/build/perl`;
    -
    -            $APSVERSION="1.2";
    -            print "Create APS files $BUILDROOT/$PROJECT.tmp/$PROJECT/APP-META.xml\n";
    -            open (SPECFROM,"<$BUILDROOT/$PROJECT/build/aps/APP-META-$APSVERSION.xml") || die "Error";
    -            open (SPECTO,">$BUILDROOT/$PROJECT.tmp/$PROJECT/APP-META.xml") || die "Error";
    -            while (<SPECFROM>) {
    -                $newbuild = $BUILD;
    -                $newbuild =~ s/(dev|alpha)/0/gi;                # dev
    -                $newbuild =~ s/beta/1/gi;                       # beta
    -                $newbuild =~ s/rc./2/gi;                        # rc
    -                if ($newbuild !~ /-/) { $newbuild.='-3'; }      # finale
    -                # now newbuild is 0-0 or 0-3 for example
    -                $_ =~ s/__VERSION__/$MAJOR.$MINOR.$REL1/;
    -                $_ =~ s/__RELEASE__/$RPMSUBVERSION/;
    -                print SPECTO $_;
    -            }
    -            close SPECFROM;
    -            close SPECTO;
    -            print "Version set to $MAJOR.$MINOR.$newbuild\n";
    -            $cmd="cp -pr \"$BUILDROOT/$PROJECT/build/aps/configure.php\" \"$BUILDROOT/$PROJECT.tmp/$PROJECT/scripts/configure.php\"";
    -            $ret=`$cmd`;
    -            $cmd="cp -pr \"$BUILDROOT/$PROJECT/doc/images\" \"$BUILDROOT/$PROJECT.tmp/$PROJECT/images\"";
    -            $ret=`$cmd`;
    - 
    -            print "Remove other files\n";
    -            $ret=`rm -fr $BUILDROOT/$PROJECT.tmp/$PROJECT/dev`;
    -            $ret=`rm -fr $BUILDROOT/$PROJECT.tmp/$PROJECT/doc`;
    -            
    -            print "Build APP-LIST.xml files\n";
    -            
    -            print "Compress $BUILDROOT/$PROJECT.tmp/$PROJECT into $FILENAMEAPS.zip...\n";
    - 
    -            print "Go to directory $BUILDROOT/$PROJECT.tmp\/$PROJECT\n";
    -            $olddir=getcwd();
    -            chdir("$BUILDROOT\/$PROJECT.tmp\/$PROJECT");
    -            $cmd= "zip -9 -r $BUILDROOT/$FILENAMEAPS.zip \*";
    -            print $cmd."\n";
    -            $ret= `$cmd`;
    -            chdir("$olddir");
    -                        
    -    		# Move to final dir
    -            print "Move $BUILDROOT/$FILENAMEAPS.zip to $NEWDESTI/$FILENAMEAPS.zip\n";
    -            $ret=`mv "$BUILDROOT/$FILENAMEAPS.zip" "$NEWDESTI/$FILENAMEAPS.zip"`;
    -            next;
    -    	}
    -
     		if ($target eq 'EXEDOLIWAMP')
     		{
     			$NEWDESTI=$DESTI;
    diff --git a/build/rpm/dolibarr_fedora.spec b/build/rpm/dolibarr_fedora.spec
    index d5a9189229e..727875485b4 100755
    --- a/build/rpm/dolibarr_fedora.spec
    +++ b/build/rpm/dolibarr_fedora.spec
    @@ -177,6 +177,7 @@ done >>%{name}.lang
     %_datadir/dolibarr/htdocs/core
     %_datadir/dolibarr/htdocs/cron
     %_datadir/dolibarr/htdocs/custom
    +%_datadir/dolibarr/htdocs/datapolicy
     %_datadir/dolibarr/htdocs/dav
     %_datadir/dolibarr/htdocs/don
     %_datadir/dolibarr/htdocs/ecm
    @@ -212,6 +213,7 @@ done >>%{name}.lang
     %_datadir/dolibarr/htdocs/supplier_proposal
     %_datadir/dolibarr/htdocs/support
     %_datadir/dolibarr/htdocs/theme
    +%_datadir/dolibarr/htdocs/takepos
     %_datadir/dolibarr/htdocs/ticket
     %_datadir/dolibarr/htdocs/user
     %_datadir/dolibarr/htdocs/variants
    diff --git a/build/rpm/dolibarr_generic.spec b/build/rpm/dolibarr_generic.spec
    index 673d5919d1a..3fb68d06a15 100755
    --- a/build/rpm/dolibarr_generic.spec
    +++ b/build/rpm/dolibarr_generic.spec
    @@ -54,7 +54,7 @@ BuildRequires: desktop-file-utils
     Group: Applications/Productivity
     Requires: apache-base, apache-mod_php, php-cgi, php-cli, php-bz2, php-gd, php-ldap, php-imap, php-mysqli, php-openssl, fonts-ttf-dejavu 
     Requires: mysql, mysql-client 
    -%else
    +%else%_datadir/dolibarr/htdocs/datapolicy
     %if 0%{?suse_version}
     # Voir http://en.opensuse.org/openSUSE:Packaging_Conventions_RPM_Macros
     Group: Productivity/Office/Management
    @@ -124,7 +124,7 @@ cui hai bisogno ed essere facile da usare.
     
     %if 0%{?sles_version}
     %{__rm} -rf $RPM_BUILD_ROOT
    -%{__mkdir} $RPM_BUILD_ROOT
    +%{__mkdir} $RPM_BUILD_ROOT%_datadir/dolibarr/htdocs/datapolicy
     %{__mkdir} $RPM_BUILD_ROOT%{_sysconfdir}
     %{__mkdir} $RPM_BUILD_ROOT%{_sysconfdir}/%{name}
     %else
    @@ -257,6 +257,7 @@ done >>%{name}.lang
     %_datadir/dolibarr/htdocs/core
     %_datadir/dolibarr/htdocs/cron
     %_datadir/dolibarr/htdocs/custom
    +%_datadir/dolibarr/htdocs/datapolicy
     %_datadir/dolibarr/htdocs/dav
     %_datadir/dolibarr/htdocs/don
     %_datadir/dolibarr/htdocs/ecm
    @@ -292,6 +293,7 @@ done >>%{name}.lang
     %_datadir/dolibarr/htdocs/supplier_proposal
     %_datadir/dolibarr/htdocs/support
     %_datadir/dolibarr/htdocs/theme
    +%_datadir/dolibarr/htdocs/takepos
     %_datadir/dolibarr/htdocs/ticket
     %_datadir/dolibarr/htdocs/user
     %_datadir/dolibarr/htdocs/variants
    diff --git a/build/rpm/dolibarr_mandriva.spec b/build/rpm/dolibarr_mandriva.spec
    index e3d2a849db2..a4004273211 100755
    --- a/build/rpm/dolibarr_mandriva.spec
    +++ b/build/rpm/dolibarr_mandriva.spec
    @@ -174,6 +174,7 @@ done >>%{name}.lang
     %_datadir/dolibarr/htdocs/core
     %_datadir/dolibarr/htdocs/cron
     %_datadir/dolibarr/htdocs/custom
    +%_datadir/dolibarr/htdocs/datapolicy
     %_datadir/dolibarr/htdocs/dav
     %_datadir/dolibarr/htdocs/don
     %_datadir/dolibarr/htdocs/ecm
    @@ -209,6 +210,7 @@ done >>%{name}.lang
     %_datadir/dolibarr/htdocs/supplier_proposal
     %_datadir/dolibarr/htdocs/support
     %_datadir/dolibarr/htdocs/theme
    +%_datadir/dolibarr/htdocs/takepos
     %_datadir/dolibarr/htdocs/ticket
     %_datadir/dolibarr/htdocs/user
     %_datadir/dolibarr/htdocs/variants
    diff --git a/build/rpm/dolibarr_opensuse.spec b/build/rpm/dolibarr_opensuse.spec
    index 5a64bec2e78..478a889c8d6 100755
    --- a/build/rpm/dolibarr_opensuse.spec
    +++ b/build/rpm/dolibarr_opensuse.spec
    @@ -185,6 +185,7 @@ done >>%{name}.lang
     %_datadir/dolibarr/htdocs/core
     %_datadir/dolibarr/htdocs/cron
     %_datadir/dolibarr/htdocs/custom
    +%_datadir/dolibarr/htdocs/datapolicy
     %_datadir/dolibarr/htdocs/dav
     %_datadir/dolibarr/htdocs/don
     %_datadir/dolibarr/htdocs/ecm
    @@ -220,6 +221,7 @@ done >>%{name}.lang
     %_datadir/dolibarr/htdocs/supplier_proposal
     %_datadir/dolibarr/htdocs/support
     %_datadir/dolibarr/htdocs/theme
    +%_datadir/dolibarr/htdocs/takepos
     %_datadir/dolibarr/htdocs/ticket
     %_datadir/dolibarr/htdocs/user
     %_datadir/dolibarr/htdocs/variants
    diff --git a/dev/dolibarr_changes.txt b/dev/dolibarr_changes.txt
    index 6303eaafaae..37aef014e63 100644
    --- a/dev/dolibarr_changes.txt
    +++ b/dev/dolibarr_changes.txt
    @@ -1,5 +1,5 @@
     
    -This file describe changes made on external library after beeing included
    +This file describes changes made on external libraries after being included
     in Dolibarr root.
     
     
    @@ -78,17 +78,24 @@ In htdocs/includes/tcpdf/tcpdf.php
     +       protected $default_monospaced_font = 'freemono';
     
     
    +		
     
     TCPDI:
     ------
     Add fpdf_tpl.php 1.2
     Add tcpdi.php
    +
     Add tcpdi_parser.php and replace:
     require_once(dirname(__FILE__).'/include/tcpdf_filters.php');
     with:
     require_once(dirname(__FILE__).'/../tecnickcom/tcpdf/include/tcpdf_filters.php');
     
     
    +* Fix by replacing
    +	} elseif (($key == '/Index') AND ($v[0] == PDF_TYPE_ARRAY AND count($v[1] >= 2))) {
    +with
    +	} elseif (($key == '/Index') AND ($v[0] == PDF_TYPE_ARRAY AND count($v[1]) >= 2)) {
    +
     
     
     JSGANTT:
    diff --git a/dev/examples/mail/dolibarr_mail_simpleHTML.txt b/dev/examples/mail/dolibarr_mail_simpleHTML.txt
    index 5c552221ca6..391800f5095 100644
    --- a/dev/examples/mail/dolibarr_mail_simpleHTML.txt
    +++ b/dev/examples/mail/dolibarr_mail_simpleHTML.txt
    @@ -4,4 +4,4 @@ X-Mailer: Dolibarr version 2.7.0-beta (using php mail)
     MIME-Version: 1.0
     Content-Type: text/html; charset=UTF-8
     Content-Transfer-Encoding: 8bit
    -<html><head><title></title></head><body>Test&eacute;<br />fdsfsdf<br />fsdf<strong>sfd</strong>s<br />fssdfsd<br /></body></html>
    +<html><head><title></title></head><body>Test&eacute;<br>fdsfsdf<br>fsdf<strong>sfd</strong>s<br>fssdfsd<br></body></html>
    diff --git a/doc/images/dolibarr_screenshot5_1920x1080_b.jpg b/doc/images/dolibarr_screenshot5_1920x1080_b.jpg
    index 5f7d8a5b573..0b5c749cb5c 100644
    Binary files a/doc/images/dolibarr_screenshot5_1920x1080_b.jpg and b/doc/images/dolibarr_screenshot5_1920x1080_b.jpg differ
    diff --git a/doc/index.html b/doc/index.html
    index b888b13d9a6..5c655136e3e 100644
    --- a/doc/index.html
    +++ b/doc/index.html
    @@ -11,15 +11,15 @@ informations on Dolibarr.<br>
     But if you are looking for other resources (downloads, documentation, addons, ...), you can find this
     on Internet on web following sites:<br>
     <br>
    -* <a href="http://wiki.dolibarr.org">Dolibarr wiki (documentation)</a><br>
    +* <a href="https://wiki.dolibarr.org">Dolibarr wiki (documentation)</a><br>
     <br>
    -* <a href="http://www.dolibarr.org">Dolibarr portal (official website)</a><br>
    +* <a href="https://www.dolibarr.org">Dolibarr portal (official website)</a><br>
     <br>
    -* <a href="http://demo.dolibarr.org">Dolibarr demo (online)</a><br>
    +* <a href="https://demo.dolibarr.org">Dolibarr demo (online)</a><br>
     <br>
    -* <a href="http://www.nltechno.com/pages/dolibarrwinbin.php">DoliWamp, the Dolibarr for Windows</a><br>
    +* <a href="https://www.nltechno.com/pages/dolibarrwinbin.php">DoliWamp, the Dolibarr for Windows</a><br>
     <br>
    -* <a href="http://www.dolistore.com">DoliStore (official addons/plugins market place)</a><br>
    +* <a href="https://www.dolistore.com">DoliStore (official addons/plugins market place)</a><br>
     
     </body>
     </html>
    \ No newline at end of file
    diff --git a/doc/install/README-FR b/doc/install/README-FR
    index f954601ae0d..2cee29cf2df 100644
    --- a/doc/install/README-FR
    +++ b/doc/install/README-FR
    @@ -9,19 +9,19 @@ Téléchargement
     * Dolibarr ERP/CRM can be downloaded at sourceforge:
     http://sourceforge.net/projects/dolibarr/files
     or from Dolibarr official web site:
    -http://www.dolibarr.org
    +https://www.dolibarr.org
     
     * Most external modules are only available on DoliStore:
    -http://www.dolistore.org
    +https://www.dolistore.org
     
     
     --------------------------------
     Documentation utilisateur
     --------------------------------
     
    -* Pour une prise en main et installation rapide, consulter le fichier
    +* Pour une prise en main et installation rapide, consultez le fichier
     README-FR à la racine.
     
    -* Une documentation utilisateur francophone plus consistente est disponible en
    +* Une documentation utilisateur francophone plus consistante est disponible en
     ligne sur le wiki de Dolibarr à l'adresse:
    -http://wiki.dolibarr.org
    +https://wiki.dolibarr.org
    diff --git a/doc/user/README b/doc/user/README
    index 19507dba0e4..129dff11058 100644
    --- a/doc/user/README
    +++ b/doc/user/README
    @@ -4,4 +4,4 @@ User guide
     --------------------------------
     
     * All Dolibarr guides are available, on line, on the Dolibarr Web site:
    -http://www.dolibarr.org
    +https://www.dolibarr.org
    diff --git a/doc/user/README-FR b/doc/user/README-FR
    index f3a839de008..fbf67fd89bc 100644
    --- a/doc/user/README-FR
    +++ b/doc/user/README-FR
    @@ -3,9 +3,9 @@ README (french)
     Documentation utilisateur
     --------------------------------
     
    -* Pour une prise en main et installation rapide, consulter le fichier
    +* Pour une prise en main et installation rapide, consultez le fichier
     README-FR à la racine.
     
    -* Une documentation utilisateur francophone plus consistente est disponible en
    +* Une documentation utilisateur francophone plus consistante est disponible en
     ligne sur le site Web de Dolibarr à l'adresse:
    -http://www.dolibarr.fr
    +https://www.dolibarr.fr
    diff --git a/htdocs/accountancy/admin/account.php b/htdocs/accountancy/admin/account.php
    index 087f9957f16..c9b72d9cc4c 100644
    --- a/htdocs/accountancy/admin/account.php
    +++ b/htdocs/accountancy/admin/account.php
    @@ -38,11 +38,11 @@ $id = GETPOST('id', 'int');
     $rowid = GETPOST('rowid', 'int');
     $contextpage=GETPOST('contextpage','aZ')?GETPOST('contextpage','aZ'):'accountingaccountlist';   // To manage different context of search
     
    -$search_account = GETPOST("search_account");
    -$search_label = GETPOST("search_label");
    -$search_accountparent = GETPOST("search_accountparent");
    -$search_pcgtype = GETPOST("search_pcgtype");
    -$search_pcgsubtype = GETPOST("search_pcgsubtype");
    +$search_account = GETPOST('search_account','alpha');
    +$search_label = GETPOST('search_label','alpha');
    +$search_accountparent = GETPOST('search_accountparent','alpha');
    +$search_pcgtype = GETPOST('search_pcgtype','alpha');
    +$search_pcgsubtype = GETPOST('search_pcgsubtype','alpha');
     
     // Security check
     if ($user->societe_id > 0) accessforbidden();
    diff --git a/htdocs/accountancy/admin/accountmodel.php b/htdocs/accountancy/admin/accountmodel.php
    index e3ed164d60b..efa23a6a586 100644
    --- a/htdocs/accountancy/admin/accountmodel.php
    +++ b/htdocs/accountancy/admin/accountmodel.php
    @@ -55,8 +55,8 @@ $acts[1] = "disable";
     $actl[0] = img_picto($langs->trans("Disabled"),'switch_off');
     $actl[1] = img_picto($langs->trans("Activated"),'switch_on');
     
    -$listoffset=GETPOST('listoffset');
    -$listlimit=GETPOST('listlimit')>0?GETPOST('listlimit'):1000;
    +$listoffset=GETPOST('listoffset','alpha');
    +$listlimit=GETPOST('listlimit','int')>0?GETPOST('listlimit','int'):1000;
     $active = 1;
     
     $sortfield = GETPOST("sortfield",'aZ09comma');
    @@ -139,13 +139,13 @@ $sourceList=array();
      * Actions
      */
     
    -if (GETPOST('button_removefilter') || GETPOST('button_removefilter.x') || GETPOST('button_removefilter_x'))
    +if (GETPOST('button_removefilter','alpha') || GETPOST('button_removefilter.x','alpha') || GETPOST('button_removefilter_x','alpha'))
     {
     	$search_country_id = '';
     }
     
     // Actions add or modify an entry into a dictionary
    -if (GETPOST('actionadd') || GETPOST('actionmodify'))
    +if (GETPOST('actionadd','alpha') || GETPOST('actionmodify','alpha'))
     {
     	$listfield=explode(',', str_replace(' ', '',$tabfield[$id]));
     	$listfieldinsert=explode(',',$tabfieldinsert[$id]);
    @@ -235,7 +235,7 @@ if (GETPOST('actionadd') || GETPOST('actionmodify'))
     	if ($_POST["accountancy_code_buy"] <= 0) $_POST["accountancy_code_buy"]='';	// If empty, we force to null
     
     	// Si verif ok et action add, on ajoute la ligne
    -	if ($ok && GETPOST('actionadd'))
    +	if ($ok && GETPOST('actionadd','alpha'))
     	{
     		if ($tabrowid[$id])
     		{
    @@ -300,7 +300,7 @@ if (GETPOST('actionadd') || GETPOST('actionmodify'))
     	}
     
     	// Si verif ok et action modify, on modifie la ligne
    -	if ($ok && GETPOST('actionmodify'))
    +	if ($ok && GETPOST('actionmodify','alpha'))
     	{
     		if ($tabrowid[$id]) { $rowidcol=$tabrowid[$id]; }
     		else { $rowidcol="rowid"; }
    @@ -341,7 +341,7 @@ if (GETPOST('actionadd') || GETPOST('actionmodify'))
     	//$_GET["id"]=GETPOST('id', 'int');       // Force affichage dictionnaire en cours d'edition
     }
     
    -if (GETPOST('actioncancel'))
    +if (GETPOST('actioncancel','alpha'))
     {
     	//$_GET["id"]=GETPOST('id', 'int');       // Force affichage dictionnaire en cours d'edition
     }
    @@ -560,7 +560,7 @@ if ($id)
     
     		$obj = new stdClass();
     		// If data was already input, we define them in obj to populate input fields.
    -		if (GETPOST('actionadd'))
    +		if (GETPOST('actionadd','alpha'))
     		{
     			foreach ($fieldlist as $key=>$val)
     			{
    diff --git a/htdocs/accountancy/admin/card.php b/htdocs/accountancy/admin/card.php
    index 6a92a3f6080..74958d606ec 100644
    --- a/htdocs/accountancy/admin/card.php
    +++ b/htdocs/accountancy/admin/card.php
    @@ -73,25 +73,28 @@ if ($action == 'add' && $user->rights->accounting->chartofaccount)
     		// To manage zero or not at the end of the accounting account
     		if($conf->global->ACCOUNTING_MANAGE_ZERO == 1)
     		{
    -			$account_number = GETPOST('account_number');
    +			$account_number = GETPOST('account_number','string');
     		}
     		else
     		{
    -			$account_number = clean_account(GETPOST('account_number'));
    +			$account_number = clean_account(GETPOST('account_number','string'));
     		}
     
    -		if (GETPOST('account_parent') <= 0) {
    +		if (GETPOST('account_parent','int') <= 0)
    +		{
     			$account_parent = 0;
    -		} else {
    +		}
    +		else
    +		{
     			$account_parent = GETPOST('account_parent','int');
     		}
     
     		$object->fk_pcg_version = $obj->pcg_version;
    -		$object->pcg_type = GETPOST('pcg_type');
    -		$object->pcg_subtype = GETPOST('pcg_subtype');
    +		$object->pcg_type = GETPOST('pcg_type','alpha');
    +		$object->pcg_subtype = GETPOST('pcg_subtype','alpha');
     		$object->account_number = $account_number;
     		$object->account_parent = $account_parent;
    -		$object->account_category = GETPOST('account_category');
    +		$object->account_category = GETPOST('account_category','alpha');
     		$object->label = GETPOST('label', 'alpha');
     		$object->active = 1;
     
    @@ -135,25 +138,28 @@ if ($action == 'add' && $user->rights->accounting->chartofaccount)
     		// To manage zero or not at the end of the accounting account
     		if($conf->global->ACCOUNTING_MANAGE_ZERO == 1)
     		{
    -			$account_number = GETPOST('account_number');
    +			$account_number = GETPOST('account_number','string');
     		}
     		else
     		{
    -			$account_number = clean_account(GETPOST('account_number'));
    +			$account_number = clean_account(GETPOST('account_number','string'));
     		}
     
    -		if (GETPOST('account_parent') <= 0) {
    +		if (GETPOST('account_parent','int') <= 0)
    +		{
     			$account_parent = 0;
    -		} else {
    +		}
    +		else
    +		{
     			$account_parent = GETPOST('account_parent','int');
     		}
     
     		$object->fk_pcg_version = $obj->pcg_version;
    -		$object->pcg_type = GETPOST('pcg_type');
    -		$object->pcg_subtype = GETPOST('pcg_subtype');
    +		$object->pcg_type = GETPOST('pcg_type','alpha');
    +		$object->pcg_subtype = GETPOST('pcg_subtype','alpha');
     		$object->account_number = $account_number;
     		$object->account_parent = $account_parent;
    -		$object->account_category = GETPOST('account_category');
    +		$object->account_category = GETPOST('account_category','alpha');
     		$object->label = GETPOST('label', 'alpha');
     
     		$result = $object->update($user);
    diff --git a/htdocs/accountancy/admin/categories.php b/htdocs/accountancy/admin/categories.php
    index 735c5595ddc..6e003738173 100644
    --- a/htdocs/accountancy/admin/categories.php
    +++ b/htdocs/accountancy/admin/categories.php
    @@ -37,9 +37,9 @@ $id = GETPOST('id', 'int');
     $rowid = GETPOST('rowid', 'int');
     $cancel = GETPOST('cancel','alpha');
     $action = GETPOST('action','aZ09');
    -$cat_id = GETPOST('account_category');
    +$cat_id = GETPOST('account_category','int');
     $selectcpt = GETPOST('cpt_bk', 'array');
    -$cpt_id = GETPOST('cptid');
    +$cpt_id = GETPOST('cptid','int');
     
     if ($cat_id == 0) {
     	$cat_id = null;
    diff --git a/htdocs/accountancy/admin/categories_list.php b/htdocs/accountancy/admin/categories_list.php
    index 900205b7588..14a6b56512d 100644
    --- a/htdocs/accountancy/admin/categories_list.php
    +++ b/htdocs/accountancy/admin/categories_list.php
    @@ -51,8 +51,8 @@ $acts[1] = "disable";
     $actl[0] = img_picto($langs->trans("Disabled"),'switch_off');
     $actl[1] = img_picto($langs->trans("Activated"),'switch_on');
     
    -$listoffset=GETPOST('listoffset');
    -$listlimit=GETPOST('listlimit')>0?GETPOST('listlimit'):1000;
    +$listoffset=GETPOST('listoffset','alpha');
    +$listlimit=GETPOST('listlimit','int')>0?GETPOST('listlimit','int'):1000;
     $active = 1;
     
     $sortfield = GETPOST("sortfield",'aZ09comma');
    @@ -134,13 +134,13 @@ $sourceList=array();
      * Actions
      */
     
    -if (GETPOST('button_removefilter') || GETPOST('button_removefilter.x') || GETPOST('button_removefilter_x'))
    +if (GETPOST('button_removefilter','alpha') || GETPOST('button_removefilter.x','alpha') || GETPOST('button_removefilter_x','alpha'))
     {
         $search_country_id = '';
     }
     
     // Actions add or modify an entry into a dictionary
    -if (GETPOST('actionadd') || GETPOST('actionmodify'))
    +if (GETPOST('actionadd','alpha') || GETPOST('actionmodify','alpha'))
     {
         $listfield=explode(',', str_replace(' ', '',$tabfield[$id]));
         $listfieldinsert=explode(',',$tabfieldinsert[$id]);
    @@ -250,7 +250,7 @@ if (GETPOST('actionadd') || GETPOST('actionmodify'))
         }
     
         // Si verif ok et action modify, on modifie la ligne
    -    if ($ok && GETPOST('actionmodify'))
    +    if ($ok && GETPOST('actionmodify','alpha'))
         {
             if ($tabrowid[$id]) { $rowidcol=$tabrowid[$id]; }
             else { $rowidcol="rowid"; }
    @@ -291,7 +291,7 @@ if (GETPOST('actionadd') || GETPOST('actionmodify'))
         //$_GET["id"]=GETPOST('id', 'int');       // Force affichage dictionnaire en cours d'edition
     }
     
    -if (GETPOST('actioncancel'))
    +if (GETPOST('actioncancel','alpha'))
     {
         //$_GET["id"]=GETPOST('id', 'int');       // Force affichage dictionnaire en cours d'edition
     }
    @@ -513,7 +513,7 @@ if ($id)
     
             $obj = new stdClass();
             // If data was already input, we define them in obj to populate input fields.
    -        if (GETPOST('actionadd'))
    +        if (GETPOST('actionadd','alpha'))
             {
                 foreach ($fieldlist as $key=>$val)
                 {
    diff --git a/htdocs/accountancy/admin/defaultaccounts.php b/htdocs/accountancy/admin/defaultaccounts.php
    index 8cd45c1cfda..31fc04fa745 100644
    --- a/htdocs/accountancy/admin/defaultaccounts.php
    +++ b/htdocs/accountancy/admin/defaultaccounts.php
    @@ -76,7 +76,7 @@ $list_account = array (
     $accounting_mode = empty($conf->global->ACCOUNTING_MODE) ? 'RECETTES-DEPENSES' : $conf->global->ACCOUNTING_MODE;
     
     
    -if (GETPOST('change_chart'))
    +if (GETPOST('change_chart', 'alpha'))
     {
         $chartofaccounts = GETPOST('chartofaccounts', 'int');
     
    diff --git a/htdocs/accountancy/admin/export.php b/htdocs/accountancy/admin/export.php
    index 3be285674b5..eccb9b0c06f 100644
    --- a/htdocs/accountancy/admin/export.php
    +++ b/htdocs/accountancy/admin/export.php
    @@ -79,6 +79,7 @@ $model_option = array (
     /*
      * Actions
      */
    +
     if ($action == 'update') {
     	$error = 0;
     
    @@ -124,6 +125,8 @@ if ($action == 'update') {
     	}
     }
     
    +
    +
     /*
      * View
      */
    @@ -267,7 +270,7 @@ if ($num2) {
             } else {
                 print '<input type="text" size="20" id="'. $label .'" name="' . $key['label'] . '" value="' . $conf->global->$label . '">';
             }
    -		
    +
     		print '</td></tr>';
     	}
     
    diff --git a/htdocs/accountancy/admin/fiscalyear_card.php b/htdocs/accountancy/admin/fiscalyear_card.php
    index cc4dd9dbb7f..05c7a3fd174 100644
    --- a/htdocs/accountancy/admin/fiscalyear_card.php
    +++ b/htdocs/accountancy/admin/fiscalyear_card.php
    @@ -166,7 +166,7 @@ if ($action == 'create')
     	print '<table class="border" width="100%">';
     
     	// Label
    -	print '<tr><td class="titlefieldcreate fieldrequired">' . $langs->trans("Label") . '</td><td><input name="label" size="32" value="' . GETPOST("label") . '"></td></tr>';
    +	print '<tr><td class="titlefieldcreate fieldrequired">' . $langs->trans("Label") . '</td><td><input name="label" size="32" value="' . GETPOST('label', 'alpha') . '"></td></tr>';
     
     	// Date start
     	print '<tr><td class="fieldrequired">' . $langs->trans("DateStart") . '</td><td>';
    @@ -183,7 +183,7 @@ if ($action == 'create')
     	print '<tr>';
     	print '<td class="fieldrequired">' . $langs->trans("Status") . '</td>';
     	print '<td class="valeur">';
    -	print $form->selectarray('statut', $statut2label, GETPOST('statut'));
    +	print $form->selectarray('statut', $statut2label, GETPOST('statut', 'int'));
     	print '</td></tr>';
     	*/
     
    diff --git a/htdocs/accountancy/admin/journals_list.php b/htdocs/accountancy/admin/journals_list.php
    index 20d0a5200a5..ae254788b08 100644
    --- a/htdocs/accountancy/admin/journals_list.php
    +++ b/htdocs/accountancy/admin/journals_list.php
    @@ -51,8 +51,8 @@ $acts[1] = "disable";
     $actl[0] = img_picto($langs->trans("Disabled"),'switch_off');
     $actl[1] = img_picto($langs->trans("Activated"),'switch_on');
     
    -$listoffset=GETPOST('listoffset');
    -$listlimit=GETPOST('listlimit')>0?GETPOST('listlimit'):1000;
    +$listoffset=GETPOST('listoffset', 'alpha');
    +$listlimit=GETPOST('listlimit', 'int')>0?GETPOST('listlimit', 'int'):1000;
     $active = 1;
     
     $sortfield = GETPOST("sortfield",'alpha');
    @@ -143,13 +143,13 @@ $sourceList = array(
      * Actions
      */
     
    -if (GETPOST('button_removefilter') || GETPOST('button_removefilter.x') || GETPOST('button_removefilter_x'))
    +if (GETPOST('button_removefilter', 'alpha') || GETPOST('button_removefilter.x', 'alpha') || GETPOST('button_removefilter_x', 'alpha'))
     {
     	$search_country_id = '';
     }
     
     // Actions add or modify an entry into a dictionary
    -if (GETPOST('actionadd') || GETPOST('actionmodify'))
    +if (GETPOST('actionadd', 'alpha') || GETPOST('actionmodify', 'alpha'))
     {
     	$listfield=explode(',', str_replace(' ', '',$tabfield[$id]));
     	$listfieldinsert=explode(',',$tabfieldinsert[$id]);
    @@ -190,7 +190,7 @@ if (GETPOST('actionadd') || GETPOST('actionmodify'))
     	if ($_POST["accountancy_code_buy"] <= 0) $_POST["accountancy_code_buy"]='';	// If empty, we force to null
     
     	// Si verif ok et action add, on ajoute la ligne
    -	if ($ok && GETPOST('actionadd'))
    +	if ($ok && GETPOST('actionadd', 'alpha'))
     	{
     		if ($tabrowid[$id])
     		{
    @@ -252,7 +252,7 @@ if (GETPOST('actionadd') || GETPOST('actionmodify'))
     	}
     
     	// Si verif ok et action modify, on modifie la ligne
    -	if ($ok && GETPOST('actionmodify'))
    +	if ($ok && GETPOST('actionmodify', 'alpha'))
     	{
     		if ($tabrowid[$id]) { $rowidcol=$tabrowid[$id]; }
     		else { $rowidcol="rowid"; }
    @@ -294,7 +294,7 @@ if (GETPOST('actionadd') || GETPOST('actionmodify'))
     	//$_GET["id"]=GETPOST('id', 'int');       // Force affichage dictionnaire en cours d'edition
     }
     
    -//if (GETPOST('actioncancel'))
    +//if (GETPOST('actioncancel', 'alpha'))
     //{
     //	$_GET["id"]=GETPOST('id', 'int');       // Force affichage dictionnaire en cours d'edition
     //}
    @@ -462,7 +462,7 @@ if ($id)
     
     		$obj = new stdClass();
     		// If data was already input, we define them in obj to populate input fields.
    -		if (GETPOST('actionadd'))
    +		if (GETPOST('actionadd', 'alpha'))
     		{
     			foreach ($fieldlist as $key=>$val)
     			{
    @@ -504,7 +504,7 @@ if ($id)
     		$paramwithsearch = $param;
     		if ($sortorder) $paramwithsearch.= '&sortorder='.$sortorder;
     		if ($sortfield) $paramwithsearch.= '&sortfield='.$sortfield;
    -		if (GETPOST('from')) $paramwithsearch.= '&from='.GETPOST('from','alpha');
    +		if (GETPOST('from', 'alpha')) $paramwithsearch.= '&from='.GETPOST('from','alpha');
     
     		// There is several pages
     		if ($num > $listlimit)
    diff --git a/htdocs/accountancy/admin/productaccount.php b/htdocs/accountancy/admin/productaccount.php
    index 2467b89b108..0babd9aab5f 100644
    --- a/htdocs/accountancy/admin/productaccount.php
    +++ b/htdocs/accountancy/admin/productaccount.php
    @@ -62,8 +62,8 @@ $search_current_account_valid = GETPOST('search_current_account_valid', 'alpha')
     if ($search_current_account_valid == '') $search_current_account_valid='withoutvalidaccount';
     
     $accounting_product_mode = GETPOST('accounting_product_mode', 'alpha');
    -$btn_changeaccount = GETPOST('changeaccount');
    -$btn_changetype = GETPOST('changetype');
    +$btn_changeaccount = GETPOST('changeaccount', 'alpha');
    +$btn_changetype = GETPOST('changetype', 'alpha');
     
     $limit = GETPOST('limit','int')?GETPOST('limit','int'):(empty($conf->global->ACCOUNTING_LIMIT_LIST_VENTILATION)?$conf->liste_limit:$conf->global->ACCOUNTING_LIMIT_LIST_VENTILATION);
     $sortfield = GETPOST("sortfield",'alpha');
    diff --git a/htdocs/accountancy/bookkeeping/balance.php b/htdocs/accountancy/bookkeeping/balance.php
    index e3290f1e542..161e3346b9c 100644
    --- a/htdocs/accountancy/bookkeeping/balance.php
    +++ b/htdocs/accountancy/bookkeeping/balance.php
    @@ -42,6 +42,21 @@ $page = GETPOST("page");
     $sortorder = GETPOST("sortorder", 'alpha');
     $sortfield = GETPOST("sortfield", 'alpha');
     $action = GETPOST('action', 'alpha');
    +if (GETPOST("exportcsv",'alpha')) $action = 'export_csv';
    +
    +// Load variable for pagination
    +$limit = GETPOST('limit','int')?GETPOST('limit','int'):$conf->liste_limit;
    +$sortfield = GETPOST('sortfield','alpha');
    +$sortorder = GETPOST('sortorder','alpha');
    +$page = GETPOST('page','int');
    +if (empty($page) || $page == -1 || GETPOST('button_search','alpha') || GETPOST('button_removefilter','alpha') || (empty($toselect) && $massaction === '0')) { $page = 0; }     // If $page is not defined, or '' or -1 or if we click on clear filters or if we select empty mass action
    +$offset = $limit * $page;
    +$pageprev = $page - 1;
    +$pagenext = $page + 1;
    +//if (! $sortfield) $sortfield="p.date_fin";
    +//if (! $sortorder) $sortorder="DESC";
    +
    +
     $search_date_start = dol_mktime(0, 0, 0, GETPOST('date_startmonth', 'int'), GETPOST('date_startday', 'int'), GETPOST('date_startyear', 'int'));
     $search_date_end = dol_mktime(0, 0, 0, GETPOST('date_endmonth', 'int'), GETPOST('date_endday', 'int'), GETPOST('date_endyear', 'int'));
     
    @@ -54,14 +69,6 @@ if ($search_accountancy_code_end == - 1) {
     	$search_accountancy_code_end = '';
     }
     
    -if (GETPOST("exportcsv",'alpha')) $action = 'export_csv';
    -
    -
    -$limit = GETPOST('limit','int')?GETPOST('limit', 'int'):$conf->liste_limit;
    -if (empty($page) || $page < 0) { $page = 0; }
    -
    -$offset = $limit * $page;
    -
     $object = new BookKeeping($db);
     
     $formaccounting = new FormAccounting($db);
    @@ -97,23 +104,27 @@ if ($sortorder == "")
     if ($sortfield == "")
     	$sortfield = "t.numero_compte";
     
    -$options = '';
    +
    +$param='';
    +if (! empty($contextpage) && $contextpage != $_SERVER["PHP_SELF"]) $param.='&contextpage='.urlencode($contextpage);
    +if ($limit > 0 && $limit != $conf->liste_limit) $param.='&limit='.urlencode($limit);
    +
     $filter = array ();
     if (! empty($search_date_start)) {
     	$filter['t.doc_date>='] = $search_date_start;
    -	$options .= '&amp;date_startmonth=' . GETPOST('date_startmonth', 'int') . '&amp;date_startday=' . GETPOST('date_startday', 'int') . '&amp;date_startyear=' . GETPOST('date_startyear', 'int');
    +	$param .= '&amp;date_startmonth=' . GETPOST('date_startmonth', 'int') . '&amp;date_startday=' . GETPOST('date_startday', 'int') . '&amp;date_startyear=' . GETPOST('date_startyear', 'int');
     }
     if (! empty($search_date_end)) {
     	$filter['t.doc_date<='] = $search_date_end;
    -	$options .= '&amp;date_endmonth=' . GETPOST('date_endmonth', 'int') . '&amp;date_endday=' . GETPOST('date_endday', 'int') . '&amp;date_endyear=' . GETPOST('date_endyear', 'int');
    +	$param .= '&amp;date_endmonth=' . GETPOST('date_endmonth', 'int') . '&amp;date_endday=' . GETPOST('date_endday', 'int') . '&amp;date_endyear=' . GETPOST('date_endyear', 'int');
     }
     if (! empty($search_accountancy_code_start)) {
     	$filter['t.numero_compte>='] = $search_accountancy_code_start;
    -	$options .= '&amp;search_accountancy_code_start=' . $search_accountancy_code_start;
    +	$param .= '&amp;search_accountancy_code_start=' . $search_accountancy_code_start;
     }
     if (! empty($search_accountancy_code_end)) {
     	$filter['t.numero_compte<='] = $search_accountancy_code_end;
    -	$options .= '&amp;search_accountancy_code_end=' . $search_accountancy_code_end;
    +	$param .= '&amp;search_accountancy_code_end=' . $search_accountancy_code_end;
     }
     
     
    @@ -135,8 +146,8 @@ if (GETPOST('button_removefilter_x','alpha') || GETPOST('button_removefilter.x',
      * View
      */
     
    -if ($action == 'export_csv') {
    -
    +if ($action == 'export_csv')
    +{
     	$sep = $conf->global->ACCOUNTING_EXPORT_SEPARATORCSV;
     
     	$filename = 'balance';
    @@ -156,13 +167,18 @@ if ($action == 'export_csv') {
     		print price($line->credit - $line->debit) . $sep;
     		print "\n";
     	}
    +
    +	exit;
     }
     
    -else {
    -	$title_page = $langs->trans("AccountBalance");
     
    -	llxHeader('', $title_page);
    +$title_page = $langs->trans("AccountBalance");
     
    +llxHeader('', $title_page);
    +
    +
    +if ($action != 'export_csv')
    +{
     	// List
     	$nbtotalofrecords = '';
     	if (empty($conf->global->MAIN_DISABLE_FULL_SCANLIST))
    @@ -188,7 +204,8 @@ else {
     	print '<input type="hidden" name="page" value="'.$page.'">';
     
     	$button = '<input type="submit" name="exportcsv" class="butAction" value="' . $langs->trans("Export") . ' ('.$conf->global->ACCOUNTING_EXPORT_FORMAT.')" />';
    -	print_barre_liste($title_page, $page, $_SERVER["PHP_SELF"], $options, $sortfield, $sortorder, $button, $result, $result, 'title_accountancy', 0);
    +
    +	print_barre_liste($title_page, $page, $_SERVER["PHP_SELF"], $param, $sortfield, $sortorder, $button, $result, $nbtotalofrecords, 'title_accountancy', 0, '', '', $limit);
     
     	$moreforfilter = '';
     
    @@ -226,12 +243,12 @@ else {
     	print '</tr>';
     
     	print '<tr class="liste_titre">';
    -	print_liste_field_titre("AccountAccounting", $_SERVER['PHP_SELF'], "t.numero_compte", "", $options, "", $sortfield, $sortorder);
    -	print_liste_field_titre("Label", $_SERVER['PHP_SELF'], "t.label_operation", "", $options, "", $sortfield, $sortorder);
    -	print_liste_field_titre("Debit", $_SERVER['PHP_SELF'], "t.debit", "", $options, 'align="right"', $sortfield, $sortorder);
    -	print_liste_field_titre("Credit", $_SERVER['PHP_SELF'], "t.credit", "", $options, 'align="right"', $sortfield, $sortorder);
    -	print_liste_field_titre("Balance", $_SERVER["PHP_SELF"], "", $options, "", 'align="right"', $sortfield, $sortorder);
    -	print_liste_field_titre('', $_SERVER["PHP_SELF"], "", $options, "", 'width="60" align="center"', $sortfield, $sortorder);
    +	print_liste_field_titre("AccountAccounting", $_SERVER['PHP_SELF'], "t.numero_compte", "", $param, "", $sortfield, $sortorder);
    +	print_liste_field_titre("Label", $_SERVER['PHP_SELF'], "t.label_operation", "", $param, "", $sortfield, $sortorder);
    +	print_liste_field_titre("Debit", $_SERVER['PHP_SELF'], "t.debit", "", $param, 'align="right"', $sortfield, $sortorder);
    +	print_liste_field_titre("Credit", $_SERVER['PHP_SELF'], "t.credit", "", $param, 'align="right"', $sortfield, $sortorder);
    +	print_liste_field_titre("Balance", $_SERVER["PHP_SELF"], "", $param, "", 'align="right"', $sortfield, $sortorder);
    +	print_liste_field_titre('', $_SERVER["PHP_SELF"], "", $param, "", 'width="60" align="center"', $sortfield, $sortorder);
     	print "</tr>\n";
     
     	$total_debit = 0;
    @@ -257,7 +274,7 @@ else {
     		{
     			// Affiche un Sous-Total par compte comptable
     			if ($displayed_account != "") {
    -				print '<tr class="liste_total"><td align="right" colspan="2">' . $langs->trans("SubTotal") . ':</td><td class="nowrap" align="right">' . price($sous_total_debit) . '</td><td class="nowrap" align="right">' . price($sous_total_credit) . '</td><td class="nowrap" align="right">' . price($sous_total_credit - $sous_total_debit) . '</td>';
    +				print '<tr class="liste_total"><td align="right" colspan="2">' . $langs->trans("SubTotal") . ':</td><td class="nowrap" align="right">' . price($sous_total_debit) . '</td><td class="nowrap" align="right">' . price($sous_total_credit) . '</td><td class="nowrap" align="right">' . price(price2num($sous_total_credit - $sous_total_debit)) . '</td>';
     				print "<td>&nbsp;</td>\n";
     				print '</tr>';
     			}
    @@ -288,11 +305,11 @@ else {
     		$sous_total_credit += $line->credit;
     	}
     
    -	print '<tr class="liste_total"><td align="right" colspan="2">' . $langs->trans("SubTotal") . ':</td><td class="nowrap" align="right">' . price($sous_total_debit) . '</td><td class="nowrap" align="right">' . price($sous_total_credit) . '</td><td class="nowrap" align="right">' . price($sous_total_credit - $sous_total_debit) . '</td>';
    +	print '<tr class="liste_total"><td align="right" colspan="2">' . $langs->trans("SubTotal") . ':</td><td class="nowrap" align="right">' . price($sous_total_debit) . '</td><td class="nowrap" align="right">' . price($sous_total_credit) . '</td><td class="nowrap" align="right">' . price(price2num($sous_total_credit - $sous_total_debit)) . '</td>';
     	print "<td>&nbsp;</td>\n";
     	print '</tr>';
     
    -	print '<tr class="liste_total"><td align="right" colspan="2">' . $langs->trans("AccountBalance") . ':</td><td class="nowrap" align="right">' . price($total_debit) . '</td><td class="nowrap" align="right">' . price($total_credit) . '</td><td class="nowrap" align="right">' . price($total_credit - $total_debit) . '</td>';
    +	print '<tr class="liste_total"><td align="right" colspan="2">' . $langs->trans("AccountBalance") . ':</td><td class="nowrap" align="right">' . price($total_debit) . '</td><td class="nowrap" align="right">' . price($total_credit) . '</td><td class="nowrap" align="right">' . price(price2num($total_credit - $total_debit)) . '</td>';
     	print "<td>&nbsp;</td>\n";
     	print '</tr>';
     
    diff --git a/htdocs/accountancy/bookkeeping/balancebymonth.php b/htdocs/accountancy/bookkeeping/balancebymonth.php
    index 3a0a1f73308..a01c42b285a 100644
    --- a/htdocs/accountancy/bookkeeping/balancebymonth.php
    +++ b/htdocs/accountancy/bookkeeping/balancebymonth.php
    @@ -64,7 +64,7 @@ $result = $db->query($sql);
     if ($result) {
     	$row = $db->fetch_row($result);
     	$nbfac = $row[0];
    -	
    +
     	$db->free($result);
     }
     
    @@ -85,7 +85,7 @@ print '<td align="center">' . $langs->trans("SeptemberMin") . '</td>';
     print '<td align="center">' . $langs->trans("OctoberMin") . '</td>';
     print '<td align="center">' . $langs->trans("NovemberMin") . '</td>';
     print '<td align="center">' . $langs->trans("DecemberMin") . '</td>';
    -print '<td align="center"><b>Total</b></td>';
    +print '<td align="center"><strong>Total</strong></td>';
     print '</tr>';
     
     $sql = "SELECT bk.numero_compte AS 'compte',";
    @@ -111,11 +111,11 @@ $resql = $db->query($sql);
     if ($resql) {
     	$i = 0;
     	$num = $db->num_rows($resql);
    -	
    +
     	while ( $i < $num ) {
    -		
    +
     		$row = $db->fetch_row($resql);
    -		
    +
     		print '<tr class="oddeven"><td width="14%">' . length_accountg($row[0]) . '</td>';
     		print '<td align="right" width="6.5%">' . price($row[1]) . '</td>';
     		print '<td align="right" width="6.5%">' . price($row[2]) . '</td>';
    @@ -129,9 +129,9 @@ if ($resql) {
     		print '<td align="right" width="6.5%">' . price($row[10]) . '</td>';
     		print '<td align="right" width="6.5%">' . price($row[11]) . '</td>';
     		print '<td align="right" width="6.5%">' . price($row[12]) . '</td>';
    -		print '<td align="right" width="8%"><b>' . price($row[13]) . '</b></td>';
    +		print '<td align="right" width="8%"><strong>' . price($row[13]) . '</strong></td>';
     		print '</tr>';
    -		
    +
     		$i ++;
     	}
     	$db->free($resql);
    diff --git a/htdocs/accountancy/bookkeeping/card.php b/htdocs/accountancy/bookkeeping/card.php
    index 5add04d7361..567fccaeab1 100644
    --- a/htdocs/accountancy/bookkeeping/card.php
    +++ b/htdocs/accountancy/bookkeeping/card.php
    @@ -1,8 +1,8 @@
     <?php
    -/* Copyright (C) 2013-2017 Olivier Geffroy      <jeff@jeffinfo.com>
    - * Copyright (C) 2013-2017 Florian Henry        <florian.henry@open-concept.pro>
    - * Copyright (C) 2013-2018 Alexandre Spangaro   <aspangaro@zendsi.com>
    - * Copyright (C) 2017      Laurent Destailleur  <eldy@users.sourceforge.net>
    +/* Copyright (C) 2013-2017  Olivier Geffroy         <jeff@jeffinfo.com>
    + * Copyright (C) 2013-2017  Florian Henry           <florian.henry@open-concept.pro>
    + * Copyright (C) 2013-2018  Alexandre Spangaro      <aspangaro@zendsi.com>
    + * Copyright (C) 2017       Laurent Destailleur     <eldy@users.sourceforge.net>
      * Copyright (C) 2018       Frédéric France         <frederic.france@netlogic.fr>
      *
      * This program is free software; you can redistribute it and/or modify
    @@ -32,6 +32,7 @@ require_once DOL_DOCUMENT_ROOT . '/core/class/html.formaccounting.class.php';
     require_once DOL_DOCUMENT_ROOT . '/compta/facture/class/facture.class.php';
     require_once DOL_DOCUMENT_ROOT . '/fourn/class/fournisseur.facture.class.php';
     require_once DOL_DOCUMENT_ROOT . '/accountancy/class/accountingjournal.class.php';
    +require_once DOL_DOCUMENT_ROOT . '/accountancy/class/accountingaccount.class.php';
     
     // Load translation files required by the page
     $langs->loadLangs(array("accountancy", "bills", "compta"));
    @@ -49,12 +50,21 @@ if ($user->societe_id > 0) {
     
     $mesg = '';
     
    -$account_number = GETPOST('account_number','alphanohtml');
    +$accountingaccount = new AccountingAccount($db);
    +$accountingjournal = new AccountingJournal($db);
    +
    +$accountingaccount_number = GETPOST('accountingaccount_number','alphanohtml');
    +$accountingaccount->fetch(null, $accountingaccount_number, true);
    +$accountingaccount_label = $accountingaccount->label;
    +
    +$journal_code = GETPOST('code_journal','alpha');
    +$accountingjournal->fetch(null, $journal_code);
    +$journal_label = $accountingjournal->label;
    +
     $subledger_account = GETPOST('subledger_account','alphanohtml');
     if ($subledger_account == - 1) {
     	$subledger_account = null;
     }
    -$label_compte = GETPOST('label_compte','alphanohtml');
     $label_operation= GETPOST('label_operation','alphanohtml');
     $debit = price2num(GETPOST('debit','alpha'));
     $credit = price2num(GETPOST('credit','alpha'));
    @@ -80,7 +90,7 @@ if ($action == "confirm_update") {
     		setEventMessages($langs->trans('ErrorDebitCredit'), null, 'errors');
     		$action='update';
     	}
    -	if (empty($account_number) || $account_number == '-1')
    +	if (empty($accountingaccount_number) || $accountingaccount_number == '-1')
     	{
     		$error++;
     		setEventMessages($langs->trans('ErrorFieldRequired', $langs->transnoentitiesnoconv("AccountAccountingShort")), null, 'errors');
    @@ -96,9 +106,9 @@ if ($action == "confirm_update") {
     			$error++;
     			setEventMessages($object->error, $object->errors, 'errors');
     		} else {
    -			$object->numero_compte = $account_number;
    +			$object->numero_compte = $accountingaccount_number;
     			$object->subledger_account = $subledger_account;
    -			$object->label_compte = $label_compte;
    +			$object->label_compte = $accountingaccount_label;
     			$object->label_operation= $label_operation;
     			$object->debit = $debit;
     			$object->credit = $credit;
    @@ -139,7 +149,7 @@ else if ($action == "add") {
     		setEventMessages($langs->trans('ErrorDebitCredit'), null, 'errors');
     		$action='';
     	}
    -	if (empty($account_number) || $account_number == '-1')
    +	if (empty($accountingaccount_number) || $accountingaccount_number == '-1')
     	{
     		$error++;
     		setEventMessages($langs->trans('ErrorFieldRequired', $langs->transnoentitiesnoconv("AccountAccountingShort")), null, 'errors');
    @@ -149,9 +159,9 @@ else if ($action == "add") {
     	if (! $error) {
     		$object = new BookKeeping($db);
     
    -		$object->numero_compte = $account_number;
    +		$object->numero_compte = $accountingaccount_number;
     		$object->subledger_account = $subledger_account;
    -		$object->label_compte = $label_compte;
    +		$object->label_compte = $accountingaccount_label;
     		$object->label_operation= $label_operation;
     		$object->debit = $debit;
     		$object->credit = $credit;
    @@ -159,7 +169,8 @@ else if ($action == "add") {
     		$object->doc_type = GETPOST('doc_type','alpha');
     		$object->piece_num = $piece_num;
     		$object->doc_ref = GETPOST('doc_ref','alpha');
    -		$object->code_journal = GETPOST('code_journal','alpha');
    +		$object->code_journal = $journal_code;
    +		$object->journal_label = $journal_label;
     		$object->fk_doc = GETPOST('fk_doc','alpha');
     		$object->fk_docdet = GETPOST('fk_docdet','alpha');
     
    @@ -212,12 +223,12 @@ else if ($action == "confirm_create") {
     
     	$object = new BookKeeping($db);
     
    -	if (! GETPOST('code_journal','alpha') || GETPOST('code_journal','alpha') == '-1') {
    +	if (! $journal_code || $journal_code == '-1') {
     		setEventMessages($langs->trans('ErrorFieldRequired', $langs->transnoentitiesnoconv("Journal")), null, 'errors');
     		$action='create';
     		$error++;
     	}
    -	if (! GETPOST('next_num_mvt'))
    +	if (! GETPOST('next_num_mvt', 'alpha'))
     	{
     		setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("NumPiece")), null, 'errors');
     		$error++;
    @@ -232,7 +243,8 @@ else if ($action == "confirm_create") {
     		$object->doc_type = GETPOST('doc_type','alpha');
     		$object->piece_num = GETPOST('next_num_mvt','alpha');
     		$object->doc_ref = GETPOST('doc_ref','alpha');
    -		$object->code_journal = GETPOST('code_journal','alpha');
    +		$object->code_journal = $journal_code;
    +		$object->journal_label = $journal_label;
     		$object->fk_doc = 0;
     		$object->fk_docdet = 0;
     		$object->montant = 0;
    @@ -253,7 +265,7 @@ else if ($action == "confirm_create") {
     }
     
     if ($action == 'setdate') {
    -	$datedoc = dol_mktime(0, 0, 0, GETPOST('doc_datemonth'), GETPOST('doc_dateday'), GETPOST('doc_dateyear'));
    +	$datedoc = dol_mktime(0, 0, 0, GETPOST('doc_datemonth', 'int'), GETPOST('doc_dateday', 'int'), GETPOST('doc_dateyear', 'int'));
     	$result = $object->updateByMvt($piece_num,'doc_date',$db->idate($datedoc),$mode);
     	if ($result < 0) {
     		setEventMessages($object->error, $object->errors, 'errors');
    @@ -267,8 +279,8 @@ if ($action == 'setdate') {
     }
     
     if ($action == 'setjournal') {
    -	$journaldoc = trim(GETPOST('code_journal','alpha'));
    -	$result = $object->updateByMvt($piece_num, 'code_journal', $journaldoc, $mode);
    +	$result = $object->updateByMvt($piece_num, 'code_journal', $journal_code, $mode);
    +	$result = $object->updateByMvt($piece_num, 'journal_label', $journal_label, $mode);
     	if ($result < 0) {
     		setEventMessages($object->error, $object->errors, 'errors');
     	} else {
    @@ -312,7 +324,6 @@ if ($action == 'valid') {
     
     $html = new Form($db);
     $formaccounting = new FormAccounting($db);
    -$accountjournal = new AccountingJournal($db);
     
     llxHeader('', $langs->trans("CreateMvts"));
     
    @@ -357,7 +368,7 @@ if ($action == 'create')
     
     	print '<tr>';
     	print '<td class="fieldrequired">' . $langs->trans("Codejournal") . '</td>';
    -	print '<td>' . $formaccounting->select_journal(GETPOST('code_journal'),'code_journal',0,1,array(),1,1) . '</td>';
    +	print '<td>' . $formaccounting->select_journal($journal_code,'code_journal',0,0,1,1) . '</td>';
     	print '</tr>';
     
     	print '<tr>';
    @@ -460,7 +471,7 @@ if ($action == 'create')
     			print '<input type="submit" class="button" value="' . $langs->trans('Modify') . '">';
     			print '</form>';
     		} else {
    -		print $object->code_journal ;
    +			print $object->code_journal ;
     		}
     		print '</td>';
     		print '</tr>';
    @@ -590,7 +601,6 @@ if ($action == 'create')
     
     				print_liste_field_titre("AccountAccountingShort");
     				print_liste_field_titre("SubledgerAccount");
    -				print_liste_field_titre("LabelAccount");
     				print_liste_field_titre("LabelOperation");
     				print_liste_field_titre("Debit", "", "", "", "", 'align="right"');
     				print_liste_field_titre("Credit", "", "", "", "", 'align="right"');
    @@ -605,7 +615,7 @@ if ($action == 'create')
     
     					if ($action == 'update' && $line->id == $id) {
     						print '<td>';
    -						print $formaccounting->select_account($line->numero_compte, 'account_number', 1, array (), 1, 1, '');
    +						print $formaccounting->select_account($line->numero_compte, 'accountingaccount_number', 1, array (), 1, 1, '');
     						print '</td>';
     						print '<td>';
     						// TODO For the moment we keep a free input text instead of a combo. The select_auxaccount has problem because it does not
    @@ -619,7 +629,6 @@ if ($action == 'create')
     							print '<input type="text" name="subledger_account" value="'.$line->subledger_account.'">';
     						}
     						print '</td>';
    -						print '<td><input type="text" class="minwidth100" name="label_compte" value="' . $line->label_compte . '"/></td>';
     						print '<td><input type="text" class="minwidth200" name="label_operation" value="' . $line->label_operation. '"/></td>';
     						print '<td align="right"><input type="text" size="6" class="right" name="debit" value="' . price($line->debit) . '"/></td>';
     						print '<td align="right"><input type="text" size="6" class="right" name="credit" value="' . price($line->credit) . '"/></td>';
    @@ -628,9 +637,9 @@ if ($action == 'create')
     						print '<input type="submit" class="button" name="update" value="' . $langs->trans("Update") . '">';
     						print '</td>';
     					} else {
    -						print '<td>' . length_accountg($line->numero_compte) . '</td>';
    +						$accountingaccount->fetch(null, $line->numero_compte, true);
    +						print '<td>' . $accountingaccount->getNomUrl(0,1,1,'',0) . '</td>';
     						print '<td>' . length_accounta($line->subledger_account) . '</td>';
    -						print '<td>' . $line->label_compte . '</td>';
     						print '<td>' . $line->label_operation. '</td>';
     						print '<td align="right">' . price($line->debit) . '</td>';
     						print '<td align="right">' . price($line->credit) . '</td>';
    @@ -663,7 +672,7 @@ if ($action == 'create')
     				if ($action == "" || $action == 'add') {
     					print '<tr class="oddeven">';
     					print '<td>';
    -					print $formaccounting->select_account($account_number, 'account_number', 1, array (), 1, 1, '');
    +					print $formaccounting->select_account($accountingaccount_number, 'accountingaccount_number', 1, array (), 1, 1, '');
     					print '</td>';
     					print '<td>';
     					// TODO For the moment we keep a fre input text instead of a combo. The select_auxaccount has problem because it does not
    @@ -677,7 +686,6 @@ if ($action == 'create')
     						print '<input type="text" name="subledger_account" value="">';
     					}
     					print '</td>';
    -					print '<td><input type="text" class="minwidth100" name="label_compte" value=""/></td>';
     					print '<td><input type="text" class="minwidth200" name="label_operation" value=""/></td>';
     					print '<td align="right"><input type="text" size="6" class="right" name="debit" value=""/></td>';
     					print '<td align="right"><input type="text" size="6" class="right" name="credit" value=""/></td>';
    diff --git a/htdocs/accountancy/bookkeeping/list.php b/htdocs/accountancy/bookkeeping/list.php
    index 132aa4e0afa..4a4630edfa5 100644
    --- a/htdocs/accountancy/bookkeeping/list.php
    +++ b/htdocs/accountancy/bookkeeping/list.php
    @@ -1,8 +1,8 @@
     <?php
    -/* Copyright (C) 2013-2016  Olivier Geffroy      <jeff@jeffinfo.com>
    - * Copyright (C) 2013-2016  Florian Henry        <florian.henry@open-concept.pro>
    - * Copyright (C) 2013-2017  Alexandre Spangaro   <aspangaro@zendsi.com>
    - * Copyright (C) 2016-2017  Laurent Destailleur  <eldy@users.sourceforge.net>
    +/* Copyright (C) 2013-2016  Olivier Geffroy         <jeff@jeffinfo.com>
    + * Copyright (C) 2013-2016  Florian Henry           <florian.henry@open-concept.pro>
    + * Copyright (C) 2013-2018  Alexandre Spangaro      <aspangaro@zendsi.com>
    + * Copyright (C) 2016-2017  Laurent Destailleur     <eldy@users.sourceforge.net>
      * Copyright (C) 2018       Frédéric France         <frederic.france@netlogic.fr>
      *
      * This program is free software; you can redistribute it and/or modify
    @@ -79,6 +79,7 @@ $search_direction = GETPOST('search_direction', 'alpha');
     $search_debit = GETPOST('search_debit', 'alpha');
     $search_credit = GETPOST('search_credit', 'alpha');
     $search_ledger_code = GETPOST('search_ledger_code', 'alpha');
    +$search_lettering_code = GETPOST('search_lettering_code', 'alpha');
     
     // Load variable for pagination
     $limit = GETPOST('limit','int')?GETPOST('limit', 'int'):(empty($conf->global->ACCOUNTING_LIMIT_LIST_VENTILATION)?$conf->liste_limit:$conf->global->ACCOUNTING_LIMIT_LIST_VENTILATION);
    @@ -138,11 +139,14 @@ $arrayfields=array(
     	't.label_operation'=>array('label'=>$langs->trans("Label"), 'checked'=>1),
     	't.debit'=>array('label'=>$langs->trans("Debit"), 'checked'=>1),
     	't.credit'=>array('label'=>$langs->trans("Credit"), 'checked'=>1),
    +	't.lettering_code'=>array('label'=>$langs->trans("LetteringCode"), 'checked'=>1),
     	't.code_journal'=>array('label'=>$langs->trans("Codejournal"), 'checked'=>1),
     	't.date_creation'=>array('label'=>$langs->trans("DateCreation"), 'checked'=>0),
     	't.tms'=>array('label'=>$langs->trans("DateModification"), 'checked'=>0),
     );
     
    +if (empty($conf->global->ACCOUNTING_ENABLE_LETTERING)) unset($arrayfields['t.lettering_code']);
    +
     
     /*
      * Actions
    @@ -176,6 +180,7 @@ if (GETPOST('button_removefilter_x','alpha') || GETPOST('button_removefilter.x',
     	$search_date_modification_end = '';
     	$search_debit = '';
     	$search_credit = '';
    +	$search_lettering_code = '';
     }
     
     // Must be after the remove filter action, before the export.
    @@ -272,6 +277,10 @@ if (! empty($search_credit)) {
     	$filter['t.credit'] = $search_credit;
     	$param .= '&search_credit=' . urlencode($search_credit);
     }
    +if (! empty($search_lettering_code)) {
    +	$filter['t.lettering_code'] = $search_lettering_code;
    +	$param .= '&search_lettering_code=' . urlencode($search_lettering_code);
    + }
     
     
     if ($action == 'delbookkeeping') {
    @@ -337,7 +346,7 @@ if ($action == 'delmouvconfirm') {
     	}
     }
     
    -// Export into a file with format defined into setup
    +// Export into a file with format defined into setup (FEC, CSV, ...)
     if ($action == 'export_file') {
     
     	$result = $object->fetchAll($sortorder, $sortfield, 0, 0, $filter);
    @@ -350,7 +359,9 @@ if ($action == 'export_file') {
     	{
     		$accountancyexport = new AccountancyExport($db);
     		$accountancyexport->export($object->lines);
    -		if (!empty($accountancyexport->errors)) {
    +
    +		if (!empty($accountancyexport->errors))
    +		{
     			setEventMessages('', $accountancyexport->errors, 'errors');
     		}
     		exit;
    @@ -546,6 +557,13 @@ if (! empty($arrayfields['t.credit']['checked']))
     	print '<input type="text" class="flat" name="search_credit" size="4" value="'.dol_escape_htmltag($search_credit).'">';
     	print '</td>';
     }
    +// Lettering code
    +if (! empty($arrayfields['t.lettering_code']['checked']))
    +{
    +	print '<td class="liste_titre center">';
    +	print '<input type="text" size="3" class="flat" name="search_lettering_code" value="' . $search_lettering_code . '"/>';
    +	print '</td>';
    +}
     // Code journal
     if (! empty($arrayfields['t.code_journal']['checked']))
     {
    @@ -595,6 +613,7 @@ if (! empty($arrayfields['t.subledger_account']['checked']))	print_liste_field_t
     if (! empty($arrayfields['t.label_operation']['checked']))		print_liste_field_titre($arrayfields['t.label_operation']['label'], $_SERVER['PHP_SELF'], "t.label_operation", "", $param, "", $sortfield, $sortorder);
     if (! empty($arrayfields['t.debit']['checked']))				print_liste_field_titre($arrayfields['t.debit']['label'], $_SERVER['PHP_SELF'], "t.debit", "", $param, 'align="right"', $sortfield, $sortorder);
     if (! empty($arrayfields['t.credit']['checked']))				print_liste_field_titre($arrayfields['t.credit']['label'], $_SERVER['PHP_SELF'], "t.credit", "", $param, 'align="right"', $sortfield, $sortorder);
    +if (! empty($arrayfields['t.lettering_code']['checked']))		print_liste_field_titre($arrayfields['t.lettering_code']['label'], $_SERVER['PHP_SELF'], "t.lettering_code", "", $param, 'align="center"', $sortfield, $sortorder);
     if (! empty($arrayfields['t.code_journal']['checked']))			print_liste_field_titre($arrayfields['t.code_journal']['label'], $_SERVER['PHP_SELF'], "t.code_journal", "", $param, 'align="center"', $sortfield, $sortorder);
     if (! empty($arrayfields['t.date_creation']['checked']))		print_liste_field_titre($arrayfields['t.date_creation']['label'], $_SERVER['PHP_SELF'], "t.date_creation", "", $param, 'align="center"', $sortfield, $sortorder);
     if (! empty($arrayfields['t.tms']['checked']))					print_liste_field_titre($arrayfields['t.tms']['label'], $_SERVER['PHP_SELF'], "t.tms", "", $param, 'align="center"', $sortfield, $sortorder);
    @@ -680,6 +699,13 @@ if ($num > 0)
     			$totalarray['totalcredit'] += $line->credit;
     		}
     
    +		// Lettering code
    +		if (! empty($arrayfields['t.lettering_code']['checked']))
    +		{
    +			print '<td align="center">' . $line->lettering_code . '</td>';
    +			if (! $i) $totalarray['nbfield']++;
    +		}
    +
     		// Journal code
     		if (! empty($arrayfields['t.code_journal']['checked']))
     		{
    diff --git a/htdocs/accountancy/bookkeeping/thirdparty_lettrage.php b/htdocs/accountancy/bookkeeping/thirdparty_lettering_customer.php
    similarity index 62%
    rename from htdocs/accountancy/bookkeeping/thirdparty_lettrage.php
    rename to htdocs/accountancy/bookkeeping/thirdparty_lettering_customer.php
    index be335107839..3fdda686eab 100644
    --- a/htdocs/accountancy/bookkeeping/thirdparty_lettrage.php
    +++ b/htdocs/accountancy/bookkeeping/thirdparty_lettering_customer.php
    @@ -3,7 +3,8 @@
      * Copyright (C) 2005      Laurent Destailleur  <eldy@users.sourceforge.net>
      * Copyright (C) 2013      Olivier Geffroy      <jeff@jeffinfo.com>
      * Copyright (C) 2013      Florian Henry	    <florian.henry@open-concept.pro>
    - * Copyright (C) 2013      Alexandre Spangaro   <alexandre.spangaro@gmail.com>
    + * Copyright (C) 2013-2018 Alexandre Spangaro      <aspangaro@zendsi.com>
    + * Copyright (C) 2018      Frédéric France         <frederic.france@netlogic.fr>
      *
      * This program is free software; you can redistribute it and/or modify
      * it under the terms of the GNU General Public License as published by
    @@ -21,12 +22,11 @@
      */
     
     /**
    - * \file accountancy/bookkeeping/thirdparty_lettrage.php
    - * \ingroup Advanced accountancy
    - * \brief Onglet de gestion de parametrages des ventilations
    + * \file        htdocs/accountancy/bookkeeping/thirdparty_lettering_customer.php
    + * \ingroup     accountancy
    + * \brief       Tab to manage customer lettering
      */
     require '../../main.inc.php';
    -
     require_once DOL_DOCUMENT_ROOT . '/core/class/html.formaccounting.class.php';
     require_once DOL_DOCUMENT_ROOT . '/accountancy/class/bookkeeping.class.php';
     require_once DOL_DOCUMENT_ROOT . '/accountancy/class/lettering.class.php';
    @@ -34,7 +34,7 @@ require_once DOL_DOCUMENT_ROOT . '/societe/class/societe.class.php';
     require_once DOL_DOCUMENT_ROOT . '/core/lib/company.lib.php';
     
     // Load translation files required by the page
    -$langs->loadLangs(array("compta"));
    +$langs->loadLangs(array("compta","accountancy"));
     
     $action = GETPOST('action', 'aZ09');
     $massaction = GETPOST('massaction', 'alpha');
    @@ -61,11 +61,10 @@ $search_year = GETPOST("search_year", 'int');
     $search_doc_type = GETPOST("search_doc_type", 'alpha');
     $search_doc_ref = GETPOST("search_doc_ref", 'alpha');
     
    -$lettering = GETPOST('lettering');
    +$lettering = GETPOST('lettering', 'alpha');
     if (! empty($lettering)) {
     	$action = $lettering;
     }
    -$toselect = GETPOST('toselect', 'array');
     
     // Did we click on purge search criteria ?
     // All tests are required to be compatible with all browsers
    @@ -79,6 +78,7 @@ if (GETPOST('button_removefilter_x', 'alpha') || GETPOST('button_removefilter.x'
     $socid = GETPOST("socid", 'int');
     // if ($user->societe_id) $socid=$user->societe_id;
     
    +$lettering = new Lettering($db);
     $object = new Societe($db);
     $object->id = $socid;
     $result = $object->fetch($socid);
    @@ -87,9 +87,6 @@ if ($result < 0)
     	setEventMessages($object->error, $object->errors, 'errors');
     }
     
    -$form = new Form($db);
    -$BookKeeping = new lettering($db);
    -$formaccounting = new FormAccounting($db);
     
     /*
      * Action
    @@ -97,82 +94,49 @@ $formaccounting = new FormAccounting($db);
     
     if ($action == 'lettering') {
     
    -	$result = $BookKeeping->updateLettrage($toselect);
    +	$result = $lettering->updateLettering($toselect);
     
     	if ($result < 0) {
    -		setEventMessages('', $BookKeeping->errors, 'errors');
    -		$error ++;
    +		setEventMessages('', $lettering->errors, 'errors');
    +		$error++;
     	}
     }
     
     if ($action == 'autolettrage') {
     
    -	$result = $BookKeeping->lettrageTiers($socid);
    +	$result = $lettering->letteringThirdparty($socid);
     
     	if ($result < 0) {
    -		setEventMessages('', $BookKeeping->errors, 'errors');
    -		$error ++;
    +		setEventMessages('', $lettering->errors, 'errors');
    +		$error++;
     	}
     }
     
    -llxHeader('', 'Compta - Grand Livre');
     
    -/*
    - * Affichage onglets
    +	/*
    + * View
      */
    +
    +$form = new Form($db);
    +$formaccounting = new FormAccounting($db);
    +
    +$title=$object->name." - ".$langs->trans('TabLetteringCustomer');
    +$help_url='EN:Module_Third_Parties|FR:Module_Tiers|ES:Empresas';
    +llxHeader('',$title,$help_url);
    +
     $head = societe_prepare_head($object);
     
     dol_htmloutput_mesg(is_numeric($error) ? '' : $error, $errors, 'error');
     
    -dol_fiche_head($head, 'accounting', $langs->trans("ThirdParty"), 0, 'company');
    +dol_fiche_head($head, 'lettering_customer', $langs->trans("ThirdParty"), 0, 'company');
     
    -print '<table width="100%" class="border">';
    -print '<tr><td width="30%">' . $langs->trans("ThirdPartyName") . '</td><td width="70%" colspan="3">';
    -$object->next_prev_filter = "te.fournisseur = 1";
    -print $form->showrefnav($object, 'socid', '', ($user->societe_id ? 0 : 1), 'rowid', 'nom', '', '');
    -print '</td></tr>';
    +$linkback = '<a href="'.DOL_URL_ROOT.'/societe/list.php?restore_lastsearch_values=1">'.$langs->trans("BackToList").'</a>';
     
    -if (! empty($conf->global->SOCIETE_USEPREFIX)) // Old not used prefix field
    -{
    -	print '<tr><td>' . $langs->trans('Prefix') . '</td><td colspan="3">' . $object->prefix_comm . '</td></tr>';
    -}
    +dol_banner_tab($object, 'socid', $linkback, ($user->societe_id?0:1), 'rowid', 'nom', '', '', 0, '', '', 'arearefnobottom');
     
    -print '<tr>';
    -print '<td class="nowrap">' . $langs->trans("CustomerCode") . '</td><td colspan="3">';
    -print $object->code_client;
    -if ($object->check_codeclient() != 0)
    -	print ' <font class="error">(' . $langs->trans("WrongCustomerCode") . ')</font>';
    -print '</td>';
    -print '</tr>';
    +dol_fiche_end();
     
    -print '<tr>';
    -print '<td>';
    -print $form->editfieldkey("CustomerAccountancyCode", 'customeraccountancycode', $object->code_compta, $object, $user->rights->societe->creer);
    -print '</td><td colspan="3">';
    -print $form->editfieldval("CustomerAccountancyCode", 'customeraccountancycode', $object->code_compta, $object, $user->rights->societe->creer);
    -print '</td>';
    -print '</tr>';
    -
    -// Address
    -print '<tr><td valign="top">' . $langs->trans("Address") . '</td><td colspan="3">';
    -dol_print_address($object->address, 'gmap', 'thirdparty', $object->id);
    -print '</td></tr>';
    -
    -// Zip / Town
    -print '<tr><td class="nowrap">' . $langs->trans("Zip") . ' / ' . $langs->trans("Town") . '</td><td colspan="3">' . $object->zip . (($object->zip && $object->town) ? ' / ' : '') . $object->town . '</td>';
    -print '</tr>';
    -
    -// Country
    -print '<tr><td>' . $langs->trans("Country") . '</td><td colspan="3">';
    -// $img=picto_from_langcode($object->country_code);
    -$img = '';
    -if ($object->isInEEC())
    -	print $form->textwithpicto(($img ? $img . ' ' : '') . $object->country, $langs->trans("CountryIsInEEC"), 1, 0);
    -else
    -	print ($img ? $img . ' ' : '') . $object->country;
    -print '</td></tr>';
    -
    -print '</table>';
    +print '<br>';
     
     $sql = "SELECT bk.rowid, bk.doc_date, bk.doc_type, bk.doc_ref, ";
     $sql .= " bk.subledger_account, bk.numero_compte , bk.label_compte, bk.debit, ";
    @@ -209,7 +173,7 @@ while ( $obj = $db->fetch_object($resql) ) {
     
     $sql .= $db->plimit($limit + 1, $offset);
     
    -dol_syslog("/accountancy/bookkeeping/thirdparty_lettrage.php", LOG_DEBUG);
    +dol_syslog("/accountancy/bookkeeping/thirdparty_lettering_customer.php", LOG_DEBUG);
     $resql = $db->query($sql);
     if (! $resql) {
     	dol_print_error($db);
    @@ -218,7 +182,7 @@ if (! $resql) {
     
     $num = $db->num_rows($resql);
     
    -dol_syslog("/accountancy/bookkeeping/thirdparty_lettrage.php", LOG_DEBUG);
    +dol_syslog("/accountancy/bookkeeping/thirdparty_lettering_customer.php", LOG_DEBUG);
     if ($resql) {
     	$i = 0;
     
    @@ -232,21 +196,19 @@ if ($resql) {
     	print_liste_field_titre("Doctype", $_SERVER["PHP_SELF"], "bk.doc_type", "", $param, "", $sortfield, $sortorder);
     	print_liste_field_titre("Docdate", $_SERVER["PHP_SELF"], "bk.doc_date", "", $param, "", $sortfield, $sortorder);
     	print_liste_field_titre("Docref", $_SERVER["PHP_SELF"], "bk.doc_ref", "", $param, "", $sortfield, $sortorder);
    -	print_liste_field_titre("Labelcompte", $_SERVER["PHP_SELF"], "bk.label_compte", "", $param, "", $sortfield, $sortorder);
    +	print_liste_field_titre("LabelAccount", $_SERVER["PHP_SELF"], "bk.label_compte", "", $param, "", $sortfield, $sortorder);
     	print_liste_field_titre("Debit", $_SERVER["PHP_SELF"], "bk.debit", "", $param, "", $sortfield, $sortorder);
     	print_liste_field_titre("Credit", $_SERVER["PHP_SELF"], "bk.credit", "", $param, "", $sortfield, $sortorder);
    -	print_liste_field_titre("Amount", $_SERVER["PHP_SELF"], "bk.montant", "", $param, "", $sortfield, $sortorder);
    -	print_liste_field_titre("Sens", $_SERVER["PHP_SELF"], "bk.sens", "", $param, "", $sortfield, $sortorder);
    +	print_liste_field_titre("Balancing", $_SERVER["PHP_SELF"], "", "", $param, "", $sortfield, $sortorder);
     	print_liste_field_titre("Codejournal", $_SERVER["PHP_SELF"], "bk.code_journal", "", $param, "", $sortfield, $sortorder);
    -	print_liste_field_titre("Solde", $_SERVER["PHP_SELF"], "", "", $param, "", $sortfield, $sortorder);
    -	print '<td></td>';
    +	print_liste_field_titre("LetteringCode", $_SERVER["PHP_SELF"], "bk.lettering_code", "", $param, "", $sortfield, $sortorder);
     	print "</tr>\n";
     
     	print '<tr class="liste_titre">';
     	print '<td><input type="text" name="search_doc_type" value="' . $search_doc_type . '"></td>';
     	print '<td><input type="text" name="search_year" value="' . $search_year . '"></td>';
     	print '<td><input type="text" name="search_doc_refe" value="' . $search_doc_ref . '"></td>';
    -	print '<td colspan="7">&nbsp;</td>';
    +	print '<td colspan="5">&nbsp;</td>';
     	print '<td align="right">';
     	$searchpicto = $form->showFilterButtons();
     	print $searchpicto;
    @@ -257,12 +219,8 @@ if ($resql) {
     	$tmp = '';
     	while ( $obj = $db->fetch_object($resql) ) {
     
    -		if ($tmp != $obj->lettering_code || empty($tmp))
    -			$tmp = $obj->lettering_code;
    -
    -		if ($tmp != $obj->lettering_code || empty($obj->lettering_code))
    -
    -		$solde += ($obj->credit - $obj->debit);
    +		if ($tmp != $obj->lettering_code || empty($tmp))						$tmp = $obj->lettering_code;
    +		/*if ($tmp != $obj->lettering_code || empty($obj->lettering_code))*/	$solde += ($obj->credit - $obj->debit);
     
     		print '<tr class="oddeven">';
     
    @@ -270,44 +228,44 @@ if ($resql) {
     			print '<td><a href="' . dol_buildpath('/accountancy/bookkeeping/card.php', 1) . '?piece_num=' . $obj->piece_num . '">';
     			print img_edit();
     			print '</a>&nbsp;' . $obj->doc_type . '</td>' . "\n";
    -		} else
    +		} else {
     			print '<td>' . $obj->doc_type . '</td>' . "\n";
    +		}
     
     		print '<td>' . dol_print_date($db->jdate($obj->doc_date), 'day') . '</td>';
     		print '<td>' . $obj->doc_ref . '</td>';
     		print '<td>' . $obj->label_compte . '</td>';
    -		print '<td>' . price($obj->debit) . '</td>';
    -		print '<td>' . price($obj->credit) . '</td>';
    -		print '<td>' . price($obj->montant) . '</td>';
    -		print '<td>' . $obj->sens . '</td>';
    -		print '<td>' . $obj->code_journal . '</td>';
    -		print '<td>' . round($solde, 2) . '</td>';
    +		print '<td align="right">' . price($obj->debit) . '</td>';
    +		print '<td align="right">' . price($obj->credit) . '</td>';
    +		print '<td align="right">' . price(round($solde, 2)) . '</td>';
    +		print '<td align="center">' . $obj->code_journal . '</td>';
     
     		if (empty($obj->lettering_code)) {
     			print '<td class="nowrap" align="center"><input type="checkbox" class="flat checkforselect" name="toselect[]" id="toselect[]" value="' . $obj->rowid . '" /></td>';
     		} else
    -			print '<td>' . $obj->lettering_code . '</td>';
    +			print '<td align="center">' . $obj->lettering_code . '</td>';
     
     		print "</tr>\n";
     	}
     
     	print '<tr class="oddeven">';
    -	print '<td colspan="4">Mouvement totaux</td>' . "\n";
    -	print '<td><strong>' . price($debit) . '</strong></td>';
    -	print '<td><strong>' . price($credit) . '</strong></td>';
    +	print '<td align="right" colspan="4">'.$langs->trans("Total").':</td>' . "\n";
    +	print '<td align="right"><strong>' . price($debit) . '</strong></td>';
    +	print '<td align="right"><strong>' . price($credit) . '</strong></td>';
     	print '<td colspan="5"></td>';
     	print "</tr>\n";
     
     	print '<tr class="oddeven">';
    -	print '<td colspan="9">Solde Comptable</td>' . "\n";
    -	print '<td><strong>' . price($credit - $debit) . '</strong></td>';
    -	print '<td colspan="5"></td>';
    +	print '<td align="right" colspan="4">'.$langs->trans("Balancing").':</td>' . "\n";
    +	print '<td colspan="2">&nbsp;</td>';
    +	print '<td align="right"><strong>' . price($credit - $debit) . '</strong></td>';
    +	print '<td colspan="3"></td>';
     	print "</tr>\n";
     
     	print "</table>";
     
     	print '<input class="butAction" type="submit" value="lettering" name="lettering" id="lettering">';
    -	print '<a class="butAction" href="' . $_SERVER["PHP_SELF"] . '?socid=' . $object->id . '&action=autolettrage">' . $langs->trans('AccountancyAutoLettering') . '</a>';
    +	//print '<a class="butAction" href="' . $_SERVER["PHP_SELF"] . '?socid=' . $object->id . '&action=autolettering">' . $langs->trans('AccountancyAutoLettering') . '</a>';
     	print "</form>";
     	$db->free($resql);
     } else {
    @@ -317,4 +275,3 @@ if ($resql) {
     // End of page
     llxFooter();
     $db->close();
    -
    diff --git a/htdocs/accountancy/bookkeeping/thirdparty_lettrage_supplier.php b/htdocs/accountancy/bookkeeping/thirdparty_lettering_supplier.php
    similarity index 60%
    rename from htdocs/accountancy/bookkeeping/thirdparty_lettrage_supplier.php
    rename to htdocs/accountancy/bookkeeping/thirdparty_lettering_supplier.php
    index 905361b4c8e..8cd51847b1e 100644
    --- a/htdocs/accountancy/bookkeeping/thirdparty_lettrage_supplier.php
    +++ b/htdocs/accountancy/bookkeeping/thirdparty_lettering_supplier.php
    @@ -3,7 +3,8 @@
      * Copyright (C) 2005      Laurent Destailleur  <eldy@users.sourceforge.net>
      * Copyright (C) 2013      Olivier Geffroy      <jeff@jeffinfo.com>
      * Copyright (C) 2013      Florian Henry	    <florian.henry@open-concept.pro>
    - * Copyright (C) 2013      Alexandre Spangaro   <alexandre.spangaro@gmail.com>
    + * Copyright (C) 2013-2018 Alexandre Spangaro      <aspangaro@zendsi.com>
    + * Copyright (C) 2018      Frédéric France         <frederic.france@netlogic.fr>
      *
      * This program is free software; you can redistribute it and/or modify
      * it under the terms of the GNU General Public License as published by
    @@ -21,14 +22,11 @@
      */
     
     /**
    - * \file accountancy/bookkeeping/thirdparty_lettrage_supplier.php
    - * \ingroup Advanced accountancy
    - * \brief Tab to setup lettering
    + * \file    	htdocs/accountancy/bookkeeping/thirdparty_lettrage_supplier.php
    + * \ingroup 	Advanced accountancy
    + * \brief 		Tab to setup lettering
      */
    -
    -// Dolibarr environment
     require '../../main.inc.php';
    -
     require_once DOL_DOCUMENT_ROOT . '/core/class/html.formaccounting.class.php';
     require_once DOL_DOCUMENT_ROOT . '/accountancy/class/bookkeeping.class.php';
     require_once DOL_DOCUMENT_ROOT . '/accountancy/class/lettering.class.php';
    @@ -36,7 +34,7 @@ require_once DOL_DOCUMENT_ROOT . '/societe/class/societe.class.php';
     require_once DOL_DOCUMENT_ROOT . '/core/lib/company.lib.php';
     
     // Load translation files required by the page
    -$langs->loadLangs(array("compta"));
    +$langs->loadLangs(array("compta","accountancy"));
     
     $action = GETPOST('action', 'aZ09');
     $massaction = GETPOST('massaction', 'alpha');
    @@ -63,11 +61,10 @@ $search_year = GETPOST("search_year",'int');
     $search_doc_type = GETPOST("search_doc_type",'alpha');
     $search_doc_ref = GETPOST("search_doc_ref",'alpha');
     
    -$lettering = GETPOST('lettering');
    +$lettering = GETPOST('lettering', 'alpha');
     if (!empty($lettering)) {
     	$action=$lettering;
     }
    -$toselect = GETPOST('toselect','array');
     
     // Did we click on purge search criteria ?
     // All tests are required to be compatible with all browsers
    @@ -83,6 +80,7 @@ if (GETPOST('button_removefilter_x','alpha') || GETPOST('button_removefilter.x',
     $socid = GETPOST("socid", 'int');
     // if ($user->societe_id) $socid=$user->societe_id;
     
    +$lettering = new Lettering($db);
     $object = new Societe($db);
     $object->id = $socid;
     $result = $object->fetch($socid);
    @@ -91,104 +89,53 @@ if ($result<0)
     	setEventMessages($object->error, $object->errors, 'errors');
     }
     
    -$form = new Form($db);
    -$BookKeeping = new lettering($db);
    -$formaccounting = new FormAccounting($db);
     
     /*
      * Action
      */
     if ($action == 'lettering') {
     
    -	$result = $BookKeeping->updateLettrage($toselect);
    +	$result = $lettering->updateLettering($toselect);
     
    -	// var_dump($result);
     	if ($result < 0) {
    -		setEventMessages('', $BookKeeping->errors, 'errors');
    -		$error ++;
    +		setEventMessages('', $lettering->errors, 'errors');
    +		$error++;
     	}
     }
     
     if ($action == 'autolettrage') {
     
    -	$result = $BookKeeping->lettrageTiers($socid);
    +	$result = $lettering->letteringThirdparty($socid);
     
     	if ($result < 0) {
    -		setEventMessages('', $BookKeeping->errors, 'errors');
    -		$error ++;
    +		setEventMessages('', $lettering->errors, 'errors');
    +		$error++;
     	}
     }
     
    -$title = 'AccountancyLettrage';
    -
    -llxHeader('', $title);
    -
    -
    -$param='';
    -if (! empty($contextpage) && $contextpage != $_SERVER["PHP_SELF"]) $param.='&contextpage='.$contextpage;
    -if ($limit > 0 && $limit != $conf->liste_limit) $param.='&limit='.$limit;
    -if (!empty($search_year)) $param.='&search_year='.$search_year;
    -if (!empty($socid)) $param.='&socid='.$socid;
    -if (!empty($search_doc_type)) $param.='&search_doc_type='.$search_doc_type;
    -if (!empty($search_doc_ref)) $param.='&search_doc_ref='.$search_doc_ref;
    -
     
     /*
    - * Display tabs
    + * View
      */
    +
    +$form = new Form($db);
    +$formaccounting = new FormAccounting($db);
    +
    +$title=$object->name." - ".$langs->trans('TabLetteringSupplier');
    +$help_url='EN:Module_Third_Parties|FR:Module_Tiers|ES:Empresas';
    +llxHeader('',$title,$help_url);
    +
     $head = societe_prepare_head($object);
     
     dol_htmloutput_mesg(is_numeric($error) ? '' : $error, $errors, 'error');
     
    -dol_fiche_head($head, 'accounting_supplier', $langs->trans("ThirdParty"), 0, 'company');
    +dol_fiche_head($head, 'lettering_supplier', $langs->trans("ThirdParty"), 0, 'company');
     
    -print '<table width="100%" class="border">';
    -print '<tr><td width="30%">' . $langs->trans("ThirdPartyName") . '</td><td width="70%" colspan="3">';
    -$object->next_prev_filter = "te.fournisseur = 1";
    -print $form->showrefnav($object, 'socid', '', ($user->societe_id ? 0 : 1), 'rowid', 'nom', '', '');
    -print '</td></tr>';
    +$linkback = '<a href="'.DOL_URL_ROOT.'/societe/list.php?restore_lastsearch_values=1">'.$langs->trans("BackToList").'</a>';
     
    -if (! empty($conf->global->SOCIETE_USEPREFIX)) // Old not used prefix field
    -{
    -	print '<tr><td>' . $langs->trans('Prefix') . '</td><td colspan="3">' . $object->prefix_comm . '</td></tr>';
    -}
    +dol_banner_tab($object, 'socid', $linkback, ($user->societe_id?0:1), 'rowid', 'nom', '', '', 0, '', '', 'arearefnobottom');
     
    -print '<tr>';
    -print '<td class="nowrap">' . $langs->trans("SupplierCode") . '</td><td colspan="3">';
    -print $object->code_fournisseur;
    -if ($object->check_codefournisseur() != 0)
    -	print ' <font class="error">(' . $langs->trans("WrongSupplierCode") . ')</font>';
    -print '</td>';
    -print '</tr>';
    -
    -print '<tr>';
    -print '<td>';
    -print $form->editfieldkey("SupplierAccountancyCode", 'supplieraccountancycode', $object->code_compta_fournisseur, $object, $user->rights->societe->creer);
    -print '</td><td colspan="3">';
    -print $form->editfieldval("SupplierAccountancyCode", 'supplieraccountancycode', $object->code_compta_fournisseur, $object, $user->rights->societe->creer);
    -print '</td>';
    -print '</tr>';
    -
    -// Address
    -print '<tr><td valign="top">' . $langs->trans("Address") . '</td><td colspan="3">';
    -dol_print_address($object->address, 'gmap', 'thirdparty', $object->id);
    -print '</td></tr>';
    -
    -// Zip / Town
    -print '<tr><td class="nowrap">' . $langs->trans("Zip") . ' / ' . $langs->trans("Town") . '</td><td colspan="3">' . $object->zip . (($object->zip && $object->town) ? ' / ' : '') . $object->town . '</td>';
    -print '</tr>';
    -
    -// Country
    -print '<tr><td>' . $langs->trans("Country") . '</td><td colspan="3">';
    -// $img=picto_from_langcode($object->country_code);
    -$img = '';
    -if ($object->isInEEC())
    -	print $form->textwithpicto(($img ? $img . ' ' : '') . $object->country, $langs->trans("CountryIsInEEC"), 1, 0);
    -else
    -	print ($img ? $img . ' ' : '') . $object->country;
    -print '</td></tr>';
    -
    -print '</table>';
    +dol_fiche_end();
     
     $sql = "SELECT bk.rowid, bk.doc_date, bk.doc_type, bk.doc_ref, ";
     $sql .= " bk.subledger_account, bk.numero_compte , bk.label_compte, bk.debit, ";
    @@ -252,21 +199,19 @@ if ($resql) {
     	print_liste_field_titre("Doctype", $_SERVER["PHP_SELF"], "bk.doc_type","",$param,"",$sortfield,$sortorder);
     	print_liste_field_titre("Docdate", $_SERVER["PHP_SELF"], "bk.doc_date","",$param,"",$sortfield,$sortorder);
     	print_liste_field_titre("Docref", $_SERVER["PHP_SELF"], "bk.doc_ref","",$param,"",$sortfield,$sortorder);
    -	print_liste_field_titre("Labelcompte", $_SERVER["PHP_SELF"], "bk.label_compte","",$param,"",$sortfield,$sortorder);
    +	print_liste_field_titre("LabelAccount", $_SERVER["PHP_SELF"], "bk.label_compte","",$param,"",$sortfield,$sortorder);
     	print_liste_field_titre("Debit", $_SERVER["PHP_SELF"], "bk.debit","",$param,"",$sortfield,$sortorder);
     	print_liste_field_titre("Credit", $_SERVER["PHP_SELF"], "bk.credit","",$param,"",$sortfield,$sortorder);
    -	print_liste_field_titre("Amount", $_SERVER["PHP_SELF"], "bk.montant","",$param,"",$sortfield,$sortorder);
    -	print_liste_field_titre("Sens", $_SERVER["PHP_SELF"], "bk.sens","",$param,"",$sortfield,$sortorder);
    +	print_liste_field_titre("Balancing", $_SERVER["PHP_SELF"], "","",$param,"",$sortfield,$sortorder);
     	print_liste_field_titre("Codejournal", $_SERVER["PHP_SELF"], "bk.code_journal","",$param,"",$sortfield,$sortorder);
    -	print_liste_field_titre("Solde", $_SERVER["PHP_SELF"], "","",$param,"",$sortfield,$sortorder);
    -	print '<td></td>';
    +	print_liste_field_titre("LetteringCode", $_SERVER["PHP_SELF"], "bk.lettering_code", "", $param, "", $sortfield, $sortorder);
     	print "</tr>\n";
     
     	print '<tr class="liste_titre">';
     	print '<td><input type="text" name="search_doc_type" value="' . $search_doc_type . '"></td>';
     	print '<td><input type="text" name="search_year" value="' . $search_year . '"></td>';
     	print '<td><input type="text" name="search_doc_refe" value="' . $search_doc_ref . '"></td>';
    -	print '<td colspan="7">&nbsp;</td>';
    +	print '<td colspan="6">&nbsp;</td>';
     	print '<td align="right">';
     	$searchpicto=$form->showFilterButtons();
     	print $searchpicto;
    @@ -277,12 +222,8 @@ if ($resql) {
     	$tmp = '';
     	while ($obj = $db->fetch_object($resql)) {
     
    -		if ($tmp != $obj->lettering_code || empty($tmp))
    -			$tmp = $obj->lettering_code;
    -
    -			if ($tmp != $obj->lettering_code || empty($obj->lettering_code))
    -
    -		$solde += ($obj->credit - $obj->debit);
    +		if ($tmp != $obj->lettering_code || empty($tmp))						$tmp = $obj->lettering_code;
    +		/*if ($tmp != $obj->lettering_code || empty($obj->lettering_code))*/	$solde += ($obj->credit - $obj->debit);
     
     		print '<tr class="oddeven">';
     
    @@ -290,45 +231,44 @@ if ($resql) {
     			print '<td><a href="' . dol_buildpath('/accountancy/bookkeeping/card.php', 1) . '?piece_num=' . $obj->piece_num . '">';
     			print img_edit();
     			print '</a>&nbsp;' . $obj->doc_type . '</td>' . "\n";
    -		} else
    +		} else {
     			print '<td>' . $obj->doc_type . '</td>' . "\n";
    +		}
     
     		print '<td>' . dol_print_date($db->jdate($obj->doc_date), 'day') . '</td>';
     		print '<td>' . $obj->doc_ref . '</td>';
     		print '<td>' . $obj->label_compte . '</td>';
    -		print '<td>' . price($obj->debit) . '</td>';
    -		print '<td>' . price($obj->credit) . '</td>';
    -		print '<td>' . price($obj->montant) . '</td>';
    -		print '<td>' . $obj->sens . '</td>';
    -		print '<td>' . $obj->code_journal . '</td>';
    -		print '<td>' . round($solde, 2) . '</td>';
    +		print '<td align="right">' . price($obj->debit) . '</td>';
    +		print '<td align="right">' . price($obj->credit) . '</td>';
    +		print '<td align="right">' . price(round($solde, 2)) . '</td>';
    +		print '<td align="center">' . $obj->code_journal . '</td>';
     
     		if (empty($obj->lettering_code)) {
     			print '<td class="nowrap" align="center"><input type="checkbox" class="flat checkforselect" name="toselect[]" id="toselect[]" value="' . $obj->rowid . '" /></td>';
     		} else
    -			print '<td>' . $obj->lettering_code . '</td>';
    +			print '<td align="center">' . $obj->lettering_code . '</td>';
     
     		print "</tr>\n";
     	}
     
     	print '<tr class="oddeven">';
    -
    -	print '<td colspan="4">Mouvement totaux</td>' . "\n";
    -	print '<td><strong>' . price($debit) . '</strong></td>';
    -	print '<td><strong>' . price($credit) . '</strong></td>';
    +	print '<td align="right" colspan="4">'.$langs->trans("Total").':</td>' . "\n";
    +	print '<td align="right"><strong>' . price($debit) . '</strong></td>';
    +	print '<td align="right"><strong>' . price($credit) . '</strong></td>';
     	print '<td colspan="5"></td>';
     	print "</tr>\n";
     
     	print '<tr class="oddeven">';
    -	print '<td colspan="9">Solde Comptable</td>' . "\n";
    -	print '<td><strong>' . price($credit - $debit) . '</strong></td>';
    -	print '<td colspan="5"></td>';
    +	print '<td align="right" colspan="4">'.$langs->trans("Balancing").':</td>' . "\n";
    +	print '<td colspan="2">&nbsp;</td>';
    +	print '<td align="right"><strong>' . price($credit - $debit) . '</strong></td>';
    +	print '<td colspan="3"></td>';
     	print "</tr>\n";
     
     	print "</table>";
     
    -	print '<input class="butAction" type="submit" value="lettering" name="lettering" id="lettering">';
    -	print '<a class="butAction" href="'.$_SERVER["PHP_SELF"].'?socid=' . $object->id . '&action=autolettrage">'.$langs->trans('AccountancyAutoLettering').'</a>';
    +	print '<input class="butAction" type="submit" value="' . $langs->trans('AccountancyLettering') . '" name="lettering" id="lettering">';
    +	//print '<a class="butAction" href="'.$_SERVER["PHP_SELF"].'?socid=' . $object->id . '&action=autolettrage">'.$langs->trans('AccountancyAutoLettering').'</a>';
     	print "</form>";
     	$db->free($resql);
     } else {
    diff --git a/htdocs/accountancy/class/accountancycategory.class.php b/htdocs/accountancy/class/accountancycategory.class.php
    index 7cd1f1d11b2..e2a7b14033c 100644
    --- a/htdocs/accountancy/class/accountancycategory.class.php
    +++ b/htdocs/accountancy/class/accountancycategory.class.php
    @@ -1,6 +1,7 @@
     <?php
     /* Copyright (C) 2016		Jamal Elbaz			<jamelbaz@gmail.pro>
      * Copyright (C) 2016-2017	Alexandre Spangaro	<aspangaro@zendsi.com>
    + * Copyright (C) 2018       Frédéric France     <frederic.france@netlogic.fr>
      *
      * This program is free software; you can redistribute it and/or modify
      * it under the terms of the GNU General Public License as published by
    @@ -816,9 +817,9 @@ class AccountancyCategory // extends CommonObject
     	 * Get all accounting account of a group.
     	 * You must choose between first parameter (personalized group) or the second (free criteria filter)
     	 *
    -	 * @param 	int 	$cat_id 				Id if personalized accounting group/category
    -	 * @param 	string 	$predefinedgroupwhere 	Sql criteria filter to select accounting accounts
    -	 * @return 	array|int       				Array of accounting accounts or -1 if error
    +	 * @param 	int 		$cat_id 				Id if personalized accounting group/category
    +	 * @param 	string 		$predefinedgroupwhere 	Sql criteria filter to select accounting accounts
    +	 * @return 	array|int							Array of accounting accounts or -1 if error
     	 */
     	public function getCptsCat($cat_id, $predefinedgroupwhere='')
     	{
    diff --git a/htdocs/accountancy/class/accountancyexport.class.php b/htdocs/accountancy/class/accountancyexport.class.php
    index 40427d68034..7b832976e89 100644
    --- a/htdocs/accountancy/class/accountancyexport.class.php
    +++ b/htdocs/accountancy/class/accountancyexport.class.php
    @@ -44,7 +44,8 @@ class AccountancyExport
     	/**
     	 * @var Type of export. Defined by $conf->global->ACCOUNTING_EXPORT_MODELCSV
     	 */
    -	public static $EXPORT_TYPE_NORMAL = 1;	 // Classic CSV
    +	public static $EXPORT_TYPE_NORMAL = 1;	 			// CSV
    +	public static $EXPORT_TYPE_CONFIGURABLE = 10;		// CSV
     	public static $EXPORT_TYPE_CEGID = 2;
     	public static $EXPORT_TYPE_COALA = 3;
     	public static $EXPORT_TYPE_BOB50 = 4;
    @@ -53,7 +54,7 @@ class AccountancyExport
     	public static $EXPORT_TYPE_EBP = 7;
     	public static $EXPORT_TYPE_COGILOG = 8;
     	public static $EXPORT_TYPE_AGIRIS = 9;
    -	public static $EXPORT_TYPE_CONFIGURABLE = 10;
    +	public static $EXPORT_TYPE_FEC = 11;
     
     
     	/**
    @@ -78,8 +79,8 @@ class AccountancyExport
     	 *
     	 * @param DoliDb $db Database handler
     	 */
    -    public function __construct(DoliDB &$db)
    -    {
    +	public function __construct(DoliDB &$db)
    +	{
     		global $conf;
     
     		$this->db = &$db;
    @@ -92,12 +93,13 @@ class AccountancyExport
     	 *
     	 * @return array of type
     	 */
    -    public static function getType()
    -    {
    +	public static function getType()
    +	{
     		global $langs;
     
     		return array (
    -				self::$EXPORT_TYPE_NORMAL => $langs->trans('Modelcsv_normal'),
    +				//self::$EXPORT_TYPE_NORMAL => $langs->trans('Modelcsv_normal'),
    +				self::$EXPORT_TYPE_CONFIGURABLE => $langs->trans('Modelcsv_configurable'),
     				self::$EXPORT_TYPE_CEGID => $langs->trans('Modelcsv_CEGID'),
     				self::$EXPORT_TYPE_COALA => $langs->trans('Modelcsv_COALA'),
     				self::$EXPORT_TYPE_BOB50 => $langs->trans('Modelcsv_bob50'),
    @@ -106,28 +108,53 @@ class AccountancyExport
     				self::$EXPORT_TYPE_EBP => $langs->trans('Modelcsv_ebp'),
     				self::$EXPORT_TYPE_COGILOG => $langs->trans('Modelcsv_cogilog'),
     				self::$EXPORT_TYPE_AGIRIS => $langs->trans('Modelcsv_agiris'),
    -				self::$EXPORT_TYPE_CONFIGURABLE => $langs->trans('Modelcsv_configurable'),
    +				self::$EXPORT_TYPE_FEC => $langs->trans('Modelcsv_FEC'),
     			);
     	}
     
    +	/**
    +	 * Return string to summarize the format (Used to generated export filename)
    +	 *
    +	 * @param	int		$type		Format id
    +	 * @return 	string				Format code
    +	 */
    +	private static function getFormatCode($type)
    +	{
    +		$formatcode = array (
    +			//self::$EXPORT_TYPE_NORMAL => 'csv',
    +			self::$EXPORT_TYPE_CONFIGURABLE => 'csv',
    +			self::$EXPORT_TYPE_CEGID => 'cegid',
    +			self::$EXPORT_TYPE_COALA => 'coala',
    +			self::$EXPORT_TYPE_BOB50 => 'bob50',
    +			self::$EXPORT_TYPE_CIEL => 'ciel',
    +			self::$EXPORT_TYPE_QUADRATUS => 'quadratus',
    +			self::$EXPORT_TYPE_EBP => 'ebp',
    +			self::$EXPORT_TYPE_COGILOG => 'cogilog',
    +			self::$EXPORT_TYPE_AGIRIS => 'agiris',
    +			self::$EXPORT_TYPE_FEC => 'fec',
    +		);
    +
    +		return $formatcode[$type];
    +	}
    +
     	/**
     	 * Array with all export type available (key + label) and parameters for config
     	 *
     	 * @return array of type
     	 */
    -    public static function getTypeConfig()
    -    {
    +	public static function getTypeConfig()
    +	{
     		global $conf, $langs;
     
     		return array (
     			'param' => array(
    -				self::$EXPORT_TYPE_NORMAL => array(
    +				/*self::$EXPORT_TYPE_NORMAL => array(
     					'label' => $langs->trans('Modelcsv_normal'),
     					'ACCOUNTING_EXPORT_FORMAT' => empty($conf->global->ACCOUNTING_EXPORT_FORMAT)?'txt':$conf->global->ACCOUNTING_EXPORT_FORMAT,
     					'ACCOUNTING_EXPORT_SEPARATORCSV' => empty($conf->global->ACCOUNTING_EXPORT_SEPARATORCSV)?',':$conf->global->ACCOUNTING_EXPORT_SEPARATORCSV,
     					'ACCOUNTING_EXPORT_ENDLINE' => empty($conf->global->ACCOUNTING_EXPORT_ENDLINE)?1:$conf->global->ACCOUNTING_EXPORT_ENDLINE,
     					'ACCOUNTING_EXPORT_DATE' => empty($conf->global->ACCOUNTING_EXPORT_DATE)?'%d%m%Y':$conf->global->ACCOUNTING_EXPORT_DATE,
    -				),
    +				),*/
     				self::$EXPORT_TYPE_CEGID => array(
     					'label' => $langs->trans('Modelcsv_CEGID'),
     				),
    @@ -161,6 +188,10 @@ class AccountancyExport
     					'ACCOUNTING_EXPORT_ENDLINE' => empty($conf->global->ACCOUNTING_EXPORT_ENDLINE)?1:$conf->global->ACCOUNTING_EXPORT_ENDLINE,
     					'ACCOUNTING_EXPORT_DATE' => empty($conf->global->ACCOUNTING_EXPORT_DATE)?'%d%m%Y':$conf->global->ACCOUNTING_EXPORT_DATE,
     				),
    +				self::$EXPORT_TYPE_FEC => array(
    +					'label' => $langs->trans('Modelcsv_FEC'),
    +					'ACCOUNTING_EXPORT_FORMAT' => 'txt',
    +				),
     			),
     			'cr'=> array (
     				'1' => $langs->trans("Unix"),
    @@ -173,34 +204,30 @@ class AccountancyExport
     		);
     	}
     
    +
     	/**
    -	 * Download the export
    +	 * Function who chose which export to use with the default config, and make the export into a file
     	 *
    +	 * @param array		$TData 		data
     	 * @return void
     	 */
    -    public static function downloadFile()
    -    {
    -		global $conf;
    -		$filename = 'general_ledger';
    -		include DOL_DOCUMENT_ROOT . '/accountancy/tpl/export_journal.tpl.php';
    -	}
    -
    -	/**
    -	 * Function who chose which export to use with the default config
    -	 *
    -	 * @param unknown $TData data
    -     * @return void
    -	 */
    -    public function export(&$TData)
    -    {
    +	public function export(&$TData)
    +	{
     		global $conf, $langs;
    +		global $search_date_end;	// Used into /accountancy/tpl/export_journal.tpl.php
    +
    +		// Define name of file to save
    +		$filename = 'general_ledger-'.$this->getFormatCode($conf->global->ACCOUNTING_EXPORT_MODELCSV);
    +
    +		include DOL_DOCUMENT_ROOT . '/accountancy/tpl/export_journal.tpl.php';
     
    -		self::downloadFile();
     
     		switch ($conf->global->ACCOUNTING_EXPORT_MODELCSV) {
     			case self::$EXPORT_TYPE_NORMAL :
    -				$this->exportNormal($TData);
    +			case self::$EXPORT_TYPE_CONFIGURABLE :
    +				$this->exportConfigurable($TData);
     				break;
    +			case self::$EXPORT_TYPE_NORMAL :
     			case self::$EXPORT_TYPE_CEGID :
     				$this->exportCegid($TData);
     				break;
    @@ -225,8 +252,8 @@ class AccountancyExport
     			case self::$EXPORT_TYPE_AGIRIS :
     				$this->exportAgiris($TData);
     				break;
    -			case self::$EXPORT_TYPE_CONFIGURABLE :
    -				$this->exportConfigurable($TData);
    +			case self::$EXPORT_TYPE_FEC :
    +				$this->exportFEC($TData);
     				break;
     			default:
     				$this->errors[] = $langs->trans('accountancy_error_modelnotfound');
    @@ -234,30 +261,6 @@ class AccountancyExport
     		}
     	}
     
    -	/**
    -	 * Export format : Normal
    -	 *
    -	 * @param array $objectLines data
    -	 *
    -	 * @return void
    -	 */
    -    public function exportNormal($objectLines)
    -    {
    -		global $conf;
    -
    -		foreach ( $objectLines as $line ) {
    -			// Std export
    -			$date = dol_print_date($line->doc_date, $conf->global->ACCOUNTING_EXPORT_DATE);
    -			print $date . $this->separator;
    -			print $line->doc_ref . $this->separator;
    -			print length_accountg($line->numero_compte) . $this->separator;
    -			print length_accounta($line->subledger_account) . $this->separator;
    -			print price($line->debit) . $this->separator;
    -			print price($line->credit) . $this->separator;
    -			print $line->code_journal . $this->separator;
    -			print $this->end_line;
    -		}
    -	}
     
     	/**
     	 * Export format : CEGID
    @@ -266,8 +269,8 @@ class AccountancyExport
     	 *
     	 * @return void
     	 */
    -    public function exportCegid($objectLines)
    -    {
    +	public function exportCegid($objectLines)
    +	{
     		foreach ( $objectLines as $line ) {
     			$date = dol_print_date($line->doc_date, '%d%m%Y');
     			$separator = ";";
    @@ -292,8 +295,8 @@ class AccountancyExport
     	 *
     	 * @return void
     	 */
    -    public function exportCogilog($objectLines)
    -    {
    +	public function exportCogilog($objectLines)
    +	{
     		foreach ( $objectLines as $line ) {
     			$date = dol_print_date($line->doc_date, '%d%m%Y');
     			$separator = ";";
    @@ -326,8 +329,8 @@ class AccountancyExport
     	 *
     	 * @return void
     	 */
    -    public function exportCoala($objectLines)
    -    {
    +	public function exportCoala($objectLines)
    +	{
     		// Coala export
     		$separator = ";";
     		$end_line = "\n";
    @@ -354,8 +357,8 @@ class AccountancyExport
     	 *
     	 * @return void
     	 */
    -    public function exportBob50($objectLines)
    -    {
    +	public function exportBob50($objectLines)
    +	{
     
     		// Bob50
     		$separator = ";";
    @@ -393,8 +396,8 @@ class AccountancyExport
     	 *
     	 * @return void
     	 */
    -    public function exportCiel(&$TData)
    -    {
    +	public function exportCiel(&$TData)
    +	{
     		global $conf;
     
     		$end_line ="\r\n";
    @@ -434,13 +437,13 @@ class AccountancyExport
     	 *
     	 * @return void
     	 */
    -    public function exportQuadratus(&$TData)
    -    {
    +	public function exportQuadratus(&$TData)
    +	{
     		global $conf;
     
     		$end_line ="\r\n";
     
    -        //We should use dol_now function not time however this is wrong date to transfert in accounting
    +		//We should use dol_now function not time however this is wrong date to transfert in accounting
     		//$date_ecriture = dol_print_date(dol_now(), $conf->global->ACCOUNTING_EXPORT_DATE); // format must be ddmmyy
     		//$date_ecriture = dol_print_date(time(), $conf->global->ACCOUNTING_EXPORT_DATE); // format must be ddmmyy
     		foreach ( $TData as $data ) {
    @@ -454,8 +457,8 @@ class AccountancyExport
     			$Tab['code_journal'] = str_pad(self::trunc($data->code_journal, 2), 2);
     			$Tab['folio'] = '000';
     
    -            //We use invoice date $data->doc_date not $date_ecriture which is the transfert date
    -            //maybe we should set an option for customer who prefer to keep in accounting software the tranfert date instead of invoice date ?
    +			//We use invoice date $data->doc_date not $date_ecriture which is the transfert date
    +			//maybe we should set an option for customer who prefer to keep in accounting software the tranfert date instead of invoice date ?
     			//$Tab['date_ecriture'] = $date_ecriture;
     			$Tab['date_ecriture'] = dol_print_date($data->doc_date, '%d%m%y');
     			$Tab['filler'] = ' ';
    @@ -463,25 +466,25 @@ class AccountancyExport
     			$Tab['sens'] = $data->sens; // C or D
     			$Tab['signe_montant'] = '+';
     
    -            //elarifr le montant doit etre en centimes sans point decimal !
    +			//elarifr le montant doit etre en centimes sans point decimal !
     			$Tab['montant'] = str_pad(abs($data->montant*100), 12, '0', STR_PAD_LEFT); // TODO manage negative amount
    -		    // $Tab['montant'] = str_pad(abs($data->montant), 12, '0', STR_PAD_LEFT); // TODO manage negative amount
    +			// $Tab['montant'] = str_pad(abs($data->montant), 12, '0', STR_PAD_LEFT); // TODO manage negative amount
     			$Tab['contrepartie'] = str_repeat(' ', 8);
     
    -            // elarifr:  date format must be fixed format : 6 char ddmmyy = %d%m%yand not defined by user / dolibarr setting
    +			// elarifr:  date format must be fixed format : 6 char ddmmyy = %d%m%yand not defined by user / dolibarr setting
     			if (! empty($data->date_echeance))
     				//$Tab['date_echeance'] = dol_print_date($data->date_echeance, $conf->global->ACCOUNTING_EXPORT_DATE);
    -				$Tab['date_echeance'] = dol_print_date($data->date_echeance,  '%d%m%y' );     // elarifr:  format must be ddmmyy
    +				$Tab['date_echeance'] = dol_print_date($data->date_echeance,  '%d%m%y' );	 // elarifr:  format must be ddmmyy
     			else
     				$Tab['date_echeance'] = '000000';
     
    -            //elarifr please keep quadra named field lettrage(2) + codestat(3) instead of fake lettrage(5)
    +			//elarifr please keep quadra named field lettrage(2) + codestat(3) instead of fake lettrage(5)
     			//$Tab['lettrage'] = str_repeat(' ', 5);
     			$Tab['lettrage'] = str_repeat(' ', 2);
     			$Tab['codestat'] = str_repeat(' ', 3);
     			$Tab['num_piece'] = str_pad(self::trunc($data->piece_num, 5), 5);
     
    -            //elarifr keep correct quadra named field instead of anon filler
    +			//elarifr keep correct quadra named field instead of anon filler
     			//$Tab['filler2'] = str_repeat(' ', 20);
     			$Tab['affaire'] = str_repeat(' ', 10);
     			$Tab['quantity1'] = str_repeat(' ', 10);
    @@ -490,16 +493,16 @@ class AccountancyExport
     			$Tab['code_journal2'] = str_pad(self::trunc($data->code_journal, 3), 3);
     			$Tab['filler3'] = str_repeat(' ', 3);
     
    -            //elarifr keep correct quadra named field instead of anon filler libelle_ecriture2 is 30 char not 32 !!!!
    -            //as we use utf8, we must remove accent to have only one ascii char instead of utf8 2 chars for specials that report wrong line size that will exceed import format spec
    -            //todo we should filter more than only accent to avoid wrong line size
    -            //TODO: remove invoice number doc_ref in libelle,
    -            //TODO: we should offer an option for customer to build the libelle using invoice number / name / date in accounting software
    +			//elarifr keep correct quadra named field instead of anon filler libelle_ecriture2 is 30 char not 32 !!!!
    +			//as we use utf8, we must remove accent to have only one ascii char instead of utf8 2 chars for specials that report wrong line size that will exceed import format spec
    +			//todo we should filter more than only accent to avoid wrong line size
    +			//TODO: remove invoice number doc_ref in libelle,
    +			//TODO: we should offer an option for customer to build the libelle using invoice number / name / date in accounting software
     			//$Tab['libelle_ecriture2'] = str_pad(self::trunc(dol_string_unaccent($data->doc_ref) . ' ' . dol_string_unaccent($data->label_operation), 30), 30);
     			$Tab['libelle_ecriture2'] = str_pad(self::trunc(dol_string_unaccent($data->label_operation), 30), 30);
     			$Tab['codetva'] = str_repeat(' ', 2);
     
    -            //elarifr we need to keep the 10 lastest number of invoice doc_ref not the beginning part that is the unusefull almost same part
    +			//elarifr we need to keep the 10 lastest number of invoice doc_ref not the beginning part that is the unusefull almost same part
     			//$Tab['num_piece3'] = str_pad(self::trunc($data->piece_num, 10), 10);
     			$Tab['num_piece3'] = substr(self::trunc($data->doc_ref, 20), -10);
     			$Tab['filler4'] = str_repeat(' ', 73);
    @@ -518,8 +521,8 @@ class AccountancyExport
     	 *
     	 * @return void
     	 */
    -    public function exportEbp($objectLines)
    -    {
    +	public function exportEbp($objectLines)
    +	{
     
     		$separator = ',';
     		$end_line = "\n";
    @@ -551,8 +554,8 @@ class AccountancyExport
     	 *
     	 * @return void
     	 */
    -    public function exportAgiris($objectLines)
    -    {
    +	public function exportAgiris($objectLines)
    +	{
     
     		$separator = ';';
     		$end_line = "\n";
    @@ -589,8 +592,8 @@ class AccountancyExport
     	 *
     	 * @return void
     	 */
    -    public function exportConfigurable($objectLines)
    -    {
    +	public function exportConfigurable($objectLines)
    +	{
     		global $conf;
     
     		foreach ($objectLines as $line) {
    @@ -601,27 +604,121 @@ class AccountancyExport
     			$tab[] = $date;
     			$tab[] = $line->doc_ref;
     			$tab[] = $line->label_operation;
    -			$tab[] =  length_accountg($line->numero_compte);
    -			$tab[] =  length_accounta($line->subledger_account);
    -			$tab[] =  price($line->debit);
    -			$tab[] =  price($line->credit);
    -			$tab[] =  price($line->montant);
    -			$tab[] =  $line->code_journal;
    +			$tab[] = length_accountg($line->numero_compte);
    +			$tab[] = length_accounta($line->subledger_account);
    +			$tab[] = price($line->debit);
    +			$tab[] = price($line->credit);
    +			$tab[] = price($line->montant);
    +			$tab[] = $line->code_journal;
     
     			$separator = $this->separator;
     			print implode($separator, $tab) . $this->end_line;
     		}
     	}
     
    +	/**
    +	 * Export format : FEC
    +	 *
    +	 * @param array $objectLines data
    +	 *
    +	 * @return void
    +	 */
    +	public function exportFEC($objectLines)
    +	{
    +		$separator = "\t";
    +		$end_line = "\n";
    +
    +		print "JournalCode" . $separator;
    +		print "JournalLib" . $separator;
    +		print "EcritureNum" . $separator;
    +		print "EcritureDate" . $separator;
    +		print "CompteNum" . $separator;
    +		print "CompteLib" . $separator;
    +		print "CompAuxNum" . $separator;
    +		print "CompAuxLib" . $separator;
    +		print "PieceRef" . $separator;
    +		print "PieceDate" . $separator;
    +		print "EcritureLib" . $separator;
    +		print "Debit" . $separator;
    +		print "Credit" . $separator;
    +		print "EcritureLet" . $separator;
    +		print "DateLet" . $separator;
    +		print "ValidDate" . $separator;
    +		print "Montantdevise" . $separator;
    +		print "Idevise";
    +		print $end_line;
    +
    +		foreach ( $objectLines as $line ) {
    +			$date_creation = dol_print_date($line->date_creation, '%d%m%Y');
    +			$date_doc = dol_print_date($line->doc_date, '%d%m%Y');
    +			$date_valid = dol_print_date($line->date_validated, '%d%m%Y');
    +
    +			// FEC:JournalCode
    +			print $line->code_journal . $separator;
    +
    +			// FEC:JournalLib
    +			print $line->journal_label . $separator;
    +
    +			// FEC:EcritureNum
    +			print $line->piece_num . $separator;
    +
    +			// FEC:EcritureDate
    +			print $date_creation . $separator;
    +
    +			// FEC:CompteNum
    +			print $line->numero_compte . $separator;
    +
    +			// FEC:CompteLib
    +			print $line->label_compte . $separator;
    +
    +			// FEC:CompAuxNum
    +			print $line->subledger_account . $separator;
    +
    +			// FEC:CompAuxLib
    +			print $line->subledger_label . $separator;
    +
    +			// FEC:PieceRef
    +			print $line->doc_ref . $separator;
    +
    +			// FEC:PieceDate
    +			print $date_doc . $separator;
    +
    +			// FEC:EcritureLib
    +			print $line->label_operation . $separator;
    +
    +			// FEC:Debit
    +			print price2num($line->debit) . $separator;
    +
    +			// FEC:Credit
    +			print price2num($line->credit) . $separator;
    +
    +			// FEC:EcritureLet
    +			print $line->lettering_code . $separator;
    +
    +			// FEC:DateLet
    +			print $line->date_lettering . $separator;
    +
    +			// FEC:ValidDate
    +			print $date_valid . $separator;
    +
    +			// FEC:Montantdevise
    +			print $line->multicurrency_amount . $separator;
    +
    +			// FEC:Idevise
    +			print $line->multicurrency_code;
    +
    +			print $end_line;
    +		}
    +	}
     
     	/**
     	 *
    -	 * @param unknown $str data
    -	 * @param integer $size data
    -     * @return string
    +	 * @param string	$str 	data
    +	 * @param integer 	$size 	data
    +	 * @return string
     	 */
    -    public static function trunc($str, $size)
    -    {
    +	public static function trunc($str, $size)
    +	{
     		return dol_trunc($str, $size, 'right', 'UTF-8', 1);
     	}
     }
    diff --git a/htdocs/accountancy/class/accountancysystem.class.php b/htdocs/accountancy/class/accountancysystem.class.php
    index 444079f5239..b70fa7238bb 100644
    --- a/htdocs/accountancy/class/accountancysystem.class.php
    +++ b/htdocs/accountancy/class/accountancysystem.class.php
    @@ -38,8 +38,16 @@ class AccountancySystem
     	 */
     	public $error='';
     
    +	/**
    +	 * @var int ID
    +	 */
     	public $rowid;
    +
    +	/**
    +     * @var int ID
    +     */
     	public $fk_pcg_version;
    +
     	public $pcg_type;
     	public $pcg_subtype;
     
    diff --git a/htdocs/accountancy/class/accountingaccount.class.php b/htdocs/accountancy/class/accountingaccount.class.php
    index 4929e118a3b..85f9ee39c61 100644
    --- a/htdocs/accountancy/class/accountingaccount.class.php
    +++ b/htdocs/accountancy/class/accountingaccount.class.php
    @@ -4,6 +4,7 @@
      * Copyright (C) 2013-2014  Florian Henry        <florian.henry@open-concept.pro>
      * Copyright (C) 2014       Juanjo Menent        <jmenent@2byte.es>
      * Copyright (C) 2015       Ari Elbaz (elarifr)  <github@accedinfo.com>
    + * Copyright (C) 2018       Frédéric France         <frederic.france@netlogic.fr>
      *
      * This program is free software; you can redistribute it and/or modify
      * it under the terms of the GNU General Public License as published by
    @@ -30,6 +31,9 @@
      */
     class AccountingAccount extends CommonObject
     {
    +	/**
    +	 * @var string Name of element
    +	 */
     	public $element='accounting_account';
     
     	/**
    @@ -59,16 +63,6 @@ class AccountingAccount extends CommonObject
     	 */
     	public $db;
     
    -	/**
    -	 * @var string Error code (or message)
    -	 */
    -	public $error='';
    -
    -	/**
    -	 * @var string[] Error codes (or messages)
    -	 */
    -	public $errors = array();
    -
     	/**
     	 * @var int ID
     	 */
    @@ -79,13 +73,44 @@ class AccountingAccount extends CommonObject
     	 */
     	public $rowid;
     
    -	public $datec; // Creation date
    +	/**
    +     * @var string Creation date
    +     */
    +	public $datec;
    +
    +	/**
    +     * @var string pcg version
    +     */
     	public $fk_pcg_version;
    +
    +    /**
    +     * @var string pcg type
    +     */
     	public $pcg_type;
    +
    +    /**
    +     * @var string pcg subtype
    +     */
     	public $pcg_subtype;
    +
    +    /**
    +     * @var string account number
    +     */
     	public $account_number;
    +
    +    /**
    +     * @var int ID parent account
    +     */
     	public $account_parent;
    +
    +    /**
    +     * @var int ID category account
    +     */
     	public $account_category;
    +
    +	/**
    +	 * @var int Status
    +	 */
     	public $status;
     
         /**
    @@ -103,8 +128,10 @@ class AccountingAccount extends CommonObject
          */
         public $fk_user_modif;
     
    -    public $active;       // duplicate with status
    -
    +	/**
    +	 * @var int active (duplicate with status)
    +	 */
    +    public $active;
     
     	/**
     	 * Constructor
    diff --git a/htdocs/accountancy/class/accountingjournal.class.php b/htdocs/accountancy/class/accountingjournal.class.php
    index 058bdb3dddb..9bd21a4a5c4 100644
    --- a/htdocs/accountancy/class/accountingjournal.class.php
    +++ b/htdocs/accountancy/class/accountingjournal.class.php
    @@ -41,7 +41,11 @@ class AccountingJournal extends CommonObject
     	 */
     	public $fk_element = '';
     
    -	public $ismultientitymanaged = 0;	// 0=No test on entity, 1=Test with field entity, 2=Test with link by societe
    +	/**
    +	 * 0=No test on entity, 1=Test with field entity, 2=Test with link by societe
    +	 * @var int
    +	 */
    +	public $ismultientitymanaged = 0;
     
     	/**
     	 * @var string String with name of icon for myobject. Must be the part after the 'object_' into object_myobject.png
    diff --git a/htdocs/accountancy/class/bookkeeping.class.php b/htdocs/accountancy/class/bookkeeping.class.php
    index 5d9572da684..0ce49e76f51 100644
    --- a/htdocs/accountancy/class/bookkeeping.class.php
    +++ b/htdocs/accountancy/class/bookkeeping.class.php
    @@ -1,7 +1,8 @@
     <?php
    -/* Copyright (C) 2014-2017 Olivier Geffroy		<jeff@jeffinfo.com>
    - * Copyright (C) 2015-2017 Alexandre Spangaro	<aspangaro@zendsi.com>
    - * Copyright (C) 2015-2017 Florian Henry		<florian.henry@open-concept.pro>
    +/* Copyright (C) 2014-2017  Olivier Geffroy     <jeff@jeffinfo.com>
    + * Copyright (C) 2015-2017  Alexandre Spangaro  <aspangaro@zendsi.com>
    + * Copyright (C) 2015-2017  Florian Henry       <florian.henry@open-concept.pro>
    + * Copyright (C) 2018       Frédéric France     <frederic.france@netlogic.fr>
      *
      * This program is free software; you can redistribute it and/or modify
      * it under the terms of the GNU General Public License as published by
    @@ -18,9 +19,9 @@
      */
     
     /**
    - *	\file		htdocs/accountancy/class/bookkeeping.class.php
    - *	\ingroup	Advanced accountancy
    - *	\brief		File of class to manage Ledger (General Ledger and Subledger)
    + * \file        htdocs/accountancy/class/bookkeeping.class.php
    + * \ingroup     Advanced accountancy
    + * \brief       File of class to manage Ledger (General Ledger and Subledger)
      */
     
     // Class
    @@ -70,8 +71,17 @@ class BookKeeping extends CommonObject
     	public $date_lim_reglement;
     	public $doc_type;
     	public $doc_ref;
    +
    +	/**
    +     * @var int ID
    +     */
     	public $fk_doc;
    +
    +	/**
    +     * @var int ID
    +     */
     	public $fk_docdet;
    +
     	public $thirdparty_code;
     	public $subledger_account;
     	public $subledger_label;
    @@ -82,7 +92,12 @@ class BookKeeping extends CommonObject
     	public $credit;
     	public $montant;
     	public $sens;
    +
    +	/**
    +     * @var int ID
    +     */
     	public $fk_user_author;
    +
     	public $import_key;
     	public $code_journal;
     	public $journal_label;
    @@ -718,6 +733,10 @@ class BookKeeping extends CommonObject
     		$sql .= " t.credit,";
     		$sql .= " t.montant,";
     		$sql .= " t.sens,";
    +		$sql .= " t.multicurrency_amount,";
    +		$sql .= " t.multicurrency_code,";
    +		$sql .= " t.lettering_code,";
    +		$sql .= " t.date_lettering,";
     		$sql .= " t.fk_user_author,";
     		$sql .= " t.import_key,";
     		$sql .= " t.code_journal,";
    @@ -766,7 +785,8 @@ class BookKeeping extends CommonObject
     		if ($resql) {
     			$num = $this->db->num_rows($resql);
     
    -			while ( $obj = $this->db->fetch_object($resql) ) {
    +			$i = 0;
    +			while ($obj = $this->db->fetch_object($resql) && (empty($limit) || $i < min($limit, $num))) {
     				$line = new BookKeepingLine();
     
     				$line->id = $obj->rowid;
    @@ -786,6 +806,10 @@ class BookKeeping extends CommonObject
     				$line->credit = $obj->credit;
     				$line->montant = $obj->montant;
     				$line->sens = $obj->sens;
    +				$line->multicurrency_amount = $obj->multicurrency_amount;
    +				$line->multicurrency_code = $obj->multicurrency_code;
    +				$line->lettering_code = $obj->lettering_code;
    +				$line->date_lettering = $obj->date_lettering;
     				$line->fk_user_author = $obj->fk_user_author;
     				$line->import_key = $obj->import_key;
     				$line->code_journal = $obj->code_journal;
    @@ -794,6 +818,8 @@ class BookKeeping extends CommonObject
     				$line->date_creation = $obj->date_creation;
     
     				$this->lines[] = $line;
    +
    +				$i++;
     			}
     			$this->db->free($resql);
     
    @@ -839,6 +865,7 @@ class BookKeeping extends CommonObject
     		$sql .= " t.label_operation,";
     		$sql .= " t.debit,";
     		$sql .= " t.credit,";
    +		$sql .= " t.lettering_code,";
     		$sql .= " t.montant,";
     		$sql .= " t.sens,";
     		$sql .= " t.fk_user_author,";
    @@ -891,7 +918,8 @@ class BookKeeping extends CommonObject
     		if ($resql) {
     			$num = $this->db->num_rows($resql);
     
    -			while ( $obj = $this->db->fetch_object($resql) ) {
    +			$i = 0;
    +			while ($obj = $this->db->fetch_object($resql) && (empty($limit) || $i < min($limit, $num))) {
     				$line = new BookKeepingLine();
     
     				$line->id = $obj->rowid;
    @@ -911,6 +939,7 @@ class BookKeeping extends CommonObject
     				$line->credit = $obj->credit;
     				$line->montant = $obj->montant;
     				$line->sens = $obj->sens;
    +				$line->lettering_code = $obj->lettering_code;
     				$line->fk_user_author = $obj->fk_user_author;
     				$line->import_key = $obj->import_key;
     				$line->code_journal = $obj->code_journal;
    @@ -920,6 +949,8 @@ class BookKeeping extends CommonObject
     				$line->date_modification = $this->db->jdate($obj->date_modification);
     
     				$this->lines[] = $line;
    +
    +				$i++;
     			}
     			$this->db->free($resql);
     
    @@ -978,8 +1009,7 @@ class BookKeeping extends CommonObject
     				}
     			}
     		}
    -		$sql.= ' WHERE 1 = 1';
    -		$sql .= " AND entity IN (" . getEntity('accountancy') . ")";
    +		$sql.= ' WHERE entity IN (' . getEntity('accountancy') . ')';
     		if (count($sqlwhere) > 0) {
     			$sql .= ' AND ' . implode(' ' . $filtermode . ' ', $sqlwhere);
     		}
    @@ -994,16 +1024,21 @@ class BookKeeping extends CommonObject
     		}
     
     		$resql = $this->db->query($sql);
    -		if ($resql) {
    +		if ($resql)
    +		{
     			$num = $this->db->num_rows($resql);
     
    -			while ( $obj = $this->db->fetch_object($resql) ) {
    +			$i = 0;
    +			while (($obj = $this->db->fetch_object($resql)) && (empty($limit) || $i < min($limit, $num)))
    +			{
     				$line = new BookKeepingLine();
     
     				$line->numero_compte = $obj->numero_compte;
     				$line->debit = $obj->debit;
     				$line->credit = $obj->credit;
     				$this->lines[] = $line;
    +
    +				$i++;
     			}
     			$this->db->free($resql);
     
    @@ -1613,9 +1648,9 @@ class BookKeeping extends CommonObject
     	/**
     	 * Transform transaction
     	 *
    -	 * @param  number   $direction     If 0 tmp => real, if 1 real => tmp
    -	 * @param  string   $piece_num     Piece num
    -	 * @return void
    +	 * @param  number   $direction      If 0 tmp => real, if 1 real => tmp
    +	 * @param  string   $piece_num      Piece num
    +	 * @return int                      int <0 if KO, >0 if OK
     	 */
     	public function transformTransaction($direction=0,$piece_num='')
     	{
    @@ -1651,8 +1686,7 @@ class BookKeeping extends CommonObject
     				$this->errors[] = 'Error ' . $this->db->lasterror();
     				dol_syslog(__METHOD__ . ' ' . join(',', $this->errors), LOG_ERR);
     			}
    -		}
    -		if ($direction==1) {
    +		} elseif ($direction==1) {
     			$sql = 'DELETE FROM ' . MAIN_DB_PREFIX . $this->table_element.'_tmp WHERE piece_num = '.$piece_num;
     			$resql = $this->db->query($sql);
     			if (! $resql) {
    @@ -1871,8 +1905,17 @@ class BookKeepingLine
     	public $doc_date = '';
     	public $doc_type;
     	public $doc_ref;
    +
    +	/**
    +     * @var int ID
    +     */
     	public $fk_doc;
    +
    +	/**
    +     * @var int ID
    +     */
     	public $fk_docdet;
    +
     	public $thirdparty_code;
     	public $subledger_account;
     	public $subledger_label;
    @@ -1883,7 +1926,12 @@ class BookKeepingLine
     	public $credit;
     	public $montant;
     	public $sens;
    +
    +	/**
    +     * @var int ID
    +     */
     	public $fk_user_author;
    +
     	public $import_key;
     	public $code_journal;
     	public $journal_label;
    diff --git a/htdocs/accountancy/class/lettering.class.php b/htdocs/accountancy/class/lettering.class.php
    index 0ddbaeb5026..3122526061b 100644
    --- a/htdocs/accountancy/class/lettering.class.php
    +++ b/htdocs/accountancy/class/lettering.class.php
    @@ -1,7 +1,8 @@
     <?php
    -/* Copyright (C) 2004-2005 Rodolphe Quiedeville <rodolphe@quiedeville.org>
    - * Copyright (C) 2013      Olivier Geffroy      <jeff@jeffinfo.com>
    - * Copyright (C) 2013      Alexandre Spangaro   <alexandre.spangaro@gmail.com>
    +/* Copyright (C) 2004-2005  Rodolphe Quiedeville    <rodolphe@quiedeville.org>
    + * Copyright (C) 2013       Olivier Geffroy         <jeff@jeffinfo.com>
    + * Copyright (C) 2013-2018  Alexandre Spangaro      <aspangaro@zendsi.com>
    + * Copyright (C) 2018       Frédéric France         <frederic.france@netlogic.fr>
      *
      * This program is free software; you can redistribute it and/or modify
      * it under the terms of the GNU General Public License as published by
    @@ -18,26 +19,27 @@
      */
     
     /**
    - * \file accountancy/class/bookkeeping.class.php
    - * \ingroup Advanced accountancy
    - * \brief 	File of class for lettering
    + * \file      	htdocs/accountancy/class/lettering.class.php
    + * \ingroup 	Advanced accountancy
    + * \brief 		File of class for lettering
      */
    +
     include_once DOL_DOCUMENT_ROOT . "/accountancy/class/bookkeeping.class.php";
     include_once DOL_DOCUMENT_ROOT . "/societe/class/societe.class.php";
     include_once DOL_DOCUMENT_ROOT . "/core/lib/date.lib.php";
     
     /**
    - * Class lettering
    + * Class Lettering
      */
    -class lettering extends BookKeeping
    +class Lettering extends BookKeeping
     {
     	/**
    -	 * lettrageTiers
    +	 * letteringThirdparty
     	 *
     	 * @param int $socid Thirdparty id
     	 * @return int 1 OK, <0 error
     	 */
    -	public function lettrageTiers($socid)
    +	public function letteringThirdparty($socid)
     	{
     		global $conf;
     
    @@ -47,6 +49,7 @@ class lettering extends BookKeeping
     		$object->id = $socid;
     		$object->fetch($socid);
     
    +
     		if ($object->code_compta == '411CUSTCODE') {
     			$object->code_compta = '';
     		}
    @@ -229,7 +232,7 @@ class lettering extends BookKeeping
     	 * @param boolean $notrigger no trigger
      	 * @return number
     	 */
    -	public function updateLettrage($ids = array(), $notrigger = false)
    +	public function updateLettering($ids = array(), $notrigger = false)
     	{
     		$error = 0;
     		$lettre = 'AAA';
    diff --git a/htdocs/accountancy/customer/lines.php b/htdocs/accountancy/customer/lines.php
    index 83ddd1bd888..af80d70f043 100644
    --- a/htdocs/accountancy/customer/lines.php
    +++ b/htdocs/accountancy/customer/lines.php
    @@ -17,7 +17,6 @@
      *
      * You should have received a copy of the GNU General Public License
      * along with this program. If not, see <http://www.gnu.org/licenses/>.
    - *
      */
     
     /**
    @@ -33,6 +32,7 @@ require_once DOL_DOCUMENT_ROOT . '/product/class/product.class.php';
     require_once DOL_DOCUMENT_ROOT . '/core/lib/accounting.lib.php';
     require_once DOL_DOCUMENT_ROOT . '/core/class/html.formother.class.php';
     require_once DOL_DOCUMENT_ROOT . '/core/lib/date.lib.php';
    +require_once DOL_DOCUMENT_ROOT . '/core/lib/company.lib.php';
     
     // Load translation files required by the page
     $langs->loadLangs(array("bills","compta","accountancy","productbatch"));
    @@ -173,7 +173,8 @@ $sql.= " fd.rowid, fd.description, fd.product_type as line_type, fd.total_ht, fd
     $sql.= " s.rowid as socid, s.nom as name, s.code_compta, s.code_client,";
     $sql.= " p.rowid as product_id, p.fk_product_type as product_type, p.ref as product_ref, p.label as product_label, p.accountancy_code_sell, aa.rowid as fk_compte, aa.account_number, aa.label as label_compte,";
     $sql.= " fd.situation_percent,";
    -$sql.= " co.label as country, s.tva_intra";
    +$sql.= " co.code as country_code, co.label as country,";
    +$sql.= " s.tva_intra";
     $parameters=array();
     $reshook=$hookmanager->executeHooks('printFieldListSelect',$parameters);    // Note that $action and $object may have been modified by hook
     $sql.=$hookmanager->resPrint;
    @@ -229,7 +230,18 @@ else if ($search_year > 0)
     	$sql.= " AND f.datef BETWEEN '".$db->idate(dol_get_first_day($search_year,1,false))."' AND '".$db->idate(dol_get_last_day($search_year,12,false))."'";
     }
     if (strlen(trim($search_country))) {
    -	$sql .= natural_search("co.label", $search_country);
    +	$arrayofcode = getCountriesInEEC();
    +	$country_code_in_EEC = $country_code_in_EEC_without_me = '';
    +	foreach ($arrayofcode as $key => $value)
    +	{
    +		$country_code_in_EEC.=($country_code_in_EEC ? "," : "")."'".$value."'";
    +		if ($value != $mysoc->country_code) $country_code_in_EEC_without_me.=($country_code_in_EEC_without_me ? "," : "")."'".$value."'";
    +	}
    +	if ($search_country == 'special_allnotme')     $sql .= " AND co.code <> '".$db->escape($mysoc->country_code)."'";
    +	elseif ($search_country == 'special_eec')      $sql .= " AND co.code IN (".$country_code_in_EEC.")";
    +	elseif ($search_country == 'special_eecnotme') $sql .= " AND co.code IN (".$country_code_in_EEC_without_me.")";
    +	elseif ($search_country == 'special_noteec')   $sql .= " AND co.code NOT IN (".$country_code_in_EEC.")";
    +	else $sql .= natural_search(array("co.code","co.label"), $search_country);
     }
     if (strlen(trim($search_tvaintra))) {
     	$sql .= natural_search("s.tva_intra", $search_tvaintra);
    @@ -297,9 +309,9 @@ if ($result) {
     	print '<tr class="liste_titre_filter">';
     	print '<td class="liste_titre"><input type="text" class="flat maxwidth25" name="search_lineid" value="' . dol_escape_htmltag($search_lineid) . '""></td>';
     	print '<td class="liste_titre"><input type="text" class="flat maxwidth50" name="search_invoice" value="' . dol_escape_htmltag($search_invoice) . '"></td>';
    -	print '<td class="liste_titre center">';
    -	if (! empty($conf->global->MAIN_LIST_FILTER_ON_DAY)) print '<input class="flat" type="text" size="1" maxlength="2" name="search_day" value="'.dol_escape_htmltag($search_day).'">';
    -   	print '<input class="flat" type="text" size="1" maxlength="2" name="search_month" value="'.dol_escape_htmltag($search_month).'">';
    +	print '<td class="liste_titre center nowraponall">';
    +	if (! empty($conf->global->MAIN_LIST_FILTER_ON_DAY)) print '<input class="flat valignmiddle" type="text" size="1" maxlength="2" name="search_day" value="'.dol_escape_htmltag($search_day).'">';
    +   	print '<input class="flat valignmiddle" type="text" size="1" maxlength="2" name="search_month" value="'.dol_escape_htmltag($search_month).'">';
        	$formother->select_year($search_year,'search_year',1, 20, 5);
     	print '</td>';
     	print '<td class="liste_titre"><input type="text" class="flat maxwidth50" name="search_ref" value="' . dol_escape_htmltag($search_ref) . '"></td>';
    @@ -307,7 +319,10 @@ if ($result) {
     	print '<td class="liste_titre"><input type="text" class="flat maxwidth50" name="search_desc" value="' . dol_escape_htmltag($search_desc) . '"></td>';
     	print '<td class="liste_titre" align="right"><input type="text" class="right flat maxwidth50" name="search_amount" value="' . dol_escape_htmltag($search_amount) . '"></td>';
     	print '<td class="liste_titre" align="right"><input type="text" class="right flat maxwidth50" placeholder="%" name="search_vat" size="1" value="' . dol_escape_htmltag($search_vat) . '"></td>';
    -	print '<td class="liste_titre"><input type="text" class="flat maxwidth50" name="search_country" value="' . dol_escape_htmltag($search_country) . '"></td>';
    +	print '<td class="liste_titre">';
    +	print $form->select_country($search_country, 'search_country', '', 0, 'maxwidth200', 'code2', 1, 0, 1);
    +	//print '<input type="text" class="flat maxwidth50" name="search_country" value="' . dol_escape_htmltag($search_country) . '">';
    +	print '</td>';
     	print '<td class="liste_titre"><input type="text" class="flat maxwidth50" name="search_tvaintra" value="' . dol_escape_htmltag($search_tvaintra) . '"></td>';
     	print '<td class="liste_titre" align="center"><input type="text" class="flat maxwidth50" name="search_account" value="' . dol_escape_htmltag($search_account) . '"></td>';
     	print '<td class="liste_titre" align="center">';
    @@ -352,7 +367,7 @@ if ($result) {
     		print '<td>' . $objp->rowid . '</td>';
     
     		// Ref Invoice
    -		print '<td>' . $facture_static->getNomUrl(1) . '</td>';
    +		print '<td class="nowraponall">' . $facture_static->getNomUrl(1) . '</td>';
     
     		print '<td align="center">' . dol_print_date($db->jdate($objp->datef), 'day') . '</td>';
     
    @@ -370,9 +385,10 @@ if ($result) {
     		print '</td>';
     
     		print '<td align="right">' . price($objp->total_ht) . '</td>';
    +
     		print '<td align="right">' . vatrate($objp->tva_tx.($objp->vat_src_code?' ('.$objp->vat_src_code.')':'')) . '</td>';
     
    -		print '<td>' . $objp->country .'</td>';
    +		print '<td>' . $langs->trans("Country".$objp->country_code) .' ('.$objp->country_code.')</td>';
     
     		print '<td>' . $objp->tva_intra . '</td>';
     
    diff --git a/htdocs/accountancy/customer/list.php b/htdocs/accountancy/customer/list.php
    index b5fec4a0e7c..74944b8f823 100644
    --- a/htdocs/accountancy/customer/list.php
    +++ b/htdocs/accountancy/customer/list.php
    @@ -34,6 +34,7 @@ require_once DOL_DOCUMENT_ROOT . '/accountancy/class/accountingaccount.class.php
     require_once DOL_DOCUMENT_ROOT . '/core/lib/accounting.lib.php';
     require_once DOL_DOCUMENT_ROOT . '/core/class/html.formother.class.php';
     require_once DOL_DOCUMENT_ROOT . '/core/lib/date.lib.php';
    +require_once DOL_DOCUMENT_ROOT . '/core/lib/company.lib.php';
     
     // Load translation files required by the page
     $langs->loadLangs(array("bills","compta","accountancy","other","productbatch"));
    @@ -212,7 +213,8 @@ $sql = "SELECT f.rowid as facid, f.facnumber as ref, f.datef, f.type as ftype,";
     $sql.= " l.rowid, l.fk_product, l.description, l.total_ht, l.fk_code_ventilation, l.product_type as type_l, l.tva_tx as tva_tx_line, l.vat_src_code,";
     $sql.= " p.rowid as product_id, p.ref as product_ref, p.label as product_label, p.fk_product_type as type, p.accountancy_code_sell as code_sell, p.tva_tx as tva_tx_prod,";
     $sql.= " aa.rowid as aarowid,";
    -$sql.= " co.label as country, s.tva_intra";
    +$sql.= " co.code as country_code, co.label as country,";
    +$sql.= " s.tva_intra";
     $parameters=array();
     $reshook=$hookmanager->executeHooks('printFieldListSelect',$parameters);    // Note that $action and $object may have been modified by hook
     $sql.=$hookmanager->resPrint;
    @@ -265,7 +267,18 @@ else if ($search_year > 0)
     	$sql.= " AND f.datef BETWEEN '".$db->idate(dol_get_first_day($search_year,1,false))."' AND '".$db->idate(dol_get_last_day($search_year,12,false))."'";
     }
     if (strlen(trim($search_country))) {
    -	$sql .= natural_search("co.label", $search_country);
    +	$arrayofcode = getCountriesInEEC();
    +	$country_code_in_EEC = $country_code_in_EEC_without_me = '';
    +	foreach ($arrayofcode as $key => $value)
    +	{
    +		$country_code_in_EEC.=($country_code_in_EEC ? "," : "")."'".$value."'";
    +		if ($value != $mysoc->country_code) $country_code_in_EEC_without_me.=($country_code_in_EEC_without_me ? "," : "")."'".$value."'";
    +	}
    +	if ($search_country == 'special_allnotme')     $sql .= " AND co.code <> '".$db->escape($mysoc->country_code)."'";
    +	elseif ($search_country == 'special_eec')      $sql .= " AND co.code IN (".$country_code_in_EEC.")";
    +	elseif ($search_country == 'special_eecnotme') $sql .= " AND co.code IN (".$country_code_in_EEC_without_me.")";
    +	elseif ($search_country == 'special_noteec')   $sql .= " AND co.code NOT IN (".$country_code_in_EEC.")";
    +	else $sql .= natural_search(array("co.code","co.label"), $search_country);
     }
     if (strlen(trim($search_tvaintra))) {
     	$sql .= natural_search("s.tva_intra", $search_tvaintra);
    @@ -371,7 +384,10 @@ if ($result) {
     	print '<td class="liste_titre"><input type="text" class="flat maxwidthonsmartphone" name="search_desc" value="' . dol_escape_htmltag($search_desc) . '"></td>';
     	print '<td class="liste_titre" align="right"><input type="text" class="flat maxwidth50 right" name="search_amount" value="' . dol_escape_htmltag($search_amount) . '"></td>';
     	print '<td class="liste_titre" align="right"><input type="text" class="flat maxwidth50 right" name="search_vat" placeholder="%" size="1" value="' . dol_escape_htmltag($search_vat) . '"></td>';
    -	print '<td class="liste_titre"><input type="text" class="flat maxwidth50" name="search_country" value="' . dol_escape_htmltag($search_country) . '"></td>';
    +	print '<td class="liste_titre">';
    +	print $form->select_country($search_country, 'search_country', '', 0, 'maxwidth200', 'code2', 1, 0, 1);
    +	//print '<input type="text" class="flat maxwidth50" name="search_country" value="' . dol_escape_htmltag($search_country) . '">';
    +	print '</td>';
     	print '<td class="liste_titre"><input type="text" class="flat maxwidth50" name="search_tvaintra" value="' . dol_escape_htmltag($search_tvaintra) . '"></td>';
     	print '<td class="liste_titre"></td>';
     	print '<td class="liste_titre"></td>';
    @@ -450,7 +466,7 @@ if ($result) {
     		print '<td>' . $objp->rowid . '</td>';
     
     		// Ref Invoice
    -		print '<td>' . $facture_static->getNomUrl(1) . '</td>';
    +		print '<td class="nowraponall">' . $facture_static->getNomUrl(1) . '</td>';
     
     		print '<td align="center">' . dol_print_date($db->jdate($objp->datef), 'day') . '</td>';
     
    diff --git a/htdocs/accountancy/expensereport/lines.php b/htdocs/accountancy/expensereport/lines.php
    index ae368a20de1..b328cf73455 100644
    --- a/htdocs/accountancy/expensereport/lines.php
    +++ b/htdocs/accountancy/expensereport/lines.php
    @@ -236,8 +236,6 @@ if ($result) {
     	if ($search_day)        $param .= '&search_day='.urlencode($search_day);
     	if ($search_month)      $param .= '&search_month='.urlencode($search_month);
     	if ($search_year)       $param .= '&search_year='.urlencode($search_year);
    -	if ($search_country)	$param .= "&search_country=" . urlencode($search_country);
    -	if ($search_tvaintra)	$param .= "&search_tvaintra=" . urlencode($search_tvaintra);
     
     	print '<form action="' . $_SERVER["PHP_SELF"] . '" method="post">' . "\n";
     	print '<input type="hidden" name="action" value="ventil">';
    diff --git a/htdocs/accountancy/index.php b/htdocs/accountancy/index.php
    index ac674eb95e0..2d34ec816e3 100644
    --- a/htdocs/accountancy/index.php
    +++ b/htdocs/accountancy/index.php
    @@ -61,13 +61,13 @@ if ($conf->accounting->enabled)
     
     	// STEPS
     	$step++;
    -	print img_picto('', 'puce').' '.$langs->trans("AccountancyAreaDescJournalSetup", $step, '<strong>'.$langs->transnoentitiesnoconv("MenuAccountancy").'-'.$langs->transnoentitiesnoconv("Setup")."-".$langs->transnoentitiesnoconv("AccountingJournals").'</strong>');
    +	print img_picto('', 'puce').' '.$langs->trans("AccountancyAreaDescJournalSetup", $step, '<a href="'.DOL_URL_ROOT.'/accountancy/admin/journals_list.php?id=35">'.'<strong>'.$langs->transnoentitiesnoconv("MenuAccountancy").'-'.$langs->transnoentitiesnoconv("Setup")."-".$langs->transnoentitiesnoconv("AccountingJournals").'</strong>'.'</a>');
     	print "<br>\n";
     	$step++;
    -	print img_picto('', 'puce').' '.$langs->trans("AccountancyAreaDescChartModel", $step, '<strong>'.$langs->transnoentitiesnoconv("MenuAccountancy").'-'.$langs->transnoentitiesnoconv("Setup")."-".$langs->transnoentitiesnoconv("Pcg_version").'</strong>');
    +	print img_picto('', 'puce').' '.$langs->trans("AccountancyAreaDescChartModel", $step, '<a href="'.DOL_URL_ROOT.'/accountancy/admin/accountmodel.php">'.'<strong>'.$langs->transnoentitiesnoconv("MenuAccountancy").'-'.$langs->transnoentitiesnoconv("Setup")."-".$langs->transnoentitiesnoconv("Pcg_version").'</strong>'.'</a>');
     	print "<br>\n";
     	$step++;
    -	print img_picto('', 'puce').' '.$langs->trans("AccountancyAreaDescChart", $step, '<strong>'.$langs->transnoentitiesnoconv("MenuAccountancy").'-'.$langs->transnoentitiesnoconv("Setup")."-".$langs->transnoentitiesnoconv("Chartofaccounts").'</strong>');
    +	print img_picto('', 'puce').' '.$langs->trans("AccountancyAreaDescChart", $step, '<a href="'.DOL_URL_ROOT.'/accountancy/admin/account.php">'.'<strong>'.$langs->transnoentitiesnoconv("MenuAccountancy").'-'.$langs->transnoentitiesnoconv("Setup")."-".$langs->transnoentitiesnoconv("Chartofaccounts").'</strong>'.'</a>');
     	print "<br>\n";
     
     	print "<br>\n";
    @@ -76,20 +76,20 @@ if ($conf->accounting->enabled)
     	print "<br>\n";
     
     	$step++;
    -	print img_picto('', 'puce').' '.$langs->trans("AccountancyAreaDescDefault", $step, '<strong>'.$langs->transnoentitiesnoconv("MenuAccountancy").'-'.$langs->transnoentitiesnoconv("Setup")."-".$langs->transnoentitiesnoconv("MenuDefaultAccounts").'</strong>');
    +	print img_picto('', 'puce').' '.$langs->trans("AccountancyAreaDescDefault", $step, '<a href="'.DOL_URL_ROOT.'/accountancy/admin/defaultaccounts.php">'.'<strong>'.$langs->transnoentitiesnoconv("MenuAccountancy").'-'.$langs->transnoentitiesnoconv("Setup")."-".$langs->transnoentitiesnoconv("MenuDefaultAccounts").'</strong>'.'</a>');
     	print "<br>\n";
     
     	$step++;
    -	print img_picto('', 'puce').' '.$langs->trans("AccountancyAreaDescBank", $step, '<strong>'.$langs->transnoentitiesnoconv("MenuAccountancy").'-'.$langs->transnoentitiesnoconv("Setup")."-".$langs->transnoentitiesnoconv("MenuBankAccounts").'</strong>')."\n";
    +	print img_picto('', 'puce').' '.$langs->trans("AccountancyAreaDescBank", $step, '<a href="'.DOL_URL_ROOT.'/compta/bank/list.php">'.'<strong>'.$langs->transnoentitiesnoconv("MenuAccountancy").'-'.$langs->transnoentitiesnoconv("Setup")."-".$langs->transnoentitiesnoconv("MenuBankAccounts").'</strong>'.'</a>')."\n";
     	print "<br>\n";
     
     	$step++;
    -	$textlink = '<strong>'.$langs->transnoentitiesnoconv("MenuAccountancy").'-'.$langs->transnoentitiesnoconv("Setup").'-'.$langs->transnoentitiesnoconv("MenuVatAccounts").'</strong>';
    +	$textlink = '<a href="'.DOL_URL_ROOT.'/admin/dict.php?id=10&from=accountancy">'.'<strong>'.$langs->transnoentitiesnoconv("MenuAccountancy").'-'.$langs->transnoentitiesnoconv("Setup").'-'.$langs->transnoentitiesnoconv("MenuVatAccounts").'</strong>'.'</a>';
     	print img_picto('', 'puce').' '.$langs->trans("AccountancyAreaDescVat", $step, $textlink);
     	print "<br>\n";
     	if (! empty($conf->tax->enabled))
     	{
    -	    $textlink = '<strong>'.$langs->transnoentitiesnoconv("MenuAccountancy").'-'.$langs->transnoentitiesnoconv("Setup").'-'.$langs->transnoentitiesnoconv("MenuTaxAccounts").'</strong>';
    +	     $textlink = '<a href="'.DOL_URL_ROOT.'/admin/dict.php?id=7&from=accountancy">'.'<strong>'.$langs->transnoentitiesnoconv("MenuAccountancy").'-'.$langs->transnoentitiesnoconv("Setup").'-'.$langs->transnoentitiesnoconv("MenuTaxAccounts").'</strong>'.'</a>';
     	    $step++;
     	    print img_picto('', 'puce').' '.$langs->trans("AccountancyAreaDescContrib", $step, $textlink);
     	    print "<br>\n";
    @@ -105,7 +105,7 @@ if ($conf->accounting->enabled)
     	if (! empty($conf->expensereport->enabled))  // TODO Move this in the default account page because this is only one accounting account per purpose, not several.
     	{
     	    $step++;
    -	    print img_picto('', 'puce').' '.$langs->trans("AccountancyAreaDescExpenseReport", $step, '<strong>'.$langs->transnoentitiesnoconv("MenuAccountancy").'-'.$langs->transnoentitiesnoconv("Setup")."-".$langs->transnoentitiesnoconv("MenuExpenseReportAccounts").'</strong>');
    +	    print img_picto('', 'puce').' '.$langs->trans("AccountancyAreaDescExpenseReport", $step, '<a href="'.DOL_URL_ROOT.'/admin/dict.php?id=17&from=accountancy">'.'<strong>'.$langs->transnoentitiesnoconv("MenuAccountancy").'-'.$langs->transnoentitiesnoconv("Setup")."-".$langs->transnoentitiesnoconv("MenuExpenseReportAccounts").'</strong>'.'</a>');
     	    print "<br>\n";
     	}
     	/*
    @@ -123,7 +123,7 @@ if ($conf->accounting->enabled)
     	}*/
     
     	$step++;
    -	print img_picto('', 'puce').' '.$langs->trans("AccountancyAreaDescProd", $step, '<strong>'.$langs->transnoentitiesnoconv("MenuAccountancy").'-'.$langs->transnoentitiesnoconv("Setup")."-".$langs->transnoentitiesnoconv("ProductsBinding").'</strong>');
    +	print img_picto('', 'puce').' '.$langs->trans("AccountancyAreaDescProd", $step, '<a href="'.DOL_URL_ROOT.'/accountancy/admin/productaccount.php">'.'<strong>'.$langs->transnoentitiesnoconv("MenuAccountancy").'-'.$langs->transnoentitiesnoconv("Setup")."-".$langs->transnoentitiesnoconv("ProductsBinding").'</strong>'.'</a>');
     	print "<br>\n";
     
     
    @@ -139,16 +139,19 @@ if ($conf->accounting->enabled)
     	$langs->loadLangs(array('bills', 'trips'));
     
     	$step++;
    -	print img_picto('', 'puce').' '.$langs->trans("AccountancyAreaDescBind", chr(64+$step), $langs->transnoentitiesnoconv("BillsCustomers"), '<strong>'.$langs->transnoentitiesnoconv("MenuAccountancy")."-".$langs->transnoentitiesnoconv("CustomersVentilation").'</strong>')."\n";
    +	print img_picto('', 'puce').' '.$langs->trans("AccountancyAreaDescBind", chr(64+$step), $langs->transnoentitiesnoconv("BillsCustomers"), '<a href="'.DOL_URL_ROOT.'/accountancy/customer/index.php">'.'<strong>'.$langs->transnoentitiesnoconv("MenuAccountancy")."-".$langs->transnoentitiesnoconv("CustomersVentilation").'</strong>'.'</a>')."\n";
     	print "<br>\n";
     
     	$step++;
    -	print img_picto('', 'puce').' '.$langs->trans("AccountancyAreaDescBind", chr(64+$step), $langs->transnoentitiesnoconv("BillsSuppliers"), '<strong>'.$langs->transnoentitiesnoconv("MenuAccountancy")."-".$langs->transnoentitiesnoconv("SuppliersVentilation").'</strong>')."\n";
    +	print img_picto('', 'puce').' '.$langs->trans("AccountancyAreaDescBind", chr(64+$step), $langs->transnoentitiesnoconv("BillsSuppliers"), '<a href="'.DOL_URL_ROOT.'/accountancy/supplier/index.php">'.'<strong>'.$langs->transnoentitiesnoconv("MenuAccountancy")."-".$langs->transnoentitiesnoconv("SuppliersVentilation").'</strong>'.'</a>')."\n";
     	print "<br>\n";
     
    -	$step++;
    -	print img_picto('', 'puce').' '.$langs->trans("AccountancyAreaDescBind", chr(64+$step), $langs->transnoentitiesnoconv("ExpenseReports"), '<strong>'.$langs->transnoentitiesnoconv("MenuAccountancy")."-".$langs->transnoentitiesnoconv("ExpenseReportsVentilation").'</strong>')."\n";
    -	print "<br>\n";
    +	if (! empty($conf->expensereport->enabled) || ! empty($conf->deplacement->enabled))
    +	{
    +		$step++;
    +		print img_picto('', 'puce').' '.$langs->trans("AccountancyAreaDescBind", chr(64+$step), $langs->transnoentitiesnoconv("ExpenseReports"), '<a href="'.DOL_URL_ROOT.'/accountancy/expensereport/index.php">'.'<strong>'.$langs->transnoentitiesnoconv("MenuAccountancy")."-".$langs->transnoentitiesnoconv("ExpenseReportsVentilation").'</strong>'.'</a>')."\n";
    +	    print "<br>\n";
    +	}
     
     	$step++;
     	print img_picto('', 'puce').' '.$langs->trans("AccountancyAreaDescWriteRecords", chr(64+$step), $langs->transnoentitiesnoconv("Journalization"), $langs->transnoentitiesnoconv("WriteBookKeeping"))."\n";
    diff --git a/htdocs/accountancy/journal/bankjournal.php b/htdocs/accountancy/journal/bankjournal.php
    index 7cd98743480..3b86835e927 100644
    --- a/htdocs/accountancy/journal/bankjournal.php
    +++ b/htdocs/accountancy/journal/bankjournal.php
    @@ -1,12 +1,12 @@
     <?php
    -/* Copyright (C) 2007-2010  Laurent Destailleur <eldy@users.sourceforge.net>
    - * Copyright (C) 2007-2010  Jean Heimburger     <jean@tiaris.info>
    - * Copyright (C) 2011       Juanjo Menent       <jmenent@2byte.es>
    - * Copyright (C) 2012       Regis Houssin       <regis.houssin@capnetworks.com>
    - * Copyright (C) 2013       Christophe Battarel <christophe.battarel@altairis.fr>
    - * Copyright (C) 2013-2018  Alexandre Spangaro  <aspangaro@zendsi.com>
    - * Copyright (C) 2013-2014  Florian Henry       <florian.henry@open-concept.pro>
    - * Copyright (C) 2013-2014  Olivier Geffroy     <jeff@jeffinfo.com>
    +/* Copyright (C) 2007-2010  Laurent Destailleur     <eldy@users.sourceforge.net>
    + * Copyright (C) 2007-2010  Jean Heimburger         <jean@tiaris.info>
    + * Copyright (C) 2011       Juanjo Menent           <jmenent@2byte.es>
    + * Copyright (C) 2012       Regis Houssin           <regis.houssin@capnetworks.com>
    + * Copyright (C) 2013       Christophe Battarel     <christophe.battarel@altairis.fr>
    + * Copyright (C) 2013-2018  Alexandre Spangaro      <aspangaro@zendsi.com>
    + * Copyright (C) 2013-2014  Florian Henry           <florian.henry@open-concept.pro>
    + * Copyright (C) 2013-2014  Olivier Geffroy         <jeff@jeffinfo.com>
      * Copyright (C) 2017-2018  Frédéric France         <frederic.france@netlogic.fr>
      *
      * This program is free software; you can redistribute it and/or modify
    @@ -33,6 +33,7 @@ require_once DOL_DOCUMENT_ROOT . '/core/lib/report.lib.php';
     require_once DOL_DOCUMENT_ROOT . '/core/lib/date.lib.php';
     require_once DOL_DOCUMENT_ROOT . '/core/lib/bank.lib.php';
     require_once DOL_DOCUMENT_ROOT . '/core/lib/accounting.lib.php';
    +require_once DOL_DOCUMENT_ROOT . '/accountancy/class/accountingaccount.class.php';
     require_once DOL_DOCUMENT_ROOT . '/accountancy/class/accountingjournal.class.php';
     require_once DOL_DOCUMENT_ROOT . '/societe/class/societe.class.php';
     require_once DOL_DOCUMENT_ROOT . '/user/class/user.class.php';
    @@ -149,12 +150,15 @@ $paymentvariousstatic = new PaymentVarious($db);
     $paymentloanstatic = new PaymentLoan($db);
     $accountLinestatic=new AccountLine($db);
     
    +$accountingaccount = new AccountingAccount($db);
    +
     // Get code of finance journal
     $accountingjournalstatic = new AccountingJournal($db);
     $accountingjournalstatic->fetch($id_journal);
     $journal = $accountingjournalstatic->code;
     $journal_label = $accountingjournalstatic->label;
     
    +
     dol_syslog("accountancy/journal/bankjournal.php", LOG_DEBUG);
     $result = $db->query($sql);
     if ($result) {
    @@ -371,7 +375,7 @@ if ($result) {
     					$tabpay[$obj->rowid]["paymentloanid"] = $paymentloanstatic->id;
     					//$tabtp[$obj->rowid][$account_pay_loan] += $obj->amount;
     				} else if ($links[$key]['type'] == 'banktransfert') {
    -                                        $accountLinestatic->fetch($links[$key]['url_id']);
    +					$accountLinestatic->fetch($links[$key]['url_id']);
     					$tabpay[$obj->rowid]["lib"] .= ' '.$langs->trans("BankTransfer").'- ' .$accountLinestatic ->getNomUrl(1);
     					$tabtp[$obj->rowid][$account_transfer] += $obj->amount;
     					$bankaccountstatic->fetch($tabpay[$obj->rowid]['fk_bank_account']);
    @@ -461,7 +465,11 @@ if (! $error && $action == 'writebookkeeping') {
     					$bookkeeping->fk_doc = $key;
     					$bookkeeping->fk_docdet = $val["fk_bank"];
     					$bookkeeping->numero_compte = $k;
    -					$bookkeeping->label_compte = $langs->trans("Bank");
    +
    +					$accountingaccount->fetch(null, $k, true);
    +					$bookkeeping->label_compte = $accountingaccount->label;
    +
    +					$bookkeeping->label_operation = $reflabel;
     					$bookkeeping->montant = $mt;
     					$bookkeeping->sens = ($mt >= 0) ? 'D' : 'C';
     					$bookkeeping->debit = ($mt >= 0 ? $mt : 0);
    @@ -517,6 +525,7 @@ if (! $error && $action == 'writebookkeeping') {
     						$bookkeeping->doc_type = 'bank';
     						$bookkeeping->fk_doc = $key;
     						$bookkeeping->fk_docdet = $val["fk_bank"];
    +						$bookkeeping->label_operation = $reflabel;
     						$bookkeeping->montant = $mt;
     						$bookkeeping->sens = ($mt < 0) ? 'D' : 'C';
     						$bookkeeping->debit = ($mt < 0 ? - $mt : 0);
    @@ -530,22 +539,30 @@ if (! $error && $action == 'writebookkeeping') {
     							$bookkeeping->subledger_account = $tabcompany[$key]['code_compta'];
     							$bookkeeping->subledger_label = $tabcompany[$key]['name'];
     							$bookkeeping->numero_compte = $conf->global->ACCOUNTING_ACCOUNT_CUSTOMER;
    -							$bookkeeping->label_compte = '';
    +
    +							$accountingaccount->fetch(null, $conf->global->ACCOUNTING_ACCOUNT_CUSTOMER, true);
    +							$bookkeeping->label_compte = $accountingaccount->label;
     						} else if ($tabtype[$key] == 'payment_supplier') {		   // If payment is payment of supplier invoice, we get ref of invoice
     							$bookkeeping->subledger_account = $tabcompany[$key]['code_compta'];
     							$bookkeeping->subledger_label = $tabcompany[$key]['name'];
     							$bookkeeping->numero_compte = $conf->global->ACCOUNTING_ACCOUNT_SUPPLIER;
    -							$bookkeeping->label_compte = '';
    +
    +							$accountingaccount->fetch(null, $conf->global->ACCOUNTING_ACCOUNT_SUPPLIER, true);
    +							$bookkeeping->label_compte = $accountingaccount->label;
     						} else if ($tabtype[$key] == 'payment_expensereport') {
     							$bookkeeping->subledger_account = $tabuser[$key]['accountancy_code'];
     							$bookkeeping->subledger_label = $tabuser[$key]['name'];
     							$bookkeeping->numero_compte = $conf->global->SALARIES_ACCOUNTING_ACCOUNT_PAYMENT;
    -							$bookkeeping->label_compte = '';
    +
    +							$accountingaccount->fetch(null, $conf->global->SALARIES_ACCOUNTING_ACCOUNT_PAYMENT, true);
    +							$bookkeeping->label_compte = $accountingaccount->label;
     						} else if ($tabtype[$key] == 'payment_salary') {
     							$bookkeeping->subledger_account = $tabuser[$key]['accountancy_code'];
     							$bookkeeping->subledger_label = $tabuser[$key]['name'];
     							$bookkeeping->numero_compte = $conf->global->SALARIES_ACCOUNTING_ACCOUNT_PAYMENT;
    -							$bookkeeping->label_compte = '';
    +
    +							$accountingaccount->fetch(null, $conf->global->SALARIES_ACCOUNTING_ACCOUNT_PAYMENT, true);
    +							$bookkeeping->label_compte = $accountingaccount->label;
     						} else if (in_array($tabtype[$key], array('sc', 'payment_sc'))) {   // If payment is payment of social contribution
     							$bookkeeping->subledger_account = '';
     							$bookkeeping->subledger_label = '';
    @@ -555,27 +572,37 @@ if (! $error && $action == 'writebookkeeping') {
     							$bookkeeping->subledger_account = '';
     							$bookkeeping->subledger_label = '';
     							$bookkeeping->numero_compte = $k;
    -							$bookkeeping->label_compte = '';
    +
    +							$accountingaccount->fetch($k, null, true);
    +							$bookkeeping->label_compte = $accountingaccount->label;
     						} else if ($tabtype[$key] == 'payment_donation') {
     							$bookkeeping->subledger_account = '';
     							$bookkeeping->subledger_label = '';
     							$bookkeeping->numero_compte = $k;
    -							$bookkeeping->label_compte = '';
    +
    +							$accountingaccount->fetch($k, null, true);
    +							$bookkeeping->label_compte = $accountingaccount->label;
     						} else if ($tabtype[$key] == 'payment_loan') {
     							$bookkeeping->subledger_account = '';
     							$bookkeeping->subledger_label = '';
     							$bookkeeping->numero_compte = $k;
    -							$bookkeeping->label_compte = '';
    +
    +							$accountingaccount->fetch($k, null, true);
    +							$bookkeeping->label_compte = $accountingaccount->label;
     						} else if ($tabtype[$key] == 'payment_various') {
     							$bookkeeping->subledger_account = '';
     							$bookkeeping->subledger_label = '';
     							$bookkeeping->numero_compte = $k;
    -							$bookkeeping->label_compte = '';
    +
    +							$accountingaccount->fetch($k, null, true);
    +							$bookkeeping->label_compte = $accountingaccount->label;
     						} else if ($tabtype[$key] == 'banktransfert') {
     							$bookkeeping->subledger_account = '';
     							$bookkeeping->subledger_label = '';
     							$bookkeeping->numero_compte = $k;
    -							$bookkeeping->label_compte = '';
    +
    +							$accountingaccount->fetch($k, null, true);
    +							$bookkeeping->label_compte = $accountingaccount->label;
     						} else {
     							if ($tabtype[$key] == 'unknown')	// Unknown transaction, we will use a waiting account for thirdparty.
     							{
    @@ -583,7 +610,9 @@ if (! $error && $action == 'writebookkeeping') {
     								$bookkeeping->subledger_account = '';
     								$bookkeeping->subledger_label = '';
     								$bookkeeping->numero_compte = $conf->global->ACCOUNTING_ACCOUNT_SUSPENSE;
    -								$bookkeeping->label_compte = '';
    +
    +								$accountingaccount->fetch(null, $conf->global->ACCOUNTING_ACCOUNT_SUSPENSE, true);
    +								$bookkeeping->label_compte = $accountingaccount->label;
     							}
     						}
     						$bookkeeping->label_operation = $reflabel;
    diff --git a/htdocs/accountancy/journal/expensereportsjournal.php b/htdocs/accountancy/journal/expensereportsjournal.php
    index c39a750af1a..9c39016f008 100644
    --- a/htdocs/accountancy/journal/expensereportsjournal.php
    +++ b/htdocs/accountancy/journal/expensereportsjournal.php
    @@ -1,11 +1,11 @@
     <?php
    -/* Copyright (C) 2007-2010  Laurent Destailleur	<eldy@users.sourceforge.net>
    - * Copyright (C) 2007-2010  Jean Heimburger		<jean@tiaris.info>
    - * Copyright (C) 2011       Juanjo Menent		<jmenent@2byte.es>
    - * Copyright (C) 2012       Regis Houssin		<regis.houssin@capnetworks.com>
    - * Copyright (C) 2013-2017  Alexandre Spangaro	<aspangaro@zendsi.com>
    - * Copyright (C) 2013-2016  Olivier Geffroy		<jeff@jeffinfo.com>
    - * Copyright (C) 2013-2016  Florian Henry		<florian.henry@open-concept.pro>
    +/* Copyright (C) 2007-2010  Laurent Destailleur     <eldy@users.sourceforge.net>
    + * Copyright (C) 2007-2010  Jean Heimburger         <jean@tiaris.info>
    + * Copyright (C) 2011       Juanjo Menent           <jmenent@2byte.es>
    + * Copyright (C) 2012       Regis Houssin           <regis.houssin@capnetworks.com>
    + * Copyright (C) 2013-2018  Alexandre Spangaro      <aspangaro@zendsi.com>
    + * Copyright (C) 2013-2016  Olivier Geffroy         <jeff@jeffinfo.com>
    + * Copyright (C) 2013-2016  Florian Henry           <florian.henry@open-concept.pro>
      * Copyright (C) 2018       Frédéric France         <frederic.france@netlogic.fr>
      *
      * This program is free software; you can redistribute it and/or modify
    @@ -61,6 +61,7 @@ if ($user->societe_id > 0)
     /*
      * Actions
      */
    +$accountingaccount = new AccountingAccount($db);
     
     // Get informations of journal
     $accountingjournalstatic = new AccountingJournal($db);
    @@ -208,8 +209,12 @@ if ($action == 'writebookkeeping') {
     					$bookkeeping->fk_doc = $key;
     					$bookkeeping->fk_docdet = $val["fk_expensereportdet"];
     					$bookkeeping->subledger_account = $tabuser[$key]['user_accountancy_code'];
    -					$bookkeeping->subledger_label = $tabuser[$key]['user_accountancy_code'];
    +					$bookkeeping->subledger_label = $tabuser[$key]['name'];
     					$bookkeeping->numero_compte = $conf->global->SALARIES_ACCOUNTING_ACCOUNT_PAYMENT;
    +
    +					$accountingaccount->fetch(null, $conf->global->SALARIES_ACCOUNTING_ACCOUNT_PAYMENT, true);
    +					$bookkeeping->label_compte = $accountingaccount->label;
    +
     					$bookkeeping->label_operation = $tabuser[$key]['name'];
     					$bookkeeping->montant = $mt;
     					$bookkeeping->sens = ($mt >= 0) ? 'C' : 'D';
    @@ -248,7 +253,6 @@ if ($action == 'writebookkeeping') {
     			foreach ( $tabht[$key] as $k => $mt ) {
     				if ($mt) {
     					// get compte id and label
    -					$accountingaccount = new AccountingAccount($db);
     					if ($accountingaccount->fetch(null, $k, true)) {
     						$bookkeeping = new BookKeeping($db);
     						$bookkeeping->doc_date = $val["date"];
    @@ -260,6 +264,7 @@ if ($action == 'writebookkeeping') {
     						$bookkeeping->subledger_account = '';
     						$bookkeeping->subledger_label = '';
     						$bookkeeping->numero_compte = $k;
    +						$bookkeeping->label_compte = $accountingaccount->label;
     						$bookkeeping->label_operation = $accountingaccount->label;
     						$bookkeeping->montant = $mt;
     						$bookkeeping->sens = ($mt < 0) ? 'C' : 'D';
    @@ -316,6 +321,10 @@ if ($action == 'writebookkeeping') {
     					$bookkeeping->subledger_account = '';
     					$bookkeeping->subledger_label = '';
     					$bookkeeping->numero_compte = $k;
    +
    +					$accountingaccount->fetch($k, null, true);
    +					$bookkeeping->label_compte = $accountingaccount->label;
    +
     					$bookkeeping->label_operation = $langs->trans("VAT"). ' '.join(', ',$def_tva[$key][$k]).' %';
     					$bookkeeping->montant = $mt;
     					$bookkeeping->sens = ($mt < 0) ? 'C' : 'D';
    @@ -400,11 +409,13 @@ if ($action == 'writebookkeeping') {
     		$param.='&date_endmonth='.$date_endmonth;
     		$param.='&date_endyear='.$date_endyear;
     		$param.='&in_bookkeeping='.$in_bookkeeping;
    +
     		header("Location: ".$_SERVER['PHP_SELF'].($param?'?'.$param:''));
     		exit;
     	}
     }
     
    +
     /*
      * View
      */
    diff --git a/htdocs/accountancy/journal/purchasesjournal.php b/htdocs/accountancy/journal/purchasesjournal.php
    index d8be52cef90..beb9891276f 100644
    --- a/htdocs/accountancy/journal/purchasesjournal.php
    +++ b/htdocs/accountancy/journal/purchasesjournal.php
    @@ -1,11 +1,11 @@
     <?php
    -/* Copyright (C) 2007-2010  Laurent Destailleur	<eldy@users.sourceforge.net>
    - * Copyright (C) 2007-2010  Jean Heimburger		<jean@tiaris.info>
    - * Copyright (C) 2011       Juanjo Menent		<jmenent@2byte.es>
    - * Copyright (C) 2012       Regis Houssin		<regis.houssin@capnetworks.com>
    - * Copyright (C) 2013-2017  Alexandre Spangaro	<aspangaro@zendsi.com>
    - * Copyright (C) 2013-2016  Olivier Geffroy		<jeff@jeffinfo.com>
    - * Copyright (C) 2013-2016  Florian Henry		<florian.henry@open-concept.pro>
    +/* Copyright (C) 2007-2010  Laurent Destailleur     <eldy@users.sourceforge.net>
    + * Copyright (C) 2007-2010  Jean Heimburger         <jean@tiaris.info>
    + * Copyright (C) 2011       Juanjo Menent           <jmenent@2byte.es>
    + * Copyright (C) 2012       Regis Houssin           <regis.houssin@capnetworks.com>
    + * Copyright (C) 2013-2017  Alexandre Spangaro      <aspangaro@zendsi.com>
    + * Copyright (C) 2013-2016  Olivier Geffroy         <jeff@jeffinfo.com>
    + * Copyright (C) 2013-2016  Florian Henry           <florian.henry@open-concept.pro>
      * Copyright (C) 2018       Frédéric France         <frederic.france@netlogic.fr>
      *
      * This program is free software; you can redistribute it and/or modify
    @@ -66,10 +66,7 @@ $parameters=array();
      */
     $reshook=$hookmanager->executeHooks('doActions',$parameters,$user,$action);    // Note that $action and $object may have been modified by some hooks
     
    -
    -/*
    - * Views
    - */
    +$accountingaccount = new AccountingAccount($db);
     
     // Get informations of journal
     $accountingjournalstatic = new AccountingJournal($db);
    @@ -310,8 +307,12 @@ if ($action == 'writebookkeeping') {
     					$bookkeeping->fk_docdet = 0;    // Useless, can be several lines that are source of this record to add
     					$bookkeeping->thirdparty_code = $companystatic->code_fournisseur;
     					$bookkeeping->subledger_account = $tabcompany[$key]['code_compta_fournisseur'];
    -					$bookkeeping->subledger_label = '';    // TODO To complete
    +					$bookkeeping->subledger_label = $tabcompany[$key]['name'];
     					$bookkeeping->numero_compte = $conf->global->ACCOUNTING_ACCOUNT_SUPPLIER;
    +
    +					$accountingaccount->fetch(null, $conf->global->ACCOUNTING_ACCOUNT_SUPPLIER, true);
    +					$bookkeeping->label_compte = $accountingaccount->label;
    +
     					$bookkeeping->label_operation = dol_trunc($companystatic->name, 16) . ' - ' . $invoicestatic->ref_supplier . ' - ' . $langs->trans("SubledgerAccount");
     					$bookkeeping->montant = $mt;
     					$bookkeeping->sens = ($mt >= 0) ? 'C' : 'D';
    @@ -352,7 +353,6 @@ if ($action == 'writebookkeeping') {
     			foreach ( $tabht[$key] as $k => $mt ) {
     				//if ($mt) {
     					// get compte id and label
    -					$accountingaccount = new AccountingAccount($db);
     					if ($accountingaccount->fetch(null, $k, true)) {
     						$bookkeeping = new BookKeeping($db);
     						$bookkeeping->doc_date = $val["date"];
    @@ -366,6 +366,7 @@ if ($action == 'writebookkeeping') {
     						$bookkeeping->subledger_account = '';
     						$bookkeeping->subledger_label = '';
     						$bookkeeping->numero_compte = $k;
    +						$bookkeeping->label_compte = $accountingaccount->label;
     						$bookkeeping->label_operation = dol_trunc($companystatic->name, 16) . ' - ' . $invoicestatic->ref_supplier . ' - ' . $accountingaccount->label;
     						$bookkeeping->montant = $mt;
     						$bookkeeping->sens = ($mt < 0) ? 'C' : 'D';
    @@ -426,6 +427,10 @@ if ($action == 'writebookkeeping') {
     						$bookkeeping->subledger_account = '';
     						$bookkeeping->subledger_label = '';
     						$bookkeeping->numero_compte = $k;
    +
    +						$accountingaccount->fetch($k, null, true);
    +						$bookkeeping->label_compte = $accountingaccount->label;
    +
     						$bookkeeping->label_operation = dol_trunc($companystatic->name, 16) . ' - ' . $invoicestatic->ref_supplier . ' - ' . $langs->trans("VAT").' '.join(', ',$def_tva[$key][$k]) .' %' . ($numtax?' - Localtax '.$numtax:'');
     						$bookkeeping->montant = $mt;
     						$bookkeeping->sens = ($mt < 0) ? 'C' : 'D';
    diff --git a/htdocs/accountancy/journal/sellsjournal.php b/htdocs/accountancy/journal/sellsjournal.php
    index 8e44d1a2c10..10cb339c2d6 100644
    --- a/htdocs/accountancy/journal/sellsjournal.php
    +++ b/htdocs/accountancy/journal/sellsjournal.php
    @@ -1,13 +1,13 @@
     <?php
    -/* Copyright (C) 2007-2010  Laurent Destailleur		<eldy@users.sourceforge.net>
    - * Copyright (C) 2007-2010  Jean Heimburger			<jean@tiaris.info>
    - * Copyright (C) 2011       Juanjo Menent			<jmenent@2byte.es>
    - * Copyright (C) 2012       Regis Houssin			<regis.houssin@capnetworks.com>
    - * Copyright (C) 2013       Christophe Battarel		<christophe.battarel@altairis.fr>
    - * Copyright (C) 2013-2017  Alexandre Spangaro		<aspangaro@zendsi.com>
    - * Copyright (C) 2013-2016  Florian Henry			<florian.henry@open-concept.pro>
    - * Copyright (C) 2013-2016  Olivier Geffroy			<jeff@jeffinfo.com>
    - * Copyright (C) 2014       Raphaël Doursenaud		<rdoursenaud@gpcsolutions.fr>
    +/* Copyright (C) 2007-2010  Laurent Destailleur     <eldy@users.sourceforge.net>
    + * Copyright (C) 2007-2010  Jean Heimburger         <jean@tiaris.info>
    + * Copyright (C) 2011       Juanjo Menent           <jmenent@2byte.es>
    + * Copyright (C) 2012       Regis Houssin           <regis.houssin@capnetworks.com>
    + * Copyright (C) 2013       Christophe Battarel     <christophe.battarel@altairis.fr>
    + * Copyright (C) 2013-2018  Alexandre Spangaro      <aspangaro@zendsi.com>
    + * Copyright (C) 2013-2016  Florian Henry           <florian.henry@open-concept.pro>
    + * Copyright (C) 2013-2016  Olivier Geffroy         <jeff@jeffinfo.com>
    + * Copyright (C) 2014       Raphaël Doursenaud      <rdoursenaud@gpcsolutions.fr>
      * Copyright (C) 2018       Frédéric France         <frederic.france@netlogic.fr>
      *
      * This program is free software; you can redistribute it and/or modify
    @@ -61,11 +61,17 @@ $now = dol_now();
     if ($user->societe_id > 0)
     	accessforbidden();
     
    +$hookmanager->initHooks(array('sellsjournal'));
    +$parameters=array();
     
     /*
      * Actions
      */
     
    +$reshook=$hookmanager->executeHooks('doActions',$parameters,$user,$action);    // Note that $action and $object may have been modified by some hooks
    +
    +$accountingaccount = new AccountingAccount($db);
    +
     // Get informations of journal
     $accountingjournalstatic = new AccountingJournal($db);
     $accountingjournalstatic->fetch($id_journal);
    @@ -313,8 +319,12 @@ if ($action == 'writebookkeeping') {
     					$bookkeeping->fk_docdet = 0;	// Useless, can be several lines that are source of this record to add
     					$bookkeeping->thirdparty_code = $companystatic->code_client;
     					$bookkeeping->subledger_account = $tabcompany[$key]['code_compta'];
    -					$bookkeeping->subledger_label = '';    // TODO To complete
    +					$bookkeeping->subledger_label = $tabcompany[$key]['name'];
     					$bookkeeping->numero_compte = $conf->global->ACCOUNTING_ACCOUNT_CUSTOMER;
    +
    +					$accountingaccount->fetch(null, $conf->global->ACCOUNTING_ACCOUNT_CUSTOMER, true);
    +					$bookkeeping->label_compte = $accountingaccount->label;
    +
     					$bookkeeping->label_operation = dol_trunc($companystatic->name, 16) . ' - ' . $invoicestatic->ref . ' - ' . $langs->trans("SubledgerAccount");
     					$bookkeeping->montant = $mt;
     					$bookkeeping->sens = ($mt >= 0) ? 'D' : 'C';
    @@ -355,7 +365,6 @@ if ($action == 'writebookkeeping') {
     			foreach ( $tabht[$key] as $k => $mt ) {
     				//if ($mt) {
     					// get compte id and label
    -					$accountingaccount = new AccountingAccount($db);
     					if ($accountingaccount->fetch(null, $k, true)) {
     						$bookkeeping = new BookKeeping($db);
     						$bookkeeping->doc_date = $val["date"];
    @@ -369,6 +378,7 @@ if ($action == 'writebookkeeping') {
     						$bookkeeping->subledger_account = '';
     						$bookkeeping->subledger_label = '';
     						$bookkeeping->numero_compte = $k;
    +						$bookkeeping->label_compte = $accountingaccount->label;
     						$bookkeeping->label_operation = dol_trunc($companystatic->name, 16) . ' - ' . $invoicestatic->ref . ' - ' . $accountingaccount->label;
     						$bookkeeping->montant = $mt;
     						$bookkeeping->sens = ($mt < 0) ? 'D' : 'C';
    @@ -428,6 +438,10 @@ if ($action == 'writebookkeeping') {
     						$bookkeeping->subledger_account = '';
     						$bookkeeping->subledger_label = '';
     						$bookkeeping->numero_compte = $k;
    +
    +						$accountingaccount->fetch($k, null, true);
    +						$bookkeeping->label_compte = $accountingaccount->label;
    +
     						$bookkeeping->label_operation = dol_trunc($companystatic->name, 16) . ' - ' . $invoicestatic->ref . ' - ' . $langs->trans("VAT").' '.join(', ',$def_tva[$key][$k]) .' %' . ($numtax?' - Localtax '.$numtax:'');
     						$bookkeeping->montant = $mt;
     						$bookkeeping->sens = ($mt < 0) ? 'D' : 'C';
    diff --git a/htdocs/accountancy/supplier/lines.php b/htdocs/accountancy/supplier/lines.php
    index 326d249f86d..580cf4c407c 100644
    --- a/htdocs/accountancy/supplier/lines.php
    +++ b/htdocs/accountancy/supplier/lines.php
    @@ -34,6 +34,7 @@ require_once DOL_DOCUMENT_ROOT . '/core/lib/date.lib.php';
     require_once DOL_DOCUMENT_ROOT . '/core/lib/accounting.lib.php';
     require_once DOL_DOCUMENT_ROOT . '/core/class/html.formother.class.php';
     require_once DOL_DOCUMENT_ROOT . '/core/lib/date.lib.php';
    +require_once DOL_DOCUMENT_ROOT . '/core/lib/company.lib.php';
     
     // Load translation files required by the page
     $langs->loadLangs(array("compta","bills","other","accountancy","productbatch"));
    @@ -172,7 +173,9 @@ print '<script type="text/javascript">
     $sql = "SELECT f.rowid as facid, f.ref as ref, f.ref_supplier, f.libelle as invoice_label, f.datef, f.fk_soc,";
     $sql.= " l.rowid, l.fk_product, l.product_type as line_type, l.description, l.total_ht , l.qty, l.tva_tx, l.vat_src_code,";
     $sql.= " aa.label, aa.account_number, ";
    -$sql.= " p.rowid as product_id, p.fk_product_type as product_type, p.ref as product_ref, p.label as product_label, p.fk_product_type as type, co.label as country, s.tva_intra";
    +$sql.= " p.rowid as product_id, p.fk_product_type as product_type, p.ref as product_ref, p.label as product_label, p.fk_product_type as type,";
    +$sql.= " co.code as country_code, co.label as country,";
    +$sql.= " s.tva_intra";
     $parameters=array();
     $reshook=$hookmanager->executeHooks('printFieldListSelect',$parameters);    // Note that $action and $object may have been modified by hook
     $sql.=$hookmanager->resPrint;
    @@ -221,7 +224,18 @@ else if ($search_year > 0)
     	$sql.= " AND f.datef BETWEEN '".$db->idate(dol_get_first_day($search_year,1,false))."' AND '".$db->idate(dol_get_last_day($search_year,12,false))."'";
     }
     if (strlen(trim($search_country))) {
    -	$sql .= natural_search("co.label", $search_country);
    +	$arrayofcode = getCountriesInEEC();
    +	$country_code_in_EEC = $country_code_in_EEC_without_me = '';
    +	foreach ($arrayofcode as $key => $value)
    +	{
    +		$country_code_in_EEC.=($country_code_in_EEC ? "," : "")."'".$value."'";
    +		if ($value != $mysoc->country_code) $country_code_in_EEC_without_me.=($country_code_in_EEC_without_me ? "," : "")."'".$value."'";
    +	}
    +	if ($search_country == 'special_allnotme')     $sql .= " AND co.code <> '".$db->escape($mysoc->country_code)."'";
    +	elseif ($search_country == 'special_eec')      $sql .= " AND co.code IN (".$country_code_in_EEC.")";
    +	elseif ($search_country == 'special_eecnotme') $sql .= " AND co.code IN (".$country_code_in_EEC_without_me.")";
    +	elseif ($search_country == 'special_noteec')   $sql .= " AND co.code NOT IN (".$country_code_in_EEC.")";
    +	else $sql .= natural_search(array("co.code","co.label"), $search_country);
     }
     if (strlen(trim($search_tvaintra))) {
     	$sql .= natural_search("s.tva_intra", $search_tvaintra);
    @@ -299,9 +313,9 @@ if ($result) {
     	print '<td class="liste_titre"><input type="text" class="flat maxwidth25" name="search_lineid" value="' . dol_escape_htmltag($search_lineid) . '""></td>';
     	print '<td class="liste_titre"><input type="text" class="flat maxwidth50" name="search_invoice" value="' . dol_escape_htmltag($search_invoice) . '"></td>';
     	print '<td class="liste_titre"></td>';
    -	print '<td class="liste_titre center">';
    -   	if (! empty($conf->global->MAIN_LIST_FILTER_ON_DAY)) print '<input class="flat" type="text" size="1" maxlength="2" name="search_day" value="'.$search_day.'">';
    -   	print '<input class="flat" type="text" size="1" maxlength="2" name="search_month" value="'.$search_month.'">';
    +	print '<td class="liste_titre center nowraponall">';
    +   	if (! empty($conf->global->MAIN_LIST_FILTER_ON_DAY)) print '<input class="flat valignmiddle" type="text" size="1" maxlength="2" name="search_day" value="'.$search_day.'">';
    +   	print '<input class="flat valignmiddle" type="text" size="1" maxlength="2" name="search_month" value="'.$search_month.'">';
        	$formother->select_year($search_year,'search_year',1, 20, 5);
     	print '</td>';
     	print '<td class="liste_titre"><input type="text" class="flat maxwidth50" name="search_ref" value="' . dol_escape_htmltag($search_ref) . '"></td>';
    @@ -309,7 +323,10 @@ if ($result) {
     	print '<td class="liste_titre"><input type="text" class="flat maxwidth50" name="search_desc" value="' . dol_escape_htmltag($search_desc) . '"></td>';
     	print '<td class="liste_titre" align="right"><input type="text" class="right flat maxwidth50" name="search_amount" value="' . dol_escape_htmltag($search_amount) . '"></td>';
     	print '<td class="liste_titre" align="right"><input type="text" class="right flat maxwidth50" name="search_vat" placeholder="%" size="1" value="' . dol_escape_htmltag($search_vat) . '"></td>';
    -	print '<td class="liste_titre"><input type="text" class="flat maxwidth50" name="search_country" value="' . dol_escape_htmltag($search_country) . '"></td>';
    +	print '<td class="liste_titre">';
    +	print $form->select_country($search_country, 'search_country', '', 0, 'maxwidth200', 'code2', 1, 0, 1);
    +	//	print '<input type="text" class="flat maxwidth50" name="search_country" value="' . dol_escape_htmltag($search_country) . '">';
    +	print '</td>';
     	print '<td class="liste_titre"><input type="text" class="flat maxwidth50" name="search_tvaintra" value="' . dol_escape_htmltag($search_tvaintra) . '"></td>';
     	print '<td class="liste_titre" align="center"><input type="text" class="flat maxwidth50" name="search_account" value="' . dol_escape_htmltag($search_account) . '"></td>';
     	print '<td class="liste_titre" align="center">';
    @@ -357,7 +374,7 @@ if ($result) {
     		print '<td>' . $objp->rowid . '</td>';
     
     		// Ref Invoice
    -		print '<td>' . $facturefournisseur_static->getNomUrl(1) . '</td>';
    +		print '<td class="nowraponall">' . $facturefournisseur_static->getNomUrl(1) . '</td>';
     
     		print '<td class="tdoverflowonsmartphone">';
     		print $objp->invoice_label;
    @@ -380,9 +397,11 @@ if ($result) {
     		print '</td>';
     
     		print '<td align="right">' . price($objp->total_ht) . '</td>';
    +
     		print '<td align="right">' . vatrate($objp->tva_tx.($objp->vat_src_code?' ('.$objp->vat_src_code.')':'')) . '</td>';
     
    -		print '<td>' . $objp->country .'</td>';
    +		print '<td>' . $langs->trans("Country".$objp->country_code) .' ('.$objp->country_code.')</td>';
    +
     		print '<td>' . $objp->tva_intra . '</td>';
     
     		print '<td align="center">';
    diff --git a/htdocs/accountancy/supplier/list.php b/htdocs/accountancy/supplier/list.php
    index 18c9fa11a3c..5ac90068ffb 100644
    --- a/htdocs/accountancy/supplier/list.php
    +++ b/htdocs/accountancy/supplier/list.php
    @@ -34,6 +34,7 @@ require_once DOL_DOCUMENT_ROOT . '/accountancy/class/accountingaccount.class.php
     require_once DOL_DOCUMENT_ROOT . '/core/lib/accounting.lib.php';
     require_once DOL_DOCUMENT_ROOT . '/core/class/html.formother.class.php';
     require_once DOL_DOCUMENT_ROOT . '/core/lib/date.lib.php';
    +require_once DOL_DOCUMENT_ROOT . '/core/lib/company.lib.php';
     
     // Load translation files required by the page
     $langs->loadLangs(array("bills","compta","accountancy","other","productbatch"));
    @@ -213,7 +214,8 @@ $sql = "SELECT f.rowid as facid, f.ref, f.ref_supplier, f.libelle as invoice_lab
     $sql.= " l.rowid, l.fk_product, l.description, l.total_ht, l.fk_code_ventilation, l.product_type as type_l, l.tva_tx as tva_tx_line, l.vat_src_code,";
     $sql.= " p.rowid as product_id, p.ref as product_ref, p.label as product_label, p.fk_product_type as type, p.accountancy_code_buy as code_buy, p.tva_tx as tva_tx_prod,";
     $sql.= " aa.rowid as aarowid,";
    -$sql.= " co.label as country, s.tva_intra";
    +$sql.= " co.code as country_code, co.label as country,";
    +$sql.= " s.tva_intra";
     $parameters=array();
     $reshook=$hookmanager->executeHooks('printFieldListSelect',$parameters);    // Note that $action and $object may have been modified by hook
     $sql.=$hookmanager->resPrint;
    @@ -250,9 +252,6 @@ if (strlen(trim($search_account))) {
     if (strlen(trim($search_vat))) {
         $sql .= natural_search("l.tva_tx", price2num($search_vat), 1);
     }
    -if (strlen(trim($search_tvaintra))) {
    -	$sql .= natural_search("s.tva_intra", $search_tvaintra);
    -}
     if ($search_month > 0)
     {
     	if ($search_year > 0 && empty($search_day))
    @@ -267,7 +266,21 @@ else if ($search_year > 0)
     	$sql.= " AND f.datef BETWEEN '".$db->idate(dol_get_first_day($search_year,1,false))."' AND '".$db->idate(dol_get_last_day($search_year,12,false))."'";
     }
     if (strlen(trim($search_country))) {
    -	$sql .= natural_search("co.label", $search_country);
    +	$arrayofcode = getCountriesInEEC();
    +	$country_code_in_EEC = $country_code_in_EEC_without_me = '';
    +	foreach ($arrayofcode as $key => $value)
    +	{
    +		$country_code_in_EEC.=($country_code_in_EEC ? "," : "")."'".$value."'";
    +		if ($value != $mysoc->country_code) $country_code_in_EEC_without_me.=($country_code_in_EEC_without_me ? "," : "")."'".$value."'";
    +	}
    +	if ($search_country == 'special_allnotme')     $sql .= " AND co.code <> '".$db->escape($mysoc->country_code)."'";
    +	elseif ($search_country == 'special_eec')      $sql .= " AND co.code IN (".$country_code_in_EEC.")";
    +	elseif ($search_country == 'special_eecnotme') $sql .= " AND co.code IN (".$country_code_in_EEC_without_me.")";
    +	elseif ($search_country == 'special_noteec')   $sql .= " AND co.code NOT IN (".$country_code_in_EEC.")";
    +	else $sql .= natural_search(array("co.code","co.label"), $search_country);
    +}
    +if (strlen(trim($search_tvaintra))) {
    +	$sql .= natural_search("s.tva_intra", $search_tvaintra);
     }
     if (! empty($conf->global->FACTURE_DEPOSITS_ARE_JUST_PAYMENTS)) {
     	$sql .= " AND f.type IN (" . FactureFournisseur::TYPE_STANDARD . "," . FactureFournisseur::TYPE_REPLACEMENT . "," . FactureFournisseur::TYPE_CREDIT_NOTE . "," . FactureFournisseur::TYPE_SITUATION . ")";
    @@ -372,7 +385,10 @@ if ($result) {
     	print '<td class="liste_titre"><input type="text" class="flat maxwidth50" name="search_desc" value="' . dol_escape_htmltag($search_desc) . '"></td>';
     	print '<td class="liste_titre" align="right"><input type="text" class="right flat maxwidth50" name="search_amount" value="' . dol_escape_htmltag($search_amount) . '"></td>';
     	print '<td class="liste_titre" align="right"><input type="text" class="right flat maxwidth50" name="search_vat" placeholder="%" size="1" value="' . dol_escape_htmltag($search_vat) . '"></td>';
    -	print '<td class="liste_titre"><input type="text" class="flat maxwidth50" name="search_country" value="' . dol_escape_htmltag($search_country) . '"></td>';
    +	print '<td class="liste_titre">';
    +	print $form->select_country($search_country, 'search_country', '', 0, 'maxwidth200', 'code2', 1, 0, 1);
    +	//print '<input type="text" class="flat maxwidth50" name="search_country" value="' . dol_escape_htmltag($search_country) . '">';
    +	print '</td>';
     	print '<td class="liste_titre"><input type="text" class="flat maxwidth50" name="search_tvaintra" value="' . dol_escape_htmltag($search_tvaintra) . '"></td>';
     	print '<td class="liste_titre"></td>';
     	print '<td class="liste_titre"></td>';
    @@ -453,7 +469,7 @@ if ($result) {
     		print '<td>' . $objp->rowid . '</td>';
     
     		// Ref Invoice
    -		print '<td>' . $facturefourn_static->getNomUrl(1) . '</td>';
    +		print '<td class="nowraponall">' . $facturefourn_static->getNomUrl(1) . '</td>';
     
     		print '<td class="tdoverflowonsmartphone">';
     		print $objp->invoice_label;
    diff --git a/htdocs/accountancy/tpl/export_journal.tpl.php b/htdocs/accountancy/tpl/export_journal.tpl.php
    index 773f7a7ff68..d0d902770c0 100644
    --- a/htdocs/accountancy/tpl/export_journal.tpl.php
    +++ b/htdocs/accountancy/tpl/export_journal.tpl.php
    @@ -1,6 +1,6 @@
     <?php
    -/* Copyright (C) 2015  Alexandre Spangaro	<aspangaro@zendsi.com>
    - * Copyright (C) 2016  Charlie Benke		<charlie@patas-monkey.com>
    +/* Copyright (C) 2015-2018  Alexandre Spangaro	<aspangaro@zendsi.com>
    + * Copyright (C) 2016       Charlie Benke		<charlie@patas-monkey.com>
      *
      * This program is free software; you can redistribute it and/or modify
      * it under the terms of the GNU General Public License as published by
    @@ -27,11 +27,40 @@ $code = $conf->global->MAIN_INFO_ACCOUNTANT_CODE;
     $prefix = $conf->global->ACCOUNTING_EXPORT_PREFIX_SPEC;
     $format = $conf->global->ACCOUNTING_EXPORT_FORMAT;
     $nodateexport = $conf->global->ACCOUNTING_EXPORT_NO_DATE_IN_FILENAME;
    +$siren = $conf->global->MAIN_INFO_SIREN;
     
     $date_export = "_" . dol_print_date(dol_now(), '%Y%m%d%H%M%S');
    +$endaccountingperiod = dol_print_date(dol_now(), '%Y%m%d');
     
     header('Content-Type: text/csv');
     
    -$completefilename = ($code?$code . "_":"") . ($prefix?$prefix . "_":"") . $filename . ($nodateexport?"":$date_export) . "." . $format;
    +
    +if ($conf->global->ACCOUNTING_EXPORT_MODELCSV == "11") // Specific filename for FEC model export
    +{
    +
    +	// FEC format is defined here: https://www.legifrance.gouv.fr/affichCodeArticle.do?idArticle=LEGIARTI000027804775&cidTexte=LEGITEXT000006069583&dateTexte=20130802&oldAction=rechCodeArticle
    +	if (empty($search_date_end))
    +	{
    +		// TODO Get the max date into bookeeping table
    +		$search_date_end = dol_now();
    +	}
    +	$datetouseforfilename = $search_date_end;
    +	$tmparray=dol_getdate($datetouseforfilename);
    +	$fiscalmonth=empty($conf->global->SOCIETE_FISCAL_MONTH_START)?1:$conf->global->SOCIETE_FISCAL_MONTH_START;
    +	// Define end of month to use
    +	if ($tmparray['mon'] <= $fiscalmonth) $tmparray['mon']=$fiscalmonth;
    +	else {
    +		$tmparray['mon']  = $fiscalmonth;
    +		$tmparray['year']++;
    +	}
    +
    +	$endaccountingperiod = dol_print_date(dol_get_last_day($tmparray['year'], $tmparray['mon']), 'dayxcard');
    +
    +	$completefilename = $siren . "FEC" . $endaccountingperiod . "." . $format;
    +}
    +else
    +{
    +	$completefilename = ($code?$code . "_":"") . ($prefix?$prefix . "_":"") . $filename . ($nodateexport?"":$date_export) . "." . $format;
    +}
     
     header('Content-Disposition: attachment;filename=' . $completefilename);
    diff --git a/htdocs/adherents/card.php b/htdocs/adherents/card.php
    index bc29c67c244..908a46c91d1 100644
    --- a/htdocs/adherents/card.php
    +++ b/htdocs/adherents/card.php
    @@ -301,6 +301,8 @@ if (empty($reshook))
     			$object->phone_mobile= trim(GETPOST("phone_mobile",'alpha'));
     			$object->email       = preg_replace('/\s+/', '', GETPOST("member_email",'alpha'));
     			$object->skype       = trim(GETPOST("skype",'alpha'));
    +			$object->twitter     = trim(GETPOST("twitter",'alpha'));
    +			$object->facebook    = trim(GETPOST("facebook",'alpha'));
     			$object->birth       = $birthdate;
     
     			$object->typeid      = GETPOST("typeid",'int');
    @@ -443,6 +445,8 @@ if (empty($reshook))
     		$phone_perso=GETPOST("phone_perso",'alpha');
     		$phone_mobile=GETPOST("phone_mobile",'alpha');
     		$skype=GETPOST("member_skype",'alpha');
    +		$twitter=GETPOST("member_twitter",'alpha');
    +		$facebook=GETPOST("member_facebook",'alpha');
     		$email=preg_replace('/\s+/', '', GETPOST("member_email",'alpha'));
     		$login=GETPOST("member_login",'alpha');
     		$pass=GETPOST("password",'alpha');
    @@ -467,7 +471,11 @@ if (empty($reshook))
     		$object->phone       = $phone;
     		$object->phone_perso = $phone_perso;
     		$object->phone_mobile= $phone_mobile;
    +
     		$object->skype       = $skype;
    +		$object->twitter     = $twitter;
    +		$object->facebook    = $facebook;
    +
     		$object->email       = $email;
     		$object->login       = $login;
     		$object->pass        = $pass;
    @@ -980,12 +988,24 @@ else
     		print '<tr><td>'.$langs->trans("PhoneMobile").'</td><td><input type="text" name="phone_mobile" size="20" value="'.(GETPOST('phone_mobile','alpha')?GETPOST('phone_mobile','alpha'):$object->phone_mobile).'"></td></tr>';
     
     	    // Skype
    -	    if (! empty($conf->skype->enabled))
    +	    if (! empty($conf->socialnetworks->enabled))
     	    {
     			print '<tr><td>'.$langs->trans("Skype").'</td><td><input type="text" name="member_skype" size="40" value="'.(GETPOST('member_skype','alpha')?GETPOST('member_skype','alpha'):$object->skype).'"></td></tr>';
     	    }
     
    -		// Birthday
    +	    // Twitter
    +	    if (! empty($conf->socialnetworks->enabled))
    +	    {
    +	    	print '<tr><td>'.$langs->trans("Twitter").'</td><td><input type="text" name="member_twitter" size="40" value="'.(GETPOST('member_twitter','alpha')?GETPOST('member_twitter','alpha'):$object->twitter).'"></td></tr>';
    +	    }
    +
    +	    // Facebook
    +	    if (! empty($conf->socialnetworks->enabled))
    +	    {
    +	    	print '<tr><td>'.$langs->trans("Facebook").'</td><td><input type="text" name="member_facebook" size="40" value="'.(GETPOST('member_facebook','alpha')?GETPOST('member_facebook','alpha'):$object->facebook).'"></td></tr>';
    +	    }
    +
    +	    // Birthday
     		print "<tr><td>".$langs->trans("Birthday")."</td><td>\n";
     		print $form->selectDate(($object->birth ? $object->birth : -1),'birth','','',1,'formsoc');
     		print "</td></tr>\n";
    @@ -1218,12 +1238,24 @@ else
     		print '<tr><td>'.$langs->trans("PhoneMobile").'</td><td><input type="text" name="phone_mobile" size="20" value="'.(isset($_POST["phone_mobile"])?GETPOST("phone_mobile"):$object->phone_mobile).'"></td></tr>';
     
     	    // Skype
    -	    if (! empty($conf->skype->enabled))
    +	    if (! empty($conf->socialnetworks->enabled))
     	    {
    -			    print '<tr><td>'.$langs->trans("Skype").'</td><td><input type="text" name="skype" class="minwidth100" value="'.(isset($_POST["skype"])?GETPOST("skype"):$object->skype).'"></td></tr>';
    +			print '<tr><td>'.$langs->trans("Skype").'</td><td><input type="text" name="skype" class="minwidth100" value="'.(isset($_POST["skype"])?GETPOST("skype"):$object->skype).'"></td></tr>';
     	    }
     
    -		// Birthday
    +	    // Twitter
    +	    if (! empty($conf->socialnetworks->enabled))
    +	    {
    +	    	print '<tr><td>'.$langs->trans("Twitter").'</td><td><input type="text" name="twitter" class="minwidth100" value="'.(isset($_POST["twitter"])?GETPOST("twitter"):$object->twitter).'"></td></tr>';
    +	    }
    +
    +	    // Facebook
    +	    if (! empty($conf->socialnetworks->enabled))
    +	    {
    +	    	print '<tr><td>'.$langs->trans("Facebook").'</td><td><input type="text" name="facebook" class="minwidth100" value="'.(isset($_POST["facebook"])?GETPOST("facebook"):$object->facebook).'"></td></tr>';
    +	    }
    +
    +	    // Birthday
     		print "<tr><td>".$langs->trans("Birthday")."</td><td>\n";
     		print $form->selectDate(($object->birth ? $object->birth : -1),'birth','','',1,'formsoc');
     		print "</td></tr>\n";
    diff --git a/htdocs/adherents/class/adherent.class.php b/htdocs/adherents/class/adherent.class.php
    index 09c5decfc43..317d7697231 100644
    --- a/htdocs/adherents/class/adherent.class.php
    +++ b/htdocs/adherents/class/adherent.class.php
    @@ -7,7 +7,7 @@
      * Copyright (C) 2009-2017	Regis Houssin			<regis.houssin@capnetworks.com>
      * Copyright (C) 2014-2016	Alexandre Spangaro		<aspangaro.dolibarr@gmail.com>
      * Copyright (C) 2015		Marcos García			<marcosgdf@gmail.com>
    - * Copyright (C) 2015		Frederic France			<frederic.france@free.fr>
    + * Copyright (C) 2015-2018  Frédéric France			<frederic.france@netlogic.fr>
      * Copyright (C) 2015		Raphaël Doursenaud		<rdoursenaud@gpcsolutions.fr>
      * Copyright (C) 2016		Juanjo Menent			<jmenent@2byte.es>
      *
    @@ -51,7 +51,11 @@ class Adherent extends CommonObject
     	 */
     	public $table_element='adherent';
     
    -	public $ismultientitymanaged = 1;  // 0=No test on entity, 1=Test with field entity, 2=Test with link by societe
    +	/**
    +	 * 0=No test on entity, 1=Test with field entity, 2=Test with link by societe
    +	 * @var int
    +	 */
    +	public $ismultientitymanaged = 1;
     
     	public $mesgs;
     
    @@ -65,8 +69,17 @@ class Adherent extends CommonObject
     	public $pass_indatabase_crypted;
     
     	public $societe;
    +
    +	/**
    +	 * @var Societe $company {@type Societe}
    +	 */
     	public $company;
    +
    +	/**
    +	 * @var string Address
    +	 */
     	public $address;
    +
     	public $zip;
     	public $town;
     
    @@ -75,11 +88,36 @@ class Adherent extends CommonObject
     	public $state;                 // Label of department
     
     	public $email;
    +
     	public $skype;
    +	public $twitter;
    +	public $facebook;
    +
    +    /**
    +     * @var string Phone number
    +     */
     	public $phone;
    +
    +    /**
    +     * @var string Private Phone number
    +     */
     	public $phone_perso;
    +
    +    /**
    +     * @var string Mobile phone number
    +     */
     	public $phone_mobile;
     
    +    /**
    +     * @var string Fax number
    +     */
    +    public $fax;
    +
    +    /**
    +     * @var string Function
    +     */
    +    public $poste;
    +
     	public $morphy;
     	public $public;
     	public $statut;			// -1:brouillon, 0:resilie, >=1:valide,paye
    @@ -87,8 +125,8 @@ class Adherent extends CommonObject
     
     	public $datec;
     	public $datem;
    -	public $datefin;
     	public $datevalid;
    +
     	public $birth;
     
     	public $note_public;
    @@ -106,6 +144,8 @@ class Adherent extends CommonObject
     	 */
         public $fk_soc;
     
    +	public $datefin;	// From member table
    +
     	// Fields loaded by fetch_subscriptions()
     	public $first_subscription_date;
     	public $first_subscription_amount;
    @@ -453,6 +493,8 @@ class Adherent extends CommonObject
     		$sql.= ", state_id = ".($this->state_id>0?$this->db->escape($this->state_id):"null");
     		$sql.= ", email = '".$this->db->escape($this->email)."'";
     		$sql.= ", skype = '".$this->db->escape($this->skype)."'";
    +		$sql.= ", twitter = '".$this->db->escape($this->twitter)."'";
    +		$sql.= ", facebook = '".$this->db->escape($this->facebook)."'";
     		$sql.= ", phone = ".($this->phone?"'".$this->db->escape($this->phone)."'":"null");
     		$sql.= ", phone_perso = ".($this->phone_perso?"'".$this->db->escape($this->phone_perso)."'":"null");
     		$sql.= ", phone_mobile = ".($this->phone_mobile?"'".$this->db->escape($this->phone_mobile)."'":"null");
    @@ -559,6 +601,8 @@ class Adherent extends CommonObject
     
     						$luser->email=$this->email;
     						$luser->skype=$this->skype;
    +						$luser->twitter=$this->twitter;
    +						$luser->facebook=$this->facebook;
     						$luser->office_phone=$this->phone;
     						$luser->user_mobile=$this->phone_mobile;
     
    @@ -598,6 +642,8 @@ class Adherent extends CommonObject
     						$lthirdparty->town=$this->town;
     						$lthirdparty->email=$this->email;
     						$lthirdparty->skype=$this->skype;
    +						$lthirdparty->twitter=$this->twitter;
    +						$lthirdparty->facebook=$this->facebook;
     						$lthirdparty->phone=$this->phone;
     						$lthirdparty->state_id=$this->state_id;
     						$lthirdparty->country_id=$this->country_id;
    @@ -1085,7 +1131,7 @@ class Adherent extends CommonObject
     
     		$sql = "SELECT d.rowid, d.ref_ext, d.civility as civility_id, d.firstname, d.lastname, d.societe as company, d.fk_soc, d.statut, d.public, d.address, d.zip, d.town, d.note_private,";
     		$sql.= " d.note_public,";
    -		$sql.= " d.email, d.skype, d.phone, d.phone_perso, d.phone_mobile, d.login, d.pass, d.pass_crypted,";
    +		$sql.= " d.email, d.skype, d.twitter, d.facebook, d.phone, d.phone_perso, d.phone_mobile, d.login, d.pass, d.pass_crypted,";
     		$sql.= " d.photo, d.fk_adherent_type, d.morphy, d.entity,";
     		$sql.= " d.datec as datec,";
     		$sql.= " d.tms as datem,";
    @@ -1157,7 +1203,10 @@ class Adherent extends CommonObject
     				$this->phone_perso		= $obj->phone_perso;
     				$this->phone_mobile		= $obj->phone_mobile;
     				$this->email			= $obj->email;
    +
     				$this->skype			= $obj->skype;
    +				$this->twitter			= $obj->twitter;
    +				$this->facebook			= $obj->facebook;
     
     				$this->photo			= $obj->photo;
     				$this->statut			= $obj->statut;
    @@ -1210,11 +1259,9 @@ class Adherent extends CommonObject
     
         // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
     	/**
    -	 *	Fonction qui recupere pour un adherent les parametres
    -	 *				first_subscription_date
    -	 *				first_subscription_amount
    -	 *				last_subscription_date
    -	 *				last_subscription_amount
    +	 *	Function to get member subscriptions data
    +	 *				first_subscription_date, first_subscription_date_start, first_subscription_date_end, first_subscription_amount
    +	 *				last_subscription_date, last_subscription_date_start, last_subscription_date_end, last_subscription_amount
     	 *
     	 *	@return		int			<0 si KO, >0 si OK
     	 */
    @@ -1245,10 +1292,14 @@ class Adherent extends CommonObject
     			{
     				if ($i==0)
     				{
    -					$this->first_subscription_date=$obj->dateh;
    +					$this->first_subscription_date=$this->db->jdate($obj->datec);
    +					$this->first_subscription_date_start=$this->db->jdate($obj->dateh);
    +					$this->first_subscription_date_end=$this->db->jdate($obj->datef);
     					$this->first_subscription_amount=$obj->subscription;
     				}
    -				$this->last_subscription_date=$obj->dateh;
    +				$this->last_subscription_date=$this->db->jdate($obj->datec);
    +				$this->last_subscription_date_start=$this->db->jdate($obj->datef);
    +				$this->last_subscription_date_end=$this->db->jdate($obj->datef);
     				$this->last_subscription_amount=$obj->subscription;
     
     				$subscription=new Subscription($this->db);
    @@ -1333,9 +1384,9 @@ class Adherent extends CommonObject
     			{
     				// Change properties of object (used by triggers)
     				$this->last_subscription_date=dol_now();
    -				$this->last_subscription_amount=$amount;
     				$this->last_subscription_date_start=$date;
     				$this->last_subscription_date_end=$datefin;
    +				$this->last_subscription_amount=$amount;
     			}
     
     			if (! $error)
    @@ -2248,7 +2299,9 @@ class Adherent extends CommonObject
     		$this->country = 'France';
     		$this->morphy = 1;
     		$this->email = 'specimen@specimen.com';
    -		$this->skype = 'tom.hanson';
    +		$this->skype = 'skypepseudo';
    +		$this->twitter = 'twitterpseudo';
    +		$this->facebook = 'facebookpseudo';
     		$this->phone        = '0999999999';
     		$this->phone_perso  = '0999999998';
     		$this->phone_mobile = '0999999997';
    @@ -2266,8 +2319,13 @@ class Adherent extends CommonObject
     		$this->need_subscription=0;
     
     		$this->first_subscription_date=time();
    +		$this->first_subscription_date_start=$this->first_subscription_date;
    +		$this->first_subscription_date_end=dol_time_plus_duree($this->first_subscription_date_start, 1, 'y');
     		$this->first_subscription_amount=10;
    -		$this->last_subscription_date=time();
    +
    +		$this->last_subscription_date=$this->first_subscription_date;
    +		$this->last_subscription_date_start=$this->first_subscription_date;
    +		$this->last_subscription_date_end=dol_time_plus_duree($this->last_subscription_date_start, 1, 'y');
     		$this->last_subscription_amount=10;
     	}
     
    @@ -2350,6 +2408,8 @@ class Adherent extends CommonObject
     		if ($this->town && ! empty($conf->global->LDAP_MEMBER_FIELD_TOWN))						$info[$conf->global->LDAP_MEMBER_FIELD_TOWN] = $this->town;
     		if ($this->country_code && ! empty($conf->global->LDAP_MEMBER_FIELD_COUNTRY))			$info[$conf->global->LDAP_MEMBER_FIELD_COUNTRY] = $this->country_code;
     		if ($this->skype && ! empty($conf->global->LDAP_MEMBER_FIELD_SKYPE))					$info[$conf->global->LDAP_MEMBER_FIELD_SKYPE] = $this->skype;
    +		if ($this->twitter && ! empty($conf->global->LDAP_MEMBER_FIELD_TWITTER))				$info[$conf->global->LDAP_MEMBER_FIELD_TWITTER] = $this->twitter;
    +		if ($this->facebook && ! empty($conf->global->LDAP_MEMBER_FIELD_FACEBOOK))				$info[$conf->global->LDAP_MEMBER_FIELD_FACEBOOK] = $this->facebook;
     		if ($this->phone && ! empty($conf->global->LDAP_MEMBER_FIELD_PHONE))					$info[$conf->global->LDAP_MEMBER_FIELD_PHONE] = $this->phone;
     		if ($this->phone_perso && ! empty($conf->global->LDAP_MEMBER_FIELD_PHONE_PERSO))		$info[$conf->global->LDAP_MEMBER_FIELD_PHONE_PERSO] = $this->phone_perso;
     		if ($this->phone_mobile && ! empty($conf->global->LDAP_MEMBER_FIELD_MOBILE))			$info[$conf->global->LDAP_MEMBER_FIELD_MOBILE] = $this->phone_mobile;
    @@ -2572,10 +2632,10 @@ class Adherent extends CommonObject
     	 * Send reminders by emails before subscription end
     	 * CAN BE A CRON TASK
     	 *
    -	 * @param	int			$daysbeforeend		Nb of days before end of subscription (negative number = after subscription)
    -	 * @return	int								0 if OK, <>0 if KO (this function is used also by cron so only 0 is OK)
    +	 * @param	string		$daysbeforeendlist		Nb of days before end of subscription (negative number = after subscription). Can be a list of delay, separated by a semicolon, for example '10;5;0;-5'
    +	 * @return	int									0 if OK, <>0 if KO (this function is used also by cron so only 0 is OK)
     	 */
    -	public function sendReminderForExpiredSubscription($daysbeforeend=10)
    +	public function sendReminderForExpiredSubscription($daysbeforeendlist='10')
     	{
     		global $conf, $langs, $mysoc, $user;
     
    @@ -2593,97 +2653,110 @@ class Adherent extends CommonObject
     		}*/
     
     		$now = dol_now();
    +		$nbok = 0;
    +		$nbko = 0;
     
    -		dol_syslog(__METHOD__, LOG_DEBUG);
    -
    -		$tmp=dol_getdate($now);
    -		$datetosearchfor = dol_time_plus_duree(dol_mktime(0, 0, 0, $tmp['mon'], $tmp['mday'], $tmp['year']), -1 * $daysbeforeend, 'd');
    -
    -		$sql = 'SELECT rowid FROM '.MAIN_DB_PREFIX.'adherent';
    -		$sql.= " WHERE datefin = '".$this->db->idate($datetosearchfor)."'";
    -
    -		$resql = $this->db->query($sql);
    -		if ($resql)
    +		$arraydaysbeforeend=explode(';',$daysbeforeendlist);
    +		foreach($arraydaysbeforeend as $daysbeforeend)			// Loop on each delay
     		{
    -			$num_rows = $this->db->num_rows($resql);
    +			dol_syslog(__METHOD__.' - Process delta = '.$daysbeforeend, LOG_DEBUG);
     
    -			include_once DOL_DOCUMENT_ROOT.'/core/class/html.formmail.class.php';
    -			$adherent = new Adherent($this->db);
    -			$formmail = new FormMail($this->db);
    -
    -			$i=0;
    -			$nbok = 0;
    -			$nbko = 0;
    -			while ($i < $num_rows)
    +			if (! is_numeric($daysbeforeend))
     			{
    -				$obj = $this->db->fetch_object($resql);
    +				$blockingerrormsg="Value for delta is not a positive or negative numeric";
    +				$nbko++;
    +				break;
    +			}
     
    -				$adherent->fetch($obj->rowid);
    +			$tmp=dol_getdate($now);
    +			$datetosearchfor = dol_time_plus_duree(dol_mktime(0, 0, 0, $tmp['mon'], $tmp['mday'], $tmp['year']), $daysbeforeend, 'd');
     
    -				if (empty($adherent->email))
    +			$sql = 'SELECT rowid FROM '.MAIN_DB_PREFIX.'adherent';
    +			$sql.= " WHERE datefin = '".$this->db->idate($datetosearchfor)."'";
    +
    +			$resql = $this->db->query($sql);
    +			if ($resql)
    +			{
    +				$num_rows = $this->db->num_rows($resql);
    +
    +				include_once DOL_DOCUMENT_ROOT.'/core/class/html.formmail.class.php';
    +				$adherent = new Adherent($this->db);
    +				$formmail = new FormMail($this->db);
    +
    +				$i=0;
    +				while ($i < $num_rows)
     				{
    -					$nbko++;
    -				}
    -				else
    -				{
    -					$adherent->fetch_thirdparty();
    +					$obj = $this->db->fetch_object($resql);
     
    -					// Send reminder email
    -					$outputlangs = new Translate('', $conf);
    -					$outputlangs->setDefaultLang(empty($adherent->thirdparty->default_lang) ? $mysoc->default_lang : $adherent->thirdparty->default_lang);
    -					// Load traductions files requiredby by page
    -					$outputlangs->loadLangs(array("main", "members"));
    -					dol_syslog("sendReminderForExpiredSubscription Language set to ".$outputlangs->defaultlang);
    +					$adherent->fetch($obj->rowid, '', '', '', true, true);
     
    -					$arraydefaultmessage=null;
    -					$labeltouse = $conf->global->ADHERENT_EMAIL_TEMPLATE_REMIND_EXPIRATION;
    -
    -					if (! empty($labeltouse)) $arraydefaultmessage=$formmail->getEMailTemplate($this->db, 'member', $user, $outputlangs, 0, 1, $labeltouse);
    -
    -					if (! empty($labeltouse) && is_object($arraydefaultmessage) && $arraydefaultmessage->id > 0)
    +					if (empty($adherent->email))
     					{
    -						$substitutionarray=getCommonSubstitutionArray($outputlangs, 0, null, $adherent);
    -						//if (is_array($adherent->thirdparty)) $substitutionarraycomp = ...
    -						complete_substitutions_array($substitutionarray, $outputlangs, $adherent);
    -
    -						$subject = make_substitutions($arraydefaultmessage->topic, $substitutionarray, $outputlangs);
    -						$msg     = make_substitutions($arraydefaultmessage->content, $substitutionarray, $outputlangs);
    -						$from = $conf->global->ADHERENT_MAIL_FROM;
    -						$to = $adherent->email;
    -
    -						$trackid = 'mem'.$adherent->id;
    -						$moreinheader='X-Dolibarr-Info: sendReminderForExpiredSubscription'."\r\n";
    -
    -						include_once DOL_DOCUMENT_ROOT.'/core/class/CMailFile.class.php';
    -						$cmail = new CMailFile($subject, $to, $from, $msg, array(), array(), array(), '', '', 0, 1, '', '', $trackid, $moreinheader);
    -						$result = $cmail->sendfile();
    -						if (! $result)
    -						{
    -							$error++;
    -							$this->error = $cmail->error;
    -							$this->errors += $cmail->errors;
    -							$nbko++;
    -						}
    -						else
    -						{
    -							$nbok++;
    -						}
    +						$nbko++;
     					}
     					else
     					{
    -						$blockingerrormsg="Can't find email template, defined into member module setup, to use for reminding";
    -						$nbko++;
    -						break;
    -					}
    -				}
    +						$adherent->fetch_thirdparty();
     
    -				$i++;
    +						// Send reminder email
    +						$outputlangs = new Translate('', $conf);
    +						$outputlangs->setDefaultLang(empty($adherent->thirdparty->default_lang) ? $mysoc->default_lang : $adherent->thirdparty->default_lang);
    +						$outputlangs->loadLangs(array("main", "members"));
    +						dol_syslog("sendReminderForExpiredSubscription Language set to ".$outputlangs->defaultlang);
    +
    +						$arraydefaultmessage=null;
    +						$labeltouse = $conf->global->ADHERENT_EMAIL_TEMPLATE_REMIND_EXPIRATION;
    +
    +						if (! empty($labeltouse)) $arraydefaultmessage=$formmail->getEMailTemplate($this->db, 'member', $user, $outputlangs, 0, 1, $labeltouse);
    +
    +						if (! empty($labeltouse) && is_object($arraydefaultmessage) && $arraydefaultmessage->id > 0)
    +						{
    +							$substitutionarray=getCommonSubstitutionArray($outputlangs, 0, null, $adherent);
    +							//if (is_array($adherent->thirdparty)) $substitutionarraycomp = ...
    +							complete_substitutions_array($substitutionarray, $outputlangs, $adherent);
    +
    +							$subject = make_substitutions($arraydefaultmessage->topic, $substitutionarray, $outputlangs);
    +							$msg     = make_substitutions($arraydefaultmessage->content, $substitutionarray, $outputlangs);
    +							$from = $conf->global->ADHERENT_MAIL_FROM;
    +							$to = $adherent->email;
    +
    +							$trackid = 'mem'.$adherent->id;
    +							$moreinheader='X-Dolibarr-Info: sendReminderForExpiredSubscription'."\r\n";
    +
    +							include_once DOL_DOCUMENT_ROOT.'/core/class/CMailFile.class.php';
    +							$cmail = new CMailFile($subject, $to, $from, $msg, array(), array(), array(), '', '', 0, 1, '', '', $trackid, $moreinheader);
    +							$result = $cmail->sendfile();
    +							if (! $result)
    +							{
    +								$error++;
    +								$this->error = $cmail->error;
    +								$this->errors += $cmail->errors;
    +								$nbko++;
    +							}
    +							else
    +							{
    +								$nbok++;
    +
    +								// TODO Add event email sent for member
    +
    +							}
    +						}
    +						else
    +						{
    +							$blockingerrormsg="Can't find email template, defined into member module setup, to use for reminding";
    +							$nbko++;
    +							break;
    +						}
    +					}
    +
    +					$i++;
    +				}
    +			}
    +			else
    +			{
    +				$this->error = $this->db->lasterror();
    +				return 1;
     			}
    -		}
    -		else
    -		{
    -			$this->error = $this->db->lasterror();
    -			return 1;
     		}
     
     		if ($blockingerrormsg)
    diff --git a/htdocs/adherents/class/adherent_type.class.php b/htdocs/adherents/class/adherent_type.class.php
    index dffd1446af0..20a85c7bf3e 100644
    --- a/htdocs/adherents/class/adherent_type.class.php
    +++ b/htdocs/adherents/class/adherent_type.class.php
    @@ -47,7 +47,11 @@ class AdherentType extends CommonObject
     	 */
     	public $picto = 'group';
     
    -	public $ismultientitymanaged = 1;  // 0=No test on entity, 1=Test with field entity, 2=Test with link by societe
    +	/**
    +	 * 0=No test on entity, 1=Test with field entity, 2=Test with link by societe
    +	 * @var int
    +	 */
    +	public $ismultientitymanaged = 1;
     
     	/**
     	 * @var string
    diff --git a/htdocs/adherents/class/subscription.class.php b/htdocs/adherents/class/subscription.class.php
    index 1c64560cf79..562b34af2b1 100644
    --- a/htdocs/adherents/class/subscription.class.php
    +++ b/htdocs/adherents/class/subscription.class.php
    @@ -51,8 +51,17 @@ class Subscription extends CommonObject
     	public $datem;				// Date modification
     	public $dateh;				// Subscription start date (date subscription)
     	public $datef;				// Subscription end date
    +
    +	/**
    +     * @var int ID
    +     */
     	public $fk_adherent;
    +
     	public $amount;
    +
    +	/**
    +     * @var int ID
    +     */
     	public $fk_bank;
     
     
    diff --git a/htdocs/admin/company.php b/htdocs/admin/company.php
    index e3ea95d18b5..cc564bfb08e 100644
    --- a/htdocs/admin/company.php
    +++ b/htdocs/admin/company.php
    @@ -75,6 +75,8 @@ if ( ($action == 'update' && ! GETPOST("cancel",'alpha'))
     		activateModulesRequiredByCountry($mysoc->country_code);
     	}
     
    +	$db->begin();
    +
     	dolibarr_set_const($db, "MAIN_INFO_SOCIETE_NOM", GETPOST("nom",'nohtml'),'chaine',0,'',$conf->entity);
     	dolibarr_set_const($db, "MAIN_INFO_SOCIETE_ADDRESS", GETPOST("MAIN_INFO_SOCIETE_ADDRESS",'nohtml'),'chaine',0,'',$conf->entity);
     	dolibarr_set_const($db, "MAIN_INFO_SOCIETE_TOWN", GETPOST("MAIN_INFO_SOCIETE_TOWN",'nohtml'),'chaine',0,'',$conf->entity);
    @@ -173,11 +175,24 @@ if ( ($action == 'update' && ! GETPOST("cancel",'alpha'))
     
     	dolibarr_set_const($db, "SOCIETE_FISCAL_MONTH_START", GETPOST("SOCIETE_FISCAL_MONTH_START",'int'),'chaine',0,'',$conf->entity);
     
    -	dolibarr_set_const($db, "FACTURE_TVAOPTION", GETPOST("optiontva",'aZ09'),'chaine',0,'',$conf->entity);
    +	// Sale tax options
    +	$usevat = GETPOST("optiontva",'aZ09');
    +	$uselocaltax1 = GETPOST("optionlocaltax1",'aZ09');
    +	$uselocaltax2 = GETPOST("optionlocaltax2",'aZ09');
    +	if ($uselocaltax1 == 'localtax1on' && ! $usevat)
    +	{
    +		setEventMessages($langs->trans("IfYouUseASecondTaxYouMustSetYouUseTheMainTax"), null, 'errors');
    +		$error++;
    +	}
    +	if ($uselocaltax2 == 'localtax2on' && ! $usevat)
    +	{
    +		setEventMessages($langs->trans("IfYouUseAThirdTaxYouMustSetYouUseTheMainTax"), null, 'errors');
    +		$error++;
    +	}
     
    -	// Local taxes
    -	dolibarr_set_const($db, "FACTURE_LOCAL_TAX1_OPTION", GETPOST("optionlocaltax1",'aZ09'),'chaine',0,'',$conf->entity);
    -	dolibarr_set_const($db, "FACTURE_LOCAL_TAX2_OPTION", GETPOST("optionlocaltax2",'aZ09'),'chaine',0,'',$conf->entity);
    +	dolibarr_set_const($db, "FACTURE_TVAOPTION", $usevat,'chaine',0,'',$conf->entity);
    +	dolibarr_set_const($db, "FACTURE_LOCAL_TAX1_OPTION", $uselocaltax1,'chaine',0,'',$conf->entity);
    +	dolibarr_set_const($db, "FACTURE_LOCAL_TAX2_OPTION", $uselocaltax2,'chaine',0,'',$conf->entity);
     
     	if($_POST["optionlocaltax1"]=="localtax1on")
     	{
    @@ -204,6 +219,15 @@ if ( ($action == 'update' && ! GETPOST("cancel",'alpha'))
     		dolibarr_set_const($db,"MAIN_INFO_LOCALTAX_CALC2", GETPOST("clt2",'aZ09'),'chaine',0,'',$conf->entity);
     	}
     
    +	if (! $error)
    +	{
    +		$db->commit();
    +	}
    +	else
    +	{
    +		$db->rollback();
    +	}
    +
     	if ($action != 'updateedit' && ! $error)
     	{
     		header("Location: ".$_SERVER["PHP_SELF"]);
    @@ -586,7 +610,7 @@ if ($action == 'edit' || $action == 'updateedit')
     	print '<td colspan="2">';
     	print "<table>";
     	print "<tr><td><label for=\"use_vat\">".$langs->trans("VATIsUsedDesc")."</label></td></tr>";
    -	print "<tr><td><i>".$langs->trans("Example").': '.$langs->trans("VATIsUsedExampleFR")."</i></td></tr>\n";
    +	if ($mysoc->country_code == 'FR') print "<tr><td><i>".$langs->trans("Example").': '.$langs->trans("VATIsUsedExampleFR")."</i></td></tr>\n";
     	print "</table>";
     	print "</td></tr>\n";
     
    @@ -595,7 +619,7 @@ if ($action == 'edit' || $action == 'updateedit')
     	print '<td colspan="2">';
     	print "<table>";
     	print "<tr><td><label for=\"no_vat\">".$langs->trans("VATIsNotUsedDesc")."</label></td></tr>";
    -	print "<tr><td><i>".$langs->trans("Example").': '.$langs->trans("VATIsNotUsedExampleFR")."</i></td></tr>\n";
    +	if ($mysoc->country_code == 'FR') print "<tr><td><i>".$langs->trans("Example").': '.$langs->trans("VATIsNotUsedExampleFR")."</i></td></tr>\n";
     	print "</table>";
     	print "</td></tr>\n";
     
    @@ -1024,7 +1048,7 @@ else
     	print '<td colspan="2">';
     	print "<table>";
     	print "<tr><td><label for=\"use_vat\">".$langs->trans("VATIsUsedDesc")."</label></td></tr>";
    -	print "<tr><td><i>".$langs->trans("Example").': '.$langs->trans("VATIsUsedExampleFR")."</i></td></tr>\n";
    +	if ($mysoc->country_code == 'FR') print "<tr><td><i>".$langs->trans("Example").': '.$langs->trans("VATIsUsedExampleFR")."</i></td></tr>\n";
     	print "</table>";
     	print "</td></tr>\n";
     
    @@ -1034,7 +1058,7 @@ else
     	print '<td colspan="2">';
     	print "<table>";
     	print "<tr><td><label=\"no_vat\">".$langs->trans("VATIsNotUsedDesc")."</label></td></tr>";
    -	print "<tr><td><i>".$langs->trans("Example").': '.$langs->trans("VATIsNotUsedExampleFR")."</i></td></tr>\n";
    +	if ($mysoc->country_code == 'FR') print "<tr><td><i>".$langs->trans("Example").': '.$langs->trans("VATIsNotUsedExampleFR")."</i></td></tr>\n";
     	print "</table>";
     	print "</td></tr>\n";
     
    diff --git a/htdocs/admin/dict.php b/htdocs/admin/dict.php
    index aaa4fb03706..0b5b63d35d6 100644
    --- a/htdocs/admin/dict.php
    +++ b/htdocs/admin/dict.php
    @@ -592,7 +592,7 @@ if ($id == 10)
      * Actions
      */
     
    -if (GETPOST('button_removefilter') || GETPOST('button_removefilter.x') || GETPOST('button_removefilter_x'))
    +if (GETPOST('button_removefilter', 'alpha') || GETPOST('button_removefilter.x', 'alpha') || GETPOST('button_removefilter_x', 'alpha'))
     {
         $search_country_id = '';
         $search_code = '';
    diff --git a/htdocs/admin/facture.php b/htdocs/admin/facture.php
    index 6c28081e6fc..cd84dbf65a5 100644
    --- a/htdocs/admin/facture.php
    +++ b/htdocs/admin/facture.php
    @@ -238,6 +238,32 @@ if ($action == 'setforcedate')
         }
     }
     
    +if ($action == 'setDefaultPDFModulesByType')
    +{
    +    $invoicetypemodels =  GETPOST('invoicetypemodels');
    +    
    +    if(!empty($invoicetypemodels) && is_array($invoicetypemodels))
    +    {
    +        $error = 0;
    +        
    +        foreach ($invoicetypemodels as $type => $value)
    +        {
    +            $res = dolibarr_set_const($db, 'FACTURE_ADDON_PDF_'.intval($type),$value,'chaine',0,'',$conf->entity);
    +            if (! $res > 0) $error++;
    +        }
    +        
    +        if (! $error)
    +        {
    +            setEventMessages($langs->trans("SetupSaved"), null, 'mesgs');
    +        }
    +        else
    +        {
    +            setEventMessages($langs->trans("Error"), null, 'errors');
    +        }
    +    }
    +    
    +   
    +}
     
     
     /*
    @@ -465,6 +491,8 @@ print "</tr>\n";
     
     clearstatcache();
     
    +$activatedModels = array();
    +
     foreach ($dirmodels as $reldir)
     {
         foreach (array('','/doc') as $valdir)
    @@ -580,6 +608,47 @@ foreach ($dirmodels as $reldir)
     }
     print '</table>';
     
    +if(!empty($conf->global->INVOICE_USE_DEFAULT_DOCUMENT)) // Hidden conf
    +{
    +    /*
    +     *  Document templates generators
    +     */
    +    print '<br>';
    +    print load_fiche_titre($langs->trans("BillsPDFModulesAccordindToInvoiceType"),'','');
    +    print '<form action="'.$_SERVER["PHP_SELF"].'#default-pdf-modules-by-type-table" method="POST">';
    +    print '<input type="hidden" name="token" value="'.$_SESSION['newtoken'].'" />';
    +    print '<input type="hidden" name="action" value="setDefaultPDFModulesByType" >';
    +    print '<table id="default-pdf-modules-by-type-table" class="noborder" width="100%">';
    +    print '<tr class="liste_titre">';
    +    print '<td>'.$langs->trans("Type").'</td>';
    +    print '<td>'.$langs->trans("Name").'</td>';
    +    print '<td align="right"><input type="submit" class="button" value="'.$langs->trans("Modify").'"></td>';
    +    print "</tr>\n";
    +    
    +    $listtype=array(
    +        Facture::TYPE_STANDARD=>$langs->trans("InvoiceStandard"),
    +        Facture::TYPE_REPLACEMENT=>$langs->trans("InvoiceReplacement"),
    +        Facture::TYPE_CREDIT_NOTE=>$langs->trans("InvoiceAvoir"),
    +        Facture::TYPE_DEPOSIT=>$langs->trans("InvoiceDeposit"),
    +    );
    +    if (! empty($conf->global->INVOICE_USE_SITUATION))
    +    {
    +        $listtype[Facture::TYPE_SITUATION] = $langs->trans("InvoiceSituation");
    +    }
    +    
    +    foreach ($listtype as $type => $trans)
    +    {
    +        $thisTypeConfName = 'FACTURE_ADDON_PDF_'.$type;
    +        $current = !empty($conf->global->{$thisTypeConfName})?$conf->global->{$thisTypeConfName}:$conf->global->FACTURE_ADDON_PDF;
    +        print '<tr >';
    +        print '<td>'.$trans.'</td>';
    +        print '<td colspan="2" >'.$form->selectarray('invoicetypemodels['.$type.']', ModelePDFFactures::liste_modeles($db), $current,0,0, 0).'</td>';
    +        print "</tr>\n";
    +    }
    +    
    +    print '</table>';
    +    print "</form>";
    +}
     
     /*
      *  Modes de reglement
    @@ -662,6 +731,7 @@ if ($resql)
         $i = 0;
         while ($i < $num)
         {
    +
             $row = $db->fetch_row($resql);
     
             print '<option value="'.$row[0].'"';
    diff --git a/htdocs/admin/mails_templates.php b/htdocs/admin/mails_templates.php
    index da6989b41fd..ab169afc096 100644
    --- a/htdocs/admin/mails_templates.php
    +++ b/htdocs/admin/mails_templates.php
    @@ -319,10 +319,11 @@ if (empty($reshook))
                     if ($i) $sql.=",";
                     $sql.= $field."=";
     
    -//                print $keycode.' - '.$_POST[$keycode].'<br>';
    -                if ($_POST[$keycode] == '' || ($keycode != 'langcode' && $keycode != 'private' && empty($_POST[$keycode]))) $sql.="null";  // lang must be '' if not defined so the unique key that include lang will work
    -                elseif ($_POST[$keycode] == '0' && $keycode == 'langcode') $sql.="''";													   // lang must be '' if not defined so the unique key that include lang will work
    -                elseif ($keycode == 'private') $sql.=((int) $_POST[$keycode]);													  		   // private must be 0 or 1
    +                //print $keycode.' - '.$_POST[$keycode].'<br>';
    +                if ($_POST[$keycode] == '' || ($keycode != 'langcode' && $keycode != 'position' && $keycode != 'private' && empty($_POST[$keycode]))) $sql.="null";  // lang must be '' if not defined so the unique key that include lang will work
    +                elseif ($_POST[$keycode] == '0' && $keycode == 'langcode') $sql.="''";	// lang must be '' if not defined so the unique key that include lang will work
    +                elseif ($keycode == 'private') $sql.=((int) $_POST[$keycode]);	        // private must be 0 or 1
    +                elseif ($keycode == 'position')	$sql.=((int) $_POST[$keycode]);
                     else $sql.="'".$db->escape($_POST[$keycode])."'";
                     $i++;
                 }
    diff --git a/htdocs/admin/notification.php b/htdocs/admin/notification.php
    index d93421ef6fb..92ba0bec200 100644
    --- a/htdocs/admin/notification.php
    +++ b/htdocs/admin/notification.php
    @@ -166,12 +166,15 @@ foreach($listofnotifiedevents as $notifiedevent)
     {
     
         $label=$langs->trans("Notify_".$notifiedevent['code']); //!=$langs->trans("Notify_".$notifiedevent['code'])?$langs->trans("Notify_".$notifiedevent['code']):$notifiedevent['label'];
    +    $elementLabel = $langs->trans(ucfirst($notifiedevent['elementtype']));
     
         if ($notifiedevent['elementtype'] == 'order_supplier') $elementLabel = $langs->trans('SupplierOrder');
         elseif ($notifiedevent['elementtype'] == 'propal') $elementLabel = $langs->trans('Proposal');
         elseif ($notifiedevent['elementtype'] == 'facture') $elementLabel = $langs->trans('Bill');
         elseif ($notifiedevent['elementtype'] == 'commande') $elementLabel = $langs->trans('Order');
         elseif ($notifiedevent['elementtype'] == 'ficheinter') $elementLabel = $langs->trans('Intervention');
    +    elseif ($notifiedevent['elementtype'] == 'shipping') $elementLabel = $langs->trans('Shipping');
    +    elseif ($notifiedevent['elementtype'] == 'expensereport') $elementLabel = $langs->trans('ExpenseReport');
     
         if ($i) print ', ';
         print $label;
    @@ -209,11 +212,15 @@ foreach($listofnotifiedevents as $notifiedevent)
     
         $label=$langs->trans("Notify_".$notifiedevent['code']); //!=$langs->trans("Notify_".$notifiedevent['code'])?$langs->trans("Notify_".$notifiedevent['code']):$notifiedevent['label'];
     
    +    $elementLabel = $langs->trans(ucfirst($notifiedevent['elementtype']));
    +	// Special cases
         if ($notifiedevent['elementtype'] == 'order_supplier') $elementLabel = $langs->trans('SupplierOrder');
         elseif ($notifiedevent['elementtype'] == 'propal') $elementLabel = $langs->trans('Proposal');
         elseif ($notifiedevent['elementtype'] == 'facture') $elementLabel = $langs->trans('Bill');
         elseif ($notifiedevent['elementtype'] == 'commande') $elementLabel = $langs->trans('Order');
     	elseif ($notifiedevent['elementtype'] == 'ficheinter') $elementLabel = $langs->trans('Intervention');
    +	elseif ($notifiedevent['elementtype'] == 'shipping') $elementLabel = $langs->trans('Shipping');
    +	elseif ($notifiedevent['elementtype'] == 'expensereport') $elementLabel = $langs->trans('ExpenseReport');
     
         print '<tr class="oddeven">';
         print '<td>'.$elementLabel.'</td>';
    diff --git a/htdocs/admin/prelevement.php b/htdocs/admin/prelevement.php
    index c40eca7380e..cdfcd451f2c 100644
    --- a/htdocs/admin/prelevement.php
    +++ b/htdocs/admin/prelevement.php
    @@ -465,7 +465,6 @@ if (! empty($conf->global->MAIN_MODULE_NOTIFICATION))
         {
             $num = $db->num_rows($resql);
             $i = 0;
    -        $var = false;
             while ($i < $num)
             {
                 $obj = $db->fetch_object($resql);
    @@ -511,7 +510,6 @@ if (! empty($conf->global->MAIN_MODULE_NOTIFICATION))
     	{
     	    $num = $db->num_rows($resql);
     	    $i = 0;
    -	    $var = false;
     	    while ($i < $num)
     	    {
     	        $obj = $db->fetch_object($resql);
    diff --git a/htdocs/admin/supplier_invoice.php b/htdocs/admin/supplier_invoice.php
    index 367d1fe0d36..3db96ddd8a4 100644
    --- a/htdocs/admin/supplier_invoice.php
    +++ b/htdocs/admin/supplier_invoice.php
    @@ -56,9 +56,12 @@ $specimenthirdparty->initAsSpecimen();
     if ($action == 'updateMask')
     {
         $maskconstinvoice=GETPOST('maskconstinvoice','alpha');
    -    $maskvalue=GETPOST('maskinvoice','alpha');
    +	$maskconstcredit=GETPOST('maskconstcredit','alpha');
    +    $maskinvoice=GETPOST('maskinvoice','alpha');
    +	$maskcredit=GETPOST('maskcredit','alpha');
     
    -    if ($maskconstinvoice)  $res = dolibarr_set_const($db,$maskconstinvoice,$maskvalue,'chaine',0,'',$conf->entity);
    +    if ($maskconstinvoice)  $res = dolibarr_set_const($db,$maskconstinvoice,$maskinvoice,'chaine',0,'',$conf->entity);
    +	if ($maskconstcredit)  $res = dolibarr_set_const($db,$maskconstcredit,$maskcredit,'chaine',0,'',$conf->entity);
     
         if (! $res > 0) $error++;
     
    diff --git a/htdocs/admin/tools/dolibarr_export.php b/htdocs/admin/tools/dolibarr_export.php
    index c9ef19dae98..4c69f2ead48 100644
    --- a/htdocs/admin/tools/dolibarr_export.php
    +++ b/htdocs/admin/tools/dolibarr_export.php
    @@ -493,6 +493,7 @@ print '</table>';
     
     </div> 	<!-- end div fichehalfleft -->
     
    +
     <div id="backupdatabaseright" class="fichehalfright" style="height:480px; overflow: auto;">
     <div class="ficheaddleft">
     
    @@ -505,21 +506,94 @@ print '<br>';
     
     </div>
     </div>
    -
    +</form>
     </fieldset>
     
     <br>
    +<!-- Dump of a server -->
    +
    +<form method="post" action="export_files.php" name="dump">
    +<input type="hidden" name="token" value="<?php echo $_SESSION['newtoken']; ?>" />
    +<input type="hidden" name="export_type" value="server" />
     
     <fieldset><legend class="legendforfieldsetstep" style="font-size: 3em">2</legend>
    +<div class="fichehalfleft">
    +
     <?php
     print $langs->trans("BackupDesc2",DOL_DATA_ROOT).'<br>';
     print $langs->trans("BackupDescX").'<br><br>';
    +
     ?>
    +
    +<label for="zipfilename_template"> <?php echo $langs->trans("FileNameToGenerate"); ?></label><br>
    +<input type="text" name="zipfilename_template" style="width: 90%"
    +	id="zipfilename_template"
    +	value="<?php
    +$prefix='documents';
    +$ext='zip';
    +
    +$file=$prefix.'_'.$dolibarr_main_db_name.'_'.dol_sanitizeFileName(DOL_VERSION).'_'.strftime("%Y%m%d%H%M").'.'.$ext;
    +echo $file;
    +?>" /> <br>
    +<br>
    +
    +<?php
    +// Show compression choices
    +print '<div class="formelementrow">';
    +print "\n";
    +
    +print $langs->trans("Compression").': &nbsp; ';
    +$filecompression = $compression;
    +array_shift($filecompression);
    +$filecompression['zip']= array('function' => 'dol_compress_dir', 'id' => 'radio_compression_zip',  'label' => $langs->trans("FormatZip"));
    +
    +foreach($filecompression as $key => $val)
    +{
    +    if (! $val['function'] || function_exists($val['function']))	// Enabled export format
    +    {
    +        print '<input type="radio" name="compression" value="'.$key.'" id="'.$val['id'].'" checked>';
    +        print ' <label for="'.$val['id'].'">'.$val['label'].'</label>';
    +    }
    +    else	// Disabled export format
    +    {
    +        print '<input type="radio" name="compression" value="'.$key.'" id="'.$val['id'].'" disabled>';
    +        print ' <label for="'.$val['id'].'">'.$val['label'].'</label>';
    +        print ' ('.$langs->trans("NotAvailable").')';
    +    }
    +    print ' &nbsp; &nbsp; ';
    +}
    +
    +print '</div>';
    +print "\n";
    +
    +?>
    +<br>
    +<div align="center"><input type="submit" class="button"
    +	value="<?php echo $langs->trans("GenerateBackup") ?>" id="buttonGo" /><br>
    +<br>
    +</div>
    +
    +</div>
    +
    +<div id="backupdatabaseright" class="fichehalfright" style="height:480px; overflow: auto;">
    +<div class="ficheaddleft">
    +
    +<?php
    +$filearray=dol_dir_list($conf->admin->dir_output.'/documents','files',0,'','',$sortfield,(strtolower($sortorder)=='asc'?SORT_ASC:SORT_DESC),1);
    +$result=$formfile->list_of_documents($filearray,null,'systemtools','',1,'documents/',1,0,$langs->trans("NoBackupFileAvailable"),0,$langs->trans("PreviousDumpFiles"));
    +print '<br>';
    +?>
    +
    +
    +</div>
    +</div>
    +
     </fieldset>
    -
    -
    -
     </form>
    +
    +
    +
    +
     <?php
     
     // End of page
    diff --git a/htdocs/admin/tools/export_files.php b/htdocs/admin/tools/export_files.php
    new file mode 100644
    index 00000000000..809cea3b271
    --- /dev/null
    +++ b/htdocs/admin/tools/export_files.php
    @@ -0,0 +1,166 @@
    +<?php
    +/* Copyright (C) 2006-2014  Laurent Destailleur <eldy@users.sourceforge.net>
    + * Copyright (C) 2011       Juanjo Menent       <jmenent@2byte.es>
    + * Copyright (C) 2015       Raphaël Doursenaud  <rdoursenaud@gpcsolutions.fr>
    + *
    +* This program is free software; you can redistribute it and/or modify
    +* it under the terms of the GNU General Public License as published by
    +* the Free Software Foundation; either version 3 of the License, or
    +* (at your option) any later version.
    +*
    +* This program is distributed in the hope that it will be useful,
    +* but WITHOUT ANY WARRANTY; without even the implied warranty of
    +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    +* GNU General Public License for more details.
    +*
    +* You should have received a copy of the GNU General Public License
    +* along with this program. If not, see <http://www.gnu.org/licenses/>.
    +*/
    +
    +/**
    + *		\file 		htdocs/admin/tools/export.php
    + *		\brief      Page to export a database into a dump file
    + */
    +
    +require '../../main.inc.php';
    +require_once DOL_DOCUMENT_ROOT.'/core/lib/admin.lib.php';
    +require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
    +require_once DOL_DOCUMENT_ROOT.'/core/class/utils.class.php';
    +require_once DOL_DOCUMENT_ROOT.'/core/class/html.formfile.class.php';
    +
    +$langs->load("admin");
    +
    +$action=GETPOST('action','alpha');
    +$what=GETPOST('what','alpha');
    +$export_type=GETPOST('export_type','alpha');
    +$file=GETPOST('zipfilename_template','alpha');
    +$compression = GETPOST('compression');
    +
    +$sortfield = GETPOST('sortfield','alpha');
    +$sortorder = GETPOST('sortorder','alpha');
    +$page = GETPOST("page",'int');
    +if (! $sortorder) $sortorder="DESC";
    +if (! $sortfield) $sortfield="date";
    +if ($page < 0) { $page = 0; }
    +elseif (empty($page)) $page = 0;
    +$limit = GETPOST('limit','int')?GETPOST('limit','int'):$conf->liste_limit;
    +$offset = $limit * $page;
    +
    +if (! $user->admin) accessforbidden();
    +
    +$errormsg='';
    +
    +
    +/*
    + * Actions
    + */
    +
    +if ($action == 'delete')
    +{
    +	$file=$conf->admin->dir_output.'/'.GETPOST('urlfile');
    +	$ret=dol_delete_file($file, 1);
    +	if ($ret) setEventMessages($langs->trans("FileWasRemoved", GETPOST('urlfile')), null, 'mesgs');
    +	else setEventMessages($langs->trans("ErrorFailToDeleteFile", GETPOST('urlfile')), null, 'errors');
    +	$action='';
    +}
    +
    +
    +/*
    + * View
    + */
    +
    +// Increase limit of time. Works only if we are not in safe mode
    +$ExecTimeLimit=600;
    +if (!empty($ExecTimeLimit))
    +{
    +    $err=error_reporting();
    +    error_reporting(0);     // Disable all errors
    +    //error_reporting(E_ALL);
    +    @set_time_limit($ExecTimeLimit);   // Need more than 240 on Windows 7/64
    +    error_reporting($err);
    +}
    +$MemoryLimit=0;
    +if (!empty($MemoryLimit))
    +{
    +    @ini_set('memory_limit', $MemoryLimit);
    +}
    +
    +$form=new Form($db);
    +$formfile = new FormFile($db);
    +
    +//$help_url='EN:Backups|FR:Sauvegardes|ES:Copias_de_seguridad';
    +//llxHeader('','',$help_url);
    +
    +//print load_fiche_titre($langs->trans("Backup"),'','title_setup');
    +
    +
    +// Start with empty buffer
    +$dump_buffer = '';
    +$dump_buffer_len = 0;
    +
    +// We will send fake headers to avoid browser timeout when buffering
    +$time_start = time();
    +
    +
    +$outputdir  = $conf->admin->dir_output.'/documents';
    +$result=dol_mkdir($outputdir);
    +
    +$utils = new Utils($db);
    +
    +if ($compression == 'zip')
    +{
    +    $ret = dol_compress_dir(DOL_DATA_ROOT, $outputdir."/".$file, $compression);
    +    if ($ret < 0)
    +    {
    +        $errormsg = $langs->trans("ErrorFailedToWriteInDir",$outputfile);
    +    }
    +}
    +elseif (in_array($compression, array('gz', 'bz')))
    +{
    +    $file = substr($file, 0, strrpos($file, '.'));
    +    $file .= '.tar';
    +    $cmd = 'tar -cf '.$outputdir."/".$file." --exclude=documents/admin/documents -C ".DOL_DATA_ROOT." ".DOL_DATA_ROOT."/../documents/";
    +    exec($cmd, $out, $retval);
    +    //var_dump($cmd, DOL_DATA_ROOT);exit;
    +    
    +    if ($retval != 0)
    +    {
    +        $langs->load("errors");
    +        dol_syslog("Documents tar retval after exec=".$retval, LOG_ERR);
    +        $errormsg = 'Error tar generation return '.$retval;
    +    }
    +    else
    +    {
    +        if ($compression == 'gz')
    +        {
    +            $cmd = "gzip " . $outputdir."/".$file;
    +        }
    +        if ($compression == 'bz')
    +        {
    +            $cmd = "bzip2 " . $outputdir."/".$file;
    +        }
    +        
    +        exec($cmd, $out, $retval);
    +        if ($retval != 0)
    +        {
    +            $errormsg = 'Error '.$compression.' generation return '.$retval;
    +            unlink($outputdir."/".$file);
    +        }
    +    }
    +}
    +
    +if ($errormsg)
    +{
    +	setEventMessages($langs->trans("Error")." : ".$errormsg, null, 'errors');
    +}
    +
    +print '<br>';
    +
    +
    +// Redirect t backup page
    +header("Location: dolibarr_export.php");
    +
    +$time_end = time();
    +
    +$db->close();
    +
    diff --git a/htdocs/api/class/api_setup.class.php b/htdocs/api/class/api_setup.class.php
    index 9389e2ff5ed..60a51074d58 100644
    --- a/htdocs/api/class/api_setup.class.php
    +++ b/htdocs/api/class/api_setup.class.php
    @@ -3,6 +3,7 @@
      * Copyright (C) 2016	Laurent Destailleur		<eldy@users.sourceforge.net>
      * Copyright (C) 2017	Regis Houssin	        <regis.houssin@capnetworks.com>
      * Copyright (C) 2017	Neil Orley	            <neil.orley@oeris.fr>
    + * Copyright (C) 2018   Frédéric France         <frederic.france@netlogic.fr>
      *
      *
      * This program is free software; you can redistribute it and/or modify
    @@ -121,7 +122,7 @@ class Setup extends DolibarrApi
          * @param string    $filter     To filter the countries by name
          * @param string    $lang       Code of the language the label of the countries must be translated to
          * @param string    $sqlfilters Other criteria to filter answers separated by a comma. Syntax example "(t.code:like:'A%') and (t.active:>=:0)"
    -     * @return List of countries
    +     * @return array                List of countries
          *
          * @url     GET dictionary/countries
          *
    @@ -379,6 +380,66 @@ class Setup extends DolibarrApi
             return $list;
         }
     
    +    /**
    +     * Get the list of civility.
    +     *
    +     * @param string    $sortfield  Sort field
    +     * @param string    $sortorder  Sort order
    +     * @param int       $limit      Number of items per page
    +     * @param int       $page       Page number (starting from zero)
    +     * @param string    $module     To filter on module events
    +     * @param string    $sqlfilters Other criteria to filter answers separated by a comma. Syntax example "(t.code:like:'A%') and (t.active:>=:0)"
    +     * @return List of events types
    +     *
    +     * @url     GET dictionary/civility
    +     *
    +     * @throws RestException
    +     */
    +    function getListOfCivility($sortfield = "code", $sortorder = 'ASC', $limit = 100, $page = 0, $module = '', $sqlfilters = '')
    +    {
    +        $list = array();
    +
    +        $sql = "SELECT rowid, code, label, module";
    +        $sql.= " FROM ".MAIN_DB_PREFIX."c_civility as t";
    +        $sql.= " WHERE t.active = 1";
    +        if ($module)    $sql.=" AND t.module LIKE '%" . $this->db->escape($module) . "%'";
    +        // Add sql filters
    +        if ($sqlfilters)
    +        {
    +            if (! DolibarrApi::_checkFilters($sqlfilters))
    +            {
    +                throw new RestException(503, 'Error when validating parameter sqlfilters '.$sqlfilters);
    +            }
    +	        $regexstring='\(([^:\'\(\)]+:[^:\'\(\)]+:[^:\(\)]+)\)';
    +            $sql.=" AND (".preg_replace_callback('/'.$regexstring.'/', 'DolibarrApi::_forge_criteria_callback', $sqlfilters).")";
    +        }
    +
    +
    +        $sql.= $this->db->order($sortfield, $sortorder);
    +
    +        if ($limit) {
    +            if ($page < 0) {
    +                $page = 0;
    +            }
    +            $offset = $limit * $page;
    +
    +            $sql .= $this->db->plimit($limit, $offset);
    +        }
    +
    +        $result = $this->db->query($sql);
    +
    +        if ($result) {
    +            $num = $this->db->num_rows($result);
    +            $min = min($num, ($limit <= 0 ? $num : $limit));
    +            for ($i = 0; $i < $min; $i++) {
    +                $list[] = $this->db->fetch_object($result);
    +            }
    +        } else {
    +            throw new RestException(503, 'Error when retrieving list of civility : '.$this->db->lasterror());
    +        }
    +
    +        return $list;
    +    }
     
         /**
          * Get the list of extra fields.
    @@ -581,6 +642,185 @@ class Setup extends DolibarrApi
             return $list;
         }
     
    +     /**
    +     * Get the list of tickets categories.
    +     *
    +     * @param string    $sortfield  Sort field
    +     * @param string    $sortorder  Sort order
    +     * @param int       $limit      Number of items per page
    +     * @param int       $page       Page number (starting from zero)
    +     * @param string    $sqlfilters Other criteria to filter answers separated by a comma. Syntax example "(t.code:like:'A%') and (t.active:>=:0)"
    +     * @return List of events types
    +     *
    +     * @url     GET dictionary/ticket_categories
    +     *
    +     * @throws RestException
    +     */
    +    function getTicketsCategories($sortfield = "code", $sortorder = 'ASC', $limit = 100, $page = 0, $sqlfilters = '')
    +    {
    +    	$list = array();
    +
    +    	$sql = "SELECT rowid, code, pos,  label, use_default, description";
    +    	$sql.= " FROM ".MAIN_DB_PREFIX."c_ticket_category as t";
    +    	$sql.= " WHERE t.active = 1";
    +    	// Add sql filters
    +    	if ($sqlfilters)
    +    	{
    +    		if (! DolibarrApi::_checkFilters($sqlfilters))
    +    		{
    +    			throw new RestException(503, 'Error when validating parameter sqlfilters '.$sqlfilters);
    +    		}
    +    		$regexstring='\(([^:\'\(\)]+:[^:\'\(\)]+:[^:\(\)]+)\)';
    +    		$sql.=" AND (".preg_replace_callback('/'.$regexstring.'/', 'DolibarrApi::_forge_criteria_callback', $sqlfilters).")";
    +    	}
    +
    +
    +    	$sql.= $this->db->order($sortfield, $sortorder);
    +
    +    	if ($limit) {
    +    		if ($page < 0) {
    +    			$page = 0;
    +    		}
    +    		$offset = $limit * $page;
    +
    +    		$sql .= $this->db->plimit($limit, $offset);
    +    	}
    +
    +    	$result = $this->db->query($sql);
    +
    +    	if ($result) {
    +    		$num = $this->db->num_rows($result);
    +    		$min = min($num, ($limit <= 0 ? $num : $limit));
    +    		for ($i = 0; $i < $min; $i++) {
    +    			$list[] = $this->db->fetch_object($result);
    +    		}
    +    	} else {
    +    		throw new RestException(503, 'Error when retrieving list of ticket categories : '.$this->db->lasterror());
    +    	}
    +
    +    	return $list;
    +    }
    +
    +    /**
    +     * Get the list of tickets severity.
    +     *
    +     * @param string    $sortfield  Sort field
    +     * @param string    $sortorder  Sort order
    +     * @param int       $limit      Number of items per page
    +     * @param int       $page       Page number (starting from zero)
    +     * @param string    $sqlfilters Other criteria to filter answers separated by a comma. Syntax example "(t.code:like:'A%') and (t.active:>=:0)"
    +     * @return List of events types
    +     *
    +     * @url     GET dictionary/ticket_severities
    +     *
    +     * @throws RestException
    +     */
    +    function getTicketsSeverities($sortfield = "code", $sortorder = 'ASC', $limit = 100, $page = 0, $sqlfilters = '')
    +    {
    +    	$list = array();
    +
    +    	$sql = "SELECT rowid, code, pos,  label, use_default, color, description";
    +    	$sql.= " FROM ".MAIN_DB_PREFIX."c_ticket_severity as t";
    +    	$sql.= " WHERE t.active = 1";
    +    	// Add sql filters
    +    	if ($sqlfilters)
    +    	{
    +    		if (! DolibarrApi::_checkFilters($sqlfilters))
    +    		{
    +    			throw new RestException(503, 'Error when validating parameter sqlfilters '.$sqlfilters);
    +    		}
    +    		$regexstring='\(([^:\'\(\)]+:[^:\'\(\)]+:[^:\(\)]+)\)';
    +    		$sql.=" AND (".preg_replace_callback('/'.$regexstring.'/', 'DolibarrApi::_forge_criteria_callback', $sqlfilters).")";
    +    	}
    +
    +
    +    	$sql.= $this->db->order($sortfield, $sortorder);
    +
    +    	if ($limit) {
    +    		if ($page < 0) {
    +    			$page = 0;
    +    		}
    +    		$offset = $limit * $page;
    +
    +    		$sql .= $this->db->plimit($limit, $offset);
    +    	}
    +
    +    	$result = $this->db->query($sql);
    +
    +    	if ($result) {
    +    		$num = $this->db->num_rows($result);
    +    		$min = min($num, ($limit <= 0 ? $num : $limit));
    +    		for ($i = 0; $i < $min; $i++) {
    +    			$list[] = $this->db->fetch_object($result);
    +    		}
    +    	} else {
    +    		throw new RestException(503, 'Error when retrieving list of ticket severities : '.$this->db->lasterror());
    +    	}
    +
    +    	return $list;
    +    }
    +
    +    /**
    +     * Get the list of tickets types.
    +     *
    +     * @param string    $sortfield  Sort field
    +     * @param string    $sortorder  Sort order
    +     * @param int       $limit      Number of items per page
    +     * @param int       $page       Page number (starting from zero)
    +     * @param string    $sqlfilters Other criteria to filter answers separated by a comma. Syntax example "(t.code:like:'A%') and (t.active:>=:0)"
    +     * @return List of events types
    +     *
    +     * @url     GET dictionary/ticket_types
    +     *
    +     * @throws RestException
    +     */
    +    function getTicketsTypes($sortfield = "code", $sortorder = 'ASC', $limit = 100, $page = 0, $sqlfilters = '')
    +    {
    +    	$list = array();
    +
    +    	$sql = "SELECT rowid, code, pos,  label, use_default, description";
    +    	$sql.= " FROM ".MAIN_DB_PREFIX."c_ticket_type as t";
    +    	$sql.= " WHERE t.active = 1";
    +    	if ($type) $sql.=" AND t.type LIKE '%" . $this->db->escape($type) . "%'";
    +    	if ($module)    $sql.=" AND t.module LIKE '%" . $this->db->escape($module) . "%'";
    +    	// Add sql filters
    +    	if ($sqlfilters)
    +    	{
    +    		if (! DolibarrApi::_checkFilters($sqlfilters))
    +    		{
    +    			throw new RestException(503, 'Error when validating parameter sqlfilters '.$sqlfilters);
    +    		}
    +    		$regexstring='\(([^:\'\(\)]+:[^:\'\(\)]+:[^:\(\)]+)\)';
    +    		$sql.=" AND (".preg_replace_callback('/'.$regexstring.'/', 'DolibarrApi::_forge_criteria_callback', $sqlfilters).")";
    +    	}
    +
    +
    +    	$sql.= $this->db->order($sortfield, $sortorder);
    +
    +    	if ($limit) {
    +    		if ($page < 0) {
    +    			$page = 0;
    +    		}
    +    		$offset = $limit * $page;
    +
    +    		$sql .= $this->db->plimit($limit, $offset);
    +    	}
    +
    +    	$result = $this->db->query($sql);
    +
    +    	if ($result) {
    +    		$num = $this->db->num_rows($result);
    +    		$min = min($num, ($limit <= 0 ? $num : $limit));
    +    		for ($i = 0; $i < $min; $i++) {
    +    			$list[] = $this->db->fetch_object($result);
    +    		}
    +    	} else {
    +    		throw new RestException(503, 'Error when retrieving list of ticket types : '.$this->db->lasterror());
    +    	}
    +
    +    	return $list;
    +    }
    +
     
         /**
          * Do a test of integrity for files and setup.
    diff --git a/htdocs/asset/admin/assets_extrafields.php b/htdocs/asset/admin/assets_extrafields.php
    index 109b0f1e94f..f220d5cb849 100644
    --- a/htdocs/asset/admin/assets_extrafields.php
    +++ b/htdocs/asset/admin/assets_extrafields.php
    @@ -64,7 +64,7 @@ $linkback='<a href="'.DOL_URL_ROOT.'/admin/modules.php">'.$langs->trans("BackToM
     print load_fiche_titre($langs->trans("AssetsSetup"),$linkback,'title_setup');
     
     
    -$head = AssetsAdminPrepareHead();
    +$head = asset_admin_prepare_head();
     
     dol_fiche_head($head, 'attributes', $langs->trans("Assets"), -1, 'generic');
     
    diff --git a/htdocs/asset/admin/assets_type_extrafields.php b/htdocs/asset/admin/assets_type_extrafields.php
    index e8f1d71370b..a791078f37b 100644
    --- a/htdocs/asset/admin/assets_type_extrafields.php
    +++ b/htdocs/asset/admin/assets_type_extrafields.php
    @@ -63,7 +63,7 @@ $linkback='<a href="'.DOL_URL_ROOT.'/admin/modules.php">'.$langs->trans("BackToM
     print load_fiche_titre($langs->trans("AssetsSetup"),$linkback,'title_setup');
     
     
    -$head = AssetsAdminPrepareHead();
    +$head = asset_admin_prepare_head();
     
     dol_fiche_head($head, 'attributes_type', $langs->trans("Assets"), -1, 'generic');
     
    diff --git a/htdocs/asset/admin/setup.php b/htdocs/asset/admin/setup.php
    index 1168fd3ada3..57738309abd 100644
    --- a/htdocs/asset/admin/setup.php
    +++ b/htdocs/asset/admin/setup.php
    @@ -58,7 +58,7 @@ $linkback='<a href="'.DOL_URL_ROOT.'/admin/modules.php">'.$langs->trans("BackToM
     print load_fiche_titre($langs->trans("AssetsSetup"),$linkback,'title_setup');
     
     
    -$head = AssetsAdminPrepareHead();
    +$head = asset_admin_prepare_head();
     
     dol_fiche_head($head, 'settings', $langs->trans("Assets"), -1, 'generic');
     
    diff --git a/htdocs/asset/card.php b/htdocs/asset/card.php
    index 9af7638316f..4f7061aed20 100644
    --- a/htdocs/asset/card.php
    +++ b/htdocs/asset/card.php
    @@ -203,7 +203,7 @@ if ($object->id > 0 && (empty($action) || ($action != 'edit' && $action != 'crea
     {
     	$res = $object->fetch_optionals($object->id, $extralabels);
     
    -	$head = AssetsPrepareHead($object);
    +	$head = asset_prepare_head($object);
     	dol_fiche_head($head, 'card', $langs->trans("Asset"), -1, 'generic');
     
     	$formconfirm = '';
    diff --git a/htdocs/asset/class/asset.class.php b/htdocs/asset/class/asset.class.php
    index 8aee71b4926..8eeacdc1964 100644
    --- a/htdocs/asset/class/asset.class.php
    +++ b/htdocs/asset/class/asset.class.php
    @@ -106,6 +106,9 @@ class Asset extends CommonObject
     	 */
     	public $ref;
     
    +	/**
    +	 * @var int Entity
    +	 */
     	public $entity;
     
         /**
    @@ -129,9 +132,22 @@ class Asset extends CommonObject
     	public $note_private;
     	public $date_creation;
     	public $tms;
    +
    +	/**
    +     * @var int ID
    +     */
     	public $fk_user_creat;
    +
    +	/**
    +     * @var int ID
    +     */
     	public $fk_user_modif;
    +
     	public $import_key;
    +
    +	/**
    +	 * @var int Status
    +	 */
     	public $status;
     
     	// If this object has a subtable with lines
    diff --git a/htdocs/asset/class/asset_type.class.php b/htdocs/asset/class/asset_type.class.php
    index f1c6f9d771b..8eb915f95eb 100644
    --- a/htdocs/asset/class/asset_type.class.php
    +++ b/htdocs/asset/class/asset_type.class.php
    @@ -44,7 +44,11 @@ class AssetType extends CommonObject
     	 */
     	public $picto = 'group';
     
    -	public $ismultientitymanaged = 1;  // 0=No test on entity, 1=Test with field entity, 2=Test with link by societe
    +	/**
    +	 * 0=No test on entity, 1=Test with field entity, 2=Test with link by societe
    +	 * @var int
    +	 */
    +	public $ismultientitymanaged = 1;
     
     	/**
          * @var string Asset type label
    diff --git a/htdocs/asset/document.php b/htdocs/asset/document.php
    index 784f65aa220..c1332ed10a2 100644
    --- a/htdocs/asset/document.php
    +++ b/htdocs/asset/document.php
    @@ -95,7 +95,7 @@ if ($object->id)
     	 * Show tabs
     	 */
     	if (! empty($conf->notification->enabled)) $langs->load("mails");
    -	$head = AssetsPrepareHead($object);
    +	$head = asset_prepare_head($object);
     
     	dol_fiche_head($head, 'document', $langs->trans("Asset"), -1, 'generic');
     
    diff --git a/htdocs/asset/info.php b/htdocs/asset/info.php
    index 9cc9495c1b9..e01316ae685 100644
    --- a/htdocs/asset/info.php
    +++ b/htdocs/asset/info.php
    @@ -55,7 +55,7 @@ $form = new Form($db);
     
     $object->info($id);
     
    -$head = AssetsPrepareHead($object);
    +$head = asset_prepare_head($object);
     
     dol_fiche_head($head, 'info', $langs->trans("Asset"), -1, 'generic');
     
    diff --git a/htdocs/asset/list.php b/htdocs/asset/list.php
    index 7e59ad4647f..fa965aade5b 100644
    --- a/htdocs/asset/list.php
    +++ b/htdocs/asset/list.php
    @@ -317,7 +317,7 @@ include DOL_DOCUMENT_ROOT.'/core/tpl/massactions_pre.tpl.php';
     if ($sall)
     {
     	foreach($fieldstosearchall as $key => $val) $fieldstosearchall[$key]=$langs->trans($val);
    -	print '<div class="divsearchfieldfilter">'.$langs->trans("FilterOnInto", $all) . join(', ',$fieldstosearchall).'</div>';
    +	print '<div class="divsearchfieldfilter">'.$langs->trans("FilterOnInto", $sall) . join(', ',$fieldstosearchall).'</div>';
     }
     
     $moreforfilter = '';
    diff --git a/htdocs/asset/note.php b/htdocs/asset/note.php
    index e95e62aeaa4..f76c6ea028f 100644
    --- a/htdocs/asset/note.php
    +++ b/htdocs/asset/note.php
    @@ -78,7 +78,7 @@ if ($id > 0 || ! empty($ref))
     {
     	$object->fetch_thirdparty();
     
    -	$head = AssetsPrepareHead($object);
    +	$head = asset_prepare_head($object);
     
     	dol_fiche_head($head, 'note', $langs->trans("Asset"), -1, 'generic');
     
    diff --git a/htdocs/bookmarks/class/bookmark.class.php b/htdocs/bookmarks/class/bookmark.class.php
    index b7846cd0864..f66ef8e4d80 100644
    --- a/htdocs/bookmarks/class/bookmark.class.php
    +++ b/htdocs/bookmarks/class/bookmark.class.php
    @@ -29,21 +29,25 @@
     class Bookmark extends CommonObject
     {
         /**
    -	   * @var string ID to identify managed object
    -	   */
    -	  public $element='bookmark';
    +	 * @var string ID to identify managed object
    +	 */
    +	public $element='bookmark';
     
         /**
          * @var string Name of table without prefix where object is stored
          */
         public $table_element='bookmark';
     
    -    public $ismultientitymanaged = 1;	// 0=No test on entity, 1=Test with field entity, 2=Test with link by societe
    +    /**
    +	 * 0=No test on entity, 1=Test with field entity, 2=Test with link by societe
    +	 * @var int
    +	 */
    +    public $ismultientitymanaged = 1;
     
         /**
    -	   * @var string String with name of icon for myobject. Must be the part after the 'object_' into object_myobject.png
    -	   */
    -	  public $picto = 'bookmark';
    +	 * @var string String with name of icon for myobject. Must be the part after the 'object_' into object_myobject.png
    +	 */
    +	public $picto = 'bookmark';
     
         /**
          * @var DoliDB Database handler.
    @@ -56,15 +60,20 @@ class Bookmark extends CommonObject
         public $id;
     
         /**
    -	   * @var int User ID
    -	   */
    -	  public $fk_user;
    +	 * @var int User ID
    +	 */
    +	public $fk_user;
     
         public $datec;
    +
         public $url;
    +
         public $target;	// 0=replace, 1=new window
    +
         public $title;
    +
         public $position;
    +
         public $favicon;
     
     
    @@ -150,7 +159,7 @@ class Bookmark extends CommonObject
             $sql.= ", ".$this->db->escape($conf->entity);
             $sql.= ")";
     
    -        dol_syslog("Bookmark::update", LOG_DEBUG);
    +        dol_syslog("Bookmark::create", LOG_DEBUG);
             $resql = $this->db->query($sql);
             if ($resql)
             {
    diff --git a/htdocs/cashdesk/validation_verif.php b/htdocs/cashdesk/validation_verif.php
    index 05da0bdebe1..b42bc90d8fb 100644
    --- a/htdocs/cashdesk/validation_verif.php
    +++ b/htdocs/cashdesk/validation_verif.php
    @@ -216,6 +216,7 @@ switch ($action)
     		$invoice->cond_reglement_id=$cond_reglement_id;
     		$invoice->mode_reglement_id=$mode_reglement_id;
     		$invoice->module_source = 'cashdesk';
    +		$invoice->pos_source = '0';
     		//print "c=".$invoice->cond_reglement_id." m=".$invoice->mode_reglement_id; exit;
     
     		// Si paiement differe ...
    diff --git a/htdocs/categories/class/categorie.class.php b/htdocs/categories/class/categorie.class.php
    index 8f09710854f..a7ddab761e0 100644
    --- a/htdocs/categories/class/categorie.class.php
    +++ b/htdocs/categories/class/categorie.class.php
    @@ -10,6 +10,7 @@
      * Copyright (C) 2015       Marcos García           <marcosgdf@gmail.com>
      * Copyright (C) 2015       Raphaël Doursenaud      <rdoursenaud@gpcsolutions.fr>
      * Copyright (C) 2016       Charlie Benke           <charlie@patas-monkey.com>
    + * Copyright (C) 2018       Frédéric France         <frederic.france@netlogic.fr>
      *
      * This program is free software; you can redistribute it and/or modify
      * it under the terms of the GNU General Public License as published by
    @@ -75,6 +76,10 @@ class Categorie extends CommonObject
     		'user'         => 7,
     		'bank_line'    => 8,
     	);
    +
    +    /**
    +	 * @var array Code mapping from ID
    +	 */
     	public static $MAP_ID_TO_CODE = array(
     		0 => 'product',
     		1 => 'supplier',
    @@ -103,7 +108,8 @@ class Categorie extends CommonObject
             'bank_account' => 'account',
             'project'  => 'project',
     	);
    -	/**
    +
    +    /**
     	 * @var array Category tables mapping from type string
     	 *
     	 * @note Move to const array when PHP 5.6 will be our minimum target
    @@ -119,7 +125,8 @@ class Categorie extends CommonObject
             'bank_account'=> 'account',
             'project'  => 'project',
     	);
    -	/**
    +
    +    /**
     	 * @var array Object class mapping from type string
     	 *
     	 * @note Move to const array when PHP 5.6 will be our minimum target
    @@ -135,7 +142,8 @@ class Categorie extends CommonObject
     		'bank_account'  => 'Account',
             'project'  => 'Project',
     	);
    -	/**
    +
    +    /**
     	 * @var array Object table mapping from type string
     	 *
     	 * @note Move to const array when PHP 5.6 will be our minimum target
    @@ -161,6 +169,9 @@ class Categorie extends CommonObject
     	 */
     	public $table_element='categorie';
     
    +	/**
    +     * @var int ID
    +     */
     	public $fk_parent;
     
     	/**
    @@ -195,7 +206,14 @@ class Categorie extends CommonObject
     	 */
     	public $type;
     
    -	public $cats = array();			// Categories table in memory
    +	/**
    +	 * @var array Categories table in memory
    +	 */
    +	public $cats = array();
    +
    +    /**
    +	 * @var array Mother of table
    +	 */
     	public $motherof = array();
     
     	/**
    @@ -802,7 +820,7 @@ class Categorie extends CommonObject
     	 * @param	string	$sortorder	Sort order
     	 * @param	int		$limit		Limit for list
     	 * @param	int		$page		Page number
    -	 * @return	array				Array of categories
    +	 * @return	array|int			Array of categories, 0 if no cat, -1 on error
     	 */
     	function getListForItem($id, $type='customer', $sortfield = "s.rowid", $sortorder = 'ASC', $limit = 0, $page = 0)
     	{
    @@ -971,7 +989,7 @@ class Categorie extends CommonObject
     	 * @param   string 	$type        	Type of categories ('customer', 'supplier', 'contact', 'product', 'member') or (0, 1, 2, ...).
     	 * @param   int    	$markafterid 	Removed all categories including the leaf $markafterid in category tree.
     	 *
    -	 * @return  array               	Array of categories. this->cats and this->motherof are set.
    +	 * @return  array|int               Array of categories. this->cats and this->motherof are set, -1 on error
     	 */
     	function get_full_arbo($type, $markafterid=0)
     	{
    @@ -1123,7 +1141,7 @@ class Categorie extends CommonObject
     	 *
     	 *	@param	int			$type		Type of category (0, 1, ...)
     	 *	@param	boolean		$parent		Just parent categories if true
    -	 *	@return	array					Table of Object Category
    +	 *	@return	array|int				Table of Object Category, -1 on error
     	 */
     	function get_all_categories($type=null, $parent=false)
     	{
    @@ -1356,7 +1374,7 @@ class Categorie extends CommonObject
     	 * @param   string|int	$type   Type of category ('customer', 'supplier', 'contact', 'product', 'member') or (0, 1, 2, ...)
     	 * @param   string 		$mode   'id'=Get array of category ids, 'object'=Get array of fetched category instances, 'label'=Get array of category
     	 *                      	    labels, 'id'= Get array of category IDs
    -	 * @return  mixed           	Array of category objects or < 0 if KO
    +	 * @return  array|int           Array of category objects or < 0 if KO
     	 */
     	function containing($id, $type, $mode='object')
     	{
    @@ -1438,7 +1456,7 @@ class Categorie extends CommonObject
      	 * 	@param		string		$type		Type of category ('member', 'customer', 'supplier', 'product', 'contact'). Old mode (0, 1, 2, ...) is deprecated.
     	 * 	@param		boolean		$exact		Exact string search (true/false)
     	 * 	@param		boolean		$case		Case sensitive (true/false)
    -	 * 	@return		array					Array of category id
    +	 * 	@return		array|int				Array of category id, -1 if error
     	 */
     	function rechercher($id, $nom, $type, $exact = false, $case = false)
     	{
    diff --git a/htdocs/categories/index.php b/htdocs/categories/index.php
    index 18112f13eba..316a21892af 100644
    --- a/htdocs/categories/index.php
    +++ b/htdocs/categories/index.php
    @@ -82,6 +82,8 @@ print '<div class="fichecenter"><div class="fichethirdleft">';
     print '<form method="post" action="index.php?type='.$type.'">';
     print '<input type="hidden" name="token" value="'.$_SESSION['newtoken'].'">';
     print '<input type="hidden" name="type" value="'.$type.'">';
    +
    +
     print '<table class="noborder nohover" width="100%">';
     print '<tr class="liste_titre">';
     print '<td colspan="3">'.$langs->trans("Search").'</td>';
    diff --git a/htdocs/comm/action/card.php b/htdocs/comm/action/card.php
    index f968f9800e9..fd0a4a2b430 100644
    --- a/htdocs/comm/action/card.php
    +++ b/htdocs/comm/action/card.php
    @@ -1705,7 +1705,7 @@ if ($id > 0)
     	        $delallowed=$user->rights->agenda->myactions->create;
     
     
    -            print $formfile->showdocuments('agenda',$object->id,$filedir,$urlsource,$genallowed,$delallowed,'',0,0,0,0,0,'','','',$object->default_lang);
    +            print $formfile->showdocuments('actions',$object->id,$filedir,$urlsource,$genallowed,$delallowed,'',0,0,0,0,0,'','','',$object->default_lang);
     
     			print '</div><div class="fichehalfright"><div class="ficheaddleft">';
     
    diff --git a/htdocs/comm/action/class/actioncomm.class.php b/htdocs/comm/action/class/actioncomm.class.php
    index c175ad900ea..4a6cec809fe 100644
    --- a/htdocs/comm/action/class/actioncomm.class.php
    +++ b/htdocs/comm/action/class/actioncomm.class.php
    @@ -1,10 +1,11 @@
     <?php
    -/* Copyright (C) 2002-2004 Rodolphe Quiedeville <rodolphe@quiedeville.org>
    - * Copyright (C) 2004-2011 Laurent Destailleur  <eldy@users.sourceforge.net>
    - * Copyright (C) 2005-2012 Regis Houssin        <regis.houssin@capnetworks.com>
    - * Copyright (C) 2011-2017 Juanjo Menent        <jmenent@2byte.es>
    - * Copyright (C) 2015	   Marcos García		<marcosgdf@gmail.com>
    - * Copyright (C) 2018	   Nicolas ZABOURI	<info@inovea-conseil.com>
    +/* Copyright (C) 2002-2004  Rodolphe Quiedeville    <rodolphe@quiedeville.org>
    + * Copyright (C) 2004-2011  Laurent Destailleur     <eldy@users.sourceforge.net>
    + * Copyright (C) 2005-2012  Regis Houssin           <regis.houssin@capnetworks.com>
    + * Copyright (C) 2011-2017  Juanjo Menent           <jmenent@2byte.es>
    + * Copyright (C) 2015	    Marcos García		    <marcosgdf@gmail.com>
    + * Copyright (C) 2018	    Nicolas ZABOURI	        <info@inovea-conseil.com>
    + * Copyright (C) 2018       Frédéric France         <frederic.france@netlogic.fr>
      *
      * This program is free software; you can redistribute it and/or modify
      * it under the terms of the GNU General Public License as published by
    @@ -67,7 +68,7 @@ class ActionComm extends CommonObject
          * Id of the event
          * @var int
          */
    -	  public $id;
    +    public $id;
     
         /**
          * Id of the event. Use $id as possible
    @@ -75,26 +76,20 @@ class ActionComm extends CommonObject
          */
         public $ref;
     
    -    var $type_id;		// Id into parent table llx_c_actioncomm (used only if option to use type is set)
    -    var $type_code;		// Code into parent table llx_c_actioncomm (used only if option to use type is set). With default setup, should be AC_OTH_AUTO or AC_OTH.
    -    var $type;			// Label into parent table llx_c_actioncomm (used only if option to use type is set)
    -    var $type_color;	// Color into parent table llx_c_actioncomm (used only if option to use type is set)
    -    var $code;			// Free code to identify action. Ie: Agenda trigger add here AC_TRIGGERNAME ('AC_COMPANY_CREATE', 'AC_PROPAL_VALIDATE', ...)
    +    public $type_id;		// Id into parent table llx_c_actioncomm (used only if option to use type is set)
    +    public $type_code;		// Code into parent table llx_c_actioncomm (used only if option to use type is set). With default setup, should be AC_OTH_AUTO or AC_OTH.
    +    public $type_label;
    +    public $type;			// Label into parent table llx_c_actioncomm (used only if option to use type is set)
    +    public $type_color;	// Color into parent table llx_c_actioncomm (used only if option to use type is set)
    +    public $code;			// Free code to identify action. Ie: Agenda trigger add here AC_TRIGGERNAME ('AC_COMPANY_CREATE', 'AC_PROPAL_VALIDATE', ...)
     
         /**
          * @var string Agenda event label
          */
         public $label;
     
    -    /**
    -     * @var string
    -     * @deprecated Use $label
    -     * @see label
    -     */
    -    public $libelle;
    -
    -    var $datec;			// Date creation record (datec)
    -    var $datem;			// Date modification record (tms)
    +    public $datec;			// Date creation record (datec)
    +    public $datem;			// Date modification record (tms)
     
         /**
          * Object user that create action
    @@ -102,7 +97,7 @@ class ActionComm extends CommonObject
          * @deprecated
          * @see authorid
          */
    -    var $author;
    +    public $author;
     
         /**
          * Object user that modified action
    @@ -110,39 +105,49 @@ class ActionComm extends CommonObject
          * @deprecated
          * @see usermodid
          */
    -    var $usermod;
    -    var $authorid;		// Id user that create action
    -    var $usermodid;		// Id user that modified action
    +    public $usermod;
     
    -    var $datep;			// Date action start (datep)
    -    var $datef;			// Date action end (datep2)
    +    /**
    +     * Id user that create action
    +     * @var int
    +     */
    +    public $authorid;
    +
    +    /**
    +     * Id user that modified action
    +     * @var int
    +     */
    +    public $usermodid;
    +
    +    public $datep;			// Date action start (datep)
    +    public $datef;			// Date action end (datep2)
     
         /**
          * @var int -1=Unkown duration
          * @deprecated
          */
    -    var $durationp = -1;
    -    var $fulldayevent = 0;    // 1=Event on full day
    +    public $durationp = -1;
    +    public $fulldayevent = 0;    // 1=Event on full day
     
         /**
          * Milestone
          * @var int
          * @deprecated Milestone is already event with end date = start date
          */
    -    var $punctual = 1;
    -    var $percentage;    // Percentage
    -    var $location;      // Location
    +    public $punctual = 1;
    +    public $percentage;    // Percentage
    +    public $location;      // Location
     
    -	var $transparency;	// Transparency (ical standard). Used to say if people assigned to event are busy or not by event. 0=available, 1=busy, 2=busy (refused events)
    -    var $priority;      // Small int (0 By default)
    +	public $transparency;	// Transparency (ical standard). Used to say if people assigned to event are busy or not by event. 0=available, 1=busy, 2=busy (refused events)
    +    public $priority;      // Small int (0 By default)
     
    -	var $userassigned = array();	// Array of user ids
    -    var $userownerid;	// Id of user owner = fk_user_action into table
    -    var $userdoneid;	// Id of user done (deprecated)
    +	public $userassigned = array();	// Array of user ids
    +    public $userownerid;	// Id of user owner = fk_user_action into table
    +    public $userdoneid;	// Id of user done (deprecated)
     
    -    var $socpeopleassigned = array(); // Array of contact ids
    +    public $socpeopleassigned = array(); // Array of contact ids
     
    -    var $otherassigned = array(); // Array of other contact emails (not user, not contact)
    +    public $otherassigned = array(); // Array of other contact emails (not user, not contact)
     
     
     	/**
    @@ -151,7 +156,7 @@ class ActionComm extends CommonObject
          * @deprecated
          * @see userownerid
          */
    -    var $usertodo;
    +    public $usertodo;
     
         /**
          * Object user that did action
    @@ -159,10 +164,10 @@ class ActionComm extends CommonObject
          * @deprecated
          * @see userdoneid
          */
    -    var $userdone;
    +    public $userdone;
     
    -    var $socid;
    -    var $contactid;
    +    public $socid;
    +    public $contactid;
     
         /**
          * Company linked to action (optional)
    @@ -170,7 +175,7 @@ class ActionComm extends CommonObject
          * @deprecated
          * @see socid
          */
    -    var $societe;
    +    public $societe;
     
         /**
          * Contact linked to action (optional)
    @@ -178,28 +183,28 @@ class ActionComm extends CommonObject
          * @deprecated
          * @see contactid
          */
    -    var $contact;
    +    public $contact;
     
         // Properties for links to other objects
    -    var $fk_element;    // Id of record
    -    var $elementid;    // Id of record alternative for API
    -    var $elementtype;   // Type of record. This if property ->element of object linked to.
    +    public $fk_element;    // Id of record
    +    public $elementid;    // Id of record alternative for API
    +    public $elementtype;   // Type of record. This if property ->element of object linked to.
     
         // Ical
    -    var $icalname;
    -    var $icalcolor;
    +    public $icalname;
    +    public $icalcolor;
     
    -    var $actions=array();
    +    public $actions=array();
     
         // Fields for emails
    -    var $email_msgid;
    -    var $email_from;
    -    var $email_sender;
    -    var $email_to;
    -    var $email_tocc;
    -    var $email_tobcc;
    -    var $email_subject;
    -    var $errors_to;
    +    public $email_msgid;
    +    public $email_from;
    +    public $email_sender;
    +    public $email_to;
    +    public $email_tocc;
    +    public $email_tobcc;
    +    public $email_subject;
    +    public $errors_to;
     
     
         /**
    @@ -339,7 +344,7 @@ class ActionComm extends CommonObject
             $sql.= ($code?("'".$code."'"):"null").", ";
             $sql.= ((isset($this->socid) && $this->socid > 0) ? $this->socid:"null").", ";
             $sql.= ((isset($this->fk_project) && $this->fk_project > 0) ? $this->fk_project:"null").", ";
    -        $sql.= " '".$this->db->escape($this->note)."', ";
    +        $sql.= " '".$this->db->escape($this->note_private?$this->note_private:$this->note)."', ";
             $sql.= ((isset($this->contactid) && $this->contactid > 0) ? $this->contactid:"null").", ";
             $sql.= (isset($user->id) && $user->id > 0 ? $user->id:"null").", ";
             $sql.= ($userownerid>0 ? $userownerid:"null").", ";
    @@ -609,6 +614,7 @@ class ActionComm extends CommonObject
                     $this->datem   				= $this->db->jdate($obj->datem);
     
                     $this->note					= $obj->note;
    +                $this->note_private			= $obj->note;
                     $this->percentage			= $obj->percentage;
     
                     $this->authorid             = $obj->fk_user_author;
    @@ -858,7 +864,7 @@ class ActionComm extends CommonObject
             $sql.= ", datep = ".(strval($this->datep)!='' ? "'".$this->db->idate($this->datep)."'" : 'null');
             $sql.= ", datep2 = ".(strval($this->datef)!='' ? "'".$this->db->idate($this->datef)."'" : 'null');
             $sql.= ", durationp = ".(isset($this->durationp) && $this->durationp >= 0 && $this->durationp != ''?"'".$this->db->escape($this->durationp)."'":"null");	// deprecated
    -        $sql.= ", note = ".($this->note ? "'".$this->db->escape($this->note)."'":"null");
    +        $sql.= ", note = '".$this->db->escape($this->note_private?$this->note_private:$this->note)."'";
             $sql.= ", fk_project =". ($this->fk_project > 0 ? $this->fk_project:"null");
             $sql.= ", fk_soc =". ($socid > 0 ? $socid:"null");
             $sql.= ", fk_contact =". ($contactid > 0 ? $contactid:"null");
    diff --git a/htdocs/comm/action/class/actioncommreminder.class.php b/htdocs/comm/action/class/actioncommreminder.class.php
    index 6c9632d83e5..6631d0e375d 100644
    --- a/htdocs/comm/action/class/actioncommreminder.class.php
    +++ b/htdocs/comm/action/class/actioncommreminder.class.php
    @@ -81,7 +81,12 @@ class ActionCommReminder extends CommonObject
     		'offsetunit' => array('type'=>'varchar(1)', 'label'=>'OffsetUnit', 'visible'=>1, 'enabled'=>1, 'position'=>57, 'notnull'=>1, 'comment'=>"m, h, d, w",),
     		'status' => array('type'=>'integer', 'label'=>'Status', 'visible'=>1, 'enabled'=>1, 'position'=>1000, 'notnull'=>1, 'default'=>0, 'index'=>0, 'arrayofkeyval'=>array('0'=>'ToDo', '1'=>'Done')),
     	);
    +
    +	/**
    +	 * @var int ID
    +	 */
     	public $rowid;
    +
     	public $dateremind;
     	public $typeremind;
     
    @@ -92,7 +97,12 @@ class ActionCommReminder extends CommonObject
     
     	public $offsetvalue;
     	public $offsetunit;
    +
    +	/**
    +	 * @var int Status
    +	 */
     	public $status;
    +
     	// END MODULEBUILDER PROPERTIES
     
     
    diff --git a/htdocs/comm/action/index.php b/htdocs/comm/action/index.php
    index b6e02861c9b..4ffa4298d20 100644
    --- a/htdocs/comm/action/index.php
    +++ b/htdocs/comm/action/index.php
    @@ -1596,13 +1596,13 @@ function show_day_events($db, $day, $month, $year, $monthshown, $style, &$eventa
                                     $cachecontacts[$event->contact->id]=$contact;
                                 }
                                 else $contact=$cachecontacts[$event->contact->id];
    -                            if ($linerelatedto) $linerelatedto.=' / ';
    +                            if ($linerelatedto) $linerelatedto.='&nbsp;';
                                 if (! empty($contact->id)) $linerelatedto.=$contact->getNomUrl(1,'',0);
                             }
                             if (! empty($event->fk_element) && $event->fk_element > 0 && ! empty($event->elementtype) && ! empty($conf->global->AGENDA_SHOW_LINKED_OBJECT))
                             {
                                 include_once DOL_DOCUMENT_ROOT.'/core/lib/functions2.lib.php';
    -                            if ($linerelatedto) $linerelatedto.=' / ';
    +                            if ($linerelatedto) $linerelatedto.='<br>';
                                 $linerelatedto.=dolGetElementUrl($event->fk_element,$event->elementtype,1);
                             }
                             if ($linerelatedto) print '<br>'.$linerelatedto;
    diff --git a/htdocs/comm/propal/card.php b/htdocs/comm/propal/card.php
    index b87c1b0c066..1e6df0b014f 100644
    --- a/htdocs/comm/propal/card.php
    +++ b/htdocs/comm/propal/card.php
    @@ -348,13 +348,13 @@ if (empty($reshook))
     			// If we select proposal to clone during creation (when option PROPAL_CLONE_ON_CREATE_PAGE is on)
     			if (GETPOST('createmode') == 'copy' && GETPOST('copie_propal'))
     			{
    -				if ($object->fetch(GETPOST('copie_propal')) > 0) {
    +				if ($object->fetch(GETPOST('copie_propal','int')) > 0) {
     					$object->ref = GETPOST('ref');
     					$object->datep = $datep;
     					$object->date_livraison = $date_delivery;
     					$object->availability_id = GETPOST('availability_id');
     					$object->demand_reason_id = GETPOST('demand_reason_id');
    -					$object->fk_delivery_address = GETPOST('fk_address');
    +					$object->fk_delivery_address = GETPOST('fk_address','int');
     					$object->shipping_method_id = GETPOST('shipping_method_id', 'int');
     					$object->duree_validite = $duration;
     					$object->cond_reglement_id = GETPOST('cond_reglement_id');
    @@ -362,9 +362,9 @@ if (empty($reshook))
     					$object->fk_account = GETPOST('fk_account', 'int');
     					$object->remise_percent = GETPOST('remise_percent');
     					$object->remise_absolue = GETPOST('remise_absolue');
    -					$object->socid = GETPOST('socid');
    -					$object->contactid = GETPOST('contactid');
    -					$object->fk_project = GETPOST('projectid');
    +					$object->socid = GETPOST('socid','int');
    +					$object->contactid = GETPOST('contactid','int');
    +					$object->fk_project = GETPOST('projectid','int');
     					$object->modelpdf = GETPOST('model');
     					$object->author = $user->id; // deprecated
     					$object->note_private = GETPOST('note_private','none');
    @@ -391,8 +391,8 @@ if (empty($reshook))
     				$object->cond_reglement_id = GETPOST('cond_reglement_id');
     				$object->mode_reglement_id = GETPOST('mode_reglement_id');
     				$object->fk_account = GETPOST('fk_account', 'int');
    -				$object->contactid = GETPOST('contactid');
    -				$object->fk_project = GETPOST('projectid');
    +				$object->contactid = GETPOST('contactid','int');
    +				$object->fk_project = GETPOST('projectid','int');
     				$object->modelpdf = GETPOST('model');
     				$object->author = $user->id; // deprecated
     				$object->note_private = GETPOST('note_private','none');
    @@ -566,6 +566,16 @@ if (empty($reshook))
     						}
     					}
     
    +					if (! empty($conf->global->PROPOSAL_AUTO_ADD_AUTHOR_AS_CONTACT))
    +					{
    +						$result = $object->add_contact($user->id, 'SALESREPFOLL', 'internal');
    +						if ($result < 0)
    +						{
    +							$error++;
    +							setEventMessages($langs->trans("ErrorFailedToAddUserAsContact"), null, 'errors');
    +						}
    +					}
    +
     					if (! $error)
     					{
     						$db->commit();
    @@ -610,12 +620,23 @@ if (empty($reshook))
     	// Classify billed
     	else if ($action == 'classifybilled' && $usercanclose)
     	{
    +		$db->begin();
    +
     		$result=$object->cloture($user, 4, '');
     		if ($result < 0)
     		{
     			setEventMessages($object->error, $object->errors, 'errors');
     			$error++;
     		}
    +
    +		if (! $error)
    +		{
    +			$db->commit();
    +		}
    +		else
    +		{
    +			$db->rollback();
    +		}
     	}
     
     	// Close proposal
    @@ -628,12 +649,23 @@ if (empty($reshook))
     			// prevent browser refresh from closing proposal several times
     			if ($object->statut == Propal::STATUS_VALIDATED)
     			{
    +				$db->begin();
    +
     				$result=$object->cloture($user, GETPOST('statut','int'), GETPOST('note_private','none'));
     				if ($result < 0)
     				{
     					setEventMessages($object->error, $object->errors, 'errors');
     					$error++;
     				}
    +
    +				if (! $error)
    +				{
    +					$db->commit();
    +				}
    +				else
    +				{
    +					$db->rollback();
    +				}
     			}
     		}
     	}
    @@ -644,12 +676,23 @@ if (empty($reshook))
     		// prevent browser refresh from reopening proposal several times
     		if ($object->statut == Propal::STATUS_SIGNED || $object->statut == Propal::STATUS_NOTSIGNED || $object->statut == Propal::STATUS_BILLED)
     		{
    +			$db->begin();
    +
     			$result=$object->reopen($user, 1);
     			if ($result < 0)
     			{
     				setEventMessages($object->error, $object->errors, 'errors');
     				$error++;
     			}
    +
    +			if (! $error)
    +			{
    +				$db->commit();
    +			}
    +			else
    +			{
    +				$db->rollback();
    +			}
     		}
     	}
     
    @@ -932,6 +975,7 @@ if (empty($reshook))
     				// Add custom code and origin country into description
     				if (empty($conf->global->MAIN_PRODUCT_DISABLE_CUSTOMCOUNTRYCODE) && (! empty($prod->customcode) || ! empty($prod->country_code)))
     				{
    +					$tmptxt = '(';
     					// Define output language
     					if (! empty($conf->global->MAIN_MULTILANGS) && ! empty($conf->global->PRODUIT_TEXTS_IN_THIRDPARTY_LANGUAGE)) {
     						$outputlangs = $langs;
    diff --git a/htdocs/comm/propal/class/propal.class.php b/htdocs/comm/propal/class/propal.class.php
    index 263a425ff01..16a19d1b41f 100644
    --- a/htdocs/comm/propal/class/propal.class.php
    +++ b/htdocs/comm/propal/class/propal.class.php
    @@ -168,7 +168,12 @@ class Propal extends CommonObject
     	public $remise = 0;
     	public $remise_percent = 0;
     	public $remise_absolue = 0;
    +
    +	/**
    +     * @var int ID
    +     */
     	public $fk_address;
    +
     	public $address_type;
     	public $address;
     	public $availability_id;
    @@ -191,7 +196,11 @@ class Propal extends CommonObject
     	public $specimen;
     
     	// Multicurrency
    +	/**
    +     * @var int ID
    +     */
     	public $fk_multicurrency;
    +
     	public $multicurrency_code;
     	public $multicurrency_tx;
     	public $multicurrency_total_ht;
    @@ -2467,16 +2476,16 @@ class Propal extends CommonObject
     
     			if (empty($conf->global->MAIN_DISABLE_PDF_AUTOUPDATE))
     			{
    -			 	// Define output language
    -			  	$outputlangs = $langs;
    -			   	if (! empty($conf->global->MAIN_MULTILANGS))
    -			   	{
    -			   		$outputlangs = new Translate("",$conf);
    -			   		$newlang=(GETPOST('lang_id','aZ09') ? GETPOST('lang_id','aZ09') : $this->thirdparty->default_lang);
    -			   		$outputlangs->setDefaultLang($newlang);
    -			   	}
    -			   	//$ret=$object->fetch($id);    // Reload to get new records
    -				   $this->generateDocument($modelpdf, $outputlangs);
    +				// Define output language
    +				$outputlangs = $langs;
    +				if (! empty($conf->global->MAIN_MULTILANGS))
    +				{
    +					$outputlangs = new Translate("",$conf);
    +					$newlang=(GETPOST('lang_id','aZ09') ? GETPOST('lang_id','aZ09') : $this->thirdparty->default_lang);
    +					$outputlangs->setDefaultLang($newlang);
    +				}
    +				//$ret=$object->fetch($id);    // Reload to get new records
    +				$this->generateDocument($modelpdf, $outputlangs);
     			}
     
     			if (! $error)
    @@ -2484,7 +2493,7 @@ class Propal extends CommonObject
     				$this->oldcopy= clone $this;
     				$this->statut = $statut;
     				$this->date_cloture = $now;
    -				$this->note_private = $note;
    +				$this->note_private = $newprivatenote;
     			}
     
     			if (! $notrigger && empty($error))
    @@ -2495,13 +2504,17 @@ class Propal extends CommonObject
     				// End call triggers
     			}
     
    -			if ( ! $error )
    +			if (! $error)
     			{
     				$this->db->commit();
     				return 1;
     			}
     			else
     			{
    +				$this->statut = $this->oldcopy->statut;
    +				$this->date_cloture = $this->oldcopy->date_cloture;
    +				$this->note_private = $this->oldcopy->note_private;
    +
     				$this->db->rollback();
     				return -1;
     			}
    @@ -3162,7 +3175,7 @@ class Propal extends CommonObject
     			$this->labelstatut[3]=$langs->trans("PropalStatusNotSigned");
     			$this->labelstatut[4]=$langs->trans("PropalStatusBilled");
     			$this->labelstatut_short[0]=$langs->trans("PropalStatusDraftShort");
    -			$this->labelstatut_short[1]=$langs->trans("Opened");
    +			$this->labelstatut_short[1]=$langs->trans("PropalStatusValidatedShort");
     			$this->labelstatut_short[2]=$langs->trans("PropalStatusSignedShort");
     			$this->labelstatut_short[3]=$langs->trans("PropalStatusNotSignedShort");
     			$this->labelstatut_short[4]=$langs->trans("PropalStatusBilledShort");
    diff --git a/htdocs/comm/propal/list.php b/htdocs/comm/propal/list.php
    index dc6e4aff17b..bc45d022e4d 100644
    --- a/htdocs/comm/propal/list.php
    +++ b/htdocs/comm/propal/list.php
    @@ -491,7 +491,7 @@ if ($resql)
     	if ($sall)
     	{
     		foreach($fieldstosearchall as $key => $val) $fieldstosearchall[$key]=$langs->trans($val);
    -		print '<div class="divsearchfieldfilter">'.$langs->trans("FilterOnInto", $all) . join(', ',$fieldstosearchall).'</div>';
    +		print '<div class="divsearchfieldfilter">'.$langs->trans("FilterOnInto", $sall) . join(', ',$fieldstosearchall).'</div>';
     	}
     
     	$i = 0;
    diff --git a/htdocs/commande/class/commande.class.php b/htdocs/commande/class/commande.class.php
    index 39b0f0db2ee..1925b71992e 100644
    --- a/htdocs/commande/class/commande.class.php
    +++ b/htdocs/commande/class/commande.class.php
    @@ -111,6 +111,9 @@ class Commande extends CommonOrder
     	public $brouillon;
     	public $cond_reglement_code;
     
    +	/**
    +     * @var int ID
    +     */
     	public $fk_account;
     
     	/**
    @@ -152,7 +155,7 @@ class Commande extends CommonOrder
     	public $demand_reason_id;   // Source reason. Why we receive order (after a phone campaign, ...)
     	public $demand_reason_code;
     	public $date;				// Date commande
    -
    +  
     	/**
     	 * @deprecated
     	 * @see date
    @@ -160,7 +163,12 @@ class Commande extends CommonOrder
     	public $date_commande;
     
     	public $date_livraison;	    // Date expected of shipment (date starting shipment, not the reception that occurs some days after)
    +
    +	/**
    +     * @var int ID
    +     */
     	public $fk_remise_except;
    +
     	public $remise_percent;
     	public $remise_absolue;
     	public $info_bits;
    @@ -180,7 +188,11 @@ class Commande extends CommonOrder
     	public $lines = array();
     
     	// Multicurrency
    +	/**
    +     * @var int ID
    +     */
     	public $fk_multicurrency;
    +
     	public $multicurrency_code;
     	public $multicurrency_tx;
     	public $multicurrency_total_ht;
    @@ -1608,7 +1620,7 @@ class Commande extends CommonOrder
     		$sql = 'SELECT c.rowid, c.entity, c.date_creation, c.ref, c.fk_soc, c.fk_user_author, c.fk_user_valid, c.fk_statut';
     		$sql.= ', c.amount_ht, c.total_ht, c.total_ttc, c.tva as total_tva, c.localtax1 as total_localtax1, c.localtax2 as total_localtax2, c.fk_cond_reglement, c.fk_mode_reglement, c.fk_availability, c.fk_input_reason';
     		$sql.= ', c.fk_account';
    -		$sql.= ', c.date_commande';
    +		$sql.= ', c.date_commande, c.date_valid, c.tms';
     		$sql.= ', c.date_livraison';
     		$sql.= ', c.fk_shipping_method';
     		$sql.= ', c.fk_warehouse';
    @@ -1661,6 +1673,9 @@ class Commande extends CommonOrder
     				$this->total_ttc			= $obj->total_ttc;
     				$this->date					= $this->db->jdate($obj->date_commande);
     				$this->date_commande		= $this->db->jdate($obj->date_commande);
    +				$this->date_creation		= $this->db->jdate($obj->date_creation);
    +				$this->date_validation		= $this->db->jdate($obj->date_valid);
    +				$this->date_modification		= $this->db->jdate($obj->tms);
     				$this->remise				= $obj->remise;
     				$this->remise_percent		= $obj->remise_percent;
     				$this->remise_absolue		= $obj->remise_absolue;
    diff --git a/htdocs/commande/list.php b/htdocs/commande/list.php
    index 558d8186a86..0e851c78cff 100644
    --- a/htdocs/commande/list.php
    +++ b/htdocs/commande/list.php
    @@ -529,7 +529,7 @@ if ($resql)
     	if ($sall)
     	{
     		foreach($fieldstosearchall as $key => $val) $fieldstosearchall[$key]=$langs->trans($val);
    -		print '<div class="divsearchfieldfilter">'.$langs->trans("FilterOnInto", $all) . join(', ',$fieldstosearchall).'</div>';
    +		print '<div class="divsearchfieldfilter">'.$langs->trans("FilterOnInto", $sall) . join(', ',$fieldstosearchall).'</div>';
     	}
     
     	$moreforfilter='';
    diff --git a/htdocs/compta/bank/bankentries_list.php b/htdocs/compta/bank/bankentries_list.php
    index 081d674a6a3..31eaa9e8f6d 100644
    --- a/htdocs/compta/bank/bankentries_list.php
    +++ b/htdocs/compta/bank/bankentries_list.php
    @@ -204,12 +204,12 @@ if (empty($reshook))
     }
     
     // Conciliation
    -if (GETPOST('confirm_reconcile') && $user->rights->banque->consolidate)
    +if ((GETPOST('confirm_savestatement','alpha') || GETPOST('confirm_reconcile','alpha')) && $user->rights->banque->consolidate)
     {
         $error=0;
     
         // Definition, nettoyage parametres
    -    $num_releve=trim(GETPOST("num_releve"));
    +    $num_releve=trim(GETPOST("num_releve","alpha"));
     
         if ($num_releve)
         {
    @@ -222,7 +222,7 @@ if (GETPOST('confirm_reconcile') && $user->rights->banque->consolidate)
                     {
                         $result=$bankline->fetch($row);
                         $bankline->num_releve=$num_releve; //$_POST["num_releve"];
    -                    $result=$bankline->update_conciliation($user, GETPOST("cat"));
    +                    $result=$bankline->update_conciliation($user, GETPOST("cat"), GETPOST('confirm_reconcile','alpha')?1:0);	// If we confirm_reconcile, we set flag 'rappro' to 1.
                         if ($result < 0)
                         {
                             setEventMessages($bankline->error, $bankline->errors, 'errors');
    @@ -248,7 +248,21 @@ if (GETPOST('confirm_reconcile') && $user->rights->banque->consolidate)
     
         if (! $error)
         {
    -        header('Location: '.$_SERVER["PHP_SELF"].'?id='.$id);	// To avoid to submit twice and allow back
    +    	$param='action=reconcile&contextpage=banktransactionlist&id='.$id.'&search_account='.$id;
    +		$param.='&search_conciliated='.urlencode($search_conciliated);
    +		if ($page) $param.='&page='.urlencode($page);
    +		if ($offset) $param.='&offset='.urlencode($offset);
    +		if ($search_thirdparty) $param.='&search_thirdparty='.urlencode($search_thirdparty);
    +		if ($search_num_releve) $param.='&search_num_releve='.urlencode($search_num_releve);
    +		if ($search_start_dt) $param.='&search_start_dt='.urlencode($search_start_dt);
    +		if ($search_end_dt) $param.='&search_end_dt='.urlencode($search_end_dt);
    +		if ($search_start_dv) $param.='&search_start_dv='.urlencode($search_start_dv);
    +		if ($search_end_dv) $param.='&search_end_dv='.urlencode($search_end_dv);
    +		if ($search_type) $param.='&search_type='.urlencode($search_type);
    +		if ($search_debit) $param.='&search_debit='.urlencode($search_debit);
    +		if ($search_credit) $param.='&search_credit='.urlencode($search_credit);
    +		$param.='&sortfield='.urlencode($sortfield).'&sortorder='.urlencode($sortorder);
    +		header('Location: '.$_SERVER["PHP_SELF"].'?'.$param);	// To avoid to submit twice and allow the back button
             exit;
         }
     }
    @@ -429,7 +443,7 @@ if ($id > 0 || ! empty($ref))
                 if ($user->rights->banque->consolidate) {
                 	$newparam = $param;
                 	$newparam = preg_replace('/search_conciliated=\d+/i','',$newparam);
    -            	$buttonreconcile = '<a class="butActionNew" style="margin-bottom: 5px !important; margin-top: 5px !important" href="'.DOL_URL_ROOT.'/compta/bank/bankentries_list.php?action=reconcile&search_conciliated=0'.$newparam.'">'.$langs->trans("Conciliate").'</a>';
    +            	$buttonreconcile = '<a class="butActionNew" style="margin-bottom: 5px !important; margin-top: 5px !important" href="'.DOL_URL_ROOT.'/compta/bank/bankentries_list.php?action=reconcile&sortfield=b.datev,b.dateo,b.rowid&amp;sortorder=asc,asc,asc&search_conciliated=0'.$newparam.'">'.$langs->trans("Conciliate").'</a>';
                 } else {
                 	$buttonreconcile = '<a class="butActionNewRefused" style="margin-bottom: 5px !important; margin-top: 5px !important" title="'.$langs->trans("NotEnoughPermissions").'" href="#">'.$langs->trans("Conciliate").'</a>';
                 }
    @@ -579,6 +593,8 @@ if ($resql)
     	        print Form::selectarray('cat', $options, GETPOST('cat'), 1);
     	    }
     	    print '<br>'.$langs->trans("ThenCheckLinesAndConciliate").' ';
    +	    print '<input class="button" name="confirm_savestatement" type="submit" value="'.$langs->trans("SaveStatementOnly").'">';
    +	    print ' '.$langs->trans("or").' ';
     	    print '<input class="button" name="confirm_reconcile" type="submit" value="'.$langs->trans("Conciliate").'">';
     	    print ' '.$langs->trans("or").' ';
     	    print '<input type="submit" name="cancel" class="button" value="'.$langs->trans("Cancel").'">';
    @@ -1401,16 +1417,17 @@ if ($resql)
     
         	if (! empty($arrayfields['b.num_releve']['checked']))
         	{
    -            print '<td class="nowrap" align="center">';
    +            print '<td class="nowraponall" align="center">';
             	// Transaction reconciliated or edit link
             	if ($bankaccount->canBeConciliated() > 0)
             	{
    -            	if ($objp->conciliated)  // If line not conciliated and account can be conciliated
    +        		if ($objp->num_releve)
                 	{
    -            	    print '<a href="releve.php?num='.$objp->num_releve.'&amp;account='.$objp->bankid.'">'.$objp->num_releve.'</a>';
    +            	    print '<a href="releve.php?num='.$objp->num_releve.'&account='.$objp->bankid.'&save_lastsearch_values=1">'.$objp->num_releve.'</a>';
                 	}
    -            	else if ($action == 'reconcile')
    +            	if (! $objp->conciliated && $action == 'reconcile')
                 	{
    +            		if ($objp->num_releve) print '&nbsp;';
                 	    print '<input class="flat" name="rowid['.$objp->rowid.']" type="checkbox" value="'.$objp->rowid.'" size="1"'.(! empty($_POST['rowid'][$objp->rowid])?' checked':'').'>';
                 	}
             	}
    @@ -1435,7 +1452,7 @@ if ($resql)
         	// Transaction reconciliated or edit link
         	if ($objp->conciliated && $bankaccount->canBeConciliated() > 0)  // If line not conciliated and account can be conciliated
         	{
    -    	    print '<a href="'.DOL_URL_ROOT.'/compta/bank/ligne.php?rowid='.$objp->rowid.'&amp;account='.$objp->bankid.'&amp;page='.$page.'">';
    +    	    print '<a href="'.DOL_URL_ROOT.'/compta/bank/ligne.php?save_lastsearch_values=1&amp;rowid='.$objp->rowid.'&amp;account='.$objp->bankid.'&amp;page='.$page.'">';
         	    print img_edit();
         	    print '</a>';
         	}
    @@ -1443,13 +1460,13 @@ if ($resql)
         	{
         	    if ($user->rights->banque->modifier || $user->rights->banque->consolidate)
         	    {
    -    	        print '<a href="'.DOL_URL_ROOT.'/compta/bank/ligne.php?rowid='.$objp->rowid.'&amp;account='.$objp->bankid.'&amp;page='.$page.'">';
    +    	        print '<a href="'.DOL_URL_ROOT.'/compta/bank/ligne.php?save_lastsearch_values=1&amp;rowid='.$objp->rowid.'&amp;account='.$objp->bankid.'&amp;page='.$page.'">';
         	        print img_edit();
         	        print '</a>';
         	    }
         	    else
         	    {
    -    	        print '<a href="'.DOL_URL_ROOT.'/compta/bank/ligne.php?rowid='.$objp->rowid.'&amp;account='.$objp->bankid.'&amp;page='.$page.'">';
    +    	        print '<a href="'.DOL_URL_ROOT.'/compta/bank/ligne.php?save_lastsearch_values=1&amp;rowid='.$objp->rowid.'&amp;account='.$objp->bankid.'&amp;page='.$page.'">';
         	        print img_view();
         	        print '</a>';
         	    }
    diff --git a/htdocs/compta/bank/categ.php b/htdocs/compta/bank/categ.php
    index 7ef798103d5..f76f73183b3 100644
    --- a/htdocs/compta/bank/categ.php
    +++ b/htdocs/compta/bank/categ.php
    @@ -34,6 +34,7 @@ require_once DOL_DOCUMENT_ROOT.'/compta/bank/class/bankcateg.class.php';
     $langs->loadLangs(array('banks', 'categories'));
     
     $action=GETPOST('action','aZ09');
    +$optioncss  = GETPOST('optioncss','aZ');												// Option for the css output (always '' except when 'print')
     
     if (!$user->rights->banque->configurer)
       accessforbidden();
    @@ -80,16 +81,36 @@ if ($categid) {
     llxHeader();
     
     
    -print load_fiche_titre($langs->trans("RubriquesTransactions"), '', 'title_bank.png');
    +print load_fiche_titre($langs->trans("RubriquesTransactions"));
     
     print '<form method="POST" action="'.$_SERVER["PHP_SELF"].'">';
    +if ($optioncss != '') print '<input type="hidden" name="optioncss" value="'.$optioncss.'">';
     print '<input type="hidden" name="token" value="'.$_SESSION['newtoken'].'">';
    +print '<input type="hidden" name="formfilteraction" id="formfilteraction" value="list">';
    +print '<input type="hidden" name="action" value="list">';
    +/*print '<input type="hidden" name="sortfield" value="'.$sortfield.'">';
    +print '<input type="hidden" name="sortorder" value="'.$sortorder.'">';
    +print '<input type="hidden" name="page" value="'.$page.'">';
    +print '<input type="hidden" name="contextpage" value="'.$contextpage.'">';
    +*/
     
    +print '<div class="div-table-responsive">';		// You can use div-table-responsive-no-min if you dont need reserved height for your table
     print '<table class="noborder" width="100%">';
     print '<tr class="liste_titre">';
     print '<td>'.$langs->trans("Ref").'</td><td colspan="2">'.$langs->trans("Label").'</td>';
     print "</tr>\n";
     
    +// Line to add category
    +if ($action != 'edit')
    +{
    +
    +	print '<tr class="oddeven">';
    +	print '<td>&nbsp;</td><td><input name="label" type="text" size="45"></td>';
    +	print '<td align="center"><input type="submit" name="add" class="button" value="'.$langs->trans("Add").'"></td>';
    +	print '</tr>';
    +}
    +
    +
     $sql = "SELECT rowid, label";
     $sql.= " FROM ".MAIN_DB_PREFIX."bank_categ";
     $sql.= " WHERE entity = ".$conf->entity;
    @@ -129,20 +150,10 @@ if ($result)
     	$db->free($result);
     }
     
    +print '</table>';
    +print '</div>';
     
    -/*
    - * Line to add category
    - */
    -if ($action != 'edit')
    -{
    -
    -	print '<tr class="oddeven">';
    -	print '<td>&nbsp;</td><td><input name="label" type="text" size="45"></td>';
    -	print '<td align="center"><input type="submit" name="add" class="button" value="'.$langs->trans("Add").'"></td>';
    -	print '</tr>';
    -}
    -
    -print '</table></form>';
    +print '</form>';
     
     // End of page
     llxFooter();
    diff --git a/htdocs/compta/bank/class/account.class.php b/htdocs/compta/bank/class/account.class.php
    index b9d19ba5b64..5a8d1326e48 100644
    --- a/htdocs/compta/bank/class/account.class.php
    +++ b/htdocs/compta/bank/class/account.class.php
    @@ -54,7 +54,7 @@ class Account extends CommonObject
     	/**
     	 * @var	int		Use id instead of rowid
     	 * @deprecated
    -	 * @see id
    +	 * @see $id
     	 */
     	public $rowid;
     
    @@ -171,6 +171,10 @@ class Account extends CommonObject
     	 * @var string
     	 */
     	public $account_number;
    +
    +	/**
    +     * @var int ID
    +     */
     	public $fk_accountancy_journal;
     
     	/**
    @@ -1182,7 +1186,7 @@ class Account extends CommonObject
     			return -1;
     		}
     
    -		return $solde;
    +		return price2num($solde, 'MU');
     	}
     
         // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
    @@ -1704,16 +1708,37 @@ class AccountLine extends CommonObject
         public $label;
     
         public $note;
    +
    +    /**
    +     * @var int ID
    +     */
     	public $fk_user_author;
    +
    +	/**
    +     * @var int ID
    +     */
     	public $fk_user_rappro;
    +
    +	/**
    +     * @var int ID
    +     */
     	public $fk_type;
    +
     	public $rappro;        // Is it conciliated
     	public $num_releve;    // If conciliated, what is bank statement
     	public $num_chq;       // Num of cheque
     	public $bank_chq;      // Bank of cheque
    -	public $fk_bordereau;  // Id of cheque receipt
     
    -	public $fk_account;            // Id of bank account
    +	/**
    +     * @var int ID of cheque receipt
    +     */
    +	public $fk_bordereau;
    +
    +	/**
    +     * @var int ID of bank account
    +     */
    +	public $fk_account;
    +
     	public $bank_account_label;    // Label of bank account
     
         /**
    @@ -1981,11 +2006,12 @@ class AccountLine extends CommonObject
     	/**
     	 *	Update conciliation field
     	 *
    -	 *	@param	User	$user		Objet user making update
    -	 *	@param 	int		$cat		Category id
    -	 *	@return	int					<0 if KO, >0 if OK
    +	 *	@param	User	$user			Objet user making update
    +	 *	@param 	int		$cat			Category id
    +	 *	@param	int		$conciliated	1=Set transaction to conciliated, 0=Keep transaction non conciliated
    +	 *	@return	int						<0 if KO, >0 if OK
     	 */
    -	function update_conciliation(User $user, $cat)
    +	function update_conciliation(User $user, $cat, $conciliated=1)
     	{
             // phpcs:enable
     		global $conf,$langs;
    @@ -2003,9 +2029,9 @@ class AccountLine extends CommonObject
     		}
     
     		$sql = "UPDATE ".MAIN_DB_PREFIX."bank SET";
    -		$sql.= " rappro = 1";
    +		$sql.= " rappro = ".$conciliated;
     		$sql.= ", num_releve = '".$this->db->escape($this->num_releve)."'";
    -		$sql.= ", fk_user_rappro = ".$user->id;
    +		if ($conciliated) $sql.= ", fk_user_rappro = ".$user->id;
     		$sql.= " WHERE rowid = ".$this->id;
     
     		dol_syslog(get_class($this)."::update_conciliation", LOG_DEBUG);
    diff --git a/htdocs/compta/bank/class/paymentvarious.class.php b/htdocs/compta/bank/class/paymentvarious.class.php
    index c3b6e942e1a..c997ff1a4f7 100644
    --- a/htdocs/compta/bank/class/paymentvarious.class.php
    +++ b/htdocs/compta/bank/class/paymentvarious.class.php
    @@ -1,5 +1,6 @@
     <?php
    -/* Copyright (C) 2017       Alexandre Spangaro  <aspangaro@zendsi.com>
    +/* Copyright (C) 2017       Alexandre Spangaro      <aspangaro@zendsi.com>
    + * Copyright (C) 2018       Frédéric France         <frederic.france@netlogic.fr>
      *
      * This program is free software; you can redistribute it and/or modify
      * it under the terms of the GNU General Public License as published by
    @@ -69,9 +70,25 @@ class PaymentVarious extends CommonObject
         public $label;
     
     	public $accountancy_code;
    +
    +	/**
    +     * @var int ID
    +     */
     	public $fk_project;
    +
    +	/**
    +     * @var int ID
    +     */
     	public $fk_bank;
    +
    +	/**
    +     * @var int ID
    +     */
     	public $fk_user_author;
    +
    +	/**
    +     * @var int ID
    +     */
     	public $fk_user_modif;
     
     
    @@ -104,9 +121,9 @@ class PaymentVarious extends CommonObject
     		$this->amount=trim($this->amount);
     		$this->label=trim($this->label);
     		$this->note=trim($this->note);
    -		$this->fk_bank=trim($this->fk_bank);
    -		$this->fk_user_author=trim($this->fk_user_author);
    -		$this->fk_user_modif=trim($this->fk_user_modif);
    +		$this->fk_bank = (int) $this->fk_bank;
    +		$this->fk_user_author = (int) $this->fk_user_author;
    +		$this->fk_user_modif = (int) $this->fk_user_modif;
     
     		$this->db->begin();
     
    @@ -304,9 +321,9 @@ class PaymentVarious extends CommonObject
     		$this->amount=price2num(trim($this->amount));
     		$this->label=trim($this->label);
     		$this->note=trim($this->note);
    -		$this->fk_bank=trim($this->fk_bank);
    -		$this->fk_user_author=trim($this->fk_user_author);
    -		$this->fk_user_modif=trim($this->fk_user_modif);
    +		$this->fk_bank = (int) $this->fk_bank;
    +		$this->fk_user_author = (int) $this->fk_user_author;
    +		$this->fk_user_modif = (int) $this->fk_user_modif;
     
     		// Check parameters
     		if (! $this->label)
    @@ -518,26 +535,26 @@ class PaymentVarious extends CommonObject
     		elseif ($mode == 2)
     		{
     			if ($statut==0) return img_picto($langs->trans($this->statuts_short[$statut]),'statut0').' '.$langs->trans($this->statuts_short[$statut]);
    -			if ($statut==1) return img_picto($langs->trans($this->statuts_short[$statut]),'statut4').' '.$langs->trans($this->statuts_short[$statut]);
    -			if ($statut==2) return img_picto($langs->trans($this->statuts_short[$statut]),'statut6').' '.$langs->trans($this->statuts_short[$statut]);
    +			elseif ($statut==1) return img_picto($langs->trans($this->statuts_short[$statut]),'statut4').' '.$langs->trans($this->statuts_short[$statut]);
    +			elseif ($statut==2) return img_picto($langs->trans($this->statuts_short[$statut]),'statut6').' '.$langs->trans($this->statuts_short[$statut]);
     		}
     		elseif ($mode == 3)
     		{
     			if ($statut==0 && ! empty($this->statuts_short[$statut])) return img_picto($langs->trans($this->statuts_short[$statut]),'statut0');
    -			if ($statut==1 && ! empty($this->statuts_short[$statut])) return img_picto($langs->trans($this->statuts_short[$statut]),'statut4');
    -			if ($statut==2 && ! empty($this->statuts_short[$statut])) return img_picto($langs->trans($this->statuts_short[$statut]),'statut6');
    +			elseif ($statut==1 && ! empty($this->statuts_short[$statut])) return img_picto($langs->trans($this->statuts_short[$statut]),'statut4');
    +			elseif ($statut==2 && ! empty($this->statuts_short[$statut])) return img_picto($langs->trans($this->statuts_short[$statut]),'statut6');
     		}
     		elseif ($mode == 4)
     		{
     			if ($statut==0 && ! empty($this->statuts_short[$statut])) return img_picto($langs->trans($this->statuts_short[$statut]),'statut0').' '.$langs->trans($this->statuts[$statut]);
    -			if ($statut==1 && ! empty($this->statuts_short[$statut])) return img_picto($langs->trans($this->statuts_short[$statut]),'statut4').' '.$langs->trans($this->statuts[$statut]);
    -			if ($statut==2 && ! empty($this->statuts_short[$statut])) return img_picto($langs->trans($this->statuts_short[$statut]),'statut6').' '.$langs->trans($this->statuts[$statut]);
    +			elseif ($statut==1 && ! empty($this->statuts_short[$statut])) return img_picto($langs->trans($this->statuts_short[$statut]),'statut4').' '.$langs->trans($this->statuts[$statut]);
    +			elseif ($statut==2 && ! empty($this->statuts_short[$statut])) return img_picto($langs->trans($this->statuts_short[$statut]),'statut6').' '.$langs->trans($this->statuts[$statut]);
     		}
     		elseif ($mode == 5)
     		{
     			if ($statut==0 && ! empty($this->statuts_short[$statut])) return $langs->trans($this->statuts_short[$statut]).' '.img_picto($langs->trans($this->statuts_short[$statut]),'statut0');
    -			if ($statut==1 && ! empty($this->statuts_short[$statut])) return $langs->trans($this->statuts_short[$statut]).' '.img_picto($langs->trans($this->statuts_short[$statut]),'statut4');
    -			if ($statut==2 && ! empty($this->statuts_short[$statut])) return $langs->trans($this->statuts_short[$statut]).' '.img_picto($langs->trans($this->statuts_short[$statut]),'statut6');
    +			elseif ($statut==1 && ! empty($this->statuts_short[$statut])) return $langs->trans($this->statuts_short[$statut]).' '.img_picto($langs->trans($this->statuts_short[$statut]),'statut4');
    +			elseif ($statut==2 && ! empty($this->statuts_short[$statut])) return $langs->trans($this->statuts_short[$statut]).' '.img_picto($langs->trans($this->statuts_short[$statut]),'statut6');
     		}
     	}
     
    diff --git a/htdocs/compta/bank/list.php b/htdocs/compta/bank/list.php
    index 0794634e3a3..79c26adfa47 100644
    --- a/htdocs/compta/bank/list.php
    +++ b/htdocs/compta/bank/list.php
    @@ -255,7 +255,7 @@ include DOL_DOCUMENT_ROOT.'/core/tpl/massactions_pre.tpl.php';
     if ($sall)
     {
         foreach($fieldstosearchall as $key => $val) $fieldstosearchall[$key]=$langs->trans($val);
    -    print '<div class="divsearchfieldfilter">'.$langs->trans("FilterOnInto", $all) . join(', ',$fieldstosearchall).'</div>';
    +    print '<div class="divsearchfieldfilter">'.$langs->trans("FilterOnInto", $sall) . join(', ',$fieldstosearchall).'</div>';
     }
     
     $moreforfilter='';
    diff --git a/htdocs/compta/deplacement/class/deplacement.class.php b/htdocs/compta/deplacement/class/deplacement.class.php
    index 403988052bd..2476f65b09f 100644
    --- a/htdocs/compta/deplacement/class/deplacement.class.php
    +++ b/htdocs/compta/deplacement/class/deplacement.class.php
    @@ -51,10 +51,18 @@ class Deplacement extends CommonObject
     	 */
     	public $fk_element = '';
     
    -	public $ismultientitymanaged = 0;	// 0=No test on entity, 1=Test with field entity, 2=Test with link by societe
    +	/**
    +	 * 0=No test on entity, 1=Test with field entity, 2=Test with link by societe
    +	 * @var int
    +	 */
    +	public $ismultientitymanaged = 0;
     
     	public $datec;         // Creation date
     	public $dated;
    +
    +	/**
    +     * @var int ID
    +     */
     	public $fk_user_author;
     
     	/**
    diff --git a/htdocs/compta/facture/card.php b/htdocs/compta/facture/card.php
    index 4d538bfc68b..a9fe72da41f 100644
    --- a/htdocs/compta/facture/card.php
    +++ b/htdocs/compta/facture/card.php
    @@ -695,6 +695,9 @@ if (empty($reshook))
     					$amount_ht[$line->tva_tx] += $line->total_ht;
     					$amount_tva[$line->tva_tx] += $line->total_tva;
     					$amount_ttc[$line->tva_tx] += $line->total_ttc;
    +					$multicurrency_amount_ht[$line->tva_tx] += $line->multicurrency_total_ht;
    +					$multicurrency_amount_tva[$line->tva_tx] += $line->multicurrency_total_tva;
    +					$multicurrency_amount_ttc[$line->tva_tx] += $line->multicurrency_total_ttc;
     					$i ++;
     				}
     			}
    @@ -750,6 +753,9 @@ if (empty($reshook))
     					$discount->amount_ht = abs($amount_ht[$tva_tx]);
     					$discount->amount_tva = abs($amount_tva[$tva_tx]);
     					$discount->amount_ttc = abs($amount_ttc[$tva_tx]);
    +					$discount->multicurrency_amount_ht = abs($multicurrency_amount_ht[$tva_tx]);
    +					$discount->multicurrency_amount_tva = abs($multicurrency_amount_tva[$tva_tx]);
    +					$discount->multicurrency_amount_ttc = abs($multicurrency_amount_ttc[$tva_tx]);
     					$discount->tva_tx = abs($tva_tx);
     
     					$result = $discount->create($user);
    @@ -1536,6 +1542,7 @@ if (empty($reshook))
     					{
     						$line->origin = $object->origin;
     						$line->origin_id = $line->id;
    +						$line->fk_prev_id = $line->id;
     						$line->fetch_optionals($line->id);
     						$line->situation_percent =  $line->get_prev_progress($object->id); // get good progress including credit note
     
    @@ -2877,7 +2884,8 @@ if ($action == 'create')
     	// Standard invoice
     	print '<div class="tagtr listofinvoicetype"><div class="tagtd listofinvoicetype">';
     	$tmp='<input type="radio" id="radio_standard" name="type" value="0"' . (GETPOST('type') == 0 ? ' checked' : '') . '> ';
    -	$desc = $form->textwithpicto($tmp.$langs->trans("InvoiceStandardAsk"), $langs->transnoentities("InvoiceStandardDesc"), 1, 'help', '', 0, 3);
    +	$tmp  = $tmp.'<label for="radio_standard" >'.$langs->trans("InvoiceStandardAsk").'</label>';
    +	$desc = $form->textwithpicto($tmp, $langs->transnoentities("InvoiceStandardDesc"), 1, 'help', '', 0, 3);
     	print $desc;
     	print '</div></div>';
     
    @@ -2896,7 +2904,8 @@ if ($action == 'create')
         		});
         		</script>';
     
    -			$desc = $form->textwithpicto($tmp.$langs->trans("InvoiceDeposit"), $langs->transnoentities("InvoiceDepositDesc"), 1, 'help', '', 0, 3);
    +			$tmp  = $tmp.'<label for="radio_deposit" >'.$langs->trans("InvoiceDeposit").'</label>';
    +			$desc = $form->textwithpicto($tmp, $langs->transnoentities("InvoiceDepositDesc"), 1, 'help', '', 0, 3);
     			print '<table class="nobordernopadding"><tr><td>';
     			print $desc;
     			print '</td>';
    @@ -2920,8 +2929,9 @@ if ($action == 'create')
     		{
     			// First situation invoice
     			print '<div class="tagtr listofinvoicetype"><div class="tagtd listofinvoicetype">';
    -			$tmp='<input type="radio" name="type" value="5"' . (GETPOST('type') == 5 ? ' checked' : '') . '> ';
    -			$desc = $form->textwithpicto($tmp.$langs->trans("InvoiceFirstSituationAsk"), $langs->transnoentities("InvoiceFirstSituationDesc"), 1, 'help', '', 0, 3);
    +			$tmp='<input id="radio_situation invoice" type="radio" name="type" value="5"' . (GETPOST('type') == 5 ? ' checked' : '') . '> ';
    +			$tmp  = $tmp.'<label for="radio_situation invoice" >'.$langs->trans("InvoiceFirstSituationAsk").'</label>';
    +			$desc = $form->textwithpicto($tmp, $langs->transnoentities("InvoiceFirstSituationDesc"), 1, 'help', '', 0, 3);
     			print $desc;
     			print '</div></div>';
     
    @@ -2931,7 +2941,7 @@ if ($action == 'create')
     			$tmp='<input type="radio" name="type" value="5"' . (GETPOST('type') == 5 && GETPOST('originid') ? ' checked' : '');
     			if ($opt == ('<option value ="0" selected>' . $langs->trans('NoSituations') . '</option>') || (GETPOST('origin') && GETPOST('origin') != 'facture' && GETPOST('origin') != 'commande')) $tmp.=' disabled';
     			$tmp.= '> ';
    -			$text = $tmp.$langs->trans("InvoiceSituationAsk") . ' ';
    +			$text = '<label>'.$tmp.$langs->trans("InvoiceSituationAsk") . '</label> ';
     			$text .= '<select class="flat" id="situations" name="situations">';
     			$text .= $opt;
     			$text .= '</select>';
    @@ -2955,7 +2965,7 @@ if ($action == 'create')
         			});
         		});
         		</script>';
    -			$text = $tmp.$langs->trans("InvoiceReplacementAsk") . ' ';
    +			$text = '<label>'.$tmp.$langs->trans("InvoiceReplacementAsk") . '</label>';
     			$text .= '<select class="flat" name="fac_replacement" id="fac_replacement"';
     			if (! $options)
     				$text .= ' disabled';
    @@ -2976,13 +2986,14 @@ if ($action == 'create')
     	{
     		print '<div class="tagtr listofinvoicetype"><div class="tagtd listofinvoicetype">';
     		$tmp='<input type="radio" name="type" id="radio_replacement" value="0" disabled> ';
    -		$text = $tmp.$langs->trans("InvoiceReplacement") . ' ';
    +		$text = '<label>'.$tmp.$langs->trans("InvoiceReplacement") . '</label> ';
     		$text.= '('.$langs->trans("YouMustCreateInvoiceFromThird").') ';
     		$desc = $form->textwithpicto($text, $langs->transnoentities("InvoiceReplacementDesc"), 1, 'help', '', 0, 3);
     		print $desc;
     		print '</div></div>';
     	}
    -
    +	
    +	
     	if (empty($origin))
     	{
     		if ($socid > 0)
    @@ -3009,7 +3020,7 @@ if ($action == 'create')
         				});
         			});
         			</script>';
    -				$text = $tmp.$langs->transnoentities("InvoiceAvoirAsk") . ' ';
    +				$text = '<label>'.$tmp.$langs->transnoentities("InvoiceAvoirAsk") . '</label> ';
     				// $text.='<input type="text" value="">';
     				$text .= '<select class="flat valignmiddle" name="fac_avoir" id="fac_avoir"';
     				if (! $optionsav)
    @@ -3038,7 +3049,7 @@ if ($action == 'create')
     			print '<div class="tagtr listofinvoicetype"><div class="tagtd listofinvoicetype">';
     			if (empty($conf->global->INVOICE_CREDIT_NOTE_STANDALONE)) $tmp='<input type="radio" name="type" id="radio_creditnote" value="0" disabled> ';
     			else $tmp='<input type="radio" name="type" id="radio_creditnote" value="2" > ';
    -			$text = $tmp.$langs->trans("InvoiceAvoir") . ' ';
    +			$text = '<label>'.$tmp.$langs->trans("InvoiceAvoir") . '</label> ';
     			$text.= '('.$langs->trans("YouMustCreateInvoiceFromThird").') ';
     			$desc = $form->textwithpicto($text, $langs->transnoentities("InvoiceAvoirDesc"), 1, 'help', '', 0, 3);
     			print $desc;
    @@ -3049,7 +3060,7 @@ if ($action == 'create')
     	// Template invoice
     	print '<div class="tagtr listofinvoicetype"><div class="tagtd listofinvoicetype">';
     	$tmp='<input type="radio" name="type" id="radio_template" value="0" disabled> ';
    -	$text = $tmp.$langs->trans("RepeatableInvoice") . ' ';
    +	$text = '<label>'.$tmp.$langs->trans("RepeatableInvoice") . '</label> ';
     	//$text.= '('.$langs->trans("YouMustCreateStandardInvoiceFirst").') ';
     	$desc = $form->textwithpicto($text, $langs->transnoentities("YouMustCreateStandardInvoiceFirstDesc"), 1, 'help', '', 0, 3);
     	print $desc;
    @@ -3057,6 +3068,41 @@ if ($action == 'create')
     
     	print '</div>';
     
    +	
    +	if(!empty($conf->global->INVOICE_USE_DEFAULT_DOCUMENT)) // Hidden conf
    +	{
    +    	// Add auto select default document model
    +    	$listtType=array(Facture::TYPE_STANDARD,Facture::TYPE_REPLACEMENT,Facture::TYPE_CREDIT_NOTE,Facture::TYPE_DEPOSIT,Facture::TYPE_SITUATION);
    +    	$jsListType='';
    +    	foreach ($listtType as $type)
    +    	{
    +    	    $thisTypeConfName = 'FACTURE_ADDON_PDF_'.$type;
    +    	    $curent = !empty($conf->global->{$thisTypeConfName})?$conf->global->{$thisTypeConfName}:$conf->global->FACTURE_ADDON_PDF;
    +    	    $jsListType.=(!empty($jsListType)?',':'').'"'.$type.'":"'.$curent.'"';
    +    	}
    +    	
    +    	print '<script type="text/javascript" language="javascript">
    +        		$(document).ready(function() {
    +                    var listType = {'.$jsListType.'};
    +        			$("[name=\'type\'").change(function() {
    +        				if($( this ).prop("checked"))
    +                        {
    +                            if(($( this ).val() in listType))
    +                            {
    +                                $("#model").val(listType[$( this ).val()]);
    +                            }
    +                            else
    +                            {
    +                                $("#model").val("'.$conf->global->FACTURE_ADDON_PDF.'");
    +                            }
    +                        }
    +        			});
    +        		});
    +        		</script>';
    +	}
    +	
    +	
    +	
     	print '</td></tr>';
     
     	if ($socid > 0)
    @@ -3147,7 +3193,14 @@ if ($action == 'create')
     	print '<td colspan="2">';
     	include_once DOL_DOCUMENT_ROOT . '/core/modules/facture/modules_facture.php';
     	$liste = ModelePDFFactures::liste_modeles($db);
    -	print $form->selectarray('model', $liste, $conf->global->FACTURE_ADDON_PDF);
    +	if(!empty($conf->global->INVOICE_USE_DEFAULT_DOCUMENT)){ // Hidden conf
    +	   $paramkey='FACTURE_ADDON_PDF_'.$object->type;
    +	   $curent = !empty($conf->global->$paramkey)?$conf->global->$paramkey:$conf->global->FACTURE_ADDON_PDF;
    +	}
    +	else{
    +	   $curent = $conf->global->FACTURE_ADDON_PDF;
    +	}
    +	print $form->selectarray('model', $liste, $curent);
     	print "</td></tr>";
     
     	// Multicurrency
    @@ -3253,8 +3306,7 @@ if ($action == 'create')
     		print '<tr><td>' . $langs->trans($newclassname) . '</td><td colspan="2">' . $objectsrc->getNomUrl(1);
     		// We check if Origin document (id and type is known) has already at least one invoice attached to it
     		$objectsrc->fetchObjectLinked($originid,$origin,'','facture');
    -		$cntinvoice=count($objectsrc->linkedObjects['facture']);
    -		if ($cntinvoice>=1)
    +		if (is_array($objectsrc->linkedObjects['facture']) && count($objectsrc->linkedObjects['facture']) >= 1)
     		{
     			setEventMessages('WarningBillExist', null, 'warnings');
     			echo ' ('.$langs->trans('LatestRelatedBill').end($objectsrc->linkedObjects['facture'])->getNomUrl(1).')';
    diff --git a/htdocs/compta/facture/class/facture-rec.class.php b/htdocs/compta/facture/class/facture-rec.class.php
    index 1c97b82d926..ad33432484f 100644
    --- a/htdocs/compta/facture/class/facture-rec.class.php
    +++ b/htdocs/compta/facture/class/facture-rec.class.php
    @@ -64,7 +64,11 @@ class FactureRec extends CommonInvoice
     	 */
     	public $picto='bill';
     
    +	/**
    +	 * @var int Entity
    +	 */
     	public $entity;
    +
     	public $number;
     	public $date;
     	public $amount;
    diff --git a/htdocs/compta/facture/class/facture.class.php b/htdocs/compta/facture/class/facture.class.php
    index dd207af57ec..20983ebd3c9 100644
    --- a/htdocs/compta/facture/class/facture.class.php
    +++ b/htdocs/compta/facture/class/facture.class.php
    @@ -98,11 +98,18 @@ class Facture extends CommonInvoice
     	public $socid;
     
     	public $author;
    +
    +	/**
    +     * @var int ID
    +     */
     	public $fk_user_author;
    +
    +	/**
    +     * @var int ID
    +     */
     	public $fk_user_valid;
    +
     	public $date;              // Date invoice
    -	public $date_creation;		// Creation date
    -	public $date_validation;	// Validation date
     	public $datem;
     	public $ref_client;
     	public $ref_int;
    @@ -128,6 +135,8 @@ class Facture extends CommonInvoice
     	public $paye;
     	//! key of module source when invoice generated from a dedicated module ('cashdesk', 'takepos', ...)
     	public $module_source;
    +	//! key of pos source ('0', '1', ...)
    +	public $pos_source;
     	//! id of template invoice when generated from a template invoice
     	public $fk_fac_rec_source;
     	//! id of source invoice if replacement invoice or credit note
    @@ -136,7 +145,11 @@ class Facture extends CommonInvoice
     	public $date_lim_reglement;
     	public $cond_reglement_code;		// Code in llx_c_paiement
     	public $mode_reglement_code;		// Code in llx_c_paiement
    -	public $fk_bank;					// Field to store bank id to use when payment mode is withdraw
    +
    +	/**
    +     * @var int ID Field to store bank id to use when payment mode is withdraw
    +     */
    +	public $fk_bank;
     
     	/**
     	 * @deprecated
    @@ -155,7 +168,11 @@ class Facture extends CommonInvoice
     	public $fac_rec;
     
     	// Multicurrency
    +	/**
    +     * @var int ID
    +     */
     	public $fk_multicurrency;
    +
     	public $multicurrency_code;
     	public $multicurrency_tx;
     	public $multicurrency_total_ht;
    @@ -447,7 +464,7 @@ class Facture extends CommonInvoice
     		$sql.= ", note_public";
     		$sql.= ", ref_client, ref_int";
             $sql.= ", fk_account";
    -		$sql.= ", module_source, fk_fac_rec_source, fk_facture_source, fk_user_author, fk_projet";
    +		$sql.= ", module_source, pos_source, fk_fac_rec_source, fk_facture_source, fk_user_author, fk_projet";
     		$sql.= ", fk_cond_reglement, fk_mode_reglement, date_lim_reglement, model_pdf";
     		$sql.= ", situation_cycle_ref, situation_counter, situation_final";
     		$sql.= ", fk_incoterms, location_incoterms";
    @@ -472,6 +489,7 @@ class Facture extends CommonInvoice
     		$sql.= ", ".($this->ref_int?"'".$this->db->escape($this->ref_int)."'":"null");
     		$sql.= ", ".($this->fk_account>0?$this->fk_account:'NULL');
     		$sql.= ", ".($this->module_source ? "'".$this->db->escape($this->module_source)."'" : "null");
    +		$sql.= ", ".($this->pos_source != '' ? "'".$this->db->escape($this->pos_source)."'" : "null");
     		$sql.= ", ".($this->fk_fac_rec_source?"'".$this->db->escape($this->fk_fac_rec_source)."'":"null");
     		$sql.= ", ".($this->fk_facture_source?"'".$this->db->escape($this->fk_facture_source)."'":"null");
     		$sql.= ", ".($user->id > 0 ? "'".$user->id."'":"null");
    @@ -972,6 +990,7 @@ class Facture extends CommonInvoice
     		$this->user_valid         = '';
     		$this->fk_facture_source  = 0;
     		$this->date_creation      = '';
    +		$this->date_modification = '';
     		$this->date_validation    = '';
     		$this->ref_client         = '';
     		$this->close_code         = '';
    @@ -1209,6 +1228,10 @@ class Facture extends CommonInvoice
     
             if ($user->rights->facture->lire) {
                 $label = '<u>' . $langs->trans("ShowInvoice") . '</u>';
    +            if ($this->type == self::TYPE_REPLACEMENT) $label='<u>' . $langs->transnoentitiesnoconv("ShowInvoiceReplace") . '</u>';
    +            if ($this->type == self::TYPE_CREDIT_NOTE) $label='<u>' . $langs->transnoentitiesnoconv("ShowInvoiceAvoir") . '</u>';
    +            if ($this->type == self::TYPE_DEPOSIT)     $label='<u>' . $langs->transnoentitiesnoconv("ShowInvoiceDeposit") . '</u>';
    +            if ($this->type == self::TYPE_SITUATION)   $label='<u>' . $langs->transnoentitiesnoconv("ShowInvoiceSituation") . '</u>';
                 if (! empty($this->ref))
                     $label .= '<br><b>'.$langs->trans('Ref') . ':</b> ' . $this->ref;
                 if (! empty($this->ref_client))
    @@ -1223,10 +1246,6 @@ class Facture extends CommonInvoice
                     $label.= '<br><b>' . $langs->trans('LT2') . ':</b> ' . price($this->total_localtax2, 0, $langs, 0, -1, -1, $conf->currency);
                 if (! empty($this->total_ttc))
                     $label.= '<br><b>' . $langs->trans('AmountTTC') . ':</b> ' . price($this->total_ttc, 0, $langs, 0, -1, -1, $conf->currency);
    -    		if ($this->type == self::TYPE_REPLACEMENT) $label=$langs->transnoentitiesnoconv("ShowInvoiceReplace").': '.$this->ref;
    -    		if ($this->type == self::TYPE_CREDIT_NOTE) $label=$langs->transnoentitiesnoconv("ShowInvoiceAvoir").': '.$this->ref;
    -    		if ($this->type == self::TYPE_DEPOSIT) $label=$langs->transnoentitiesnoconv("ShowInvoiceDeposit").': '.$this->ref;
    -    		if ($this->type == self::TYPE_SITUATION) $label=$langs->transnoentitiesnoconv("ShowInvoiceSituation").': '.$this->ref;
         		if ($moretitle) $label.=' - '.$moretitle;
             }
     
    @@ -1341,6 +1360,7 @@ class Facture extends CommonInvoice
     				$this->date_pointoftax		= $this->db->jdate($obj->date_pointoftax);
     				$this->date_creation		= $this->db->jdate($obj->datec);
     				$this->date_validation		= $this->db->jdate($obj->datev);
    +				$this->date_modification		= $this->db->jdate($obj->datem);
     				$this->datem				= $this->db->jdate($obj->datem);
     				$this->remise_percent		= $obj->remise_percent;
     				$this->remise_absolue		= $obj->remise_absolue;
    @@ -1751,9 +1771,9 @@ class Facture extends CommonInvoice
     			$facligne->total_ttc = -$remise->amount_ttc;
     
     			$facligne->multicurrency_subprice = -$remise->multicurrency_subprice;
    -			$facligne->multicurrency_total_ht = -$remise->multicurrency_total_ht;
    -			$facligne->multicurrency_total_tva = -$remise->multicurrency_total_tva;
    -			$facligne->multicurrency_total_ttc = -$remise->multicurrency_total_ttc;
    +			$facligne->multicurrency_total_ht = -$remise->multicurrency_amount_ht;
    +			$facligne->multicurrency_total_tva = -$remise->multicurrency_amount_tva;
    +			$facligne->multicurrency_total_ttc = -$remise->multicurrency_amount_ttc;
     
     			$lineid=$facligne->insert();
     			if ($lineid > 0)
    @@ -4087,7 +4107,7 @@ class Facture extends CommonInvoice
     	 *  @param  int			$hidedetails    Hide details of lines
     	 *  @param  int			$hidedesc       Hide description
     	 *  @param  int			$hideref        Hide ref
    -	 * @param   null|array  $moreparams     Array to provide more information
    +	 *  @param   null|array  $moreparams     Array to provide more information
     	 *	@return int        					<0 if KO, >0 if OK
     	 */
     	public function generateDocument($modele, $outputlangs, $hidedetails=0, $hidedesc=0, $hideref=0, $moreparams=null)
    @@ -4096,12 +4116,15 @@ class Facture extends CommonInvoice
     
     		$langs->load("bills");
     
    -		if (! dol_strlen($modele)) {
    -
    +		if (! dol_strlen($modele))
    +		{
     			$modele = 'crabe';
    +			$thisTypeConfName = 'FACTURE_ADDON_PDF_'.$this->type;
     
     			if ($this->modelpdf) {
     				$modele = $this->modelpdf;
    +			} elseif (! empty($conf->global->$thisTypeConfName)) {
    +				$modele = $conf->global->$thisTypeConfName;
     			} elseif (! empty($conf->global->FACTURE_ADDON_PDF)) {
     				$modele = $conf->global->FACTURE_ADDON_PDF;
     			}
    @@ -4315,42 +4338,42 @@ class FactureLigne extends CommonInvoiceLine
     	 */
     	public $table_element='facturedet';
     
    -	var $oldline;
    +	public $oldline;
     
     	//! From llx_facturedet
     	//! Id facture
    -	var $fk_facture;
    +	public $fk_facture;
     	//! Id parent line
    -	var $fk_parent_line;
    +	public $fk_parent_line;
     	/**
     	 * @deprecated
     	 */
    -	var $label;
    +	public $label;
     	//! Description ligne
    -	var $desc;
    +	public $desc;
     
    -	var $localtax1_type;	// Local tax 1 type
    -	var $localtax2_type;	// Local tax 2 type
    -	var $fk_remise_except;	// Link to line into llx_remise_except
    -	var $rang = 0;
    +	public $localtax1_type;	// Local tax 1 type
    +	public $localtax2_type;	// Local tax 2 type
    +	public $fk_remise_except;	// Link to line into llx_remise_except
    +	public $rang = 0;
     
    -	var $fk_fournprice;
    -	var $pa_ht;
    -	var $marge_tx;
    -	var $marque_tx;
    +	public $fk_fournprice;
    +	public $pa_ht;
    +	public $marge_tx;
    +	public $marque_tx;
     
    -	var $special_code;	// Liste d'options non cumulabels:
    +	public $special_code;	// Liste d'options non cumulabels:
     	// 1: frais de port
     	// 2: ecotaxe
     	// 3: ??
     
    -	var $origin;
    -	var $origin_id;
    +	public $origin;
    +	public $origin_id;
     
    -	var $fk_code_ventilation = 0;
    +	public $fk_code_ventilation = 0;
     
    -	var $date_start;
    -	var $date_end;
    +	public $date_start;
    +	public $date_end;
     
     	// Ne plus utiliser
     	//var $price;         	// P.U. HT apres remise % de ligne (exemple 80)
    @@ -4361,17 +4384,17 @@ class FactureLigne extends CommonInvoiceLine
     	 * @deprecated
     	 * @see product_ref
     	 */
    -	var $ref;				// Product ref (deprecated)
    -	var $product_ref;       // Product ref
    +	public $ref;				// Product ref (deprecated)
    +	public $product_ref;       // Product ref
     	/**
     	 * @deprecated
     	 * @see product_label
     	 */
    -	var $libelle;      		// Product label (deprecated)
    -	var $product_label;     // Product label
    -	var $product_desc;  	// Description produit
    +	public $libelle;      		// Product label (deprecated)
    +	public $product_label;     // Product label
    +	public $product_desc;  	// Description produit
     
    -	var $skip_update_total; // Skip update price total for special lines
    +	public $skip_update_total; // Skip update price total for special lines
     
     	/**
     	 * @var int Situation advance percentage
    @@ -4384,12 +4407,12 @@ class FactureLigne extends CommonInvoiceLine
     	public $fk_prev_id;
     
     	// Multicurrency
    -	var $fk_multicurrency;
    -	var $multicurrency_code;
    -	var $multicurrency_subprice;
    -	var $multicurrency_total_ht;
    -	var $multicurrency_total_tva;
    -	var $multicurrency_total_ttc;
    +	public $fk_multicurrency;
    +	public $multicurrency_code;
    +	public $multicurrency_subprice;
    +	public $multicurrency_total_ht;
    +	public $multicurrency_total_tva;
    +	public $multicurrency_total_ttc;
     
     	/**
     	 *	Load invoice line from database
    diff --git a/htdocs/compta/facture/class/facturestats.class.php b/htdocs/compta/facture/class/facturestats.class.php
    index ef54a6ffa5f..1201c429a2a 100644
    --- a/htdocs/compta/facture/class/facturestats.class.php
    +++ b/htdocs/compta/facture/class/facturestats.class.php
    @@ -88,8 +88,8 @@ class FactureStats extends Stats
     			$this->where.=" AND f.fk_soc = ".$this->socid;
     		}
             if ($this->userid > 0) $this->where.=' AND f.fk_user_author = '.$this->userid;
    -		if (! empty($conf->global->FACTURE_DEPOSITS_ARE_JUST_PAYMENTS)) $this->where.= " AND f.type IN (0,1,2)";
    -		else $this->where.= " AND f.type IN (0,1,2,3)";
    +		if (! empty($conf->global->FACTURE_DEPOSITS_ARE_JUST_PAYMENTS)) $this->where.= " AND f.type IN (0,1,2,5)";
    +		else $this->where.= " AND f.type IN (0,1,2,3,5)";
     	}
     
     
    diff --git a/htdocs/compta/facture/list.php b/htdocs/compta/facture/list.php
    index 2e5cb83883f..35338722353 100644
    --- a/htdocs/compta/facture/list.php
    +++ b/htdocs/compta/facture/list.php
    @@ -422,7 +422,7 @@ if ($filtre)
     }
     if ($search_ref) $sql .= natural_search('f.facnumber', $search_ref);
     if ($search_refcustomer) $sql .= natural_search('f.ref_client', $search_refcustomer);
    -if ($search_type != '') $sql.=" AND f.type IN (".$db->escape($search_type).")";
    +if ($search_type != '' && $search_type != '-1') $sql.=" AND f.type IN (".$db->escape($search_type).")";
     if ($search_project) $sql .= natural_search('p.ref', $search_project);
     if ($search_societe) $sql .= natural_search('s.nom', $search_societe);
     if ($search_town)  $sql.= natural_search('s.town', $search_town);
    @@ -458,7 +458,7 @@ if ($search_month > 0)
     	if ($search_year > 0 && empty($search_day))
     	$sql.= " AND f.datef BETWEEN '".$db->idate(dol_get_first_day($search_year,$search_month,false))."' AND '".$db->idate(dol_get_last_day($search_year,$search_month,false))."'";
     	else if ($search_year > 0 && ! empty($search_day))
    -	$sql.= " AND f.datef BETWEEN '".$db->idate(dol_mktime(0, 0, 0, $search_month, $search_day, $search_year))."' AND '".$db->idate(dol_mktime(23, 59, 59, $search_month, $search_day, $serch_year))."'";
    +	$sql.= " AND f.datef BETWEEN '".$db->idate(dol_mktime(0, 0, 0, $search_month, $search_day, $search_year))."' AND '".$db->idate(dol_mktime(23, 59, 59, $search_month, $search_day, $search_year))."'";
     	else
     	$sql.= " AND date_format(f.datef, '%m') = '".$search_month."'";
     }
    diff --git a/htdocs/compta/index.php b/htdocs/compta/index.php
    index ea43c270b5f..eec0c640b67 100644
    --- a/htdocs/compta/index.php
    +++ b/htdocs/compta/index.php
    @@ -162,7 +162,6 @@ if (! empty($conf->facture->enabled) && $user->rights->facture->lire)
     
     	if ( $resql )
     	{
    -		$var = false;
     		$num = $db->num_rows($resql);
     
     		print '<table class="noborder" width="100%">';
    @@ -350,7 +349,6 @@ if (! empty($conf->facture->enabled) && $user->rights->facture->lire)
     	$resql = $db->query($sql);
     	if ($resql)
     	{
    -		$var=false;
     		$num = $db->num_rows($resql);
     		$i = 0;
     
    @@ -473,7 +471,6 @@ if (! empty($conf->fournisseur->enabled) && $user->rights->fournisseur->facture-
     	$resql=$db->query($sql);
     	if ($resql)
     	{
    -		$var=false;
     		$num = $db->num_rows($resql);
     
     		print '<table class="noborder" width="100%">';
    @@ -520,7 +517,6 @@ if (! empty($conf->fournisseur->enabled) && $user->rights->fournisseur->facture-
     				$total_ttc +=  $obj->total_ttc;
     				$totalam +=  $obj->am;
     				$i++;
    -				$var = !$var;
     			}
     		}
     		else
    @@ -1069,7 +1065,7 @@ if ($resql)
     		$obj = $db->fetch_object($resql);
     
     
    -		print "<tr ".$bc[$var]."><td>".dol_print_date($db->jdate($obj->da),"day")."</td>";
    +		print '<tr class="oddeven"><td>'.dol_print_date($db->jdate($obj->da),"day").'</td>';
     		print '<td><a href="action/card.php">'.$obj->libelle.' '.$obj->label.'</a></td></tr>';
     		$i++;
     	}
    @@ -1080,7 +1076,6 @@ if ($resql)
     
     print '</div></div></div>';
     
    -
    +// End of page
     llxFooter();
    -
     $db->close();
    diff --git a/htdocs/compta/localtax/class/localtax.class.php b/htdocs/compta/localtax/class/localtax.class.php
    index 6838f9a65b2..49c95c26c2e 100644
    --- a/htdocs/compta/localtax/class/localtax.class.php
    +++ b/htdocs/compta/localtax/class/localtax.class.php
    @@ -55,8 +55,19 @@ class Localtax extends CommonObject
          */
         public $label;
     
    +    /**
    +     * @var int ID
    +     */
     	public $fk_bank;
    +
    +	/**
    +     * @var int ID
    +     */
     	public $fk_user_creat;
    +
    +	/**
    +     * @var int ID
    +     */
     	public $fk_user_modif;
     
         /**
    diff --git a/htdocs/compta/paiement.php b/htdocs/compta/paiement.php
    index 764ca818f7f..94cd53b5424 100644
    --- a/htdocs/compta/paiement.php
    +++ b/htdocs/compta/paiement.php
    @@ -526,7 +526,7 @@ if ($action == 'create' || $action == 'confirm_paiement' || $action == 'add_paie
              */
     
             $sql = 'SELECT f.rowid as facid, f.facnumber, f.total_ttc, f.multicurrency_code, f.multicurrency_total_ttc, f.type,';
    -        $sql.= ' f.datef as df, f.fk_soc as socid';
    +        $sql.= ' f.datef as df, f.fk_soc as socid, f.date_lim_reglement as dlr';
             $sql.= ' FROM '.MAIN_DB_PREFIX.'facture as f';
     		$sql.= ' WHERE f.entity IN ('.getEntity('facture', $conf->entity).')';
             $sql.= ' AND (f.fk_soc = '.$facture->socid;
    @@ -578,6 +578,7 @@ if ($action == 'create' || $action == 'confirm_paiement' || $action == 'add_paie
                     print '<tr class="liste_titre">';
                     print '<td>'.$arraytitle.'</td>';
                     print '<td align="center">'.$langs->trans('Date').'</td>';
    +                print '<td align="center">'.$langs->trans('DateMaxPayment').'</td>';
                     if (!empty($conf->multicurrency->enabled)) print '<td>'.$langs->trans('Currency').'</td>';
                     if (!empty($conf->multicurrency->enabled)) print '<td align="right">'.$langs->trans('MulticurrencyAmountTTC').'</td>';
                     if (!empty($conf->multicurrency->enabled)) print '<td align="right">'.$multicurrencyalreadypayedlabel.'</td>';
    @@ -629,7 +630,25 @@ if ($action == 'create' || $action == 'confirm_paiement' || $action == 'add_paie
     
                         // Date
                         print '<td align="center">'.dol_print_date($db->jdate($objp->df),'day')."</td>\n";
    -
    +                    
    +                    // Date Max Payment
    +                    if ($objp->dlr > 0 )
    +                    {
    +                        print '<td align="center">';
    +                        print dol_print_date($db->jdate($objp->dlr), 'day');
    +                        
    +                        if ($invoice->hasDelay())
    +                        {
    +                            print img_warning($langs->trans('Late'));
    +                        }
    +                        
    +                        print '</td>';
    +                    }
    +                    else
    +                    {
    +                        print '<td align="center"><b>--</b></td>';
    +                    }
    +                    
                         // Currency
                         if (!empty($conf->multicurrency->enabled)) print '<td align="center">'.$objp->multicurrency_code."</td>\n";
     
    diff --git a/htdocs/compta/paiement/cheque/class/remisecheque.class.php b/htdocs/compta/paiement/cheque/class/remisecheque.class.php
    index ade6895ac41..64d0f8601fa 100644
    --- a/htdocs/compta/paiement/cheque/class/remisecheque.class.php
    +++ b/htdocs/compta/paiement/cheque/class/remisecheque.class.php
    @@ -152,6 +152,8 @@ class RemiseCheque extends CommonObject
     
     		$now=dol_now();
     
    +		dol_syslog("RemiseCheque::Create start", LOG_DEBUG);
    +
     		$this->db->begin();
     
     		$sql = "INSERT INTO ".MAIN_DB_PREFIX."bordereau_cheque (";
    @@ -178,7 +180,6 @@ class RemiseCheque extends CommonObject
     		$sql.= ", ''";
     		$sql.= ")";
     
    -		dol_syslog("RemiseCheque::Create", LOG_DEBUG);
     		$resql = $this->db->query($sql);
     		if ( $resql )
     		{
    @@ -195,7 +196,6 @@ class RemiseCheque extends CommonObject
     				$sql.= " SET ref='(PROV".$this->id.")'";
     				$sql.= " WHERE rowid=".$this->id."";
     
    -				dol_syslog("RemiseCheque::Create", LOG_DEBUG);
     				$resql = $this->db->query($sql);
     				if (! $resql)
     				{
    @@ -242,13 +242,12 @@ class RemiseCheque extends CommonObject
     						if($linetoremise==$lineid) $checkremise=true;
     					}
     
    -					if($checkremise==true)
    +					if ($checkremise)
     					{
     						$sql = "UPDATE ".MAIN_DB_PREFIX."bank";
     						$sql.= " SET fk_bordereau = ".$this->id;
     						$sql.= " WHERE rowid = ".$lineid;
     
    -						dol_syslog("RemiseCheque::Create", LOG_DEBUG);
     						$resql = $this->db->query($sql);
     						if (!$resql)
     						{
    @@ -284,11 +283,13 @@ class RemiseCheque extends CommonObject
             if (! $this->errno)
             {
                 $this->db->commit();
    +            dol_syslog("RemiseCheque::Create end", LOG_DEBUG);
                 return $this->id;
             }
             else
             {
                 $this->db->rollback();
    +            dol_syslog("RemiseCheque::Create end", LOG_DEBUG);
                 return $this->errno;
             }
     	}
    diff --git a/htdocs/compta/paiement/cheque/index.php b/htdocs/compta/paiement/cheque/index.php
    index ecb035caeb8..c3cf1634557 100644
    --- a/htdocs/compta/paiement/cheque/index.php
    +++ b/htdocs/compta/paiement/cheque/index.php
    @@ -91,7 +91,7 @@ $max=10;
     
     $sql = "SELECT bc.rowid, bc.date_bordereau as db, bc.amount, bc.ref as ref,";
     $sql.= " bc.statut, bc.nbcheque,";
    -$sql.= " ba.ref, ba.label, ba.rowid as bid, ba.number, ba.currency_code, ba.account_number, ba.fk_accountancy_journal,";
    +$sql.= " ba.ref as bref, ba.label, ba.rowid as bid, ba.number, ba.currency_code, ba.account_number, ba.fk_accountancy_journal,";
     $sql.= " aj.code";
     $sql.= " FROM ".MAIN_DB_PREFIX."bordereau_cheque as bc, ".MAIN_DB_PREFIX."bank_account as ba";
     $sql.= " LEFT JOIN ".MAIN_DB_PREFIX."accounting_journal as aj ON aj.rowid = ba.fk_accountancy_journal";
    @@ -120,7 +120,7 @@ if ($resql)
     	    $checkdepositstatic->statut=$objp->statut;
     
     		$accountstatic->id=$objp->bid;
    -		$accountstatic->ref=$objp->ref;
    +		$accountstatic->ref=$objp->bref;
     		$accountstatic->label=$objp->label;
     		$accountstatic->number=$objp->number;
     		$accountstatic->currency_code=$objp->currency_code;
    diff --git a/htdocs/compta/paiement/class/paiement.class.php b/htdocs/compta/paiement/class/paiement.class.php
    index 952f478087b..18dabbcf980 100644
    --- a/htdocs/compta/paiement/class/paiement.class.php
    +++ b/htdocs/compta/paiement/class/paiement.class.php
    @@ -1,12 +1,14 @@
     <?php
    -/* Copyright (C) 2002-2004 Rodolphe Quiedeville  <rodolphe@quiedeville.org>
    - * Copyright (C) 2004-2010 Laurent Destailleur   <eldy@users.sourceforge.net>
    - * Copyright (C)      2005 Marc Barilley / Ocebo <marc@ocebo.com>
    +/* Copyright (C) 2002-2004  Rodolphe Quiedeville    <rodolphe@quiedeville.org>
    + * Copyright (C) 2004-2010  Laurent Destailleur     <eldy@users.sourceforge.net>
    + * Copyright (C) 2005       Marc Barilley / Ocebo   <marc@ocebo.com>
      * Copyright (C) 2012      Cédric Salvador       <csalvador@gpcsolutions.fr>
      * Copyright (C) 2014      Raphaël Doursenaud    <rdoursenaud@gpcsolutions.fr>
      * Copyright (C) 2014      Marcos García 		 <marcosgdf@gmail.com>
      * Copyright (C) 2015      Juanjo Menent		 <jmenent@2byte.es>
      * Copyright (C) 2018      Ferran Marcet		 <fmarcet@2byte.es>
    + * Copyright (C) 2018      Thibault FOUCART		 <support@ptibogxiv.net>
    + * Copyright (C) 2018       Frédéric France         <frederic.france@netlogic.fr>
      *
      * This program is free software; you can redistribute it and/or modify
      * it under the terms of the GNU General Public License as published by
    @@ -72,14 +74,69 @@ class Paiement extends CommonObject
     	public $author;
     	public $paiementid;	// Type de paiement. Stocke dans fk_paiement
     	// de llx_paiement qui est lie aux types de
    -	//paiement de llx_c_paiement
    -	public $num_paiement;	// Numero du CHQ, VIR, etc...
    -	public $num_payment;	// Numero du CHQ, VIR, etc...
    -	public $bank_account;	// Id compte bancaire du paiement
    -	public $bank_line;     // Id de la ligne d'ecriture bancaire
    +    //paiement de llx_c_paiement
    +
    +    /**
    +     * @var string type libelle
    +     */
    +    public $type_libelle;
    +
    +    /**
    +     * @var string type code
    +     */
    +    public $type_code;
    +
    +    /**
    +     * @var string Numero du CHQ, VIR, etc...
    +     * @deprecated
    +     * @see num_payment
    +     */
    +    public $numero;
    +
    +    /**
    +     * @var string Numero du CHQ, VIR, etc...
    +     * @deprecated
    +     * @see num_payment
    +     */
    +    public $num_paiement;
    +
    +    /**
    +     * @var string Numero du CHQ, VIR, etc...
    +     */
    +    public $num_payment;
    +
    +    /**
    +     * @var string Id of external payment mode
    +     */
    +    public $ext_payment_id;
    +
    +    /**
    +     * @var string Name of external payment mode
    +     */
    +    public $ext_payment_site;
    +
    +    /**
    +     * @var int bank account id of payment
    +     * @deprecated
    +     */
    +    public $bank_account;
    +
    +    /**
    +     * @var int bank account id of payment
    +     */
    +    public $fk_account;
    +
    +    /**
    +     * @var int id of payment line in bank account
    +     */
    +    public $bank_line;
    +
     	// fk_paiement dans llx_paiement est l'id du type de paiement (7 pour CHQ, ...)
    -	// fk_paiement dans llx_paiement_facture est le rowid du paiement
    -    public $fk_paiement;    // Type of paiment
    +    // fk_paiement dans llx_paiement_facture est le rowid du paiement
    +    /**
    +     * @var int payment id
    +     */
    +    public $fk_paiement;    // Type of payment
     
     
     	/**
    @@ -87,7 +144,7 @@ class Paiement extends CommonObject
     	 *
     	 *  @param		DoliDB		$db      Database handler
     	 */
    -	function __construct($db)
    +	public function __construct($db)
     	{
     		$this->db = $db;
     	}
    @@ -100,9 +157,9 @@ class Paiement extends CommonObject
     	 *    @param	int		$fk_bank	Id of bank line associated to payment
     	 *    @return   int		            <0 if KO, 0 if not found, >0 if OK
     	 */
    -	function fetch($id, $ref='', $fk_bank='')
    +	public function fetch($id, $ref='', $fk_bank='')
     	{
    -		$sql = 'SELECT p.rowid, p.ref, p.datep as dp, p.amount, p.statut, p.fk_bank,';
    +		$sql = 'SELECT p.rowid, p.ref, p.datep as dp, p.amount, p.statut, p.ext_payment_id, p.ext_payment_site, p.fk_bank,';
     		$sql.= ' c.code as type_code, c.libelle as type_libelle,';
     		$sql.= ' p.num_paiement as num_payment, p.note,';
     		$sql.= ' b.fk_account';
    @@ -135,6 +192,8 @@ class Paiement extends CommonObject
     				$this->type_libelle   = $obj->type_libelle;
     				$this->type_code      = $obj->type_code;
     				$this->statut         = $obj->statut;
    +                $this->ext_payment_id = $obj->ext_payment_id;
    +                $this->ext_payment_site = $obj->ext_payment_site;
     
     				$this->bank_account   = $obj->fk_account; // deprecated
     				$this->fk_account     = $obj->fk_account;
    @@ -229,8 +288,8 @@ class Paiement extends CommonObject
     		}
     		$note = ($this->note_public?$this->note_public:$this->note);
     
    -		$sql = "INSERT INTO ".MAIN_DB_PREFIX."paiement (entity, ref, datec, datep, amount, multicurrency_amount, fk_paiement, num_paiement, note, fk_user_creat)";
    -		$sql.= " VALUES (".$conf->entity.", '".$this->ref."', '". $this->db->idate($now)."', '".$this->db->idate($this->datepaye)."', '".$total."', '".$mtotal."', ".$this->paiementid.", '".$this->num_paiement."', '".$this->db->escape($note)."', ".$user->id.")";
    +		$sql = "INSERT INTO ".MAIN_DB_PREFIX."paiement (entity, ref, datec, datep, amount, multicurrency_amount, fk_paiement, num_paiement, note, ext_payment_id, ext_payment_site, fk_user_creat)";
    +		$sql.= " VALUES (".$conf->entity.", '".$this->db->escape($this->ref)."', '". $this->db->idate($now)."', '".$this->db->idate($this->datepaye)."', ".$total.", ".$mtotal.", ".$this->paiementid.", '".$this->db->escape($this->num_paiement)."', '".$this->db->escape($note)."', ".($this->ext_payment_id?"'".$this->db->escape($this->ext_payment_id)."'":"null").", ".($this->ext_payment_site?"'".$this->db->escape($this->ext_payment_site)."'":"null").", ".$user->id.")";
     
     		dol_syslog(get_class($this)."::Create insert paiement", LOG_DEBUG);
     		$resql = $this->db->query($sql);
    diff --git a/htdocs/compta/prelevement/create.php b/htdocs/compta/prelevement/create.php
    index 0d07c341458..3dccc0ff912 100644
    --- a/htdocs/compta/prelevement/create.php
    +++ b/htdocs/compta/prelevement/create.php
    @@ -46,7 +46,7 @@ $result = restrictedArea($user, 'prelevement', '', '', 'bons');
     $action = GETPOST('action','alpha');
     $mode = GETPOST('mode','alpha')?GETPOST('mode','alpha'):'real';
     $format = GETPOST('format','aZ09');
    -$limit = GETPOST('limit')?GETPOST('limit','int'):$conf->liste_limit;
    +$limit = GETPOST('limit','int')?GETPOST('limit','int'):$conf->liste_limit;
     $page = GETPOST("page",'int');
     if (empty($page) || $page == -1) { $page = 0; }     // If $page is not defined, or '' or -1
     $offset = $limit * $page;
    diff --git a/htdocs/compta/salaries/class/paymentsalary.class.php b/htdocs/compta/salaries/class/paymentsalary.class.php
    index ea67873c2ee..4da78cb492d 100644
    --- a/htdocs/compta/salaries/class/paymentsalary.class.php
    +++ b/htdocs/compta/salaries/class/paymentsalary.class.php
    @@ -56,7 +56,12 @@ class PaymentSalary extends CommonObject
     	public $datep;
     	public $datev;
     	public $amount;
    +
    +	/**
    +     * @var int ID
    +     */
     	public $fk_project;
    +
     	public $type_payment;
     	public $num_payment;
     
    @@ -67,8 +72,20 @@ class PaymentSalary extends CommonObject
     
     	public $datesp;
     	public $dateep;
    +
    +	/**
    +     * @var int ID
    +     */
     	public $fk_bank;
    +
    +	/**
    +     * @var int ID
    +     */
     	public $fk_user_author;
    +
    +	/**
    +     * @var int ID
    +     */
     	public $fk_user_modif;
     
     
    diff --git a/htdocs/compta/sociales/class/cchargesociales.class.php b/htdocs/compta/sociales/class/cchargesociales.class.php
    index 9013edee195..a8f5c430691 100644
    --- a/htdocs/compta/sociales/class/cchargesociales.class.php
    +++ b/htdocs/compta/sociales/class/cchargesociales.class.php
    @@ -48,7 +48,12 @@ class Cchargesociales
     	public $deductible;
     	public $active;
     	public $code;
    +
    +	/**
    +     * @var int ID
    +     */
     	public $fk_pays;
    +
     	public $module;
     	public $accountancy_code;
     
    diff --git a/htdocs/compta/sociales/class/chargesociales.class.php b/htdocs/compta/sociales/class/chargesociales.class.php
    index aa5786d0eb5..e44d02f83e2 100644
    --- a/htdocs/compta/sociales/class/chargesociales.class.php
    +++ b/htdocs/compta/sociales/class/chargesociales.class.php
    @@ -64,7 +64,15 @@ class ChargeSociales extends CommonObject
         public $date_creation;
         public $date_modification;
         public $date_validation;
    +
    +    /**
    +     * @var int ID
    +     */
         public $fk_account;
    +
    +    /**
    +     * @var int ID
    +     */
     	public $fk_project;
     
     
    diff --git a/htdocs/compta/sociales/class/paymentsocialcontribution.class.php b/htdocs/compta/sociales/class/paymentsocialcontribution.class.php
    index 442e63efe11..b6ff4a49337 100644
    --- a/htdocs/compta/sociales/class/paymentsocialcontribution.class.php
    +++ b/htdocs/compta/sociales/class/paymentsocialcontribution.class.php
    @@ -46,7 +46,11 @@ class PaymentSocialContribution extends CommonObject
     	 */
     	public $picto = 'payment';
     
    +	/**
    +     * @var int ID
    +     */
     	public $fk_charge;
    +
     	public $datec='';
     	public $tms='';
     	public $datep='';
    @@ -59,10 +63,27 @@ class PaymentSocialContribution extends CommonObject
     
         public $amount;            // Total amount of payment
         public $amounts=array();   // Array of amounts
    +
    +    /**
    +     * @var int ID
    +     */
     	public $fk_typepaiement;
    +
     	public $num_paiement;
    +
    +	/**
    +     * @var int ID
    +     */
     	public $fk_bank;
    +
    +	/**
    +     * @var int ID
    +     */
     	public $fk_user_creat;
    +
    +	/**
    +     * @var int ID
    +     */
     	public $fk_user_modif;
     
     	/**
    diff --git a/htdocs/compta/tva/class/tva.class.php b/htdocs/compta/tva/class/tva.class.php
    index 8b407c9be61..c78e0d8dd7a 100644
    --- a/htdocs/compta/tva/class/tva.class.php
    +++ b/htdocs/compta/tva/class/tva.class.php
    @@ -1,8 +1,9 @@
     <?php
    -/* Copyright (C) 2002-2003 Rodolphe Quiedeville <rodolphe@quiedeville.org>
    - * Copyright (C) 2004-2008 Laurent Destailleur  <eldy@users.sourceforge.net>
    - * Copyright (C) 2011-2017 Alexandre Spangaro   <aspangaro@zendsi.com>
    - * Copyright (C) 2018      Philippe Grand       <philippe.grand@atoo-net.com>
    +/* Copyright (C) 2002-2003  Rodolphe Quiedeville    <rodolphe@quiedeville.org>
    + * Copyright (C) 2004-2008  Laurent Destailleur     <eldy@users.sourceforge.net>
    + * Copyright (C) 2011-2017  Alexandre Spangaro      <aspangaro@zendsi.com>
    + * Copyright (C) 2018       Philippe Grand          <philippe.grand@atoo-net.com>
    + * Copyright (C) 2018       Frédéric France         <frederic.france@netlogic.fr>
      *
      * This program is free software; you can redistribute it and/or modify
      * it under the terms of the GNU General Public License as published by
    @@ -60,8 +61,19 @@ class Tva extends CommonObject
          */
         public $label;
     
    +    /**
    +     * @var int ID
    +     */
     	public $fk_bank;
    +
    +	/**
    +     * @var int ID
    +     */
     	public $fk_user_creat;
    +
    +	/**
    +     * @var int ID
    +     */
     	public $fk_user_modif;
     
         /**
    @@ -92,9 +104,9 @@ class Tva extends CommonObject
     		$this->amount=trim($this->amount);
     		$this->label=trim($this->label);
     		$this->note=trim($this->note);
    -		$this->fk_bank=trim($this->fk_bank);
    -		$this->fk_user_creat=trim($this->fk_user_creat);
    -		$this->fk_user_modif=trim($this->fk_user_modif);
    +		$this->fk_bank = (int) $this->fk_bank;
    +		$this->fk_user_creat = (int) $this->fk_user_creat;
    +		$this->fk_user_modif = (int) $this->fk_user_modif;
     
     		// Check parameters
     		// Put here code to add control on parameters values
    @@ -171,9 +183,9 @@ class Tva extends CommonObject
     		$this->amount=trim($this->amount);
     		$this->label=trim($this->label);
     		$this->note=trim($this->note);
    -		$this->fk_bank=trim($this->fk_bank);
    -		$this->fk_user_creat=trim($this->fk_user_creat);
    -		$this->fk_user_modif=trim($this->fk_user_modif);
    +		$this->fk_bank = (int) $this->fk_bank;
    +		$this->fk_user_creat = (int) $this->fk_user_creat;
    +		$this->fk_user_modif = (int) $this->fk_user_modif;
     
     		// Check parameters
     		// Put here code to add control on parameters values
    @@ -508,9 +520,9 @@ class Tva extends CommonObject
             $this->amount=price2num(trim($this->amount));
             $this->label=trim($this->label);
     		$this->note=trim($this->note);
    -		$this->fk_bank=trim($this->fk_bank);
    -		$this->fk_user_creat=trim($this->fk_user_creat);
    -		$this->fk_user_modif=trim($this->fk_user_modif);
    +		$this->fk_bank = (int) $this->fk_bank;
    +		$this->fk_user_creat = (int) $this->fk_user_creat;
    +		$this->fk_user_modif = (int) $this->fk_user_modif;
     		if (empty($this->datec)) $this->datec = dol_now();
     
             // Check parameters
    @@ -652,8 +664,8 @@ class Tva extends CommonObject
     	function update_fk_bank($id_bank)
     	{
             // phpcs:enable
    -		$sql = 'UPDATE '.MAIN_DB_PREFIX.'tva SET fk_bank = '.$id_bank;
    -		$sql.= ' WHERE rowid = '.$this->id;
    +		$sql = 'UPDATE '.MAIN_DB_PREFIX.'tva SET fk_bank = '.(int) $id_bank;
    +		$sql.= ' WHERE rowid = '.(int) $this->id;
     		$result = $this->db->query($sql);
     		if ($result)
     		{
    @@ -758,7 +770,7 @@ class Tva extends CommonObject
     	{
     		$sql = "SELECT t.rowid, t.tms, t.fk_user_modif, t.datec, t.fk_user_creat";
     		$sql.= " FROM ".MAIN_DB_PREFIX."tva as t";
    -		$sql.= " WHERE t.rowid = ".$id;
    +		$sql.= " WHERE t.rowid = ".(int) $id;
     
     		dol_syslog(get_class($this)."::info", LOG_DEBUG);
     		$result=$this->db->query($sql);
    diff --git a/htdocs/contact/class/contact.class.php b/htdocs/contact/class/contact.class.php
    index b8cadaa4632..b5d17676d8d 100644
    --- a/htdocs/contact/class/contact.class.php
    +++ b/htdocs/contact/class/contact.class.php
    @@ -47,7 +47,11 @@ class Contact extends CommonObject
     	 */
     	public $table_element='socpeople';
     
    -	public $ismultientitymanaged = 1;	// 0=No test on entity, 1=Test with field entity, 2=Test with link by societe
    +	/**
    +	 * 0=No test on entity, 1=Test with field entity, 2=Test with link by societe
    +	 * @var int
    +	 */
    +	public $ismultientitymanaged = 1;
     
     	/**
     	 * @var string String with name of icon for myobject. Must be the part after the 'object_' into object_myobject.png
    @@ -889,6 +893,7 @@ class Contact extends CommonObject
     		$sql.=" FROM ".MAIN_DB_PREFIX."element_contact as ec, ".MAIN_DB_PREFIX."c_type_contact as tc";
     		$sql.=" WHERE ec.fk_c_type_contact = tc.rowid";
     		$sql.=" AND fk_socpeople = ". $this->id;
    +		$sql.=" AND tc.source = 'external'";
     		$sql.=" GROUP BY tc.element";
     
     		dol_syslog(get_class($this)."::load_ref_elements", LOG_DEBUG);
    diff --git a/htdocs/contact/list.php b/htdocs/contact/list.php
    index 04132fa9b75..52a2c4bbe7f 100644
    --- a/htdocs/contact/list.php
    +++ b/htdocs/contact/list.php
    @@ -68,6 +68,8 @@ $search_phone_mobile=GETPOST("search_phone_mobile",'alpha');
     $search_fax=GETPOST("search_fax",'alpha');
     $search_email=GETPOST("search_email",'alpha');
     $search_skype=GETPOST("search_skype",'alpha');
    +$search_twitter=GETPOST("search_twitter",'alpha');
    +$search_facebook=GETPOST("search_facebook",'alpha');
     $search_priv=GETPOST("search_priv",'alpha');
     $search_categ=GETPOST("search_categ",'int');
     $search_categ_thirdparty=GETPOST("search_categ_thirdparty",'int');
    @@ -156,7 +158,9 @@ $arrayfields=array(
     	'p.phone_mobile'=>array('label'=>"PhoneMobile", 'checked'=>1),
     	'p.fax'=>array('label'=>"Fax", 'checked'=>0),
     	'p.email'=>array('label'=>"EMail", 'checked'=>1),
    -	'p.skype'=>array('label'=>"Skype", 'checked'=>1, 'enabled'=>(! empty($conf->skype->enabled))),
    +	'p.skype'=>array('label'=>"Skype", 'checked'=>1, 'enabled'=>(! empty($conf->socialnetworks->enabled))),
    +	'p.twitter'=>array('label'=>"Twitter", 'checked'=>1, 'enabled'=>(! empty($conf->socialnetworks->enabled))),
    +	'p.facebook'=>array('label'=>"Facebook", 'checked'=>1, 'enabled'=>(! empty($conf->socialnetworks->enabled))),
     	'p.thirdparty'=>array('label'=>"ThirdParty", 'checked'=>1, 'enabled'=>empty($conf->global->SOCIETE_DISABLE_CONTACTS)),
     	'p.priv'=>array('label'=>"ContactVisibility", 'checked'=>1, 'position'=>200),
     	'p.datec'=>array('label'=>"DateCreationShort", 'checked'=>0, 'position'=>500),
    @@ -198,7 +202,7 @@ if (empty($reshook))
     	include DOL_DOCUMENT_ROOT.'/core/actions_changeselectedfields.inc.php';
     
     	// Did we click on purge search criteria ?
    -	if (GETPOST('button_removefilter_x') || GETPOST('button_removefilter.x') || GETPOST('button_removefilter'))	// All tests are required to be compatible with all browsers
    +	if (GETPOST('button_removefilter_x', 'alpha') || GETPOST('button_removefilter.x', 'alpha') || GETPOST('button_removefilter', 'alpha'))	// All tests are required to be compatible with all browsers
     	{
     		$sall="";
     		$search_id='';
    @@ -217,6 +221,8 @@ if (empty($reshook))
     		$search_fax="";
     		$search_email="";
     		$search_skype="";
    +		$search_twitter="";
    +		$search_facebook="";
     		$search_priv="";
     		$search_status=-1;
     		$search_categ='';
    @@ -311,6 +317,8 @@ if (strlen($search_phone_pro))      $sql.= natural_search('p.phone', $search_pho
     if (strlen($search_phone_mobile))   $sql.= natural_search('p.phone_mobile', $search_phone_mobile);
     if (strlen($search_fax))            $sql.= natural_search('p.fax', $search_fax);
     if (strlen($search_skype))          $sql.= natural_search('p.skype', $search_skype);
    +if (strlen($search_twitter))        $sql.= natural_search('p.twitter', $search_twitter);
    +if (strlen($search_facebook))       $sql.= natural_search('p.facebook', $search_facebook);
     if (strlen($search_email))          $sql.= natural_search('p.email', $search_email);
     if (strlen($search_zip))   			$sql.= natural_search("p.zip",$search_zip);
     if ($search_status != '' && $search_status >= 0) $sql.= " AND p.statut = ".$db->escape($search_status);
    @@ -601,6 +609,18 @@ if (! empty($arrayfields['p.skype']['checked']))
     	print '<input class="flat" type="text" name="search_skype" size="6" value="'.dol_escape_htmltag($search_skype).'">';
     	print '</td>';
     }
    +if (! empty($arrayfields['p.twitter']['checked']))
    +{
    +	print '<td class="liste_titre">';
    +	print '<input class="flat" type="text" name="search_twitter" size="6" value="'.dol_escape_htmltag($search_twitter).'">';
    +	print '</td>';
    +}
    +if (! empty($arrayfields['p.facebook']['checked']))
    +{
    +	print '<td class="liste_titre">';
    +	print '<input class="flat" type="text" name="search_facebook" size="6" value="'.dol_escape_htmltag($search_facebook).'">';
    +	print '</td>';
    +}
     if (! empty($arrayfields['p.thirdparty']['checked']))
     {
     	print '<td class="liste_titre">';
    @@ -671,6 +691,8 @@ if (! empty($arrayfields['p.phone_mobile']['checked']))        print_liste_field
     if (! empty($arrayfields['p.fax']['checked']))                 print_liste_field_titre($arrayfields['p.fax']['label'],$_SERVER["PHP_SELF"],"p.fax", $begin, $param, '', $sortfield,$sortorder);
     if (! empty($arrayfields['p.email']['checked']))               print_liste_field_titre($arrayfields['p.email']['label'],$_SERVER["PHP_SELF"],"p.email", $begin, $param, '', $sortfield,$sortorder);
     if (! empty($arrayfields['p.skype']['checked']))               print_liste_field_titre($arrayfields['p.skype']['label'],$_SERVER["PHP_SELF"],"p.skype", $begin, $param, '', $sortfield,$sortorder);
    +if (! empty($arrayfields['p.twitter']['checked']))             print_liste_field_titre($arrayfields['p.twitter']['label'],$_SERVER["PHP_SELF"],"p.twitter", $begin, $param, '', $sortfield,$sortorder);
    +if (! empty($arrayfields['p.facebook']['checked']))            print_liste_field_titre($arrayfields['p.facebook']['label'],$_SERVER["PHP_SELF"],"p.facebook", $begin, $param, '', $sortfield,$sortorder);
     if (! empty($arrayfields['p.thirdparty']['checked']))          print_liste_field_titre($arrayfields['p.thirdparty']['label'],$_SERVER["PHP_SELF"],"s.nom", $begin, $param, '', $sortfield,$sortorder);
     if (! empty($arrayfields['p.priv']['checked']))                print_liste_field_titre($arrayfields['p.priv']['label'],$_SERVER["PHP_SELF"],"p.priv", $begin, $param, 'align="center"', $sortfield,$sortorder);
     // Extra fields
    @@ -801,7 +823,19 @@ while ($i < min($num,$limit))
     	// Skype
     	if (! empty($arrayfields['p.skype']['checked']))
     	{
    -		if (! empty($conf->skype->enabled)) { print '<td>'.dol_print_skype($obj->skype,$obj->rowid,$obj->socid,'AC_SKYPE',18).'</td>'; }
    +		if (! empty($conf->socialnetworks->enabled)) { print '<td>'.dol_print_socialnetworks($obj->skype,$obj->rowid,$obj->socid,'skype').'</td>'; }
    +		if (! $i) $totalarray['nbfield']++;
    +	}
    +	// Twitter
    +	if (! empty($arrayfields['p.twitter']['checked']))
    +	{
    +		if (! empty($conf->socialnetworks->enabled)) { print '<td>'.dol_print_socialnetworks($obj->twitter,$obj->rowid,$obj->socid,'twitter').'</td>'; }
    +		if (! $i) $totalarray['nbfield']++;
    +	}
    +	// Facebook
    +	if (! empty($arrayfields['p.facebook']['checked']))
    +	{
    +		if (! empty($conf->socialnetworks->enabled)) { print '<td>'.dol_print_socialnetworks($obj->facebook,$obj->rowid,$obj->socid,'facebook').'</td>'; }
     		if (! $i) $totalarray['nbfield']++;
     	}
     	// Company
    diff --git a/htdocs/contrat/class/contrat.class.php b/htdocs/contrat/class/contrat.class.php
    index 2bcb802000f..7e0c2d13ca5 100644
    --- a/htdocs/contrat/class/contrat.class.php
    +++ b/htdocs/contrat/class/contrat.class.php
    @@ -10,6 +10,7 @@
      * Copyright (C) 2014-2015	Marcos García			<marcosgdf@gmail.com>
      * Copyright (C) 2015-2017	Ferran Marcet			<fmarcet@2byte.es>
      * Copyright (C) 2018   	Nicolas ZABOURI			<info@inovea-conseil.com>
    + * Copyright (C) 2018       Frédéric France         <frederic.france@netlogic.fr>
      *
      * This program is free software; you can redistribute it and/or modify
      * it under the terms of the GNU General Public License as published by
    @@ -2519,8 +2520,16 @@ class ContratLigne extends CommonObjectLine
     
     	public $tms;
     
    +	/**
    +     * @var int ID
    +     */
     	public $fk_contrat;
    +
    +	/**
    +     * @var int ID
    +     */
     	public $fk_product;
    +
     	public $statut;					// 0 inactive, 4 active, 5 closed
     	public $type;						// 0 for product, 1 for service
     
    @@ -2563,6 +2572,10 @@ class ContratLigne extends CommonObjectLine
     	public $qty;
     	public $remise_percent;
     	public $remise;
    +
    +	/**
    +     * @var int ID
    +     */
     	public $fk_remise_except;
     
     	public $subprice;					// Unit price HT
    @@ -2582,13 +2595,30 @@ class ContratLigne extends CommonObjectLine
     	public $total_localtax2;
     	public $total_ttc;
     
    +	/**
    +     * @var int ID
    +     */
     	public $fk_fournprice;
    +
     	public $pa_ht;
     
     	public $info_bits;
    +
    +	/**
    +     * @var int ID
    +     */
     	public $fk_user_author;
    +
    +	/**
    +     * @var int ID
    +     */
     	public $fk_user_ouverture;
    +
    +	/**
    +     * @var int ID
    +     */
     	public $fk_user_cloture;
    +
     	public $commentaire;
     
     	const STATUS_INITIAL = 0;
    @@ -2858,9 +2888,9 @@ class ContratLigne extends CommonObjectLine
     		$error=0;
     
     		// Clean parameters
    -		$this->fk_contrat=trim($this->fk_contrat);
    -		$this->fk_product=trim($this->fk_product);
    -		$this->statut=(int) $this->statut;
    +		$this->fk_contrat = (int) $this->fk_contrat;
    +		$this->fk_product = (int) $this->fk_product;
    +		$this->statut = (int) $this->statut;
     		$this->label=trim($this->label);
     		$this->description=trim($this->description);
     		$this->vat_src_code=trim($this->vat_src_code);
    @@ -2870,7 +2900,7 @@ class ContratLigne extends CommonObjectLine
     		$this->qty=trim($this->qty);
     		$this->remise_percent=trim($this->remise_percent);
     		$this->remise=trim($this->remise);
    -		$this->fk_remise_except=trim($this->fk_remise_except);
    +		$this->fk_remise_except = (int) $this->fk_remise_except;
     		$this->subprice=price2num($this->subprice);
     		$this->price_ht=price2num($this->price_ht);
     		$this->total_ht=trim($this->total_ht);
    @@ -2879,9 +2909,9 @@ class ContratLigne extends CommonObjectLine
     		$this->total_localtax2=trim($this->total_localtax2);
     		$this->total_ttc=trim($this->total_ttc);
     		$this->info_bits=trim($this->info_bits);
    -		$this->fk_user_author=trim($this->fk_user_author);
    -		$this->fk_user_ouverture=trim($this->fk_user_ouverture);
    -		$this->fk_user_cloture=trim($this->fk_user_cloture);
    +		$this->fk_user_author = (int) $this->fk_user_author;
    +		$this->fk_user_ouverture = (int) $this->fk_user_ouverture;
    +		$this->fk_user_cloture = (int) $this->fk_user_cloture;
     		$this->commentaire=trim($this->commentaire);
     		//if (empty($this->subprice)) $this->subprice = 0;
     		if (empty($this->price_ht)) $this->price_ht = 0;
    diff --git a/htdocs/core/actions_linkedfiles.inc.php b/htdocs/core/actions_linkedfiles.inc.php
    index 297f7821599..58f96b7faf1 100644
    --- a/htdocs/core/actions_linkedfiles.inc.php
    +++ b/htdocs/core/actions_linkedfiles.inc.php
    @@ -50,13 +50,17 @@ if (GETPOST('sendit','alpha') && ! empty($conf->global->MAIN_UPLOAD_DOC))
     
     		if (! $error)
     		{
    +			// Define if we have to generate thumbs or not
    +			$generatethumbs = 1;
    +			if (GETPOST('section_dir')) $generatethumbs=0;
    +
     			if (! empty($upload_dirold) && ! empty($conf->global->PRODUCT_USE_OLD_PATH_FOR_PHOTO))
     			{
    -				$result = dol_add_file_process($upload_dirold, 0, 1, 'userfile', GETPOST('savingdocmask', 'alpha'));
    +				$result = dol_add_file_process($upload_dirold, 0, 1, 'userfile', GETPOST('savingdocmask', 'alpha'), null, '', $generatethumbs);
     			}
     			elseif (! empty($upload_dir))
     			{
    -				$result = dol_add_file_process($upload_dir, 0, 1, 'userfile', GETPOST('savingdocmask', 'alpha'));
    +				$result = dol_add_file_process($upload_dir, 0, 1, 'userfile', GETPOST('savingdocmask', 'alpha'), null, '', $generatethumbs);
     			}
     		}
     	}
    @@ -69,7 +73,7 @@ elseif (GETPOST('linkit','none') && ! empty($conf->global->MAIN_UPLOAD_DOC))
             if (substr($link, 0, 7) != 'http://' && substr($link, 0, 8) != 'https://' && substr($link, 0, 7) != 'file://') {
                 $link = 'http://' . $link;
             }
    -        dol_add_file_process($upload_dir, 0, 1, 'userfile', null, $link);
    +        dol_add_file_process($upload_dir, 0, 1, 'userfile', null, $link, '', 0);
         }
     }
     
    @@ -77,20 +81,23 @@ elseif (GETPOST('linkit','none') && ! empty($conf->global->MAIN_UPLOAD_DOC))
     // Delete file/link
     if ($action == 'confirm_deletefile' && $confirm == 'yes')
     {
    -        $urlfile = GETPOST('urlfile', 'alpha', 0, null, null, 1);	// Do not use urldecode here ($_GET and $_REQUEST are already decoded by PHP).
    -        if (GETPOST('section', 'alpha')) $file = $upload_dir . "/" . $urlfile;	// For a delete of GED module urlfile contains full path from upload_dir
    -        else															// For documents pages, upload_dir contains already path to file from module dir, so we clean path into urlfile.
    +        $urlfile = GETPOST('urlfile', 'alpha', 0, null, null, 1);				// Do not use urldecode here ($_GET and $_REQUEST are already decoded by PHP).
    +        if (GETPOST('section', 'alpha')) 	// For a delete from the ECM module, upload_dir is ECM root dir and urlfile contains relative path from upload_dir
    +        {
    +        	$file = $upload_dir . (preg_match('/\/$/', $upload_dir) ? '' : '/') . $urlfile;
    +        }
    +        else								// For a delete from the file manager into another module, or from documents pages, upload_dir contains already path to file from module dir, so we clean path into urlfile.
     		{
            		$urlfile=basename($urlfile);
    -			$file = $upload_dir . "/" . $urlfile;
    +       		$file = $upload_dir . (preg_match('/\/$/', $upload_dir) ? '' : '/') . $urlfile;
     			if (! empty($upload_dirold)) $fileold = $upload_dirold . "/" . $urlfile;
     		}
    -        $linkid = GETPOST('linkid', 'int');	// Do not use urldecode here ($_GET and $_REQUEST are already decoded by PHP).
    +        $linkid = GETPOST('linkid', 'int');
     
    -        if ($urlfile)
    +        if ($urlfile)		// delete of a file
             {
    -	        $dir = dirname($file).'/';     // Chemin du dossier contenant l'image d'origine
    -	        $dirthumb = $dir.'/thumbs/';   // Chemin du dossier contenant la vignette
    +	        $dir = dirname($file).'/';		// Chemin du dossier contenant l'image d'origine
    +	        $dirthumb = $dir.'/thumbs/';	// Chemin du dossier contenant la vignette (if file is an image)
     
     	        $ret = dol_delete_file($file, 0, 0, 0, (is_object($object)?$object:null));
                 if (! empty($fileold)) dol_delete_file($fileold, 0, 0, 0, (is_object($object)?$object:null));     // Delete file using old path
    @@ -114,7 +121,7 @@ if ($action == 'confirm_deletefile' && $confirm == 'yes')
                 if ($ret) setEventMessages($langs->trans("FileWasRemoved", $urlfile), null, 'mesgs');
                 else setEventMessages($langs->trans("ErrorFailToDeleteFile", $urlfile), null, 'errors');
             }
    -        elseif ($linkid)
    +        elseif ($linkid)	// delete of external link
             {
                 require_once DOL_DOCUMENT_ROOT . '/core/class/link.class.php';
                 $link = new Link($db);
    @@ -143,7 +150,7 @@ if ($action == 'confirm_deletefile' && $confirm == 'yes')
             	}
             	else
             	{
    -        		header('Location: ' . $_SERVER["PHP_SELF"] . '?id=' . $object->id.(!empty($withproject)?'&withproject=1':''));
    +        		header('Location: '.$_SERVER["PHP_SELF"].'?id='.$object->id.(GETPOST('section_dir','alpha')?'&section_dir='.urlencode(GETPOST('section_dir','alpha')):'').(!empty($withproject)?'&withproject=1':''));
             		exit;
             	}
             }
    @@ -208,13 +215,20 @@ elseif ($action == 'renamefile' && GETPOST('renamefilesave','alpha'))
     	            		$result = dol_move($srcpath, $destpath);
     			            if ($result)
     			            {
    -			            	if ($object->id)
    -			            	{
    -			                	$object->addThumbs($destpath);
    -			            	}
    +			            	// Define if we have to generate thumbs or not
    +			            	$generatethumbs = 1;
    +			            	if (GETPOST('section_dir')) $generatethumbs=0;
     
    -			                // TODO Add revert function of addThumbs to remove for old name
    -			                //$object->delThumbs($srcpath);
    +			            	if ($generatethumbs)
    +			            	{
    +				            	if ($object->id)
    +				            	{
    +				                	$object->addThumbs($destpath);
    +				            	}
    +
    +				                // TODO Add revert function of addThumbs to remove thumbs with old name
    +				                //$object->delThumbs($srcpath);
    +			            	}
     
     			                setEventMessages($langs->trans("FileRenamed"), null);
     			            }
    diff --git a/htdocs/core/actions_massactions.inc.php b/htdocs/core/actions_massactions.inc.php
    index 2bb55264cf9..6621ffaeb8a 100644
    --- a/htdocs/core/actions_massactions.inc.php
    +++ b/htdocs/core/actions_massactions.inc.php
    @@ -1098,6 +1098,18 @@ if (! $error && ($massaction == 'delete' || ($action == 'delete' && $confirm ==
     				continue;
     			}
     
    +			if ($objectclass == "Task" && $objecttmp->hasChildren() > 0)
    +			{
    +				$sql = "UPDATE ".MAIN_DB_PREFIX."projet_task SET fk_task_parent = 0 WHERE fk_task_parent = ".$objecttmp->id;
    +				$res = $db->query($sql);
    +
    +				if (!$res)
    +				{
    +					setEventMessage('ErrorRecordParentingNotModified', 'errors');
    +					$error++;
    +				}
    +			}
    +
     			if (in_array($objecttmp->element, array('societe', 'member'))) $result = $objecttmp->delete($objecttmp->id, $user, 1);
     			else $result = $objecttmp->delete($user);
     
    diff --git a/htdocs/core/actions_printing.inc.php b/htdocs/core/actions_printing.inc.php
    index d2d34cd523a..d5c40c17ad0 100644
    --- a/htdocs/core/actions_printing.inc.php
    +++ b/htdocs/core/actions_printing.inc.php
    @@ -47,11 +47,21 @@ if ($action == 'print_file' && $user->rights->printing->read) {
                 {
                     $printerfound++;
     
    -                $subdir=(GETPOST('printer', 'alpha')=='expedition'?'sending':'');
    +                $subdir='';
                     $module = GETPOST('printer', 'alpha');
    -                if ($module =='commande_fournisseur') {
    -                    $module = 'fournisseur';
    -                    $subdir = 'commande';
    +                switch ($module )
    +                {
    +                    case 'livraison' :
    +                        $subdir = 'receipt';
    +                        $module = 'expedition';
    +                        break;
    +                    case 'expedition' :
    +                        $subdir = 'sending';
    +                        break;
    +                    case 'commande_fournisseur' :
    +                        $module = 'fournisseur';
    +                        $subdir = 'commande';
    +                        break;
                     }
                     try {
                         $ret = $printer->printFile(GETPOST('file', 'alpha'), $module, $subdir);
    diff --git a/htdocs/core/actions_sendmails.inc.php b/htdocs/core/actions_sendmails.inc.php
    index 6afd6b1e354..153c5ca9364 100644
    --- a/htdocs/core/actions_sendmails.inc.php
    +++ b/htdocs/core/actions_sendmails.inc.php
    @@ -425,7 +425,7 @@ if (($action == 'send' || $action == 'relance') && ! $_POST['addfile'] && ! $_PO
     					    if (empty($actiontypecode)) $actiontypecode='AC_OTH_AUTO'; // Event insert into agenda automatically
     
     						$object->socid			= $sendtosocid;	   // To link to a company
    -						$object->sendtoid		= $sendtoid;	   // To link to contacts/addresses. This is an array.
    +						$object->sendtoid		= $sendtoid;	   // To link to contact addresses. This is an array.
     						$object->actiontypecode	= $actiontypecode; // Type of event ('AC_OTH', 'AC_OTH_AUTO', 'AC_XXX'...)
     						$object->actionmsg		= $actionmsg;      // Long text
     						$object->actionmsg2		= $actionmsg2;     // Short text
    diff --git a/htdocs/core/ajax/ajaxdirpreview.php b/htdocs/core/ajax/ajaxdirpreview.php
    index 8d1c5cd712c..82f83595537 100644
    --- a/htdocs/core/ajax/ajaxdirpreview.php
    +++ b/htdocs/core/ajax/ajaxdirpreview.php
    @@ -82,9 +82,16 @@ else    // For no ajax call
                 dol_print_error($db,$ecmdir->error);
                 exit;
             }
    +
    +        $relativepath=$ecmdir->getRelativePath();	// Example   'mydir/'
         }
    -    $relativepath=$ecmdir->getRelativePath();
    -    $upload_dir = $rootdirfordoc.'/'.$relativepath;
    +	elseif (GETPOST('section_dir'))
    +	{
    +		$relativepath=GETPOST('section_dir');
    +	}
    +	//var_dump($section.'-'.GETPOST('section_dir').'-'.$relativepath);
    +
    +	$upload_dir = $rootdirfordoc.'/'.$relativepath;
     }
     
     if (empty($url))
    @@ -226,7 +233,18 @@ if ($type == 'directory')
         {
         	if ($module == 'medias')
         	{
    -    		$relativepath=GETPOST('file','alpha');
    +    		/*
    +    		   $_POST is array like
    +    		  'token' => string '062380e11b7dcd009d07318b57b71750' (length=32)
    +			  'action' => string 'file_manager' (length=12)
    +			  'website' => string 'template' (length=8)
    +			  'pageid' => string '124' (length=3)
    +			  'section_dir' => string 'mydir/' (length=3)
    +			  'section_id' => string '0' (length=1)
    +			  'max_file_size' => string '2097152' (length=7)
    +			  'sendit' => string 'Envoyer fichier' (length=15)
    +    		 */
    +    		$relativepath=GETPOST('file','alpha')?GETPOST('file','alpha'):GETPOST('section_dir','alpha');
         		if ($relativepath && $relativepath!= '/') $relativepath.='/';
         		$upload_dir = $dolibarr_main_data_root.'/'.$module.'/'.$relativepath;
         		if (GETPOSTISSET('website') || GETPOSTISSET('file_manager'))
    diff --git a/htdocs/core/ajax/ajaxdirtree.php b/htdocs/core/ajax/ajaxdirtree.php
    index 4b588751829..a1fafa80559 100644
    --- a/htdocs/core/ajax/ajaxdirtree.php
    +++ b/htdocs/core/ajax/ajaxdirtree.php
    @@ -1,5 +1,6 @@
     <?php
    -/* Copyright (C) 2007-2012 Laurent Destailleur  <eldy@users.sourceforge.net>
    +/* Copyright (C) 2007-2018  Laurent Destailleur     <eldy@users.sourceforge.net>
    + * Copyright (C) 2018       Frédéric France         <frederic.france@netlogic.fr>
      *
      * This program is free software; you can redistribute it and/or modify
      * it under the terms of the GNU General Public License as published by
    @@ -30,6 +31,7 @@ if (! defined('NOREQUIREMENU')) define('NOREQUIREMENU','1');
     if (! defined('NOREQUIREHTML')) define('NOREQUIREHTML','1');
     if (! defined('NOREQUIREAJAX')) define('NOREQUIREAJAX','1');
     
    +
     if (! isset($mode) || $mode != 'noajax')    // For ajax call
     {
     	$res=@include '../../main.inc.php';
    @@ -39,16 +41,26 @@ if (! isset($mode) || $mode != 'noajax')    // For ajax call
     	include_once DOL_DOCUMENT_ROOT.'/core/class/html.form.class.php';
     	include_once DOL_DOCUMENT_ROOT.'/ecm/class/ecmdirectory.class.php';
     
    +	//if (GETPOST('preopened')) { $_GET['dir'] = $_POST['dir'] = '/bbb/'; }
    +
     	$openeddir = GETPOST('openeddir');
     	$modulepart= GETPOST('modulepart');
     	$selecteddir = jsUnEscape(GETPOST('dir'));        // relative path. We must decode using same encoding function used by javascript: escape()
    +
    +	$preopened = GETPOST('preopened');
    +
     	if ($selecteddir != '/') $selecteddir = preg_replace('/\/$/','',$selecteddir);    // We removed last '/' except if it is '/'
     }
     else    // For no ajax call
     {
    +	//if (GETPOST('preopened')) { $_GET['dir'] = $_POST['dir'] = GETPOST('preopened'); }
    +
     	$openeddir = GETPOST('openeddir');
     	$modulepart= GETPOST('modulepart');
     	$selecteddir = GETPOST('dir');
    +
    +	$preopened = GETPOST('preopened');
    +
     	if ($selecteddir != '/') $selecteddir = preg_replace('/\/$/','',$selecteddir);    // We removed last '/' except if it is '/'
     	if (empty($url)) $url=DOL_URL_ROOT.'/ecm/index.php';
     }
    @@ -58,8 +70,16 @@ $langs->load("ecm");
     
     // Define fullpathselecteddir.
     $fullpathselecteddir='<none>';
    -if ($modulepart == 'ecm') $fullpathselecteddir=$conf->ecm->dir_output.'/'.($selecteddir != '/' ? $selecteddir : '');
    -if ($modulepart == 'medias') $fullpathselecteddir=$dolibarr_main_data_root.'/medias/'.($selecteddir != '/' ? $selecteddir : '');
    +if ($modulepart == 'ecm')
    +{
    +	$fullpathselecteddir=$conf->ecm->dir_output.'/'.($selecteddir != '/' ? $selecteddir : '');
    +	$fullpathpreopened=$conf->ecm->dir_output.'/'.($preopened != '/' ? $preopened : '');
    +}
    +elseif ($modulepart == 'medias')
    +{
    +	$fullpathselecteddir=$dolibarr_main_data_root.'/medias/'.($selecteddir != '/' ? $selecteddir : '');
    +	$fullpathpreopened=$dolibarr_main_data_root.'/medias/'.($preopened != '/' ? $preopened : '');
    +}
     
     
     // Security:
    @@ -77,7 +97,7 @@ if ($modulepart == 'ecm')
     {
     	if (! $user->rights->ecm->read) accessforbidden();
     }
    -if ($modulepart == 'medias')
    +elseif ($modulepart == 'medias')
     {
     	// Always allowed
     }
    @@ -87,20 +107,20 @@ if ($modulepart == 'medias')
      * View
      */
     
    -if (! isset($mode) || $mode != 'noajax')
    +if (! isset($mode) || $mode != 'noajax')	// if ajax mode
     {
     	top_httphead();
     }
     
    -//print '<!-- selecteddir = '.$selecteddir.', openeddir = '.$openeddir.', modulepart='.$modulepart.' -->'."\n";
    +//print '<!-- selecteddir (relative dir we click on) = '.$selecteddir.', openeddir = '.$openeddir.', modulepart='.$modulepart.', preopened='.$preopened.' -->'."\n";
     $userstatic=new User($db);
     $form=new Form($db);
     $ecmdirstatic = new EcmDirectory($db);
     
    -// Load full tree from database. We will use it to define nbofsubdir and nboffilesinsubdir
    +// Load full tree of ECM module from database. We will use it to define nbofsubdir and nboffilesinsubdir
     if (empty($sqltree)) $sqltree=$ecmdirstatic->get_full_arbo(0);
     
    -// Try to find key into $sqltree
    +// Try to find selected dir id into $sqltree and save it into $current_ecmdir_id
     $current_ecmdir_id=-1;
     foreach($sqltree as $keycursor => $val)
     {
    @@ -113,131 +133,13 @@ foreach($sqltree as $keycursor => $val)
     
     if (! empty($conf->use_javascript_ajax) && empty($conf->global->MAIN_ECM_DISABLE_JS))
     {
    -	if (file_exists($fullpathselecteddir))
    -	{
    -		$files = @scandir($fullpathselecteddir);
    +	treeOutputForAbsoluteDir($sqltree, $selecteddir, $fullpathselecteddir, $modulepart, $websitekey, $pageid, $preopened, $fullpathpreopened);
     
    -		if ($files)
    -	    {
    -	    	natcasesort($files);
    -	    	if (count($files) > 2)    /* The 2 accounts for . and .. */
    -	    	{
    -	    		echo '<ul class="ecmjqft" style="display: none;">'."\n";
    -
    -	    		// All dirs
    -	    		foreach ($files as $file)    // $file can be '.', '..', or 'My dir' or 'My file'
    -	    		{
    -	    		    if ($file == 'temp') continue;
    -
    -	    	        $nbofsubdir=0;
    -	    	        $nboffilesinsubdir=0;
    -
    -	    	        $val=array();
    -
    -	    	        // Loop on all database entries (sqltree) to find the one matching the subdir found into dir to scan
    -			        foreach($sqltree as $key => $tmpval)
    -			        {
    -	    	            //print "-- key=".$key." - ".$tmpval['fullrelativename']." vs ".(($selecteddir != '/'?$selecteddir.'/':'').$file)."<br>\n";
    -			        	if ($tmpval['fullrelativename'] == (($selecteddir != '/'?$selecteddir.'/':'').$file))		// We found equivalent record into database
    -			            {
    -			                $val=$tmpval;
    -			                $resarray=tree_showpad($sqltree,$key,1);
    -
    -			                // Refresh cache for this subdir
    -			            	if (isset($val['cachenbofdoc']) && $val['cachenbofdoc'] < 0)	// Cache is not up to date, so we update it for this directory t
    -			            	{
    -			            		$result=$ecmdirstatic->fetch($val['id']);
    -			            		$ecmdirstatic->ref=$ecmdirstatic->label;
    -
    -			            		$result=$ecmdirstatic->refreshcachenboffile(0);
    -			            		$val['cachenbofdoc']=$result;
    -			            	}
    -
    -	                        $a=$resarray[0];
    -	                        $nbofsubdir=$resarray[1];
    -	                        $nboffilesinsubdir=$resarray[2];
    -	                        break;
    -			            }
    -			        }
    -
    -	    		    //print 'modulepart='.$modulepart.' fullpathselecteddir='.$fullpathselecteddir.' - val[fullrelativename] (in database)='.$val['fullrelativename'].' - val[id]='.$val['id'].' - is_dir='.dol_is_dir($fullpathselecteddir . $file).' - file='.$file."\n";
    -	    		    if ($file != '.' && $file != '..' && ((! empty($val['fullrelativename']) && $val['id'] >= 0) || dol_is_dir($fullpathselecteddir . (preg_match('/\/$/',$fullpathselecteddir)?'':'/') . $file)))
    -	    		    {
    -						if (empty($val['fullrelativename']))	// If we did not find entry into database, but found a directory (dol_is_dir was ok at previous test)
    -						{
    -	    		    		$val['fullrelativename']=(($selecteddir && $selecteddir != '/')?$selecteddir.'/':'').$file;
    -	    		    		$val['id']=0;
    -	    		    		$val['label']=$file;
    -	    		    		$val['description']='';
    -	    		    		$nboffilesinsubdir=$langs->trans("Unknown");
    -						}
    -
    -			        	print '<li class="directory collapsed">';
    -
    -	    				print "<a class=\"fmdirlia jqft ecmjqft\" href=\"";
    -	    				print "#";
    -	    				print "\" rel=\"" . dol_escape_htmltag($val['fullrelativename'].'/') . "\" id=\"fmdirlia_id_".$val['id']."\"";
    -						print " onClick=\"loadandshowpreview('".dol_escape_js($val['fullrelativename'])."',".$val['id'].")";
    -	    				print "\">";
    -	    				print dol_escape_htmltag($file);
    -	    				print "</a>";
    -
    -	    				print '<div class="ecmjqft">';
    -
    -	    				print '<table class="nobordernopadding"><tr>';
    -
    -	    				/*print '<td align="left">';
    -	    				print dol_escape_htmltag($file);
    -	    				print '</td>';*/
    -
    -	    				// Nb of docs
    -	    				print '<td align="right">';
    -	    				print (isset($val['cachenbofdoc']) && $val['cachenbofdoc']  >= 0)?$val['cachenbofdoc']:'&nbsp;';
    -	    				print '</td>';
    -	    				print '<td align="left">';
    -	    				if ($nbofsubdir > 0  && $nboffilesinsubdir > 0) print '<font color="#AAAAAA">+'.$nboffilesinsubdir.'</font> ';
    -	    				print '</td>';
    -
    -	    				// Edit link
    -	    				print '<td align="right" width="18"><a href="';
    -	    				print DOL_URL_ROOT.'/ecm/dir_card.php?module='.urlencode($modulepart).'&section='.$val['id'].'&relativedir='.urlencode($val['fullrelativename']);
    -	    				print '&backtopage='.urlencode($_SERVER["PHP_SELF"].'?file_manager=1&website='.$websitekey.'&pageid='.$pageid);
    -	    				print '">'.img_edit($langs->trans("Edit").' - '.$langs->trans("View"), 0, 'class="valignmiddle opacitymedium"').'</a></td>';
    -
    -	    				// Add link
    -	    				//print '<td align="right"><a href="'.DOL_URL_ROOT.'/ecm/dir_add_card.php?action=create&amp;catParent='.$val['id'].'">'.img_edit_add().'</a></td>';
    -	    				//print '<td align="right" width="14">&nbsp;</td>';
    -
    -	    				// Info
    -	    				if ($modulepart == 'ecm')
    -	    				{
    -	    					print '<td align="right" width="18">';
    -		    				$userstatic->id=isset($val['fk_user_c'])?$val['fk_user_c']:0;
    -		    				$userstatic->lastname=isset($val['login_c'])?$val['login_c']:0;
    -		    				$htmltooltip='<b>'.$langs->trans("ECMSection").'</b>: '.$val['label'].'<br>';
    -		    				$htmltooltip='<b>'.$langs->trans("Type").'</b>: '.$langs->trans("ECMSectionManual").'<br>';
    -		    				$htmltooltip.='<b>'.$langs->trans("ECMCreationUser").'</b>: '.$userstatic->getNomUrl(1, '', false, 1).'<br>';
    -		    				$htmltooltip.='<b>'.$langs->trans("ECMCreationDate").'</b>: '.(isset($val['date_c'])?dol_print_date($val['date_c'],"dayhour"):$langs->trans("NeedRefresh")).'<br>';
    -		    				$htmltooltip.='<b>'.$langs->trans("Description").'</b>: '.$val['description'].'<br>';
    -		    				$htmltooltip.='<b>'.$langs->trans("ECMNbOfFilesInDir").'</b>: '.((isset($val['cachenbofdoc']) && $val['cachenbofdoc'] >= 0)?$val['cachenbofdoc']:$langs->trans("NeedRefresh")).'<br>';
    -		    				if ($nboffilesinsubdir > 0) $htmltooltip.='<b>'.$langs->trans("ECMNbOfFilesInSubDir").'</b>: '.$nboffilesinsubdir;
    -		    				else $htmltooltip.='<b>'.$langs->trans("ECMNbOfSubDir").'</b>: '.($nbofsubdir >= 0 ? $nbofsubdir : $langs->trans("NeedRefresh")).'<br>';
    -		    				print $form->textwithpicto('',$htmltooltip,1,"info");
    -		    				print "</td>";
    -	    				}
    -
    -	    				print "</tr></table>\n";
    -	                    print '</div>';
    -
    -	                    //print '<div>&nbsp;</div>';
    -	    				print "</li>\n";
    -	    			}
    -	    		}
    -
    -	    		// Enable jquery handlers on new generated HTML objects (same code than into lib_footer.js.php)
    -	    		// Because the content is reloaded by ajax call, we must also reenable some jquery hooks
    -				print "\n<!-- JS CODE TO ENABLE Tooltips on all object with class classfortooltip (reload into ajaxdirtree) -->\n";
    -	    		print '<script type="text/javascript">
    +	// TODO Find a solution to not output this code for each leaf we open
    +	// Enable jquery handlers on new generated HTML objects (same code than into lib_footer.js.php)
    +	// Because the content is reloaded by ajax call, we must also reenable some jquery hooks
    +	print "\n<!-- JS CODE TO ENABLE Tooltips on all object with class classfortooltip (reload into ajaxdirtree) -->\n";
    +	print '<script type="text/javascript">
     	            	jQuery(document).ready(function () {
     	            		jQuery(".classfortooltip").tooltip({
     							show: { collision: "flipfit", effect:\'toggle\', delay:50 },
    @@ -250,13 +152,6 @@ if (! empty($conf->use_javascript_ajax) && empty($conf->global->MAIN_ECM_DISABLE
     	            	});
     	            	</script>';
     
    -	    		echo "</ul>\n";
    -
    -	    	}
    -	    }
    -	    else print "PermissionDenied";
    -	}
    -
     	// This ajax service is called only when a directory $selecteddir is opened but not when closed.
     	//print '<script language="javascript">';
     	//print "loadandshowpreview('".dol_escape_js($selecteddir)."');";
    @@ -426,3 +321,176 @@ if (empty($conf->use_javascript_ajax) || ! empty($conf->global->MAIN_ECM_DISABLE
     
     // Close db if mode is not noajax
     if ((! isset($mode) || $mode != 'noajax') && is_object($db)) $db->close();
    +
    +
    +
    +/**
    + * treeOutputForAbsoluteDir
    + *
    + * @param	array	$sqltree				Sqltree
    + * @param	string	$selecteddir			Selected dir
    + * @param	string	$fullpathselecteddir	Full path of selected dir
    + * @param	string	$modulepart				Modulepart
    + * @param	string	$websitekey				Website key
    + * @param	int		$pageid					Page id
    + * @param	string	$preopened				Current open dir
    + * @param	string	$fullpathpreopened		Full path of current open dir
    + * @param	int		$depth					Depth
    + * @return	void
    + */
    +function treeOutputForAbsoluteDir($sqltree, $selecteddir, $fullpathselecteddir, $modulepart, $websitekey, $pageid, $preopened, $fullpathpreopened, $depth=0)
    +{
    +	global $conf, $db, $langs, $form;
    +	global $dolibarr_main_data_root;
    +
    +	$ecmdirstatic = new EcmDirectory($db);
    +	$userstatic = new User($db);
    +
    +	if (file_exists($fullpathselecteddir))
    +	{
    +		$files = @scandir($fullpathselecteddir);
    +
    +		if (! empty($files))
    +		{
    +			natcasesort($files);
    +			if (count($files) > 2)    /* The 2 accounts for . and .. */
    +			{
    +				echo '<ul class="ecmjqft" style="display: none;">'."\n";
    +
    +				// All dirs
    +				foreach ($files as $file)    // $file can be '.', '..', or 'My dir' or 'My file'
    +				{
    +					if ($file == 'temp') continue;
    +
    +					$nbofsubdir=0;
    +					$nboffilesinsubdir=0;
    +
    +					$val=array();
    +
    +					// Loop on all database entries (sqltree) to find the one matching the subdir found into dir to scan
    +					foreach($sqltree as $key => $tmpval)
    +					{
    +						//print "-- key=".$key." - ".$tmpval['fullrelativename']." vs ".(($selecteddir != '/'?$selecteddir.'/':'').$file)."<br>\n";
    +						if ($tmpval['fullrelativename'] == (($selecteddir != '/'?$selecteddir.'/':'').$file))		// We found equivalent record into database
    +						{
    +							$val=$tmpval;
    +							$resarray=tree_showpad($sqltree,$key,1);
    +
    +							// Refresh cache for this subdir
    +							if (isset($val['cachenbofdoc']) && $val['cachenbofdoc'] < 0)	// Cache is not up to date, so we update it for this directory t
    +							{
    +								$result=$ecmdirstatic->fetch($val['id']);
    +								$ecmdirstatic->ref=$ecmdirstatic->label;
    +
    +								$result=$ecmdirstatic->refreshcachenboffile(0);
    +								$val['cachenbofdoc']=$result;
    +							}
    +
    +							$a=$resarray[0];
    +							$nbofsubdir=$resarray[1];
    +							$nboffilesinsubdir=$resarray[2];
    +							break;
    +						}
    +					}
    +
    +					//print 'modulepart='.$modulepart.' fullpathselecteddir='.$fullpathselecteddir.' - val[fullrelativename] (in database)='.$val['fullrelativename'].' - val[id]='.$val['id'].' - is_dir='.dol_is_dir($fullpathselecteddir . $file).' - file='.$file."\n";
    +					if ($file != '.' && $file != '..' && ((! empty($val['fullrelativename']) && $val['id'] >= 0) || dol_is_dir($fullpathselecteddir . (preg_match('/\/$/',$fullpathselecteddir)?'':'/') . $file)))
    +					{
    +						if (empty($val['fullrelativename']))	// If we did not find entry into database, but found a directory (dol_is_dir was ok at previous test)
    +						{
    +							$val['fullrelativename']=(($selecteddir && $selecteddir != '/')?$selecteddir.'/':'').$file;
    +							$val['id']=0;
    +							$val['label']=$file;
    +							$val['description']='';
    +							$nboffilesinsubdir=$langs->trans("Unknown");
    +						}
    +
    +						$collapsedorexpanded='collapsed';
    +						if (preg_match('/^'.preg_quote($val['fullrelativename'].'/', '/').'/', $preopened)) $collapsedorexpanded='expanded';
    +						print '<li class="directory '.$collapsedorexpanded.'">';	// collapsed is opposite if expanded
    +
    +						print "<a class=\"fmdirlia jqft ecmjqft\" href=\"";
    +						print "#";
    +						print "\" rel=\"" . dol_escape_htmltag($val['fullrelativename'].'/') . "\" id=\"fmdirlia_id_".$val['id']."\"";
    +						print " onClick=\"loadandshowpreview('".dol_escape_js($val['fullrelativename'])."',".$val['id'].")";
    +						print "\">";
    +						print dol_escape_htmltag($file);
    +						print "</a>";
    +
    +						print '<div class="ecmjqft">';
    +
    +						print '<table class="nobordernopadding"><tr>';
    +
    +						/*print '<td align="left">';
    +						 print dol_escape_htmltag($file);
    +						 print '</td>';*/
    +
    +						// Nb of docs
    +						print '<td align="right">';
    +						print (isset($val['cachenbofdoc']) && $val['cachenbofdoc']  >= 0)?$val['cachenbofdoc']:'&nbsp;';
    +						print '</td>';
    +						print '<td align="left">';
    +						if ($nbofsubdir > 0  && $nboffilesinsubdir > 0) print '<font color="#AAAAAA">+'.$nboffilesinsubdir.'</font> ';
    +						print '</td>';
    +
    +						// Edit link
    +						print '<td align="right" width="18"><a href="';
    +						print DOL_URL_ROOT.'/ecm/dir_card.php?module='.urlencode($modulepart).'&section='.$val['id'].'&relativedir='.urlencode($val['fullrelativename']);
    +						print '&backtopage='.urlencode($_SERVER["PHP_SELF"].'?file_manager=1&website='.$websitekey.'&pageid='.$pageid);
    +						print '">'.img_edit($langs->trans("Edit").' - '.$langs->trans("View"), 0, 'class="valignmiddle opacitymedium"').'</a></td>';
    +
    +						// Add link
    +						//print '<td align="right"><a href="'.DOL_URL_ROOT.'/ecm/dir_add_card.php?action=create&amp;catParent='.$val['id'].'">'.img_edit_add().'</a></td>';
    +						//print '<td align="right" width="14">&nbsp;</td>';
    +
    +						// Info
    +						if ($modulepart == 'ecm')
    +						{
    +							print '<td align="right" width="18">';
    +							$userstatic->id=isset($val['fk_user_c'])?$val['fk_user_c']:0;
    +							$userstatic->lastname=isset($val['login_c'])?$val['login_c']:0;
    +							$htmltooltip='<b>'.$langs->trans("ECMSection").'</b>: '.$val['label'].'<br>';
    +							$htmltooltip='<b>'.$langs->trans("Type").'</b>: '.$langs->trans("ECMSectionManual").'<br>';
    +							$htmltooltip.='<b>'.$langs->trans("ECMCreationUser").'</b>: '.$userstatic->getNomUrl(1, '', false, 1).'<br>';
    +							$htmltooltip.='<b>'.$langs->trans("ECMCreationDate").'</b>: '.(isset($val['date_c'])?dol_print_date($val['date_c'],"dayhour"):$langs->trans("NeedRefresh")).'<br>';
    +							$htmltooltip.='<b>'.$langs->trans("Description").'</b>: '.$val['description'].'<br>';
    +							$htmltooltip.='<b>'.$langs->trans("ECMNbOfFilesInDir").'</b>: '.((isset($val['cachenbofdoc']) && $val['cachenbofdoc'] >= 0)?$val['cachenbofdoc']:$langs->trans("NeedRefresh")).'<br>';
    +							if ($nboffilesinsubdir > 0) $htmltooltip.='<b>'.$langs->trans("ECMNbOfFilesInSubDir").'</b>: '.$nboffilesinsubdir;
    +							else $htmltooltip.='<b>'.$langs->trans("ECMNbOfSubDir").'</b>: '.($nbofsubdir >= 0 ? $nbofsubdir : $langs->trans("NeedRefresh")).'<br>';
    +							print $form->textwithpicto('',$htmltooltip,1,"info");
    +							print "</td>";
    +						}
    +
    +						print "</tr></table>\n";
    +						print '</div>';
    +
    +						//print 'selecteddir='.$selecteddir.' preopened='.$preopened.' $val[\'fullrelativename\']='.$val['fullrelativename']."<br>\n";
    +						if (preg_match('/^'.preg_quote($val['fullrelativename'].'/', '/').'/', $preopened))
    +						{
    +							//print 'modulepart='.$modulepart.' fullpathselecteddir='.$fullpathselecteddir.' - val[fullrelativename] (in database)='.$val['fullrelativename'].' - val[id]='.$val['id'].' - is_dir='.dol_is_dir($fullpathselecteddir . $file).' - file='.$file."\n";
    +							$newselecteddir = $val['fullrelativename'];
    +							$newfullpathselecteddir='';
    +							if ($modulepart == 'ecm')
    +							{
    +								$newfullpathselecteddir=$conf->ecm->dir_output.'/'.($val['fullrelativename'] != '/' ? $val['fullrelativename'] : '');
    +							}
    +							elseif ($modulepart == 'medias')
    +							{
    +								$newfullpathselecteddir=$dolibarr_main_data_root.'/medias/'.($val['fullrelativename'] != '/' ? $val['fullrelativename'] : '');
    +							}
    +
    +							if ($newfullpathselecteddir) treeOutputForAbsoluteDir($sqltree, $newselecteddir, $newfullpathselecteddir, $modulepart, $websitekey, $pageid, $preopened, $fullpathpreopened, $depth+1);
    +						}
    +
    +						print "</li>\n";
    +					}
    +				}
    +
    +				echo "</ul>\n";
    +
    +			}
    +		}
    +		else print "PermissionDenied";
    +	}
    +}
    +
    diff --git a/htdocs/core/boxes/box_contracts.php b/htdocs/core/boxes/box_contracts.php
    index 6f9a62e1063..7592f882b59 100644
    --- a/htdocs/core/boxes/box_contracts.php
    +++ b/htdocs/core/boxes/box_contracts.php
    @@ -40,7 +40,7 @@ class box_contracts extends ModeleBoxes
          * @var DoliDB Database handler.
          */
         public $db;
    -    
    +
         var $param;
     
         var $info_box_head = array();
    @@ -83,7 +83,7 @@ class box_contracts extends ModeleBoxes
             	$contractstatic=new Contrat($db);
             	$thirdpartytmp=new Societe($db);
     
    -    	    $sql = "SELECT s.nom as name, s.rowid as socid,";
    +    	    $sql = "SELECT s.nom as name, s.rowid as socid, s.email, s.client, s.fournisseur, s.code_client, s.code_fournisseur, s.code_compta, s.code_compta_fournisseur,";
         		$sql.= " c.rowid, c.ref, c.statut as fk_statut, c.date_contrat, c.datec, c.fin_validite, c.date_cloture";
         		$sql.= " FROM ".MAIN_DB_PREFIX."societe as s, ".MAIN_DB_PREFIX."contrat as c";
         		if (!$user->rights->societe->client->voir && !$user->societe_id) $sql.= ", ".MAIN_DB_PREFIX."societe_commerciaux as sc";
    @@ -108,6 +108,7 @@ class box_contracts extends ModeleBoxes
                     while ($line < $num)
                     {
         				$objp = $db->fetch_object($resql);
    +
         				$datec=$db->jdate($objp->datec);
         				$dateterm=$db->jdate($objp->fin_validite);
         				$dateclose=$db->jdate($objp->date_cloture);
    @@ -120,6 +121,13 @@ class box_contracts extends ModeleBoxes
     
         				$thirdpartytmp->name = $objp->name;
         				$thirdpartytmp->id = $objp->socid;
    +    				$thirdpartytmp->email = $objp->email;
    +    				$thirdpartytmp->client = $objp->client;
    +    				$thirdpartytmp->fournisseur = $objp->fournisseur;
    +    				$thirdpartytmp->code_client = $objp->code_client;
    +    				$thirdpartytmp->code_fournisseur = $objp->code_fournisseur;
    +    				$thirdpartytmp->code_compta = $objp->code_compta;
    +    				$thirdpartytmp->code_compta_fournisseur = $objp->code_compta_fournisseur;
     
         				// fin_validite is no more on contract but on services
         				// if ($objp->fk_statut == 1 && $dateterm < ($now - $conf->contrat->cloture->warning_delay)) { $late = img_warning($langs->trans("Late")); }
    diff --git a/htdocs/core/boxes/box_factures.php b/htdocs/core/boxes/box_factures.php
    index 348bd7b9fe5..e281fbe5c60 100644
    --- a/htdocs/core/boxes/box_factures.php
    +++ b/htdocs/core/boxes/box_factures.php
    @@ -76,9 +76,11 @@ class box_factures extends ModeleBoxes
             include_once DOL_DOCUMENT_ROOT.'/compta/facture/class/facture.class.php';
             include_once DOL_DOCUMENT_ROOT.'/societe/class/societe.class.php';
     
    -        $facturestatic=new Facture($db);
    +        $facturestatic = new Facture($db);
             $societestatic = new Societe($db);
     
    +        $langs->load("bills");
    +
     		$text = $langs->trans("BoxTitleLast".($conf->global->MAIN_LASTBOX_ON_OBJECT_DATE?"":"Modified")."CustomerBills",$max);
     		$this->info_box_head = array(
     				'text' => $text,
    @@ -92,9 +94,7 @@ class box_factures extends ModeleBoxes
                 $sql.= ", f.total_ttc";
                 $sql.= ", f.datef as df";
     			$sql.= ", f.paye, f.fk_statut, f.datec, f.tms";
    -            $sql.= ", s.nom as name";
    -            $sql.= ", s.rowid as socid";
    -            $sql.= ", s.code_client";
    +            $sql.= ", s.rowid as socid, s.nom as name, s.code_client, s.email, s.tva_intra, s.code_compta, s.siren as idprof1, s.siret as idprof2, s.ape as idprof3, s.idprof4, s.idprof5, s.idprof6";
     			$sql.= ", f.date_lim_reglement as datelimite";
     			$sql.= " FROM (".MAIN_DB_PREFIX."societe as s,".MAIN_DB_PREFIX."facture as f";
     			if (!$user->rights->societe->client->voir && !$user->societe_id) $sql.= ", ".MAIN_DB_PREFIX."societe_commerciaux as sc";
    @@ -121,6 +121,7 @@ class box_factures extends ModeleBoxes
                         $datelimite = $db->jdate($objp->datelimite);
                         $date = $db->jdate($objp->df);
                         $datem = $db->jdate($objp->tms);
    +
                         $facturestatic->id = $objp->facid;
                         $facturestatic->ref = $objp->facnumber;
                         $facturestatic->type = $objp->type;
    @@ -133,7 +134,14 @@ class box_factures extends ModeleBoxes
                         $societestatic->id = $objp->socid;
                         $societestatic->name = $objp->name;
                         $societestatic->code_client = $objp->code_client;
    -
    +                    $societestatic->tva_intra = $objp->tva_intra;
    +                    $societestatic->email = $objp->email;
    +                    $societestatic->idprof1 = $objp->idprof1;
    +                    $societestatic->idprof2 = $objp->idprof2;
    +                    $societestatic->idprof3 = $objp->idprof3;
    +                    $societestatic->idprof4 = $objp->idprof4;
    +                    $societestatic->idprof5 = $objp->idprof5;
    +                    $societestatic->idprof6 = $objp->idprof6;
     
     					$late = '';
     					if ($facturestatic->hasDelay()) {
    diff --git a/htdocs/core/boxes/box_services_contracts.php b/htdocs/core/boxes/box_services_contracts.php
    index 41d287d0c37..7c73bbbe328 100644
    --- a/htdocs/core/boxes/box_services_contracts.php
    +++ b/htdocs/core/boxes/box_services_contracts.php
    @@ -41,7 +41,7 @@ class box_services_contracts extends ModeleBoxes
          * @var DoliDB Database handler.
          */
         public $db;
    -    
    +
     	var $param;
     
     	var $info_box_head = array();
    @@ -88,8 +88,8 @@ class box_services_contracts extends ModeleBoxes
     		    $thirdpartytmp = new Societe($db);
     		    $productstatic = new Product($db);
     
    -			$sql = "SELECT s.nom as name, s.rowid as socid,";
    -			$sql.= " c.rowid, c.ref, c.statut as contract_status,";
    +			$sql = "SELECT s.nom as name, s.rowid as socid, s.email, s.client, s.fournisseur, s.code_client, s.code_fournisseur, s.code_compta, s.code_compta_fournisseur,";
    +			$sql.= " c.rowid, c.ref, c.statut as contract_status, c.ref_customer, c.ref_supplier,";
     			$sql.= " cd.rowid as cdid, cd.label, cd.description, cd.tms as datem, cd.statut, cd.product_type as type,";
     			$sql.= " p.rowid as product_id, p.ref as product_ref, p.label as plabel, p.fk_product_type as ptype, p.entity";
     			$sql.= " FROM (".MAIN_DB_PREFIX."societe as s";
    @@ -127,9 +127,18 @@ class box_services_contracts extends ModeleBoxes
                         $contractstatic->statut=$objp->contract_status;
     					$contractstatic->id=$objp->rowid;
     					$contractstatic->ref=$objp->ref;
    +					$contractstatic->ref_customer=$objp->ref_customer;
    +					$contractstatic->ref_supplier=$objp->ref_supplier;
     
     					$thirdpartytmp->name = $objp->name;
     					$thirdpartytmp->id = $objp->socid;
    +					$thirdpartytmp->email = $objp->email;
    +					$thirdpartytmp->client = $objp->client;
    +					$thirdpartytmp->fournisseur = $objp->fournisseur;
    +					$thirdpartytmp->code_client = $objp->code_client;
    +					$thirdpartytmp->code_fournisseur = $objp->code_fournisseur;
    +					$thirdpartytmp->code_compta = $objp->code_compta;
    +					$thirdpartytmp->code_compta_fournisseur = $objp->code_compta_fournisseur;
     
     					// Multilangs
     					if (! empty($conf->global->MAIN_MULTILANGS) && $objp->product_id > 0) // if option multilang is on
    diff --git a/htdocs/core/boxes/box_services_expired.php b/htdocs/core/boxes/box_services_expired.php
    index afc087ad715..c23e9940377 100644
    --- a/htdocs/core/boxes/box_services_expired.php
    +++ b/htdocs/core/boxes/box_services_expired.php
    @@ -39,7 +39,7 @@ class box_services_expired extends ModeleBoxes
          * @var DoliDB Database handler.
          */
         public $db;
    -    
    +
         var $param;
     
         var $info_box_head = array();
    @@ -84,7 +84,7 @@ class box_services_expired extends ModeleBoxes
         	    // Select contracts with at least one expired service
     			$sql = "SELECT ";
         		$sql.= " c.rowid, c.ref, c.statut as fk_statut, c.date_contrat, c.ref_customer, c.ref_supplier,";
    -			$sql.= " s.nom as name, s.rowid as socid,";
    +			$sql.= " s.nom as name, s.rowid as socid, s.email, s.client, s.fournisseur, s.code_client, s.code_fournisseur, s.code_compta, s.code_compta_fournisseur,";
     			$sql.= " MIN(cd.date_fin_validite) as date_line, COUNT(cd.rowid) as nb_services";
         		$sql.= " FROM ".MAIN_DB_PREFIX."contrat as c, ".MAIN_DB_PREFIX."societe s, ".MAIN_DB_PREFIX."contratdet as cd";
                 if (!$user->rights->societe->client->voir && !$user->societe_id) $sql.= ", ".MAIN_DB_PREFIX."societe_commerciaux as sc";
    @@ -113,8 +113,15 @@ class box_services_expired extends ModeleBoxes
     
         				$objp = $db->fetch_object($resql);
     
    -    				$thirdpartytmp->id = $objp->socid;
         				$thirdpartytmp->name = $objp->name;
    +    				$thirdpartytmp->id = $objp->socid;
    +    				$thirdpartytmp->email = $objp->email;
    +    				$thirdpartytmp->client = $objp->client;
    +    				$thirdpartytmp->fournisseur = $objp->fournisseur;
    +    				$thirdpartytmp->code_client = $objp->code_client;
    +    				$thirdpartytmp->code_fournisseur = $objp->code_fournisseur;
    +    				$thirdpartytmp->code_compta = $objp->code_compta;
    +    				$thirdpartytmp->code_compta_fournisseur = $objp->code_compta_fournisseur;
     
         				$contract->id = $objp->rowid;
         				$contract->ref = $objp->ref;
    diff --git a/htdocs/core/boxes/modules_boxes.php b/htdocs/core/boxes/modules_boxes.php
    index 4377b90d17a..47646a0facf 100644
    --- a/htdocs/core/boxes/modules_boxes.php
    +++ b/htdocs/core/boxes/modules_boxes.php
    @@ -213,7 +213,6 @@ class ModeleBoxes // Can't be abtract as it is instantiated to build "empty" box
             require_once DOL_DOCUMENT_ROOT .'/core/lib/files.lib.php';
     
     		$MAXLENGTHBOX=60;   // Mettre 0 pour pas de limite
    -		$var = false;
     
             $cachetime = 900;   // 900 : 15mn
             $cachedir = DOL_DATA_ROOT.'/boxes/temp';
    diff --git a/htdocs/core/class/CMailFile.class.php b/htdocs/core/class/CMailFile.class.php
    index 7562cd609c2..a37f6b1562b 100644
    --- a/htdocs/core/class/CMailFile.class.php
    +++ b/htdocs/core/class/CMailFile.class.php
    @@ -117,7 +117,7 @@ class CMailFile
     	 *  @param  string  $sendcontext      	 'standard', 'emailing', ... (used to define with sending mode and parameters to use)
     	 *  @param	string	$replyto			 Reply-to email (will be set to same value than From by default if not provided)
     	 */
    -	function __construct($subject,$to,$from,$msg,$filename_list=array(),$mimetype_list=array(),$mimefilename_list=array(),$addr_cc="",$addr_bcc="",$deliveryreceipt=0,$msgishtml=0,$errors_to='',$css='',$trackid='',$moreinheader='',$sendcontext='standard',$replyto='')
    +	function __construct($subject, $to, $from, $msg, $filename_list=array(), $mimetype_list=array(), $mimefilename_list=array(), $addr_cc="", $addr_bcc="", $deliveryreceipt=0, $msgishtml=0, $errors_to='', $css='', $trackid='', $moreinheader='', $sendcontext='standard', $replyto='')
     	{
     		global $conf, $dolibarr_main_data_root;
     
    @@ -569,7 +569,8 @@ class CMailFile
     				$keyforstarttls  ='MAIN_MAIL_EMAIL_STARTTLS_EMAILING';
     			}
     
    -			if(!empty($conf->global->MAIN_MAIL_FORCE_SENDTO)) {
    +			if (!empty($conf->global->MAIN_MAIL_FORCE_SENDTO))
    +			{
     				$this->addr_to = $conf->global->MAIN_MAIL_FORCE_SENDTO;
     				$this->addr_cc = '';
     				$this->addr_bcc = '';
    @@ -1349,10 +1350,10 @@ class CMailFile
     		// Build the list of image extensions
     		$extensions = array_keys($this->image_types);
     
    -
    +		$matches = array();
     		preg_match_all('/(?:"|\')([^"\']+\.('.implode('|', $extensions).'))(?:"|\')/Ui', $this->html, $matches);  // If "xxx.ext" or 'xxx.ext' found
     
    -		if ($matches)
    +		if (! empty($matches))
     		{
     			$i=0;
     			foreach ($matches[1] as $full)
    diff --git a/htdocs/core/class/comment.class.php b/htdocs/core/class/comment.class.php
    index 287d260f4d2..161ce438e29 100644
    --- a/htdocs/core/class/comment.class.php
    +++ b/htdocs/core/class/comment.class.php
    @@ -47,6 +47,9 @@ class Comment extends CommonObject
     
     	public $datec;
     
    +	/**
    +     * @var int ID
    +     */
     	public $fk_user_author;
     
     	/**
    diff --git a/htdocs/core/class/commondocgenerator.class.php b/htdocs/core/class/commondocgenerator.class.php
    index 3792aaf9327..92458831d0b 100644
    --- a/htdocs/core/class/commondocgenerator.class.php
    +++ b/htdocs/core/class/commondocgenerator.class.php
    @@ -1,10 +1,11 @@
     <?php
    -/* Copyright (C) 2003-2005	Rodolphe Quiedeville	<rodolphe@quiedeville.org>
    - * Copyright (C) 2004-2010	Laurent Destailleur	<eldy@users.sourceforge.net>
    - * Copyright (C) 2004		Eric Seigne		<eric.seigne@ryxeo.com>
    - * Copyright (C) 2005-2012	Regis Houssin		<regis.houssin@capnetworks.com>
    - * Copyright (C) 2015       	Marcos García           <marcosgdf@gmail.com>
    - * Copyright (C) 2016       	Charlie Benke           <charlie@patas-monkey.com>
    +/* Copyright (C) 2003-2005	Rodolphe Quiedeville    <rodolphe@quiedeville.org>
    + * Copyright (C) 2004-2010	Laurent Destailleur     <eldy@users.sourceforge.net>
    + * Copyright (C) 2004		Eric Seigne             <eric.seigne@ryxeo.com>
    + * Copyright (C) 2005-2012	Regis Houssin           <regis.houssin@capnetworks.com>
    + * Copyright (C) 2015       Marcos García           <marcosgdf@gmail.com>
    + * Copyright (C) 2016       Charlie Benke           <charlie@patas-monkey.com>
    + * Copyright (C) 2018       Frédéric France         <frederic.france@netlogic.fr>
      *
      * This program is free software; you can redistribute it and/or modify
      * it under the terms of the GNU General Public License as published by
    @@ -38,6 +39,14 @@ abstract class CommonDocGenerator
     	 */
     	public $error='';
     
    +    /**
    +     * @var string[]    Array of error strings
    +     */
    +    public $errors = array();
    +
    +	/**
    +     * @var DoliDB Database handler.
    +     */
     	protected $db;
     
     
    @@ -235,10 +244,10 @@ abstract class CommonDocGenerator
     	/**
     	 * Define array with couple subtitution key => subtitution value
     	 *
    -	 * @param	Contact 		$object        	contact
    +	 * @param	Contact 	$object        	contact
     	 * @param	Translate 	$outputlangs   	object for output
    -	 * @param   array_key	$array_key	    Name of the key for return array
    -	 * @return	array of substitution key->code
    +	 * @param   array		$array_key	    Name of the key for return array
    +	 * @return	array 						Array of substitution key->code
     	 */
         function get_substitutionarray_contact($object, $outputlangs, $array_key = 'object')
         {
    @@ -574,9 +583,9 @@ abstract class CommonDocGenerator
         /**
          * Define array with couple substitution key => substitution value
          *
    -     * @param   Expedition			$object             Main object to use as data source
    +     * @param   Expedition		$object             Main object to use as data source
          * @param   Translate		$outputlangs        Lang object to use for output
    -     * @param   array_key		$array_key	        Name of the key for return array
    +     * @param   array			$array_key	        Name of the key for return array
          * @return	array								Array of substitution
          */
         function get_substitutionarray_shipment($object,$outputlangs,$array_key='object')
    @@ -799,7 +808,7 @@ abstract class CommonDocGenerator
     	/**
     	 * Rect pdf
     	 *
    -	 * @param	PDF		$pdf			Object PDF
    +	 * @param	TCPDF	$pdf			Object PDF
     	 * @param	float	$x				Abscissa of first point
     	 * @param	float	$y		        Ordinate of first point
     	 * @param	float	$l				??
    @@ -815,4 +824,227 @@ abstract class CommonDocGenerator
             if (empty($hidebottom)) $pdf->line($x+$l, $y+$h, $x, $y+$h);
             $pdf->line($x, $y+$h, $x, $y);
         }
    +
    +
    +    /**
    +     *   	uasort callback function to Sort colums fields
    +     *
    +     *   	@param	array			$a    			PDF lines array fields configs
    +     *   	@param	array			$b    			PDF lines array fields configs
    +     *      @return	int								Return compare result
    +     */
    +    function columnSort($a, $b)
    +    {
    +        if(empty($a['rank'])){ $a['rank'] = 0; }
    +        if(empty($b['rank'])){ $b['rank'] = 0; }
    +        if ($a['rank'] == $b['rank']) {
    +            return 0;
    +        }
    +        return ($a['rank'] > $b['rank']) ? -1 : 1;
    +    }
    +
    +    /**
    +     *   	Prepare Array Column Field
    +     *
    +     *   	@param	object			$object				common object
    +     *   	@param	Translate		$outputlangs		langs
    +     *      @param	int				$hidedetails		Do not show line details
    +     *      @param	int				$hidedesc			Do not show desc
    +     *      @param	int				$hideref			Do not show ref
    +     *      @return	null
    +     */
    +    function prepareArrayColumnField($object,$outputlangs,$hidedetails=0,$hidedesc=0,$hideref=0)
    +    {
    +        global $conf;
    +
    +        $this->defineColumnField($object,$outputlangs,$hidedetails,$hidedesc,$hideref);
    +
    +
    +        // Sorting
    +        uasort ( $this->cols, array( $this, 'columnSort' ) );
    +
    +        // Positionning
    +        $curX = $this->page_largeur-$this->marge_droite; // start from right
    +
    +        // Array witdh
    +        $arrayWidth = $this->page_largeur-$this->marge_droite-$this->marge_gauche;
    +
    +        // Count flexible column
    +        $totalDefinedColWidth = 0;
    +        $countFlexCol = 0;
    +        foreach ($this->cols as $colKey =>& $colDef)
    +        {
    +            if(!$this->getColumnStatus($colKey)) continue; // continue if desable
    +
    +            if(!empty($colDef['scale'])){
    +                // In case of column widht is defined by percentage
    +                $colDef['width'] = abs($arrayWidth * $colDef['scale'] / 100 );
    +            }
    +
    +            if(empty($colDef['width'])){
    +                $countFlexCol++;
    +            }
    +            else{
    +                $totalDefinedColWidth += $colDef['width'];
    +            }
    +        }
    +
    +        foreach ($this->cols as $colKey =>& $colDef)
    +        {
    +            // setting empty conf with default
    +            if(!empty($colDef['title'])){
    +                $colDef['title'] = array_replace($this->defaultTitlesFieldsStyle, $colDef['title']);
    +            }
    +            else{
    +                $colDef['title'] = $this->defaultTitlesFieldsStyle;
    +            }
    +
    +            // setting empty conf with default
    +            if(!empty($colDef['content'])){
    +                $colDef['content'] = array_replace($this->defaultContentsFieldsStyle, $colDef['content']);
    +            }
    +            else{
    +                $colDef['content'] = $this->defaultContentsFieldsStyle;
    +            }
    +
    +            if($this->getColumnStatus($colKey))
    +            {
    +                // In case of flexible column
    +                if(empty($colDef['width'])){
    +                    $colDef['width'] = abs(($arrayWidth - $totalDefinedColWidth)) / $countFlexCol;
    +                }
    +
    +                // Set positions
    +                $lastX = $curX;
    +                $curX = $lastX - $colDef['width'];
    +                $colDef['xStartPos'] = $curX;
    +                $colDef['xEndPos']   = $lastX;
    +            }
    +        }
    +    }
    +
    +    /**
    +     *   	get column content width from column key
    +     *
    +     *   	@param	string			$colKey    		the column key
    +     *      @return	float      width in mm
    +     */
    +    function getColumnContentWidth($colKey)
    +    {
    +        $colDef = $this->cols[$colKey];
    +        return  $colDef['width'] - $colDef['content']['padding'][3] - $colDef['content']['padding'][1];
    +    }
    +
    +
    +    /**
    +     *   	get column content X (abscissa) left position from column key
    +     *
    +     *   	@param	string    $colKey    		the column key
    +     *      @return	float      X position in mm
    +     */
    +    function getColumnContentXStart($colKey)
    +    {
    +        $colDef = $this->cols[$colKey];
    +        return  $colDef['xStartPos'] + $colDef['content']['padding'][3];
    +    }
    +
    +    /**
    +     *   	get column position rank from column key
    +     *
    +     *   	@param	string		$colKey    		the column key
    +     *      @return	int         rank on success and -1 on error
    +     */
    +    function getColumnRank($colKey)
    +    {
    +        if(!isset($this->cols[$colKey]['rank'])) return -1;
    +        return  $this->cols[$colKey]['rank'];
    +    }
    +
    +    /**
    +     *   	get column position rank from column key
    +     *
    +     *   	@param	string		$newColKey    	the new column key
    +     *   	@param	array		$defArray    	a single column definition array
    +     *   	@param	string		$targetCol    	target column used to place the new column beside
    +     *   	@param	bool		$insertAfterTarget    	insert before or after target column ?
    +     *      @return	int         new rank on success and -1 on error
    +     */
    +    function insertNewColumnDef($newColKey, $defArray, $targetCol = false, $insertAfterTarget = false)
    +    {
    +        // prepare wanted rank
    +        $rank = -1;
    +
    +        // try to get rank from target column
    +        if(!empty($targetCol)){
    +            $rank = $this->getColumnRank($targetCol);
    +            if($rank>=0 && $insertAfterTarget){ $rank++; }
    +        }
    +
    +        // get rank from new column definition
    +        if($rank<0 && !empty($defArray['rank'])){
    +            $rank = $defArray['rank'];
    +        }
    +
    +        // error: no rank
    +        if($rank<0){ return -1; }
    +
    +        foreach ($this->cols as $colKey =>& $colDef)
    +        {
    +            if( $rank <= $colDef['rank'])
    +            {
    +                $colDef['rank'] = $colDef['rank'] + 1;
    +            }
    +        }
    +
    +        $defArray['rank'] = $rank;
    +        $this->cols[$newColKey] = $defArray; // array_replace is used to preserve keys
    +
    +        return $rank;
    +    }
    +
    +
    +    /**
    +     *   	print standard column content
    +     *
    +     *   	@param	PDF		    $pdf    	pdf object
    +     *   	@param	float		$curY    	curent Y position
    +     *   	@param	string		$colKey    	the column key
    +     *   	@param	string		$columnText   column text
    +     *      @return	int         new rank on success and -1 on error
    +     */
    +    function printStdColumnContent($pdf, &$curY, $colKey, $columnText = '')
    +    {
    +        global $hookmanager;
    +
    +        $parameters=array(
    +            'object' => $object,
    +            'curY' => &$curY,
    +            'columnText' => $columnText,
    +            'colKey' => $colKey
    +        );
    +        $reshook=$hookmanager->executeHooks('printStdColumnContent',$parameters,$this);    // Note that $action and $object may have been modified by hook
    +        if ($reshook < 0) setEventMessages($hookmanager->error,$hookmanager->errors,'errors');
    +        if (!$reshook)
    +        {
    +            if(empty($columnText)) return;
    +            $pdf->SetXY($this->getColumnContentXStart($colKey),$curY); // Set curent position
    +            $colDef = $this->cols[$colKey];
    +            $pdf->MultiCell( $this->getColumnContentWidth($colKey),2, $columnText,'',$colDef['content']['align']);
    +        }
    +    }
    +
    +
    +    /**
    +     *   	get column status from column key
    +     *
    +     *   	@param	string			$colKey    		the column key
    +     *      @return	float      width in mm
    +     */
    +    function getColumnStatus($colKey)
    +    {
    +        if( !empty($this->cols[$colKey]['status'])){
    +            return true;
    +        }
    +        else  return  false;
    +    }
     }
    diff --git a/htdocs/core/class/commonobject.class.php b/htdocs/core/class/commonobject.class.php
    index a11cd3dd49e..4729e11ff85 100644
    --- a/htdocs/core/class/commonobject.class.php
    +++ b/htdocs/core/class/commonobject.class.php
    @@ -399,6 +399,12 @@ abstract class CommonObject
     	public $firstname;
     	public $civility_id;
     
    +	// Dates
    +	public $date_creation;			// Date creation
    +	public $date_validation;		// Date validation
    +	public $date_modification;		// Date last change (tms field)
    +
    +
     
     	// No constructor as it is an abstract class
     
    @@ -609,12 +615,23 @@ abstract class CommonObject
     			$out.=dol_print_url($this->url,'_goout',0,1);
     			$outdone++;
     		}
    -		if (! empty($conf->skype->enabled))
    +		$out.='<div style="clear: both;">';
    +		if (! empty($conf->socialnetworks->enabled))
     		{
    -			$out.='<div style="clear: both;"></div>';
    -			if ($this->skype) $out.=dol_print_skype($this->skype,$this->id,$object->id,'AC_SKYPE');
    +			if ($this->skype) $out.=dol_print_socialnetworks($this->skype,$this->id,$object->id,'skype');
     			$outdone++;
     		}
    +		if (! empty($conf->socialnetworks->enabled))
    +		{
    +			if ($this->twitter) $out.=dol_print_socialnetworks($this->twitter,$this->id,$object->id,'twitter');
    +			$outdone++;
    +		}
    +		if (! empty($conf->socialnetworks->enabled))
    +		{
    +			if ($this->facebook) $out.=dol_print_socialnetworks($this->facebook,$this->id,$object->id,'facebook');
    +			$outdone++;
    +		}
    +		$out.='</div>';
     
     		$out.='<!-- END Part to show address block -->';
     
    @@ -4799,6 +4816,7 @@ abstract class CommonObject
     			$resql=$this->db->query($sql);
     			if ($resql)
     			{
    +				$this->array_options = array();
     				$numrows=$this->db->num_rows($resql);
     				if ($numrows)
     				{
    @@ -6185,6 +6203,7 @@ abstract class CommonObject
     				$InfoFieldList = explode(":", $param_list[0]);
     				$classname=$InfoFieldList[0];
     				$classpath=$InfoFieldList[1];
    +				$getnomurlparam=(empty($InfoFieldList[2]) ? 3 : $InfoFieldList[2]);
     				if (! empty($classpath))
     				{
     					dol_include_once($InfoFieldList[1]);
    @@ -6192,7 +6211,7 @@ abstract class CommonObject
     					{
     						$object = new $classname($this->db);
     						$object->fetch($value);
    -						$value=$object->getNomUrl(3);
    +						$value=$object->getNomUrl($getnomurlparam);
     					}
     				}
     				else
    @@ -6201,6 +6220,7 @@ abstract class CommonObject
     					return 'Error bad setup of extrafield';
     				}
     			}
    +			else $value='';
     		}
     		elseif ($type == 'text' || $type == 'html')
     		{
    diff --git a/htdocs/core/class/discount.class.php b/htdocs/core/class/discount.class.php
    index 6f6e3a09041..26a5dfe9fb1 100644
    --- a/htdocs/core/class/discount.class.php
    +++ b/htdocs/core/class/discount.class.php
    @@ -34,9 +34,9 @@ class DiscountAbsolute
         public $db;
     
         /**
    -	   * @var string Error code (or message)
    -	   */
    -	  public $error;
    +	 * @var string Error code (or message)
    +	 */
    +	public $error;
     
     	/**
     	 * @var string[]	Array of error strings
    @@ -48,9 +48,9 @@ class DiscountAbsolute
     	 */
     	public $id;
     
    -   /**
    -	  * @var int Thirdparty ID
    -	  */
    +    /**
    +	 * @var int Thirdparty ID
    +	 */
         public $fk_soc;
     
         public $discount_type;			// 0 => customer discount, 1 => supplier discount
    @@ -60,20 +60,34 @@ class DiscountAbsolute
         public $tva_tx;				// Vat rate
     
         /**
    -	   * @var int User ID Id utilisateur qui accorde la remise
    -	   */
    -	  public $fk_user;
    +	 * @var int User ID Id utilisateur qui accorde la remise
    +	 */
    +	public $fk_user;
     
         /**
    -	   * @var string description
    -	   */
    -	  public $description;
    +	 * @var string description
    +	 */
    +	public $description;
     
         public $datec;					// Date creation
    -    public $fk_facture_line;  		// Id invoice line when a discount is used into an invoice line (for absolute discounts)
    -    public $fk_facture;			    // Id invoice when a discount line is used into an invoice (for credit note)
    -    public $fk_facture_source;		// Id facture avoir a l'origine de la remise
    -    public $ref_facture_source;	    // Ref facture avoir a l'origine de la remise
    +
    +    /**
    +     * @var int ID invoice line when a discount is used into an invoice line (for absolute discounts)
    +     */
    +    public $fk_facture_line;
    +
    +    /**
    +     * @var int ID invoice when a discount line is used into an invoice (for credit note)
    +     */
    +    public $fk_facture;
    +
    +    /**
    +     * @var int ID credit note having caused the discount
    +     */
    +    public $fk_facture_source;
    +
    +    public $ref_facture_source;	    // Ref credit note having caused the discount
    +
         public $ref_invoice_supplier_source;
     
         /**
    @@ -137,7 +151,7 @@ class DiscountAbsolute
                     $this->amount_tva = $obj->amount_tva;
                     $this->amount_ttc = $obj->amount_ttc;
     
    -                $this->multicurrency_amount_ht = $obj->multicurrency_amount_ht;
    +                $this->multicurrency_amount_ht = $this->multicurrency_subprice = $obj->multicurrency_amount_ht;
                     $this->multicurrency_amount_tva = $obj->multicurrency_amount_tva;
                     $this->multicurrency_amount_ttc = $obj->multicurrency_amount_ttc;
     
    @@ -185,8 +199,17 @@ class DiscountAbsolute
             $this->amount_ht=price2num($this->amount_ht);
             $this->amount_tva=price2num($this->amount_tva);
             $this->amount_ttc=price2num($this->amount_ttc);
    +
             $this->tva_tx=price2num($this->tva_tx);
     
    +        $this->multicurrency_amount_ht=price2num($this->multicurrency_amount_ht);
    +        $this->multicurrency_amount_tva=price2num($this->multicurrency_amount_tva);
    +        $this->multicurrency_amount_ttc=price2num($this->multicurrency_amount_ttc);
    +
    +        if (empty($this->multicurrency_amount_ht)) $this->multicurrency_amount_ht=0;
    +        if (empty($this->multicurrency_amount_tva)) $this->multicurrency_amount_tva=0;
    +        if (empty($this->multicurrency_amount_ttc)) $this->multicurrency_amount_ttc=0;
    +
             // Check parameters
             if (empty($this->description))
             {
    @@ -199,10 +222,12 @@ class DiscountAbsolute
             $sql = "INSERT INTO ".MAIN_DB_PREFIX."societe_remise_except";
             $sql.= " (entity, datec, fk_soc, discount_type, fk_user, description,";
             $sql.= " amount_ht, amount_tva, amount_ttc, tva_tx,";
    +        $sql.= " multicurrency_amount_ht, multicurrency_amount_tva, multicurrency_amount_ttc,";
             $sql.= " fk_facture_source, fk_invoice_supplier_source";
             $sql.= ")";
             $sql.= " VALUES (".$conf->entity.", '".$this->db->idate($this->datec!=''?$this->datec:dol_now())."', ".$this->fk_soc.", ".(empty($this->discount_type)?0:intval($this->discount_type)).", ".$user->id.", '".$this->db->escape($this->description)."',";
             $sql.= " ".$this->amount_ht.", ".$this->amount_tva.", ".$this->amount_ttc.", ".$this->tva_tx.",";
    +        $sql.= " ".$this->multicurrency_amount_ht.", ".$this->multicurrency_amount_tva.", ".$this->multicurrency_amount_ttc.", ";
             $sql.= " ".($this->fk_facture_source ? "'".$this->db->escape($this->fk_facture_source)."'":"null").",";
             $sql.= " ".($this->fk_invoice_supplier_source ? "'".$this->db->escape($this->fk_invoice_supplier_source)."'":"null");
             $sql.= ")";
    diff --git a/htdocs/core/class/events.class.php b/htdocs/core/class/events.class.php
    index d8d71513cd9..020998fa37a 100644
    --- a/htdocs/core/class/events.class.php
    +++ b/htdocs/core/class/events.class.php
    @@ -61,7 +61,12 @@ class Events // extends CommonObject
     
     	public $tms;
     	public $type;
    +
    +	/**
    +	 * @var int Entity
    +	 */
     	public $entity;
    +
     	public $dateevent;
     
     	/**
    diff --git a/htdocs/core/class/extrafields.class.php b/htdocs/core/class/extrafields.class.php
    index 07f6849e7ec..3f5b515e725 100644
    --- a/htdocs/core/class/extrafields.class.php
    +++ b/htdocs/core/class/extrafields.class.php
    @@ -247,8 +247,8 @@ class ExtraFields
     				$typedb='varchar';
     				$lengthdb='255';
     			} elseif (($type=='select') || ($type=='sellist') || ($type=='radio') ||($type=='checkbox') ||($type=='chkbxlst')){
    -				$typedb='text';
    -				$lengthdb='';
    +				$typedb='varchar';
    +				$lengthdb='255';
     			} elseif ($type=='link') {
     				$typedb='int';
     				$lengthdb='11';
    @@ -555,8 +555,8 @@ class ExtraFields
     				$typedb='varchar';
     				$lengthdb='255';
     			} elseif (($type=='select') || ($type=='sellist') || ($type=='radio') || ($type=='checkbox') || ($type=='chkbxlst')) {
    -				$typedb='text';
    -				$lengthdb='';
    +				$typedb='varchar';
    +				$lengthdb='255';
     			} elseif ($type == 'html') {
     				$typedb='text';
     			} elseif ($type=='link') {
    @@ -1881,11 +1881,16 @@ class ExtraFields
     				if (empty($enabled)) continue;
     				if (empty($perms)) continue;
     
    -				if ($this->attributes[$object->table_element]['required'][$key] && empty($_POST["options_".$key])) // Check if empty without GETPOST, value can be alpha, int, array, etc...
    +				if ($this->attributes[$object->table_element]['required'][$key])	// Value is required
     				{
    -					//print 'ccc'.$value.'-'.$this->attributes[$object->table_element]['required'][$key];
    -					$nofillrequired++;
    -					$error_field_required[] = $langs->transnoentitiesnoconv($value);
    +					// Check if empty without using GETPOST, value can be alpha, int, array, etc...
    +					if ((! is_array($_POST["options_".$key]) && empty($_POST["options_".$key]) && $_POST["options_".$key] != '0')
    +						|| (is_array($_POST["options_".$key]) && empty($_POST["options_".$key])))
    +					{
    +						//print 'ccc'.$value.'-'.$this->attributes[$object->table_element]['required'][$key];
    +						$nofillrequired++;
    +						$error_field_required[] = $langs->transnoentitiesnoconv($value);
    +					}
     				}
     
     				if (in_array($key_type,array('date')))
    diff --git a/htdocs/core/class/fiscalyear.class.php b/htdocs/core/class/fiscalyear.class.php
    index c4ab50179d9..985d67d5cae 100644
    --- a/htdocs/core/class/fiscalyear.class.php
    +++ b/htdocs/core/class/fiscalyear.class.php
    @@ -48,7 +48,11 @@ class Fiscalyear extends CommonObject
     	 */
     	public $fk_element = '';
     
    -	public $ismultientitymanaged = 1;	// 0=No test on entity, 1=Test with field entity, 2=Test with link by societe
    +	/**
    +	 * 0=No test on entity, 1=Test with field entity, 2=Test with link by societe
    +	 * @var int
    +	 */
    +	public $ismultientitymanaged = 1;
     
     	/**
     	 * @var int ID
    @@ -64,6 +68,10 @@ class Fiscalyear extends CommonObject
     	public $date_end;
     	public $datec;
     	public $statut;		// 0=open, 1=closed
    +
    +	/**
    +	 * @var int Entity
    +	 */
     	public $entity;
     
     	public $statuts=array();
    diff --git a/htdocs/core/class/google.class.php b/htdocs/core/class/google.class.php
    index 5756acd90e0..615729ba9c3 100644
    --- a/htdocs/core/class/google.class.php
    +++ b/htdocs/core/class/google.class.php
    @@ -30,13 +30,13 @@ class GoogleAPI
          * @var DoliDB Database handler.
          */
         public $db;
    -	
    +
     	/**
     	 * @var string Error code (or message)
     	 */
     	public $error='';
     
    -	var $key;
    +	public $key;
     
     	/**
     	 * Constructor
    diff --git a/htdocs/core/class/html.form.class.php b/htdocs/core/class/html.form.class.php
    index 9fce2c6c0cc..d42d1dde48f 100644
    --- a/htdocs/core/class/html.form.class.php
    +++ b/htdocs/core/class/html.form.class.php
    @@ -58,15 +58,20 @@ class Form
     	 */
     	public $error='';
     
    -	var $num;
    +    /**
    +     * @var string[]    Array of error strings
    +     */
    +    public $errors = array();
    +
    +	public $num;
     
     	// Cache arrays
    -	var $cache_types_paiements=array();
    -	var $cache_conditions_paiements=array();
    -	var $cache_availability=array();
    -	var $cache_demand_reason=array();
    -	var $cache_types_fees=array();
    -	var $cache_vatrates=array();
    +	public $cache_types_paiements=array();
    +	public $cache_conditions_paiements=array();
    +	public $cache_availability=array();
    +	public $cache_demand_reason=array();
    +	public $cache_types_fees=array();
    +	public $cache_vatrates=array();
     
     
     	/**
    @@ -663,15 +668,16 @@ class Form
     	 *  @param  string	$htmloption     	Options html on select object
     	 *  @param	integer	$maxlength			Max length for labels (0=no limit)
     	 *  @param	string	$morecss			More css class
    -	 *  @param	string	$usecodeaskey		'code3'=Use code on 3 alpha as key, 'code2"=Use code on 2 alpha as key
    +	 *  @param	string	$usecodeaskey		''=Use id as key (default), 'code3'=Use code on 3 alpha as key, 'code2"=Use code on 2 alpha as key
     	 *  @param	int		$showempty			Show empty choice
    -	 *  @param	int		$disablefavorites	Disable favorites
    +	 *  @param	int		$disablefavorites	1=Disable favorites,
    +	 *  @param	int		$addspecialentries	1=Add dedicated entries for group of countries (like 'European Economic Community', ...)
     	 *  @return string           			HTML string with select
     	 */
    -	function select_country($selected='', $htmlname='country_id', $htmloption='', $maxlength=0, $morecss='minwidth300', $usecodeaskey='', $showempty=1, $disablefavorites=0)
    +	function select_country($selected='', $htmlname='country_id', $htmloption='', $maxlength=0, $morecss='minwidth300', $usecodeaskey='', $showempty=1, $disablefavorites=0, $addspecialentries=0)
     	{
             // phpcs:enable
    -		global $conf,$langs;
    +		global $conf,$langs,$mysoc;
     
     		$langs->load("dict");
     
    @@ -713,9 +719,25 @@ class Form
     				if (empty($disablefavorites)) array_multisort($favorite, SORT_DESC, $label, SORT_ASC, $countryArray);
     				else $countryArray = dol_sort_array($countryArray, 'label');
     
    +				if ($showempty)
    +				{
    +					$out.='<option value="">&nbsp;</option>'."\n";
    +				}
    +
    +				if ($addspecialentries)	// Add dedicated entries for groups of countries
    +				{
    +					//if ($showempty) $out.= '<option value="" disabled class="selectoptiondisabledwhite">--------------</option>';
    +					$out.= '<option value="special_allnotme"'.($selected == 'special_allnotme' ? ' selected' : '').'>'.$langs->trans("CountriesExceptMe", $langs->transnoentitiesnoconv("Country".$mysoc->country_code)).'</option>';
    +					$out.= '<option value="special_eec"'.($selected == 'special_eec' ? ' selected' : '').'>'.$langs->trans("CountriesInEEC").'</option>';
    +					if ($mysoc->isInEEC()) $out.= '<option value="special_eecnotme"'.($selected == 'special_eecnotme' ? ' selected' : '').'>'.$langs->trans("CountriesInEECExceptMe", $langs->transnoentitiesnoconv("Country".$mysoc->country_code)).'</option>';
    +					$out.= '<option value="special_noteec"'.($selected == 'special_noteec' ? ' selected' : '').'>'.$langs->trans("CountriesNotInEEC").'</option>';
    +					$out.= '<option value="" disabled class="selectoptiondisabledwhite">--------------</option>';
    +				}
    +
     				foreach ($countryArray as $row)
     				{
    -					if (empty($showempty) && empty($row['rowid'])) continue;
    +					//if (empty($showempty) && empty($row['rowid'])) continue;
    +					if (empty($row['rowid'])) continue;
     
     					if (empty($disablefavorites) && $row['favorite'] && $row['code_iso']) $atleastonefavorite++;
     					if (empty($row['favorite']) && $atleastonefavorite)
    @@ -2049,6 +2071,12 @@ class Form
     			$sql.= " LEFT JOIN ".MAIN_DB_PREFIX."product_stock as ps on ps.fk_product = p.rowid";
     			$sql.= " LEFT JOIN ".MAIN_DB_PREFIX."entrepot as e on ps.fk_entrepot = e.rowid";
     		}
    +		
    +		// include search in supplier ref
    +		if(!empty($conf->global->MAIN_SEARCH_PRODUCT_BY_FOURN_REF))
    +		{
    +            $sql.= " LEFT JOIN ".MAIN_DB_PREFIX."product_fournisseur_price as pfp ON p.rowid = pfp.fk_product";
    +		}
     
     		//Price by customer
     		if (! empty($conf->global->PRODUIT_CUSTOMER_PRICES) && !empty($socid)) {
    @@ -2102,6 +2130,7 @@ class Form
     				if ($i > 0) $sql.=" AND ";
     				$sql.="(p.ref LIKE '".$db->escape($prefix.$crit)."%' OR p.label LIKE '".$db->escape($prefix.$crit)."%'";
     				if (! empty($conf->global->MAIN_MULTILANGS)) $sql.=" OR pl.label LIKE '".$db->escape($prefix.$crit)."%'";
    +				if (! empty($conf->global->MAIN_SEARCH_PRODUCT_BY_FOURN_REF)) $sql.=" OR pfp.ref_fourn LIKE '".$db->escape($prefix.$crit)."%'";
     				$sql.=")";
     				$i++;
     			}
    @@ -3051,7 +3080,10 @@ class Form
     				$obj = $this->db->fetch_object($resql);
     
     				// Si traduction existe, on l'utilise, sinon on prend le libelle par defaut
    -				$label=($langs->trans("DemandReasonType".$obj->code)!=("DemandReasonType".$obj->code)?$langs->trans("DemandReasonType".$obj->code):($obj->label!='-'?$obj->label:''));
    +				$label=($obj->label!='-'?$obj->label:'');
    +				if ($langs->trans("DemandReasonType".$obj->code) != ("DemandReasonType".$obj->code)) $label = $langs->trans("DemandReasonType".$obj->code); // So translation key DemandReasonTypeSRC_XXX will work
    +				if ($langs->trans($obj->code) != $obj->code) $label=$langs->trans($obj->code);																// So translation key SRC_XXX will work
    +
     				$tmparray[$obj->rowid]['id']   =$obj->rowid;
     				$tmparray[$obj->rowid]['code'] =$obj->code;
     				$tmparray[$obj->rowid]['label']=$label;
    @@ -3100,7 +3132,8 @@ class Form
     			{
     				print '<option value="'.$arraydemandreason['id'].'">';
     			}
    -			print $arraydemandreason['label'];
    +			$label=$arraydemandreason['label'];	// Translation of label was already done into the ->loadCacheInputReason
    +			print $langs->trans($label);
     			print '</option>';
     		}
     		print '</select>';
    @@ -3470,13 +3503,19 @@ class Form
     
     			while($res = $this->db->fetch_object($resql))
     			{
    +			    $unitLabel = $res->label;
    +			    if (! empty($langs->tab_translate['unit'.$res->code]))	// check if Translation is available before
    +			    {
    +			        $unitLabel = $langs->trans('unit'.$res->code)!=$res->label?$langs->trans('unit'.$res->code):$res->label;
    +			    }
    +			    
     				if ($selected == $res->rowid)
     				{
    -					$return.='<option value="'.$res->rowid.'" selected>'.($langs->trans('unit'.$res->code)!=$res->label?$langs->trans('unit'.$res->code):$res->label).'</option>';
    +				    $return.='<option value="'.$res->rowid.'" selected>'.$unitLabel.'</option>';
     				}
     				else
     				{
    -					$return.='<option value="'.$res->rowid.'">'.($langs->trans('unit'.$res->code)!=$res->label?$langs->trans('unit'.$res->code):$res->label).'</option>';
    +				    $return.='<option value="'.$res->rowid.'">'.$unitLabel.'</option>';
     				}
     			}
     			$return.='</select>';
    @@ -3696,6 +3735,7 @@ class Form
     	function form_confirm($page, $title, $question, $action, $formquestion='', $selectedchoice="", $useajax=0, $height=170, $width=500)
     	{
             // phpcs:enable
    +        dol_syslog(__METHOD__ . ': using form_confirm is deprecated. Use formconfim instead.', LOG_WARNING);
     		print $this->formconfirm($page, $title, $question, $action, $formquestion, $selectedchoice, $useajax, $height, $width);
     	}
     
    @@ -3723,7 +3763,7 @@ class Form
     	 *     @param	int			$disableformtag		1=Disable form tag. Can be used if we are already inside a <form> section.
     	 *     @return 	string      	    			HTML ajax code if a confirm ajax popup is required, Pure HTML code if it's an html form
     	 */
    -	function formconfirm($page, $title, $question, $action, $formquestion='', $selectedchoice='', $useajax=0, $height=200, $width=500, $disableformtag=0)
    +	function formconfirm($page, $title, $question, $action, $formquestion='', $selectedchoice='', $useajax=0, $height=210, $width=500, $disableformtag=0)
     	{
     		global $langs,$conf;
     		global $useglobalvars;
    @@ -3873,7 +3913,7 @@ class Form
     			$formconfirm.= ($question ? '<div class="confirmmessage">'.img_help('','').' '.$question . '</div>': '');
     			$formconfirm.= '</div>'."\n";
     
    -			$formconfirm.= "\n<!-- begin ajax form_confirm page=".$page." -->\n";
    +			$formconfirm.= "\n<!-- begin ajax formconfirm page=".$page." -->\n";
     			$formconfirm.= '<script type="text/javascript">'."\n";
     			$formconfirm.= 'jQuery(document).ready(function() {
                 $(function() {
    @@ -3944,11 +3984,11 @@ class Form
                 });
                 });
                 </script>';
    -			$formconfirm.= "<!-- end ajax form_confirm -->\n";
    +			$formconfirm.= "<!-- end ajax formconfirm -->\n";
     		}
     		else
     		{
    -			$formconfirm.= "\n<!-- begin form_confirm page=".$page." -->\n";
    +			$formconfirm.= "\n<!-- begin formconfirm page=".$page." -->\n";
     
     			if (empty($disableformtag)) $formconfirm.= '<form method="POST" action="'.$page.'" class="notoptoleftroright">'."\n";
     
    @@ -3982,7 +4022,7 @@ class Form
     			if (empty($disableformtag)) $formconfirm.= "</form>\n";
     			$formconfirm.= '<br>';
     
    -			$formconfirm.= "<!-- end form_confirm -->\n";
    +			$formconfirm.= "<!-- end formconfirm -->\n";
     		}
     
     		return $formconfirm;
    diff --git a/htdocs/core/class/html.formfile.class.php b/htdocs/core/class/html.formfile.class.php
    index 4a59e28f044..bfc67880a96 100644
    --- a/htdocs/core/class/html.formfile.class.php
    +++ b/htdocs/core/class/html.formfile.class.php
    @@ -310,7 +310,7 @@ class FormFile
     		$param.= 'entity='.(!empty($object->entity)?$object->entity:$conf->entity);
     
     		$printer=0;
    -		if (in_array($modulepart,array('facture','supplier_proposal','propal','proposal','order','commande','expedition', 'commande_fournisseur', 'expensereport')))	// The direct print feature is implemented only for such elements
    +		if (in_array($modulepart,array('facture','supplier_proposal','propal','proposal','order','commande','expedition', 'commande_fournisseur', 'expensereport','livraison')))	// The direct print feature is implemented only for such elements
     		{
     			$printer = (!empty($user->rights->printing->read) && !empty($conf->printing->enabled))?true:false;
     		}
    @@ -1139,7 +1139,6 @@ class FormFile
     				//var_dump($sortfield.' - '.$sortorder);
     				if ($sortfield && $sortorder)	// If $sortfield is for example 'position_name', we will sort on the property 'position_name' (that is concat of position+name)
     				{
    -					//var_dump($sortfield);
     					$filearray=dol_sort_array($filearray, $sortfield, $sortorder);
     				}
     			}
    @@ -1162,7 +1161,7 @@ class FormFile
     					print '<!-- Line list_of_documents '.$key.' relativepath = '.$relativepath.' -->'."\n";
     					// Do we have entry into database ?
     					print '<!-- In database: position='.$filearray[$key]['position'].' -->'."\n";
    -					print '<tr id="row-'.($filearray[$key]['rowid']>0?$filearray[$key]['rowid']:'-AFTER'.$lastrowid.'POS'.($i+1)).'">';
    +					print '<tr class="oddeven" id="row-'.($filearray[$key]['rowid']>0?$filearray[$key]['rowid']:'AFTER'.$lastrowid.'POS'.($i+1)).'">';
     
     					// File name
     					print '<td class="minwith200">';
    @@ -1258,12 +1257,9 @@ class FormFile
     								if ($forcedownload) $paramlink.=($paramlink?'&':'').'attachment=1';
     
     								$fulllink=$urlwithroot.'/document.php'.($paramlink?'?'.$paramlink:'');
    -								//if (! empty($object->ref))       $fulllink.='&hashn='.$object->ref;		// Hash of file path
    -								//elseif (! empty($object->label)) $fulllink.='&hashc='.$object->label;		// Hash of file content
     
     								print img_picto($langs->trans("FileSharedViaALink"),'object_globe.png').' ';
     								print '<input type="text" class="quatrevingtpercent" id="downloadlink" name="downloadexternallink" value="'.dol_escape_htmltag($fulllink).'">';
    -								//print ' <a href="'.$fulllink.'">'.$langs->trans("Download").'</a>';	// No target here
     							}
     							else
     							{
    @@ -1299,17 +1295,12 @@ class FormFile
     
     							if ($permtoeditline)
     							{
    -								print '<a href="'.(($useinecm == 1)?'#':($url.'?action=editfile&urlfile='.urlencode($filepath).$param)).'" class="editfilelink" rel="'.$filepath.'">'.img_edit('default',0,'class="paddingrightonly"').'</a>';
    +								$paramsectiondir=(in_array($modulepart, array('medias','ecm'))?'&section_dir='.urlencode($relativepath):'');
    +								print '<a href="'.(($useinecm == 1)?'#':($url.'?action=editfile&urlfile='.urlencode($filepath).$paramsectiondir.$param)).'" class="editfilelink" rel="'.$filepath.'">'.img_edit('default',0,'class="paddingrightonly"').'</a>';
     							}
     						}
     						if ($permonobject)
     						{
    -							/*
    -    						if ($file['level1name'] <> $object->id)
    -    							$filepath=$file['level1name'].'/'.$file['name'];
    -    						else
    -    							$filepath=$file['name'];
    -    						*/
     							$useajax=1;
     							if (! empty($conf->dol_use_jmobile)) $useajax=0;
     							if (empty($conf->use_javascript_ajax)) $useajax=0;
    diff --git a/htdocs/core/class/html.formmail.class.php b/htdocs/core/class/html.formmail.class.php
    index c80358315c6..68da2dce777 100644
    --- a/htdocs/core/class/html.formmail.class.php
    +++ b/htdocs/core/class/html.formmail.class.php
    @@ -4,6 +4,7 @@
      * Copyright (C) 2010-2011 Juanjo Menent	    <jmenent@2byte.es>
      * Copyright (C) 2015-2017 Marcos García        <marcosgdf@gmail.com>
      * Copyright (C) 2015-2017 Nicolas ZABOURI      <info@inovea-conseil.com>
    + * Copyright (C) 2018       Frédéric France     <frederic.france@netlogic.fr>
      *
      * This program is free software; you can redistribute it and/or modify
      * it under the terms of the GNU General Public License as published by
    @@ -44,7 +45,28 @@ class FormMail extends Form
     
     	public $fromname;
     	public $frommail;
    -	public $replytoname;
    +
    +    /**
    +     * @var string user, company, robot
    +     */
    +    public $fromtype;
    +
    +    /**
    +     * @var int ID
    +     */
    +    public $fromid;
    +
    +    /**
    +     * @var string thirdparty etc
    +     */
    +    public $totype;
    +
    +    /**
    +     * @var int ID
    +     */
    +    public $toid;
    +
    +    public $replytoname;
     	public $replytomail;
     	public $toname;
     	public $tomail;
    @@ -91,11 +113,6 @@ class FormMail extends Form
     	public $withtouser=array();
     	public $withtoccuser=array();
     
    -	/**
    -	 * @var string Error code (or message)
    -	 */
    -	public $error='';
    -
     	public $lines_model;
     
     
    diff --git a/htdocs/core/class/html.formprojet.class.php b/htdocs/core/class/html.formprojet.class.php
    index 04cc6705623..b2166453bbd 100644
    --- a/htdocs/core/class/html.formprojet.class.php
    +++ b/htdocs/core/class/html.formprojet.class.php
    @@ -235,7 +235,7 @@ class FormProjets
     						}
     						else if ($obj->fk_statut == 2)
     						{
    -							if ($discard_close == 2) $disabled=1;
    +							if ($discard_closed == 2) $disabled=1;
     							$labeltoshow.=' - '.$langs->trans("Closed");
     						}
     						else if ( empty($conf->global->PROJECT_ALLOW_TO_LINK_FROM_OTHER_COMPANY) &&  $socid > 0 && (! empty($obj->fk_soc) && $obj->fk_soc != $socid))
    diff --git a/htdocs/core/class/html.formsms.class.php b/htdocs/core/class/html.formsms.class.php
    index a04da7caf08..4ef6208723d 100644
    --- a/htdocs/core/class/html.formsms.class.php
    +++ b/htdocs/core/class/html.formsms.class.php
    @@ -1,20 +1,21 @@
     <?php
    -/* Copyright (C) 2005-2011 Laurent Destailleur  <eldy@users.sourceforge.net>
    - * Copyright (C) 2010      Juanjo Menent        <jmenent@2byte.es>
    -*
    -* This program is free software; you can redistribute it and/or modify
    -* it under the terms of the GNU General Public License as published by
    -* the Free Software Foundation; either version 3 of the License, or
    -* (at your option) any later version.
    -*
    -* This program is distributed in the hope that it will be useful,
    -* but WITHOUT ANY WARRANTY; without even the implied warranty of
    -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    -* GNU General Public License for more details.
    -*
    -* You should have received a copy of the GNU General Public License
    -* along with this program. If not, see <http://www.gnu.org/licenses/>.
    -*/
    +/* Copyright (C) 2005-2011  Laurent Destailleur     <eldy@users.sourceforge.net>
    + * Copyright (C) 2010       Juanjo Menent           <jmenent@2byte.es>
    + * Copyright (C) 2018       Frédéric France         <frederic.france@netlogic.fr>
    + *
    + * This program is free software; you can redistribute it and/or modify
    + * it under the terms of the GNU General Public License as published by
    + * the Free Software Foundation; either version 3 of the License, or
    + * (at your option) any later version.
    + *
    + * This program is distributed in the hope that it will be useful,
    + * but WITHOUT ANY WARRANTY; without even the implied warranty of
    + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    + * GNU General Public License for more details.
    + *
    + * You should have received a copy of the GNU General Public License
    + * along with this program. If not, see <http://www.gnu.org/licenses/>.
    + */
     
     /**
      *       \file       htdocs/core/class/html.formsms.class.php
    @@ -37,33 +38,38 @@ class FormSms
          */
         public $db;
     
    -    var $fromname;
    -    var $fromsms;
    -    var $replytoname;
    -    var $replytomail;
    -    var $toname;
    -    var $tomail;
    +    public $fromname;
    +    public $fromsms;
    +    public $replytoname;
    +    public $replytomail;
    +    public $toname;
    +    public $tomail;
     
    -    var $withsubstit;			// Show substitution array
    -    var $withfrom;
    -    var $withto;
    -    var $withtopic;
    -    var $withbody;
    +    public $withsubstit;			// Show substitution array
    +    public $withfrom;
    +    public $withto;
    +    public $withtopic;
    +    public $withbody;
     
    -    var $withfromreadonly;
    -    var $withreplytoreadonly;
    -    var $withtoreadonly;
    -    var $withtopicreadonly;
    -    var $withcancel;
    +    public $withfromreadonly;
    +    public $withreplytoreadonly;
    +    public $withtoreadonly;
    +    public $withtopicreadonly;
    +    public $withcancel;
     
    -    var $substit=array();
    -    var $param=array();
    +    public $substit=array();
    +    public $param=array();
     
         /**
          * @var string Error code (or message)
          */
         public $error='';
     
    +    /**
    +     * @var string[]	Array of error strings
    +     */
    +    public $errors=array();
    +
     
         /**
          *	Constructor
    diff --git a/htdocs/core/class/html.formticket.class.php b/htdocs/core/class/html.formticket.class.php
    index 5d2136bd236..6c4a9703014 100644
    --- a/htdocs/core/class/html.formticket.class.php
    +++ b/htdocs/core/class/html.formticket.class.php
    @@ -45,6 +45,10 @@ class FormTicket
         public $db;
     
         public $track_id;
    +
    +    /**
    +     * @var int ID
    +     */
         public $fk_user_create;
     
         public $message;
    diff --git a/htdocs/core/class/menubase.class.php b/htdocs/core/class/menubase.class.php
    index 7db88051e5e..1ca10d9dd9b 100644
    --- a/htdocs/core/class/menubase.class.php
    +++ b/htdocs/core/class/menubase.class.php
    @@ -1,6 +1,7 @@
     <?php
     /* Copyright (C) 2007-2009	Laurent Destailleur	<eldy@users.sourceforge.net>
      * Copyright (C) 2009-2012	Regis Houssin		<regis.houssin@capnetworks.com>
    + * Copyright (C) 2018       Frédéric France     <frederic.france@netlogic.fr>
      *
      * This program is free software; you can redistribute it and/or modify
      * it under the terms of the GNU General Public License as published by
    @@ -52,9 +53,25 @@ class Menubase
         public $module;
         public $type;
         public $mainmenu;
    +
    +    /**
    +     * @var int ID
    +     */
         public $fk_menu;
    +
    +    /**
    +     * @var string fk_mainmenu
    +     */
         public $fk_mainmenu;
    +
    +    /**
    +     * @var string fk_leftmenu
    +     */
         public $fk_leftmenu;
    +
    +    /**
    +     * @var int position
    +     */
         public $position;
         public $url;
         public $target;
    @@ -98,10 +115,10 @@ class Menubase
             $this->type=trim($this->type);
             $this->mainmenu=trim($this->mainmenu);
             $this->leftmenu=trim($this->leftmenu);
    -        $this->fk_menu=trim($this->fk_menu);          // If -1, fk_mainmenu and fk_leftmenu must be defined
    +        $this->fk_menu = (int) $this->fk_menu;          // If -1, fk_mainmenu and fk_leftmenu must be defined
             $this->fk_mainmenu=trim($this->fk_mainmenu);
             $this->fk_leftmenu=trim($this->fk_leftmenu);
    -        $this->position=trim($this->position);
    +        $this->position = (int) $this->position;
             $this->url=trim($this->url);
             $this->target=trim($this->target);
             $this->titre=trim($this->titre);
    @@ -109,7 +126,7 @@ class Menubase
             $this->perms=trim($this->perms);
             $this->enabled=trim($this->enabled);
             $this->user=trim($this->user);
    -        $this->position=trim($this->position);
    +        if (empty($this->position)) $this->position=0;
             if (! $this->level) $this->level=0;
     
             // Check parameters
    @@ -142,7 +159,7 @@ class Menubase
             $sql = "SELECT count(*)";
             $sql.= " FROM ".MAIN_DB_PREFIX."menu";
             $sql.= " WHERE menu_handler = '".$this->db->escape($this->menu_handler)."'";
    -        $sql.= " AND fk_menu = ".((int) $this->db->escape($this->fk_menu));
    +        $sql.= " AND fk_menu = ".((int) $this->fk_menu);
             $sql.= " AND position = ".((int) $this->position);
             $sql.= " AND url = '".$this->db->escape($this->url)."'";
             $sql.= " AND entity = ".$conf->entity;
    @@ -239,10 +256,10 @@ class Menubase
             $this->type=trim($this->type);
             $this->mainmenu=trim($this->mainmenu);
             $this->leftmenu=trim($this->leftmenu);
    -        $this->fk_menu=trim($this->fk_menu);
    +        $this->fk_menu = (int) $this->fk_menu;
             $this->fk_mainmenu=trim($this->fk_mainmenu);
             $this->fk_leftmenu=trim($this->fk_leftmenu);
    -        $this->position=trim($this->position);
    +        $this->position = (int) $this->position;
             $this->url=trim($this->url);
             $this->target=trim($this->target);
             $this->titre=trim($this->titre);
    @@ -261,7 +278,7 @@ class Menubase
             $sql.= " type='".$this->db->escape($this->type)."',";
             $sql.= " mainmenu='".$this->db->escape($this->mainmenu)."',";
             $sql.= " leftmenu='".$this->db->escape($this->leftmenu)."',";
    -        $sql.= " fk_menu='".$this->db->escape($this->fk_menu)."',";
    +        $sql.= " fk_menu=".$this->fk_menu.",";
             $sql.= " fk_mainmenu=".($this->fk_mainmenu?"'".$this->db->escape($this->fk_mainmenu)."'":"null").",";
             $sql.= " fk_leftmenu=".($this->fk_leftmenu?"'".$this->db->escape($this->fk_leftmenu)."'":"null").",";
             $sql.= " position=".($this->position > 0 ? $this->position : 0).",";
    diff --git a/htdocs/core/class/notify.class.php b/htdocs/core/class/notify.class.php
    index fb6c94b00f7..7a24e4928c7 100644
    --- a/htdocs/core/class/notify.class.php
    +++ b/htdocs/core/class/notify.class.php
    @@ -51,11 +51,11 @@ class Notify
     	 */
     	public $errors = array();
     
    -	var $author;
    -	var $ref;
    -	var $date;
    -	var $duree;
    -	var $note;
    +	public $author;
    +	public $ref;
    +	public $date;
    +	public $duree;
    +	public $note;
     
     	/**
          * @var int Project ID
    @@ -65,6 +65,7 @@ class Notify
     	// Les codes actions sont definis dans la table llx_notify_def
     
     	// codes actions supported are
    +	// @TODO defined also into interface_50_modNotificiation_Notificiation.class.php
     	public $arrayofnotifsupported = array(
     		'BILL_VALIDATE',
     		'BILL_PAYED',
    @@ -76,7 +77,11 @@ class Notify
     		'ORDER_SUPPLIER_VALIDATE',
     		'ORDER_SUPPLIER_APPROVE',
     		'ORDER_SUPPLIER_REFUSE',
    -		'SHIPPING_VALIDATE'
    +		'SHIPPING_VALIDATE',
    +		'EXPENSE_REPORT_VALIDATE',
    +		'EXPENSE_REPORT_APPROVE',
    +		'HOLIDAY_VALIDATE',
    +		'HOLIDAY_APPROVE'
     	);
     
     
    @@ -340,22 +345,27 @@ class Notify
     		$oldref=(empty($object->oldref)?$object->ref:$object->oldref);
     		$newref=(empty($object->newref)?$object->ref:$object->newref);
     
    +		$sql = '';
    +
     		// Check notification per third party
    -		$sql = "SELECT 'tocontactid' as type_target, c.email, c.rowid as cid, c.lastname, c.firstname, c.default_lang,";
    -		$sql.= " a.rowid as adid, a.label, a.code, n.rowid, n.type";
    -		$sql.= " FROM ".MAIN_DB_PREFIX."socpeople as c,";
    -		$sql.= " ".MAIN_DB_PREFIX."c_action_trigger as a,";
    -		$sql.= " ".MAIN_DB_PREFIX."notify_def as n,";
    -		$sql.= " ".MAIN_DB_PREFIX."societe as s";
    -		$sql.= " WHERE n.fk_contact = c.rowid AND a.rowid = n.fk_action";
    -		$sql.= " AND n.fk_soc = s.rowid";
    -		if (is_numeric($notifcode)) $sql.= " AND n.fk_action = ".$notifcode;	// Old usage
    -		else $sql.= " AND a.code = '".$notifcode."'";	// New usage
    -		$sql .= " AND s.rowid = ".$object->socid;
    +		if ($object->socid > 0)
    +		{
    +			$sql.= "SELECT 'tocontactid' as type_target, c.email, c.rowid as cid, c.lastname, c.firstname, c.default_lang,";
    +			$sql.= " a.rowid as adid, a.label, a.code, n.rowid, n.type";
    +			$sql.= " FROM ".MAIN_DB_PREFIX."socpeople as c,";
    +			$sql.= " ".MAIN_DB_PREFIX."c_action_trigger as a,";
    +			$sql.= " ".MAIN_DB_PREFIX."notify_def as n,";
    +			$sql.= " ".MAIN_DB_PREFIX."societe as s";
    +			$sql.= " WHERE n.fk_contact = c.rowid AND a.rowid = n.fk_action";
    +			$sql.= " AND n.fk_soc = s.rowid";
    +			if (is_numeric($notifcode)) $sql.= " AND n.fk_action = ".$notifcode;	// Old usage
    +			else $sql.= " AND a.code = '".$notifcode."'";	// New usage
    +			$sql .= " AND s.rowid = ".$object->socid;
    +
    +			$sql.= "\nUNION\n";
    +		}
     
     		// Check notification per user
    -		$sql.= "\nUNION\n";
    -
     		$sql.= "SELECT 'touserid' as type_target, c.email, c.rowid as cid, c.lastname, c.firstname, c.lang as default_lang,";
     		$sql.= " a.rowid as adid, a.label, a.code, n.rowid, n.type";
     		$sql.= " FROM ".MAIN_DB_PREFIX."user as c,";
    @@ -363,7 +373,7 @@ class Notify
     		$sql.= " ".MAIN_DB_PREFIX."notify_def as n";
     		$sql.= " WHERE n.fk_user = c.rowid AND a.rowid = n.fk_action";
     		if (is_numeric($notifcode)) $sql.= " AND n.fk_action = ".$notifcode;	// Old usage
    -		else $sql.= " AND a.code = '".$notifcode."'";	// New usage
    +		else $sql.= " AND a.code = '".$this->db->escape($notifcode)."'";	// New usage
     
     		$result = $this->db->query($sql);
     		if ($result)
    @@ -396,6 +406,7 @@ class Notify
     						{
     							$outputlangs = new Translate('', $conf);
     							$outputlangs->setDefaultLang($obj->default_lang);
    +							$outputlangs->loadLangs(array("main","other"));
     						}
     
     						$subject = '['.$mysoc->name.'] '.$outputlangs->transnoentitiesnoconv("DolibarrNotification").($projtitle?' '.$projtitle:'');
    @@ -405,72 +416,92 @@ class Notify
     								$link='/compta/facture/card.php?facid='.$object->id;
     								$dir_output = $conf->facture->dir_output;
     								$object_type = 'facture';
    -								$mesg = $langs->transnoentitiesnoconv("EMailTextInvoiceValidated",$newref);
    +								$mesg = $outputlangs->transnoentitiesnoconv("EMailTextInvoiceValidated",$newref);
     								break;
     							case 'BILL_PAYED':
     								$link='/compta/facture/card.php?facid='.$object->id;
     								$dir_output = $conf->facture->dir_output;
     								$object_type = 'facture';
    -								$mesg = $langs->transnoentitiesnoconv("EMailTextInvoicePayed",$newref);
    +								$mesg = $outputlangs->transnoentitiesnoconv("EMailTextInvoicePayed",$newref);
     								break;
     							case 'ORDER_VALIDATE':
     								$link='/commande/card.php?id='.$object->id;
     								$dir_output = $conf->commande->dir_output;
     								$object_type = 'order';
    -								$mesg = $langs->transnoentitiesnoconv("EMailTextOrderValidated",$newref);
    +								$mesg = $outputlangs->transnoentitiesnoconv("EMailTextOrderValidated",$newref);
     								break;
     							case 'PROPAL_VALIDATE':
     								$link='/comm/propal/card.php?id='.$object->id;
     								$dir_output = $conf->propal->multidir_output[$object->entity];
     								$object_type = 'propal';
    -								$mesg = $langs->transnoentitiesnoconv("EMailTextProposalValidated",$newref);
    +								$mesg = $outputlangs->transnoentitiesnoconv("EMailTextProposalValidated",$newref);
     								break;
     							case 'PROPAL_CLOSE_SIGNED':
     								$link='/comm/propal/card.php?id='.$object->id;
     								$dir_output = $conf->propal->multidir_output[$object->entity];
     								$object_type = 'propal';
    -								$mesg = $langs->transnoentitiesnoconv("EMailTextProposalClosedSigned",$newref);
    +								$mesg = $outputlangs->transnoentitiesnoconv("EMailTextProposalClosedSigned",$newref);
     								break;
     							case 'FICHINTER_ADD_CONTACT':
     								$link='/fichinter/card.php?id='.$object->id;
     								$dir_output = $conf->ficheinter->dir_output;
     								$object_type = 'ficheinter';
    -								$mesg = $langs->transnoentitiesnoconv("EMailTextInterventionAddedContact",$object->ref);
    +								$mesg = $outputlangs->transnoentitiesnoconv("EMailTextInterventionAddedContact",$newref);
     								break;
     							case 'FICHINTER_VALIDATE':
     								$link='/fichinter/card.php?id='.$object->id;
     								$dir_output = $conf->ficheinter->dir_output;
     								$object_type = 'ficheinter';
    -								$mesg = $langs->transnoentitiesnoconv("EMailTextInterventionValidated",$object->ref);
    +								$mesg = $outputlangs->transnoentitiesnoconv("EMailTextInterventionValidated",$newref);
     								break;
     							case 'ORDER_SUPPLIER_VALIDATE':
     								$link='/fourn/commande/card.php?id='.$object->id;
     								$dir_output = $conf->fournisseur->commande->dir_output;
     								$object_type = 'order_supplier';
    -								$mesg = $langs->transnoentitiesnoconv("Hello").",\n\n";
    -								$mesg.= $langs->transnoentitiesnoconv("EMailTextOrderValidatedBy",$object->ref,$user->getFullName($langs));
    -								$mesg.= "\n\n".$langs->transnoentitiesnoconv("Sincerely").".\n\n";
    +								$mesg = $outputlangs->transnoentitiesnoconv("Hello").",\n\n";
    +								$mesg.= $outputlangs->transnoentitiesnoconv("EMailTextOrderValidatedBy",$newref,$user->getFullName($langs));
    +								$mesg.= "\n\n".$outputlangs->transnoentitiesnoconv("Sincerely").".\n\n";
     								break;
     							case 'ORDER_SUPPLIER_APPROVE':
     								$link='/fourn/commande/card.php?id='.$object->id;
     								$dir_output = $conf->fournisseur->commande->dir_output;
     								$object_type = 'order_supplier';
    -								$mesg = $langs->transnoentitiesnoconv("Hello").",\n\n";
    -								$mesg.= $langs->transnoentitiesnoconv("EMailTextOrderApprovedBy",$newref,$user->getFullName($langs));
    -								$mesg.= "\n\n".$langs->transnoentitiesnoconv("Sincerely").".\n\n";
    +								$mesg = $outputlangs->transnoentitiesnoconv("Hello").",\n\n";
    +								$mesg.= $outputlangs->transnoentitiesnoconv("EMailTextOrderApprovedBy",$newref,$user->getFullName($langs));
    +								$mesg.= "\n\n".$outputlangs->transnoentitiesnoconv("Sincerely").".\n\n";
     								break;
     							case 'ORDER_SUPPLIER_REFUSE':
     								$link='/fourn/commande/card.php?id='.$object->id;
     								$dir_output = $conf->fournisseur->commande->dir_output;
     								$object_type = 'order_supplier';
    -								$mesg = $langs->transnoentitiesnoconv("Hello").",\n\n";
    -								$mesg.= $langs->transnoentitiesnoconv("EMailTextOrderRefusedBy",$newref,$user->getFullName($langs));
    -								$mesg.= "\n\n".$langs->transnoentitiesnoconv("Sincerely").".\n\n";
    +								$mesg = $outputlangs->transnoentitiesnoconv("Hello").",\n\n";
    +								$mesg.= $outputlangs->transnoentitiesnoconv("EMailTextOrderRefusedBy",$newref,$user->getFullName($langs));
    +								$mesg.= "\n\n".$outputlangs->transnoentitiesnoconv("Sincerely").".\n\n";
     								break;
     							case 'SHIPPING_VALIDATE':
     								$dir_output = $conf->expedition->dir_output.'/sending/';
     								$object_type = 'order_supplier';
    -								$mesg = $langs->transnoentitiesnoconv("EMailTextExpeditionValidated",$newref);
    +								$mesg = $outputlangs->transnoentitiesnoconv("EMailTextExpeditionValidated",$newref);
    +								break;
    +							case 'EXPENSE_REPORT_VALIDATE':
    +								$dir_output = $conf->expensereport->dir_output;
    +								$object_type = 'expensereport';
    +								$mesg = $outputlangs->transnoentitiesnoconv("EMailTextExpenseReportValidated",$newref);
    +								break;
    +							case 'EXPENSE_REPORT_APPROVE':
    +								$dir_output = $conf->expensereport->dir_output;
    +								$object_type = 'expensereport';
    +								$mesg = $outputlangs->transnoentitiesnoconv("EMailTextExpenseReportApproved",$newref);
    +								break;
    +							case 'HOLIDAY_VALIDATE':
    +								$dir_output = $conf->holiday->dir_output;
    +								$object_type = 'holiday';
    +								$mesg = $outputlangs->transnoentitiesnoconv("EMailTextHolidayValidated",$newref);
    +								break;
    +							case 'HOLIDAY_APPROVE':
    +								$dir_output = $conf->holiday->dir_output;
    +								$object_type = 'holiday';
    +								$mesg = $outputlangs->transnoentitiesnoconv("EMailTextHolidayApproved",$newref);
     								break;
     						}
     						$ref = dol_sanitizeFileName($newref);
    @@ -662,6 +693,26 @@ class Notify
     						$object_type = 'order_supplier';
     						$mesg = $langs->transnoentitiesnoconv("EMailTextExpeditionValidated",$newref);
     						break;
    +					case 'EXPENSE_REPORT_VALIDATE':
    +						$dir_output = $conf->expensereport->dir_output;
    +						$object_type = 'expensereport';
    +						$mesg = $langs->transnoentitiesnoconv("EMailTextExpenseReportValidated",$newref);
    +						break;
    +					case 'EXPENSE_REPORT_APPROVE':
    +						$dir_output = $conf->expensereport->dir_output;
    +						$object_type = 'expensereport';
    +						$mesg = $langs->transnoentitiesnoconv("EMailTextExpenseReportApproved",$newref);
    +						break;
    +					case 'HOLIDAY_VALIDATE':
    +						$dir_output = $conf->holiday->dir_output;
    +						$object_type = 'holiday';
    +						$mesg = $langs->transnoentitiesnoconv("EMailTextHolidayValidated",$newref);
    +						break;
    +					case 'HOLIDAY_APPROVE':
    +						$dir_output = $conf->holiday->dir_output;
    +						$object_type = 'holiday';
    +						$mesg = $langs->transnoentitiesnoconv("EMailTextHolidayApproved",$newref);
    +						break;
     				}
     				$ref = dol_sanitizeFileName($newref);
     				$pdf_path = $dir_output."/".$ref."/".$ref.".pdf";
    @@ -679,6 +730,8 @@ class Notify
     				$message.= $langs->transnoentities("YouReceiveMailBecauseOfNotification2",$application,$mysoc->name)."\n";
     				$message.= "\n";
     				$message.= $mesg;
    +				//if ($link) $message.= "\n" . $urlwithroot . $link;	// link already added around the ref into the text
    +
     				$message = nl2br($message);
     
     				// Replace keyword __SUPERVISOREMAIL__
    diff --git a/htdocs/core/class/translate.class.php b/htdocs/core/class/translate.class.php
    index 17f83452ba5..2e489f6ba65 100644
    --- a/htdocs/core/class/translate.class.php
    +++ b/htdocs/core/class/translate.class.php
    @@ -655,11 +655,12 @@ class Translate
     	 *  @param  string	$param2     chaine de param2
     	 *  @param  string	$param3     chaine de param3
     	 *  @param  string	$param4     chaine de param4
    +	 *  @param  string	$param5     chaine de param5
     	 *  @return string      		Translated string (encoded into UTF8)
     	 */
    -	function transnoentities($key, $param1='', $param2='', $param3='', $param4='')
    +	function transnoentities($key, $param1='', $param2='', $param3='', $param4='', $param5='')
     	{
    -		return $this->convToOutputCharset($this->transnoentitiesnoconv($key, $param1, $param2, $param3, $param4));
    +		return $this->convToOutputCharset($this->transnoentitiesnoconv($key, $param1, $param2, $param3, $param4, $param5));
     	}
     
     
    @@ -675,9 +676,10 @@ class Translate
     	 *  @param  string	$param2     chaine de param2
     	 *  @param  string	$param3     chaine de param3
     	 *  @param  string	$param4     chaine de param4
    +	 *  @param  string	$param5     chaine de param5
     	 *  @return string      		Translated string
     	 */
    -	function transnoentitiesnoconv($key, $param1='', $param2='', $param3='', $param4='')
    +	function transnoentitiesnoconv($key, $param1='', $param2='', $param3='', $param4='', $param5='')
     	{
     		global $conf;
     
    @@ -700,7 +702,7 @@ class Translate
                 if (! preg_match('/^Format/',$key))
                 {
                 	//print $str;
    -           		$str=sprintf($str,$param1,$param2,$param3,$param4);	// Replace %s and %d except for FormatXXX strings.
    +           		$str=sprintf($str, $param1, $param2, $param3, $param4, $param5);	// Replace %s and %d except for FormatXXX strings.
                 }
     
                 return $str;
    diff --git a/htdocs/core/class/utils.class.php b/htdocs/core/class/utils.class.php
    index 9f680ef4990..7904f485d6a 100644
    --- a/htdocs/core/class/utils.class.php
    +++ b/htdocs/core/class/utils.class.php
    @@ -284,8 +284,9 @@ class Utils
     			}
     
     			$errormsg='';
    +			$handle = '';
     
    -			// Debut appel methode execution
    +			// Start call method to execute dump
     			$fullcommandcrypted=$command." ".$paramcrypted." 2>&1";
     			$fullcommandclear=$command." ".$paramclear." 2>&1";
     			if ($compression == 'none') $handle = fopen($outputfile, 'w');
    diff --git a/htdocs/core/lib/ajax.lib.php b/htdocs/core/lib/ajax.lib.php
    index 8a39043a680..bb08018b7f6 100644
    --- a/htdocs/core/lib/ajax.lib.php
    +++ b/htdocs/core/lib/ajax.lib.php
    @@ -546,7 +546,7 @@ function ajax_constantonoff($code, $input=array(), $entity=null, $revertonoff=0,
      *  @param  string  $text_on    Text if on
      *  @param  string  $text_off   Text if off
      *  @param  array   $input      Array of type->list of CSS element to switch. Example: array('disabled'=>array(0=>'cssid'))
    - *  @return void
    + *  @return string              html for button on/off
      */
     function ajax_object_onoff($object, $code, $field, $text_on, $text_off, $input=array())
     {
    diff --git a/htdocs/core/lib/asset.lib.php b/htdocs/core/lib/asset.lib.php
    index 7a4fd80158c..b0a4a6b81a9 100644
    --- a/htdocs/core/lib/asset.lib.php
    +++ b/htdocs/core/lib/asset.lib.php
    @@ -26,7 +26,7 @@
      *
      * @return array head array with tabs
      */
    -function AssetsAdminPrepareHead()
    +function asset_admin_prepare_head()
     {
     	global $langs, $conf;
     
    @@ -70,7 +70,7 @@ function AssetsAdminPrepareHead()
      *
      * @return array head array with tabs
      */
    -function AssetsPrepareHead()
    +function asset_prepare_head()
     {
     	global $langs, $conf;
     
    diff --git a/htdocs/core/lib/company.lib.php b/htdocs/core/lib/company.lib.php
    index a23474e1104..46e3922a0d0 100644
    --- a/htdocs/core/lib/company.lib.php
    +++ b/htdocs/core/lib/company.lib.php
    @@ -6,11 +6,11 @@
      * Copyright (C) 2013-2014  Florian Henry           <florian.henry@open-concept.pro>
      * Copyright (C) 2013-2014  Juanjo Menent           <jmenent@2byte.es>
      * Copyright (C) 2013       Christophe Battarel     <contact@altairis.fr>
    - * Copyright (C) 2013       Alexandre Spangaro      <aspangaro.dolibarr@gmail.com>
    + * Copyright (C) 2013-2018  Alexandre Spangaro      <aspangaro@zendsi.com>
      * Copyright (C) 2015-2018  Frédéric France         <frederic.france@netlogic.fr>
      * Copyright (C) 2015       Raphaël Doursenaud      <rdoursenaud@gpcsolutions.fr>
    - * Copyright (C) 2017       Rui Strecht			    <rui.strecht@aliartalentos.com>
    - * Copyright (C) 2018       Ferran Marcet		    <fmarcet@2byte.es>
    + * Copyright (C) 2017       Rui Strecht             <rui.strecht@aliartalentos.com>
    + * Copyright (C) 2018       Ferran Marcet           <fmarcet@2byte.es>
      *
      * This program is free software; you can redistribute it and/or modify
      * it under the terms of the GNU General Public License as published by
    @@ -154,18 +154,18 @@ function societe_prepare_head(Societe $object)
     		// Tab to accountancy
     		if (! empty($conf->accounting->enabled) && $object->client>0)
     		{
    -			$head[$h][0] = DOL_URL_ROOT.'/accountancy/bookkeeping/thirdparty_lettrage.php?socid='.$object->id;
    -			$head[$h][1] = $langs->trans("TabAccountingCustomer");
    -			$head[$h][2] = 'accounting';
    +			$head[$h][0] = DOL_URL_ROOT.'/accountancy/bookkeeping/thirdparty_lettering_customer.php?socid='.$object->id;
    +			$head[$h][1] = $langs->trans("TabLetteringCustomer");
    +			$head[$h][2] = 'lettering_customer';
     			$h++;
     		}
     
     		// Tab to accountancy
     		if (! empty($conf->accounting->enabled) && $object->fournisseur>0)
     		{
    -			$head[$h][0] = DOL_URL_ROOT.'/accountancy/bookkeeping/thirdparty_lettrage_supplier.php?socid='.$object->id;
    -			$head[$h][1] = $langs->trans("TabAccountingSupplier");
    -			$head[$h][2] = 'accounting_supplier';
    +			$head[$h][0] = DOL_URL_ROOT.'/accountancy/bookkeeping/thirdparty_lettering_supplier.php?socid='.$object->id;
    +			$head[$h][1] = $langs->trans("TabLetteringSupplier");
    +			$head[$h][2] = 'lettering_supplier';
     			$h++;
     		}
     	}
    @@ -1303,6 +1303,8 @@ function show_actions_done($conf, $langs, $db, $filterobj, $objcon='', $noprint=
     
         global $param;
     
    +    dol_include_once('/comm/action/class/actioncomm.class.php');
    +
         // Check parameters
         if (! is_object($filterobj) && ! is_object($objcon)) dol_print_error('','BadParameter');
     
    @@ -1358,6 +1360,7 @@ function show_actions_done($conf, $langs, $db, $filterobj, $objcon='', $noprint=
             	$sql.= " AND a.fk_element = o.rowid AND a.elementtype = 'product'";
             	if ($filterobj->id) $sql.= " AND a.fk_element = ".$filterobj->id;
             }
    +        //TODO check how ot work with new table actioncomm_resources and multiple contact affectation
             if (is_object($objcon) && $objcon->id) $sql.= " AND a.fk_contact = ".$objcon->id;
             // Condition on actioncode
             if (! empty($actioncode))
    @@ -1394,6 +1397,14 @@ function show_actions_done($conf, $langs, $db, $filterobj, $objcon='', $noprint=
                 {
                     $obj = $db->fetch_object($resql);
     
    +                $contactaction = new ActionComm($db);
    +                $contactaction->id=$obj->id;
    +                $result = $contactaction->fetchResources();
    +                if ($result<0) {
    +                	dol_print_error($db);
    +                	setEventMessage("company.lib::show_actions_done Error fetch ressource",'errors');
    +                }
    +
                     //if ($donetodo == 'todo') $sql.= " AND ((a.percent >= 0 AND a.percent < 100) OR (a.percent = -1 AND a.datep > '".$db->idate($now)."'))";
                     //elseif ($donetodo == 'done') $sql.= " AND (a.percent = 100 OR (a.percent = -1 AND a.datep <= '".$db->idate($now)."'))";
                     $tododone='';
    @@ -1415,6 +1426,7 @@ function show_actions_done($conf, $langs, $db, $filterobj, $objcon='', $noprint=
                         'userphoto'=>$obj->user_photo,
     
                         'contact_id'=>$obj->fk_contact,
    +                	'socpeopleassigned' => $contactaction->socpeopleassigned,
                 		'lastname'=>$obj->lastname,
                 		'firstname'=>$obj->firstname,
                 		'fk_element'=>$obj->fk_element,
    @@ -1559,7 +1571,7 @@ function show_actions_done($conf, $langs, $db, $filterobj, $objcon='', $noprint=
     		$out.=getTitleFieldOfList($langs->trans("Label"), 0, $_SERVER["PHP_SELF"], '', '', $param, '', $sortfield, $sortorder);
             $out.=getTitleFieldOfList($langs->trans("Date"), 0, $_SERVER["PHP_SELF"], 'a.datep,a.id', '', $param, 'align="center"', $sortfield, $sortorder);
     		$out.=getTitleFieldOfList('');
    -		$out.=getTitleFieldOfList($langs->trans("ActionOnContact"), 0, $_SERVER["PHP_SELF"], 'a.fk_contact', '', $param, '', $sortfield, $sortorder);
    +		$out.=getTitleFieldOfList($langs->trans("ActionOnContact"), 0, $_SERVER["PHP_SELF"], '', '', $param, '', $sortfield, $sortorder);
     		$out.=getTitleFieldOfList($langs->trans("Status"), 0, $_SERVER["PHP_SELF"], 'a.percent', '', $param, 'align="center"', $sortfield, $sortorder);
     		$out.=getTitleFieldOfList('', 0, $_SERVER["PHP_SELF"], '', '', $param, '', $sortfield, $sortorder, 'maxwidthsearch ');
     		$out.='</tr>';
    @@ -1678,10 +1690,28 @@ function show_actions_done($conf, $langs, $db, $filterobj, $objcon='', $noprint=
                     $contactstatic->firstname=$histo[$key]['firstname'];
                     $contactstatic->id=$histo[$key]['contact_id'];
                     $out.='<td width="120">'.$contactstatic->getNomUrl(1,'',10).'</td>';
    -            }
    -            else
    -            {
    -                $out.='<td>&nbsp;</td>';
    +            } elseif (isset($histo[$key]['socpeopleassigned']) && is_array($histo[$key]['socpeopleassigned']) && count($histo[$key]['socpeopleassigned']) > 0) {
    +				$out .= '<td>';
    +				foreach ( $histo[$key]['socpeopleassigned'] as $cid => $Tab ) {
    +					$contact = new Contact($db);
    +					$result = $contact->fetch($cid);
    +
    +					if ($result < 0)
    +						dol_print_error($db, $contact->error);
    +
    +					if ($result > 0) {
    +						$out .= $contact->getNomUrl(1);
    +						if (isset($histo[$key]['acode']) && $histo[$key]['acode'] == 'AC_TEL') {
    +							if (! empty($contact->phone_pro))
    +								$out .= '(' . dol_print_phone($contact->phone_pro) . ')';
    +						}
    +						$out .= '<div class="paddingright"></div>';
    +					}
    +				}
    +				$out .= '</td>';
    +			}
    +            else {
    +            	$out.='<td>&nbsp;</td>';
                 }
     
                 // Status
    diff --git a/htdocs/core/lib/date.lib.php b/htdocs/core/lib/date.lib.php
    index 8f01ea6aebe..84048ac9c66 100644
    --- a/htdocs/core/lib/date.lib.php
    +++ b/htdocs/core/lib/date.lib.php
    @@ -572,6 +572,8 @@ function dol_get_first_day_week($day,$month,$year,$gm=false)
      */
     function num_public_holiday($timestampStart, $timestampEnd, $countrycode='FR', $lastday=0)
     {
    +	global $conf;
    +
     	$nbFerie = 0;
     
     	// Check to ensure we use correct parameters
    @@ -583,10 +585,31 @@ function num_public_holiday($timestampStart, $timestampEnd, $countrycode='FR', $
     	{
     		$ferie=false;
     		$countryfound=0;
    +		$includesaturdayandsunday=1;
     
     		$jour  = date("d", $timestampStart);
     		$mois  = date("m", $timestampStart);
     		$annee = date("Y", $timestampStart);
    +
    +
    +		// Check into var $conf->global->HOLIDAY_MORE_DAYS   MM-DD,YYYY-MM-DD, ...
    +		if (! empty($conf->global->HOLIDAY_MORE_PUBLIC_HOLIDAYS))
    +		{
    +			$arrayofdaystring=explode(',',$conf->global->HOLIDAY_MORE_PUBLIC_HOLIDAYS);
    +			foreach($arrayofdaystring as $daystring)
    +			{
    +				$tmp=explode('-',$daystring);
    +				if ($tmp[2])
    +				{
    +					if ($tmp[0] == $annee && $tmp[1] == $mois && $tmp[2] == $jour) $ferie=true;
    +				}
    +				else
    +				{
    +					if ($tmp[0] == $mois && $tmp[1] == $jour) $ferie=true;
    +				}
    +			}
    +		}
    +
     		if ($countrycode == 'FR')
     		{
     			$countryfound=1;
    @@ -649,12 +672,6 @@ function num_public_holiday($timestampStart, $timestampEnd, $countrycode='FR', $
     			$mois_pentecote = date("m", $date_pentecote);
     			if($jour_pentecote == $jour && $mois_pentecote == $mois) $ferie=true;
     			// "Pentecote"
    -
    -			// Calul des samedis et dimanches
    -			$jour_julien = unixtojd($timestampStart);
    -			$jour_semaine = jddayofweek($jour_julien, 0);
    -			if($jour_semaine == 0 || $jour_semaine == 6) $ferie=true;
    -			// Samedi (6) et dimanche (0)
     		}
     
     		// Pentecoste and Ascensione in Italy go to the sunday after: isn't holiday.
    @@ -681,12 +698,18 @@ function num_public_holiday($timestampStart, $timestampEnd, $countrycode='FR', $
     			$mois_paques = date("m", $date_paques);
     			if($jour_paques == $jour && $mois_paques == $mois) $ferie=true;
     			// Paques
    +		}
     
    -			// Calul des samedis et dimanches
    -			$jour_julien = unixtojd($timestampStart);
    -			$jour_semaine = jddayofweek($jour_julien, 0);
    -			if($jour_semaine == 0 || $jour_semaine == 6) $ferie=true;
    -			//Samedi (6) et dimanche (0)
    +		if ($countrycode == 'IN')
    +		{
    +			$countryfound=1;
    +
    +			if($jour == 1 && $mois == 1) $ferie=true; // New Year's Day
    +			if($jour == 26 && $mois == 1) $ferie=true; // Republic Day
    +			if($jour == 1 && $mois == 5) $ferie=true; // May Day
    +			if($jour == 15 && $mois == 8) $ferie=true; // Independence Day
    +			if($jour == 2 && $mois == 10) $ferie=true; // Gandhi Jayanti
    +			if($jour == 25 && $mois == 12) $ferie=true; // Christmas
     		}
     
     		if ($countrycode == 'ES')
    @@ -724,12 +747,6 @@ function num_public_holiday($timestampStart, $timestampEnd, $countrycode='FR', $
     			$mois_viernes = date("m", $date_viernes);
     			if($jour_viernes == $jour && $mois_viernes == $mois) $ferie=true;
     			//Viernes Santo
    -
    -			// Calul des samedis et dimanches
    -			$jour_julien = unixtojd($timestampStart);
    -			$jour_semaine = jddayofweek($jour_julien, 0);
    -			if($jour_semaine == 0 || $jour_semaine == 6) $ferie=true;
    -			//Samedi (6) et dimanche (0)
     		}
     
     		if ($countrycode == 'AT')
    @@ -811,22 +828,15 @@ function num_public_holiday($timestampStart, $timestampEnd, $countrycode='FR', $
     		    $mois_fronleichnam = date("m", $date_fronleichnam);
     		    if($jour_fronleichnam == $jour && $mois_fronleichnam == $mois) $ferie=true;
     		    // Fronleichnam
    -
    -		    // Calul des samedis et dimanches
    -		    $jour_julien = unixtojd($timestampStart);
    -		    $jour_semaine = jddayofweek($jour_julien, 0);
    -		    if($jour_semaine == 0 || $jour_semaine == 6) $ferie=true;
    -		    //Samedi (6) et dimanche (0)
     		}
     
    -		// Cas pays non defini
    -		if (! $countryfound)
    +		// If we have to include saturday and sunday
    +		if ($includesaturdayandsunday)
     		{
    -			// Calul des samedis et dimanches
     			$jour_julien = unixtojd($timestampStart);
     			$jour_semaine = jddayofweek($jour_julien, 0);
     			if($jour_semaine == 0 || $jour_semaine == 6) $ferie=true;
    -			//Samedi (6) et dimanche (0)
    +			//Saturday (6) and Sunday (0)
     		}
     
     		// On incremente compteur
    diff --git a/htdocs/core/lib/files.lib.php b/htdocs/core/lib/files.lib.php
    index 5aff804b4da..7897041ebbf 100644
    --- a/htdocs/core/lib/files.lib.php
    +++ b/htdocs/core/lib/files.lib.php
    @@ -2496,7 +2496,7 @@ function dol_check_secure_access_document($modulepart, $original_file, $entity,
     		//$sqlprotectagainstexternals = "SELECT fk_soc as fk_soc FROM ".MAIN_DB_PREFIX."fichinter WHERE ref='".$db->escape($refname)."' AND entity=".$conf->entity;
     	}
     	// Wrapping pour les propales
    -	else if ($modulepart == 'propal' && !empty($conf->propal->multidir_output[$entity]))
    +	else if (($modulepart == 'propal' || $modulepart == 'propale') && !empty($conf->propal->multidir_output[$entity]))
     	{
     		if ($fuser->rights->propale->{$lire} || preg_match('/^specimen/i',$original_file))
     		{
    diff --git a/htdocs/core/lib/functions.lib.php b/htdocs/core/lib/functions.lib.php
    index d53e20fdc7d..7888338cdc2 100644
    --- a/htdocs/core/lib/functions.lib.php
    +++ b/htdocs/core/lib/functions.lib.php
    @@ -13,6 +13,7 @@
      * Copyright (C) 2014		Cédric GROSS					<c.gross@kreiz-it.fr>
      * Copyright (C) 2014-2015	Marcos García				<marcosgdf@gmail.com>
      * Copyright (C) 2015		Jean-François Ferry			<jfefe@aternatik.fr>
    + * Copyright (C) 2018       Frédéric France             <frederic.france@netlogic.fr>
      *
      * This program is free software; you can redistribute it and/or modify
      * it under the terms of the GNU General Public License as published by
    @@ -2189,50 +2190,52 @@ function dol_print_email($email,$cid=0,$socid=0,$addlink=0,$max=64,$showinvalid=
     }
     
     /**
    - * Show Skype link
    + * Show social network link
      *
    - * @param	string		$skype			Skype to show (only skype, without 'Name of recipient' before)
    + * @param	string		$value			Skype to show (only skype, without 'Name of recipient' before)
      * @param	int 		$cid 			Id of contact if known
      * @param	int 		$socid 			Id of third party if known
    - * @param	int 		$addlink		0=no link to create action
    - * @param	int			$max			Max number of characters to show
    + * @param	string 		$type			'skype','facebook',...
      * @return	string						HTML Link
      */
    -function dol_print_skype($skype,$cid=0,$socid=0,$addlink=0,$max=64)
    +function dol_print_socialnetworks($value,$cid,$socid,$type)
     {
     	global $conf,$user,$langs;
     
    -	$newskype=$skype;
    +	$newskype=$value;
     
    -	if (empty($skype)) return '&nbsp;';
    +	if (empty($value)) return '&nbsp;';
     
    -	if (! empty($addlink))
    +	if (! empty($type))
     	{
    -		$newskype =img_picto($langs->trans("Skype"), 'object_skype.png');
    -		$newskype.= '&nbsp;';
    -		$newskype.=dol_trunc($skype,$max);
    -		$newskype.= '&nbsp;';
    -		$newskype.='<a href="skype:';
    -		$newskype.=dol_trunc($skype,$max);
    -		$newskype.='?call" alt="'.$langs->trans("Call").'&nbsp;'.$skype.'" title="'.$langs->trans("Call").'&nbsp;'.$skype.'">';
    -		$newskype.='<img src="'.DOL_URL_ROOT.'/theme/common/skype_callbutton.png" border="0">';
    -		$newskype.='</a>&nbsp;&nbsp;&nbsp;<a href="skype:';
    -		$newskype.=dol_trunc($skype,$max);
    -		$newskype.='?chat" alt="'.$langs->trans("Chat").'&nbsp;'.$skype.'" title="'.$langs->trans("Chat").'&nbsp;'.$skype.'">';
    -		$newskype.='<img src="'.DOL_URL_ROOT.'/theme/common/skype_chatbutton.png" border="0">';
    -		$newskype.='</a>';
    -
    -		if (($cid || $socid) && ! empty($conf->agenda->enabled) && $user->rights->agenda->myactions->create)
    +		$newskype ='<div class="divsocialnetwork inline-block valignmiddle">';
    +		$newskype.=img_picto($langs->trans(strtoupper($type)), $type.'.png', '', false, 0, 0, '', 'paddingright');
    +		$newskype.=$value;
    +		if ($type == 'skype')
     		{
    -			$type='AC_SKYPE'; $link='';
    -			if (! empty($conf->global->AGENDA_ADDACTIONFORSKYPE)) $link='<a href="'.DOL_URL_ROOT.'/comm/action/card.php?action=create&amp;backtopage=1&amp;actioncode='.$type.'&amp;contactid='.$cid.'&amp;socid='.$socid.'">'.img_object($langs->trans("AddAction"),"calendar").'</a>';
    -			$newskype='<div class="divskype nowrap">'.$newskype.($link?' '.$link:'').'</div>';
    +			$newskype.= '&nbsp;';
    +			$newskype.='<a href="skype:';
    +			$newskype.=$value;
    +			$newskype.='?call" alt="'.$langs->trans("Call").'&nbsp;'.$value.'" title="'.$langs->trans("Call").'&nbsp;'.$value.'">';
    +			$newskype.='<img src="'.DOL_URL_ROOT.'/theme/common/skype_callbutton.png" border="0">';
    +			$newskype.='</a><a href="skype:';
    +			$newskype.=$value;
    +			$newskype.='?chat" alt="'.$langs->trans("Chat").'&nbsp;'.$value.'" title="'.$langs->trans("Chat").'&nbsp;'.$value.'">';
    +			$newskype.='<img class="paddingleft" src="'.DOL_URL_ROOT.'/theme/common/skype_chatbutton.png" border="0">';
    +			$newskype.='</a>';
     		}
    +		if (($cid || $socid) && ! empty($conf->agenda->enabled) && $user->rights->agenda->myactions->create && $type=='skype')
    +		{
    +			$addlink='AC_SKYPE'; $link='';
    +			if (! empty($conf->global->AGENDA_ADDACTIONFORSKYPE)) $link='<a href="'.DOL_URL_ROOT.'/comm/action/card.php?action=create&amp;backtopage=1&amp;actioncode='.$addlink.'&amp;contactid='.$cid.'&amp;socid='.$socid.'">'.img_object($langs->trans("AddAction"),"calendar").'</a>';
    +			$newskype.=($link?' '.$link:'');
    +		}
    +		$newskype.='</div>';
     	}
     	else
     	{
     		$langs->load("errors");
    -		$newskype.=img_warning($langs->trans("ErrorBadSkype",$skype));
    +		$newskype.=img_warning($langs->trans("ErrorBadSocialNetworkValue",$value));
     	}
     	return $newskype;
     }
    @@ -3151,11 +3154,13 @@ function img_picto($titlealt, $picto, $moreatt = '', $pictoisfullpath = false, $
     		//if (in_array($picto, array('switch_off', 'switch_on', 'off', 'on')))
     		if (empty($srconly) && in_array($pictowithoutext, array(
     				'bank', 'close_title', 'delete', 'edit', 'ellipsis-h', 'filter', 'grip', 'grip_title', 'list', 'listlight', 'off', 'on', 'play', 'playdisabled', 'printer', 'resize',
    -				'note','switch_off', 'switch_on', 'unlink', 'uparrow', '1downarrow', '1uparrow')
    -			)) {
    +				'note','switch_off', 'switch_on', 'unlink', 'uparrow', '1downarrow', '1uparrow',
    +				'skype','twitter','facebook'
    +			)
    +		)) {
     			$fakey = $pictowithoutext;
     			$facolor = ''; $fasize = '';
    -			$marginleftonlyshort = 0;
    +			$marginleftonlyshort = 2;
     			if ($pictowithoutext == 'switch_off') {
     				$fakey = 'fa-toggle-off';
     				$facolor = '#999';
    @@ -3237,12 +3242,13 @@ function img_picto($titlealt, $picto, $moreatt = '', $pictoisfullpath = false, $
     			else {
     				$fakey = 'fa-'.$pictowithoutext;
     				$facolor = '#444';
    +				$marginleftonlyshort=0;
     			}
     
     			if (preg_match('/class="([^"]+)"/', $moreatt, $reg)) {
     				$morecss.= ($morecss?' ':'').$reg[1];
     			}
    -			$enabledisablehtml = '<span class="fa '.$fakey.' '.($marginleftonlyshort?'marginleftonlyshort':'marginleftonly').' valignmiddle'.($morecss?' '.$morecss:'').'" style="'.($fasize?('font-size: '.$fasize.';'):'').($facolor?(' color: '.$facolor.';'):'').'" alt="'.dol_escape_htmltag($titlealt).'"'.(($notitle || empty($title))?'':' title="'.dol_escape_htmltag($title).'"').($moreatt?' '.$moreatt:'').'>';
    +			$enabledisablehtml = '<span class="fa '.$fakey.' '.($marginleftonlyshort?($marginleftonlyshort==1?'marginleftonlyshort':'marginleftonly'):'').' valignmiddle'.($morecss?' '.$morecss:'').'" style="'.($fasize?('font-size: '.$fasize.';'):'').($facolor?(' color: '.$facolor.';'):'').'" alt="'.dol_escape_htmltag($titlealt).'"'.(($notitle || empty($title))?'':' title="'.dol_escape_htmltag($title).'"').($moreatt?' '.$moreatt:'').'>';
     			if (! empty($conf->global->MAIN_OPTIMIZEFORTEXTBROWSER)) {
     				$enabledisablehtml.= $titlealt;
     			}
    @@ -4565,6 +4571,7 @@ function price($amount, $form=0, $outlangs='', $trunc=1, $rounding=-1, $forcerou
      * 									'MU'=Round to Max unit price (MAIN_MAX_DECIMALS_UNIT)
      *									'MT'=Round to Max for totals with Tax (MAIN_MAX_DECIMALS_TOT)
      *									'MS'=Round to Max for stock quantity (MAIN_MAX_DECIMALS_STOCK)
    + *									Numeric = Nb of digits for rounding
      * 	@param	int		$alreadysqlnb	Put 1 if you know that content is already universal format number
      *	@return	string					Amount with universal numeric format (Example: '99.99999') or unchanged text if conversion fails. If amount is null or '', it returns ''.
      *
    @@ -4615,7 +4622,7 @@ function price2num($amount,$rounding='',$alreadysqlnb=0)
     		if ($rounding == 'MU')     $nbofdectoround=$conf->global->MAIN_MAX_DECIMALS_UNIT;
     		elseif ($rounding == 'MT') $nbofdectoround=$conf->global->MAIN_MAX_DECIMALS_TOT;
     		elseif ($rounding == 'MS') $nbofdectoround=empty($conf->global->MAIN_MAX_DECIMALS_STOCK)?5:$conf->global->MAIN_MAX_DECIMALS_STOCK;
    -		elseif (is_numeric($rounding))  $nbofdectoround=$rounding; 	// For admin info page
    +		elseif (is_numeric($rounding))  $nbofdectoround=$rounding;
     		//print "RR".$amount.' - '.$nbofdectoround.'<br>';
     		if (dol_strlen($nbofdectoround)) $amount = round($amount,$nbofdectoround);	// $nbofdectoround can be 0.
     		else return 'ErrorBadParameterProvidedToFunction';
    @@ -5982,6 +5989,7 @@ function getCommonSubstitutionArray($outputlangs, $onlykey=0, $exclude=null, $ob
     
     			$substitutionarray['__THIRDPARTY_ID__'] = '__THIRDPARTY_ID__';
     			$substitutionarray['__THIRDPARTY_NAME__'] = '__THIRDPARTY_NAME__';
    +			$substitutionarray['__THIRDPARTY_NAME_ALIAS__'] = '__THIRDPARTY_NAME_ALIAS__';
     			$substitutionarray['__THIRDPARTY_EMAIL__'] = '__THIRDPARTY_EMAIL__';
     
     			if (is_object($object) && $object->element == 'member')
    @@ -6044,6 +6052,12 @@ function getCommonSubstitutionArray($outputlangs, $onlykey=0, $exclude=null, $ob
     			$substitutionarray['__MEMBER_PHONE__']=$msgishtml?dol_htmlentitiesbr($object->phone):$object->phone;
     			$substitutionarray['__MEMBER_PHONEPRO__']=$msgishtml?dol_htmlentitiesbr($object->phone_perso):$object->phone_perso;
     			$substitutionarray['__MEMBER_PHONEMOBILE__']=$msgishtml?dol_htmlentitiesbr($object->phone_mobile):$object->phone_mobile;
    +			$substitutionarray['__MEMBER_FIRST_SUBSCRIPTION_DATE__']       = dol_print_date($object->first_subscription_date, 'dayrfc');
    +			$substitutionarray['__MEMBER_FIRST_SUBSCRIPTION_DATE_START__'] = dol_print_date($object->first_subscription_date_start, 'dayrfc');
    +			$substitutionarray['__MEMBER_FIRST_SUBSCRIPTION_DATE_END__']   = dol_print_date($object->first_subscription_date_end, 'dayrfc');
    +			$substitutionarray['__MEMBER_LAST_SUBSCRIPTION_DATE__']        = dol_print_date($object->last_subscription_date, 'dayrfc');
    +			$substitutionarray['__MEMBER_LAST_SUBSCRIPTION_DATE_START__']  = dol_print_date($object->last_subscription_date_start, 'dayrfc');
    +			$substitutionarray['__MEMBER_LAST_SUBSCRIPTION_DATE_END__']    = dol_print_date($object->last_subscription_date_end, 'dayrfc');
     
     			if (is_object($object) && $object->element == 'societe')
     			{
    @@ -6212,7 +6226,7 @@ function getCommonSubstitutionArray($outputlangs, $onlykey=0, $exclude=null, $ob
      *  @param  array		$substitutionarray		Array with key->val to substitute. Example: array('__MYKEY__' => 'MyVal', ...)
      *  @param	Translate	$outputlangs			Output language
      * 	@return string  		    				Output string after substitutions
    - *  @see	complete_substitutions_array
    + *  @see	complete_substitutions_array, getCommonSubstitutionArray
      */
     function make_substitutions($text, $substitutionarray, $outputlangs=null)
     {
    @@ -7013,11 +7027,12 @@ function complete_head_from_modules($conf,$langs,$object,&$head,&$h,$type,$mode=
     	// No need to make a return $head. Var is modified as a reference
     	if (! empty($hookmanager))
     	{
    -		$parameters=array('object' => $object, 'mode' => $mode, 'head'=>$head);
    -		$reshook=$hookmanager->executeHooks('completeTabsHead',$parameters);
    +		$parameters=array('object' => $object, 'mode' => $mode, 'head' => $head);
    +		$reshook=$hookmanager->executeHooks('completeTabsHead', $parameters);
     		if ($reshook > 0)
     		{
     			$head = $hookmanager->resArray;
    +            $h = count($head);
     		}
     	}
     }
    diff --git a/htdocs/core/lib/import.lib.php b/htdocs/core/lib/import.lib.php
    index 89847d69c11..ea700c38845 100644
    --- a/htdocs/core/lib/import.lib.php
    +++ b/htdocs/core/lib/import.lib.php
    @@ -1,8 +1,9 @@
     <?php
    -/* Copyright (C) 2006-2009 Laurent Destailleur  <eldy@users.sourceforge.net>
    - * Copyright (C) 2007      Rodolphe Quiedeville <rodolphe@quiedeville.org>
    - * Copyright (C) 2010      Regis Houssin        <regis.houssin@capnetworks.com>
    - * Copyright (C) 2010      Juanjo Menent        <jmenent@2byte.es>
    +/* Copyright (C) 2006-2009  Laurent Destailleur     <eldy@users.sourceforge.net>
    + * Copyright (C) 2007       Rodolphe Quiedeville    <rodolphe@quiedeville.org>
    + * Copyright (C) 2010       Regis Houssin           <regis.houssin@capnetworks.com>
    + * Copyright (C) 2010       Juanjo Menent           <jmenent@2byte.es>
    + * Copyright (C) 2018       Frédéric France         <frederic.france@netlogic.fr>
      *
      * This program is free software; you can redistribute it and/or modify
      * it under the terms of the GNU General Public License as published by
    @@ -20,10 +21,9 @@
      */
     
     /**
    - *  \file       htdocs/core/lib/order.lib.php
    - *  \brief      Ensemble de fonctions de base pour le module commande
    - *  \ingroup    commande
    - */
    + *  \file       htdocs/core/lib/import.lib.php
    + *  \brief      Ensemble de fonctions de base pour le module import
    + *  \ingroup    import
     
     /**
      * Function to return list of tabs for import pages
    diff --git a/htdocs/core/lib/payments.lib.php b/htdocs/core/lib/payments.lib.php
    index ecbdfad82f5..0119b0f0ee5 100644
    --- a/htdocs/core/lib/payments.lib.php
    +++ b/htdocs/core/lib/payments.lib.php
    @@ -1,6 +1,7 @@
     <?php
     /**
    - * Copyright (C) 2013	Marcos García	<marcosgdf@gmail.com>
    + * Copyright (C) 2013	    Marcos García	        <marcosgdf@gmail.com>
    + * Copyright (C) 2018       Frédéric France         <frederic.france@netlogic.fr>
      *
      * This program is free software; you can redistribute it and/or modify
      * it under the terms of the GNU General Public License as published by
    @@ -164,7 +165,7 @@ function getOnlinePaymentUrl($mode, $type, $ref='', $amount='9.99', $freetag='yo
     			else $out.='&securekey='.dol_hash($conf->global->PAYMENT_SECURITY_TOKEN, 2);
     		}
     	}
    -	if ($type == 'order')
    +	elseif ($type == 'order')
     	{
     		$out=DOL_MAIN_URL_ROOT.'/public/payment/newpayment.php?source=order&ref='.($mode?'<font color="#666666">':'');
     		if ($mode == 1) $out.='order_ref';
    @@ -182,7 +183,7 @@ function getOnlinePaymentUrl($mode, $type, $ref='', $amount='9.99', $freetag='yo
     			}
     		}
     	}
    -	if ($type == 'invoice')
    +	elseif ($type == 'invoice')
     	{
     		$out=DOL_MAIN_URL_ROOT.'/public/payment/newpayment.php?source=invoice&ref='.($mode?'<font color="#666666">':'');
     		if ($mode == 1) $out.='invoice_ref';
    @@ -200,7 +201,7 @@ function getOnlinePaymentUrl($mode, $type, $ref='', $amount='9.99', $freetag='yo
     			}
     		}
     	}
    -	if ($type == 'contractline')
    +	elseif ($type == 'contractline')
     	{
     		$out=DOL_MAIN_URL_ROOT.'/public/payment/newpayment.php?source=contractline&ref='.($mode?'<font color="#666666">':'');
     		if ($mode == 1) $out.='contractline_ref';
    @@ -218,7 +219,7 @@ function getOnlinePaymentUrl($mode, $type, $ref='', $amount='9.99', $freetag='yo
     			}
     		}
     	}
    -	if ($type == 'member' || $type == 'membersubscription')
    +	elseif ($type == 'member' || $type == 'membersubscription')
     	{
     		$out=DOL_MAIN_URL_ROOT.'/public/payment/newpayment.php?source=membersubscription&ref='.($mode?'<font color="#666666">':'');
     		if ($mode == 1) $out.='member_ref';
    @@ -335,14 +336,14 @@ function htmlPrintOnlinePaymentFooter($fromcompany, $langs, $addformmessage=0, $
     
         	$parammessageform='ONLINE_PAYMENT_MESSAGE_FORM_'.$suffix;
         	if (! empty($conf->global->$parammessageform)) print $langs->transnoentities($conf->global->$parammessageform);
    -    	else if (! empty($conf->global->ONLINE_PAYMENT_MESSAGE_FORM)) print $langs->transnoentities($conf->global->ONLINE_PAYMENT_MESSAGE_FORM);
    +    	elseif (! empty($conf->global->ONLINE_PAYMENT_MESSAGE_FORM)) print $langs->transnoentities($conf->global->ONLINE_PAYMENT_MESSAGE_FORM);
     
         	// Add other message if VAT exists
         	if ($object->total_vat != 0 || $object->total_tva != 0)
         	{
         		$parammessageform='ONLINE_PAYMENT_MESSAGE_FORMIFVAT_'.$suffix;
         		if (! empty($conf->global->$parammessageform)) print $langs->transnoentities($conf->global->$parammessageform);
    -    		else if (! empty($conf->global->ONLINE_PAYMENT_MESSAGE_FORMIFVAT)) print $langs->transnoentities($conf->global->ONLINE_PAYMENT_MESSAGE_FORMIFVAT);
    +    		elseif (! empty($conf->global->ONLINE_PAYMENT_MESSAGE_FORMIFVAT)) print $langs->transnoentities($conf->global->ONLINE_PAYMENT_MESSAGE_FORMIFVAT);
         	}
         }
     
    diff --git a/htdocs/core/lib/pdf.lib.php b/htdocs/core/lib/pdf.lib.php
    index e112c0a279c..5b8a5d6d4c4 100644
    --- a/htdocs/core/lib/pdf.lib.php
    +++ b/htdocs/core/lib/pdf.lib.php
    @@ -1395,7 +1395,7 @@ function pdf_getlinedesc($object,$i,$outputlangs,$hideref=0,$hidedesc=0,$issuppl
     			if ($detail->eatby) $dte[]=$outputlangs->transnoentitiesnoconv('printEatby',dol_print_date($detail->eatby, $format, false, $outputlangs));
     			if ($detail->sellby) $dte[]=$outputlangs->transnoentitiesnoconv('printSellby',dol_print_date($detail->sellby, $format, false, $outputlangs));
     			if ($detail->batch) $dte[]=$outputlangs->transnoentitiesnoconv('printBatch',$detail->batch);
    -			$dte[]=$outputlangs->transnoentitiesnoconv('printQty',$detail->dluo_qty);
    +			$dte[]=$outputlangs->transnoentitiesnoconv('printQty',$detail->qty);
     			$libelleproduitservice.= "__N__  ".implode(" - ", $dte);
     		}
     	}
    diff --git a/htdocs/core/lib/sendings.lib.php b/htdocs/core/lib/sendings.lib.php
    index c01026b445d..38660cc272a 100644
    --- a/htdocs/core/lib/sendings.lib.php
    +++ b/htdocs/core/lib/sendings.lib.php
    @@ -364,7 +364,7 @@ function show_list_sending_receive($origin,$origin_id,$filter='')
     								$detail.= $langs->trans("Batch").': '.$dbatch->batch;
     								$detail.= ' - '.$langs->trans("SellByDate").': '.dol_print_date($dbatch->sellby,"day");
     								$detail.= ' - '.$langs->trans("EatByDate").': '.dol_print_date($dbatch->eatby,"day");
    -								$detail.= ' - '.$langs->trans("Qty").': '.$dbatch->dluo_qty;
    +								$detail.= ' - '.$langs->trans("Qty").': '.$dbatch->qty;
     								$detail.= '<br>';
     				            }
     				            print $form->textwithtooltip(img_picto('', 'object_barcode').' '.$langs->trans("DetailBatchNumber"),$detail);
    diff --git a/htdocs/core/lib/stock.lib.php b/htdocs/core/lib/stock.lib.php
    index ac59ab230c7..579944117ab 100644
    --- a/htdocs/core/lib/stock.lib.php
    +++ b/htdocs/core/lib/stock.lib.php
    @@ -39,7 +39,7 @@ function stock_prepare_head($object)
     	$head[$h][2] = 'card';
     	$h++;
     
    -	$head[$h][0] = DOL_URL_ROOT.'/product/stock/mouvement.php?id='.$object->id;
    +	$head[$h][0] = DOL_URL_ROOT.'/product/stock/movement_list.php?id='.$object->id;
     	$head[$h][1] = $langs->trans("StockMovements");
     	$head[$h][2] = 'movements';
     	$h++;
    diff --git a/htdocs/core/lib/website.lib.php b/htdocs/core/lib/website.lib.php
    index 9f848fb68ee..350014b3eb9 100644
    --- a/htdocs/core/lib/website.lib.php
    +++ b/htdocs/core/lib/website.lib.php
    @@ -305,9 +305,9 @@ function redirectToContainer($containerref, $containeraliasalt='',$containerid=0
      */
     function includeContainer($containerref)
     {
    -	global $conf, $db, $hookmanager, $langs, $mysoc, $user, $website, $weblangs;	// Very important. Required to have var available when running inluded containers.
    +	global $conf, $db, $hookmanager, $langs, $mysoc, $user, $website, $websitepage, $weblangs;	// Very important. Required to have var available when running inluded containers.
     	global $includehtmlcontentopened;
    -	global $websitekey;
    +	global $websitekey, $websitepagefile;
     
     	$MAXLEVEL=20;
     
    @@ -607,7 +607,7 @@ function dolSavePageContent($filetpl, $object, $objectpage)
     
     	$tplcontent ='';
     	$tplcontent.= "<?php // BEGIN PHP\n";
    -	$tplcontent.= '$websitekey=basename(dirname(__FILE__));'."\n";
    +	$tplcontent.= '$websitekey=basename(dirname(__FILE__)); if (empty($websitepagefile)) $websitepagefile=__FILE__;'."\n";
     	$tplcontent.= "if (! defined('USEDOLIBARRSERVER') && ! defined('USEDOLIBARREDITOR')) { require_once './master.inc.php'; } // Not already loaded"."\n";
     	$tplcontent.= "require_once DOL_DOCUMENT_ROOT.'/core/lib/website.lib.php';\n";
     	$tplcontent.= "require_once DOL_DOCUMENT_ROOT.'/core/website.inc.php';\n";
    @@ -624,6 +624,7 @@ function dolSavePageContent($filetpl, $object, $objectpage)
     	$tplcontent.= '<meta name="title" content="'.dol_string_nohtmltag($objectpage->title, 0, 'UTF-8').'" />'."\n";
     	$tplcontent.= '<meta name="description" content="'.dol_string_nohtmltag($objectpage->description, 0, 'UTF-8').'" />'."\n";
     	$tplcontent.= '<meta name="generator" content="'.DOL_APPLICATION_TITLE.' '.DOL_VERSION.' (https://www.dolibarr.org)" />'."\n";
    +	$tplcontent.= '<link href="/'.(($objectpage->id == $object->fk_default_home) ? '' : ($objectpage->pageurl.'.php')).'" rel="canonical" />'."\n";
     	$tplcontent.= '<!-- Include link to CSS file -->'."\n";
     	$tplcontent.= '<link rel="stylesheet" href="styles.css.php?website=<?php echo $websitekey; ?>" type="text/css" />'."\n";
     	$tplcontent.= '<!-- Include HTML header from common file -->'."\n";
    @@ -672,7 +673,7 @@ function dolSaveIndexPage($pathofwebsite, $fileindex, $filetpl, $filewrapper)
     	dol_delete_file($fileindex);
     	$indexcontent = '<?php'."\n";
     	$indexcontent.= "// BEGIN PHP File generated to provide an index.php as Home Page or alias redirector - DO NOT MODIFY - It is just a generated wrapper.\n";
    -	$indexcontent.= '$websitekey=basename(dirname(__FILE__));'."\n";
    +	$indexcontent.= '$websitekey=basename(dirname(__FILE__)); if (empty($websitepagefile)) $websitepagefile=__FILE__;'."\n";
     	$indexcontent.= "if (! defined('USEDOLIBARRSERVER') && ! defined('USEDOLIBARREDITOR')) { require_once './master.inc.php'; } // Load master if not already loaded\n";
     	$indexcontent.= 'if (! empty($_GET[\'pageref\']) || ! empty($_GET[\'pagealiasalt\']) || ! empty($_GET[\'pageid\'])) {'."\n";
     	$indexcontent.= "	require_once DOL_DOCUMENT_ROOT.'/core/lib/website.lib.php';\n";
    diff --git a/htdocs/core/login/functions_openid.php b/htdocs/core/login/functions_openid.php
    index 83543c43dd5..79cf1a09cb9 100644
    --- a/htdocs/core/login/functions_openid.php
    +++ b/htdocs/core/login/functions_openid.php
    @@ -70,7 +70,7 @@ function check_user_password_openid($usertotest,$passwordtotest,$entitytotest)
             $openid = new SimpleOpenID();
             $openid->SetIdentity($_GET['openid_identity']);
             $openid_validation_result = $openid->ValidateWithServer();
    -        if ($openid_validation_result == true)
    +        if ($openid_validation_result === true)
             {
                 // OK HERE KEY IS VALID
     
    @@ -90,7 +90,7 @@ function check_user_password_openid($usertotest,$passwordtotest,$entitytotest)
                     }
                 }
             }
    -        else if($openid->IsError() == true)
    +        else if($openid->IsError() === true)
             {
                 // ON THE WAY, WE GOT SOME ERROR
                 $error = $openid->GetError();
    diff --git a/htdocs/core/menus/init_menu_auguria.sql b/htdocs/core/menus/init_menu_auguria.sql
    index 806960aaa34..682746b3412 100644
    --- a/htdocs/core/menus/init_menu_auguria.sql
    +++ b/htdocs/core/menus/init_menu_auguria.sql
    @@ -63,10 +63,16 @@ insert into llx_menu (module, enabled, menu_handler, type, rowid, mainmenu, left
     insert into llx_menu (module, enabled, menu_handler, type, rowid, mainmenu, leftmenu, fk_menu, url, titre, level, langs, perms, target, usertype, position, entity) values ('', '$leftmenu=="admintools"', __HANDLER__, 'left', 320__+MAX_llx_menu__, 'home', '', 300__+MAX_llx_menu__, '/product/admin/product_tools.php?mainmenu=home&amp;leftmenu=admintools', 'ProductVatMassChange', 1, 'products', '', '', 2, 15, __ENTITY__);
     -- Home - Menu users and groups
     insert into llx_menu (module, enabled, menu_handler, type, rowid, mainmenu, leftmenu, fk_menu, url, titre, level, langs, perms, target, usertype, position, entity) values ('', '1', __HANDLER__, 'left', 400__+MAX_llx_menu__, 'home', 'users', 1__+MAX_llx_menu__, '/user/home.php?leftmenu=users', 'MenuUsersAndGroups', 0, 'users', '', '', 2, 4, __ENTITY__);
    +
     insert into llx_menu (module, enabled, menu_handler, type, rowid, mainmenu, leftmenu, fk_menu, url, titre, level, langs, perms, target, usertype, position, entity) values ('', '$leftmenu=="users"', __HANDLER__, 'left', 401__+MAX_llx_menu__, 'home', '', 400__+MAX_llx_menu__, '/user/list.php?leftmenu=users', 'Users', 1, 'users', '$user->rights->user->user->lire || $user->admin', '', 2, 0, __ENTITY__);
     insert into llx_menu (module, enabled, menu_handler, type, rowid, mainmenu, leftmenu, fk_menu, url, titre, level, langs, perms, target, usertype, position, entity) values ('', '$leftmenu=="users"', __HANDLER__, 'left', 402__+MAX_llx_menu__, 'home', '', 401__+MAX_llx_menu__, '/user/card.php?leftmenu=users&amp;action=create', 'NewUser', 2, 'users', '($user->rights->user->user->creer || $user->admin) && !(! empty($conf->multicompany->enabled) && $conf->entity > 1 && $conf->global->MULTICOMPANY_TRANSVERSE_MODE)', '', 2, 0, __ENTITY__);
    -insert into llx_menu (module, enabled, menu_handler, type, rowid, mainmenu, leftmenu, fk_menu, url, titre, level, langs, perms, target, usertype, position, entity) values ('', '$leftmenu=="users"', __HANDLER__, 'left', 403__+MAX_llx_menu__, 'home', '', 400__+MAX_llx_menu__, '/user/group/list.php?leftmenu=users', 'Groups', 1, 'users', '(($conf->global->MAIN_USE_ADVANCED_PERMS?$user->rights->user->group_advance->read:$user->rights->user->user->lire) || $user->admin) && !(! empty($conf->multicompany->enabled) && $conf->entity > 1 && $conf->global->MULTICOMPANY_TRANSVERSE_MODE)', '', 2, 1, __ENTITY__);
    -insert into llx_menu (module, enabled, menu_handler, type, rowid, mainmenu, leftmenu, fk_menu, url, titre, level, langs, perms, target, usertype, position, entity) values ('', '$leftmenu=="users"', __HANDLER__, 'left', 404__+MAX_llx_menu__, 'home', '', 403__+MAX_llx_menu__, '/user/group/card.php?leftmenu=users&amp;action=create', 'NewGroup', 2, 'users', '(($conf->global->MAIN_USE_ADVANCED_PERMS?$user->rights->user->group_advance->write:$user->rights->user->user->creer) || $user->admin) && !(! empty($conf->multicompany->enabled) && $conf->entity > 1 && $conf->global->MULTICOMPANY_TRANSVERSE_MODE)', '', 2, 0, __ENTITY__);
    +
    +insert into llx_menu (module, enabled, menu_handler, type, rowid, mainmenu, leftmenu, fk_menu, url, titre, level, langs, perms, target, usertype, position, entity) values ('', '$leftmenu=="users"', __HANDLER__, 'left', 404__+MAX_llx_menu__, 'home', '', 401__+MAX_llx_menu__, '/user/hierarchy.php?leftmenu=users', 'HierarchicView', 1, 'users', '$user->rights->user->user->lire || $user->admin', '', 2, 0, __ENTITY__);
    +insert into llx_menu (module, enabled, menu_handler, type, rowid, mainmenu, leftmenu, fk_menu, url, titre, level, langs, perms, target, usertype, position, entity) values ('', '$leftmenu=="users"', __HANDLER__, 'left', 405__+MAX_llx_menu__, 'home', '', 401__+MAX_llx_menu__, '/categories/index.php?leftmenu=users&type=7', 'UsersCategoriesShort', 1, 'categories', '$user->rights->user->user->lire || $user->admin', '', 2, 0, __ENTITY__);
    +
    +insert into llx_menu (module, enabled, menu_handler, type, rowid, mainmenu, leftmenu, fk_menu, url, titre, level, langs, perms, target, usertype, position, entity) values ('', '$leftmenu=="users"', __HANDLER__, 'left', 407__+MAX_llx_menu__, 'home', '', 400__+MAX_llx_menu__, '/user/group/list.php?leftmenu=users', 'Groups', 1, 'users', '(($conf->global->MAIN_USE_ADVANCED_PERMS?$user->rights->user->group_advance->read:$user->rights->user->user->lire) || $user->admin) && !(! empty($conf->multicompany->enabled) && $conf->entity > 1 && $conf->global->MULTICOMPANY_TRANSVERSE_MODE)', '', 2, 1, __ENTITY__);
    +insert into llx_menu (module, enabled, menu_handler, type, rowid, mainmenu, leftmenu, fk_menu, url, titre, level, langs, perms, target, usertype, position, entity) values ('', '$leftmenu=="users"', __HANDLER__, 'left', 408__+MAX_llx_menu__, 'home', '', 407__+MAX_llx_menu__, '/user/group/card.php?leftmenu=users&amp;action=create', 'NewGroup', 2, 'users', '(($conf->global->MAIN_USE_ADVANCED_PERMS?$user->rights->user->group_advance->write:$user->rights->user->user->creer) || $user->admin) && !(! empty($conf->multicompany->enabled) && $conf->entity > 1 && $conf->global->MULTICOMPANY_TRANSVERSE_MODE)', '', 2, 0, __ENTITY__);
    +
     -- Third parties
     insert into llx_menu (module, enabled, menu_handler, type, rowid, mainmenu, leftmenu, fk_menu, url, titre, level, langs, perms, target, usertype, position, entity) values ('', '$conf->societe->enabled', __HANDLER__, 'left', 500__+MAX_llx_menu__, 'companies', 'thirdparties', 2__+MAX_llx_menu__, '/societe/index.php?leftmenu=thirdparties', 'ThirdParty', 0, 'companies', '$user->rights->societe->lire', '', 2, 0, __ENTITY__);
     insert into llx_menu (module, enabled, menu_handler, type, rowid, mainmenu, leftmenu, fk_menu, url, titre, level, langs, perms, target, usertype, position, entity) values ('', '$conf->societe->enabled', __HANDLER__, 'left', 501__+MAX_llx_menu__, 'companies', '', 500__+MAX_llx_menu__, '/societe/card.php?action=create', 'MenuNewThirdParty', 1, 'companies', '$user->rights->societe->lire', '', 2, 0, __ENTITY__);
    @@ -114,7 +120,7 @@ insert into llx_menu (module, enabled, menu_handler, type, rowid, mainmenu, left
     insert into llx_menu (module, enabled, menu_handler, type, rowid, mainmenu, leftmenu, fk_menu, url, titre, level, langs, perms, target, usertype, position, entity) values ('', '$conf->stock->enabled', __HANDLER__, 'left', 3100__+MAX_llx_menu__, 'products', 'stock', 3__+MAX_llx_menu__, '/product/stock/index.php?leftmenu=stock', 'Stock', 0, 'stocks', '$user->rights->stock->lire', '', 2, 3, __ENTITY__);
     insert into llx_menu (module, enabled, menu_handler, type, rowid, mainmenu, leftmenu, fk_menu, url, titre, level, langs, perms, target, usertype, position, entity) values ('', '$conf->stock->enabled', __HANDLER__, 'left', 3101__+MAX_llx_menu__, 'products', '', 3100__+MAX_llx_menu__, '/product/stock/card.php?action=create', 'MenuNewWarehouse', 1, 'stocks', '$user->rights->stock->creer', '', 2, 0, __ENTITY__);
     insert into llx_menu (module, enabled, menu_handler, type, rowid, mainmenu, leftmenu, fk_menu, url, titre, level, langs, perms, target, usertype, position, entity) values ('', '$conf->stock->enabled', __HANDLER__, 'left', 3102__+MAX_llx_menu__, 'products', '', 3100__+MAX_llx_menu__, '/product/stock/list.php', 'List', 1, 'stocks', '$user->rights->stock->lire', '', 2, 1, __ENTITY__);
    -insert into llx_menu (module, enabled, menu_handler, type, rowid, mainmenu, leftmenu, fk_menu, url, titre, level, langs, perms, target, usertype, position, entity) values ('', '$conf->stock->enabled', __HANDLER__, 'left', 3104__+MAX_llx_menu__, 'products', '', 3100__+MAX_llx_menu__, '/product/stock/mouvement.php', 'Movements', 1, 'stocks', '$user->rights->stock->mouvement->lire', '', 2, 3, __ENTITY__);
    +insert into llx_menu (module, enabled, menu_handler, type, rowid, mainmenu, leftmenu, fk_menu, url, titre, level, langs, perms, target, usertype, position, entity) values ('', '$conf->stock->enabled', __HANDLER__, 'left', 3104__+MAX_llx_menu__, 'products', '', 3100__+MAX_llx_menu__, '/product/stock/movement_list.php', 'Movements', 1, 'stocks', '$user->rights->stock->mouvement->lire', '', 2, 3, __ENTITY__);
     insert into llx_menu (module, enabled, menu_handler, type, rowid, mainmenu, leftmenu, fk_menu, url, titre, level, langs, perms, target, usertype, position, entity) values ('', '$conf->stock->enabled && $conf->supplier_order->enabled', __HANDLER__, 'left', 3105__+MAX_llx_menu__, 'products', '', 3100__+MAX_llx_menu__, '/product/stock/replenish.php', 'Replenishments', 1, 'stocks', '$user->rights->stock->mouvement->creer && $user->rights->fournisseur->lire', '', 2, 4, __ENTITY__);
     insert into llx_menu (module, enabled, menu_handler, type, rowid, mainmenu, leftmenu, fk_menu, url, titre, level, langs, perms, target, usertype, position, entity) values ('', '$conf->stock->enabled', __HANDLER__, 'left', 3106__+MAX_llx_menu__, 'products', '', 3100__+MAX_llx_menu__, '/product/stock/massstockmove.php', 'MassStockTransferShort', 1, 'stocks', '$user->rights->stock->mouvement->creer', '', 2, 5, __ENTITY__);
     
    diff --git a/htdocs/core/menus/standard/eldy.lib.php b/htdocs/core/menus/standard/eldy.lib.php
    index 3a7e6ae784b..562ed99a020 100644
    --- a/htdocs/core/menus/standard/eldy.lib.php
    +++ b/htdocs/core/menus/standard/eldy.lib.php
    @@ -616,6 +616,11 @@ function print_left_eldy_menu($db,$menu_array_before,$menu_array_after,&$tabMenu
     					$newmenu->add("/user/card.php?leftmenu=users&action=create", $langs->trans("NewUser"),2, ($user->rights->user->user->creer || $user->admin) && !(! empty($conf->multicompany->enabled) && $conf->entity > 1 && $conf->global->MULTICOMPANY_TRANSVERSE_MODE), '', 'home');
     					$newmenu->add("/user/list.php?leftmenu=users", $langs->trans("ListOfUsers"), 2, $user->rights->user->user->lire || $user->admin);
     					$newmenu->add("/user/hierarchy.php?leftmenu=users", $langs->trans("HierarchicView"), 2, $user->rights->user->user->lire || $user->admin);
    +					if (! empty($conf->categorie->enabled))
    +					{
    +						$langs->load("categories");
    +						$newmenu->add("/categories/index.php?leftmenu=users&type=7", $langs->trans("UsersCategoriesShort"), 2, $user->rights->categorie->lire, '', $mainmenu, 'cat');
    +					}
     					$newmenu->add("", $langs->trans("Groups"), 1, ($user->rights->user->user->lire || $user->admin) && !(! empty($conf->multicompany->enabled) && $conf->entity > 1 && $conf->global->MULTICOMPANY_TRANSVERSE_MODE));
     					$newmenu->add("/user/group/card.php?leftmenu=users&action=create", $langs->trans("NewGroup"), 2, (($conf->global->MAIN_USE_ADVANCED_PERMS?$user->rights->user->group_advance->write:$user->rights->user->user->creer) || $user->admin) && !(! empty($conf->multicompany->enabled) && $conf->entity > 1 && $conf->global->MULTICOMPANY_TRANSVERSE_MODE));
     					$newmenu->add("/user/group/list.php?leftmenu=users", $langs->trans("ListOfGroups"), 2, (($conf->global->MAIN_USE_ADVANCED_PERMS?$user->rights->user->group_advance->read:$user->rights->user->user->lire) || $user->admin) && !(! empty($conf->multicompany->enabled) && $conf->entity > 1 && $conf->global->MULTICOMPANY_TRANSVERSE_MODE));
    @@ -679,6 +684,25 @@ function print_left_eldy_menu($db,$menu_array_before,$menu_array_after,&$tabMenu
     				$newmenu->add("/societe/card.php?leftmenu=suppliers&amp;action=create&amp;type=f",$langs->trans("MenuNewSupplier"), 2, $user->rights->societe->creer && ($user->rights->fournisseur->lire || $user->rights->supplier_proposal->lire));
     			}
     
    +			// Categories
    +			if (! empty($conf->categorie->enabled))
    +			{
    +				$langs->load("categories");
    +				if (empty($conf->global->SOCIETE_DISABLE_PROSPECTS) || empty($conf->global->SOCIETE_DISABLE_CUSTOMERS))
    +				{
    +					// Categories prospects/customers
    +					$menutoshow=$langs->trans("CustomersProspectsCategoriesShort");
    +					if (! empty($conf->global->SOCIETE_DISABLE_PROSPECTS)) $menutoshow=$langs->trans("CustomersCategoriesShort");
    +					if (! empty($conf->global->SOCIETE_DISABLE_CUSTOMERS)) $menutoshow=$langs->trans("ProspectsCategoriesShort");
    +					$newmenu->add("/categories/index.php?leftmenu=cat&amp;type=2", $menutoshow, 1, $user->rights->categorie->lire, '', $mainmenu, 'cat');
    +				}
    +				// Categories suppliers
    +				if (! empty($conf->fournisseur->enabled))
    +				{
    +					$newmenu->add("/categories/index.php?leftmenu=catfournish&amp;type=1", $langs->trans("SuppliersCategoriesShort"), 1, $user->rights->categorie->lire);
    +				}
    +			}
    +
     			// Contacts
     			$newmenu->add("/societe/index.php?leftmenu=thirdparties", (! empty($conf->global->SOCIETE_ADDRESSES_MANAGEMENT) ? $langs->trans("Contacts") : $langs->trans("ContactsAddresses")), 0, $user->rights->societe->contact->lire, '', $mainmenu, 'contacts');
     			$newmenu->add("/contact/card.php?leftmenu=contacts&amp;action=create", (! empty($conf->global->SOCIETE_ADDRESSES_MANAGEMENT) ? $langs->trans("NewContact") : $langs->trans("NewContactAddress")), 1, $user->rights->societe->contact->creer);
    @@ -693,25 +717,8 @@ function print_left_eldy_menu($db,$menu_array_before,$menu_array_after,&$tabMenu
     			if (! empty($conf->categorie->enabled))
     			{
     				$langs->load("categories");
    -				if (empty($conf->global->SOCIETE_DISABLE_PROSPECTS) || empty($conf->global->SOCIETE_DISABLE_CUSTOMERS))
    -				{
    -					// Categories prospects/customers
    -				    $menutoshow=$langs->trans("CustomersProspectsCategoriesShort");
    -				    if (! empty($conf->global->SOCIETE_DISABLE_PROSPECTS)) $menutoshow=$langs->trans("CustomersCategoriesShort");
    -				    if (! empty($conf->global->SOCIETE_DISABLE_CUSTOMERS)) $menutoshow=$langs->trans("ProspectsCategoriesShort");
    -					$newmenu->add("/categories/index.php?leftmenu=cat&amp;type=2", $menutoshow, 0, $user->rights->categorie->lire, '', $mainmenu, 'cat');
    -				    $newmenu->add("/categories/card.php?action=create&amp;type=2", $langs->trans("NewCategory"), 1, $user->rights->categorie->creer);
    -				}
     				// Categories Contact
    -				$newmenu->add("/categories/index.php?leftmenu=catcontact&amp;type=4", $langs->trans("ContactCategoriesShort"), 0, $user->rights->categorie->lire, '', $mainmenu, 'cat');
    -				$newmenu->add("/categories/card.php?action=create&amp;type=4", $langs->trans("NewCategory"), 1, $user->rights->categorie->creer);
    -				// Categories suppliers
    -				if (! empty($conf->fournisseur->enabled))
    -				{
    -					$newmenu->add("/categories/index.php?leftmenu=catfournish&amp;type=1", $langs->trans("SuppliersCategoriesShort"), 0, $user->rights->categorie->lire);
    -					$newmenu->add("/categories/card.php?action=create&amp;type=1", $langs->trans("NewCategory"), 1, $user->rights->categorie->creer);
    -				}
    -				//if ($usemenuhider || empty($leftmenu) || $leftmenu=="cat") $newmenu->add("/categories/list.php", $langs->trans("List"), 1, $user->rights->categorie->lire);
    +				$newmenu->add("/categories/index.php?leftmenu=catcontact&amp;type=4", $langs->trans("ContactCategoriesShort"), 1, $user->rights->categorie->lire, '', $mainmenu, 'cat');
     			}
     		}
     
    @@ -1206,10 +1213,8 @@ function print_left_eldy_menu($db,$menu_array_before,$menu_array_after,&$tabMenu
     
                 if (! empty($conf->categorie->enabled)) {
                     $langs->load("categories");
    -                $newmenu->add("/categories/index.php?type=5",$langs->trans("Rubriques"),0,$user->rights->categorie->creer, '', $mainmenu, 'tags');
    -                $newmenu->add("/categories/card.php?action=create&amp;type=5",$langs->trans("NewCategory"),1,$user->rights->categorie->creer);
    -                $newmenu->add("/compta/bank/categ.php",$langs->trans("RubriquesTransactions"),0,$user->rights->categorie->creer, '', $mainmenu, 'tags');
    -                $newmenu->add("/compta/bank/categ.php",$langs->trans("NewCategory"),1,$user->rights->categorie->creer, '', $mainmenu, 'tags');
    +                $newmenu->add("/categories/index.php?type=5",$langs->trans("Rubriques"),1,$user->rights->categorie->creer, '', $mainmenu, 'tags');
    +                $newmenu->add("/compta/bank/categ.php",$langs->trans("RubriquesTransactions"),1,$user->rights->categorie->creer, '', $mainmenu, 'tags');
     	    }
     
     			// Prelevements
    @@ -1269,6 +1274,14 @@ function print_left_eldy_menu($db,$menu_array_before,$menu_array_after,&$tabMenu
     				{
     					$newmenu->add("/product/stats/card.php?id=all&leftmenu=stats&type=0", $langs->trans("Statistics"), 1, $user->rights->produit->lire && $user->rights->propale->lire);
     				}
    +
    +				// Categories
    +				if (! empty($conf->categorie->enabled))
    +				{
    +					$langs->load("categories");
    +					$newmenu->add("/categories/index.php?leftmenu=cat&amp;type=0", $langs->trans("Categories"), 1, $user->rights->categorie->lire, '', $mainmenu, 'cat');
    +					//if ($usemenuhider || empty($leftmenu) || $leftmenu=="cat") $newmenu->add("/categories/list.php", $langs->trans("List"), 1, $user->rights->categorie->lire);
    +				}
     			}
     
     			// Services
    @@ -1281,15 +1294,13 @@ function print_left_eldy_menu($db,$menu_array_before,$menu_array_after,&$tabMenu
     				{
     					$newmenu->add("/product/stats/card.php?id=all&leftmenu=stats&type=1", $langs->trans("Statistics"), 1, $user->rights->service->lire && $user->rights->propale->lire);
     				}
    -			}
    -
    -			// Categories
    -			if (! empty($conf->categorie->enabled))
    -			{
    -				$langs->load("categories");
    -				$newmenu->add("/categories/index.php?leftmenu=cat&amp;type=0", $langs->trans("Categories"), 0, $user->rights->categorie->lire, '', $mainmenu, 'cat');
    -				$newmenu->add("/categories/card.php?action=create&amp;type=0", $langs->trans("NewCategory"), 1, $user->rights->categorie->creer);
    -				//if ($usemenuhider || empty($leftmenu) || $leftmenu=="cat") $newmenu->add("/categories/list.php", $langs->trans("List"), 1, $user->rights->categorie->lire);
    +				// Categories
    +				if (! empty($conf->categorie->enabled))
    +				{
    +					$langs->load("categories");
    +					$newmenu->add("/categories/index.php?leftmenu=cat&amp;type=0", $langs->trans("Categories"), 1, $user->rights->categorie->lire, '', $mainmenu, 'cat');
    +					//if ($usemenuhider || empty($leftmenu) || $leftmenu=="cat") $newmenu->add("/categories/list.php", $langs->trans("List"), 1, $user->rights->categorie->lire);
    +				}
     			}
     
     			// Warehouse
    @@ -1299,7 +1310,7 @@ function print_left_eldy_menu($db,$menu_array_before,$menu_array_after,&$tabMenu
     				$newmenu->add("/product/stock/index.php?leftmenu=stock", $langs->trans("Warehouses"), 0, $user->rights->stock->lire, '', $mainmenu, 'stock');
     				$newmenu->add("/product/stock/card.php?action=create", $langs->trans("MenuNewWarehouse"), 1, $user->rights->stock->creer);
     				$newmenu->add("/product/stock/list.php", $langs->trans("List"), 1, $user->rights->stock->lire);
    -				$newmenu->add("/product/stock/mouvement.php", $langs->trans("Movements"), 1, $user->rights->stock->mouvement->lire);
    +				$newmenu->add("/product/stock/movement_list.php", $langs->trans("Movements"), 1, $user->rights->stock->mouvement->lire);
     
                     $newmenu->add("/product/stock/massstockmove.php", $langs->trans("MassStockTransferShort"), 1, $user->rights->stock->mouvement->creer);
                     if ($conf->supplier_order->enabled) $newmenu->add("/product/stock/replenish.php", $langs->trans("Replenishment"), 1, $user->rights->stock->mouvement->creer && $user->rights->fournisseur->lire);
    @@ -1405,9 +1416,7 @@ function print_left_eldy_menu($db,$menu_array_before,$menu_array_after,&$tabMenu
     				if (! empty($conf->categorie->enabled))
     				{
     					$langs->load("categories");
    -					$newmenu->add("/categories/index.php?leftmenu=cat&amp;type=6", $langs->trans("Categories"), 0, $user->rights->categorie->lire, '', $mainmenu, 'cat');
    -					$newmenu->add("/categories/card.php?action=create&amp;type=6", $langs->trans("NewCategory"), 1, $user->rights->categorie->creer);
    -					//if ($usemenuhider || empty($leftmenu) || $leftmenu=="cat") $newmenu->add("/categories/list.php", $langs->trans("List"), 1, $user->rights->categorie->lire);
    +					$newmenu->add("/categories/index.php?leftmenu=cat&amp;type=6", $langs->trans("Categories"), 1, $user->rights->categorie->lire, '', $mainmenu, 'cat');
     				}
     			}
     		}
    @@ -1539,23 +1548,21 @@ function print_left_eldy_menu($db,$menu_array_before,$menu_array_after,&$tabMenu
     				$newmenu->add("/adherents/list.php?leftmenu=members&amp;statut=1&amp;filter=outofdate",$langs->trans("MenuMembersNotUpToDate"),2,$user->rights->adherent->lire);
     				$newmenu->add("/adherents/list.php?leftmenu=members&amp;statut=0",$langs->trans("MenuMembersResiliated"),2,$user->rights->adherent->lire);
     				$newmenu->add("/adherents/stats/index.php?leftmenu=members",$langs->trans("MenuMembersStats"),1,$user->rights->adherent->lire);
    -				if (! empty($conf->global->MEMBER_LINK_TO_HTPASSWDFILE) && ($usemenuhider || empty($leftmenu) || $leftmenu=='none' || $leftmenu=="members" || $leftmenu=="export")) $newmenu->add("/adherents/htpasswd.php?leftmenu=export",$langs->trans("Filehtpasswd"),1,$user->rights->adherent->export);
    +
     				$newmenu->add("/adherents/cartes/carte.php?leftmenu=export",$langs->trans("MembersCards"),1,$user->rights->adherent->export);
    +				if (! empty($conf->global->MEMBER_LINK_TO_HTPASSWDFILE) && ($usemenuhider || empty($leftmenu) || $leftmenu=='none' || $leftmenu=="members" || $leftmenu=="export")) $newmenu->add("/adherents/htpasswd.php?leftmenu=export",$langs->trans("Filehtpasswd"),1,$user->rights->adherent->export);
    +
    +				if (! empty($conf->categorie->enabled))
    +				{
    +					$langs->load("categories");
    +					$newmenu->add("/categories/index.php?leftmenu=cat&amp;type=3", $langs->trans("Categories"), 1, $user->rights->categorie->lire, '', $mainmenu, 'cat');
    +				}
     
     				$newmenu->add("/adherents/index.php?leftmenu=members&amp;mainmenu=members",$langs->trans("Subscriptions"),0,$user->rights->adherent->cotisation->lire);
     				$newmenu->add("/adherents/list.php?leftmenu=members&amp;statut=-1,1&amp;mainmenu=members",$langs->trans("NewSubscription"),1,$user->rights->adherent->cotisation->creer);
     				$newmenu->add("/adherents/subscription/list.php?leftmenu=members",$langs->trans("List"),1,$user->rights->adherent->cotisation->lire);
     				$newmenu->add("/adherents/stats/index.php?leftmenu=members",$langs->trans("MenuMembersStats"),1,$user->rights->adherent->lire);
     
    -
    -				if (! empty($conf->categorie->enabled))
    -				{
    -					$langs->load("categories");
    -					$newmenu->add("/categories/index.php?leftmenu=cat&amp;type=3", $langs->trans("Categories"), 0, $user->rights->categorie->lire, '', $mainmenu, 'cat');
    -					$newmenu->add("/categories/card.php?action=create&amp;type=3", $langs->trans("NewCategory"), 1, $user->rights->categorie->creer);
    -					//if ($usemenuhider || empty($leftmenu) || $leftmenu=="cat") $newmenu->add("/categories/list.php", $langs->trans("List"), 1, $user->rights->categorie->lire);
    -				}
    -
     				//$newmenu->add("/adherents/index.php?leftmenu=export&amp;mainmenu=members",$langs->trans("Tools"),0,$user->rights->adherent->export, '', $mainmenu, 'export');
     				//if (! empty($conf->export->enabled) && ($usemenuhider || empty($leftmenu) || $leftmenu=="export")) $newmenu->add("/exports/index.php?leftmenu=export",$langs->trans("Datas"),1,$user->rights->adherent->export);
     
    diff --git a/htdocs/core/modules/commande/doc/doc_generic_order_odt.modules.php b/htdocs/core/modules/commande/doc/doc_generic_order_odt.modules.php
    index 3839edb85c1..dff597c5593 100644
    --- a/htdocs/core/modules/commande/doc/doc_generic_order_odt.modules.php
    +++ b/htdocs/core/modules/commande/doc/doc_generic_order_odt.modules.php
    @@ -4,21 +4,22 @@
      * Copyright (C) 2014		Marcos García		<marcosgdf@gmail.com>
      * Copyright (C) 2016		Charlie Benke		<charlie@patas-monkey.com>
      * Copyright (C) 2018       Philippe Grand      <philippe.grand@atoo-net.com>
    -*
    -* This program is free software; you can redistribute it and/or modify
    -* it under the terms of the GNU General Public License as published by
    -* the Free Software Foundation; either version 3 of the License, or
    -* (at your option) any later version.
    -*
    -* This program is distributed in the hope that it will be useful,
    -* but WITHOUT ANY WARRANTY; without even the implied warranty of
    -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    -* GNU General Public License for more details.
    -*
    -* You should have received a copy of the GNU General Public License
    -* along with this program. If not, see <http://www.gnu.org/licenses/>.
    -* or see http://www.gnu.org/
    -*/
    + * Copyright (C) 2018       Frédéric France     <frederic.france@netlogic.fr>
    + *
    + * This program is free software; you can redistribute it and/or modify
    + * it under the terms of the GNU General Public License as published by
    + * the Free Software Foundation; either version 3 of the License, or
    + * (at your option) any later version.
    + *
    + * This program is distributed in the hope that it will be useful,
    + * but WITHOUT ANY WARRANTY; without even the implied warranty of
    + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    + * GNU General Public License for more details.
    + *
    + * You should have received a copy of the GNU General Public License
    + * along with this program. If not, see <http://www.gnu.org/licenses/>.
    + * or see http://www.gnu.org/
    + */
     
     /**
      *	\file       htdocs/core/modules/commande/doc/doc_generic_order_odt.modules.php
    @@ -46,7 +47,7 @@ class doc_generic_order_odt extends ModelePDFCommandes
     	public $emetteur;
     
     	/**
    -   * @var array() Minimum version of PHP required by module.
    +   * @var array Minimum version of PHP required by module.
     	 * e.g.: PHP ≥ 5.4 = array(5, 4)
        */
     	public $phpmin = array(5, 4);
    @@ -351,6 +352,7 @@ class doc_generic_order_odt extends ModelePDFCommandes
     				catch(Exception $e)
     				{
     					$this->error=$e->getMessage();
    +					dol_syslog($e->getMessage(), LOG_INFO);
     					return -1;
     				}
     				// After construction $odfHandler->contentXml contains content and
    @@ -366,6 +368,7 @@ class doc_generic_order_odt extends ModelePDFCommandes
     				}
     				catch(OdfException $e)
     				{
    +                    dol_syslog($e->getMessage(), LOG_INFO);
     				}
     
     				// Define substitution array
    @@ -402,6 +405,7 @@ class doc_generic_order_odt extends ModelePDFCommandes
     					}
     					catch(OdfException $e)
     					{
    +                        dol_syslog($e->getMessage(), LOG_INFO);
     					}
     				}
     				// Replace tags of lines
    @@ -434,9 +438,11 @@ class doc_generic_order_odt extends ModelePDFCommandes
     								}
     								catch(OdfException $e)
     								{
    +                                    dol_syslog($e->getMessage(), LOG_INFO);
     								}
     								catch(SegmentException $e)
     								{
    +                                    dol_syslog($e->getMessage(), LOG_INFO);
     								}
     							}
     							$listlines->merge();
    @@ -460,6 +466,7 @@ class doc_generic_order_odt extends ModelePDFCommandes
     					}
     					catch(OdfException $e)
     					{
    +                        dol_syslog($e->getMessage(), LOG_INFO);
     					}
     				}
     
    @@ -473,7 +480,8 @@ class doc_generic_order_odt extends ModelePDFCommandes
     					try {
     						$odfHandler->exportAsAttachedPDF($file);
     					}catch (Exception $e){
    -						$this->error=$e->getMessage();
    +                        $this->error=$e->getMessage();
    +                        dol_syslog($e->getMessage(), LOG_INFO);
     						return -1;
     					}
     				}
    @@ -481,7 +489,8 @@ class doc_generic_order_odt extends ModelePDFCommandes
     					try {
     					$odfHandler->saveToDisk($file);
     					}catch (Exception $e){
    -						$this->error=$e->getMessage();
    +                        $this->error=$e->getMessage();
    +                        dol_syslog($e->getMessage(), LOG_INFO);
     						return -1;
     					}
     				}
    diff --git a/htdocs/core/modules/commande/doc/pdf_einstein.modules.php b/htdocs/core/modules/commande/doc/pdf_einstein.modules.php
    index d3b5d12d620..ad77e9bea32 100644
    --- a/htdocs/core/modules/commande/doc/pdf_einstein.modules.php
    +++ b/htdocs/core/modules/commande/doc/pdf_einstein.modules.php
    @@ -27,7 +27,7 @@
     /**
      *	\file       htdocs/core/modules/commande/doc/pdf_einstein.modules.php
      *	\ingroup    commande
    - *	\brief      Fichier de la classe permettant de generer les commandes au modele Einstein
    + *	\brief      File of Class to generate PDF orders with template Einstein
      */
     
     require_once DOL_DOCUMENT_ROOT.'/core/modules/commande/modules_commande.php';
    @@ -38,7 +38,7 @@ require_once DOL_DOCUMENT_ROOT.'/core/lib/pdf.lib.php';
     
     
     /**
    - *	Classe to generate PDF orders with template Einstein
    + *	Class to generate PDF orders with template Einstein
      */
     class pdf_einstein extends ModelePDFCommandes
     {
    @@ -149,13 +149,13 @@ class pdf_einstein extends ModelePDFCommandes
     		$this->marge_haute =isset($conf->global->MAIN_PDF_MARGIN_TOP)?$conf->global->MAIN_PDF_MARGIN_TOP:10;
     		$this->marge_basse =isset($conf->global->MAIN_PDF_MARGIN_BOTTOM)?$conf->global->MAIN_PDF_MARGIN_BOTTOM:10;
     
    -		$this->option_logo = 1;                    // Affiche logo
    -		$this->option_tva = 1;                     // Gere option tva FACTURE_TVAOPTION
    -		$this->option_modereg = 1;                 // Affiche mode reglement
    -		$this->option_condreg = 1;                 // Affiche conditions reglement
    -		$this->option_codeproduitservice = 1;      // Affiche code produit-service
    -		$this->option_multilang = 1;               // Dispo en plusieurs langues
    -		$this->option_escompte = 0;                // Affiche si il y a eu escompte
    +		$this->option_logo = 1;                    // Display logo
    +		$this->option_tva = 1;                     // Manage the vat option FACTURE_TVAOPTION
    +		$this->option_modereg = 1;                 // Display payment mode
    +		$this->option_condreg = 1;                 // Display payment terms
    +		$this->option_codeproduitservice = 1;      // Display product-service code
    +		$this->option_multilang = 1;               // Available in several languages
    +		$this->option_escompte = 0;                // Displays if there has been a discount
     		$this->option_credit_note = 0;             // Support credit notes
     		$this->option_freetext = 1;				   // Support add of a personalised text
     		$this->option_draft_watermark = 1;		   // Support add of a watermark on drafts
    @@ -1261,27 +1261,30 @@ class pdf_einstein extends ModelePDFCommandes
     		$pdf->SetXY($this->marge_gauche,$posy);
     
     		// Logo
    -		$logo=$conf->mycompany->dir_output.'/logos/'.$this->emetteur->logo;
    -		if ($this->emetteur->logo)
    +		if (empty($conf->global->PDF_DISABLE_MYCOMPANY_LOGO))
     		{
    -			if (is_readable($logo))
    +			$logo=$conf->mycompany->dir_output.'/logos/'.$this->emetteur->logo;
    +			if ($this->emetteur->logo)
     			{
    -			    $height=pdf_getHeightForLogo($logo);
    -			    $pdf->Image($logo, $this->marge_gauche, $posy, 0, $height);	// width=0 (auto)
    +				if (is_readable($logo))
    +				{
    +				    $height=pdf_getHeightForLogo($logo);
    +				    $pdf->Image($logo, $this->marge_gauche, $posy, 0, $height);	// width=0 (auto)
    +				}
    +				else
    +				{
    +					$pdf->SetTextColor(200,0,0);
    +					$pdf->SetFont('','B', $default_font_size -2);
    +					$pdf->MultiCell(100, 3, $outputlangs->transnoentities("ErrorLogoFileNotFound",$logo), 0, 'L');
    +					$pdf->MultiCell(100, 3, $outputlangs->transnoentities("ErrorGoToGlobalSetup"), 0, 'L');
    +				}
     			}
     			else
     			{
    -				$pdf->SetTextColor(200,0,0);
    -				$pdf->SetFont('','B', $default_font_size -2);
    -				$pdf->MultiCell(100, 3, $outputlangs->transnoentities("ErrorLogoFileNotFound",$logo), 0, 'L');
    -				$pdf->MultiCell(100, 3, $outputlangs->transnoentities("ErrorGoToGlobalSetup"), 0, 'L');
    +				$text=$this->emetteur->name;
    +				$pdf->MultiCell(100, 4, $outputlangs->convToOutputCharset($text), 0, 'L');
     			}
     		}
    -		else
    -		{
    -			$text=$this->emetteur->name;
    -			$pdf->MultiCell(100, 4, $outputlangs->convToOutputCharset($text), 0, 'L');
    -		}
     
     		$pdf->SetFont('','B', $default_font_size + 3);
     		$pdf->SetXY($posx,$posy);
    diff --git a/htdocs/core/modules/commande/doc/pdf_eratosthene.modules.php b/htdocs/core/modules/commande/doc/pdf_eratosthene.modules.php
    new file mode 100644
    index 00000000000..1c85adddfcc
    --- /dev/null
    +++ b/htdocs/core/modules/commande/doc/pdf_eratosthene.modules.php
    @@ -0,0 +1,1675 @@
    +<?php
    +/* Copyright (C) 2004-2014	Laurent Destailleur	<eldy@users.sourceforge.net>
    + * Copyright (C) 2005-2012	Regis Houssin		<regis.houssin@capnetworks.com>
    + * Copyright (C) 2008		Raphael Bertrand	<raphael.bertrand@resultic.fr>
    + * Copyright (C) 2010-2013	Juanjo Menent		<jmenent@2byte.es>
    + * Copyright (C) 2012      	Christophe Battarel <christophe.battarel@altairis.fr>
    + * Copyright (C) 2012       Cedric Salvador     <csalvador@gpcsolutions.fr>
    + * Copyright (C) 2015       Marcos García       <marcosgdf@gmail.com>
    + * Copyright (C) 2017       Ferran Marcet       <fmarcet@2byte.es>
    + * Copyright (C) 2018       Frédéric France         <frederic.france@netlogic.fr>
    + *
    + * This program is free software; you can redistribute it and/or modify
    + * it under the terms of the GNU General Public License as published by
    + * the Free Software Foundation; either version 3 of the License, or
    + * (at your option) any later version.
    + *
    + * This program is distributed in the hope that it will be useful,
    + * but WITHOUT ANY WARRANTY; without even the implied warranty of
    + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    + * GNU General Public License for more details.
    + *
    + * You should have received a copy of the GNU General Public License
    + * along with this program. If not, see <http://www.gnu.org/licenses/>.
    + * or see http://www.gnu.org/
    + */
    +
    +/**
    + *	\file       htdocs/core/modules/commande/doc/pdf_eratosthene.modules.php
    + *	\ingroup    commande
    + *	\brief      Fichier de la classe permettant de generer les commandes au modele Eratosthène
    + */
    +
    +require_once DOL_DOCUMENT_ROOT.'/core/modules/commande/modules_commande.php';
    +require_once DOL_DOCUMENT_ROOT.'/product/class/product.class.php';
    +require_once DOL_DOCUMENT_ROOT.'/core/lib/company.lib.php';
    +require_once DOL_DOCUMENT_ROOT.'/core/lib/functions2.lib.php';
    +require_once DOL_DOCUMENT_ROOT.'/core/lib/pdf.lib.php';
    +
    +
    +/**
    + *	Classe to generate PDF orders with template Eratosthene
    + */
    +class pdf_eratosthene extends ModelePDFCommandes
    +{
    +    /**
    +     * @var DoliDb Database handler
    +     */
    +    public $db;
    +
    +	/**
    +     * @var string model name
    +     */
    +    public $name;
    +
    +	/**
    +     * @var string model description (short text)
    +     */
    +    public $description;
    +
    +    /**
    +     * @var int 	Save the name of generated file as the main doc when generating a doc with this template
    +     */
    +    public $update_main_doc_field;
    +
    +	/**
    +     * @var string document type
    +     */
    +    public $type;
    +
    +	/**
    +     * @var array Minimum version of PHP required by module.
    +	 * e.g.: PHP ≥ 5.3 = array(5, 3)
    +     */
    +	public $phpmin = array(5, 2);
    +
    +	/**
    +     * Dolibarr version of the loaded document
    +     * @public string
    +     */
    +	public $version = 'development';
    +
    +    public $page_largeur;
    +    public $page_hauteur;
    +    public $format;
    +	public $marge_gauche;
    +	public $marge_droite;
    +	public $marge_haute;
    +	public $marge_basse;
    +
    +    public $emetteur;	// Objet societe qui emet
    +
    +
    +	/**
    +	 *	Constructor
    +	 *
    +	 *  @param		DoliDB		$db      Database handler
    +	 */
    +	public function __construct($db)
    +	{
    +		global $conf,$langs,$mysoc;
    +
    +		// Translations
    +		$langs->loadLangs(array("main", "bills", "products"));
    +
    +		$this->db = $db;
    +		$this->name = "eratosthene";
    +		$this->description = $langs->trans('PDFEratostheneDescription');
    +		$this->update_main_doc_field = 1;		// Save the name of generated file as the main doc when generating a doc with this template
    +
    +		// Dimension page
    +		$this->type = 'pdf';
    +		$formatarray=pdf_getFormat();
    +		$this->page_largeur = $formatarray['width'];
    +		$this->page_hauteur = $formatarray['height'];
    +		$this->format = array($this->page_largeur,$this->page_hauteur);
    +		$this->marge_gauche=isset($conf->global->MAIN_PDF_MARGIN_LEFT)?$conf->global->MAIN_PDF_MARGIN_LEFT:10;
    +		$this->marge_droite=isset($conf->global->MAIN_PDF_MARGIN_RIGHT)?$conf->global->MAIN_PDF_MARGIN_RIGHT:10;
    +		$this->marge_haute =isset($conf->global->MAIN_PDF_MARGIN_TOP)?$conf->global->MAIN_PDF_MARGIN_TOP:10;
    +		$this->marge_basse =isset($conf->global->MAIN_PDF_MARGIN_BOTTOM)?$conf->global->MAIN_PDF_MARGIN_BOTTOM:10;
    +
    +		$this->option_logo = 1;                    // Affiche logo
    +		$this->option_tva = 1;                     // Gere option tva FACTURE_TVAOPTION
    +		$this->option_modereg = 1;                 // Affiche mode reglement
    +		$this->option_condreg = 1;                 // Affiche conditions reglement
    +		$this->option_codeproduitservice = 1;      // Affiche code produit-service
    +		$this->option_multilang = 1;               // Dispo en plusieurs langues
    +		$this->option_escompte = 0;                // Affiche si il y a eu escompte
    +		$this->option_credit_note = 0;             // Support credit notes
    +		$this->option_freetext = 1;				   // Support add of a personalised text
    +		$this->option_draft_watermark = 1;		   // Support add of a watermark on drafts
    +
    +		$this->franchise=!$mysoc->tva_assuj;
    +
    +		// Get source company
    +		$this->emetteur=$mysoc;
    +		if (empty($this->emetteur->country_code)) $this->emetteur->country_code=substr($langs->defaultlang,-2);    // By default, if was not defined
    +
    +		// Define position of columns
    +		$this->posxdesc=$this->marge_gauche+1;
    +
    +
    +		$this->tva=array();
    +		$this->localtax1=array();
    +		$this->localtax2=array();
    +		$this->atleastoneratenotnull=0;
    +		$this->atleastonediscount=0;
    +	}
    +
    +    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
    +    /**
    +     *  Function to build pdf onto disk
    +     *
    +     *  @param		Object		$object				Object to generate
    +     *  @param		Translate	$outputlangs		Lang output object
    +     *  @param		string		$srctemplatepath	Full path of source filename for generator using a template file
    +     *  @param		int			$hidedetails		Do not show line details
    +     *  @param		int			$hidedesc			Do not show desc
    +     *  @param		int			$hideref			Do not show ref
    +     *  @return     int             			    1=OK, 0=KO
    +	 */
    +	public function write_file($object, $outputlangs, $srctemplatepath='', $hidedetails=0, $hidedesc=0, $hideref=0)
    +	{
    +	    // phpcs:enable
    +		global $user, $langs, $conf, $mysoc, $db, $hookmanager, $nblignes;
    +
    +		if (! is_object($outputlangs)) $outputlangs=$langs;
    +		// For backward compatibility with FPDF, force output charset to ISO, because FPDF expect text to be encoded in ISO
    +		if (! empty($conf->global->MAIN_USE_FPDF)) $outputlangs->charset_output='ISO-8859-1';
    +
    +		// Translations
    +		$outputlangs->loadLangs(array("main", "dict", "companies", "bills", "products", "orders", "deliveries"));
    +
    +		$nblignes = count($object->lines);
    +
    +		if ($conf->commande->dir_output)
    +		{
    +            $object->fetch_thirdparty();
    +
    +            $deja_regle = 0;
    +
    +            // Definition of $dir and $file
    +			if ($object->specimen)
    +			{
    +				$dir = $conf->commande->dir_output;
    +				$file = $dir . "/SPECIMEN.pdf";
    +			}
    +			else
    +			{
    +				$objectref = dol_sanitizeFileName($object->ref);
    +				$dir = $conf->commande->dir_output . "/" . $objectref;
    +				$file = $dir . "/" . $objectref . ".pdf";
    +			}
    +
    +			if (! file_exists($dir))
    +			{
    +				if (dol_mkdir($dir) < 0)
    +				{
    +					$this->error=$langs->transnoentities("ErrorCanNotCreateDir",$dir);
    +					return 0;
    +				}
    +			}
    +
    +			if (file_exists($dir))
    +			{
    +				// Add pdfgeneration hook
    +				if (! is_object($hookmanager))
    +				{
    +					include_once DOL_DOCUMENT_ROOT.'/core/class/hookmanager.class.php';
    +					$hookmanager=new HookManager($this->db);
    +				}
    +				$hookmanager->initHooks(array('pdfgeneration'));
    +				$parameters=array('file'=>$file,'object'=>$object,'outputlangs'=>$outputlangs);
    +				global $action;
    +				$reshook=$hookmanager->executeHooks('beforePDFCreation',$parameters,$object,$action);    // Note that $action and $object may have been modified by some hooks
    +
    +				// Create pdf instance
    +				$pdf=pdf_getInstance($this->format);
    +				$default_font_size = pdf_getPDFFontSize($outputlangs);	// Must be after pdf_getInstance
    +				$pdf->SetAutoPageBreak(1,0);
    +
    +				$heightforinfotot = 40;	// Height reserved to output the info and total part
    +		        $heightforfreetext= (isset($conf->global->MAIN_PDF_FREETEXT_HEIGHT)?$conf->global->MAIN_PDF_FREETEXT_HEIGHT:5);	// Height reserved to output the free text on last page
    +		        $heightforfooter = $this->marge_basse + (empty($conf->global->MAIN_GENERATE_DOCUMENTS_SHOW_FOOT_DETAILS)?12:22);	// Height reserved to output the footer (value include bottom margin)
    +
    +                if (class_exists('TCPDF'))
    +                {
    +                    $pdf->setPrintHeader(false);
    +                    $pdf->setPrintFooter(false);
    +                }
    +                $pdf->SetFont(pdf_getPDFFont($outputlangs));
    +                // Set path to the background PDF File
    +                if (! empty($conf->global->MAIN_ADD_PDF_BACKGROUND))
    +                {
    +                    $pagecount = $pdf->setSourceFile($conf->mycompany->dir_output.'/'.$conf->global->MAIN_ADD_PDF_BACKGROUND);
    +                    $tplidx = $pdf->importPage(1);
    +                }
    +
    +				$pdf->Open();
    +				$pagenb=0;
    +				$pdf->SetDrawColor(128,128,128);
    +
    +				$pdf->SetTitle($outputlangs->convToOutputCharset($object->ref));
    +				$pdf->SetSubject($outputlangs->transnoentities("PdfOrderTitle"));
    +				$pdf->SetCreator("Dolibarr ".DOL_VERSION);
    +				$pdf->SetAuthor($outputlangs->convToOutputCharset($user->getFullName($outputlangs)));
    +				$pdf->SetKeyWords($outputlangs->convToOutputCharset($object->ref)." ".$outputlangs->transnoentities("PdfOrderTitle")." ".$outputlangs->convToOutputCharset($object->thirdparty->name));
    +				if (! empty($conf->global->MAIN_DISABLE_PDF_COMPRESSION)) $pdf->SetCompression(false);
    +
    +				$pdf->SetMargins($this->marge_gauche, $this->marge_haute, $this->marge_droite);   // Left, Top, Right
    +
    +				/// Does we have at least one line with discount $this->atleastonediscount
    +				foreach ($object->lines as $line) {
    +				    if ($line->remise_percent){
    +				        $this->atleastonediscount = true;
    +				        break;
    +				    }
    +				}
    +
    +				if (empty($this->atleastonediscount) && empty($conf->global->PRODUCT_USE_UNITS))
    +				{
    +					$this->posxpicture+=($this->postotalht - $this->posxdiscount);
    +					$this->posxtva+=($this->postotalht - $this->posxdiscount);
    +					$this->posxup+=($this->postotalht - $this->posxdiscount);
    +					$this->posxqty+=($this->postotalht - $this->posxdiscount);
    +					$this->posxdiscount+=($this->postotalht - $this->posxdiscount);
    +					//$this->postotalht;
    +				}
    +
    +				// New page
    +				$pdf->AddPage();
    +				if (! empty($tplidx)) $pdf->useTemplate($tplidx);
    +				$pagenb++;
    +				$top_shift = $this->_pagehead($pdf, $object, 1, $outputlangs);
    +				$pdf->SetFont('','', $default_font_size - 1);
    +				$pdf->MultiCell(0, 3, '');		// Set interline to 3
    +				$pdf->SetTextColor(0,0,0);
    +
    +
    +				$tab_top = 90+$top_shift;
    +				$tab_top_newpage = (empty($conf->global->MAIN_PDF_DONOTREPEAT_HEAD)?42+$top_shift:10);
    +
    +				// Incoterm
    +				if ($conf->incoterm->enabled)
    +				{
    +					$desc_incoterms = $object->getIncotermsForPDF();
    +					if ($desc_incoterms)
    +					{
    +						$tab_top -= 2;
    +
    +						$pdf->SetFont('','', $default_font_size - 1);
    +						$pdf->writeHTMLCell(190, 3, $this->posxdesc-1, $tab_top-1, dol_htmlentitiesbr($desc_incoterms), 0, 1);
    +						$nexY = $pdf->GetY();
    +						$height_incoterms=$nexY-$tab_top;
    +
    +						// Rect prend une longueur en 3eme param
    +						$pdf->SetDrawColor(192,192,192);
    +						$pdf->Rect($this->marge_gauche, $tab_top-1, $this->page_largeur-$this->marge_gauche-$this->marge_droite, $height_incoterms+1);
    +
    +						$tab_top = $nexY+6;
    +					}
    +				}
    +
    +				// Affiche notes
    +				$notetoshow=empty($object->note_public)?'':$object->note_public;
    +				if (! empty($conf->global->MAIN_ADD_SALE_REP_SIGNATURE_IN_NOTE))
    +				{
    +					// Get first sale rep
    +					if (is_object($object->thirdparty))
    +					{
    +						$salereparray=$object->thirdparty->getSalesRepresentatives($user);
    +						$salerepobj=new User($this->db);
    +						$salerepobj->fetch($salereparray[0]['id']);
    +						if (! empty($salerepobj->signature)) $notetoshow=dol_concatdesc($notetoshow, $salerepobj->signature);
    +					}
    +				}
    +
    +				$pagenb = $pdf->getPage();
    +				if ($notetoshow)
    +				{
    +				    $tab_width = $this->page_largeur-$this->marge_gauche-$this->marge_droite;
    +				    $pageposbeforenote = $pagenb;
    +
    +				    $substitutionarray=pdf_getSubstitutionArray($outputlangs, null, $object);
    +				    complete_substitutions_array($substitutionarray, $outputlangs, $object);
    +				    $notetoshow = make_substitutions($notetoshow, $substitutionarray, $outputlangs);
    +
    +					$tab_top -= 2;
    +
    +				    $pdf->startTransaction();
    +
    +				    $pdf->SetFont('','', $default_font_size - 1);
    +				    $pdf->writeHTMLCell(190, 3, $this->posxdesc-1, $tab_top, dol_htmlentitiesbr($notetoshow), 0, 1);
    +				    // Description
    +				    $pageposafternote=$pdf->getPage();
    +				    $posyafter = $pdf->GetY();
    +
    +				    if($pageposafternote>$pageposbeforenote )
    +				    {
    +				        $pdf->rollbackTransaction(true);
    +
    +				        // prepar pages to receive notes
    +				        while ($pagenb < $pageposafternote) {
    +				            $pdf->AddPage();
    +				            $pagenb++;
    +				            if (! empty($tplidx)) $pdf->useTemplate($tplidx);
    +				            if (empty($conf->global->MAIN_PDF_DONOTREPEAT_HEAD)) $this->_pagehead($pdf, $object, 0, $outputlangs);
    +				            // $this->_pagefoot($pdf,$object,$outputlangs,1);
    +				            $pdf->setTopMargin($tab_top_newpage);
    +				            // The only function to edit the bottom margin of current page to set it.
    +				            $pdf->setPageOrientation('', 1, $heightforfooter + $heightforfreetext);
    +				        }
    +
    +				        // back to start
    +				        $pdf->setPage($pageposbeforenote);
    +				        $pdf->setPageOrientation('', 1, $heightforfooter + $heightforfreetext);
    +				        $pdf->SetFont('','', $default_font_size - 1);
    +				        $pdf->writeHTMLCell(190, 3, $this->posxdesc-1, $tab_top, dol_htmlentitiesbr($notetoshow), 0, 1);
    +				        $pageposafternote=$pdf->getPage();
    +
    +				        $posyafter = $pdf->GetY();
    +
    +				        if ($posyafter > ($this->page_hauteur - ($heightforfooter+$heightforfreetext+20)))	// There is no space left for total+free text
    +				        {
    +				            $pdf->AddPage('','',true);
    +				            $pagenb++;
    +				            $pageposafternote++;
    +				            $pdf->setPage($pageposafternote);
    +				            $pdf->setTopMargin($tab_top_newpage);
    +				            // The only function to edit the bottom margin of current page to set it.
    +				            $pdf->setPageOrientation('', 1, $heightforfooter + $heightforfreetext);
    +				            //$posyafter = $tab_top_newpage;
    +				        }
    +
    +
    +				        // apply note frame to previus pages
    +				        $i = $pageposbeforenote;
    +				        while ($i < $pageposafternote) {
    +				            $pdf->setPage($i);
    +
    +
    +				            $pdf->SetDrawColor(128,128,128);
    +				            // Draw note frame
    +				            if($i>$pageposbeforenote){
    +				                $height_note = $this->page_hauteur - ($tab_top_newpage + $heightforfooter);
    +				                $pdf->Rect($this->marge_gauche, $tab_top_newpage-1, $tab_width, $height_note + 1);
    +				            }
    +				            else{
    +				                $height_note = $this->page_hauteur - ($tab_top + $heightforfooter);
    +				                $pdf->Rect($this->marge_gauche, $tab_top-1, $tab_width, $height_note + 1);
    +				            }
    +
    +				            // Add footer
    +				            $pdf->setPageOrientation('', 1, 0);	// The only function to edit the bottom margin of current page to set it.
    +				            $this->_pagefoot($pdf,$object,$outputlangs,1);
    +
    +				            $i++;
    +				        }
    +
    +				        // apply note frame to last page
    +				        $pdf->setPage($pageposafternote);
    +				        if (! empty($tplidx)) $pdf->useTemplate($tplidx);
    +				        if (empty($conf->global->MAIN_PDF_DONOTREPEAT_HEAD)) $this->_pagehead($pdf, $object, 0, $outputlangs);
    +				        $height_note=$posyafter-$tab_top_newpage;
    +				        $pdf->Rect($this->marge_gauche, $tab_top_newpage-1, $tab_width, $height_note+1);
    +
    +				    }
    +				    else // No pagebreak
    +				    {
    +				        $pdf->commitTransaction();
    +				        $posyafter = $pdf->GetY();
    +				        $height_note=$posyafter-$tab_top;
    +				        $pdf->Rect($this->marge_gauche, $tab_top-1, $tab_width, $height_note+1);
    +
    +
    +				        if($posyafter > ($this->page_hauteur - ($heightforfooter+$heightforfreetext+20)) )
    +				        {
    +				            // not enough space, need to add page
    +				            $pdf->AddPage('','',true);
    +				            $pagenb++;
    +				            $pageposafternote++;
    +				            $pdf->setPage($pageposafternote);
    +				            if (! empty($tplidx)) $pdf->useTemplate($tplidx);
    +				            if (empty($conf->global->MAIN_PDF_DONOTREPEAT_HEAD)) $this->_pagehead($pdf, $object, 0, $outputlangs);
    +
    +				            $posyafter = $tab_top_newpage;
    +				        }
    +
    +				    }
    +
    +				    $tab_height = $tab_height - $height_note;
    +				    $tab_top = $posyafter +6;
    +				}
    +				else
    +				{
    +					$height_note=0;
    +				}
    +
    +				$iniY = $tab_top + 7;
    +				$curY = $tab_top + 7;
    +				$nexY = $tab_top + 7;
    +
    +				// Use new auto collum system
    +				$this->prepareArrayColumnField($object,$outputlangs,$hidedetails,$hidedesc,$hideref);
    +
    +				// Loop on each lines
    +				$pageposbeforeprintlines=$pdf->getPage();
    +				$pagenb = $pageposbeforeprintlines;
    +				for ($i = 0 ; $i < $nblignes ; $i++)
    +				{
    +					$curY = $nexY;
    +					$pdf->SetFont('','', $default_font_size - 1);   // Into loop to work with multipage
    +					$pdf->SetTextColor(0,0,0);
    +
    +					$pdf->setTopMargin($tab_top_newpage);
    +					$pdf->setPageOrientation('', 1, $heightforfooter+$heightforfreetext+$heightforinfotot);	// The only function to edit the bottom margin of current page to set it.
    +					$pageposbefore=$pdf->getPage();
    +
    +					// Description of product line
    +					$curX = $this->posxdesc-1;
    +
    +					$showpricebeforepagebreak=1;
    +
    +					if($this->getColumnStatus('desc'))
    +					{
    +    					$pdf->startTransaction();
    +    					pdf_writelinedesc($pdf,$object,$i,$outputlangs,$this->getColumnContentWidth('desc'),3,$this->getColumnContentXStart('desc'),$curY,$hideref,$hidedesc);
    +    					$pageposafter=$pdf->getPage();
    +    					if ($pageposafter > $pageposbefore)	// There is a pagebreak
    +    					{
    +    						$pdf->rollbackTransaction(true);
    +    						$pageposafter=$pageposbefore;
    +    						//print $pageposafter.'-'.$pageposbefore;exit;
    +    						$pdf->setPageOrientation('', 1, $heightforfooter);	// The only function to edit the bottom margin of current page to set it.
    +    						pdf_writelinedesc($pdf,$object,$i,$outputlangs,$this->getColumnContentWidth('desc'),3,$this->getColumnContentXStart('desc'),$curY,$hideref,$hidedesc);
    +    						$pageposafter=$pdf->getPage();
    +    						$posyafter=$pdf->GetY();
    +    						if ($posyafter > ($this->page_hauteur - ($heightforfooter+$heightforfreetext+$heightforinfotot)))	// There is no space left for total+free text
    +    						{
    +    							if ($i == ($nblignes-1))	// No more lines, and no space left to show total, so we create a new page
    +    							{
    +    								$pdf->AddPage('','',true);
    +    								if (! empty($tplidx)) $pdf->useTemplate($tplidx);
    +    								//if (empty($conf->global->MAIN_PDF_DONOTREPEAT_HEAD)) $this->_pagehead($pdf, $object, 0, $outputlangs);
    +    								$pdf->setPage($pageposafter+1);
    +    							}
    +    						}
    +    						else
    +    						{
    +    							// We found a page break
    +    							$showpricebeforepagebreak=0;
    +    						}
    +    					}
    +    					else	// No pagebreak
    +    					{
    +    						$pdf->commitTransaction();
    +    					}
    +    					$posYAfterDescription=$pdf->GetY();
    +					}
    +
    +					$nexY = $pdf->GetY();
    +					$pageposafter=$pdf->getPage();
    +
    +					$pdf->setPage($pageposbefore);
    +					$pdf->setTopMargin($this->marge_haute);
    +					$pdf->setPageOrientation('', 1, 0);	// The only function to edit the bottom margin of current page to set it.
    +
    +					// We suppose that a too long description is moved completely on next page
    +					if ($pageposafter > $pageposbefore && empty($showpricebeforepagebreak)) {
    +						$pdf->setPage($pageposafter); $curY = $tab_top_newpage;
    +					}
    +
    +					$pdf->SetFont('','',  $default_font_size - 1);   // On repositionne la police par defaut
    +
    +					// VAT Rate
    +					if ($this->getColumnStatus('vat'))
    +					{
    +					    $vat_rate = pdf_getlinevatrate($object, $i, $outputlangs, $hidedetails);
    +					    $this->printStdColumnContent($pdf, $curY, 'vat', $vat_rate);
    +					    $nexY = max($pdf->GetY(),$nexY);
    +					}
    +
    +					// Unit price before discount
    +					if ($this->getColumnStatus('subprice'))
    +					{
    +					    $up_excl_tax = pdf_getlineupexcltax($object, $i, $outputlangs, $hidedetails);
    +					    $this->printStdColumnContent($pdf, $curY, 'subprice', $up_excl_tax);
    +					    $nexY = max($pdf->GetY(),$nexY);
    +					}
    +
    +					// Quantity
    +					// Enough for 6 chars
    +					if ($this->getColumnStatus('qty'))
    +					{
    +					    $qty = pdf_getlineqty($object, $i, $outputlangs, $hidedetails);
    +					    $this->printStdColumnContent($pdf, $curY, 'qty', $qty);
    +					    $nexY = max($pdf->GetY(),$nexY);
    +					}
    +
    +
    +					// Unit
    +					if ($this->getColumnStatus('unit'))
    +					{
    +					    $unit = pdf_getlineunit($object, $i, $outputlangs, $hidedetails, $hookmanager);
    +					    $this->printStdColumnContent($pdf, $curY, 'unit', $unit);
    +					    $nexY = max($pdf->GetY(),$nexY);
    +					}
    +
    +					// Discount on line
    +					if ($this->getColumnStatus('discount') && $object->lines[$i]->remise_percent)
    +					{
    +					    $remise_percent = pdf_getlineremisepercent($object, $i, $outputlangs, $hidedetails);
    +					    $this->printStdColumnContent($pdf, $curY, 'discount', $remise_percent);
    +					    $nexY = max($pdf->GetY(),$nexY);
    +					}
    +
    +					// Total HT line
    +					if ($this->getColumnStatus('totalexcltax'))
    +					{
    +					    $total_excl_tax = pdf_getlinetotalexcltax($object, $i, $outputlangs, $hidedetails);
    +					    $this->printStdColumnContent($pdf, $curY, 'totalexcltax', $total_excl_tax);
    +					    $nexY = max($pdf->GetY(),$nexY);
    +					}
    +
    +
    +					$parameters=array(
    +					    'object' => $object,
    +					    'i' => $i,
    +					    'pdf' =>& $pdf,
    +					    'curY' =>& $curY,
    +					    'nexY' =>& $nexY,
    +					    'outputlangs' => $outputlangs,
    +					    'hidedetails' => $hidedetails
    +					);
    +					$reshook=$hookmanager->executeHooks('printPDFline',$parameters,$this);    // Note that $object may have been modified by hook
    +
    +
    +					// Collecte des totaux par valeur de tva dans $this->tva["taux"]=total_tva
    +					if ($conf->multicurrency->enabled && $object->multicurrency_tx != 1) $tvaligne=$object->lines[$i]->multicurrency_total_tva;
    +					else $tvaligne=$object->lines[$i]->total_tva;
    +
    +					$localtax1ligne=$object->lines[$i]->total_localtax1;
    +					$localtax2ligne=$object->lines[$i]->total_localtax2;
    +					$localtax1_rate=$object->lines[$i]->localtax1_tx;
    +					$localtax2_rate=$object->lines[$i]->localtax2_tx;
    +					$localtax1_type=$object->lines[$i]->localtax1_type;
    +					$localtax2_type=$object->lines[$i]->localtax2_type;
    +
    +					if ($object->remise_percent) $tvaligne-=($tvaligne*$object->remise_percent)/100;
    +					if ($object->remise_percent) $localtax1ligne-=($localtax1ligne*$object->remise_percent)/100;
    +					if ($object->remise_percent) $localtax2ligne-=($localtax2ligne*$object->remise_percent)/100;
    +
    +					$vatrate=(string) $object->lines[$i]->tva_tx;
    +
    +					// Retrieve type from database for backward compatibility with old records
    +					if ((! isset($localtax1_type) || $localtax1_type=='' || ! isset($localtax2_type) || $localtax2_type=='') // if tax type not defined
    +					&& (! empty($localtax1_rate) || ! empty($localtax2_rate))) // and there is local tax
    +					{
    +						$localtaxtmp_array=getLocalTaxesFromRate($vatrate,0,$object->thirdparty,$mysoc);
    +						$localtax1_type = $localtaxtmp_array[0];
    +						$localtax2_type = $localtaxtmp_array[2];
    +					}
    +
    +				    // retrieve global local tax
    +					if ($localtax1_type && $localtax1ligne != 0)
    +						$this->localtax1[$localtax1_type][$localtax1_rate]+=$localtax1ligne;
    +					if ($localtax2_type && $localtax2ligne != 0)
    +						$this->localtax2[$localtax2_type][$localtax2_rate]+=$localtax2ligne;
    +
    +					if (($object->lines[$i]->info_bits & 0x01) == 0x01) $vatrate.='*';
    +					if (! isset($this->tva[$vatrate])) 				$this->tva[$vatrate]=0;
    +					$this->tva[$vatrate] += $tvaligne;
    +
    +					// Add line
    +					if (! empty($conf->global->MAIN_PDF_DASH_BETWEEN_LINES) && $i < ($nblignes - 1))
    +					{
    +						$pdf->setPage($pageposafter);
    +						$pdf->SetLineStyle(array('dash'=>'1,1','color'=>array(80,80,80)));
    +						//$pdf->SetDrawColor(190,190,200);
    +						$pdf->line($this->marge_gauche, $nexY+1, $this->page_largeur - $this->marge_droite, $nexY+1);
    +						$pdf->SetLineStyle(array('dash'=>0));
    +					}
    +
    +					$nexY+=2;    // Passe espace entre les lignes
    +
    +					// Detect if some page were added automatically and output _tableau for past pages
    +					while ($pagenb < $pageposafter)
    +					{
    +						$pdf->setPage($pagenb);
    +						if ($pagenb == $pageposbeforeprintlines)
    +						{
    +							$this->_tableau($pdf, $tab_top, $this->page_hauteur - $tab_top - $heightforfooter, 0, $outputlangs, 0, 1, $object->multicurrency_code);
    +						}
    +						else
    +						{
    +							$this->_tableau($pdf, $tab_top_newpage, $this->page_hauteur - $tab_top_newpage - $heightforfooter, 0, $outputlangs, 1, 1, $object->multicurrency_code);
    +						}
    +						$this->_pagefoot($pdf,$object,$outputlangs,1);
    +						$pagenb++;
    +						$pdf->setPage($pagenb);
    +						$pdf->setPageOrientation('', 1, 0);	// The only function to edit the bottom margin of current page to set it.
    +						if (empty($conf->global->MAIN_PDF_DONOTREPEAT_HEAD)) $this->_pagehead($pdf, $object, 0, $outputlangs);
    +					}
    +					if (isset($object->lines[$i+1]->pagebreak) && $object->lines[$i+1]->pagebreak)
    +					{
    +					    if ($pagenb == $pageposafter)
    +						{
    +							$this->_tableau($pdf, $tab_top, $this->page_hauteur - $tab_top - $heightforfooter, 0, $outputlangs, 0, 1, $object->multicurrency_code);
    +						}
    +						else
    +						{
    +							$this->_tableau($pdf, $tab_top_newpage, $this->page_hauteur - $tab_top_newpage - $heightforfooter, 0, $outputlangs, 1, 1, $object->multicurrency_code);
    +						}
    +						$this->_pagefoot($pdf,$object,$outputlangs,1);
    +						// New page
    +						$pdf->AddPage();
    +						if (! empty($tplidx)) $pdf->useTemplate($tplidx);
    +						$pagenb++;
    +						if (empty($conf->global->MAIN_PDF_DONOTREPEAT_HEAD)) $this->_pagehead($pdf, $object, 0, $outputlangs);
    +					}
    +				}
    +
    +				// Show square
    +				if ($pagenb == $pageposbeforeprintlines)
    +					$this->_tableau($pdf, $tab_top, $this->page_hauteur - $tab_top - $heightforinfotot - $heightforfreetext - $heightforfooter, 0, $outputlangs, 0, 0, $object->multicurrency_code);
    +				else
    +					$this->_tableau($pdf, $tab_top_newpage, $this->page_hauteur - $tab_top_newpage - $heightforinfotot - $heightforfreetext - $heightforfooter, 0, $outputlangs, 1, 0, $object->multicurrency_code);
    +				$bottomlasttab=$this->page_hauteur - $heightforinfotot - $heightforfreetext - $heightforfooter + 1;
    +
    +				// Affiche zone infos
    +				$posy=$this->drawInfoTable($pdf, $object, $bottomlasttab, $outputlangs);
    +
    +				// Affiche zone totaux
    +				$posy=$this->drawTotalTable($pdf, $object, $deja_regle, $bottomlasttab, $outputlangs);
    +
    +				// Affiche zone versements
    +				/*
    +				if ($deja_regle)
    +				{
    +					$posy=$this->drawPaymentsTable($pdf, $object, $posy, $outputlangs);
    +				}
    +				*/
    +
    +				// Pied de page
    +				$this->_pagefoot($pdf, $object, $outputlangs);
    +				if (method_exists($pdf, 'AliasNbPages')) $pdf->AliasNbPages();
    +
    +				$pdf->Close();
    +
    +				$pdf->Output($file, 'F');
    +
    +				// Add pdfgeneration hook
    +				$hookmanager->initHooks(array('pdfgeneration'));
    +				$parameters=array('file'=>$file, 'object'=>$object, 'outputlangs'=>$outputlangs);
    +				global $action;
    +				$reshook=$hookmanager->executeHooks('afterPDFCreation', $parameters, $this, $action);    // Note that $action and $object may have been modified by some hooks
    +
    +				if (! empty($conf->global->MAIN_UMASK))
    +					@chmod($file, octdec($conf->global->MAIN_UMASK));
    +
    +				$this->result = array('fullpath'=>$file);
    +
    +				return 1;   // Pas d'erreur
    +			}
    +			else
    +			{
    +				$this->error=$langs->transnoentities("ErrorCanNotCreateDir",$dir);
    +				return 0;
    +			}
    +		}
    +		else
    +		{
    +			$this->error=$langs->transnoentities("ErrorConstantNotDefined","COMMANDE_OUTPUTDIR");
    +			return 0;
    +		}
    +	}
    +
    +	/**
    +	 *  Show payments table
    +   *
    +	 *  @param	TCPDF		$pdf     		Object PDF
    +	 *  @param  Object		$object			Object order
    +	 *	@param	int			$posy			Position y in PDF
    +	 *	@param	Translate	$outputlangs	Object langs for output
    +	 *	@return int							<0 if KO, >0 if OK
    +	 */
    +	private function drawPaymentsTable(&$pdf, $object, $posy, $outputlangs)
    +	{
    +	}
    +
    +	/**
    +	 *   Show miscellaneous information (payment mode, payment term, ...)
    +	 *
    +	 *   @param		TCPDF		$pdf     		Object PDF
    +	 *   @param		Object		$object			Object to show
    +	 *   @param		int			$posy			Y
    +	 *   @param		Translate	$outputlangs	Langs object
    +	 *   @return	void
    +	 */
    +	private function drawInfoTable(&$pdf, $object, $posy, $outputlangs)
    +	{
    +		global $conf;
    +		$default_font_size = pdf_getPDFFontSize($outputlangs);
    +
    +		$pdf->SetFont('','', $default_font_size - 1);
    +
    +        // If France, show VAT mention if not applicable
    +		if ($this->emetteur->country_code == 'FR' && $this->franchise == 1)
    +		{
    +			$pdf->SetFont('','B', $default_font_size - 2);
    +			$pdf->SetXY($this->marge_gauche, $posy);
    +			$pdf->MultiCell(100, 3, $outputlangs->transnoentities("VATIsNotUsedForInvoice"), 0, 'L', 0);
    +
    +			$posy=$pdf->GetY()+4;
    +		}
    +
    +		$posxval=52;
    +
    +		// Show payments conditions
    +		if ($object->cond_reglement_code || $object->cond_reglement)
    +		{
    +			$pdf->SetFont('','B', $default_font_size - 2);
    +			$pdf->SetXY($this->marge_gauche, $posy);
    +			$titre = $outputlangs->transnoentities("PaymentConditions").':';
    +			$pdf->MultiCell(43, 4, $titre, 0, 'L');
    +
    +			$pdf->SetFont('','', $default_font_size - 2);
    +			$pdf->SetXY($posxval, $posy);
    +			$lib_condition_paiement=$outputlangs->transnoentities("PaymentCondition".$object->cond_reglement_code)!=('PaymentCondition'.$object->cond_reglement_code)?$outputlangs->transnoentities("PaymentCondition".$object->cond_reglement_code):$outputlangs->convToOutputCharset($object->cond_reglement_doc);
    +			$lib_condition_paiement=str_replace('\n',"\n",$lib_condition_paiement);
    +			$pdf->MultiCell(67, 4, $lib_condition_paiement,0,'L');
    +
    +			$posy=$pdf->GetY()+3;
    +		}
    +
    +        // Check a payment mode is defined
    +        /* Not used with orders
    +		if (empty($object->mode_reglement_code)
    +        	&& ! $conf->global->FACTURE_CHQ_NUMBER
    +        	&& ! $conf->global->FACTURE_RIB_NUMBER)
    +		{
    +            $pdf->SetXY($this->marge_gauche, $posy);
    +            $pdf->SetTextColor(200,0,0);
    +            $pdf->SetFont('','B', $default_font_size - 2);
    +            $pdf->MultiCell(80, 3, $outputlangs->transnoentities("ErrorNoPaiementModeConfigured"),0,'L',0);
    +            $pdf->SetTextColor(0,0,0);
    +
    +            $posy=$pdf->GetY()+1;
    +        }
    +		*/
    +		/* TODO
    +		else if (! empty($object->availability_code))
    +		{
    +            $pdf->SetXY($this->marge_gauche, $posy);
    +            $pdf->SetTextColor(200,0,0);
    +            $pdf->SetFont('','B', $default_font_size - 2);
    +            $pdf->MultiCell(80, 3, $outputlangs->transnoentities("AvailabilityPeriod").': '.,0,'L',0);
    +            $pdf->SetTextColor(0,0,0);
    +
    +            $posy=$pdf->GetY()+1;
    +		}*/
    +
    +	    // Show planed date of delivery
    +        if (! empty($object->date_livraison))
    +		{
    +            $outputlangs->load("sendings");
    +			$pdf->SetFont('','B', $default_font_size - 2);
    +			$pdf->SetXY($this->marge_gauche, $posy);
    +			$titre = $outputlangs->transnoentities("DateDeliveryPlanned").':';
    +			$pdf->MultiCell(80, 4, $titre, 0, 'L');
    +			$pdf->SetFont('','', $default_font_size - 2);
    +			$pdf->SetXY($posxval, $posy);
    +			$dlp=dol_print_date($object->date_livraison,"daytext",false,$outputlangs,true);
    +			$pdf->MultiCell(80, 4, $dlp, 0, 'L');
    +
    +            $posy=$pdf->GetY()+1;
    +		}
    +        elseif ($object->availability_code || $object->availability)    // Show availability conditions
    +		{
    +			$pdf->SetFont('','B', $default_font_size - 2);
    +			$pdf->SetXY($this->marge_gauche, $posy);
    +			$titre = $outputlangs->transnoentities("AvailabilityPeriod").':';
    +			$pdf->MultiCell(80, 4, $titre, 0, 'L');
    +			$pdf->SetTextColor(0,0,0);
    +			$pdf->SetFont('','', $default_font_size - 2);
    +			$pdf->SetXY($posxval, $posy);
    +			$lib_availability=$outputlangs->transnoentities("AvailabilityType".$object->availability_code)!=('AvailabilityType'.$object->availability_code)?$outputlangs->transnoentities("AvailabilityType".$object->availability_code):$outputlangs->convToOutputCharset(isset($object->availability)?$object->availability:'');
    +			$lib_availability=str_replace('\n',"\n",$lib_availability);
    +			$pdf->MultiCell(80, 4, $lib_availability, 0, 'L');
    +
    +			$posy=$pdf->GetY()+1;
    +		}
    +
    +      	// Show payment mode
    +        if ($object->mode_reglement_code
    +        	 && $object->mode_reglement_code != 'CHQ'
    +           	 && $object->mode_reglement_code != 'VIR')
    +           	 {
    +	            $pdf->SetFont('','B', $default_font_size - 2);
    +	            $pdf->SetXY($this->marge_gauche, $posy);
    +	            $titre = $outputlangs->transnoentities("PaymentMode").':';
    +	            $pdf->MultiCell(80, 5, $titre, 0, 'L');
    +
    +				$pdf->SetFont('','', $default_font_size - 2);
    +	            $pdf->SetXY($posxval, $posy);
    +	            $lib_mode_reg=$outputlangs->transnoentities("PaymentType".$object->mode_reglement_code)!=('PaymentType'.$object->mode_reglement_code)?$outputlangs->transnoentities("PaymentType".$object->mode_reglement_code):$outputlangs->convToOutputCharset($object->mode_reglement);
    +	            $pdf->MultiCell(80, 5, $lib_mode_reg,0,'L');
    +
    +	            $posy=$pdf->GetY()+2;
    +           	 }
    +
    +		// Show payment mode CHQ
    +        if (empty($object->mode_reglement_code) || $object->mode_reglement_code == 'CHQ')
    +        {
    +        	// Si mode reglement non force ou si force a CHQ
    +	        if (! empty($conf->global->FACTURE_CHQ_NUMBER))
    +	        {
    +	            if ($conf->global->FACTURE_CHQ_NUMBER > 0)
    +	            {
    +	                $account = new Account($this->db);
    +	                $account->fetch($conf->global->FACTURE_CHQ_NUMBER);
    +
    +	                $pdf->SetXY($this->marge_gauche, $posy);
    +	                $pdf->SetFont('','B', $default_font_size - 3);
    +	                $pdf->MultiCell(100, 3, $outputlangs->transnoentities('PaymentByChequeOrderedTo',$account->proprio),0,'L',0);
    +		            $posy=$pdf->GetY()+1;
    +
    +		            if (empty($conf->global->MAIN_PDF_HIDE_CHQ_ADDRESS))
    +		            {
    +		                $pdf->SetXY($this->marge_gauche, $posy);
    +		                $pdf->SetFont('','', $default_font_size - 3);
    +		                $pdf->MultiCell(100, 3, $outputlangs->convToOutputCharset($account->owner_address), 0, 'L', 0);
    +			            $posy=$pdf->GetY()+2;
    +		            }
    +	            }
    +	            if ($conf->global->FACTURE_CHQ_NUMBER == -1)
    +	            {
    +	                $pdf->SetXY($this->marge_gauche, $posy);
    +	                $pdf->SetFont('','B', $default_font_size - 3);
    +	                $pdf->MultiCell(100, 3, $outputlangs->transnoentities('PaymentByChequeOrderedTo',$this->emetteur->name),0,'L',0);
    +		            $posy=$pdf->GetY()+1;
    +
    +		            if (empty($conf->global->MAIN_PDF_HIDE_CHQ_ADDRESS))
    +		            {
    +			            $pdf->SetXY($this->marge_gauche, $posy);
    +		                $pdf->SetFont('','', $default_font_size - 3);
    +		                $pdf->MultiCell(100, 3, $outputlangs->convToOutputCharset($this->emetteur->getFullAddress()), 0, 'L', 0);
    +			            $posy=$pdf->GetY()+2;
    +		            }
    +	            }
    +	        }
    +		}
    +
    +        // If payment mode not forced or forced to VIR, show payment with BAN
    +        if (empty($object->mode_reglement_code) || $object->mode_reglement_code == 'VIR')
    +        {
    +			if (! empty($object->fk_account) || ! empty($object->fk_bank) || ! empty($conf->global->FACTURE_RIB_NUMBER))
    +			{
    +				$bankid=(empty($object->fk_account)?$conf->global->FACTURE_RIB_NUMBER:$object->fk_account);
    +				if (! empty($object->fk_bank)) $bankid=$object->fk_bank;   // For backward compatibility when object->fk_account is forced with object->fk_bank
    +				$account = new Account($this->db);
    +				$account->fetch($bankid);
    +
    +				$curx=$this->marge_gauche;
    +				$cury=$posy;
    +
    +				$posy=pdf_bank($pdf,$outputlangs,$curx,$cury,$account,0,$default_font_size);
    +
    +				$posy+=2;
    +			}
    +        }
    +
    +		return $posy;
    +	}
    +
    +
    +	/**
    +	 *	Show total to pay
    +	 *
    +	 *	@param	TCPDF		$pdf           Object PDF
    +	 *	@param  Facture		$object         Object invoice
    +	 *	@param  int			$deja_regle     Montant deja regle
    +	 *	@param	int			$posy			Position depart
    +	 *	@param	Translate	$outputlangs	Objet langs
    +	 *	@return int							Position pour suite
    +	 */
    +	private function drawTotalTable(&$pdf, $object, $deja_regle, $posy, $outputlangs)
    +	{
    +	    global $conf,$mysoc;
    +
    +		$default_font_size = pdf_getPDFFontSize($outputlangs);
    +
    +		$tab2_top = $posy;
    +		$tab2_hl = 4;
    +		$pdf->SetFont('','', $default_font_size - 1);
    +
    +		// Tableau total
    +        $col1x = 120; $col2x = 170;
    +		if ($this->page_largeur < 210) // To work with US executive format
    +		{
    +			$col2x-=20;
    +		}
    +		$largcol2 = ($this->page_largeur - $this->marge_droite - $col2x);
    +
    +		$useborder=0;
    +		$index = 0;
    +
    +		// Total HT
    +		$pdf->SetFillColor(255,255,255);
    +		$pdf->SetXY($col1x, $tab2_top + 0);
    +		$pdf->MultiCell($col2x-$col1x, $tab2_hl, $outputlangs->transnoentities("TotalHT"), 0, 'L', 1);
    +
    +		$total_ht = ($conf->multicurrency->enabled && $object->mylticurrency_tx != 1 ? $object->multicurrency_total_ht : $object->total_ht);
    +		$pdf->SetXY($col2x, $tab2_top + 0);
    +		$pdf->MultiCell($largcol2, $tab2_hl, price($total_ht + (! empty($object->remise)?$object->remise:0), 0, $outputlangs), 0, 'R', 1);
    +
    +		// Show VAT by rates and total
    +		$pdf->SetFillColor(248,248,248);
    +
    +		$total_ttc = ($conf->multicurrency->enabled && $object->multicurrency_tx != 1) ? $object->multicurrency_total_ttc : $object->total_ttc;
    +
    +		$this->atleastoneratenotnull=0;
    +		if (empty($conf->global->MAIN_GENERATE_DOCUMENTS_WITHOUT_VAT))
    +		{
    +			$tvaisnull=((! empty($this->tva) && count($this->tva) == 1 && isset($this->tva['0.000']) && is_float($this->tva['0.000'])) ? true : false);
    +			if (! empty($conf->global->MAIN_GENERATE_DOCUMENTS_WITHOUT_VAT_IFNULL) && $tvaisnull)
    +			{
    +				// Nothing to do
    +			}
    +			else
    +			{
    +				//Local tax 1 before VAT
    +				//if (! empty($conf->global->FACTURE_LOCAL_TAX1_OPTION) && $conf->global->FACTURE_LOCAL_TAX1_OPTION=='localtax1on')
    +				//{
    +					foreach( $this->localtax1 as $localtax_type => $localtax_rate )
    +					{
    +						if (in_array((string) $localtax_type, array('1','3','5'))) continue;
    +						foreach( $localtax_rate as $tvakey => $tvaval )
    +						{
    +							if ($tvakey!=0)    // On affiche pas taux 0
    +							{
    +								//$this->atleastoneratenotnull++;
    +
    +								$index++;
    +								$pdf->SetXY($col1x, $tab2_top + $tab2_hl * $index);
    +
    +								$tvacompl='';
    +								if (preg_match('/\*/',$tvakey))
    +								{
    +									$tvakey=str_replace('*','',$tvakey);
    +									$tvacompl = " (".$outputlangs->transnoentities("NonPercuRecuperable").")";
    +								}
    +								$totalvat = $outputlangs->transcountrynoentities("TotalLT1",$mysoc->country_code).' ';
    +								$totalvat.=vatrate(abs($tvakey),1).$tvacompl;
    +								$pdf->MultiCell($col2x-$col1x, $tab2_hl, $totalvat, 0, 'L', 1);
    +
    +								$pdf->SetXY($col2x, $tab2_top + $tab2_hl * $index);
    +								$pdf->MultiCell($largcol2, $tab2_hl, price($tvaval, 0, $outputlangs), 0, 'R', 1);
    +							}
    +						}
    +					}
    +	      		//}
    +				//Local tax 2 before VAT
    +				//if (! empty($conf->global->FACTURE_LOCAL_TAX2_OPTION) && $conf->global->FACTURE_LOCAL_TAX2_OPTION=='localtax2on')
    +				//{
    +					foreach( $this->localtax2 as $localtax_type => $localtax_rate )
    +					{
    +						if (in_array((string) $localtax_type, array('1','3','5'))) continue;
    +						foreach( $localtax_rate as $tvakey => $tvaval )
    +						{
    +							if ($tvakey!=0)    // On affiche pas taux 0
    +							{
    +								//$this->atleastoneratenotnull++;
    +
    +
    +
    +								$index++;
    +								$pdf->SetXY($col1x, $tab2_top + $tab2_hl * $index);
    +
    +								$tvacompl='';
    +								if (preg_match('/\*/',$tvakey))
    +								{
    +									$tvakey=str_replace('*','',$tvakey);
    +									$tvacompl = " (".$outputlangs->transnoentities("NonPercuRecuperable").")";
    +								}
    +								$totalvat = $outputlangs->transcountrynoentities("TotalLT2",$mysoc->country_code).' ';
    +								$totalvat.=vatrate(abs($tvakey),1).$tvacompl;
    +								$pdf->MultiCell($col2x-$col1x, $tab2_hl, $totalvat, 0, 'L', 1);
    +
    +								$pdf->SetXY($col2x, $tab2_top + $tab2_hl * $index);
    +								$pdf->MultiCell($largcol2, $tab2_hl, price($tvaval, 0, $outputlangs), 0, 'R', 1);
    +
    +							}
    +						}
    +					}
    +				//}
    +				// VAT
    +				foreach($this->tva as $tvakey => $tvaval)
    +				{
    +					if ($tvakey != 0)    // On affiche pas taux 0
    +					{
    +						$this->atleastoneratenotnull++;
    +
    +						$index++;
    +						$pdf->SetXY($col1x, $tab2_top + $tab2_hl * $index);
    +
    +						$tvacompl='';
    +						if (preg_match('/\*/',$tvakey))
    +						{
    +							$tvakey=str_replace('*','',$tvakey);
    +							$tvacompl = " (".$outputlangs->transnoentities("NonPercuRecuperable").")";
    +						}
    +						$totalvat =$outputlangs->transcountrynoentities("TotalVAT",$mysoc->country_code).' ';
    +						$totalvat.=vatrate($tvakey,1).$tvacompl;
    +						$pdf->MultiCell($col2x-$col1x, $tab2_hl, $totalvat, 0, 'L', 1);
    +
    +						$pdf->SetXY($col2x, $tab2_top + $tab2_hl * $index);
    +						$pdf->MultiCell($largcol2, $tab2_hl, price($tvaval, 0, $outputlangs), 0, 'R', 1);
    +					}
    +				}
    +
    +				//Local tax 1 after VAT
    +				//if (! empty($conf->global->FACTURE_LOCAL_TAX1_OPTION) && $conf->global->FACTURE_LOCAL_TAX1_OPTION=='localtax1on')
    +				//{
    +					foreach( $this->localtax1 as $localtax_type => $localtax_rate )
    +					{
    +						if (in_array((string) $localtax_type, array('2','4','6'))) continue;
    +
    +						foreach( $localtax_rate as $tvakey => $tvaval )
    +						{
    +							if ($tvakey != 0)    // On affiche pas taux 0
    +							{
    +								//$this->atleastoneratenotnull++;
    +
    +								$index++;
    +								$pdf->SetXY($col1x, $tab2_top + $tab2_hl * $index);
    +
    +								$tvacompl='';
    +								if (preg_match('/\*/',$tvakey))
    +								{
    +									$tvakey=str_replace('*','',$tvakey);
    +									$tvacompl = " (".$outputlangs->transnoentities("NonPercuRecuperable").")";
    +								}
    +								$totalvat = $outputlangs->transcountrynoentities("TotalLT1",$mysoc->country_code).' ';
    +
    +								$totalvat.=vatrate(abs($tvakey),1).$tvacompl;
    +								$pdf->MultiCell($col2x-$col1x, $tab2_hl, $totalvat, 0, 'L', 1);
    +								$pdf->SetXY($col2x, $tab2_top + $tab2_hl * $index);
    +								$pdf->MultiCell($largcol2, $tab2_hl, price($tvaval, 0, $outputlangs), 0, 'R', 1);
    +							}
    +						}
    +					}
    +	      		//}
    +				//Local tax 2 after VAT
    +				//if (! empty($conf->global->FACTURE_LOCAL_TAX2_OPTION) && $conf->global->FACTURE_LOCAL_TAX2_OPTION=='localtax2on')
    +				//{
    +					foreach( $this->localtax2 as $localtax_type => $localtax_rate )
    +					{
    +						if (in_array((string) $localtax_type, array('2','4','6'))) continue;
    +
    +						foreach( $localtax_rate as $tvakey => $tvaval )
    +						{
    +							if ($tvakey != 0)    // On affiche pas taux 0
    +							{
    +								//$this->atleastoneratenotnull++;
    +
    +								$index++;
    +								$pdf->SetXY($col1x, $tab2_top + $tab2_hl * $index);
    +
    +								$tvacompl='';
    +								if (preg_match('/\*/',$tvakey))
    +								{
    +									$tvakey=str_replace('*','',$tvakey);
    +									$tvacompl = " (".$outputlangs->transnoentities("NonPercuRecuperable").")";
    +								}
    +								$totalvat = $outputlangs->transcountrynoentities("TotalLT2",$mysoc->country_code).' ';
    +
    +								$totalvat.=vatrate(abs($tvakey),1).$tvacompl;
    +								$pdf->MultiCell($col2x-$col1x, $tab2_hl, $totalvat, 0, 'L', 1);
    +
    +								$pdf->SetXY($col2x, $tab2_top + $tab2_hl * $index);
    +								$pdf->MultiCell($largcol2, $tab2_hl, price($tvaval, 0, $outputlangs), 0, 'R', 1);
    +							}
    +						}
    +					}
    +				//}
    +
    +				// Total TTC
    +				$index++;
    +				$pdf->SetXY($col1x, $tab2_top + $tab2_hl * $index);
    +				$pdf->SetTextColor(0,0,60);
    +				$pdf->SetFillColor(224,224,224);
    +				$pdf->MultiCell($col2x-$col1x, $tab2_hl, $outputlangs->transnoentities("TotalTTC"), $useborder, 'L', 1);
    +
    +				$pdf->SetXY($col2x, $tab2_top + $tab2_hl * $index);
    +				$pdf->MultiCell($largcol2, $tab2_hl, price($total_ttc, 0, $outputlangs), $useborder, 'R', 1);
    +			}
    +		}
    +
    +		$pdf->SetTextColor(0,0,0);
    +
    +        $creditnoteamount=0;
    +        $depositsamount=0;
    +		//$creditnoteamount=$object->getSumCreditNotesUsed();
    +		//$depositsamount=$object->getSumDepositsUsed();
    +		//print "x".$creditnoteamount."-".$depositsamount;exit;
    +		$resteapayer = price2num($total_ttc - $deja_regle - $creditnoteamount - $depositsamount, 'MT');
    +		if (! empty($object->paye)) $resteapayer=0;
    +
    +		if ($deja_regle > 0)
    +		{
    +			// Already paid + Deposits
    +			$index++;
    +
    +			$pdf->SetXY($col1x, $tab2_top + $tab2_hl * $index);
    +			$pdf->MultiCell($col2x-$col1x, $tab2_hl, $outputlangs->transnoentities("AlreadyPaid"), 0, 'L', 0);
    +			$pdf->SetXY($col2x, $tab2_top + $tab2_hl * $index);
    +			$pdf->MultiCell($largcol2, $tab2_hl, price($deja_regle, 0, $outputlangs), 0, 'R', 0);
    +
    +			$index++;
    +			$pdf->SetTextColor(0,0,60);
    +			$pdf->SetFillColor(224,224,224);
    +			$pdf->SetXY($col1x, $tab2_top + $tab2_hl * $index);
    +			$pdf->MultiCell($col2x-$col1x, $tab2_hl, $outputlangs->transnoentities("RemainderToPay"), $useborder, 'L', 1);
    +
    +			$pdf->SetXY($col2x, $tab2_top + $tab2_hl * $index);
    +			$pdf->MultiCell($largcol2, $tab2_hl, price($resteapayer, 0, $outputlangs), $useborder, 'R', 1);
    +
    +			$pdf->SetFont('','', $default_font_size - 1);
    +			$pdf->SetTextColor(0,0,0);
    +		}
    +
    +		$index++;
    +		return ($tab2_top + ($tab2_hl * $index));
    +	}
    +
    +	/**
    +	 *   Show table for lines
    +	 *
    +	 *   @param		TCPDF		$pdf     		Object PDF
    +	 *   @param		string		$tab_top		Top position of table
    +	 *   @param		string		$tab_height		Height of table (rectangle)
    +	 *   @param		int			$nexY			Y (not used)
    +	 *   @param		Translate	$outputlangs	Langs object
    +	 *   @param		int			$hidetop		1=Hide top bar of array and title, 0=Hide nothing, -1=Hide only title
    +	 *   @param		int			$hidebottom		Hide bottom bar of array
    +	 *   @param		string		$currency		Currency code
    +	 *   @return	void
    +	 */
    +	private function _tableau(&$pdf, $tab_top, $tab_height, $nexY, $outputlangs, $hidetop=0, $hidebottom=0, $currency='')
    +	{
    +		global $conf;
    +
    +		// Force to disable hidetop and hidebottom
    +		$hidebottom=0;
    +		if ($hidetop) $hidetop=-1;
    +
    +		$currency = !empty($currency) ? $currency : $conf->currency;
    +		$default_font_size = pdf_getPDFFontSize($outputlangs);
    +
    +		// Amount in (at tab_top - 1)
    +		$pdf->SetTextColor(0,0,0);
    +		$pdf->SetFont('','', $default_font_size - 2);
    +
    +		if (empty($hidetop))
    +		{
    +			$titre = $outputlangs->transnoentities("AmountInCurrency",$outputlangs->transnoentitiesnoconv("Currency".$currency));
    +			$pdf->SetXY($this->page_largeur - $this->marge_droite - ($pdf->GetStringWidth($titre) + 3), $tab_top-4);
    +			$pdf->MultiCell(($pdf->GetStringWidth($titre) + 3), 2, $titre);
    +
    +			//$conf->global->MAIN_PDF_TITLE_BACKGROUND_COLOR='230,230,230';
    +			if (! empty($conf->global->MAIN_PDF_TITLE_BACKGROUND_COLOR)) $pdf->Rect($this->marge_gauche, $tab_top, $this->page_largeur-$this->marge_droite-$this->marge_gauche, 5, 'F', null, explode(',',$conf->global->MAIN_PDF_TITLE_BACKGROUND_COLOR));
    +		}
    +
    +		$pdf->SetDrawColor(128,128,128);
    +		$pdf->SetFont('','', $default_font_size - 1);
    +
    +		// Output Rect
    +		$this->printRect($pdf,$this->marge_gauche, $tab_top, $this->page_largeur-$this->marge_gauche-$this->marge_droite, $tab_height, $hidetop, $hidebottom);	// Rect prend une longueur en 3eme param et 4eme param
    +
    +
    +		foreach ($this->cols as $colKey => $colDef)
    +		{
    +		    if(!$this->getColumnStatus($colKey)) continue;
    +
    +		    // get title label
    +		    $colDef['title']['label'] = !empty($colDef['title']['label'])?$colDef['title']['label']:$outputlangs->transnoentities($colDef['title']['textkey']);
    +
    +		    // Add column separator
    +		    if(!empty($colDef['border-left'])){
    +		        $pdf->line($colDef['xStartPos'], $tab_top, $colDef['xStartPos'], $tab_top + $tab_height);
    +		    }
    +
    +		    if (empty($hidetop))
    +		    {
    +		      $pdf->SetXY($colDef['xStartPos'] + $colDef['title']['padding'][3], $tab_top + $colDef['title']['padding'][0] );
    +
    +		      $textWidth = $colDef['width'] - $colDef['title']['padding'][3] -$colDef['title']['padding'][1];
    +		      $pdf->MultiCell($textWidth,2,$colDef['title']['label'],'',$colDef['title']['align']);
    +		    }
    +		}
    +
    +		if (empty($hidetop)){
    +			$pdf->line($this->marge_gauche, $tab_top+5, $this->page_largeur-$this->marge_droite, $tab_top+5);	// line prend une position y en 2eme param et 4eme param
    +		}
    +	}
    +
    +	/**
    +	 *  Show top header of page.
    +	 *
    +	 *  @param	TCPDF		$pdf     		Object PDF
    +	 *  @param  Object		$object     	Object to show
    +	 *  @param  int	    	$showaddress    0=no, 1=yes
    +	 *  @param  Translate	$outputlangs	Object lang for output
    +	 *  @param	string		$titlekey		Translation key to show as title of document
    +	 *  @return	void
    +	 */
    +	private function _pagehead(&$pdf, $object, $showaddress, $outputlangs, $titlekey="PdfOrderTitle")
    +	{
    +		global $conf,$langs,$hookmanager;
    +
    +		// Translations
    +		$outputlangs->loadLangs(array("main", "bills", "propal", "orders", "companies"));
    +
    +		$default_font_size = pdf_getPDFFontSize($outputlangs);
    +
    +		pdf_pagehead($pdf,$outputlangs,$this->page_hauteur);
    +
    +		// Show Draft Watermark
    +		if($object->statut==0 && (! empty($conf->global->COMMANDE_DRAFT_WATERMARK)) )
    +		{
    +            pdf_watermark($pdf,$outputlangs,$this->page_hauteur,$this->page_largeur,'mm',$conf->global->COMMANDE_DRAFT_WATERMARK);
    +		}
    +
    +		$pdf->SetTextColor(0,0,60);
    +		$pdf->SetFont('','B', $default_font_size + 3);
    +
    +		$posy=$this->marge_haute;
    +		$posx=$this->page_largeur-$this->marge_droite-100;
    +
    +		$pdf->SetXY($this->marge_gauche,$posy);
    +
    +		// Logo
    +		if (empty($conf->global->PDF_DISABLE_MYCOMPANY_LOGO))
    +		{
    +			$logo=$conf->mycompany->dir_output.'/logos/'.$this->emetteur->logo;
    +			if ($this->emetteur->logo)
    +			{
    +				if (is_readable($logo))
    +				{
    +				    $height=pdf_getHeightForLogo($logo);
    +				    $pdf->Image($logo, $this->marge_gauche, $posy, 0, $height);	// width=0 (auto)
    +				}
    +				else
    +				{
    +					$pdf->SetTextColor(200,0,0);
    +					$pdf->SetFont('','B', $default_font_size -2);
    +					$pdf->MultiCell(100, 3, $outputlangs->transnoentities("ErrorLogoFileNotFound",$logo), 0, 'L');
    +					$pdf->MultiCell(100, 3, $outputlangs->transnoentities("ErrorGoToGlobalSetup"), 0, 'L');
    +				}
    +			}
    +			else
    +			{
    +				$text=$this->emetteur->name;
    +				$pdf->MultiCell(100, 4, $outputlangs->convToOutputCharset($text), 0, 'L');
    +			}
    +		}
    +
    +		$pdf->SetFont('','B', $default_font_size + 3);
    +		$pdf->SetXY($posx,$posy);
    +		$pdf->SetTextColor(0,0,60);
    +		$title=$outputlangs->transnoentities($titlekey);
    +		$pdf->MultiCell(100, 3, $title, '', 'R');
    +
    +		$pdf->SetFont('','B',$default_font_size);
    +
    +		$posy+=5;
    +		$pdf->SetXY($posx,$posy);
    +		$pdf->SetTextColor(0,0,60);
    +		$pdf->MultiCell(100, 4, $outputlangs->transnoentities("Ref")." : " . $outputlangs->convToOutputCharset($object->ref), '', 'R');
    +
    +		$posy+=1;
    +		$pdf->SetFont('','', $default_font_size - 1);
    +
    +		if ($object->ref_client)
    +		{
    +			$posy+=5;
    +			$pdf->SetXY($posx,$posy);
    +			$pdf->SetTextColor(0,0,60);
    +			$pdf->MultiCell(100, 3, $outputlangs->transnoentities("RefCustomer")." : " . $outputlangs->convToOutputCharset($object->ref_client), '', 'R');
    +		}
    +
    +		$posy+=4;
    +		$pdf->SetXY($posx,$posy);
    +		$pdf->SetTextColor(0,0,60);
    +		$pdf->MultiCell(100, 3, $outputlangs->transnoentities("OrderDate")." : " . dol_print_date($object->date,"%d %b %Y",false,$outputlangs,true), '', 'R');
    +
    +		// Get contact
    +		if (!empty($conf->global->DOC_SHOW_FIRST_SALES_REP))
    +		{
    +		    $arrayidcontact=$object->getIdContact('internal','SALESREPFOLL');
    +		    if (count($arrayidcontact) > 0)
    +		    {
    +                $usertmp=new User($this->db);
    +		        $usertmp->fetch($arrayidcontact[0]);
    +                $posy+=4;
    +                $pdf->SetXY($posx,$posy);
    +		        $pdf->SetTextColor(0,0,60);
    +		        $pdf->MultiCell(100, 3, $langs->trans("SalesRepresentative")." : ".$usertmp->getFullName($langs), '', 'R');
    +		    }
    +		}
    +
    +		$posy+=2;
    +
    +		$top_shift = 0;
    +		// Show list of linked objects
    +		$current_y = $pdf->getY();
    +		$posy = pdf_writeLinkedObjects($pdf, $object, $outputlangs, $posx, $posy, 100, 3, 'R', $default_font_size);
    +		if ($current_y < $pdf->getY())
    +		{
    +			$top_shift = $pdf->getY() - $current_y;
    +		}
    +
    +		if ($showaddress)
    +		{
    +			// Sender properties
    +			$carac_emetteur='';
    +		 	// Add internal contact of proposal if defined
    +			$arrayidcontact=$object->getIdContact('internal','SALESREPFOLL');
    +		 	if (count($arrayidcontact) > 0)
    +		 	{
    +		 		$object->fetch_user($arrayidcontact[0]);
    +		 		$labelbeforecontactname=($outputlangs->transnoentities("FromContactName")!='FromContactName'?$outputlangs->transnoentities("FromContactName"):$outputlangs->transnoentities("Name"));
    +		 		$carac_emetteur .= ($carac_emetteur ? "\n" : '' ).$labelbeforecontactname." ".$outputlangs->convToOutputCharset($object->user->getFullName($outputlangs))."\n";
    +		 	}
    +
    +		 	$carac_emetteur .= pdf_build_address($outputlangs, $this->emetteur, $object->thirdparty, '', 0, 'source', $object);
    +
    +			// Show sender
    +			$posy=42+$top_shift;
    +			$posx=$this->marge_gauche;
    +			if (! empty($conf->global->MAIN_INVERT_SENDER_RECIPIENT)) $posx=$this->page_largeur-$this->marge_droite-80;
    +			$hautcadre=40;
    +
    +			// Show sender frame
    +			$pdf->SetTextColor(0,0,0);
    +			$pdf->SetFont('','', $default_font_size - 2);
    +			$pdf->SetXY($posx,$posy-5);
    +			$pdf->MultiCell(66,5, $outputlangs->transnoentities("BillFrom").":", 0, 'L');
    +			$pdf->SetXY($posx,$posy);
    +			$pdf->SetFillColor(230,230,230);
    +			$pdf->MultiCell(82, $hautcadre, "", 0, 'R', 1);
    +			$pdf->SetTextColor(0,0,60);
    +
    +			// Show sender name
    +			$pdf->SetXY($posx+2,$posy+3);
    +			$pdf->SetFont('','B', $default_font_size);
    +			$pdf->MultiCell(80, 4, $outputlangs->convToOutputCharset($this->emetteur->name), 0, 'L');
    +			$posy=$pdf->getY();
    +
    +			// Show sender information
    +			$pdf->SetXY($posx+2,$posy);
    +			$pdf->SetFont('','', $default_font_size - 1);
    +			$pdf->MultiCell(80, 4, $carac_emetteur, 0, 'L');
    +
    +
    +
    +			// If CUSTOMER contact defined on order, we use it
    +			$usecontact=false;
    +			$arrayidcontact=$object->getIdContact('external','CUSTOMER');
    +			if (count($arrayidcontact) > 0)
    +			{
    +				$usecontact=true;
    +				$result=$object->fetch_contact($arrayidcontact[0]);
    +			}
    +
    +			//Recipient name
    +			// On peut utiliser le nom de la societe du contact
    +			if ($usecontact && !empty($conf->global->MAIN_USE_COMPANY_NAME_OF_CONTACT)) {
    +				$thirdparty = $object->contact;
    +			} else {
    +				$thirdparty = $object->thirdparty;
    +			}
    +
    +			$carac_client_name= pdfBuildThirdpartyName($thirdparty, $outputlangs);
    +
    +			$carac_client=pdf_build_address($outputlangs,$this->emetteur,$object->thirdparty,($usecontact?$object->contact:''),$usecontact,'target', $object);
    +
    +			// Show recipient
    +			$widthrecbox=100;
    +			if ($this->page_largeur < 210) $widthrecbox=84;	// To work with US executive format
    +			$posy=42+$top_shift;
    +			$posx=$this->page_largeur-$this->marge_droite-$widthrecbox;
    +			if (! empty($conf->global->MAIN_INVERT_SENDER_RECIPIENT)) $posx=$this->marge_gauche;
    +
    +			// Show recipient frame
    +			$pdf->SetTextColor(0,0,0);
    +			$pdf->SetFont('','', $default_font_size - 2);
    +			$pdf->SetXY($posx+2,$posy-5);
    +			$pdf->MultiCell($widthrecbox, 5, $outputlangs->transnoentities("BillTo").":",0,'L');
    +			$pdf->Rect($posx, $posy, $widthrecbox, $hautcadre);
    +
    +			// Show recipient name
    +			$pdf->SetXY($posx+2,$posy+3);
    +			$pdf->SetFont('','B', $default_font_size);
    +			$pdf->MultiCell($widthrecbox, 4, $carac_client_name, 0, 'L');
    +
    +			$posy = $pdf->getY();
    +
    +			// Show recipient information
    +			$pdf->SetFont('','', $default_font_size - 1);
    +			$pdf->SetXY($posx+2,$posy);
    +			$pdf->MultiCell($widthrecbox, 4, $carac_client, 0, 'L');
    +		}
    +
    +		$pdf->SetTextColor(0,0,0);
    +		return $top_shift;
    +	}
    +
    +	/**
    +	 *   	Show footer of page. Need this->emetteur object
    +     *
    +	 *   	@param	TCPDF		$pdf     			PDF
    +	 * 		@param	Object		$object				Object to show
    +	 *      @param	Translate	$outputlangs		Object lang for output
    +	 *      @param	int			$hidefreetext		1=Hide free text
    +	 *      @return	int								Return height of bottom margin including footer text
    +	 */
    +	private function _pagefoot(&$pdf,$object,$outputlangs,$hidefreetext=0)
    +	{
    +		global $conf;
    +		$showdetails=$conf->global->MAIN_GENERATE_DOCUMENTS_SHOW_FOOT_DETAILS;
    +		return pdf_pagefoot($pdf,$outputlangs,'ORDER_FREE_TEXT',$this->emetteur,$this->marge_basse,$this->marge_gauche,$this->page_hauteur,$object,$showdetails,$hidefreetext);
    +	}
    +
    +
    +
    +	/**
    +	 *   	Define Array Column Field
    +	 *
    +	 *   	@param	object			$object    		common object
    +	 *   	@param	Translate		$outputlangs    langs
    +	 *      @param	int				$hidedetails	Do not show line details
    +	 *      @param	int				$hidedesc		Do not show desc
    +	 *      @param	int				$hideref		Do not show ref
    +	 *      @return	null
    +	 */
    +    public function defineColumnField($object,$outputlangs,$hidedetails=0,$hidedesc=0,$hideref=0)
    +    {
    +	    global $conf, $hookmanager;
    +
    +	    // Default field style for content
    +	    $this->defaultContentsFieldsStyle = array(
    +	        'align' => 'R', // R,C,L
    +	        'padding' => array(0.5,0.5,0.5,0.5), // Like css 0 => top , 1 => right, 2 => bottom, 3 => left
    +	    );
    +
    +	    // Default field style for content
    +	    $this->defaultTitlesFieldsStyle = array(
    +	        'align' => 'C', // R,C,L
    +	        'padding' => array(0.5,0,0.5,0), // Like css 0 => top , 1 => right, 2 => bottom, 3 => left
    +	    );
    +
    +	    /*
    +	     * For exemple
    +	     $this->cols['theColKey'] = array(
    +	     'rank' => $rank, // int : use for ordering columns
    +	     'width' => 20, // the column width in mm
    +	     'title' => array(
    +	     'textkey' => 'yourLangKey', // if there is no label, yourLangKey will be translated to replace label
    +	     'label' => ' ', // the final label : used fore final generated text
    +	     'align' => 'L', // text alignement :  R,C,L
    +	     'padding' => array(0.5,0.5,0.5,0.5), // Like css 0 => top , 1 => right, 2 => bottom, 3 => left
    +	     ),
    +	     'content' => array(
    +	     'align' => 'L', // text alignement :  R,C,L
    +	     'padding' => array(0.5,0.5,0.5,0.5), // Like css 0 => top , 1 => right, 2 => bottom, 3 => left
    +	     ),
    +	     );
    +	     */
    +
    +	    $rank=0; // do not use negative rank
    +	    $this->cols['desc'] = array(
    +	        'rank' => $rank,
    +	        'width' => false, // only for desc
    +	        'status' => true,
    +	        'title' => array(
    +	            'textkey' => 'Designation', // use lang key is usefull in somme case with module
    +	            'align' => 'L',
    +	            // 'textkey' => 'yourLangKey', // if there is no label, yourLangKey will be translated to replace label
    +	            // 'label' => ' ', // the final label
    +	            'padding' => array(0.5,0.5,0.5,0.5), // Like css 0 => top , 1 => right, 2 => bottom, 3 => left
    +	        ),
    +	        'content' => array(
    +	            'align' => 'L',
    +	        ),
    +	    );
    +
    +	    $rank = $rank + 10;
    +	    $this->cols['photo'] = array(
    +	        'rank' => $rank,
    +	        'width' => (empty($conf->global->MAIN_DOCUMENTS_WITH_PICTURE_WIDTH)?20:$conf->global->MAIN_DOCUMENTS_WITH_PICTURE_WIDTH), // in mm
    +	        'status' => false,
    +	        'title' => array(
    +	            'textkey' => 'Photo',
    +	            'label' => ' '
    +	        ),
    +	        'content' => array(
    +	            'padding' => array(0,0,0,0), // Like css 0 => top , 1 => right, 2 => bottom, 3 => left
    +	        ),
    +	        'border-left' => false, // remove left line separator
    +	    );
    +
    +	    if (! empty($conf->global->MAIN_GENERATE_ORDERS_WITH_PICTURE))
    +	    {
    +	        $this->cols['photo']['status'] = true;
    +	    }
    +
    +
    +	    $rank = $rank + 10;
    +	    $this->cols['vat'] = array(
    +	        'rank' => $rank,
    +	        'status' => false,
    +	        'width' => 16, // in mm
    +	        'title' => array(
    +	            'textkey' => 'VAT'
    +	        ),
    +	        'border-left' => true, // add left line separator
    +	    );
    +
    +	    if (empty($conf->global->MAIN_GENERATE_DOCUMENTS_WITHOUT_VAT) && empty($conf->global->MAIN_GENERATE_DOCUMENTS_WITHOUT_VAT_COLUMN))
    +	    {
    +	        $this->cols['vat']['status'] = true;
    +	    }
    +
    +	    $rank = $rank + 10;
    +	    $this->cols['subprice'] = array(
    +	        'rank' => $rank,
    +	        'width' => 19, // in mm
    +	        'status' => true,
    +	        'title' => array(
    +	            'textkey' => 'PriceUHT'
    +	        ),
    +	        'border-left' => true, // add left line separator
    +	    );
    +
    +	    $rank = $rank + 10;
    +	    $this->cols['qty'] = array(
    +	        'rank' => $rank,
    +	        'width' => 16, // in mm
    +	        'status' => true,
    +	        'title' => array(
    +	            'textkey' => 'Qty'
    +	        ),
    +	        'border-left' => true, // add left line separator
    +	    );
    +
    +	    $rank = $rank + 10;
    +	    $this->cols['progress'] = array(
    +	        'rank' => $rank,
    +	        'width' => 19, // in mm
    +	        'status' => false,
    +	        'title' => array(
    +	            'textkey' => 'Progress'
    +	        ),
    +	        'border-left' => false, // add left line separator
    +	    );
    +
    +	    if($this->situationinvoice)
    +	    {
    +	        $this->cols['progress']['status'] = true;
    +	    }
    +
    +	    $rank = $rank + 10;
    +	    $this->cols['unit'] = array(
    +	        'rank' => $rank,
    +	        'width' => 11, // in mm
    +	        'status' => false,
    +	        'title' => array(
    +	            'textkey' => 'Unit'
    +	        ),
    +	        'border-left' => true, // add left line separator
    +	    );
    +	    if($conf->global->PRODUCT_USE_UNITS){
    +	        $this->cols['unit']['status'] = true;
    +	    }
    +
    +	    $rank = $rank + 10;
    +	    $this->cols['discount'] = array(
    +	        'rank' => $rank,
    +	        'width' => 13, // in mm
    +	        'status' => false,
    +	        'title' => array(
    +	            'textkey' => 'ReductionShort'
    +	        ),
    +	        'border-left' => true, // add left line separator
    +	    );
    +	    if ($this->atleastonediscount){
    +	        $this->cols['discount']['status'] = true;
    +	    }
    +
    +	    $rank = $rank + 10;
    +	    $this->cols['totalexcltax'] = array(
    +	        'rank' => $rank,
    +	        'width' => 26, // in mm
    +	        'status' => true,
    +	        'title' => array(
    +	            'textkey' => 'TotalHT'
    +	        ),
    +	        'border-left' => true, // add left line separator
    +	    );
    +
    +
    +	    $parameters=array(
    +	        'object' => $object,
    +	        'outputlangs' => $outputlangs,
    +	        'hidedetails' => $hidedetails,
    +	        'hidedesc' => $hidedesc,
    +	        'hideref' => $hideref
    +	    );
    +
    +	    $reshook=$hookmanager->executeHooks('defineColumnField',$parameters,$this);    // Note that $object may have been modified by hook
    +	    if ($reshook < 0)
    +	    {
    +	        setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
    +	    }
    +	    elseif (empty($reshook))
    +	    {
    +	        $this->cols = array_replace($this->cols, $hookmanager->resArray); // array_replace is used to preserve keys
    +	    }
    +	    else
    +	    {
    +	        $this->cols = $hookmanager->resArray;
    +	    }
    +	}
    +}
    diff --git a/htdocs/core/modules/commande/modules_commande.php b/htdocs/core/modules/commande/modules_commande.php
    index 1a4b732246d..7a1ffea8792 100644
    --- a/htdocs/core/modules/commande/modules_commande.php
    +++ b/htdocs/core/modules/commande/modules_commande.php
    @@ -39,10 +39,6 @@ require_once DOL_DOCUMENT_ROOT.'/core/class/discount.class.php';
      */
     abstract class ModelePDFCommandes extends CommonDocGenerator
     {
    -	/**
    -	 * @var string Error code (or message)
    -	 */
    -	public $error='';
     
         // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
         /**
    diff --git a/htdocs/core/modules/facture/doc/pdf_crabe.modules.php b/htdocs/core/modules/facture/doc/pdf_crabe.modules.php
    index af770999fda..c4d69424cb2 100644
    --- a/htdocs/core/modules/facture/doc/pdf_crabe.modules.php
    +++ b/htdocs/core/modules/facture/doc/pdf_crabe.modules.php
    @@ -1598,27 +1598,30 @@ class pdf_crabe extends ModelePDFFactures
     		$pdf->SetXY($this->marge_gauche,$posy);
     
     		// Logo
    -		$logo=$conf->mycompany->dir_output.'/logos/'.$this->emetteur->logo;
    -		if ($this->emetteur->logo)
    +		if (empty($conf->global->PDF_DISABLE_MYCOMPANY_LOGO))
     		{
    -			if (is_readable($logo))
    +			$logo=$conf->mycompany->dir_output.'/logos/'.$this->emetteur->logo;
    +			if ($this->emetteur->logo)
     			{
    -			    $height=pdf_getHeightForLogo($logo);
    -				$pdf->Image($logo, $this->marge_gauche, $posy, 0, $height);	// width=0 (auto)
    +				if (is_readable($logo))
    +				{
    +				    $height=pdf_getHeightForLogo($logo);
    +					$pdf->Image($logo, $this->marge_gauche, $posy, 0, $height);	// width=0 (auto)
    +				}
    +				else
    +				{
    +					$pdf->SetTextColor(200,0,0);
    +					$pdf->SetFont('','B',$default_font_size - 2);
    +					$pdf->MultiCell($w, 3, $outputlangs->transnoentities("ErrorLogoFileNotFound",$logo), 0, 'L');
    +					$pdf->MultiCell($w, 3, $outputlangs->transnoentities("ErrorGoToGlobalSetup"), 0, 'L');
    +				}
     			}
     			else
     			{
    -				$pdf->SetTextColor(200,0,0);
    -				$pdf->SetFont('','B',$default_font_size - 2);
    -				$pdf->MultiCell($w, 3, $outputlangs->transnoentities("ErrorLogoFileNotFound",$logo), 0, 'L');
    -				$pdf->MultiCell($w, 3, $outputlangs->transnoentities("ErrorGoToGlobalSetup"), 0, 'L');
    +				$text=$this->emetteur->name;
    +				$pdf->MultiCell($w, 4, $outputlangs->convToOutputCharset($text), 0, 'L');
     			}
     		}
    -		else
    -		{
    -			$text=$this->emetteur->name;
    -			$pdf->MultiCell($w, 4, $outputlangs->convToOutputCharset($text), 0, 'L');
    -		}
     
     		$pdf->SetFont('','B', $default_font_size + 3);
     		$pdf->SetXY($posx,$posy);
    diff --git a/htdocs/core/modules/facture/doc/pdf_sponge.modules.php b/htdocs/core/modules/facture/doc/pdf_sponge.modules.php
    new file mode 100644
    index 00000000000..d03d60f50fe
    --- /dev/null
    +++ b/htdocs/core/modules/facture/doc/pdf_sponge.modules.php
    @@ -0,0 +1,2027 @@
    +<?php
    +/* Copyright (C) 2004-2014	Laurent Destailleur	<eldy@users.sourceforge.net>
    + * Copyright (C) 2005-2012	Regis Houssin		<regis.houssin@capnetworks.com>
    + * Copyright (C) 2008		Raphael Bertrand		<raphael.bertrand@resultic.fr>
    + * Copyright (C) 2010-2014	Juanjo Menent		<jmenent@2byte.es>
    + * Copyright (C) 2012		Christophe Battarel	<christophe.battarel@altairis.fr>
    + * Copyright (C) 2012		Cédric Salvador		<csalvador@gpcsolutions.fr>
    + * Copyright (C) 2012-2014	Raphaël Doursenaud	<rdoursenaud@gpcsolutions.fr>
    + * Copyright (C) 2015		Marcos García		<marcosgdf@gmail.com>
    + * Copyright (C) 2017		Ferran Marcet		<fmarcet@2byte.es>
    + * Copyright (C) 2018       Frédéric France         <frederic.france@netlogic.fr>
    + *
    + * This program is free software; you can redistribute it and/or modify
    + * it under the terms of the GNU General Public License as published by
    + * the Free Software Foundation; either version 3 of the License, or
    + * (at your option) any later version.
    + *
    + * This program is distributed in the hope that it will be useful,
    + * but WITHOUT ANY WARRANTY; without even the implied warranty of
    + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    + * GNU General Public License for more details.
    + *
    + * You should have received a copy of the GNU General Public License
    + * along with this program. If not, see <http://www.gnu.org/licenses/>.
    + * or see http://www.gnu.org/
    + */
    +
    +/**
    + *	\file       htdocs/core/modules/facture/doc/pdf_sponge.modules.php
    + *	\ingroup    facture
    + *	\brief      File of class to generate customers invoices from sponge model
    + */
    +
    +require_once DOL_DOCUMENT_ROOT.'/core/modules/facture/modules_facture.php';
    +require_once DOL_DOCUMENT_ROOT.'/product/class/product.class.php';
    +require_once DOL_DOCUMENT_ROOT.'/core/lib/company.lib.php';
    +require_once DOL_DOCUMENT_ROOT.'/core/lib/functions2.lib.php';
    +require_once DOL_DOCUMENT_ROOT.'/core/lib/pdf.lib.php';
    +
    +
    +/**
    + *	Class to manage PDF invoice template sponge
    + */
    +class pdf_sponge extends ModelePDFFactures
    +{
    +     /**
    +     * @var DoliDb Database handler
    +     */
    +    public $db;
    +
    +	/**
    +     * @var string model name
    +     */
    +    public $name;
    +
    +	/**
    +     * @var string model description (short text)
    +     */
    +    public $description;
    +
    +    /**
    +     * @var int 	Save the name of generated file as the main doc when generating a doc with this template
    +     */
    +    public $update_main_doc_field;
    +
    +	/**
    +     * @var string document type
    +     */
    +    public $type;
    +
    +	/**
    +     * @var array Minimum version of PHP required by module.
    +	 * e.g.: PHP ≥ 5.3 = array(5, 3)
    +     */
    +	public $phpmin = array(5, 2);
    +
    +	/**
    +     * Dolibarr version of the loaded document
    +     * @public string
    +     */
    +	public $version = 'development';
    +
    +    public $page_largeur;
    +    public $page_hauteur;
    +    public $format;
    +	public $marge_gauche;
    +	public $marge_droite;
    +	public $marge_haute;
    +	public $marge_basse;
    +
    +	public $emetteur;	// Objet societe qui emet
    +
    +	/**
    +	 * @var bool Situation invoice type
    +	 */
    +	public $situationinvoice;
    +
    +	/**
    +	 * @var float X position for the situation progress column
    +	 */
    +	public $posxprogress;
    +
    +
    +	/**
    +	 *	Constructor
    +	 *
    +	 *  @param		DoliDB		$db      Database handler
    +	 */
    +	function __construct($db)
    +	{
    +		global $conf,$langs,$mysoc;
    +
    +		// Translations
    +		$langs->loadLangs(array("main", "bills"));
    +
    +		$this->db = $db;
    +		$this->name = "sponge";
    +		$this->description = $langs->trans('PDFSpongeDescription');
    +		$this->update_main_doc_field = 1;		// Save the name of generated file as the main doc when generating a doc with this template
    +
    +		// Dimensiont page
    +		$this->type = 'pdf';
    +		$formatarray=pdf_getFormat();
    +		$this->page_largeur = $formatarray['width'];
    +		$this->page_hauteur = $formatarray['height'];
    +		$this->format = array($this->page_largeur,$this->page_hauteur);
    +		$this->marge_gauche=isset($conf->global->MAIN_PDF_MARGIN_LEFT)?$conf->global->MAIN_PDF_MARGIN_LEFT:10;
    +		$this->marge_droite=isset($conf->global->MAIN_PDF_MARGIN_RIGHT)?$conf->global->MAIN_PDF_MARGIN_RIGHT:10;
    +		$this->marge_haute =isset($conf->global->MAIN_PDF_MARGIN_TOP)?$conf->global->MAIN_PDF_MARGIN_TOP:10;
    +		$this->marge_basse =isset($conf->global->MAIN_PDF_MARGIN_BOTTOM)?$conf->global->MAIN_PDF_MARGIN_BOTTOM:10;
    +
    +		$this->option_logo = 1;                    // Affiche logo
    +		$this->option_tva = 1;                     // Gere option tva FACTURE_TVAOPTION
    +		$this->option_modereg = 1;                 // Affiche mode reglement
    +		$this->option_condreg = 1;                 // Affiche conditions reglement
    +		$this->option_codeproduitservice = 1;      // Affiche code produit-service
    +		$this->option_multilang = 1;               // Dispo en plusieurs langues
    +		$this->option_escompte = 1;                // Affiche si il y a eu escompte
    +		$this->option_credit_note = 1;             // Support credit notes
    +		$this->option_freetext = 1;				   // Support add of a personalised text
    +		$this->option_draft_watermark = 1;		   // Support add of a watermark on drafts
    +
    +		$this->franchise=!$mysoc->tva_assuj;
    +
    +		// Get source company
    +		$this->emetteur=$mysoc;
    +		if (empty($this->emetteur->country_code)) $this->emetteur->country_code=substr($langs->defaultlang,-2);    // By default, if was not defined
    +
    +		// Define position of columns
    +		$this->posxdesc=$this->marge_gauche+1; // used for notes ans other stuff
    +
    +		//  Use new system for position of columns, view  $this->defineColumnField()
    +
    +		$this->tva=array();
    +		$this->localtax1=array();
    +		$this->localtax2=array();
    +		$this->atleastoneratenotnull=0;
    +		$this->atleastonediscount=0;
    +		$this->situationinvoice=false;
    +	}
    +
    +
    +    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
    +    /**
    +     *  Function to build pdf onto disk
    +     *
    +     *  @param		Object		$object				Object to generate
    +     *  @param		Translate	$outputlangs		Lang output object
    +     *  @param		string		$srctemplatepath	Full path of source filename for generator using a template file
    +     *  @param		int			$hidedetails		Do not show line details
    +     *  @param		int			$hidedesc			Do not show desc
    +     *  @param		int			$hideref			Do not show ref
    +     *  @return     int         	    			1=OK, 0=KO
    +	 */
    +	public function write_file($object,$outputlangs,$srctemplatepath='',$hidedetails=0,$hidedesc=0,$hideref=0)
    +	{
    +	    // phpcs:enable
    +	    global $user,$langs,$conf,$mysoc,$db,$hookmanager,$nblignes;
    +
    +	    if (! is_object($outputlangs)) $outputlangs=$langs;
    +	    // For backward compatibility with FPDF, force output charset to ISO, because FPDF expect text to be encoded in ISO
    +	    if (! empty($conf->global->MAIN_USE_FPDF)) $outputlangs->charset_output='ISO-8859-1';
    +
    +	    // Translations
    +	    $outputlangs->loadLangs(array("main", "bills", "products", "dict", "companies"));
    +
    +	    $nblignes = count($object->lines);
    +
    +	    // Loop on each lines to detect if there is at least one image to show
    +	    $realpatharray=array();
    +	    $this->atleastonephoto = false;
    +	    if (! empty($conf->global->MAIN_GENERATE_INVOICES_WITH_PICTURE))
    +	    {
    +	        $objphoto = new Product($this->db);
    +
    +	        for ($i = 0 ; $i < $nblignes ; $i++)
    +	        {
    +	            if (empty($object->lines[$i]->fk_product)) continue;
    +
    +	            $objphoto->fetch($object->lines[$i]->fk_product);
    +	            //var_dump($objphoto->ref);exit;
    +	            if (! empty($conf->global->PRODUCT_USE_OLD_PATH_FOR_PHOTO))
    +	            {
    +	                $pdir[0] = get_exdir($objphoto->id,2,0,0,$objphoto,'product') . $objphoto->id ."/photos/";
    +	                $pdir[1] = get_exdir(0,0,0,0,$objphoto,'product') . dol_sanitizeFileName($objphoto->ref).'/';
    +	            }
    +	            else
    +	            {
    +	                $pdir[0] = get_exdir(0,0,0,0,$objphoto,'product') . dol_sanitizeFileName($objphoto->ref).'/';				// default
    +	                $pdir[1] = get_exdir($objphoto->id,2,0,0,$objphoto,'product') . $objphoto->id ."/photos/";	// alternative
    +	            }
    +
    +	            $arephoto = false;
    +	            foreach ($pdir as $midir)
    +	            {
    +	                if (! $arephoto)
    +	                {
    +	                    $dir = $conf->product->dir_output.'/'.$midir;
    +
    +	                    foreach ($objphoto->liste_photos($dir,1) as $key => $obj)
    +	                    {
    +	                        if (empty($conf->global->CAT_HIGH_QUALITY_IMAGES))		// If CAT_HIGH_QUALITY_IMAGES not defined, we use thumb if defined and then original photo
    +	                        {
    +	                            if ($obj['photo_vignette'])
    +	                            {
    +	                                $filename= $obj['photo_vignette'];
    +	                            }
    +	                            else
    +	                            {
    +	                                $filename=$obj['photo'];
    +	                            }
    +	                        }
    +	                        else
    +	                        {
    +	                            $filename=$obj['photo'];
    +	                        }
    +
    +	                        $realpath = $dir.$filename;
    +	                        $arephoto = true;
    +	                        $this->atleastonephoto = true;
    +	                    }
    +	                }
    +	            }
    +
    +	            if ($realpath && $arephoto) $realpatharray[$i]=$realpath;
    +	        }
    +	    }
    +
    +	    //if (count($realpatharray) == 0) $this->posxpicture=$this->posxtva;
    +
    +	    if ($conf->facture->dir_output)
    +	    {
    +	        $object->fetch_thirdparty();
    +
    +	        $deja_regle = $object->getSommePaiement(($conf->multicurrency->enabled && $object->multicurrency_tx != 1) ? 1 : 0);
    +	        $amount_credit_notes_included = $object->getSumCreditNotesUsed(($conf->multicurrency->enabled && $object->multicurrency_tx != 1) ? 1 : 0);
    +	        $amount_deposits_included = $object->getSumDepositsUsed(($conf->multicurrency->enabled && $object->multicurrency_tx != 1) ? 1 : 0);
    +
    +	        // Definition of $dir and $file
    +	        if ($object->specimen)
    +	        {
    +	            $dir = $conf->facture->dir_output;
    +	            $file = $dir . "/SPECIMEN.pdf";
    +	        }
    +	        else
    +	        {
    +	            $objectref = dol_sanitizeFileName($object->ref);
    +	            $dir = $conf->facture->dir_output . "/" . $objectref;
    +	            $file = $dir . "/" . $objectref . ".pdf";
    +	        }
    +	        if (! file_exists($dir))
    +	        {
    +	            if (dol_mkdir($dir) < 0)
    +	            {
    +	                $this->error=$langs->transnoentities("ErrorCanNotCreateDir",$dir);
    +	                return 0;
    +	            }
    +	        }
    +
    +	        if (file_exists($dir))
    +	        {
    +	            // Add pdfgeneration hook
    +	            if (! is_object($hookmanager))
    +	            {
    +	                include_once DOL_DOCUMENT_ROOT.'/core/class/hookmanager.class.php';
    +	                $hookmanager=new HookManager($this->db);
    +	            }
    +	            $hookmanager->initHooks(array('pdfgeneration'));
    +	            $parameters=array('file'=>$file,'object'=>$object,'outputlangs'=>$outputlangs);
    +	            global $action;
    +	            $reshook=$hookmanager->executeHooks('beforePDFCreation',$parameters,$object,$action);    // Note that $action and $object may have been modified by some hooks
    +
    +	            // Set nblignes with the new facture lines content after hook
    +	            $nblignes = count($object->lines);
    +	            $nbpayments = count($object->getListOfPayments());
    +
    +	            // Create pdf instance
    +	            $pdf=pdf_getInstance($this->format);
    +	            $default_font_size = pdf_getPDFFontSize($outputlangs);	// Must be after pdf_getInstance
    +	            $pdf->SetAutoPageBreak(1,0);
    +
    +	            $heightforinfotot = 50+(4*$nbpayments);	// Height reserved to output the info and total part and payment part
    +	            $heightforfreetext= (isset($conf->global->MAIN_PDF_FREETEXT_HEIGHT)?$conf->global->MAIN_PDF_FREETEXT_HEIGHT:5);	// Height reserved to output the free text on last page
    +	            $heightforfooter = $this->marge_basse + (empty($conf->global->MAIN_GENERATE_DOCUMENTS_SHOW_FOOT_DETAILS)?12:22);	// Height reserved to output the footer (value include bottom margin)
    +
    +	            if (class_exists('TCPDF'))
    +	            {
    +	                $pdf->setPrintHeader(false);
    +	                $pdf->setPrintFooter(false);
    +	            }
    +	            $pdf->SetFont(pdf_getPDFFont($outputlangs));
    +
    +	            // Set path to the background PDF File
    +                if (! empty($conf->global->MAIN_ADD_PDF_BACKGROUND))
    +	            {
    +	                $pagecount = $pdf->setSourceFile($conf->mycompany->dir_output.'/'.$conf->global->MAIN_ADD_PDF_BACKGROUND);
    +	                $tplidx = $pdf->importPage(1);
    +	            }
    +
    +	            $pdf->Open();
    +	            $pagenb=0;
    +	            $pdf->SetDrawColor(128,128,128);
    +
    +	            $pdf->SetTitle($outputlangs->convToOutputCharset($object->ref));
    +	            $pdf->SetSubject($outputlangs->transnoentities("PdfInvoiceTitle"));
    +	            $pdf->SetCreator("Dolibarr ".DOL_VERSION);
    +	            $pdf->SetAuthor($outputlangs->convToOutputCharset($user->getFullName($outputlangs)));
    +	            $pdf->SetKeyWords($outputlangs->convToOutputCharset($object->ref)." ".$outputlangs->transnoentities("PdfInvoiceTitle")." ".$outputlangs->convToOutputCharset($object->thirdparty->name));
    +	            if (! empty($conf->global->MAIN_DISABLE_PDF_COMPRESSION)) $pdf->SetCompression(false);
    +
    +	            $pdf->SetMargins($this->marge_gauche, $this->marge_haute, $this->marge_droite);   // Left, Top, Right
    +
    +	            // Does we have at least one line with discount $this->atleastonediscount
    +	            foreach ($object->lines as $line) {
    +	               if ($line->remise_percent){
    +	                    $this->atleastonediscount = true;
    +	                    break;
    +	               }
    +	            }
    +
    +
    +	            // Situation invoice handling
    +	            if ($object->situation_cycle_ref)
    +	            {
    +	                $this->situationinvoice = true;
    +	            }
    +
    +	            // New page
    +	            $pdf->AddPage();
    +	            if (! empty($tplidx)) $pdf->useTemplate($tplidx);
    +	            $pagenb++;
    +
    +	            $top_shift = $this->_pagehead($pdf, $object, 1, $outputlangs);
    +	            $pdf->SetFont('','', $default_font_size - 1);
    +	            $pdf->MultiCell(0, 3, '');		// Set interline to 3
    +	            $pdf->SetTextColor(0,0,0);
    +
    +	            $tab_top = 90+$top_shift;
    +	            $tab_top_newpage = (empty($conf->global->MAIN_PDF_DONOTREPEAT_HEAD)?42+$top_shift:10);
    +	            $tab_height = 130-$top_shift;
    +	            $tab_height_newpage = 150;
    +	            if (empty($conf->global->MAIN_PDF_DONOTREPEAT_HEAD)) $tab_height_newpage -= $top_shift;
    +
    +	            // Incoterm
    +	            $height_incoterms = 0;
    +	            if ($conf->incoterm->enabled)
    +	            {
    +	                $desc_incoterms = $object->getIncotermsForPDF();
    +	                if ($desc_incoterms)
    +	                {
    +						$tab_top -= 2;
    +
    +	                    $pdf->SetFont('','', $default_font_size - 1);
    +	                    $pdf->writeHTMLCell(190, 3, $this->posxdesc-1, $tab_top-1, dol_htmlentitiesbr($desc_incoterms), 0, 1);
    +	                    $nexY = max($pdf->GetY(),$nexY);
    +	                    $height_incoterms=$nexY-$tab_top;
    +
    +	                    // Rect prend une longueur en 3eme param
    +	                    $pdf->SetDrawColor(192,192,192);
    +	                    $pdf->Rect($this->marge_gauche, $tab_top-1, $this->page_largeur-$this->marge_gauche-$this->marge_droite, $height_incoterms+1);
    +
    +	                    $tab_top = $nexY+6;
    +	                    $height_incoterms += 4;
    +	                }
    +	            }
    +
    +	            // Affiche notes
    +	            $notetoshow=empty($object->note_public)?'':$object->note_public;
    +	            if (! empty($conf->global->MAIN_ADD_SALE_REP_SIGNATURE_IN_NOTE))
    +	            {
    +	                // Get first sale rep
    +	                if (is_object($object->thirdparty))
    +	                {
    +	                    $salereparray=$object->thirdparty->getSalesRepresentatives($user);
    +	                    $salerepobj=new User($this->db);
    +	                    $salerepobj->fetch($salereparray[0]['id']);
    +	                    if (! empty($salerepobj->signature)) $notetoshow=dol_concatdesc($notetoshow, $salerepobj->signature);
    +	                }
    +	            }
    +
    +	            $pagenb = $pdf->getPage();
    +	            if ($notetoshow)
    +	            {
    +					$tab_top -= 2;
    +
    +	                $tab_width = $this->page_largeur-$this->marge_gauche-$this->marge_droite;
    +	                $pageposbeforenote = $pagenb;
    +
    +	                $substitutionarray=pdf_getSubstitutionArray($outputlangs, null, $object);
    +	                complete_substitutions_array($substitutionarray, $outputlangs, $object);
    +	                $notetoshow = make_substitutions($notetoshow, $substitutionarray, $outputlangs);
    +
    +
    +	                $pdf->startTransaction();
    +
    +	                $pdf->SetFont('','', $default_font_size - 1);
    +	                $pdf->writeHTMLCell(190, 3, $this->posxdesc-1, $tab_top, dol_htmlentitiesbr($notetoshow), 0, 1);
    +	                // Description
    +	                $pageposafternote=$pdf->getPage();
    +	                $posyafter = $pdf->GetY();
    +
    +	                if($pageposafternote>$pageposbeforenote )
    +	                {
    +	                    $pdf->rollbackTransaction(true);
    +
    +	                    // prepar pages to receive notes
    +	                    while ($pagenb < $pageposafternote) {
    +	                        $pdf->AddPage();
    +	                        $pagenb++;
    +	                        if (! empty($tplidx)) $pdf->useTemplate($tplidx);
    +	                        if (empty($conf->global->MAIN_PDF_DONOTREPEAT_HEAD)) $this->_pagehead($pdf, $object, 0, $outputlangs);
    +	                        // $this->_pagefoot($pdf,$object,$outputlangs,1);
    +	                        $pdf->setTopMargin($tab_top_newpage);
    +	                        // The only function to edit the bottom margin of current page to set it.
    +	                        $pdf->setPageOrientation('', 1, $heightforfooter + $heightforfreetext);
    +	                    }
    +
    +	                    // back to start
    +	                    $pdf->setPage($pageposbeforenote);
    +	                    $pdf->setPageOrientation('', 1, $heightforfooter + $heightforfreetext);
    +	                    $pdf->SetFont('','', $default_font_size - 1);
    +	                    $pdf->writeHTMLCell(190, 3, $this->posxdesc-1, $tab_top, dol_htmlentitiesbr($notetoshow), 0, 1);
    +	                    $pageposafternote=$pdf->getPage();
    +
    +	                    $posyafter = $pdf->GetY();
    +
    +	                    if ($posyafter > ($this->page_hauteur - ($heightforfooter+$heightforfreetext+20)))	// There is no space left for total+free text
    +	                    {
    +	                        $pdf->AddPage('','',true);
    +	                        $pagenb++;
    +	                        $pageposafternote++;
    +	                        $pdf->setPage($pageposafternote);
    +	                        $pdf->setTopMargin($tab_top_newpage);
    +	                        // The only function to edit the bottom margin of current page to set it.
    +	                        $pdf->setPageOrientation('', 1, $heightforfooter + $heightforfreetext);
    +	                        //$posyafter = $tab_top_newpage;
    +	                    }
    +
    +
    +	                    // apply note frame to previus pages
    +	                    $i = $pageposbeforenote;
    +	                    while ($i < $pageposafternote) {
    +	                        $pdf->setPage($i);
    +
    +
    +	                        $pdf->SetDrawColor(128,128,128);
    +	                        // Draw note frame
    +	                        if($i>$pageposbeforenote){
    +	                            $height_note = $this->page_hauteur - ($tab_top_newpage + $heightforfooter);
    +	                            $pdf->Rect($this->marge_gauche, $tab_top_newpage-1, $tab_width, $height_note + 1);
    +	                        }
    +	                        else{
    +	                            $height_note = $this->page_hauteur - ($tab_top + $heightforfooter);
    +	                            $pdf->Rect($this->marge_gauche, $tab_top-1, $tab_width, $height_note + 1);
    +	                        }
    +
    +	                        // Add footer
    +	                        $pdf->setPageOrientation('', 1, 0);	// The only function to edit the bottom margin of current page to set it.
    +	                        $this->_pagefoot($pdf,$object,$outputlangs,1);
    +
    +	                        $i++;
    +	                    }
    +
    +	                    // apply note frame to last page
    +	                    $pdf->setPage($pageposafternote);
    +	                    if (! empty($tplidx)) $pdf->useTemplate($tplidx);
    +	                    if (empty($conf->global->MAIN_PDF_DONOTREPEAT_HEAD)) $this->_pagehead($pdf, $object, 0, $outputlangs);
    +	                    $height_note=$posyafter-$tab_top_newpage;
    +	                    $pdf->Rect($this->marge_gauche, $tab_top_newpage-1, $tab_width, $height_note+1);
    +
    +	                }
    +	                else // No pagebreak
    +	                {
    +	                    $pdf->commitTransaction();
    +	                    $posyafter = $pdf->GetY();
    +	                    $height_note=$posyafter-$tab_top;
    +	                    $pdf->Rect($this->marge_gauche, $tab_top-1, $tab_width, $height_note+1);
    +
    +
    +	                    if($posyafter > ($this->page_hauteur - ($heightforfooter+$heightforfreetext+20)) )
    +	                    {
    +	                        // not enough space, need to add page
    +	                        $pdf->AddPage('','',true);
    +	                        $pagenb++;
    +	                        $pageposafternote++;
    +	                        $pdf->setPage($pageposafternote);
    +	                        if (! empty($tplidx)) $pdf->useTemplate($tplidx);
    +	                        if (empty($conf->global->MAIN_PDF_DONOTREPEAT_HEAD)) $this->_pagehead($pdf, $object, 0, $outputlangs);
    +
    +	                        $posyafter = $tab_top_newpage;
    +	                    }
    +
    +	                }
    +
    +	                $tab_height = $tab_height - $height_note;
    +	                $tab_top = $posyafter +6;
    +	            }
    +	            else
    +	            {
    +	                $height_note=0;
    +	            }
    +
    +	            $iniY = $tab_top + 7;
    +	            $curY = $tab_top + 7;
    +	            $nexY = $tab_top + 7;
    +
    +	            // Use new auto collum system
    +	            $this->prepareArrayColumnField($object,$outputlangs,$hidedetails,$hidedesc,$hideref);
    +
    +	            // Loop on each lines
    +	            $pageposbeforeprintlines=$pdf->getPage();
    +	            $pagenb = $pageposbeforeprintlines;
    +	            for ($i = 0; $i < $nblignes; $i++)
    +	            {
    +
    +	                $curY = $nexY;
    +	                $pdf->SetFont('','', $default_font_size - 1);   // Into loop to work with multipage
    +	                $pdf->SetTextColor(0,0,0);
    +
    +	                // Define size of image if we need it
    +	                $imglinesize=array();
    +	                if (! empty($realpatharray[$i])) $imglinesize=pdf_getSizeForImage($realpatharray[$i]);
    +
    +	                $pdf->setTopMargin($tab_top_newpage);
    +	                $pdf->setPageOrientation('', 1, $heightforfooter+$heightforfreetext+$heightforinfotot);	// The only function to edit the bottom margin of current page to set it.
    +	                $pageposbefore=$pdf->getPage();
    +
    +	                $showpricebeforepagebreak=1;
    +	                $posYAfterImage=0;
    +	                $posYAfterDescription=0;
    +
    +	                if($this->getColumnStatus('photo'))
    +	                {
    +    	                // We start with Photo of product line
    +    	                if (isset($imglinesize['width']) && isset($imglinesize['height']) && ($curY + $imglinesize['height']) > ($this->page_hauteur-($heightforfooter+$heightforfreetext+$heightforinfotot)))	// If photo too high, we moved completely on new page
    +    	                {
    +    	                    $pdf->AddPage('','',true);
    +    	                    if (! empty($tplidx)) $pdf->useTemplate($tplidx);
    +    	                    $pdf->setPage($pageposbefore+1);
    +
    +    	                    $curY = $tab_top_newpage;
    +    	                    $showpricebeforepagebreak=0;
    +    	                }
    +
    +    	                if (!empty($this->cols['photo']) && isset($imglinesize['width']) && isset($imglinesize['height']))
    +    	                {
    +    	                    $pdf->Image($realpatharray[$i], $this->getColumnContentXStart('photo'), $curY, $imglinesize['width'], $imglinesize['height'], '', '', '', 2, 300);	// Use 300 dpi
    +    	                    // $pdf->Image does not increase value return by getY, so we save it manually
    +    	                    $posYAfterImage=$curY+$imglinesize['height'];
    +    	                }
    +	                }
    +
    +	                // Description of product line
    +	                if ($this->getColumnStatus('desc'))
    +	                {
    +    	                $pdf->startTransaction();
    +    	                pdf_writelinedesc($pdf,$object,$i,$outputlangs,$this->getColumnContentWidth('desc'),3,$this->getColumnContentXStart('desc'),$curY,$hideref,$hidedesc);
    +    	                $pageposafter=$pdf->getPage();
    +    	                if ($pageposafter > $pageposbefore)	// There is a pagebreak
    +    	                {
    +    	                    $pdf->rollbackTransaction(true);
    +    	                    $pageposafter=$pageposbefore;
    +    	                    //print $pageposafter.'-'.$pageposbefore;exit;
    +    	                    $pdf->setPageOrientation('', 1, $heightforfooter);	// The only function to edit the bottom margin of current page to set it.
    +    	                    pdf_writelinedesc($pdf,$object,$i,$outputlangs,$this->getColumnContentWidth('desc'),3,$this->getColumnContentXStart('desc'),$curY,$hideref,$hidedesc);
    +    	                    $pageposafter=$pdf->getPage();
    +    	                    $posyafter=$pdf->GetY();
    +    	                    //var_dump($posyafter); var_dump(($this->page_hauteur - ($heightforfooter+$heightforfreetext+$heightforinfotot))); exit;
    +    	                    if ($posyafter > ($this->page_hauteur - ($heightforfooter+$heightforfreetext+$heightforinfotot)))	// There is no space left for total+free text
    +    	                    {
    +    	                        if ($i == ($nblignes-1))	// No more lines, and no space left to show total, so we create a new page
    +    	                        {
    +    	                            $pdf->AddPage('','',true);
    +    	                            if (! empty($tplidx)) $pdf->useTemplate($tplidx);
    +    	                            $pdf->setPage($pageposafter+1);
    +    	                        }
    +    	                    }
    +    	                    else
    +    	                    {
    +    	                        // We found a page break
    +    	                        $showpricebeforepagebreak=0;
    +    	                    }
    +    	                }
    +    	                else	// No pagebreak
    +    	                {
    +    	                    $pdf->commitTransaction();
    +    	                }
    +    	                $posYAfterDescription=$pdf->GetY();
    +	                }
    +
    +	                $nexY = $pdf->GetY();
    +	                $pageposafter=$pdf->getPage();
    +	                $pdf->setPage($pageposbefore);
    +	                $pdf->setTopMargin($this->marge_haute);
    +	                $pdf->setPageOrientation('', 1, 0);	// The only function to edit the bottom margin of current page to set it.
    +
    +	                // We suppose that a too long description or photo were moved completely on next page
    +	                if ($pageposafter > $pageposbefore && empty($showpricebeforepagebreak)) {
    +	                    $pdf->setPage($pageposafter); $curY = $tab_top_newpage;
    +	                }
    +
    +	                $pdf->SetFont('','', $default_font_size - 1);   // On repositionne la police par defaut
    +
    +	                // VAT Rate
    +	                if ($this->getColumnStatus('vat'))
    +	                {
    +	                    $vat_rate = pdf_getlinevatrate($object, $i, $outputlangs, $hidedetails);
    +	                    $this->printStdColumnContent($pdf, $curY, 'vat', $vat_rate);
    +	                    $nexY = max($pdf->GetY(),$nexY);
    +	                }
    +
    +	                // Unit price before discount
    +	                if ($this->getColumnStatus('subprice'))
    +	                {
    +	                    $up_excl_tax = pdf_getlineupexcltax($object, $i, $outputlangs, $hidedetails);
    +	                    $this->printStdColumnContent($pdf, $curY, 'subprice', $up_excl_tax);
    +	                    $nexY = max($pdf->GetY(),$nexY);
    +	                }
    +
    +	                // Quantity
    +	                // Enough for 6 chars
    +	                if ($this->getColumnStatus('qty'))
    +	                {
    +	                    $qty = pdf_getlineqty($object, $i, $outputlangs, $hidedetails);
    +	                    $this->printStdColumnContent($pdf, $curY, 'qty', $qty);
    +	                    $nexY = max($pdf->GetY(),$nexY);
    +	                }
    +
    +	                // Situation progress
    +	                if ($this->getColumnStatus('progress'))
    +	                {
    +	                    $progress = pdf_getlineprogress($object, $i, $outputlangs, $hidedetails);
    +	                    $this->printStdColumnContent($pdf, $curY, 'progress', $progress);
    +	                    $nexY = max($pdf->GetY(),$nexY);
    +	                }
    +
    +	                // Unit
    +	                if ($this->getColumnStatus('unit'))
    +	                {
    +	                    $unit = pdf_getlineunit($object, $i, $outputlangs, $hidedetails, $hookmanager);
    +	                    $this->printStdColumnContent($pdf, $curY, 'unit', $unit);
    +	                    $nexY = max($pdf->GetY(),$nexY);
    +	                }
    +
    +	                // Discount on line
    +	                if ($this->getColumnStatus('discount') && $object->lines[$i]->remise_percent)
    +	                {
    +	                    $remise_percent = pdf_getlineremisepercent($object, $i, $outputlangs, $hidedetails);
    +	                    $this->printStdColumnContent($pdf, $curY, 'discount', $remise_percent);
    +	                    $nexY = max($pdf->GetY(),$nexY);
    +	                }
    +
    +	                // Total HT line
    +	                if ($this->getColumnStatus('totalexcltax'))
    +	                {
    +	                    $total_excl_tax = pdf_getlinetotalexcltax($object, $i, $outputlangs, $hidedetails);
    +	                    $this->printStdColumnContent($pdf, $curY, 'totalexcltax', $total_excl_tax);
    +	                    $nexY = max($pdf->GetY(),$nexY);
    +	                }
    +
    +
    +	                $parameters=array(
    +	                    'object' => $object,
    +	                    'i' => $i,
    +	                    'pdf' =>& $pdf,
    +	                    'curY' =>& $curY,
    +	                    'nexY' =>& $nexY,
    +	                    'outputlangs' => $outputlangs,
    +	                    'hidedetails' => $hidedetails
    +	                );
    +	                $reshook=$hookmanager->executeHooks('printPDFline',$parameters,$this);    // Note that $object may have been modified by hook
    +
    +
    +
    +	                $sign=1;
    +	                if (isset($object->type) && $object->type == 2 && ! empty($conf->global->INVOICE_POSITIVE_CREDIT_NOTE)) $sign=-1;
    +	                // Collecte des totaux par valeur de tva dans $this->tva["taux"]=total_tva
    +	                $prev_progress = $object->lines[$i]->get_prev_progress($object->id);
    +	                if ($prev_progress > 0 && !empty($object->lines[$i]->situation_percent)) // Compute progress from previous situation
    +	                {
    +	                    if ($conf->multicurrency->enabled && $object->multicurrency_tx != 1) $tvaligne = $sign * $object->lines[$i]->multicurrency_total_tva * ($object->lines[$i]->situation_percent - $prev_progress) / $object->lines[$i]->situation_percent;
    +	                    else $tvaligne = $sign * $object->lines[$i]->total_tva * ($object->lines[$i]->situation_percent - $prev_progress) / $object->lines[$i]->situation_percent;
    +	                } else {
    +	                    if ($conf->multicurrency->enabled && $object->multicurrency_tx != 1) $tvaligne= $sign * $object->lines[$i]->multicurrency_total_tva;
    +	                    else $tvaligne= $sign * $object->lines[$i]->total_tva;
    +	                }
    +
    +	                $localtax1ligne=$object->lines[$i]->total_localtax1;
    +	                $localtax2ligne=$object->lines[$i]->total_localtax2;
    +	                $localtax1_rate=$object->lines[$i]->localtax1_tx;
    +	                $localtax2_rate=$object->lines[$i]->localtax2_tx;
    +	                $localtax1_type=$object->lines[$i]->localtax1_type;
    +	                $localtax2_type=$object->lines[$i]->localtax2_type;
    +
    +	                if ($object->remise_percent) $tvaligne-=($tvaligne*$object->remise_percent)/100;
    +	                if ($object->remise_percent) $localtax1ligne-=($localtax1ligne*$object->remise_percent)/100;
    +	                if ($object->remise_percent) $localtax2ligne-=($localtax2ligne*$object->remise_percent)/100;
    +
    +	                $vatrate=(string) $object->lines[$i]->tva_tx;
    +
    +	                // Retrieve type from database for backward compatibility with old records
    +	                if ((! isset($localtax1_type) || $localtax1_type=='' || ! isset($localtax2_type) || $localtax2_type=='') // if tax type not defined
    +	                    && (! empty($localtax1_rate) || ! empty($localtax2_rate))) // and there is local tax
    +	                {
    +	                    $localtaxtmp_array=getLocalTaxesFromRate($vatrate,0, $object->thirdparty, $mysoc);
    +	                    $localtax1_type = $localtaxtmp_array[0];
    +	                    $localtax2_type = $localtaxtmp_array[2];
    +	                }
    +
    +	                // retrieve global local tax
    +	                if ($localtax1_type && $localtax1ligne != 0)
    +	                    $this->localtax1[$localtax1_type][$localtax1_rate]+=$localtax1ligne;
    +	                    if ($localtax2_type && $localtax2ligne != 0)
    +	                        $this->localtax2[$localtax2_type][$localtax2_rate]+=$localtax2ligne;
    +
    +	                        if (($object->lines[$i]->info_bits & 0x01) == 0x01) $vatrate.='*';
    +	                        if (! isset($this->tva[$vatrate])) 				$this->tva[$vatrate]=0;
    +	                        $this->tva[$vatrate] += $tvaligne;
    +
    +	                        $nexY = max($nexY,$posYAfterImage);
    +
    +	                        // Add line
    +	                        if (! empty($conf->global->MAIN_PDF_DASH_BETWEEN_LINES) && $i < ($nblignes - 1))
    +	                        {
    +	                            $pdf->setPage($pageposafter);
    +	                            $pdf->SetLineStyle(array('dash'=>'1,1','color'=>array(80,80,80)));
    +	                            //$pdf->SetDrawColor(190,190,200);
    +	                            $pdf->line($this->marge_gauche, $nexY+1, $this->page_largeur - $this->marge_droite, $nexY+1);
    +	                            $pdf->SetLineStyle(array('dash'=>0));
    +	                        }
    +
    +	                        $nexY+=2;    // Passe espace entre les lignes
    +
    +	                        // Detect if some page were added automatically and output _tableau for past pages
    +	                        while ($pagenb < $pageposafter)
    +	                        {
    +	                            $pdf->setPage($pagenb);
    +	                            if ($pagenb == $pageposbeforeprintlines)
    +	                            {
    +	                                $this->_tableau($pdf, $tab_top, $this->page_hauteur - $tab_top - $heightforfooter, 0, $outputlangs, 0, 1, $object->multicurrency_code);
    +	                            }
    +	                            else
    +	                            {
    +	                                $this->_tableau($pdf, $tab_top_newpage, $this->page_hauteur - $tab_top_newpage - $heightforfooter, 0, $outputlangs, 1, 1, $object->multicurrency_code);
    +	                            }
    +	                            $this->_pagefoot($pdf,$object,$outputlangs,1);
    +	                            $pagenb++;
    +	                            $pdf->setPage($pagenb);
    +	                            $pdf->setPageOrientation('', 1, 0);	// The only function to edit the bottom margin of current page to set it.
    +	                            if (empty($conf->global->MAIN_PDF_DONOTREPEAT_HEAD)) $this->_pagehead($pdf, $object, 0, $outputlangs);
    +	                        }
    +
    +	                        if (isset($object->lines[$i+1]->pagebreak) && $object->lines[$i+1]->pagebreak)
    +	                        {
    +	                            if ($pagenb == $pageposafter)
    +	                            {
    +	                                $this->_tableau($pdf, $tab_top, $this->page_hauteur - $tab_top - $heightforfooter, 0, $outputlangs, 0, 1, $object->multicurrency_code);
    +	                            }
    +	                            else
    +	                            {
    +	                                $this->_tableau($pdf, $tab_top_newpage, $this->page_hauteur - $tab_top_newpage - $heightforfooter, 0, $outputlangs, 1, 1, $object->multicurrency_code);
    +	                            }
    +	                            $this->_pagefoot($pdf,$object,$outputlangs,1);
    +	                            // New page
    +	                            $pdf->AddPage();
    +	                            if (! empty($tplidx)) $pdf->useTemplate($tplidx);
    +	                            $pagenb++;
    +	                            if (empty($conf->global->MAIN_PDF_DONOTREPEAT_HEAD)) $this->_pagehead($pdf, $object, 0, $outputlangs);
    +	                        }
    +
    +	            }
    +
    +	            // Show square
    +	            if ($pagenb == $pageposbeforeprintlines)
    +	            {
    +	                $this->_tableau($pdf, $tab_top, $this->page_hauteur - $tab_top - $heightforinfotot - $heightforfreetext - $heightforfooter, 0, $outputlangs, 0, 0, $object->multicurrency_code);
    +	                $bottomlasttab=$this->page_hauteur - $heightforinfotot - $heightforfreetext - $heightforfooter + 1;
    +	            }
    +	            else
    +	            {
    +	                $this->_tableau($pdf, $tab_top_newpage, $this->page_hauteur - $tab_top_newpage - $heightforinfotot - $heightforfreetext - $heightforfooter, 0, $outputlangs, 1, 0, $object->multicurrency_code);
    +	                $bottomlasttab=$this->page_hauteur - $heightforinfotot - $heightforfreetext - $heightforfooter + 1;
    +	            }
    +
    +	            // Affiche zone infos
    +	            $posy=$this->drawInfoTable($pdf, $object, $bottomlasttab, $outputlangs);
    +
    +	            // Affiche zone totaux
    +	            $posy=$this->drawTotalTable($pdf, $object, $deja_regle, $bottomlasttab, $outputlangs);
    +
    +	            // Affiche zone versements
    +	            if (($deja_regle || $amount_credit_notes_included || $amount_deposits_included) && empty($conf->global->INVOICE_NO_PAYMENT_DETAILS))
    +	            {
    +	                $posy=$this->drawPaymentsTable($pdf, $object, $posy, $outputlangs);
    +	            }
    +
    +	            // Pied de page
    +	            $this->_pagefoot($pdf,$object,$outputlangs);
    +	            if (method_exists($pdf,'AliasNbPages')) $pdf->AliasNbPages();
    +
    +	            $pdf->Close();
    +
    +	            $pdf->Output($file,'F');
    +
    +	            // Add pdfgeneration hook
    +	            $hookmanager->initHooks(array('pdfgeneration'));
    +	            $parameters=array('file'=>$file,'object'=>$object,'outputlangs'=>$outputlangs);
    +	            global $action;
    +	            $reshook=$hookmanager->executeHooks('afterPDFCreation',$parameters,$this,$action);    // Note that $action and $object may have been modified by some hooks
    +
    +	            if (! empty($conf->global->MAIN_UMASK))
    +	                @chmod($file, octdec($conf->global->MAIN_UMASK));
    +
    +	                $this->result = array('fullpath'=>$file);
    +
    +	                return 1;   // No error
    +	        }
    +	        else
    +	        {
    +	            $this->error=$langs->transnoentities("ErrorCanNotCreateDir",$dir);
    +	            return 0;
    +	        }
    +	    }
    +	    else
    +	    {
    +	        $this->error=$langs->transnoentities("ErrorConstantNotDefined","FAC_OUTPUTDIR");
    +	        return 0;
    +	    }
    +	}
    +
    +
    +	/**
    +	 *  Show payments table
    +	 *
    +     *  @param	PDF			$pdf           Object PDF
    +     *  @param  Object		$object         Object invoice
    +     *  @param  int			$posy           Position y in PDF
    +     *  @param  Translate	$outputlangs    Object langs for output
    +     *  @return int             			<0 if KO, >0 if OK
    +	 */
    +	function drawPaymentsTable(&$pdf, $object, $posy, $outputlangs)
    +	{
    +		global $conf;
    +
    +        $sign=1;
    +        if ($object->type == 2 && ! empty($conf->global->INVOICE_POSITIVE_CREDIT_NOTE)) $sign=-1;
    +
    +        $tab3_posx = 120;
    +		$tab3_top = $posy + 8;
    +		$tab3_width = 80;
    +		$tab3_height = 4;
    +		if ($this->page_largeur < 210) // To work with US executive format
    +		{
    +			$tab3_posx -= 20;
    +		}
    +
    +		$default_font_size = pdf_getPDFFontSize($outputlangs);
    +
    +		$title=$outputlangs->transnoentities("PaymentsAlreadyDone");
    +		if ($object->type == 2) $title=$outputlangs->transnoentities("PaymentsBackAlreadyDone");
    +
    +		$pdf->SetFont('','', $default_font_size - 3);
    +		$pdf->SetXY($tab3_posx, $tab3_top - 4);
    +		$pdf->MultiCell(60, 3, $title, 0, 'L', 0);
    +
    +		$pdf->line($tab3_posx, $tab3_top, $tab3_posx+$tab3_width, $tab3_top);
    +
    +		$pdf->SetFont('','', $default_font_size - 4);
    +		$pdf->SetXY($tab3_posx, $tab3_top);
    +		$pdf->MultiCell(20, 3, $outputlangs->transnoentities("Payment"), 0, 'L', 0);
    +		$pdf->SetXY($tab3_posx+21, $tab3_top);
    +		$pdf->MultiCell(20, 3, $outputlangs->transnoentities("Amount"), 0, 'L', 0);
    +		$pdf->SetXY($tab3_posx+40, $tab3_top);
    +		$pdf->MultiCell(20, 3, $outputlangs->transnoentities("Type"), 0, 'L', 0);
    +		$pdf->SetXY($tab3_posx+58, $tab3_top);
    +		$pdf->MultiCell(20, 3, $outputlangs->transnoentities("Num"), 0, 'L', 0);
    +
    +		$pdf->line($tab3_posx, $tab3_top-1+$tab3_height, $tab3_posx+$tab3_width, $tab3_top-1+$tab3_height);
    +
    +		$y=0;
    +
    +		$pdf->SetFont('','', $default_font_size - 4);
    +
    +
    +		// Loop on each deposits and credit notes included
    +		$sql = "SELECT re.rowid, re.amount_ht, re.multicurrency_amount_ht, re.amount_tva, re.multicurrency_amount_tva,  re.amount_ttc, re.multicurrency_amount_ttc,";
    +		$sql.= " re.description, re.fk_facture_source,";
    +		$sql.= " f.type, f.datef";
    +		$sql.= " FROM ".MAIN_DB_PREFIX ."societe_remise_except as re, ".MAIN_DB_PREFIX ."facture as f";
    +		$sql.= " WHERE re.fk_facture_source = f.rowid AND re.fk_facture = ".$object->id;
    +		$resql=$this->db->query($sql);
    +		if ($resql)
    +		{
    +			$num = $this->db->num_rows($resql);
    +			$i=0;
    +			$invoice=new Facture($this->db);
    +			while ($i < $num)
    +			{
    +				$y+=3;
    +				$obj = $this->db->fetch_object($resql);
    +
    +				if ($obj->type == 2) $text=$outputlangs->trans("CreditNote");
    +				elseif ($obj->type == 3) $text=$outputlangs->trans("Deposit");
    +				else $text=$outputlangs->trans("UnknownType");
    +
    +				$invoice->fetch($obj->fk_facture_source);
    +
    +				$pdf->SetXY($tab3_posx, $tab3_top+$y);
    +				$pdf->MultiCell(20, 3, dol_print_date($obj->datef,'day',false,$outputlangs,true), 0, 'L', 0);
    +				$pdf->SetXY($tab3_posx+21, $tab3_top+$y);
    +				$pdf->MultiCell(20, 3, price(($conf->multicurrency->enabled && $object->multicurrency_tx != 1) ? $obj->multicurrency_amount_ttc : $obj->amount_ttc, 0, $outputlangs), 0, 'L', 0);
    +				$pdf->SetXY($tab3_posx+40, $tab3_top+$y);
    +				$pdf->MultiCell(20, 3, $text, 0, 'L', 0);
    +				$pdf->SetXY($tab3_posx+58, $tab3_top+$y);
    +				$pdf->MultiCell(20, 3, $invoice->ref, 0, 'L', 0);
    +
    +				$pdf->line($tab3_posx, $tab3_top+$y+3, $tab3_posx+$tab3_width, $tab3_top+$y+3);
    +
    +				$i++;
    +			}
    +		}
    +		else
    +		{
    +			$this->error=$this->db->lasterror();
    +			return -1;
    +		}
    +
    +		// Loop on each payment
    +		// TODO Call getListOfPaymentsgetListOfPayments instead of hard coded sql
    +		$sql = "SELECT p.datep as date, p.fk_paiement, p.num_paiement as num, pf.amount as amount, pf.multicurrency_amount,";
    +		$sql.= " cp.code";
    +		$sql.= " FROM ".MAIN_DB_PREFIX."paiement_facture as pf, ".MAIN_DB_PREFIX."paiement as p";
    +		$sql.= " LEFT JOIN ".MAIN_DB_PREFIX."c_paiement as cp ON p.fk_paiement = cp.id";
    +		$sql.= " WHERE pf.fk_paiement = p.rowid AND pf.fk_facture = ".$object->id;
    +		//$sql.= " WHERE pf.fk_paiement = p.rowid AND pf.fk_facture = 1";
    +		$sql.= " ORDER BY p.datep";
    +
    +		$resql=$this->db->query($sql);
    +		if ($resql)
    +		{
    +			$num = $this->db->num_rows($resql);
    +			$i=0;
    +			while ($i < $num) {
    +				$y+=3;
    +				$row = $this->db->fetch_object($resql);
    +
    +				$pdf->SetXY($tab3_posx, $tab3_top+$y);
    +				$pdf->MultiCell(20, 3, dol_print_date($this->db->jdate($row->date),'day',false,$outputlangs,true), 0, 'L', 0);
    +				$pdf->SetXY($tab3_posx+21, $tab3_top+$y);
    +				$pdf->MultiCell(20, 3, price($sign * (($conf->multicurrency->enabled && $object->multicurrency_tx != 1) ? $row->multicurrency_amount : $row->amount), 0, $outputlangs), 0, 'L', 0);
    +				$pdf->SetXY($tab3_posx+40, $tab3_top+$y);
    +				$oper = $outputlangs->transnoentitiesnoconv("PaymentTypeShort" . $row->code);
    +
    +				$pdf->MultiCell(20, 3, $oper, 0, 'L', 0);
    +				$pdf->SetXY($tab3_posx+58, $tab3_top+$y);
    +				$pdf->MultiCell(30, 3, $row->num, 0, 'L', 0);
    +
    +				$pdf->line($tab3_posx, $tab3_top+$y+3, $tab3_posx+$tab3_width, $tab3_top+$y+3);
    +
    +				$i++;
    +			}
    +		}
    +		else
    +		{
    +			$this->error=$this->db->lasterror();
    +			return -1;
    +		}
    +	}
    +
    +
    +	/**
    +	 *   Show miscellaneous information (payment mode, payment term, ...)
    +	 *
    +	 *   @param		PDF			$pdf     		Object PDF
    +	 *   @param		Object		$object			Object to show
    +	 *   @param		int			$posy			Y
    +	 *   @param		Translate	$outputlangs	Langs object
    +	 *   @return	void
    +	 */
    +	private function drawInfoTable(&$pdf, $object, $posy, $outputlangs)
    +	{
    +		global $conf;
    +
    +		$default_font_size = pdf_getPDFFontSize($outputlangs);
    +
    +		$pdf->SetFont('','', $default_font_size - 1);
    +
    +		// If France, show VAT mention if not applicable
    +		if ($this->emetteur->country_code == 'FR' && $this->franchise == 1)
    +		{
    +			$pdf->SetFont('','B', $default_font_size - 2);
    +			$pdf->SetXY($this->marge_gauche, $posy);
    +			$pdf->MultiCell(100, 3, $outputlangs->transnoentities("VATIsNotUsedForInvoice"), 0, 'L', 0);
    +
    +			$posy=$pdf->GetY()+4;
    +		}
    +
    +		$posxval=52;
    +
    +		// Show payments conditions
    +		if ($object->type != 2 && ($object->cond_reglement_code || $object->cond_reglement))
    +		{
    +			$pdf->SetFont('','B', $default_font_size - 2);
    +			$pdf->SetXY($this->marge_gauche, $posy);
    +			$titre = $outputlangs->transnoentities("PaymentConditions").':';
    +			$pdf->MultiCell(43, 4, $titre, 0, 'L');
    +
    +			$pdf->SetFont('','', $default_font_size - 2);
    +			$pdf->SetXY($posxval, $posy);
    +			$lib_condition_paiement=$outputlangs->transnoentities("PaymentCondition".$object->cond_reglement_code)!=('PaymentCondition'.$object->cond_reglement_code)?$outputlangs->transnoentities("PaymentCondition".$object->cond_reglement_code):$outputlangs->convToOutputCharset($object->cond_reglement_doc);
    +			$lib_condition_paiement=str_replace('\n',"\n",$lib_condition_paiement);
    +			$pdf->MultiCell(67, 4, $lib_condition_paiement,0,'L');
    +
    +			$posy=$pdf->GetY()+3;
    +		}
    +
    +		if ($object->type != 2)
    +		{
    +			// Check a payment mode is defined
    +			if (empty($object->mode_reglement_code)
    +			&& empty($conf->global->FACTURE_CHQ_NUMBER)
    +			&& empty($conf->global->FACTURE_RIB_NUMBER))
    +			{
    +				$this->error = $outputlangs->transnoentities("ErrorNoPaiementModeConfigured");
    +			}
    +			// Avoid having any valid PDF with setup that is not complete
    +			elseif (($object->mode_reglement_code == 'CHQ' && empty($conf->global->FACTURE_CHQ_NUMBER) && empty($object->fk_account) && empty($object->fk_bank))
    +				|| ($object->mode_reglement_code == 'VIR' && empty($conf->global->FACTURE_RIB_NUMBER) && empty($object->fk_account) && empty($object->fk_bank)))
    +			{
    +				$outputlangs->load("errors");
    +
    +				$pdf->SetXY($this->marge_gauche, $posy);
    +				$pdf->SetTextColor(200,0,0);
    +				$pdf->SetFont('','B', $default_font_size - 2);
    +				$this->error = $outputlangs->transnoentities("ErrorPaymentModeDefinedToWithoutSetup",$object->mode_reglement_code);
    +				$pdf->MultiCell(80, 3, $this->error,0,'L',0);
    +				$pdf->SetTextColor(0,0,0);
    +
    +				$posy=$pdf->GetY()+1;
    +			}
    +
    +			// Show payment mode
    +			if ($object->mode_reglement_code
    +			&& $object->mode_reglement_code != 'CHQ'
    +			&& $object->mode_reglement_code != 'VIR')
    +			{
    +				$pdf->SetFont('','B', $default_font_size - 2);
    +				$pdf->SetXY($this->marge_gauche, $posy);
    +				$titre = $outputlangs->transnoentities("PaymentMode").':';
    +				$pdf->MultiCell(80, 5, $titre, 0, 'L');
    +
    +				$pdf->SetFont('','', $default_font_size - 2);
    +				$pdf->SetXY($posxval, $posy);
    +				$lib_mode_reg=$outputlangs->transnoentities("PaymentType".$object->mode_reglement_code)!=('PaymentType'.$object->mode_reglement_code)?$outputlangs->transnoentities("PaymentType".$object->mode_reglement_code):$outputlangs->convToOutputCharset($object->mode_reglement);
    +				$pdf->MultiCell(80, 5, $lib_mode_reg,0,'L');
    +
    +				$posy=$pdf->GetY()+2;
    +			}
    +
    +			// Show payment mode CHQ
    +			if (empty($object->mode_reglement_code) || $object->mode_reglement_code == 'CHQ')
    +			{
    +				// Si mode reglement non force ou si force a CHQ
    +				if (! empty($conf->global->FACTURE_CHQ_NUMBER))
    +				{
    +					$diffsizetitle=(empty($conf->global->PDF_DIFFSIZE_TITLE)?3:$conf->global->PDF_DIFFSIZE_TITLE);
    +
    +					if ($conf->global->FACTURE_CHQ_NUMBER > 0)
    +					{
    +						$account = new Account($this->db);
    +						$account->fetch($conf->global->FACTURE_CHQ_NUMBER);
    +
    +						$pdf->SetXY($this->marge_gauche, $posy);
    +						$pdf->SetFont('','B', $default_font_size - $diffsizetitle);
    +						$pdf->MultiCell(100, 3, $outputlangs->transnoentities('PaymentByChequeOrderedTo',$account->proprio),0,'L',0);
    +						$posy=$pdf->GetY()+1;
    +
    +			            if (empty($conf->global->MAIN_PDF_HIDE_CHQ_ADDRESS))
    +			            {
    +							$pdf->SetXY($this->marge_gauche, $posy);
    +							$pdf->SetFont('','', $default_font_size - $diffsizetitle);
    +							$pdf->MultiCell(100, 3, $outputlangs->convToOutputCharset($account->owner_address), 0, 'L', 0);
    +							$posy=$pdf->GetY()+2;
    +			            }
    +					}
    +					if ($conf->global->FACTURE_CHQ_NUMBER == -1)
    +					{
    +						$pdf->SetXY($this->marge_gauche, $posy);
    +						$pdf->SetFont('','B', $default_font_size - $diffsizetitle);
    +						$pdf->MultiCell(100, 3, $outputlangs->transnoentities('PaymentByChequeOrderedTo',$this->emetteur->name),0,'L',0);
    +						$posy=$pdf->GetY()+1;
    +
    +			            if (empty($conf->global->MAIN_PDF_HIDE_CHQ_ADDRESS))
    +			            {
    +							$pdf->SetXY($this->marge_gauche, $posy);
    +							$pdf->SetFont('','', $default_font_size - $diffsizetitle);
    +							$pdf->MultiCell(100, 3, $outputlangs->convToOutputCharset($this->emetteur->getFullAddress()), 0, 'L', 0);
    +							$posy=$pdf->GetY()+2;
    +			            }
    +					}
    +				}
    +			}
    +
    +			// If payment mode not forced or forced to VIR, show payment with BAN
    +			if (empty($object->mode_reglement_code) || $object->mode_reglement_code == 'VIR')
    +			{
    +				if (! empty($object->fk_account) || ! empty($object->fk_bank) || ! empty($conf->global->FACTURE_RIB_NUMBER))
    +				{
    +					$bankid=(empty($object->fk_account)?$conf->global->FACTURE_RIB_NUMBER:$object->fk_account);
    +					if (! empty($object->fk_bank)) $bankid=$object->fk_bank;   // For backward compatibility when object->fk_account is forced with object->fk_bank
    +					$account = new Account($this->db);
    +					$account->fetch($bankid);
    +
    +					$curx=$this->marge_gauche;
    +					$cury=$posy;
    +
    +					$posy=pdf_bank($pdf,$outputlangs,$curx,$cury,$account,0,$default_font_size);
    +
    +					$posy+=2;
    +				}
    +			}
    +		}
    +
    +		return $posy;
    +	}
    +
    +
    +	/**
    +	 *	Show total to pay
    +	 *
    +	 *	@param	PDF			$pdf           Object PDF
    +	 *	@param  Facture		$object         Object invoice
    +	 *	@param  int			$deja_regle     Montant deja regle
    +	 *	@param	int			$posy			Position depart
    +	 *	@param	Translate	$outputlangs	Objet langs
    +	 *	@return int							Position pour suite
    +	 */
    +	private function drawTotalTable(&$pdf, $object, $deja_regle, $posy, $outputlangs)
    +	{
    +		global $conf,$mysoc;
    +
    +        $sign=1;
    +        if ($object->type == 2 && ! empty($conf->global->INVOICE_POSITIVE_CREDIT_NOTE)) $sign=-1;
    +
    +        $default_font_size = pdf_getPDFFontSize($outputlangs);
    +
    +		$tab2_top = $posy;
    +		$tab2_hl = 4;
    +		$pdf->SetFont('','', $default_font_size - 1);
    +
    +		// Tableau total
    +		$col1x = 120; $col2x = 170;
    +		if ($this->page_largeur < 210) // To work with US executive format
    +		{
    +			$col2x-=20;
    +		}
    +		$largcol2 = ($this->page_largeur - $this->marge_droite - $col2x);
    +
    +		$useborder=0;
    +		$index = 0;
    +
    +		// Total HT
    +		$pdf->SetFillColor(255,255,255);
    +		$pdf->SetXY($col1x, $tab2_top + 0);
    +		$pdf->MultiCell($col2x-$col1x, $tab2_hl, $outputlangs->transnoentities("TotalHT"), 0, 'L', 1);
    +
    +		$total_ht = ($conf->multicurrency->enabled && $object->mylticurrency_tx != 1 ? $object->multicurrency_total_ht : $object->total_ht);
    +		$pdf->SetXY($col2x, $tab2_top + 0);
    +		$pdf->MultiCell($largcol2, $tab2_hl, price($sign * ($total_ht + (! empty($object->remise)?$object->remise:0)), 0, $outputlangs), 0, 'R', 1);
    +
    +		// Show VAT by rates and total
    +		$pdf->SetFillColor(248,248,248);
    +
    +		$total_ttc = ($conf->multicurrency->enabled && $object->multicurrency_tx != 1) ? $object->multicurrency_total_ttc : $object->total_ttc;
    +
    +		$this->atleastoneratenotnull=0;
    +		if (empty($conf->global->MAIN_GENERATE_DOCUMENTS_WITHOUT_VAT))
    +		{
    +			$tvaisnull=((! empty($this->tva) && count($this->tva) == 1 && isset($this->tva['0.000']) && is_float($this->tva['0.000'])) ? true : false);
    +			if (! empty($conf->global->MAIN_GENERATE_DOCUMENTS_WITHOUT_VAT_IFNULL) && $tvaisnull)
    +			{
    +				// Nothing to do
    +			}
    +			else
    +			{
    +			    // FIXME amount of vat not supported with multicurrency
    +
    +				//Local tax 1 before VAT
    +				//if (! empty($conf->global->FACTURE_LOCAL_TAX1_OPTION) && $conf->global->FACTURE_LOCAL_TAX1_OPTION=='localtax1on')
    +				//{
    +					foreach( $this->localtax1 as $localtax_type => $localtax_rate )
    +					{
    +						if (in_array((string) $localtax_type, array('1','3','5'))) continue;
    +
    +						foreach( $localtax_rate as $tvakey => $tvaval )
    +						{
    +							if ($tvakey!=0)    // On affiche pas taux 0
    +							{
    +								//$this->atleastoneratenotnull++;
    +
    +								$index++;
    +								$pdf->SetXY($col1x, $tab2_top + $tab2_hl * $index);
    +
    +								$tvacompl='';
    +								if (preg_match('/\*/',$tvakey))
    +								{
    +									$tvakey=str_replace('*','',$tvakey);
    +									$tvacompl = " (".$outputlangs->transnoentities("NonPercuRecuperable").")";
    +								}
    +
    +								$totalvat = $outputlangs->transcountrynoentities("TotalLT1",$mysoc->country_code).' ';
    +								$totalvat.=vatrate(abs($tvakey),1).$tvacompl;
    +								$pdf->MultiCell($col2x-$col1x, $tab2_hl, $totalvat, 0, 'L', 1);
    +
    +								$pdf->SetXY($col2x, $tab2_top + $tab2_hl * $index);
    +								$pdf->MultiCell($largcol2, $tab2_hl, price($tvaval, 0, $outputlangs), 0, 'R', 1);
    +							}
    +						}
    +					}
    +	      		//}
    +				//Local tax 2 before VAT
    +				//if (! empty($conf->global->FACTURE_LOCAL_TAX2_OPTION) && $conf->global->FACTURE_LOCAL_TAX2_OPTION=='localtax2on')
    +				//{
    +					foreach( $this->localtax2 as $localtax_type => $localtax_rate )
    +					{
    +						if (in_array((string) $localtax_type, array('1','3','5'))) continue;
    +
    +						foreach( $localtax_rate as $tvakey => $tvaval )
    +						{
    +							if ($tvakey!=0)    // On affiche pas taux 0
    +							{
    +								//$this->atleastoneratenotnull++;
    +
    +
    +
    +								$index++;
    +								$pdf->SetXY($col1x, $tab2_top + $tab2_hl * $index);
    +
    +								$tvacompl='';
    +								if (preg_match('/\*/',$tvakey))
    +								{
    +									$tvakey=str_replace('*','',$tvakey);
    +									$tvacompl = " (".$outputlangs->transnoentities("NonPercuRecuperable").")";
    +								}
    +								$totalvat = $outputlangs->transcountrynoentities("TotalLT2",$mysoc->country_code).' ';
    +								$totalvat.=vatrate(abs($tvakey),1).$tvacompl;
    +								$pdf->MultiCell($col2x-$col1x, $tab2_hl, $totalvat, 0, 'L', 1);
    +
    +								$pdf->SetXY($col2x, $tab2_top + $tab2_hl * $index);
    +								$pdf->MultiCell($largcol2, $tab2_hl, price($tvaval, 0, $outputlangs), 0, 'R', 1);
    +
    +							}
    +						}
    +					}
    +
    +                //}
    +
    +				// VAT
    +				// Situations totals migth be wrong on huge amounts
    +				if ($object->situation_cycle_ref && $object->situation_counter > 1) {
    +
    +					$sum_pdf_tva = 0;
    +					foreach($this->tva as $tvakey => $tvaval){
    +						$sum_pdf_tva+=$tvaval; // sum VAT amounts to compare to object
    +					}
    +
    +					if($sum_pdf_tva!=$object->total_tva) { // apply coef to recover the VAT object amount (the good one)
    +						$coef_fix_tva = $object->total_tva / $sum_pdf_tva;
    +
    +						foreach($this->tva as $tvakey => $tvaval) {
    +							$this->tva[$tvakey]=$tvaval * $coef_fix_tva;
    +						}
    +					}
    +
    +				}
    +
    +				foreach($this->tva as $tvakey => $tvaval)
    +				{
    +					if ($tvakey != 0)    // On affiche pas taux 0
    +					{
    +						$this->atleastoneratenotnull++;
    +
    +						$index++;
    +						$pdf->SetXY($col1x, $tab2_top + $tab2_hl * $index);
    +
    +						$tvacompl='';
    +						if (preg_match('/\*/',$tvakey))
    +						{
    +							$tvakey=str_replace('*','',$tvakey);
    +							$tvacompl = " (".$outputlangs->transnoentities("NonPercuRecuperable").")";
    +						}
    +						$totalvat =$outputlangs->transcountrynoentities("TotalVAT",$mysoc->country_code).' ';
    +						$totalvat.=vatrate($tvakey,1).$tvacompl;
    +						$pdf->MultiCell($col2x-$col1x, $tab2_hl, $totalvat, 0, 'L', 1);
    +
    +						$pdf->SetXY($col2x, $tab2_top + $tab2_hl * $index);
    +						$pdf->MultiCell($largcol2, $tab2_hl, price($tvaval, 0, $outputlangs), 0, 'R', 1);
    +					}
    +				}
    +
    +				//Local tax 1 after VAT
    +				//if (! empty($conf->global->FACTURE_LOCAL_TAX1_OPTION) && $conf->global->FACTURE_LOCAL_TAX1_OPTION=='localtax1on')
    +				//{
    +					foreach( $this->localtax1 as $localtax_type => $localtax_rate )
    +					{
    +						if (in_array((string) $localtax_type, array('2','4','6'))) continue;
    +
    +						foreach( $localtax_rate as $tvakey => $tvaval )
    +						{
    +							if ($tvakey != 0)    // On affiche pas taux 0
    +							{
    +								//$this->atleastoneratenotnull++;
    +
    +								$index++;
    +								$pdf->SetXY($col1x, $tab2_top + $tab2_hl * $index);
    +
    +								$tvacompl='';
    +								if (preg_match('/\*/',$tvakey))
    +								{
    +									$tvakey=str_replace('*','',$tvakey);
    +									$tvacompl = " (".$outputlangs->transnoentities("NonPercuRecuperable").")";
    +								}
    +								$totalvat = $outputlangs->transcountrynoentities("TotalLT1",$mysoc->country_code).' ';
    +								$totalvat.=vatrate(abs($tvakey),1).$tvacompl;
    +
    +								$pdf->MultiCell($col2x-$col1x, $tab2_hl, $totalvat, 0, 'L', 1);
    +								$pdf->SetXY($col2x, $tab2_top + $tab2_hl * $index);
    +								$pdf->MultiCell($largcol2, $tab2_hl, price($tvaval, 0, $outputlangs), 0, 'R', 1);
    +							}
    +						}
    +					}
    +	      		//}
    +				//Local tax 2 after VAT
    +				//if (! empty($conf->global->FACTURE_LOCAL_TAX2_OPTION) && $conf->global->FACTURE_LOCAL_TAX2_OPTION=='localtax2on')
    +				//{
    +					foreach( $this->localtax2 as $localtax_type => $localtax_rate )
    +					{
    +						if (in_array((string) $localtax_type, array('2','4','6'))) continue;
    +
    +						foreach( $localtax_rate as $tvakey => $tvaval )
    +						{
    +						    // retrieve global local tax
    +							if ($tvakey != 0)    // On affiche pas taux 0
    +							{
    +								//$this->atleastoneratenotnull++;
    +
    +								$index++;
    +								$pdf->SetXY($col1x, $tab2_top + $tab2_hl * $index);
    +
    +								$tvacompl='';
    +								if (preg_match('/\*/',$tvakey))
    +								{
    +									$tvakey=str_replace('*','',$tvakey);
    +									$tvacompl = " (".$outputlangs->transnoentities("NonPercuRecuperable").")";
    +								}
    +								$totalvat = $outputlangs->transcountrynoentities("TotalLT2",$mysoc->country_code).' ';
    +
    +								$totalvat.=vatrate(abs($tvakey),1).$tvacompl;
    +								$pdf->MultiCell($col2x-$col1x, $tab2_hl, $totalvat, 0, 'L', 1);
    +
    +								$pdf->SetXY($col2x, $tab2_top + $tab2_hl * $index);
    +								$pdf->MultiCell($largcol2, $tab2_hl, price($tvaval, 0, $outputlangs), 0, 'R', 1);
    +							}
    +						}
    +					//}
    +				}
    +
    +				// Revenue stamp
    +				if (price2num($object->revenuestamp) != 0)
    +				{
    +					$index++;
    +					$pdf->SetXY($col1x, $tab2_top + $tab2_hl * $index);
    +					$pdf->MultiCell($col2x-$col1x, $tab2_hl, $outputlangs->transnoentities("RevenueStamp"), $useborder, 'L', 1);
    +
    +					$pdf->SetXY($col2x, $tab2_top + $tab2_hl * $index);
    +					$pdf->MultiCell($largcol2, $tab2_hl, price($sign * $object->revenuestamp), $useborder, 'R', 1);
    +				}
    +
    +				// Total TTC
    +				$index++;
    +				$pdf->SetXY($col1x, $tab2_top + $tab2_hl * $index);
    +				$pdf->SetTextColor(0,0,60);
    +				$pdf->SetFillColor(224,224,224);
    +				$pdf->MultiCell($col2x-$col1x, $tab2_hl, $outputlangs->transnoentities("TotalTTC"), $useborder, 'L', 1);
    +
    +				$pdf->SetXY($col2x, $tab2_top + $tab2_hl * $index);
    +				$pdf->MultiCell($largcol2, $tab2_hl, price($sign * $total_ttc, 0, $outputlangs), $useborder, 'R', 1);
    +			}
    +		}
    +
    +		$pdf->SetTextColor(0,0,0);
    +
    +		$creditnoteamount=$object->getSumCreditNotesUsed(($conf->multicurrency->enabled && $object->multicurrency_tx != 1) ? 1 : 0);
    +		$depositsamount=$object->getSumDepositsUsed(($conf->multicurrency->enabled && $object->multicurrency_tx != 1) ? 1 : 0);
    +		//print "x".$creditnoteamount."-".$depositsamount;exit;
    +		$resteapayer = price2num($total_ttc - $deja_regle - $creditnoteamount - $depositsamount, 'MT');
    +		if ($object->paye) $resteapayer=0;
    +
    +		if (($deja_regle > 0 || $creditnoteamount > 0 || $depositsamount > 0) && empty($conf->global->INVOICE_NO_PAYMENT_DETAILS))
    +		{
    +			// Already paid + Deposits
    +			$index++;
    +			$pdf->SetXY($col1x, $tab2_top + $tab2_hl * $index);
    +			$pdf->MultiCell($col2x-$col1x, $tab2_hl, $outputlangs->transnoentities("Paid"), 0, 'L', 0);
    +			$pdf->SetXY($col2x, $tab2_top + $tab2_hl * $index);
    +			$pdf->MultiCell($largcol2, $tab2_hl, price($deja_regle + $depositsamount, 0, $outputlangs), 0, 'R', 0);
    +
    +			// Credit note
    +			if ($creditnoteamount)
    +			{
    +				$index++;
    +				$pdf->SetXY($col1x, $tab2_top + $tab2_hl * $index);
    +				$pdf->MultiCell($col2x-$col1x, $tab2_hl, $outputlangs->transnoentities("CreditNotes"), 0, 'L', 0);
    +				$pdf->SetXY($col2x, $tab2_top + $tab2_hl * $index);
    +				$pdf->MultiCell($largcol2, $tab2_hl, price($creditnoteamount, 0, $outputlangs), 0, 'R', 0);
    +			}
    +
    +			// Escompte
    +			if ($object->close_code == Facture::CLOSECODE_DISCOUNTVAT)
    +			{
    +				$index++;
    +				$pdf->SetFillColor(255,255,255);
    +
    +				$pdf->SetXY($col1x, $tab2_top + $tab2_hl * $index);
    +				$pdf->MultiCell($col2x-$col1x, $tab2_hl, $outputlangs->transnoentities("EscompteOfferedShort"), $useborder, 'L', 1);
    +				$pdf->SetXY($col2x, $tab2_top + $tab2_hl * $index);
    +				$pdf->MultiCell($largcol2, $tab2_hl, price($object->total_ttc - $deja_regle - $creditnoteamount - $depositsamount, 0, $outputlangs), $useborder, 'R', 1);
    +
    +				$resteapayer=0;
    +			}
    +
    +			$index++;
    +			$pdf->SetTextColor(0,0,60);
    +			$pdf->SetFillColor(224,224,224);
    +			$pdf->SetXY($col1x, $tab2_top + $tab2_hl * $index);
    +			$pdf->MultiCell($col2x-$col1x, $tab2_hl, $outputlangs->transnoentities("RemainderToPay"), $useborder, 'L', 1);
    +			$pdf->SetXY($col2x, $tab2_top + $tab2_hl * $index);
    +			$pdf->MultiCell($largcol2, $tab2_hl, price($resteapayer, 0, $outputlangs), $useborder, 'R', 1);
    +
    +			$pdf->SetFont('','', $default_font_size - 1);
    +			$pdf->SetTextColor(0,0,0);
    +		}
    +
    +		$index++;
    +		return ($tab2_top + ($tab2_hl * $index));
    +	}
    +
    +	/**
    +	 *   Show table for lines
    +	 *
    +	 *   @param		PDF			$pdf     		Object PDF
    +	 *   @param		string		$tab_top		Top position of table
    +	 *   @param		string		$tab_height		Height of table (rectangle)
    +	 *   @param		int			$nexY			Y (not used)
    +	 *   @param		Translate	$outputlangs	Langs object
    +	 *   @param		int			$hidetop		1=Hide top bar of array and title, 0=Hide nothing, -1=Hide only title
    +	 *   @param		int			$hidebottom		Hide bottom bar of array
    +	 *   @param		string		$currency		Currency code
    +	 *   @return	void
    +	 */
    +	function _tableau(&$pdf, $tab_top, $tab_height, $nexY, $outputlangs, $hidetop=0, $hidebottom=0, $currency='')
    +	{
    +		global $conf;
    +
    +		// Force to disable hidetop and hidebottom
    +		$hidebottom=0;
    +		if ($hidetop) $hidetop=-1;
    +
    +		$currency = !empty($currency) ? $currency : $conf->currency;
    +		$default_font_size = pdf_getPDFFontSize($outputlangs);
    +
    +		// Amount in (at tab_top - 1)
    +		$pdf->SetTextColor(0,0,0);
    +		$pdf->SetFont('','', $default_font_size - 2);
    +
    +		if (empty($hidetop))
    +		{
    +			$titre = $outputlangs->transnoentities("AmountInCurrency",$outputlangs->transnoentitiesnoconv("Currency".$currency));
    +			$pdf->SetXY($this->page_largeur - $this->marge_droite - ($pdf->GetStringWidth($titre) + 3), $tab_top-4);
    +			$pdf->MultiCell(($pdf->GetStringWidth($titre) + 3), 2, $titre);
    +
    +			//$conf->global->MAIN_PDF_TITLE_BACKGROUND_COLOR='230,230,230';
    +			if (! empty($conf->global->MAIN_PDF_TITLE_BACKGROUND_COLOR)) $pdf->Rect($this->marge_gauche, $tab_top, $this->page_largeur-$this->marge_droite-$this->marge_gauche, 5, 'F', null, explode(',',$conf->global->MAIN_PDF_TITLE_BACKGROUND_COLOR));
    +		}
    +
    +		$pdf->SetDrawColor(128,128,128);
    +		$pdf->SetFont('','', $default_font_size - 1);
    +
    +		// Output Rect
    +		$this->printRect($pdf,$this->marge_gauche, $tab_top, $this->page_largeur-$this->marge_gauche-$this->marge_droite, $tab_height, $hidetop, $hidebottom);	// Rect prend une longueur en 3eme param et 4eme param
    +
    +
    +		foreach ($this->cols as $colKey => $colDef)
    +		{
    +		    if(!$this->getColumnStatus($colKey)) continue;
    +
    +		    // get title label
    +		    $colDef['title']['label'] = !empty($colDef['title']['label'])?$colDef['title']['label']:$outputlangs->transnoentities($colDef['title']['textkey']);
    +
    +		    // Add column separator
    +		    if(!empty($colDef['border-left'])){
    +		        $pdf->line($colDef['xStartPos'], $tab_top, $colDef['xStartPos'], $tab_top + $tab_height);
    +		    }
    +
    +		    if (empty($hidetop))
    +		    {
    +		      $pdf->SetXY($colDef['xStartPos'] + $colDef['title']['padding'][3], $tab_top + $colDef['title']['padding'][0] );
    +
    +		      $textWidth = $colDef['width'] - $colDef['title']['padding'][3] -$colDef['title']['padding'][1];
    +		      $pdf->MultiCell($textWidth,2,$colDef['title']['label'],'',$colDef['title']['align']);
    +		    }
    +		}
    +
    +		if (empty($hidetop)){
    +			$pdf->line($this->marge_gauche, $tab_top+5, $this->page_largeur-$this->marge_droite, $tab_top+5);	// line prend une position y en 2eme param et 4eme param
    +		}
    +	}
    +
    +	/**
    +	 *  Show top header of page.
    +	 *
    +	 *  @param	PDF			$pdf     		Object PDF
    +	 *  @param  Object		$object     	Object to show
    +	 *  @param  int	    	$showaddress    0=no, 1=yes
    +	 *  @param  Translate	$outputlangs	Object lang for output
    +	 *  @return	void
    +	 */
    +	function _pagehead(&$pdf, $object, $showaddress, $outputlangs)
    +	{
    +		global $conf, $langs;
    +
    +		// Translations
    +		$outputlangs->loadLangs(array("main", "bills", "propal", "companies"));
    +
    +		$default_font_size = pdf_getPDFFontSize($outputlangs);
    +
    +		pdf_pagehead($pdf,$outputlangs,$this->page_hauteur);
    +
    +		// Show Draft Watermark
    +		if($object->statut==Facture::STATUS_DRAFT && (! empty($conf->global->FACTURE_DRAFT_WATERMARK)) )
    +        {
    +		      pdf_watermark($pdf,$outputlangs,$this->page_hauteur,$this->page_largeur,'mm',$conf->global->FACTURE_DRAFT_WATERMARK);
    +        }
    +
    +		$pdf->SetTextColor(0,0,60);
    +		$pdf->SetFont('','B', $default_font_size + 3);
    +
    +		$w = 110;
    +
    +		$posy=$this->marge_haute;
    +        $posx=$this->page_largeur-$this->marge_droite-$w;
    +
    +		$pdf->SetXY($this->marge_gauche,$posy);
    +
    +		// Logo
    +		if (empty($conf->global->PDF_DISABLE_MYCOMPANY_LOGO))
    +		{
    +			$logo=$conf->mycompany->dir_output.'/logos/'.$this->emetteur->logo;
    +			if ($this->emetteur->logo)
    +			{
    +				if (is_readable($logo))
    +				{
    +				    $height=pdf_getHeightForLogo($logo);
    +					$pdf->Image($logo, $this->marge_gauche, $posy, 0, $height);	// width=0 (auto)
    +				}
    +				else
    +				{
    +					$pdf->SetTextColor(200,0,0);
    +					$pdf->SetFont('','B',$default_font_size - 2);
    +					$pdf->MultiCell($w, 3, $outputlangs->transnoentities("ErrorLogoFileNotFound",$logo), 0, 'L');
    +					$pdf->MultiCell($w, 3, $outputlangs->transnoentities("ErrorGoToGlobalSetup"), 0, 'L');
    +				}
    +			}
    +			else
    +			{
    +				$text=$this->emetteur->name;
    +				$pdf->MultiCell($w, 4, $outputlangs->convToOutputCharset($text), 0, 'L');
    +			}
    +		}
    +
    +		$pdf->SetFont('','B', $default_font_size + 3);
    +		$pdf->SetXY($posx,$posy);
    +		$pdf->SetTextColor(0,0,60);
    +		$title=$outputlangs->transnoentities("PdfInvoiceTitle");
    +		if ($object->type == 1) $title=$outputlangs->transnoentities("InvoiceReplacement");
    +		if ($object->type == 2) $title=$outputlangs->transnoentities("InvoiceAvoir");
    +		if ($object->type == 3) $title=$outputlangs->transnoentities("InvoiceDeposit");
    +		if ($object->type == 4) $title=$outputlangs->transnoentities("InvoiceProForma");
    +		if ($this->situationinvoice) $title=$outputlangs->transnoentities("InvoiceSituation");
    +		$pdf->MultiCell($w, 3, $title, '', 'R');
    +
    +		$pdf->SetFont('','B',$default_font_size);
    +
    +		$posy+=5;
    +		$pdf->SetXY($posx,$posy);
    +		$pdf->SetTextColor(0,0,60);
    +		$textref=$outputlangs->transnoentities("Ref")." : " . $outputlangs->convToOutputCharset($object->ref);
    +		if ($object->statut == Facture::STATUS_DRAFT)
    +		{
    +			$pdf->SetTextColor(128,0,0);
    +			$textref.=' - '.$outputlangs->transnoentities("NotValidated");
    +		}
    +		$pdf->MultiCell($w, 4, $textref, '', 'R');
    +
    +		$posy+=1;
    +		$pdf->SetFont('','', $default_font_size - 2);
    +
    +		if ($object->ref_client)
    +		{
    +			$posy+=4;
    +			$pdf->SetXY($posx,$posy);
    +			$pdf->SetTextColor(0,0,60);
    +			$pdf->MultiCell($w, 3, $outputlangs->transnoentities("RefCustomer")." : " . $outputlangs->convToOutputCharset($object->ref_client), '', 'R');
    +		}
    +
    +		$objectidnext=$object->getIdReplacingInvoice('validated');
    +		if ($object->type == 0 && $objectidnext)
    +		{
    +			$objectreplacing=new Facture($this->db);
    +			$objectreplacing->fetch($objectidnext);
    +
    +			$posy+=3;
    +			$pdf->SetXY($posx,$posy);
    +			$pdf->SetTextColor(0,0,60);
    +			$pdf->MultiCell($w, 3, $outputlangs->transnoentities("ReplacementByInvoice").' : '.$outputlangs->convToOutputCharset($objectreplacing->ref), '', 'R');
    +		}
    +		if ($object->type == 1)
    +		{
    +			$objectreplaced=new Facture($this->db);
    +			$objectreplaced->fetch($object->fk_facture_source);
    +
    +			$posy+=4;
    +			$pdf->SetXY($posx,$posy);
    +			$pdf->SetTextColor(0,0,60);
    +			$pdf->MultiCell($w, 3, $outputlangs->transnoentities("ReplacementInvoice").' : '.$outputlangs->convToOutputCharset($objectreplaced->ref), '', 'R');
    +		}
    +		if ($object->type == 2 && !empty($object->fk_facture_source))
    +		{
    +			$objectreplaced=new Facture($this->db);
    +			$objectreplaced->fetch($object->fk_facture_source);
    +
    +			$posy+=3;
    +			$pdf->SetXY($posx,$posy);
    +			$pdf->SetTextColor(0,0,60);
    +			$pdf->MultiCell($w, 3, $outputlangs->transnoentities("CorrectionInvoice").' : '.$outputlangs->convToOutputCharset($objectreplaced->ref), '', 'R');
    +		}
    +
    +		$posy+=4;
    +		$pdf->SetXY($posx,$posy);
    +		$pdf->SetTextColor(0,0,60);
    +		$pdf->MultiCell($w, 3, $outputlangs->transnoentities("DateInvoice")." : " . dol_print_date($object->date,"day",false,$outputlangs), '', 'R');
    +
    +		if (! empty($conf->global->INVOICE_POINTOFTAX_DATE))
    +		{
    +			$posy+=4;
    +			$pdf->SetXY($posx,$posy);
    +			$pdf->SetTextColor(0,0,60);
    +			$pdf->MultiCell($w, 3, $outputlangs->transnoentities("DatePointOfTax")." : " . dol_print_date($object->date_pointoftax,"day",false,$outputlangs), '', 'R');
    +		}
    +
    +		if ($object->type != 2)
    +		{
    +			$posy+=3;
    +			$pdf->SetXY($posx,$posy);
    +			$pdf->SetTextColor(0,0,60);
    +			$pdf->MultiCell($w, 3, $outputlangs->transnoentities("DateDue")." : " . dol_print_date($object->date_lim_reglement,"day",false,$outputlangs,true), '', 'R');
    +		}
    +
    +		if ($object->thirdparty->code_client)
    +		{
    +			$posy+=3;
    +			$pdf->SetXY($posx,$posy);
    +			$pdf->SetTextColor(0,0,60);
    +			$pdf->MultiCell($w, 3, $outputlangs->transnoentities("CustomerCode")." : " . $outputlangs->transnoentities($object->thirdparty->code_client), '', 'R');
    +		}
    +
    +		// Get contact
    +		if (!empty($conf->global->DOC_SHOW_FIRST_SALES_REP))
    +		{
    +		    $arrayidcontact=$object->getIdContact('internal','SALESREPFOLL');
    +		    if (count($arrayidcontact) > 0)
    +		    {
    +		        $usertmp=new User($this->db);
    +		        $usertmp->fetch($arrayidcontact[0]);
    +                $posy+=4;
    +                $pdf->SetXY($posx,$posy);
    +		        $pdf->SetTextColor(0,0,60);
    +		        $pdf->MultiCell($w, 3, $langs->transnoentities("SalesRepresentative")." : ".$usertmp->getFullName($langs), '', 'R');
    +		    }
    +		}
    +
    +		$posy+=1;
    +
    +		$top_shift = 0;
    +		// Show list of linked objects
    +		$current_y = $pdf->getY();
    +		$posy = pdf_writeLinkedObjects($pdf, $object, $outputlangs, $posx, $posy, $w, 3, 'R', $default_font_size);
    +		if ($current_y < $pdf->getY())
    +		{
    +			$top_shift = $pdf->getY() - $current_y;
    +		}
    +
    +		if ($showaddress)
    +		{
    +			// Sender properties
    +			$carac_emetteur = pdf_build_address($outputlangs, $this->emetteur, $object->thirdparty, '', 0, 'source', $object);
    +
    +			// Show sender
    +			$posy=!empty($conf->global->MAIN_PDF_USE_ISO_LOCATION) ? 40 : 42;
    +			$posy+=$top_shift;
    +			$posx=$this->marge_gauche;
    +			if (! empty($conf->global->MAIN_INVERT_SENDER_RECIPIENT)) $posx=$this->page_largeur-$this->marge_droite-80;
    +
    +			$hautcadre=!empty($conf->global->MAIN_PDF_USE_ISO_LOCATION) ? 38 : 40;
    +			$widthrecbox=!empty($conf->global->MAIN_PDF_USE_ISO_LOCATION) ? 92 : 82;
    +
    +
    +			// Show sender frame
    +			$pdf->SetTextColor(0,0,0);
    +			$pdf->SetFont('','', $default_font_size - 2);
    +			$pdf->SetXY($posx,$posy-5);
    +			$pdf->MultiCell(66,5, $outputlangs->transnoentities("BillFrom").":", 0, 'L');
    +			$pdf->SetXY($posx,$posy);
    +			$pdf->SetFillColor(230,230,230);
    +			$pdf->MultiCell($widthrecbox, $hautcadre, "", 0, 'R', 1);
    +			$pdf->SetTextColor(0,0,60);
    +
    +			// Show sender name
    +			$pdf->SetXY($posx+2,$posy+3);
    +			$pdf->SetFont('','B', $default_font_size);
    +			$pdf->MultiCell($widthrecbox-2, 4, $outputlangs->convToOutputCharset($this->emetteur->name), 0, 'L');
    +			$posy=$pdf->getY();
    +
    +			// Show sender information
    +			$pdf->SetXY($posx+2,$posy);
    +			$pdf->SetFont('','', $default_font_size - 1);
    +			$pdf->MultiCell($widthrecbox-2, 4, $carac_emetteur, 0, 'L');
    +
    +			// If BILLING contact defined on invoice, we use it
    +			$usecontact=false;
    +			$arrayidcontact=$object->getIdContact('external','BILLING');
    +			if (count($arrayidcontact) > 0)
    +			{
    +				$usecontact=true;
    +				$result=$object->fetch_contact($arrayidcontact[0]);
    +			}
    +
    +			//Recipient name
    +			// On peut utiliser le nom de la societe du contact
    +			if ($usecontact && !empty($conf->global->MAIN_USE_COMPANY_NAME_OF_CONTACT)) {
    +				$thirdparty = $object->contact;
    +			} else {
    +				$thirdparty = $object->thirdparty;
    +			}
    +
    +			$carac_client_name= pdfBuildThirdpartyName($thirdparty, $outputlangs);
    +
    +			$carac_client=pdf_build_address($outputlangs,$this->emetteur,$object->thirdparty,($usecontact?$object->contact:''),$usecontact,'target',$object);
    +
    +			// Show recipient
    +			$widthrecbox=!empty($conf->global->MAIN_PDF_USE_ISO_LOCATION) ? 92 : 100;
    +			if ($this->page_largeur < 210) $widthrecbox=84;	// To work with US executive format
    +			$posy=!empty($conf->global->MAIN_PDF_USE_ISO_LOCATION) ? 40 : 42;
    +			$posy+=$top_shift;
    +			$posx=$this->page_largeur-$this->marge_droite-$widthrecbox;
    +			if (! empty($conf->global->MAIN_INVERT_SENDER_RECIPIENT)) $posx=$this->marge_gauche;
    +
    +			// Show recipient frame
    +			$pdf->SetTextColor(0,0,0);
    +			$pdf->SetFont('','', $default_font_size - 2);
    +			$pdf->SetXY($posx+2,$posy-5);
    +			$pdf->MultiCell($widthrecbox, 5, $outputlangs->transnoentities("BillTo").":",0,'L');
    +			$pdf->Rect($posx, $posy, $widthrecbox, $hautcadre);
    +
    +			// Show recipient name
    +			$pdf->SetXY($posx+2,$posy+3);
    +			$pdf->SetFont('','B', $default_font_size);
    +			$pdf->MultiCell($widthrecbox, 2, $carac_client_name, 0, 'L');
    +
    +			$posy = $pdf->getY();
    +
    +			// Show recipient information
    +			$pdf->SetFont('','', $default_font_size - 1);
    +			$pdf->SetXY($posx+2,$posy);
    +			$pdf->MultiCell($widthrecbox, 4, $carac_client, 0, 'L');
    +		}
    +
    +		$pdf->SetTextColor(0,0,0);
    +		return $top_shift;
    +	}
    +
    +	/**
    +	 *   	Show footer of page. Need this->emetteur object
    +     *
    +	 *   	@param	PDF			$pdf     			PDF
    +	 * 		@param	Object		$object				Object to show
    +	 *      @param	Translate	$outputlangs		Object lang for output
    +	 *      @param	int			$hidefreetext		1=Hide free text
    +	 *      @return	int								Return height of bottom margin including footer text
    +	 */
    +	function _pagefoot(&$pdf,$object,$outputlangs,$hidefreetext=0)
    +	{
    +		global $conf;
    +		$showdetails=$conf->global->MAIN_GENERATE_DOCUMENTS_SHOW_FOOT_DETAILS;
    +		return pdf_pagefoot($pdf,$outputlangs,'INVOICE_FREE_TEXT',$this->emetteur,$this->marge_basse,$this->marge_gauche,$this->page_hauteur,$object,$showdetails,$hidefreetext);
    +	}
    +
    +	/**
    +	 *   	Define Array Column Field
    +	 *
    +	 *   	@param	object			$object    		common object
    +	 *   	@param	outputlangs		$outputlangs    langs
    +     *      @param	int			   $hidedetails		Do not show line details
    +     *      @param	int			   $hidedesc		Do not show desc
    +     *      @param	int			   $hideref			Do not show ref
    +	 *      @return	null
    +	 */
    +    function defineColumnField($object,$outputlangs,$hidedetails=0,$hidedesc=0,$hideref=0)
    +    {
    +	    global $conf, $hookmanager;
    +
    +	    // Default field style for content
    +	    $this->defaultContentsFieldsStyle = array(
    +	        'align' => 'R', // R,C,L
    +	        'padding' => array(0.5,0.5,0.5,0.5), // Like css 0 => top , 1 => right, 2 => bottom, 3 => left
    +	    );
    +
    +	    // Default field style for content
    +	    $this->defaultTitlesFieldsStyle = array(
    +	        'align' => 'C', // R,C,L
    +	        'padding' => array(0.5,0,0.5,0), // Like css 0 => top , 1 => right, 2 => bottom, 3 => left
    +	    );
    +
    +	    /*
    +	     * For exemple
    +	    $this->cols['theColKey'] = array(
    +	        'rank' => $rank, // int : use for ordering columns
    +	        'width' => 20, // the column width in mm
    +	        'title' => array(
    +	            'textkey' => 'yourLangKey', // if there is no label, yourLangKey will be translated to replace label
    +	            'label' => ' ', // the final label : used fore final generated text
    +	            'align' => 'L', // text alignement :  R,C,L
    +	            'padding' => array(0.5,0.5,0.5,0.5), // Like css 0 => top , 1 => right, 2 => bottom, 3 => left
    +	        ),
    +	        'content' => array(
    +	            'align' => 'L', // text alignement :  R,C,L
    +	            'padding' => array(0.5,0.5,0.5,0.5), // Like css 0 => top , 1 => right, 2 => bottom, 3 => left
    +	        ),
    +	    );
    +	    */
    +
    +	    $rank=0; // do not use negative rank
    +	    $this->cols['desc'] = array(
    +	        'rank' => $rank,
    +	        'width' => false, // only for desc
    +	        'status' => true,
    +	        'title' => array(
    +	            'textkey' => 'Designation', // use lang key is usefull in somme case with module
    +	            'align' => 'L',
    +	            // 'textkey' => 'yourLangKey', // if there is no label, yourLangKey will be translated to replace label
    +	            // 'label' => ' ', // the final label
    +	            'padding' => array(0.5,0.5,0.5,0.5), // Like css 0 => top , 1 => right, 2 => bottom, 3 => left
    +	        ),
    +	        'content' => array(
    +	            'align' => 'L',
    +	        ),
    +	    );
    +
    +	    // PHOTO
    +        $rank = $rank + 10;
    +        $this->cols['photo'] = array(
    +            'rank' => $rank,
    +            'width' => (empty($conf->global->MAIN_DOCUMENTS_WITH_PICTURE_WIDTH)?20:$conf->global->MAIN_DOCUMENTS_WITH_PICTURE_WIDTH), // in mm
    +            'status' => false,
    +            'title' => array(
    +                'textkey' => 'Photo',
    +                'label' => ' '
    +            ),
    +            'content' => array(
    +                'padding' => array(0,0,0,0), // Like css 0 => top , 1 => right, 2 => bottom, 3 => left
    +            ),
    +            'border-left' => false, // remove left line separator
    +        );
    +
    +	    if (! empty($conf->global->MAIN_GENERATE_INVOICES_WITH_PICTURE) && !empty($this->atleastonephoto))
    +	    {
    +	        $this->cols['photo']['status'] = true;
    +	    }
    +
    +
    +	    $rank = $rank + 10;
    +	    $this->cols['vat'] = array(
    +	        'rank' => $rank,
    +	        'status' => false,
    +	        'width' => 16, // in mm
    +	        'title' => array(
    +	            'textkey' => 'VAT'
    +	        ),
    +	        'border-left' => true, // add left line separator
    +	    );
    +
    +	    if (empty($conf->global->MAIN_GENERATE_DOCUMENTS_WITHOUT_VAT) && empty($conf->global->MAIN_GENERATE_DOCUMENTS_WITHOUT_VAT_COLUMN))
    +	    {
    +	        $this->cols['vat']['status'] = true;
    +	    }
    +
    +	    $rank = $rank + 10;
    +	    $this->cols['subprice'] = array(
    +	        'rank' => $rank,
    +	        'width' => 19, // in mm
    +	        'status' => true,
    +	        'title' => array(
    +	            'textkey' => 'PriceUHT'
    +	        ),
    +	        'border-left' => true, // add left line separator
    +	    );
    +
    +	    $rank = $rank + 10;
    +	    $this->cols['qty'] = array(
    +	        'rank' => $rank,
    +	        'width' => 16, // in mm
    +	        'status' => true,
    +	        'title' => array(
    +	            'textkey' => 'Qty'
    +	        ),
    +	        'border-left' => true, // add left line separator
    +	    );
    +
    +	    $rank = $rank + 10;
    +	    $this->cols['progress'] = array(
    +	        'rank' => $rank,
    +	        'width' => 19, // in mm
    +	        'status' => false,
    +	        'title' => array(
    +	            'textkey' => 'Progress'
    +	        ),
    +	        'border-left' => true, // add left line separator
    +	    );
    +
    +	    if($this->situationinvoice)
    +	    {
    +	        $this->cols['progress']['status'] = true;
    +	    }
    +
    +	    $rank = $rank + 10;
    +	    $this->cols['unit'] = array(
    +	        'rank' => $rank,
    +	        'width' => 11, // in mm
    +	        'status' => false,
    +	        'title' => array(
    +	            'textkey' => 'Unit'
    +	        ),
    +	        'border-left' => true, // add left line separator
    +	    );
    +	    if($conf->global->PRODUCT_USE_UNITS){
    +	        $this->cols['unit']['status'] = true;
    +	    }
    +
    +	    $rank = $rank + 10;
    +	    $this->cols['discount'] = array(
    +	        'rank' => $rank,
    +	        'width' => 13, // in mm
    +	        'status' => false,
    +	        'title' => array(
    +	            'textkey' => 'ReductionShort'
    +	        ),
    +	        'border-left' => true, // add left line separator
    +	    );
    +	    if ($this->atleastonediscount){
    +	        $this->cols['discount']['status'] = true;
    +	    }
    +
    +	    $rank = $rank + 10;
    +	    $this->cols['totalexcltax'] = array(
    +	        'rank' => $rank,
    +	        'width' => 26, // in mm
    +	        'status' => true,
    +	        'title' => array(
    +	            'textkey' => 'TotalHT'
    +	        ),
    +	        'border-left' => true, // add left line separator
    +	    );
    +
    +
    +	    $parameters=array(
    +	        'object' => $object,
    +	        'outputlangs' => $outputlangs,
    +	        'hidedetails' => $hidedetails,
    +	        'hidedesc' => $hidedesc,
    +	        'hideref' => $hideref
    +	    );
    +
    +	    $reshook=$hookmanager->executeHooks('defineColumnField',$parameters,$this);    // Note that $object may have been modified by hook
    +	    if ($reshook < 0)
    +	    {
    +	        setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
    +	    }
    +	    elseif (empty($reshook))
    +	    {
    +	        $this->cols = array_replace($this->cols, $hookmanager->resArray); // array_replace is used to preserve keys
    +	    }
    +	    else
    +	    {
    +	        $this->cols = $hookmanager->resArray;
    +	    }
    +	}
    +}
    diff --git a/htdocs/core/modules/import/import_csv.modules.php b/htdocs/core/modules/import/import_csv.modules.php
    index 60dc9bf6c15..34bff81e55c 100644
    --- a/htdocs/core/modules/import/import_csv.modules.php
    +++ b/htdocs/core/modules/import/import_csv.modules.php
    @@ -633,6 +633,7 @@ class ImportCsv extends ModeleImports
     				//print 'listfields='.$listfields.'<br>listvalues='.$listvalues.'<br>';
     
     				// If no error for this $alias/$tablename, we have a complete $listfields and $listvalues that are defined
    +				// so we can try to make the insert or update now.
     				if (! $errorforthistable)
     				{
     					//print "$alias/$tablename/$listfields/$listvalues<br>";
    @@ -644,7 +645,7 @@ class ImportCsv extends ModeleImports
     						if (!empty($updatekeys)) {
     							// We do SELECT to get the rowid, if we already have the rowid, it's to be used below for related tables (extrafields)
     
    -							if (empty($lastinsertid)) {
    +							if (empty($lastinsertid)) {	// No insert done yet for a parent table
     								$sqlSelect = 'SELECT rowid FROM '.$tablename;
     
     								$data = array_combine($listfields, $listvalues);
    @@ -680,10 +681,11 @@ class ImportCsv extends ModeleImports
     									$error++;
     								}
     							} else {
    -								// We have a last INSERT ID. Check if we have a row referencing this foreign key.
    +								// We have a last INSERT ID (got by previous pass), so we check if we have a row referencing this foreign key.
     								// This is required when updating table with some extrafields. When inserting a record in parent table, we can make
     								// a direct insert into subtable extrafields, but when me wake an update, the insertid is defined and the child record
    -								// may already exists. So we rescan the extrafield table to be know if record exists or not for the rowid.
    +								// may already exists. So we rescan the extrafield table to know if record exists or not for the rowid.
    +								// Note: For extrafield tablename, we have in importfieldshidden_array an enty 'extra.fk_object'=>'lastrowid-tableparent' so $keyfield is 'fk_object'
     								$sqlSelect = 'SELECT rowid FROM '.$tablename;
     
     								if(empty($keyfield)) $keyfield = 'rowid';
    diff --git a/htdocs/core/modules/import/import_xlsx.modules.php b/htdocs/core/modules/import/import_xlsx.modules.php
    index 36b57e2d69a..2c37caa5d40 100644
    --- a/htdocs/core/modules/import/import_xlsx.modules.php
    +++ b/htdocs/core/modules/import/import_xlsx.modules.php
    @@ -656,6 +656,7 @@ class ImportXlsx extends ModeleImports
     				//print 'listfields='.$listfields.'<br>listvalues='.$listvalues.'<br>';
     
     				// If no error for this $alias/$tablename, we have a complete $listfields and $listvalues that are defined
    +				// so we can try to make the insert or update now.
     				if (! $errorforthistable)
     				{
     					//print "$alias/$tablename/$listfields/$listvalues<br>";
    @@ -665,7 +666,8 @@ class ImportXlsx extends ModeleImports
     						$insertdone = false;
     						if (!empty($updatekeys)) {
     							// We do SELECT to get the rowid, if we already have the rowid, it's to be used below for related tables (extrafields)
    -							if (empty($lastinsertid)) {
    +
    +							if (empty($lastinsertid)) {	// No insert done yet for a parent table
     								$sqlSelect = 'SELECT rowid FROM '.$tablename;
     
     								$data = array_combine($listfields, $listvalues);
    @@ -704,7 +706,8 @@ class ImportXlsx extends ModeleImports
     								// We have a last INSERT ID. Check if we have a row referencing this foreign key.
     								// This is required when updating table with some extrafields. When inserting a record in parent table, we can make
     								// a direct insert into subtable extrafields, but when me wake an update, the insertid is defined and the child record
    -								// may already exists. So we rescan the extrafield table to be know if record exists or not for the rowid.
    +								// may already exists. So we rescan the extrafield table to know if record exists or not for the rowid.
    +								// Note: For extrafield tablename, we have in importfieldshidden_array an enty 'extra.fk_object'=>'lastrowid-tableparent' so $keyfield is 'fk_object'
     								$sqlSelect = 'SELECT rowid FROM '.$tablename;
     
     								if(empty($keyfield)) $keyfield = 'rowid';
    diff --git a/htdocs/core/modules/mailings/modules_mailings.php b/htdocs/core/modules/mailings/modules_mailings.php
    index e0316a75390..f7136d4aa63 100644
    --- a/htdocs/core/modules/mailings/modules_mailings.php
    +++ b/htdocs/core/modules/mailings/modules_mailings.php
    @@ -41,7 +41,7 @@ class MailingTargets // This can't be abstract as it is used for some method
     	 */
     	public $error='';
     
    -    var $tooltip='';
    +    public $tooltip='';
     
     
         /**
    diff --git a/htdocs/core/modules/modDataPolicies.class.php b/htdocs/core/modules/modDataPolicy.class.php
    similarity index 59%
    rename from htdocs/core/modules/modDataPolicies.class.php
    rename to htdocs/core/modules/modDataPolicy.class.php
    index 74bbe0ba7d2..ca53440a3b9 100644
    --- a/htdocs/core/modules/modDataPolicies.class.php
    +++ b/htdocs/core/modules/modDataPolicy.class.php
    @@ -18,12 +18,12 @@
      */
     
     /**
    - * 	\defgroup   datapolicies     Module datapolicies
    - *  \brief      datapolicies module descriptor.
    + * 	\defgroup   datapolicy     Module datapolicy
    + *  \brief      datapolicy module descriptor.
      *
    - *  \file       htdocs/datapolicies/core/modules/modGdpr.class.php
    - *  \ingroup    datapolicies
    - *  \brief      Description and activation file for module DATAPOLICIES
    + *  \file       htdocs/datapolicy/core/modules/modDataPolicy.class.php
    + *  \ingroup    datapolicy
    + *  \brief      Description and activation file for module DATAPOLICY
      */
     include_once DOL_DOCUMENT_ROOT . '/core/modules/DolibarrModules.class.php';
     
    @@ -33,9 +33,9 @@ include_once DOL_DOCUMENT_ROOT . '/core/modules/DolibarrModules.class.php';
     // so we ignore the Squiz.Classes.ValidClassName.NotCamelCaps rule.
     // @codingStandardsIgnoreStart
     /**
    - *  Description and activation class for module datapolicies
    + *  Description and activation class for module datapolicy
      */
    -class modDataPolicies extends DolibarrModules {
    +class modDataPolicy extends DolibarrModules {
     
         // @codingStandardsIgnoreEnd
         /**
    @@ -53,7 +53,7 @@ class modDataPolicies extends DolibarrModules {
             // Use here a free id (See in Home -> System information -> Dolibarr for list of used modules id).
             $this->numero = 4100;
             // Key text used to identify module (for permissions, menus, etc...)
    -        $this->rights_class = 'datapolicies';
    +        $this->rights_class = 'datapolicy';
     
             // Family can be 'base' (core modules),'crm','financial','hr','projects','products','ecm','technic' (transverse modules),'interface' (link with external tools),'other','...'
             // It is used to group modules by family in module setup page
    @@ -62,16 +62,16 @@ class modDataPolicies extends DolibarrModules {
             $this->module_position = '70';
             // Gives the possibility to the module, to provide his own family info and position of this family (Overwrite $this->family and $this->module_position. Avoid this)
             //$this->familyinfo = array('myownfamily' => array('position' => '01', 'label' => $langs->trans("MyOwnFamily")));
    -        // Module label (no space allowed), used if translation string 'ModuledatapoliciesName' not found (MyModue is name of module).
    +        // Module label (no space allowed), used if translation string 'ModuledatapolicyName' not found (MyModue is name of module).
             $this->name = preg_replace('/^mod/i', '', get_class($this));
    -        // Module description, used if translation string 'ModuledatapoliciesDesc' not found (MyModue is name of module).
    -        $this->description = "Module to manage Data policies (for compliance with GDPR in Europe or other Data policies rules)";
    +        // Module description, used if translation string 'ModuledatapolicyDesc' not found (MyModue is name of module).
    +        $this->description = "Module to manage Data policy (for compliance with GDPR in Europe or other Data policy rules)";
             // Used only if file README.md and README-LL.md not found.
             $this->descriptionlong = "";
     
             // Possible values for version are: 'development', 'experimental', 'dolibarr', 'dolibarr_deprecated' or a version string like 'x.y.z'
             $this->version = 'development';
    -        // Key used in llx_const table to save module status enabled/disabled (where datapolicies is value of property name of module in uppercase)
    +        // Key used in llx_const table to save module status enabled/disabled (where datapolicy is value of property name of module in uppercase)
             $this->const_name = 'MAIN_MODULE_' . strtoupper($this->name);
             // Name of image file used for this module.
             // If file is in theme/yourtheme/img directory under name object_pictovalue.png, use this->picto='pictovalue'
    @@ -79,9 +79,9 @@ class modDataPolicies extends DolibarrModules {
             $this->picto = 'generic';
     
             // Defined all module parts (triggers, login, substitutions, menus, css, etc...)
    -        // for default path (eg: /datapolicies/core/xxxxx) (0=disable, 1=enable)
    -        // for specific path of parts (eg: /datapolicies/core/modules/barcode)
    -        // for specific css file (eg: /datapolicies/css/datapolicies.css.php)
    +        // for default path (eg: /datapolicy/core/xxxxx) (0=disable, 1=enable)
    +        // for specific path of parts (eg: /datapolicy/core/modules/barcode)
    +        // for specific css file (eg: /datapolicy/css/datapolicy.css.php)
             $this->module_parts = array(
                 'triggers' => 0, // Set this to 1 if module has its own trigger directory (core/triggers)
                 'login' => 0, // Set this to 1 if module has its own login method file (core/login)
    @@ -95,41 +95,41 @@ class modDataPolicies extends DolibarrModules {
             );
     
             // Data directories to create when module is enabled.
    -        // Example: this->dirs = array("/datapolicies/temp","/datapolicies/subdir");
    -        $this->dirs = array("/datapolicies/temp");
    +        // Example: this->dirs = array("/datapolicy/temp","/datapolicy/subdir");
    +        $this->dirs = array("/datapolicy/temp");
     
    -        // Config pages. Put here list of php page, stored into datapolicies/admin directory, to use to setup module.
    -        $this->config_page_url = array("setup.php@datapolicies");
    +        // Config pages. Put here list of php page, stored into datapolicy/admin directory, to use to setup module.
    +        $this->config_page_url = array("setup.php@datapolicy");
     
             // Dependencies
             $this->hidden = false;   // A condition to hide module
             $this->depends = array();  // List of module class names as string that must be enabled if this module is enabled
             $this->requiredby = array(); // List of module ids to disable if this one is disabled
             $this->conflictwith = array(); // List of module class names as string this module is in conflict with
    -        $this->langfiles = array("datapolicies@datapolicies");
    +        $this->langfiles = array("datapolicy@datapolicy");
             $this->phpmin = array(5, 3);     // Minimum version of PHP required by module
             $this->need_dolibarr_version = array(4, 0); // Minimum version of Dolibarr required by module
             $this->warnings_activation = array();                     // Warning to show when we activate module. array('always'='text') or array('FR'='textfr','ES'='textes'...)
             $this->warnings_activation_ext = array();                 // Warning to show when we activate an external module. array('always'='text') or array('FR'='textfr','ES'='textes'...)
    -        //$this->automatic_activation = array('FR'=>'datapoliciesWasAutomaticallyActivatedBecauseOfYourCountryChoice');
    +        //$this->automatic_activation = array('FR'=>'datapolicyWasAutomaticallyActivatedBecauseOfYourCountryChoice');
             //$this->always_enabled = true;								// If true, can't be disabled
             // Constants
             // List of particular constants to add when module is enabled (key, 'chaine', value, desc, visible, 'current' or 'allentities', deleteonunactive)
    -        // Example: $this->const=array(0=>array('datapolicies_MYNEWCONST1','chaine','myvalue','This is a constant to add',1),
    -        //                             1=>array('datapolicies_MYNEWCONST2','chaine','myvalue','This is another constant to add',0, 'current', 1)
    +        // Example: $this->const=array(0=>array('datapolicy_MYNEWCONST1','chaine','myvalue','This is a constant to add',1),
    +        //                             1=>array('datapolicy_MYNEWCONST2','chaine','myvalue','This is another constant to add',0, 'current', 1)
             // );
             $this->const = array(
    -            array('DATAPOLICIES_TIERS_CLIENT', 'chaine', '', $langs->trans('NUMBER_MONTH_BEFORE_DELETION'), 0),
    -            array('DATAPOLICIES_TIERS_PROSPECT', 'chaine', '', $langs->trans('NUMBER_MONTH_BEFORE_DELETION'), 0),
    -            array('DATAPOLICIES_TIERS_PROSPECT_CLIENT', 'chaine', '', $langs->trans('NUMBER_MONTH_BEFORE_DELETION'), 0),
    -            array('DATAPOLICIES_TIERS_NIPROSPECT_NICLIENT', 'chaine', '', $langs->trans('NUMBER_MONTH_BEFORE_DELETION'), 0),
    -            array('DATAPOLICIES_TIERS_FOURNISSEUR', 'chaine', '', $langs->trans('NUMBER_MONTH_BEFORE_DELETION'), 0),
    -            array('DATAPOLICIES_CONTACT_CLIENT', 'chaine', '', $langs->trans('NUMBER_MONTH_BEFORE_DELETION'), 0),
    -            array('DATAPOLICIES_CONTACT_PROSPECT', 'chaine', '', $langs->trans('NUMBER_MONTH_BEFORE_DELETION'), 0),
    -            array('DATAPOLICIES_CONTACT_PROSPECT_CLIENT', 'chaine', '', $langs->trans('NUMBER_MONTH_BEFORE_DELETION'), 0),
    -            array('DATAPOLICIES_CONTACT_NIPROSPECT_NICLIENT', 'chaine', '', $langs->trans('NUMBER_MONTH_BEFORE_DELETION'), 0),
    -            array('DATAPOLICIES_CONTACT_FOURNISSEUR', 'chaine', '', $langs->trans('NUMBER_MONTH_BEFORE_DELETION'), 0),
    -            array('DATAPOLICIES_ADHERENT', 'chaine', '', $langs->trans('NUMBER_MONTH_BEFORE_DELETION'), 0),
    +            array('DATAPOLICY_TIERS_CLIENT', 'chaine', '', $langs->trans('NUMBER_MONTH_BEFORE_DELETION'), 0),
    +            array('DATAPOLICY_TIERS_PROSPECT', 'chaine', '', $langs->trans('NUMBER_MONTH_BEFORE_DELETION'), 0),
    +            array('DATAPOLICY_TIERS_PROSPECT_CLIENT', 'chaine', '', $langs->trans('NUMBER_MONTH_BEFORE_DELETION'), 0),
    +            array('DATAPOLICY_TIERS_NIPROSPECT_NICLIENT', 'chaine', '', $langs->trans('NUMBER_MONTH_BEFORE_DELETION'), 0),
    +            array('DATAPOLICY_TIERS_FOURNISSEUR', 'chaine', '', $langs->trans('NUMBER_MONTH_BEFORE_DELETION'), 0),
    +            array('DATAPOLICY_CONTACT_CLIENT', 'chaine', '', $langs->trans('NUMBER_MONTH_BEFORE_DELETION'), 0),
    +            array('DATAPOLICY_CONTACT_PROSPECT', 'chaine', '', $langs->trans('NUMBER_MONTH_BEFORE_DELETION'), 0),
    +            array('DATAPOLICY_CONTACT_PROSPECT_CLIENT', 'chaine', '', $langs->trans('NUMBER_MONTH_BEFORE_DELETION'), 0),
    +            array('DATAPOLICY_CONTACT_NIPROSPECT_NICLIENT', 'chaine', '', $langs->trans('NUMBER_MONTH_BEFORE_DELETION'), 0),
    +            array('DATAPOLICY_CONTACT_FOURNISSEUR', 'chaine', '', $langs->trans('NUMBER_MONTH_BEFORE_DELETION'), 0),
    +            array('DATAPOLICY_ADHERENT', 'chaine', '', $langs->trans('NUMBER_MONTH_BEFORE_DELETION'), 0),
             );
     
             $country = explode(":", $conf->global->MAIN_INFO_SOCIETE_COUNTRY);
    @@ -140,17 +140,17 @@ class modDataPolicies extends DolibarrModules {
               'fr_FR:ParentCompany'=>'Maison mère ou revendeur'
               ) */
     
    -        if (!isset($conf->datapolicies) || !isset($conf->datapolicies->enabled)) {
    -            $conf->datapolicies = new stdClass();
    -            $conf->datapolicies->enabled = 0;
    +        if (!isset($conf->datapolicy) || !isset($conf->datapolicy->enabled)) {
    +            $conf->datapolicy = new stdClass();
    +            $conf->datapolicy->enabled = 0;
             }
     
     
             // Array to add new pages in new tabs
             $this->tabs = array();
             // Example:
    -        // $this->tabs[] = array('data'=>'objecttype:+tabname1:Title1:mylangfile@datapolicies:$user->rights->datapolicies->read:/datapolicies/mynewtab1.php?id=__ID__');  					// To add a new tab identified by code tabname1
    -        // $this->tabs[] = array('data'=>'objecttype:+tabname2:SUBSTITUTION_Title2:mylangfile@datapolicies:$user->rights->othermodule->read:/datapolicies/mynewtab2.php?id=__ID__',  	// To add another new tab identified by code tabname2. Label will be result of calling all substitution functions on 'Title2' key.
    +        // $this->tabs[] = array('data'=>'objecttype:+tabname1:Title1:mylangfile@datapolicy:$user->rights->datapolicy->read:/datapolicy/mynewtab1.php?id=__ID__');  					// To add a new tab identified by code tabname1
    +        // $this->tabs[] = array('data'=>'objecttype:+tabname2:SUBSTITUTION_Title2:mylangfile@datapolicy:$user->rights->othermodule->read:/datapolicy/mynewtab2.php?id=__ID__',  	// To add another new tab identified by code tabname2. Label will be result of calling all substitution functions on 'Title2' key.
             // $this->tabs[] = array('data'=>'objecttype:-tabname:NU:conditiontoremove');                                                     										// To remove an existing tab identified by code tabname
             //
             // Where objecttype can be
    @@ -177,7 +177,7 @@ class modDataPolicies extends DolibarrModules {
             $this->dictionaries = array();
             /* Example:
               $this->dictionaries=array(
    -          'langs'=>'mylangfile@datapolicies',
    +          'langs'=>'mylangfile@datapolicy',
               'tabname'=>array(MAIN_DB_PREFIX."table1",MAIN_DB_PREFIX."table2",MAIN_DB_PREFIX."table3"),		// List of tables we want to see into dictonnary editor
               'tablib'=>array("Table1","Table2","Table3"),													// Label of tables
               'tabsql'=>array('SELECT f.rowid as rowid, f.code, f.label, f.active FROM '.MAIN_DB_PREFIX.'table1 as f','SELECT f.rowid as rowid, f.code, f.label, f.active FROM '.MAIN_DB_PREFIX.'table2 as f','SELECT f.rowid as rowid, f.code, f.label, f.active FROM '.MAIN_DB_PREFIX.'table3 as f'),	// Request to select fields
    @@ -186,21 +186,21 @@ class modDataPolicies extends DolibarrModules {
               'tabfieldvalue'=>array("code,label","code,label","code,label"),																				// List of fields (list of fields to edit a record)
               'tabfieldinsert'=>array("code,label","code,label","code,label"),																			// List of fields (list of fields for insert)
               'tabrowid'=>array("rowid","rowid","rowid"),																									// Name of columns with primary key (try to always name it 'rowid')
    -          'tabcond'=>array($conf->datapolicies->enabled,$conf->datapolicies->enabled,$conf->datapolicies->enabled)												// Condition to show each dictionary
    +          'tabcond'=>array($conf->datapolicy->enabled,$conf->datapolicy->enabled,$conf->datapolicy->enabled)												// Condition to show each dictionary
               );
              */
     
     
             // Boxes/Widgets
    -        // Add here list of php file(s) stored in datapolicies/core/boxes that contains class to show a widget.
    +        // Add here list of php file(s) stored in datapolicy/core/boxes that contains class to show a widget.
             $this->boxes = array();
     
     
             // Cronjobs (List of cron jobs entries to add when module is enabled)
             // unit_frequency must be 60 for minute, 3600 for hour, 86400 for day, 604800 for week
             $this->cronjobs = array(
    -            0 => array('label' => 'DATAPOLICIES Cron', 'jobtype' => 'method', 'class' => '/datapolicies/class/datapoliciesCron.class.php', 'objectname' => 'RgpdCron', 'method' => 'exec', 'parameters' => '', 'comment' => 'Comment', 'frequency' => 1, 'unitfrequency' => 86400, 'status' => 1, 'test' => true),
    -            1 => array('label' => 'DATAPOLICIES Mailing', 'jobtype' => 'method', 'class' => '/datapolicies/class/datapoliciesCron.class.php', 'objectname' => 'RgpdCron', 'method' => 'sendMailing', 'parameters' => '', 'comment' => 'Comment', 'frequency' => 1, 'unitfrequency' => 86400, 'status' => 0, 'test' => true)
    +            0 => array('label' => 'DATAPOLICY Cron', 'jobtype' => 'method', 'class' => '/datapolicy/class/datapolicyCron.class.php', 'objectname' => 'RgpdCron', 'method' => 'exec', 'parameters' => '', 'comment' => 'Comment', 'frequency' => 1, 'unitfrequency' => 86400, 'status' => 1, 'test' => true),
    +            //1 => array('label' => 'DATAPOLICY Mailing', 'jobtype' => 'method', 'class' => '/datapolicy/class/datapolicyCron.class.php', 'objectname' => 'RgpdCron', 'method' => 'sendMailing', 'parameters' => '', 'comment' => 'Comment', 'frequency' => 1, 'unitfrequency' => 86400, 'status' => 0, 'test' => true)
             );
             // Example: $this->cronjobs=array(0=>array('label'=>'My label', 'jobtype'=>'method', 'class'=>'/dir/class/file.class.php', 'objectname'=>'MyClass', 'method'=>'myMethod', 'parameters'=>'param1, param2', 'comment'=>'Comment', 'frequency'=>2, 'unitfrequency'=>3600, 'status'=>0, 'test'=>true),
             //                                1=>array('label'=>'My label', 'jobtype'=>'command', 'command'=>'', 'parameters'=>'param1, param2', 'comment'=>'Comment', 'frequency'=>1, 'unitfrequency'=>3600*24, 'status'=>0, 'test'=>true)
    @@ -224,36 +224,34 @@ class modDataPolicies extends DolibarrModules {
         {
         	global $langs;
     
    -    	$this->_load_tables('/datapolicies/sql/');
    +    	$this->_load_tables('/datapolicy/sql/');
     
             // Create extrafields
             include_once DOL_DOCUMENT_ROOT . '/core/class/extrafields.class.php';
             $extrafields = new ExtraFields($this->db);
     
    -
    +		/*
             // Extrafield contact
    -        //$result1=$extrafields->addExtraField('datapolicies_separate', "DATAPOLICIES_BLOCKCHECKBOX", 'separate', 100,  1, 'thirdparty',   0, 0, '', '', 1, '', '1', 0, '', '', 'datapolicies@datapolicies', '$conf->datapolicies->enabled');
    -        $result1 = $extrafields->addExtraField('datapolicies_consentement', $langs->trans("DATAPOLICIES_consentement"), 'boolean', 101, 3, 'thirdparty', 0, 0, '', '', 1, '', '3', 0, '', '', 'datapolicies@datapolicies', '$conf->datapolicies->enabled');
    -        $result1 = $extrafields->addExtraField('datapolicies_opposition_traitement', $langs->trans("DATAPOLICIES_opposition_traitement"), 'boolean', 102, 3, 'thirdparty', 0, 0, '', '', 1, '', '3', 0, '', '', 'datapolicies@datapolicies', '$conf->datapolicies->enabled');
    -        $result1 = $extrafields->addExtraField('datapolicies_opposition_prospection', $langs->trans("DATAPOLICIES_opposition_prospection"), 'boolean', 103, 3, 'thirdparty', 0, 0, '', '', 1, '', '3', 0, '', '', 'datapolicies@datapolicies', '$conf->datapolicies->enabled');
    -        $result1 = $extrafields->addExtraField('datapolicies_date', $langs->trans("DATAPOLICIES_date"), 'date', 104, 3, 'thirdparty', 0, 0, '', '', 1, '', '3', 0);
    -        $result1 = $extrafields->addExtraField('datapolicies_send', $langs->trans("DATAPOLICIES_send"), 'date', 105, 3, 'thirdparty', 0, 0, '', '', 0, '', '0', 0);
    +        $result1 = $extrafields->addExtraField('datapolicy_consentement', $langs->trans("DATAPOLICY_consentement"), 'boolean', 101, 3, 'thirdparty', 0, 0, '', '', 1, '', '3', 0, '', '', 'datapolicy@datapolicy', '$conf->datapolicy->enabled');
    +        $result1 = $extrafields->addExtraField('datapolicy_opposition_traitement', $langs->trans("DATAPOLICY_opposition_traitement"), 'boolean', 102, 3, 'thirdparty', 0, 0, '', '', 1, '', '3', 0, '', '', 'datapolicy@datapolicy', '$conf->datapolicy->enabled');
    +        $result1 = $extrafields->addExtraField('datapolicy_opposition_prospection', $langs->trans("DATAPOLICY_opposition_prospection"), 'boolean', 103, 3, 'thirdparty', 0, 0, '', '', 1, '', '3', 0, '', '', 'datapolicy@datapolicy', '$conf->datapolicy->enabled');
    +        $result1 = $extrafields->addExtraField('datapolicy_date', $langs->trans("DATAPOLICY_date"), 'date', 104, 3, 'thirdparty', 0, 0, '', '', 1, '', '3', 0);
    +        $result1 = $extrafields->addExtraField('datapolicy_send', $langs->trans("DATAPOLICY_send"), 'date', 105, 3, 'thirdparty', 0, 0, '', '', 0, '', '0', 0);
     
             // Extrafield Tiers
    -        //$result1=$extrafields->addExtraField('datapolicies_separate', "DATAPOLICIES_BLOCKCHECKBOX", 'separate', 100,  1, 'contact',   0, 0, '', '', 1, '', '1', 0, '', '', 'datapolicies@datapolicies', '$conf->datapolicies->enabled');
    -        $result1 = $extrafields->addExtraField('datapolicies_consentement', $langs->trans("DATAPOLICIES_consentement"), 'boolean', 101, 3, 'contact', 0, 0, '', '', 1, '', '3', 0, '', '', 'datapolicies@datapolicies', '$conf->datapolicies->enabled');
    -        $result1 = $extrafields->addExtraField('datapolicies_opposition_traitement', $langs->trans("DATAPOLICIES_opposition_traitement"), 'boolean', 102, 3, 'contact', 0, 0, '', '', 1, '', '3', 0, '', '', 'datapolicies@datapolicies', '$conf->datapolicies->enabled');
    -        $result1 = $extrafields->addExtraField('datapolicies_opposition_prospection', $langs->trans("DATAPOLICIES_opposition_prospection"), 'boolean', 103, 3, 'contact', 0, 0, '', '', 1, '', '3', 0, '', '', 'datapolicies@datapolicies', '$conf->datapolicies->enabled');
    -        $result1 = $extrafields->addExtraField('datapolicies_date', $langs->trans("DATAPOLICIES_date"), 'date', 104, 3, 'contact', 0, 0, '', '', 1, '', '3', 0);
    -        $result1 = $extrafields->addExtraField('datapolicies_send', $langs->trans("DATAPOLICIES_send"), 'date', 105, 3, 'contact', 0, 0, '', '', 0, '', '0', 0);
    +        $result1 = $extrafields->addExtraField('datapolicy_consentement', $langs->trans("DATAPOLICY_consentement"), 'boolean', 101, 3, 'contact', 0, 0, '', '', 1, '', '3', 0, '', '', 'datapolicy@datapolicy', '$conf->datapolicy->enabled');
    +        $result1 = $extrafields->addExtraField('datapolicy_opposition_traitement', $langs->trans("DATAPOLICY_opposition_traitement"), 'boolean', 102, 3, 'contact', 0, 0, '', '', 1, '', '3', 0, '', '', 'datapolicy@datapolicy', '$conf->datapolicy->enabled');
    +        $result1 = $extrafields->addExtraField('datapolicy_opposition_prospection', $langs->trans("DATAPOLICY_opposition_prospection"), 'boolean', 103, 3, 'contact', 0, 0, '', '', 1, '', '3', 0, '', '', 'datapolicy@datapolicy', '$conf->datapolicy->enabled');
    +        $result1 = $extrafields->addExtraField('datapolicy_date', $langs->trans("DATAPOLICY_date"), 'date', 104, 3, 'contact', 0, 0, '', '', 1, '', '3', 0);
    +        $result1 = $extrafields->addExtraField('datapolicy_send', $langs->trans("DATAPOLICY_send"), 'date', 105, 3, 'contact', 0, 0, '', '', 0, '', '0', 0);
     
             // Extrafield Adherent
    -        //$result1=$extrafields->addExtraField('datapolicies_separate', "DATAPOLICIES_BLOCKCHECKBOX", 'separate', 100,  1, 'adherent',   0, 0, '', '', 1, '', '1', 0, '', '', 'datapolicies@datapolicies', '$conf->datapolicies->enabled');
    -        $result1 = $extrafields->addExtraField('datapolicies_consentement', $langs->trans("DATAPOLICIES_consentement"), 'boolean', 101, 3, 'adherent', 0, 0, '', '', 1, '', '3', 0, '', '', 'datapolicies@datapolicies', '$conf->datapolicies->enabled');
    -        $result1 = $extrafields->addExtraField('datapolicies_opposition_traitement', $langs->trans("DATAPOLICIES_opposition_traitement"), 'boolean', 102, 3, 'adherent', 0, 0, '', '', 1, '', '3', 0, '', '', 'datapolicies@datapolicies', '$conf->datapolicies->enabled');
    -        $result1 = $extrafields->addExtraField('datapolicies_opposition_prospection', $langs->trans("DATAPOLICIES_opposition_prospection"), 'boolean', 103, 3, 'adherent', 0, 0, '', '', 1, '', '3', 0, '', '', 'datapolicies@datapolicies', '$conf->datapolicies->enabled');
    -        $result1 = $extrafields->addExtraField('datapolicies_date', $langs->trans("DATAPOLICIES_date"), 'date', 104, 3, 'adherent', 0, 0, '', '', 1, '', '3', 0);
    -        $result1 = $extrafields->addExtraField('datapolicies_send', $langs->trans("DATAPOLICIES_send"), 'date', 105, 3, 'adherent', 0, 0, '', '', 0, '', '0', 0);
    +        $result1 = $extrafields->addExtraField('datapolicy_consentement', $langs->trans("DATAPOLICY_consentement"), 'boolean', 101, 3, 'adherent', 0, 0, '', '', 1, '', '3', 0, '', '', 'datapolicy@datapolicy', '$conf->datapolicy->enabled');
    +        $result1 = $extrafields->addExtraField('datapolicy_opposition_traitement', $langs->trans("DATAPOLICY_opposition_traitement"), 'boolean', 102, 3, 'adherent', 0, 0, '', '', 1, '', '3', 0, '', '', 'datapolicy@datapolicy', '$conf->datapolicy->enabled');
    +        $result1 = $extrafields->addExtraField('datapolicy_opposition_prospection', $langs->trans("DATAPOLICY_opposition_prospection"), 'boolean', 103, 3, 'adherent', 0, 0, '', '', 1, '', '3', 0, '', '', 'datapolicy@datapolicy', '$conf->datapolicy->enabled');
    +        $result1 = $extrafields->addExtraField('datapolicy_date', $langs->trans("DATAPOLICY_date"), 'date', 104, 3, 'adherent', 0, 0, '', '', 1, '', '3', 0);
    +        $result1 = $extrafields->addExtraField('datapolicy_send', $langs->trans("DATAPOLICY_send"), 'date', 105, 3, 'adherent', 0, 0, '', '', 0, '', '0', 0);
    +		*/
     
             $sql = array();
     
    diff --git a/htdocs/core/modules/modStock.class.php b/htdocs/core/modules/modStock.class.php
    index e9e33c8bbf3..d4f79f1efcf 100644
    --- a/htdocs/core/modules/modStock.class.php
    +++ b/htdocs/core/modules/modStock.class.php
    @@ -273,7 +273,7 @@ class modStock extends DolibarrModules
     			'e.rowid'=>'IdWarehouse','e.ref'=>'LocationSummary','e.description'=>'DescWareHouse','e.lieu'=>'LieuWareHouse','e.address'=>'Address','e.zip'=>'Zip',
     			'e.town'=>'Town','p.rowid'=>"ProductId",'p.ref'=>"Ref",'p.fk_product_type'=>"Type",'p.label'=>"Label",'p.description'=>"Description",'p.note'=>"Note",
     			'p.price'=>"Price",'p.tva_tx'=>'VAT','p.tosell'=>"OnSell",'p.tobuy'=>'OnBuy','p.duration'=>"Duration",'p.datec'=>'DateCreation',
    -			'p.tms'=>'DateModification','sm.rowid'=>'MovementId','sm.value'=>'Qty','sm.datem'=>'DateMovement','sm.label'=>'LabelMovement',
    +			'p.tms'=>'DateModification','sm.rowid'=>'MovementId','sm.value'=>'Qty','sm.datem'=>'DateMovement','sm.label'=>'MovementLabel',
     			'sm.inventorycode'=>'InventoryCode'
     		);
     		$this->export_TypeFields_array[$r]=array(
    diff --git a/htdocs/core/modules/propale/doc/pdf_azur.modules.php b/htdocs/core/modules/propale/doc/pdf_azur.modules.php
    index 40b73e4bf7f..adb52867a36 100644
    --- a/htdocs/core/modules/propale/doc/pdf_azur.modules.php
    +++ b/htdocs/core/modules/propale/doc/pdf_azur.modules.php
    @@ -1463,27 +1463,30 @@ class pdf_azur extends ModelePDFPropales
     		$pdf->SetXY($this->marge_gauche,$posy);
     
     		// Logo
    -		$logo=$conf->mycompany->dir_output.'/logos/'.$this->emetteur->logo;
    -		if ($this->emetteur->logo)
    +		if (empty($conf->global->PDF_DISABLE_MYCOMPANY_LOGO))
     		{
    -			if (is_readable($logo))
    +			$logo=$conf->mycompany->dir_output.'/logos/'.$this->emetteur->logo;
    +			if ($this->emetteur->logo)
     			{
    -			    $height=pdf_getHeightForLogo($logo);
    -			    $pdf->Image($logo, $this->marge_gauche, $posy, 0, $height);	// width=0 (auto)
    +				if (is_readable($logo))
    +				{
    +				    $height=pdf_getHeightForLogo($logo);
    +				    $pdf->Image($logo, $this->marge_gauche, $posy, 0, $height);	// width=0 (auto)
    +				}
    +				else
    +				{
    +					$pdf->SetTextColor(200,0,0);
    +					$pdf->SetFont('','B',$default_font_size - 2);
    +					$pdf->MultiCell(100, 3, $outputlangs->transnoentities("ErrorLogoFileNotFound",$logo), 0, 'L');
    +					$pdf->MultiCell(100, 3, $outputlangs->transnoentities("ErrorGoToGlobalSetup"), 0, 'L');
    +				}
     			}
     			else
     			{
    -				$pdf->SetTextColor(200,0,0);
    -				$pdf->SetFont('','B',$default_font_size - 2);
    -				$pdf->MultiCell(100, 3, $outputlangs->transnoentities("ErrorLogoFileNotFound",$logo), 0, 'L');
    -				$pdf->MultiCell(100, 3, $outputlangs->transnoentities("ErrorGoToGlobalSetup"), 0, 'L');
    +				$text=$this->emetteur->name;
    +				$pdf->MultiCell(100, 4, $outputlangs->convToOutputCharset($text), 0, 'L');
     			}
     		}
    -		else
    -		{
    -			$text=$this->emetteur->name;
    -			$pdf->MultiCell(100, 4, $outputlangs->convToOutputCharset($text), 0, 'L');
    -		}
     
     		$pdf->SetFont('','B',$default_font_size + 3);
     		$pdf->SetXY($posx,$posy);
    diff --git a/htdocs/core/modules/propale/doc/pdf_cyan.modules.php b/htdocs/core/modules/propale/doc/pdf_cyan.modules.php
    new file mode 100644
    index 00000000000..e43734039ca
    --- /dev/null
    +++ b/htdocs/core/modules/propale/doc/pdf_cyan.modules.php
    @@ -0,0 +1,1891 @@
    +<?php
    +/* Copyright (C) 2004-2014 Laurent Destailleur  <eldy@users.sourceforge.net>
    + * Copyright (C) 2005-2012 Regis Houssin        <regis.houssin@capnetworks.com>
    + * Copyright (C) 2008      Raphael Bertrand     <raphael.bertrand@resultic.fr>
    + * Copyright (C) 2010-2015 Juanjo Menent	    <jmenent@2byte.es>
    + * Copyright (C) 2012      Christophe Battarel   <christophe.battarel@altairis.fr>
    + * Copyright (C) 2012      Cedric Salvador      <csalvador@gpcsolutions.fr>
    + * Copyright (C) 2015      Marcos García        <marcosgdf@gmail.com>
    + * Copyright (C) 2017      Ferran Marcet        <fmarcet@2byte.es>
    + * Copyright (C) 2018       Frédéric France         <frederic.france@netlogic.fr>
    + *
    + * This program is free software; you can redistribute it and/or modify
    + * it under the terms of the GNU General Public License as published by
    + * the Free Software Foundation; either version 3 of the License, or
    + * (at your option) any later version.
    + *
    + * This program is distributed in the hope that it will be useful,
    + * but WITHOUT ANY WARRANTY; without even the implied warranty of
    + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    + * GNU General Public License for more details.
    + *
    + * You should have received a copy of the GNU General Public License
    + * along with this program. If not, see <http://www.gnu.org/licenses/>.
    + * or see http://www.gnu.org/
    + */
    +
    +/**
    + *	\file       htdocs/core/modules/propale/doc/pdf_cyan.modules.php
    + *	\ingroup    propale
    + *	\brief      Fichier de la classe permettant de generer les propales au modele Cyan
    + */
    +require_once DOL_DOCUMENT_ROOT.'/core/modules/propale/modules_propale.php';
    +require_once DOL_DOCUMENT_ROOT.'/product/class/product.class.php';
    +require_once DOL_DOCUMENT_ROOT.'/core/lib/company.lib.php';
    +require_once DOL_DOCUMENT_ROOT.'/core/lib/functions2.lib.php';
    +require_once DOL_DOCUMENT_ROOT.'/core/lib/pdf.lib.php';
    +
    +
    +/**
    + *	Class to generate PDF proposal Cyan
    + */
    +class pdf_cyan extends ModelePDFPropales
    +{
    +	public $db;
    +	public $name;
    +	public $description;
    +	public $update_main_doc_field;	// Save the name of generated file as the main doc when generating a doc with this template
    +	public $type;
    +
    +	public $phpmin = array(4,3,0); // Minimum version of PHP required by module
    +	public $version = 'development';
    +
    +	public $page_largeur;
    +	public $page_hauteur;
    +	public $format;
    +	public $marge_gauche;
    +	public	$marge_droite;
    +	public	$marge_haute;
    +	public	$marge_basse;
    +
    +	public $emetteur;	// Objet societe qui emet
    +
    +
    +	/**
    +	 *	Constructor
    +	 *
    +	 *  @param		DoliDB		$db      Database handler
    +	 */
    +	public function __construct($db)
    +	{
    +		global $conf,$langs,$mysoc;
    +
    +		// Translations
    +		$langs->loadLangs(array("main", "bills"));
    +
    +		$this->db = $db;
    +		$this->name = "cyan";
    +		$this->description = $langs->trans('DocModelCyanDescription');
    +		$this->update_main_doc_field = 1;		// Save the name of generated file as the main doc when generating a doc with this template
    +
    +		// Dimension page
    +		$this->type = 'pdf';
    +		$formatarray=pdf_getFormat();
    +		$this->page_largeur = $formatarray['width'];
    +		$this->page_hauteur = $formatarray['height'];
    +		$this->format = array($this->page_largeur,$this->page_hauteur);
    +		$this->marge_gauche=isset($conf->global->MAIN_PDF_MARGIN_LEFT)?$conf->global->MAIN_PDF_MARGIN_LEFT:10;
    +		$this->marge_droite=isset($conf->global->MAIN_PDF_MARGIN_RIGHT)?$conf->global->MAIN_PDF_MARGIN_RIGHT:10;
    +		$this->marge_haute =isset($conf->global->MAIN_PDF_MARGIN_TOP)?$conf->global->MAIN_PDF_MARGIN_TOP:10;
    +		$this->marge_basse =isset($conf->global->MAIN_PDF_MARGIN_BOTTOM)?$conf->global->MAIN_PDF_MARGIN_BOTTOM:10;
    +
    +		$this->option_logo = 1;                    // Affiche logo
    +		$this->option_tva = 1;                     // Gere option tva FACTURE_TVAOPTION
    +		$this->option_modereg = 1;                 // Affiche mode reglement
    +		$this->option_condreg = 1;                 // Affiche conditions reglement
    +		$this->option_codeproduitservice = 1;      // Affiche code produit-service
    +		$this->option_multilang = 1;               // Dispo en plusieurs langues
    +		$this->option_escompte = 0;                // Affiche si il y a eu escompte
    +		$this->option_credit_note = 0;             // Support credit notes
    +		$this->option_freetext = 1;				   // Support add of a personalised text
    +		$this->option_draft_watermark = 1;		   //Support add of a watermark on drafts
    +
    +		$this->franchise=!$mysoc->tva_assuj;
    +
    +		// Get source company
    +		$this->emetteur=$mysoc;
    +		if (empty($this->emetteur->country_code)) $this->emetteur->country_code=substr($langs->defaultlang,-2);    // By default, if was not defined
    +
    +		// Define position of columns
    +		$this->posxdesc=$this->marge_gauche+1;
    +
    +
    +
    +		$this->tva=array();
    +		$this->localtax1=array();
    +		$this->localtax2=array();
    +		$this->atleastoneratenotnull=0;
    +		$this->atleastonediscount=0;
    +	}
    +
    +    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
    +	/**
    +     *  Function to build pdf onto disk
    +     *
    +     *  @param		Object		$object				Object to generate
    +     *  @param		Translate	$outputlangs		Lang output object
    +     *  @param		string		$srctemplatepath	Full path of source filename for generator using a template file
    +     *  @param		int			$hidedetails		Do not show line details
    +     *  @param		int			$hidedesc			Do not show desc
    +     *  @param		int			$hideref			Do not show ref
    +     *  @return     int             				1=OK, 0=KO
    +	 */
    +	public function write_file($object,$outputlangs,$srctemplatepath='',$hidedetails=0,$hidedesc=0,$hideref=0)
    +	{
    +	  // phpcs:enable
    +		global $user,$langs,$conf,$mysoc,$db,$hookmanager,$nblignes;
    +
    +		if (! is_object($outputlangs)) $outputlangs=$langs;
    +		// For backward compatibility with FPDF, force output charset to ISO, because FPDF expect text to be encoded in ISO
    +		if (! empty($conf->global->MAIN_USE_FPDF)) $outputlangs->charset_output='ISO-8859-1';
    +
    +		$outputlangs->load("main");
    +		$outputlangs->load("dict");
    +		$outputlangs->load("companies");
    +		$outputlangs->load("bills");
    +		$outputlangs->load("propal");
    +		$outputlangs->load("products");
    +
    +		$nblignes = count($object->lines);
    +
    +		// Loop on each lines to detect if there is at least one image to show
    +		$realpatharray=array();
    +		$this->atleastonephoto = false;
    +		if (! empty($conf->global->MAIN_GENERATE_PROPOSALS_WITH_PICTURE))
    +		{
    +			$objphoto = new Product($this->db);
    +
    +			for ($i = 0 ; $i < $nblignes ; $i++)
    +			{
    +				if (empty($object->lines[$i]->fk_product)) continue;
    +
    +				$objphoto->fetch($object->lines[$i]->fk_product);
    +                //var_dump($objphoto->ref);exit;
    +				if (! empty($conf->global->PRODUCT_USE_OLD_PATH_FOR_PHOTO))
    +				{
    +					$pdir[0] = get_exdir($objphoto->id,2,0,0,$objphoto,'product') . $objphoto->id ."/photos/";
    +					$pdir[1] = get_exdir(0,0,0,0,$objphoto,'product') . dol_sanitizeFileName($objphoto->ref).'/';
    +				}
    +				else
    +				{
    +					$pdir[0] = get_exdir(0,0,0,0,$objphoto,'product') . dol_sanitizeFileName($objphoto->ref).'/';				// default
    +					$pdir[1] = get_exdir($objphoto->id,2,0,0,$objphoto,'product') . $objphoto->id ."/photos/";	// alternative
    +				}
    +
    +				$arephoto = false;
    +				foreach ($pdir as $midir)
    +				{
    +					if (! $arephoto)
    +					{
    +						$dir = $conf->product->dir_output.'/'.$midir;
    +
    +						foreach ($objphoto->liste_photos($dir,1) as $key => $obj)
    +						{
    +							if (empty($conf->global->CAT_HIGH_QUALITY_IMAGES))		// If CAT_HIGH_QUALITY_IMAGES not defined, we use thumb if defined and then original photo
    +							{
    +								if ($obj['photo_vignette'])
    +								{
    +									$filename= $obj['photo_vignette'];
    +								}
    +								else
    +								{
    +									$filename=$obj['photo'];
    +								}
    +							}
    +							else
    +							{
    +								$filename=$obj['photo'];
    +							}
    +
    +							$realpath = $dir.$filename;
    +							$arephoto = true;
    +							$this->atleastonephoto = true;
    +						}
    +					}
    +				}
    +
    +				if ($realpath && $arephoto) $realpatharray[$i]=$realpath;
    +			}
    +		}
    +
    +		if (count($realpatharray) == 0) $this->posxpicture=$this->posxtva;
    +
    +		if ($conf->propal->multidir_output[$conf->entity])
    +		{
    +			$object->fetch_thirdparty();
    +
    +			$deja_regle = 0;
    +
    +			// Definition of $dir and $file
    +			if ($object->specimen)
    +			{
    +				$dir = $conf->propal->multidir_output[$conf->entity];
    +				$file = $dir . "/SPECIMEN.pdf";
    +			}
    +			else
    +			{
    +				$objectref = dol_sanitizeFileName($object->ref);
    +				$dir = $conf->propal->multidir_output[$object->entity] . "/" . $objectref;
    +				$file = $dir . "/" . $objectref . ".pdf";
    +			}
    +
    +			if (! file_exists($dir))
    +			{
    +				if (dol_mkdir($dir) < 0)
    +				{
    +					$this->error=$langs->transnoentities("ErrorCanNotCreateDir",$dir);
    +					return 0;
    +				}
    +			}
    +
    +			if (file_exists($dir))
    +			{
    +				// Add pdfgeneration hook
    +				if (! is_object($hookmanager))
    +				{
    +					include_once DOL_DOCUMENT_ROOT.'/core/class/hookmanager.class.php';
    +					$hookmanager=new HookManager($this->db);
    +				}
    +				$hookmanager->initHooks(array('pdfgeneration'));
    +				$parameters=array('file'=>$file,'object'=>$object,'outputlangs'=>$outputlangs);
    +				global $action;
    +				$reshook=$hookmanager->executeHooks('beforePDFCreation',$parameters,$object,$action);    // Note that $action and $object may have been modified by some hooks
    +
    +				// Create pdf instance
    +                $pdf=pdf_getInstance($this->format);
    +                $default_font_size = pdf_getPDFFontSize($outputlangs);	// Must be after pdf_getInstance
    +	            $pdf->SetAutoPageBreak(1,0);
    +
    +                if (class_exists('TCPDF'))
    +                {
    +                    $pdf->setPrintHeader(false);
    +                    $pdf->setPrintFooter(false);
    +                }
    +                $pdf->SetFont(pdf_getPDFFont($outputlangs));
    +                // Set path to the background PDF File
    +                if (! empty($conf->global->MAIN_ADD_PDF_BACKGROUND))
    +                {
    +                    $pagecount = $pdf->setSourceFile($conf->mycompany->dir_output.'/'.$conf->global->MAIN_ADD_PDF_BACKGROUND);
    +                    $tplidx = $pdf->importPage(1);
    +                }
    +
    +				$pdf->Open();
    +				$pagenb=0;
    +				$pdf->SetDrawColor(128,128,128);
    +
    +				$pdf->SetTitle($outputlangs->convToOutputCharset($object->ref));
    +				$pdf->SetSubject($outputlangs->transnoentities("PdfCommercialProposalTitle"));
    +				$pdf->SetCreator("Dolibarr ".DOL_VERSION);
    +				$pdf->SetAuthor($outputlangs->convToOutputCharset($user->getFullName($outputlangs)));
    +				$pdf->SetKeyWords($outputlangs->convToOutputCharset($object->ref)." ".$outputlangs->transnoentities("PdfCommercialProposalTitle")." ".$outputlangs->convToOutputCharset($object->thirdparty->name));
    +				if (! empty($conf->global->MAIN_DISABLE_PDF_COMPRESSION)) $pdf->SetCompression(false);
    +
    +				$pdf->SetMargins($this->marge_gauche, $this->marge_haute, $this->marge_droite);   // Left, Top, Right
    +
    +				// Does we have at least one line with discount $this->atleastonediscount
    +				foreach ($object->lines as $line) {
    +				    if ($line->remise_percent){
    +				        $this->atleastonediscount = true;
    +				        break;
    +				    }
    +				}
    +
    +
    +
    +				// New page
    +				$pdf->AddPage();
    +				if (! empty($tplidx)) $pdf->useTemplate($tplidx);
    +				$pagenb++;
    +
    +                $heightforinfotot = 40;	// Height reserved to output the info and total part
    +                $heightforsignature = empty($conf->global->PROPAL_DISABLE_SIGNATURE)?(pdfGetHeightForHtmlContent($pdf, $outputlangs->transnoentities("ProposalCustomerSignature"))+10):0;
    +                $heightforfreetext= (isset($conf->global->MAIN_PDF_FREETEXT_HEIGHT)?$conf->global->MAIN_PDF_FREETEXT_HEIGHT:5);	// Height reserved to output the free text on last page
    +                $heightforfooter = $this->marge_basse + (empty($conf->global->MAIN_GENERATE_DOCUMENTS_SHOW_FOOT_DETAILS)?12:22);	// Height reserved to output the footer (value include bottom margin)
    +                //print $heightforinfotot + $heightforsignature + $heightforfreetext + $heightforfooter;exit;
    +
    +				$top_shift = $this->_pagehead($pdf, $object, 1, $outputlangs);
    +				$pdf->SetFont('','', $default_font_size - 1);
    +				$pdf->MultiCell(0, 3, '');		// Set interline to 3
    +				$pdf->SetTextColor(0,0,0);
    +
    +
    +	            $tab_top = 90+$top_shift;
    +				$tab_top_newpage = (empty($conf->global->MAIN_PDF_DONOTREPEAT_HEAD)?42+$top_shift:10);
    +
    +
    +				// Incoterm
    +				$height_incoterms = 0;
    +				if ($conf->incoterm->enabled)
    +				{
    +					$desc_incoterms = $object->getIncotermsForPDF();
    +					if ($desc_incoterms)
    +					{
    +						$tab_top -= 2;
    +
    +						$pdf->SetFont('','', $default_font_size - 1);
    +						$pdf->writeHTMLCell(190, 3, $this->posxdesc-1, $tab_top-1, dol_htmlentitiesbr($desc_incoterms), 0, 1);
    +						$nexY = $pdf->GetY();
    +						$height_incoterms=$nexY-$tab_top;
    +
    +						// Rect prend une longueur en 3eme param
    +						$pdf->SetDrawColor(192,192,192);
    +						$pdf->Rect($this->marge_gauche, $tab_top-1, $this->page_largeur-$this->marge_gauche-$this->marge_droite, $height_incoterms+1);
    +
    +						$tab_top = $nexY+6;
    +					}
    +				}
    +
    +				// Affiche notes
    +				$notetoshow=empty($object->note_public)?'':$object->note_public;
    +				if (! empty($conf->global->MAIN_ADD_SALE_REP_SIGNATURE_IN_NOTE))
    +				{
    +					// Get first sale rep
    +					if (is_object($object->thirdparty))
    +					{
    +						$salereparray=$object->thirdparty->getSalesRepresentatives($user);
    +						$salerepobj=new User($this->db);
    +						$salerepobj->fetch($salereparray[0]['id']);
    +						if (! empty($salerepobj->signature)) $notetoshow=dol_concatdesc($notetoshow, $salerepobj->signature);
    +					}
    +				}
    +				if (! empty($conf->global->MAIN_ADD_CREATOR_IN_NOTE) && $object->user_author_id > 0)
    +				{
    +				    $tmpuser=new User($this->db);
    +				    $tmpuser->fetch($object->user_author_id);
    +				    $notetoshow.='Affaire suivi par '.$tmpuser->getFullName($langs);
    +				    if ($tmpuser->email) $notetoshow.=',  Mail: '.$tmpuser->email;
    +				    if ($tmpuser->office_phone) $notetoshow.=', Tel: '.$tmpuser->office_phone;
    +				}
    +
    +				$pagenb = $pdf->getPage();
    +				if ($notetoshow)
    +				{
    +					$tab_top -= 2;
    +
    +				    $tab_width = $this->page_largeur-$this->marge_gauche-$this->marge_droite;
    +				    $pageposbeforenote = $pagenb;
    +
    +					$substitutionarray=pdf_getSubstitutionArray($outputlangs, null, $object);
    +					complete_substitutions_array($substitutionarray, $outputlangs, $object);
    +					$notetoshow = make_substitutions($notetoshow, $substitutionarray, $outputlangs);
    +
    +
    +					$pdf->startTransaction();
    +
    +					$pdf->SetFont('','', $default_font_size - 1);
    +					$pdf->writeHTMLCell(190, 3, $this->posxdesc-1, $tab_top, dol_htmlentitiesbr($notetoshow), 0, 1);
    +					// Description
    +					$pageposafternote=$pdf->getPage();
    +					$posyafter = $pdf->GetY();
    +
    +					if($pageposafternote>$pageposbeforenote )
    +					{
    +					    $pdf->rollbackTransaction(true);
    +
    +					    // prepar pages to receive notes
    +					    while ($pagenb < $pageposafternote) {
    +					        $pdf->AddPage();
    +					        $pagenb++;
    +					        if (! empty($tplidx)) $pdf->useTemplate($tplidx);
    +					        if (empty($conf->global->MAIN_PDF_DONOTREPEAT_HEAD)) $this->_pagehead($pdf, $object, 0, $outputlangs);
    +					        // $this->_pagefoot($pdf,$object,$outputlangs,1);
    +					        $pdf->setTopMargin($tab_top_newpage);
    +					        // The only function to edit the bottom margin of current page to set it.
    +					        $pdf->setPageOrientation('', 1, $heightforfooter + $heightforfreetext);
    +					    }
    +
    +					    // back to start
    +					    $pdf->setPage($pageposbeforenote);
    +					    $pdf->setPageOrientation('', 1, $heightforfooter + $heightforfreetext);
    +					    $pdf->SetFont('','', $default_font_size - 1);
    +					    $pdf->writeHTMLCell(190, 3, $this->posxdesc-1, $tab_top, dol_htmlentitiesbr($notetoshow), 0, 1);
    +					    $pageposafternote=$pdf->getPage();
    +
    +					    $posyafter = $pdf->GetY();
    +
    +					    if ($posyafter > ($this->page_hauteur - ($heightforfooter+$heightforfreetext+20)))	// There is no space left for total+free text
    +					    {
    +					        $pdf->AddPage('','',true);
    +					        $pagenb++;
    +					        $pageposafternote++;
    +					        $pdf->setPage($pageposafternote);
    +					        $pdf->setTopMargin($tab_top_newpage);
    +					        // The only function to edit the bottom margin of current page to set it.
    +					        $pdf->setPageOrientation('', 1, $heightforfooter + $heightforfreetext);
    +					        //$posyafter = $tab_top_newpage;
    +					    }
    +
    +
    +					    // apply note frame to previus pages
    +					    $i = $pageposbeforenote;
    +					    while ($i < $pageposafternote) {
    +					        $pdf->setPage($i);
    +
    +
    +					        $pdf->SetDrawColor(128,128,128);
    +					        // Draw note frame
    +					        if($i>$pageposbeforenote){
    +					            $height_note = $this->page_hauteur - ($tab_top_newpage + $heightforfooter);
    +					            $pdf->Rect($this->marge_gauche, $tab_top_newpage-1, $tab_width, $height_note + 1);
    +					        }
    +					        else{
    +					            $height_note = $this->page_hauteur - ($tab_top + $heightforfooter);
    +					            $pdf->Rect($this->marge_gauche, $tab_top-1, $tab_width, $height_note + 1);
    +					        }
    +
    +					        // Add footer
    +					        $pdf->setPageOrientation('', 1, 0);	// The only function to edit the bottom margin of current page to set it.
    +					        $this->_pagefoot($pdf,$object,$outputlangs,1);
    +
    +					        $i++;
    +					    }
    +
    +					    // apply note frame to last page
    +					    $pdf->setPage($pageposafternote);
    +					    if (! empty($tplidx)) $pdf->useTemplate($tplidx);
    +					    if (empty($conf->global->MAIN_PDF_DONOTREPEAT_HEAD)) $this->_pagehead($pdf, $object, 0, $outputlangs);
    +					    $height_note=$posyafter-$tab_top_newpage;
    +					    $pdf->Rect($this->marge_gauche, $tab_top_newpage-1, $tab_width, $height_note+1);
    +
    +					}
    +					else // No pagebreak
    +					{
    +					    $pdf->commitTransaction();
    +					    $posyafter = $pdf->GetY();
    +					    $height_note=$posyafter-$tab_top;
    +					    $pdf->Rect($this->marge_gauche, $tab_top-1, $tab_width, $height_note+1);
    +
    +
    +					    if($posyafter > ($this->page_hauteur - ($heightforfooter+$heightforfreetext+20)) )
    +					    {
    +					        // not enough space, need to add page
    +					        $pdf->AddPage('','',true);
    +					        $pagenb++;
    +					        $pageposafternote++;
    +					        $pdf->setPage($pageposafternote);
    +					        if (! empty($tplidx)) $pdf->useTemplate($tplidx);
    +					        if (empty($conf->global->MAIN_PDF_DONOTREPEAT_HEAD)) $this->_pagehead($pdf, $object, 0, $outputlangs);
    +
    +					        $posyafter = $tab_top_newpage;
    +					    }
    +
    +					}
    +
    +					$tab_height = $tab_height - $height_note;
    +					$tab_top = $posyafter +6;
    +				}
    +				else
    +				{
    +					$height_note=0;
    +				}
    +
    +				$iniY = $tab_top + 7;
    +				$curY = $tab_top + 7;
    +				$nexY = $tab_top + 7;
    +
    +				// Use new auto collum system
    +				$this->prepareArrayColumnField($object,$outputlangs,$hidedetails,$hidedesc,$hideref);
    +
    +				// Loop on each lines
    +				$pageposbeforeprintlines=$pdf->getPage();
    +				$pagenb = $pageposbeforeprintlines;
    +				for ($i = 0; $i < $nblignes; $i++)
    +				{
    +					$curY = $nexY;
    +					$pdf->SetFont('','', $default_font_size - 1);   // Into loop to work with multipage
    +					$pdf->SetTextColor(0,0,0);
    +
    +					// Define size of image if we need it
    +					$imglinesize=array();
    +					if (! empty($realpatharray[$i])) $imglinesize=pdf_getSizeForImage($realpatharray[$i]);
    +
    +					$pdf->setTopMargin($tab_top_newpage);
    +					$pdf->setPageOrientation('', 1, $heightforfooter+$heightforfreetext+$heightforsignature+$heightforinfotot);	// The only function to edit the bottom margin of current page to set it.
    +					$pageposbefore=$pdf->getPage();
    +
    +					$showpricebeforepagebreak=1;
    +					$posYAfterImage=0;
    +					$posYAfterDescription=0;
    +
    +					if($this->getColumnStatus('photo'))
    +					{
    +    					// We start with Photo of product line
    +    					if (isset($imglinesize['width']) && isset($imglinesize['height']) && ($curY + $imglinesize['height']) > ($this->page_hauteur-($heightforfooter+$heightforfreetext+$heightforsignature+$heightforinfotot)))	// If photo too high, we moved completely on new page
    +    					{
    +    						$pdf->AddPage('','',true);
    +    						if (! empty($tplidx)) $pdf->useTemplate($tplidx);
    +    						//if (empty($conf->global->MAIN_PDF_DONOTREPEAT_HEAD)) $this->_pagehead($pdf, $object, 0, $outputlangs);
    +    						$pdf->setPage($pageposbefore+1);
    +
    +    						$curY = $tab_top_newpage;
    +    						$showpricebeforepagebreak=0;
    +    					}
    +
    +
    +    					if (!empty($this->cols['photo']) && isset($imglinesize['width']) && isset($imglinesize['height']))
    +    					{
    +    						$pdf->Image($realpatharray[$i], $this->getColumnContentXStart('photo'), $curY, $imglinesize['width'], $imglinesize['height'], '', '', '', 2, 300);	// Use 300 dpi
    +    						// $pdf->Image does not increase value return by getY, so we save it manually
    +    						$posYAfterImage=$curY+$imglinesize['height'];
    +    					}
    +					}
    +
    +					// Description of product line
    +					if($this->getColumnStatus('desc'))
    +					{
    +    					$pdf->startTransaction();
    +    					pdf_writelinedesc($pdf,$object,$i,$outputlangs,$this->getColumnContentWidth('desc'),3,$this->getColumnContentXStart('desc'),$curY,$hideref,$hidedesc);
    +    					$pageposafter=$pdf->getPage();
    +    					if ($pageposafter > $pageposbefore)	// There is a pagebreak
    +    					{
    +    						$pdf->rollbackTransaction(true);
    +    						$pageposafter=$pageposbefore;
    +    						//print $pageposafter.'-'.$pageposbefore;exit;
    +    						$pdf->setPageOrientation('', 1, $heightforfooter);	// The only function to edit the bottom margin of current page to set it.
    +    						pdf_writelinedesc($pdf,$object,$i,$outputlangs,$this->getColumnContentWidth('desc'),3,$this->getColumnContentXStart('desc'),$curY,$hideref,$hidedesc);
    +
    +    						$pageposafter=$pdf->getPage();
    +    						$posyafter=$pdf->GetY();
    +    						//var_dump($posyafter); var_dump(($this->page_hauteur - ($heightforfooter+$heightforfreetext+$heightforinfotot))); exit;
    +    						if ($posyafter > ($this->page_hauteur - ($heightforfooter+$heightforfreetext+$heightforsignature+$heightforinfotot)))	// There is no space left for total+free text
    +    						{
    +    							if ($i == ($nblignes-1))	// No more lines, and no space left to show total, so we create a new page
    +    							{
    +    								$pdf->AddPage('','',true);
    +    								if (! empty($tplidx)) $pdf->useTemplate($tplidx);
    +    								//if (empty($conf->global->MAIN_PDF_DONOTREPEAT_HEAD)) $this->_pagehead($pdf, $object, 0, $outputlangs);
    +    								$pdf->setPage($pageposafter+1);
    +    							}
    +    						}
    +    						else
    +    						{
    +    							// We found a page break
    +    							$showpricebeforepagebreak=0;
    +    						}
    +    					}
    +    					else	// No pagebreak
    +    					{
    +    						$pdf->commitTransaction();
    +    					}
    +    					$posYAfterDescription=$pdf->GetY();
    +					}
    +
    +					$nexY = $pdf->GetY();
    +					$pageposafter=$pdf->getPage();
    +
    +					$pdf->setPage($pageposbefore);
    +					$pdf->setTopMargin($this->marge_haute);
    +					$pdf->setPageOrientation('', 1, 0);	// The only function to edit the bottom margin of current page to set it.
    +
    +					// We suppose that a too long description or photo were moved completely on next page
    +					if ($pageposafter > $pageposbefore && empty($showpricebeforepagebreak)) {
    +						$pdf->setPage($pageposafter); $curY = $tab_top_newpage;
    +					}
    +
    +					$pdf->SetFont('','', $default_font_size - 1);   // On repositionne la police par defaut
    +
    +					// VAT Rate
    +					if ($this->getColumnStatus('vat'))
    +					{
    +					    $vat_rate = pdf_getlinevatrate($object, $i, $outputlangs, $hidedetails);
    +					    $this->printStdColumnContent($pdf, $curY, 'vat', $vat_rate);
    +					    $nexY = max($pdf->GetY(),$nexY);
    +					}
    +
    +					// Unit price before discount
    +					if ($this->getColumnStatus('subprice'))
    +					{
    +					    $up_excl_tax = pdf_getlineupexcltax($object, $i, $outputlangs, $hidedetails);
    +					    $this->printStdColumnContent($pdf, $curY, 'subprice', $up_excl_tax);
    +					    $nexY = max($pdf->GetY(),$nexY);
    +					}
    +
    +					// Quantity
    +					// Enough for 6 chars
    +					if ($this->getColumnStatus('qty'))
    +					{
    +					    $qty = pdf_getlineqty($object, $i, $outputlangs, $hidedetails);
    +					    $this->printStdColumnContent($pdf, $curY, 'qty', $qty);
    +					    $nexY = max($pdf->GetY(),$nexY);
    +					}
    +
    +
    +					// Unit
    +					if ($this->getColumnStatus('unit'))
    +					{
    +					    $unit = pdf_getlineunit($object, $i, $outputlangs, $hidedetails, $hookmanager);
    +					    $this->printStdColumnContent($pdf, $curY, 'unit', $unit);
    +					    $nexY = max($pdf->GetY(),$nexY);
    +					}
    +
    +					// Discount on line
    +					if ($this->getColumnStatus('discount') && $object->lines[$i]->remise_percent)
    +					{
    +					    $remise_percent = pdf_getlineremisepercent($object, $i, $outputlangs, $hidedetails);
    +					    $this->printStdColumnContent($pdf, $curY, 'discount', $remise_percent);
    +					    $nexY = max($pdf->GetY(),$nexY);
    +					}
    +
    +					// Total HT line
    +					if ($this->getColumnStatus('totalexcltax'))
    +					{
    +					    $total_excl_tax = pdf_getlinetotalexcltax($object, $i, $outputlangs, $hidedetails);
    +					    $this->printStdColumnContent($pdf, $curY, 'totalexcltax', $total_excl_tax);
    +					    $nexY = max($pdf->GetY(),$nexY);
    +					}
    +
    +
    +					$parameters=array(
    +					    'object' => $object,
    +					    'i' => $i,
    +					    'pdf' =>& $pdf,
    +					    'curY' =>& $curY,
    +					    'nexY' =>& $nexY,
    +					    'outputlangs' => $outputlangs,
    +					    'hidedetails' => $hidedetails
    +					);
    +					$reshook=$hookmanager->executeHooks('printPDFline',$parameters,$this);    // Note that $object may have been modified by hook
    +
    +
    +
    +					// Collecte des totaux par valeur de tva dans $this->tva["taux"]=total_tva
    +					if ($conf->multicurrency->enabled && $object->multicurrency_tx != 1) $tvaligne=$object->lines[$i]->multicurrency_total_tva;
    +					else $tvaligne=$object->lines[$i]->total_tva;
    +
    +					$localtax1ligne=$object->lines[$i]->total_localtax1;
    +					$localtax2ligne=$object->lines[$i]->total_localtax2;
    +					$localtax1_rate=$object->lines[$i]->localtax1_tx;
    +					$localtax2_rate=$object->lines[$i]->localtax2_tx;
    +					$localtax1_type=$object->lines[$i]->localtax1_type;
    +					$localtax2_type=$object->lines[$i]->localtax2_type;
    +
    +					if ($object->remise_percent) $tvaligne-=($tvaligne*$object->remise_percent)/100;
    +					if ($object->remise_percent) $localtax1ligne-=($localtax1ligne*$object->remise_percent)/100;
    +					if ($object->remise_percent) $localtax2ligne-=($localtax2ligne*$object->remise_percent)/100;
    +
    +					$vatrate=(string) $object->lines[$i]->tva_tx;
    +
    +					// Retrieve type from database for backward compatibility with old records
    +					if ((! isset($localtax1_type) || $localtax1_type=='' || ! isset($localtax2_type) || $localtax2_type=='') // if tax type not defined
    +					&& (! empty($localtax1_rate) || ! empty($localtax2_rate))) // and there is local tax
    +					{
    +						$localtaxtmp_array=getLocalTaxesFromRate($vatrate,0,$object->thirdparty,$mysoc);
    +						$localtax1_type = $localtaxtmp_array[0];
    +						$localtax2_type = $localtaxtmp_array[2];
    +					}
    +
    +				    // retrieve global local tax
    +					if ($localtax1_type && $localtax1ligne != 0)
    +						$this->localtax1[$localtax1_type][$localtax1_rate]+=$localtax1ligne;
    +					if ($localtax2_type && $localtax2ligne != 0)
    +						$this->localtax2[$localtax2_type][$localtax2_rate]+=$localtax2ligne;
    +
    +					if (($object->lines[$i]->info_bits & 0x01) == 0x01) $vatrate.='*';
    +					if (! isset($this->tva[$vatrate]))				$this->tva[$vatrate]=0;
    +					$this->tva[$vatrate] += $tvaligne;
    +
    +					if ($posYAfterImage > $posYAfterDescription) $nexY=$posYAfterImage;
    +
    +					// Add line
    +					if (! empty($conf->global->MAIN_PDF_DASH_BETWEEN_LINES) && $i < ($nblignes - 1))
    +					{
    +						$pdf->setPage($pageposafter);
    +						$pdf->SetLineStyle(array('dash'=>'1,1','color'=>array(80,80,80)));
    +						//$pdf->SetDrawColor(190,190,200);
    +						$pdf->line($this->marge_gauche, $nexY+1, $this->page_largeur - $this->marge_droite, $nexY+1);
    +						$pdf->SetLineStyle(array('dash'=>0));
    +					}
    +
    +					$nexY+=2;    // Passe espace entre les lignes
    +
    +					// Detect if some page were added automatically and output _tableau for past pages
    +					while ($pagenb < $pageposafter)
    +					{
    +						$pdf->setPage($pagenb);
    +						if ($pagenb == $pageposbeforeprintlines)
    +						{
    +							$this->_tableau($pdf, $tab_top, $this->page_hauteur - $tab_top - $heightforfooter, 0, $outputlangs, 0, 1, $object->multicurrency_code);
    +						}
    +						else
    +						{
    +							$this->_tableau($pdf, $tab_top_newpage, $this->page_hauteur - $tab_top_newpage - $heightforfooter, 0, $outputlangs, 1, 1, $object->multicurrency_code);
    +						}
    +						$this->_pagefoot($pdf,$object,$outputlangs,1);
    +						$pagenb++;
    +						$pdf->setPage($pagenb);
    +						$pdf->setPageOrientation('', 1, 0);	// The only function to edit the bottom margin of current page to set it.
    +						if (empty($conf->global->MAIN_PDF_DONOTREPEAT_HEAD)) $this->_pagehead($pdf, $object, 0, $outputlangs);
    +					}
    +					if (isset($object->lines[$i+1]->pagebreak) && $object->lines[$i+1]->pagebreak)
    +					{
    +					    if ($pagenb == $pageposafter)
    +						{
    +							$this->_tableau($pdf, $tab_top, $this->page_hauteur - $tab_top - $heightforfooter, 0, $outputlangs, 0, 1, $object->multicurrency_code);
    +						}
    +						else
    +						{
    +							$this->_tableau($pdf, $tab_top_newpage, $this->page_hauteur - $tab_top_newpage - $heightforfooter, 0, $outputlangs, 1, 1, $object->multicurrency_code);
    +						}
    +						$this->_pagefoot($pdf,$object,$outputlangs,1);
    +						// New page
    +						$pdf->AddPage();
    +						if (! empty($tplidx)) $pdf->useTemplate($tplidx);
    +						$pagenb++;
    +						if (empty($conf->global->MAIN_PDF_DONOTREPEAT_HEAD)) $this->_pagehead($pdf, $object, 0, $outputlangs);
    +					}
    +				}
    +
    +				// Show square
    +				if ($pagenb == $pageposbeforeprintlines)
    +				{
    +					$this->_tableau($pdf, $tab_top, $this->page_hauteur - $tab_top - $heightforinfotot - $heightforfreetext - $heightforsignature - $heightforfooter, 0, $outputlangs, 0, 0, $object->multicurrency_code);
    +					$bottomlasttab=$this->page_hauteur - $heightforinfotot - $heightforfreetext - $heightforsignature - $heightforfooter + 1;
    +				}
    +				else
    +				{
    +					$this->_tableau($pdf, $tab_top_newpage, $this->page_hauteur - $tab_top_newpage - $heightforinfotot - $heightforfreetext - $heightforsignature - $heightforfooter, 0, $outputlangs, 1, 0, $object->multicurrency_code);
    +					$bottomlasttab=$this->page_hauteur - $heightforinfotot - $heightforfreetext - $heightforsignature - $heightforfooter + 1;
    +				}
    +
    +				// Affiche zone infos
    +				$posy=$this->drawInfoTable($pdf, $object, $bottomlasttab, $outputlangs);
    +
    +				// Affiche zone totaux
    +				$posy=$this->drawTotalTable($pdf, $object, 0, $bottomlasttab, $outputlangs);
    +
    +				// Affiche zone versements
    +				/*
    +				if ($deja_regle || $amount_credit_notes_included || $amount_deposits_included)
    +				{
    +					$posy=$this->drawPaymentsTable($pdf, $object, $posy, $outputlangs);
    +				}
    +				*/
    +
    +				// Customer signature area
    +				if (empty($conf->global->PROPAL_DISABLE_SIGNATURE))
    +				{
    +				    $posy=$this->drawSignatureArea($pdf, $object, $posy, $outputlangs);
    +				}
    +
    +				// Pied de page
    +				$this->_pagefoot($pdf,$object,$outputlangs);
    +				if (method_exists($pdf,'AliasNbPages')) $pdf->AliasNbPages();
    +
    +				//If propal merge product PDF is active
    +				if (!empty($conf->global->PRODUIT_PDF_MERGE_PROPAL))
    +				{
    +					require_once DOL_DOCUMENT_ROOT.'/product/class/propalmergepdfproduct.class.php';
    +
    +					$already_merged = array ();
    +					foreach ( $object->lines as $line ) {
    +						if (! empty($line->fk_product) && ! (in_array($line->fk_product, $already_merged))) {
    +							// Find the desire PDF
    +							$filetomerge = new Propalmergepdfproduct($this->db);
    +
    +							if ($conf->global->MAIN_MULTILANGS) {
    +								$filetomerge->fetch_by_product($line->fk_product, $outputlangs->defaultlang);
    +							} else {
    +								$filetomerge->fetch_by_product($line->fk_product);
    +							}
    +
    +							$already_merged[] = $line->fk_product;
    +
    +							$product = new Product($this->db);
    +							$product->fetch($line->fk_product);
    +
    +							if ($product->entity!=$conf->entity) {
    +								$entity_product_file=$product->entity;
    +							} else {
    +								$entity_product_file=$conf->entity;
    +							}
    +
    +							// If PDF is selected and file is not empty
    +							if (count($filetomerge->lines) > 0) {
    +								foreach ( $filetomerge->lines as $linefile ) {
    +									if (! empty($linefile->id) && ! empty($linefile->file_name)) {
    +
    +
    +										if (! empty($conf->global->PRODUCT_USE_OLD_PATH_FOR_PHOTO))
    +										{
    +											if (! empty($conf->product->enabled)) {
    +												$filetomerge_dir = $conf->product->multidir_output[$entity_product_file] . '/' . get_exdir($product->id,2,0,0,$product,'product') . $product->id ."/photos";
    +											} elseif (! empty($conf->service->enabled)) {
    +												$filetomerge_dir = $conf->service->multidir_output[$entity_product_file] . '/' . get_exdir($product->id,2,0,0,$product,'product') . $product->id ."/photos";
    +											}
    +										}
    +										else
    +										{
    +											if (! empty($conf->product->enabled)) {
    +												$filetomerge_dir = $conf->product->multidir_output[$entity_product_file] . '/' . get_exdir(0,0,0,0,$product,'product') . dol_sanitizeFileName($product->ref);
    +											} elseif (! empty($conf->service->enabled)) {
    +												$filetomerge_dir = $conf->service->multidir_output[$entity_product_file] . '/' . get_exdir(0,0,0,0,$product,'product') . dol_sanitizeFileName($product->ref);
    +											}
    +										}
    +
    +										dol_syslog(get_class($this) . ':: upload_dir=' . $filetomerge_dir, LOG_DEBUG);
    +
    +										$infile = $filetomerge_dir . '/' . $linefile->file_name;
    +										if (file_exists($infile) && is_readable($infile)) {
    +											$pagecount = $pdf->setSourceFile($infile);
    +											for($i = 1; $i <= $pagecount; $i ++) {
    +												$tplIdx = $pdf->importPage($i);
    +												if ($tplIdx!==false) {
    +													$s = $pdf->getTemplatesize($tplIdx);
    +													$pdf->AddPage($s['h'] > $s['w'] ? 'P' : 'L');
    +													$pdf->useTemplate($tplIdx);
    +												} else {
    +													setEventMessages(null, array($infile.' cannot be added, probably protected PDF'),'warnings');
    +												}
    +											}
    +										}
    +									}
    +								}
    +							}
    +						}
    +					}
    +				}
    +
    +				$pdf->Close();
    +
    +				$pdf->Output($file,'F');
    +
    +				//Add pdfgeneration hook
    +				$hookmanager->initHooks(array('pdfgeneration'));
    +				$parameters=array('file'=>$file,'object'=>$object,'outputlangs'=>$outputlangs);
    +				global $action;
    +				$reshook=$hookmanager->executeHooks('afterPDFCreation',$parameters,$this,$action);    // Note that $action and $object may have been modified by some hooks
    +
    +				if (! empty($conf->global->MAIN_UMASK))
    +				@chmod($file, octdec($conf->global->MAIN_UMASK));
    +
    +				$this->result = array('fullpath'=>$file);
    +
    +				return 1;   // Pas d'erreur
    +			}
    +			else
    +			{
    +				$this->error=$langs->trans("ErrorCanNotCreateDir",$dir);
    +				return 0;
    +			}
    +		}
    +		else
    +		{
    +			$this->error=$langs->trans("ErrorConstantNotDefined","PROP_OUTPUTDIR");
    +			return 0;
    +		}
    +	}
    +
    +	/**
    +	 *  Show payments table
    +	 *
    +     *  @param	TCPDF		$pdf           Object PDF
    +     *  @param  Object		$object         Object proposal
    +     *  @param  int			$posy           Position y in PDF
    +     *  @param  Translate	$outputlangs    Object langs for output
    +     *  @return int             			<0 if KO, >0 if OK
    +	 */
    +	private function drawPaymentsTable(&$pdf, $object, $posy, $outputlangs)
    +	{
    +	}
    +
    +	/**
    +	 *   Show miscellaneous information (payment mode, payment term, ...)
    +	 *
    +	 *   @param		TCPDF		$pdf     		Object PDF
    +	 *   @param		Object		$object			Object to show
    +	 *   @param		int			$posy			Y
    +	 *   @param		Translate	$outputlangs	Langs object
    +	 *   @return	void
    +	 */
    +	function drawInfoTable(&$pdf, $object, $posy, $outputlangs)
    +	{
    +		global $conf;
    +		$default_font_size = pdf_getPDFFontSize($outputlangs);
    +
    +		$pdf->SetFont('','', $default_font_size - 1);
    +
    +		// If France, show VAT mention if not applicable
    +		if ($this->emetteur->country_code == 'FR' && $this->franchise == 1)
    +		{
    +			$pdf->SetFont('','B', $default_font_size - 2);
    +			$pdf->SetXY($this->marge_gauche, $posy);
    +			$pdf->MultiCell(100, 3, $outputlangs->transnoentities("VATIsNotUsedForInvoice"), 0, 'L', 0);
    +
    +			$posy=$pdf->GetY()+4;
    +		}
    +
    +		$posxval=52;
    +
    +        // Show shipping date
    +        if (! empty($object->date_livraison))
    +		{
    +            $outputlangs->load("sendings");
    +			$pdf->SetFont('','B', $default_font_size - 2);
    +			$pdf->SetXY($this->marge_gauche, $posy);
    +			$titre = $outputlangs->transnoentities("DateDeliveryPlanned").':';
    +			$pdf->MultiCell(80, 4, $titre, 0, 'L');
    +			$pdf->SetFont('','', $default_font_size - 2);
    +			$pdf->SetXY($posxval, $posy);
    +			$dlp=dol_print_date($object->date_livraison,"daytext",false,$outputlangs,true);
    +			$pdf->MultiCell(80, 4, $dlp, 0, 'L');
    +
    +            $posy=$pdf->GetY()+1;
    +		}
    +        elseif ($object->availability_code || $object->availability)    // Show availability conditions
    +		{
    +			$pdf->SetFont('','B', $default_font_size - 2);
    +			$pdf->SetXY($this->marge_gauche, $posy);
    +			$titre = $outputlangs->transnoentities("AvailabilityPeriod").':';
    +			$pdf->MultiCell(80, 4, $titre, 0, 'L');
    +			$pdf->SetTextColor(0,0,0);
    +			$pdf->SetFont('','', $default_font_size - 2);
    +			$pdf->SetXY($posxval, $posy);
    +			$lib_availability=$outputlangs->transnoentities("AvailabilityType".$object->availability_code)!=('AvailabilityType'.$object->availability_code)?$outputlangs->transnoentities("AvailabilityType".$object->availability_code):$outputlangs->convToOutputCharset($object->availability);
    +			$lib_availability=str_replace('\n',"\n",$lib_availability);
    +			$pdf->MultiCell(80, 4, $lib_availability, 0, 'L');
    +
    +			$posy=$pdf->GetY()+1;
    +		}
    +
    +		// Show payments conditions
    +		if (empty($conf->global->PROPALE_PDF_HIDE_PAYMENTTERMCOND) && ($object->cond_reglement_code || $object->cond_reglement))
    +		{
    +			$pdf->SetFont('','B', $default_font_size - 2);
    +			$pdf->SetXY($this->marge_gauche, $posy);
    +			$titre = $outputlangs->transnoentities("PaymentConditions").':';
    +			$pdf->MultiCell(43, 4, $titre, 0, 'L');
    +
    +			$pdf->SetFont('','', $default_font_size - 2);
    +			$pdf->SetXY($posxval, $posy);
    +			$lib_condition_paiement=$outputlangs->transnoentities("PaymentCondition".$object->cond_reglement_code)!=('PaymentCondition'.$object->cond_reglement_code)?$outputlangs->transnoentities("PaymentCondition".$object->cond_reglement_code):$outputlangs->convToOutputCharset($object->cond_reglement_doc);
    +			$lib_condition_paiement=str_replace('\n',"\n",$lib_condition_paiement);
    +			$pdf->MultiCell(67, 4, $lib_condition_paiement,0,'L');
    +
    +			$posy=$pdf->GetY()+3;
    +		}
    +
    +		if (empty($conf->global->PROPALE_PDF_HIDE_PAYMENTTERMMODE))
    +		{
    +			// Check a payment mode is defined
    +			/* Not required on a proposal
    +			if (empty($object->mode_reglement_code)
    +			&& ! $conf->global->FACTURE_CHQ_NUMBER
    +			&& ! $conf->global->FACTURE_RIB_NUMBER)
    +			{
    +				$pdf->SetXY($this->marge_gauche, $posy);
    +				$pdf->SetTextColor(200,0,0);
    +				$pdf->SetFont('','B', $default_font_size - 2);
    +				$pdf->MultiCell(90, 3, $outputlangs->transnoentities("ErrorNoPaiementModeConfigured"),0,'L',0);
    +				$pdf->SetTextColor(0,0,0);
    +
    +				$posy=$pdf->GetY()+1;
    +			}
    +			*/
    +
    +			// Show payment mode
    +			if ($object->mode_reglement_code
    +			&& $object->mode_reglement_code != 'CHQ'
    +			&& $object->mode_reglement_code != 'VIR')
    +			{
    +				$pdf->SetFont('','B', $default_font_size - 2);
    +				$pdf->SetXY($this->marge_gauche, $posy);
    +				$titre = $outputlangs->transnoentities("PaymentMode").':';
    +				$pdf->MultiCell(80, 5, $titre, 0, 'L');
    +				$pdf->SetFont('','', $default_font_size - 2);
    +				$pdf->SetXY($posxval, $posy);
    +				$lib_mode_reg=$outputlangs->transnoentities("PaymentType".$object->mode_reglement_code)!=('PaymentType'.$object->mode_reglement_code)?$outputlangs->transnoentities("PaymentType".$object->mode_reglement_code):$outputlangs->convToOutputCharset($object->mode_reglement);
    +				$pdf->MultiCell(80, 5, $lib_mode_reg,0,'L');
    +
    +				$posy=$pdf->GetY()+2;
    +			}
    +
    +			// Show payment mode CHQ
    +			if (empty($object->mode_reglement_code) || $object->mode_reglement_code == 'CHQ')
    +			{
    +				// Si mode reglement non force ou si force a CHQ
    +				if (! empty($conf->global->FACTURE_CHQ_NUMBER))
    +				{
    +					$diffsizetitle=(empty($conf->global->PDF_DIFFSIZE_TITLE)?3:$conf->global->PDF_DIFFSIZE_TITLE);
    +
    +					if ($conf->global->FACTURE_CHQ_NUMBER > 0)
    +					{
    +						$account = new Account($this->db);
    +						$account->fetch($conf->global->FACTURE_CHQ_NUMBER);
    +
    +						$pdf->SetXY($this->marge_gauche, $posy);
    +						$pdf->SetFont('','B', $default_font_size - $diffsizetitle);
    +						$pdf->MultiCell(100, 3, $outputlangs->transnoentities('PaymentByChequeOrderedTo',$account->proprio),0,'L',0);
    +						$posy=$pdf->GetY()+1;
    +
    +			            if (empty($conf->global->MAIN_PDF_HIDE_CHQ_ADDRESS))
    +			            {
    +							$pdf->SetXY($this->marge_gauche, $posy);
    +							$pdf->SetFont('','', $default_font_size - $diffsizetitle);
    +							$pdf->MultiCell(100, 3, $outputlangs->convToOutputCharset($account->owner_address), 0, 'L', 0);
    +							$posy=$pdf->GetY()+2;
    +			            }
    +					}
    +					if ($conf->global->FACTURE_CHQ_NUMBER == -1)
    +					{
    +						$pdf->SetXY($this->marge_gauche, $posy);
    +						$pdf->SetFont('','B', $default_font_size - $diffsizetitle);
    +						$pdf->MultiCell(100, 3, $outputlangs->transnoentities('PaymentByChequeOrderedTo',$this->emetteur->name),0,'L',0);
    +						$posy=$pdf->GetY()+1;
    +
    +			            if (empty($conf->global->MAIN_PDF_HIDE_CHQ_ADDRESS))
    +			            {
    +							$pdf->SetXY($this->marge_gauche, $posy);
    +							$pdf->SetFont('','', $default_font_size - $diffsizetitle);
    +							$pdf->MultiCell(100, 3, $outputlangs->convToOutputCharset($this->emetteur->getFullAddress()), 0, 'L', 0);
    +							$posy=$pdf->GetY()+2;
    +			            }
    +					}
    +				}
    +			}
    +
    +			// If payment mode not forced or forced to VIR, show payment with BAN
    +			if (empty($object->mode_reglement_code) || $object->mode_reglement_code == 'VIR')
    +			{
    +				if (! empty($object->fk_account) || ! empty($object->fk_bank) || ! empty($conf->global->FACTURE_RIB_NUMBER))
    +				{
    +					$bankid=(empty($object->fk_account)?$conf->global->FACTURE_RIB_NUMBER:$object->fk_account);
    +					if (! empty($object->fk_bank)) $bankid=$object->fk_bank;   // For backward compatibility when object->fk_account is forced with object->fk_bank
    +					$account = new Account($this->db);
    +					$account->fetch($bankid);
    +
    +					$curx=$this->marge_gauche;
    +					$cury=$posy;
    +
    +					$posy=pdf_bank($pdf,$outputlangs,$curx,$cury,$account,0,$default_font_size);
    +
    +					$posy+=2;
    +				}
    +			}
    +		}
    +
    +		return $posy;
    +	}
    +
    +
    +	/**
    +	 *	Show total to pay
    +	 *
    +	 *	@param	PDF			$pdf            Object PDF
    +	 *	@param  Facture		$object         Object invoice
    +	 *	@param  int			$deja_regle     Montant deja regle
    +	 *	@param	int			$posy			Position depart
    +	 *	@param	Translate	$outputlangs	Objet langs
    +	 *	@return int							Position pour suite
    +	 */
    +	private function drawTotalTable(&$pdf, $object, $deja_regle, $posy, $outputlangs)
    +	{
    +		global $conf,$mysoc;
    +		$default_font_size = pdf_getPDFFontSize($outputlangs);
    +
    +		$tab2_top = $posy;
    +		$tab2_hl = 4;
    +		$pdf->SetFont('','', $default_font_size - 1);
    +
    +		// Tableau total
    +		$col1x = 120; $col2x = 170;
    +		if ($this->page_largeur < 210) // To work with US executive format
    +		{
    +			$col2x-=20;
    +		}
    +		$largcol2 = ($this->page_largeur - $this->marge_droite - $col2x);
    +
    +		$useborder=0;
    +		$index = 0;
    +
    +		// Total HT
    +		$pdf->SetFillColor(255,255,255);
    +		$pdf->SetXY($col1x, $tab2_top + 0);
    +		$pdf->MultiCell($col2x-$col1x, $tab2_hl, $outputlangs->transnoentities("TotalHT"), 0, 'L', 1);
    +
    +		$total_ht = ($conf->multicurrency->enabled && $object->mylticurrency_tx != 1 ? $object->multicurrency_total_ht : $object->total_ht);
    +		$pdf->SetXY($col2x, $tab2_top + 0);
    +		$pdf->MultiCell($largcol2, $tab2_hl, price($total_ht + (! empty($object->remise)?$object->remise:0), 0, $outputlangs), 0, 'R', 1);
    +
    +		// Show VAT by rates and total
    +		$pdf->SetFillColor(248,248,248);
    +
    +		$total_ttc = ($conf->multicurrency->enabled && $object->multicurrency_tx != 1) ? $object->multicurrency_total_ttc : $object->total_ttc;
    +
    +		$this->atleastoneratenotnull=0;
    +		if (empty($conf->global->MAIN_GENERATE_DOCUMENTS_WITHOUT_VAT))
    +		{
    +			$tvaisnull=((! empty($this->tva) && count($this->tva) == 1 && isset($this->tva['0.000']) && is_float($this->tva['0.000'])) ? true : false);
    +			if (! empty($conf->global->MAIN_GENERATE_DOCUMENTS_WITHOUT_VAT_IFNULL) && $tvaisnull)
    +			{
    +				// Nothing to do
    +			}
    +			else
    +			{
    +				//Local tax 1 before VAT
    +				//if (! empty($conf->global->FACTURE_LOCAL_TAX1_OPTION) && $conf->global->FACTURE_LOCAL_TAX1_OPTION=='localtax1on')
    +				//{
    +					foreach( $this->localtax1 as $localtax_type => $localtax_rate )
    +					{
    +						if (in_array((string) $localtax_type, array('1','3','5'))) continue;
    +
    +						foreach( $localtax_rate as $tvakey => $tvaval )
    +						{
    +							if ($tvakey!=0)    // On affiche pas taux 0
    +							{
    +								//$this->atleastoneratenotnull++;
    +
    +								$index++;
    +								$pdf->SetXY($col1x, $tab2_top + $tab2_hl * $index);
    +
    +								$tvacompl='';
    +								if (preg_match('/\*/',$tvakey))
    +								{
    +									$tvakey=str_replace('*','',$tvakey);
    +									$tvacompl = " (".$outputlangs->transnoentities("NonPercuRecuperable").")";
    +								}
    +								$totalvat = $outputlangs->transcountrynoentities("TotalLT1",$mysoc->country_code).' ';
    +								$totalvat.=vatrate(abs($tvakey),1).$tvacompl;
    +								$pdf->MultiCell($col2x-$col1x, $tab2_hl, $totalvat, 0, 'L', 1);
    +
    +								$pdf->SetXY($col2x, $tab2_top + $tab2_hl * $index);
    +								$pdf->MultiCell($largcol2, $tab2_hl, price($tvaval, 0, $outputlangs), 0, 'R', 1);
    +							}
    +						}
    +					}
    +	      		//}
    +				//Local tax 2 before VAT
    +				//if (! empty($conf->global->FACTURE_LOCAL_TAX2_OPTION) && $conf->global->FACTURE_LOCAL_TAX2_OPTION=='localtax2on')
    +				//{
    +					foreach( $this->localtax2 as $localtax_type => $localtax_rate )
    +					{
    +						if (in_array((string) $localtax_type, array('1','3','5'))) continue;
    +
    +						foreach( $localtax_rate as $tvakey => $tvaval )
    +						{
    +							if ($tvakey!=0)    // On affiche pas taux 0
    +							{
    +								//$this->atleastoneratenotnull++;
    +
    +
    +
    +								$index++;
    +								$pdf->SetXY($col1x, $tab2_top + $tab2_hl * $index);
    +
    +								$tvacompl='';
    +								if (preg_match('/\*/',$tvakey))
    +								{
    +									$tvakey=str_replace('*','',$tvakey);
    +									$tvacompl = " (".$outputlangs->transnoentities("NonPercuRecuperable").")";
    +								}
    +								$totalvat = $outputlangs->transcountrynoentities("TotalLT2", $mysoc->country_code).' ';
    +								$totalvat.=vatrate(abs($tvakey),1).$tvacompl;
    +								$pdf->MultiCell($col2x-$col1x, $tab2_hl, $totalvat, 0, 'L', 1);
    +
    +								$pdf->SetXY($col2x, $tab2_top + $tab2_hl * $index);
    +								$pdf->MultiCell($largcol2, $tab2_hl, price($tvaval, 0, $outputlangs), 0, 'R', 1);
    +
    +							}
    +						}
    +					}
    +				//}
    +				// VAT
    +				foreach($this->tva as $tvakey => $tvaval)
    +				{
    +					if ($tvakey != 0)    // On affiche pas taux 0
    +					{
    +						$this->atleastoneratenotnull++;
    +
    +						$index++;
    +						$pdf->SetXY($col1x, $tab2_top + $tab2_hl * $index);
    +
    +						$tvacompl='';
    +						if (preg_match('/\*/',$tvakey))
    +						{
    +							$tvakey=str_replace('*','',$tvakey);
    +							$tvacompl = " (".$outputlangs->transnoentities("NonPercuRecuperable").")";
    +						}
    +						$totalvat =$outputlangs->transcountrynoentities("TotalVAT",$mysoc->country_code).' ';
    +						$totalvat.=vatrate($tvakey,1).$tvacompl;
    +						$pdf->MultiCell($col2x-$col1x, $tab2_hl, $totalvat, 0, 'L', 1);
    +
    +						$pdf->SetXY($col2x, $tab2_top + $tab2_hl * $index);
    +						$pdf->MultiCell($largcol2, $tab2_hl, price($tvaval, 0, $outputlangs), 0, 'R', 1);
    +					}
    +				}
    +
    +				//Local tax 1 after VAT
    +				//if (! empty($conf->global->FACTURE_LOCAL_TAX1_OPTION) && $conf->global->FACTURE_LOCAL_TAX1_OPTION=='localtax1on')
    +				//{
    +					foreach( $this->localtax1 as $localtax_type => $localtax_rate )
    +					{
    +						if (in_array((string) $localtax_type, array('2','4','6'))) continue;
    +
    +						foreach( $localtax_rate as $tvakey => $tvaval )
    +						{
    +							if ($tvakey != 0)    // On affiche pas taux 0
    +							{
    +								//$this->atleastoneratenotnull++;
    +
    +								$index++;
    +								$pdf->SetXY($col1x, $tab2_top + $tab2_hl * $index);
    +
    +								$tvacompl='';
    +								if (preg_match('/\*/',$tvakey))
    +								{
    +									$tvakey=str_replace('*','',$tvakey);
    +									$tvacompl = " (".$outputlangs->transnoentities("NonPercuRecuperable").")";
    +								}
    +								$totalvat = $outputlangs->transcountrynoentities("TotalLT1",$mysoc->country_code).' ';
    +
    +								$totalvat.=vatrate(abs($tvakey),1).$tvacompl;
    +								$pdf->MultiCell($col2x-$col1x, $tab2_hl, $totalvat, 0, 'L', 1);
    +								$pdf->SetXY($col2x, $tab2_top + $tab2_hl * $index);
    +								$pdf->MultiCell($largcol2, $tab2_hl, price($tvaval, 0, $outputlangs), 0, 'R', 1);
    +							}
    +						}
    +					}
    +	      		//}
    +				//Local tax 2 after VAT
    +				//if (! empty($conf->global->FACTURE_LOCAL_TAX2_OPTION) && $conf->global->FACTURE_LOCAL_TAX2_OPTION=='localtax2on')
    +				//{
    +					foreach( $this->localtax2 as $localtax_type => $localtax_rate )
    +					{
    +						if (in_array((string) $localtax_type, array('2','4','6'))) continue;
    +
    +						foreach( $localtax_rate as $tvakey => $tvaval )
    +						{
    +						    // retrieve global local tax
    +							if ($tvakey != 0)    // On affiche pas taux 0
    +							{
    +								//$this->atleastoneratenotnull++;
    +
    +								$index++;
    +								$pdf->SetXY($col1x, $tab2_top + $tab2_hl * $index);
    +
    +								$tvacompl='';
    +								if (preg_match('/\*/',$tvakey))
    +								{
    +									$tvakey=str_replace('*','',$tvakey);
    +									$tvacompl = " (".$outputlangs->transnoentities("NonPercuRecuperable").")";
    +								}
    +								$totalvat = $outputlangs->transcountrynoentities("TotalLT2",$mysoc->country_code).' ';
    +
    +								$totalvat.=vatrate(abs($tvakey),1).$tvacompl;
    +								$pdf->MultiCell($col2x-$col1x, $tab2_hl, $totalvat, 0, 'L', 1);
    +
    +								$pdf->SetXY($col2x, $tab2_top + $tab2_hl * $index);
    +								$pdf->MultiCell($largcol2, $tab2_hl, price($tvaval, 0, $outputlangs), 0, 'R', 1);
    +							}
    +						}
    +					}
    +				//}
    +
    +				// Total TTC
    +				$index++;
    +				$pdf->SetXY($col1x, $tab2_top + $tab2_hl * $index);
    +				$pdf->SetTextColor(0,0,60);
    +				$pdf->SetFillColor(224,224,224);
    +				$pdf->MultiCell($col2x-$col1x, $tab2_hl, $outputlangs->transnoentities("TotalTTC"), $useborder, 'L', 1);
    +
    +				$pdf->SetXY($col2x, $tab2_top + $tab2_hl * $index);
    +				$pdf->MultiCell($largcol2, $tab2_hl, price($total_ttc, 0, $outputlangs), $useborder, 'R', 1);
    +			}
    +		}
    +
    +		$pdf->SetTextColor(0,0,0);
    +
    +		/*
    +		$resteapayer = $object->total_ttc - $deja_regle;
    +		if (! empty($object->paye)) $resteapayer=0;
    +		*/
    +
    +		if ($deja_regle > 0)
    +		{
    +			$index++;
    +
    +			$pdf->SetXY($col1x, $tab2_top + $tab2_hl * $index);
    +			$pdf->MultiCell($col2x-$col1x, $tab2_hl, $outputlangs->transnoentities("AlreadyPaid"), 0, 'L', 0);
    +
    +			$pdf->SetXY($col2x, $tab2_top + $tab2_hl * $index);
    +			$pdf->MultiCell($largcol2, $tab2_hl, price($deja_regle, 0, $outputlangs), 0, 'R', 0);
    +
    +			/*
    +			if ($object->close_code == 'discount_vat')
    +			{
    +				$index++;
    +				$pdf->SetFillColor(255,255,255);
    +
    +				$pdf->SetXY($col1x, $tab2_top + $tab2_hl * $index);
    +				$pdf->MultiCell($col2x-$col1x, $tab2_hl, $outputlangs->transnoentities("EscompteOfferedShort"), $useborder, 'L', 1);
    +
    +				$pdf->SetXY($col2x, $tab2_top + $tab2_hl * $index);
    +				$pdf->MultiCell($largcol2, $tab2_hl, price($object->total_ttc - $deja_regle, 0, $outputlangs), $useborder, 'R', 1);
    +
    +				$resteapayer=0;
    +			}
    +			*/
    +
    +			$index++;
    +			$pdf->SetTextColor(0,0,60);
    +			$pdf->SetFillColor(224,224,224);
    +			$pdf->SetXY($col1x, $tab2_top + $tab2_hl * $index);
    +			$pdf->MultiCell($col2x-$col1x, $tab2_hl, $outputlangs->transnoentities("RemainderToPay"), $useborder, 'L', 1);
    +
    +			$pdf->SetXY($col2x, $tab2_top + $tab2_hl * $index);
    +			$pdf->MultiCell($largcol2, $tab2_hl, price($resteapayer, 0, $outputlangs), $useborder, 'R', 1);
    +
    +			$pdf->SetFont('','', $default_font_size - 1);
    +			$pdf->SetTextColor(0,0,0);
    +		}
    +
    +		$index++;
    +		return ($tab2_top + ($tab2_hl * $index));
    +	}
    +
    +	/**
    +	 *   Show table for lines
    +	 *
    +	 *   @param		PDF			$pdf     		Object PDF
    +	 *   @param		string		$tab_top		Top position of table
    +	 *   @param		string		$tab_height		Height of table (rectangle)
    +	 *   @param		int			$nexY			Y (not used)
    +	 *   @param		Translate	$outputlangs	Langs object
    +	 *   @param		int			$hidetop		1=Hide top bar of array and title, 0=Hide nothing, -1=Hide only title
    +	 *   @param		int			$hidebottom		Hide bottom bar of array
    +	 *   @param		string		$currency		Currency code
    +	 *   @return	void
    +	 */
    +	function _tableau(&$pdf, $tab_top, $tab_height, $nexY, $outputlangs, $hidetop=0, $hidebottom=0, $currency='')
    +	{
    +		global $conf;
    +
    +		// Force to disable hidetop and hidebottom
    +		$hidebottom=0;
    +		if ($hidetop) $hidetop=-1;
    +
    +		$currency = !empty($currency) ? $currency : $conf->currency;
    +		$default_font_size = pdf_getPDFFontSize($outputlangs);
    +
    +		// Amount in (at tab_top - 1)
    +		$pdf->SetTextColor(0,0,0);
    +		$pdf->SetFont('','', $default_font_size - 2);
    +
    +		if (empty($hidetop))
    +		{
    +			$titre = $outputlangs->transnoentities("AmountInCurrency",$outputlangs->transnoentitiesnoconv("Currency".$currency));
    +			$pdf->SetXY($this->page_largeur - $this->marge_droite - ($pdf->GetStringWidth($titre) + 3), $tab_top-4);
    +			$pdf->MultiCell(($pdf->GetStringWidth($titre) + 3), 2, $titre);
    +
    +			//$conf->global->MAIN_PDF_TITLE_BACKGROUND_COLOR='230,230,230';
    +			if (! empty($conf->global->MAIN_PDF_TITLE_BACKGROUND_COLOR)) $pdf->Rect($this->marge_gauche, $tab_top, $this->page_largeur-$this->marge_droite-$this->marge_gauche, 5, 'F', null, explode(',',$conf->global->MAIN_PDF_TITLE_BACKGROUND_COLOR));
    +		}
    +
    +		$pdf->SetDrawColor(128,128,128);
    +		$pdf->SetFont('','', $default_font_size - 1);
    +
    +		// Output Rect
    +		$this->printRect($pdf,$this->marge_gauche, $tab_top, $this->page_largeur-$this->marge_gauche-$this->marge_droite, $tab_height, $hidetop, $hidebottom);	// Rect prend une longueur en 3eme param et 4eme param
    +
    +
    +		foreach ($this->cols as $colKey => $colDef)
    +		{
    +		    if(!$this->getColumnStatus($colKey)) continue;
    +
    +		    // get title label
    +		    $colDef['title']['label'] = !empty($colDef['title']['label'])?$colDef['title']['label']:$outputlangs->transnoentities($colDef['title']['textkey']);
    +
    +		    // Add column separator
    +		    if(!empty($colDef['border-left'])){
    +		        $pdf->line($colDef['xStartPos'], $tab_top, $colDef['xStartPos'], $tab_top + $tab_height);
    +		    }
    +
    +		    if (empty($hidetop))
    +		    {
    +		      $pdf->SetXY($colDef['xStartPos'] + $colDef['title']['padding'][3], $tab_top + $colDef['title']['padding'][0] );
    +
    +		      $textWidth = $colDef['width'] - $colDef['title']['padding'][3] -$colDef['title']['padding'][1];
    +		      $pdf->MultiCell($textWidth,2,$colDef['title']['label'],'',$colDef['title']['align']);
    +		    }
    +		}
    +
    +		if (empty($hidetop)){
    +			$pdf->line($this->marge_gauche, $tab_top+5, $this->page_largeur-$this->marge_droite, $tab_top+5);	// line prend une position y en 2eme param et 4eme param
    +		}
    +	}
    +
    +	/**
    +	 *  Show top header of page.
    +	 *
    +	 *  @param	PDF			$pdf     		Object PDF
    +	 *  @param  Object		$object     	Object to show
    +	 *  @param  int	    	$showaddress    0=no, 1=yes
    +	 *  @param  Translate	$outputlangs	Object lang for output
    +	 *  @return	void
    +	 */
    +	function _pagehead(&$pdf, $object, $showaddress, $outputlangs)
    +	{
    +		global $conf,$langs;
    +
    +		$outputlangs->load("main");
    +		$outputlangs->load("bills");
    +		$outputlangs->load("propal");
    +		$outputlangs->load("companies");
    +
    +		$default_font_size = pdf_getPDFFontSize($outputlangs);
    +
    +		pdf_pagehead($pdf,$outputlangs,$this->page_hauteur);
    +
    +		//  Show Draft Watermark
    +		if($object->statut==0 && (! empty($conf->global->PROPALE_DRAFT_WATERMARK)) )
    +		{
    +            pdf_watermark($pdf,$outputlangs,$this->page_hauteur,$this->page_largeur,'mm',$conf->global->PROPALE_DRAFT_WATERMARK);
    +		}
    +
    +		$pdf->SetTextColor(0,0,60);
    +		$pdf->SetFont('','B', $default_font_size + 3);
    +
    +		$posy=$this->marge_haute;
    +		$posx=$this->page_largeur-$this->marge_droite-100;
    +
    +		$pdf->SetXY($this->marge_gauche,$posy);
    +
    +		// Logo
    +		if (empty($conf->global->PDF_DISABLE_MYCOMPANY_LOGO))
    +		{
    +			$logo=$conf->mycompany->dir_output.'/logos/'.$this->emetteur->logo;
    +			if ($this->emetteur->logo)
    +			{
    +				if (is_readable($logo))
    +				{
    +				    $height=pdf_getHeightForLogo($logo);
    +				    $pdf->Image($logo, $this->marge_gauche, $posy, 0, $height);	// width=0 (auto)
    +				}
    +				else
    +				{
    +					$pdf->SetTextColor(200,0,0);
    +					$pdf->SetFont('','B',$default_font_size - 2);
    +					$pdf->MultiCell(100, 3, $outputlangs->transnoentities("ErrorLogoFileNotFound",$logo), 0, 'L');
    +					$pdf->MultiCell(100, 3, $outputlangs->transnoentities("ErrorGoToGlobalSetup"), 0, 'L');
    +				}
    +			}
    +			else
    +			{
    +				$text=$this->emetteur->name;
    +				$pdf->MultiCell(100, 4, $outputlangs->convToOutputCharset($text), 0, 'L');
    +			}
    +		}
    +
    +		$pdf->SetFont('','B',$default_font_size + 3);
    +		$pdf->SetXY($posx,$posy);
    +		$pdf->SetTextColor(0,0,60);
    +		$title=$outputlangs->transnoentities("PdfCommercialProposalTitle");
    +		$pdf->MultiCell(100, 4, $title, '', 'R');
    +
    +		$pdf->SetFont('','B',$default_font_size);
    +
    +		$posy+=5;
    +		$pdf->SetXY($posx,$posy);
    +		$pdf->SetTextColor(0,0,60);
    +		$pdf->MultiCell(100, 4, $outputlangs->transnoentities("Ref")." : " . $outputlangs->convToOutputCharset($object->ref), '', 'R');
    +
    +		$posy+=1;
    +		$pdf->SetFont('','', $default_font_size - 2);
    +
    +		if ($object->ref_client)
    +		{
    +			$posy+=4;
    +			$pdf->SetXY($posx,$posy);
    +			$pdf->SetTextColor(0,0,60);
    +			$pdf->MultiCell(100, 3, $outputlangs->transnoentities("RefCustomer")." : " . $outputlangs->convToOutputCharset($object->ref_client), '', 'R');
    +		}
    +
    +		$posy+=4;
    +		$pdf->SetXY($posx,$posy);
    +		$pdf->SetTextColor(0,0,60);
    +		$pdf->MultiCell(100, 3, $outputlangs->transnoentities("Date")." : " . dol_print_date($object->date,"day",false,$outputlangs,true), '', 'R');
    +
    +		$posy+=4;
    +		$pdf->SetXY($posx,$posy);
    +		$pdf->SetTextColor(0,0,60);
    +		$pdf->MultiCell(100, 3, $outputlangs->transnoentities("DateEndPropal")." : " . dol_print_date($object->fin_validite,"day",false,$outputlangs,true), '', 'R');
    +
    +		if ($object->thirdparty->code_client)
    +		{
    +			$posy+=4;
    +			$pdf->SetXY($posx,$posy);
    +			$pdf->SetTextColor(0,0,60);
    +			$pdf->MultiCell(100, 3, $outputlangs->transnoentities("CustomerCode")." : " . $outputlangs->transnoentities($object->thirdparty->code_client), '', 'R');
    +		}
    +
    +		// Get contact
    +		if (!empty($conf->global->DOC_SHOW_FIRST_SALES_REP))
    +		{
    +		    $arrayidcontact=$object->getIdContact('internal','SALESREPFOLL');
    +		    if (count($arrayidcontact) > 0)
    +		    {
    +		        $usertmp=new User($this->db);
    +		        $usertmp->fetch($arrayidcontact[0]);
    +                $posy+=4;
    +                $pdf->SetXY($posx,$posy);
    +		        $pdf->SetTextColor(0,0,60);
    +		        $pdf->MultiCell(100, 3, $langs->trans("SalesRepresentative")." : ".$usertmp->getFullName($langs), '', 'R');
    +		    }
    +		}
    +
    +		$posy+=2;
    +
    +		$top_shift = 0;
    +		// Show list of linked objects
    +		$current_y = $pdf->getY();
    +		$posy = pdf_writeLinkedObjects($pdf, $object, $outputlangs, $posx, $posy, 100, 3, 'R', $default_font_size);
    +		if ($current_y < $pdf->getY())
    +		{
    +			$top_shift = $pdf->getY() - $current_y;
    +		}
    +
    +		if ($showaddress)
    +		{
    +			// Sender properties
    +			$carac_emetteur='';
    +		 	// Add internal contact of proposal if defined
    +			$arrayidcontact=$object->getIdContact('internal','SALESREPFOLL');
    +		 	if (count($arrayidcontact) > 0)
    +		 	{
    +		 		$object->fetch_user($arrayidcontact[0]);
    +		 		$labelbeforecontactname=($outputlangs->transnoentities("FromContactName")!='FromContactName'?$outputlangs->transnoentities("FromContactName"):$outputlangs->transnoentities("Name"));
    +		 		$carac_emetteur .= ($carac_emetteur ? "\n" : '' ).$labelbeforecontactname." ".$outputlangs->convToOutputCharset($object->user->getFullName($outputlangs))."\n";
    +		 	}
    +
    +		 	$carac_emetteur .= pdf_build_address($outputlangs, $this->emetteur, $object->thirdparty, '', 0, 'source', $object);
    +
    +			// Show sender
    +			$posy=42+$top_shift;
    +		 	$posx=$this->marge_gauche;
    +			if (! empty($conf->global->MAIN_INVERT_SENDER_RECIPIENT)) $posx=$this->page_largeur-$this->marge_droite-80;
    +			$hautcadre=40;
    +
    +			// Show sender frame
    +			$pdf->SetTextColor(0,0,0);
    +			$pdf->SetFont('','', $default_font_size - 2);
    +			$pdf->SetXY($posx,$posy-5);
    +			$pdf->MultiCell(66,5, $outputlangs->transnoentities("BillFrom").":", 0, 'L');
    +			$pdf->SetXY($posx,$posy);
    +			$pdf->SetFillColor(230,230,230);
    +			$pdf->MultiCell(82, $hautcadre, "", 0, 'R', 1);
    +			$pdf->SetTextColor(0,0,60);
    +
    +			// Show sender name
    +			$pdf->SetXY($posx+2,$posy+3);
    +			$pdf->SetFont('','B', $default_font_size);
    +			$pdf->MultiCell(80, 4, $outputlangs->convToOutputCharset($this->emetteur->name), 0, 'L');
    +			$posy=$pdf->getY();
    +
    +			// Show sender information
    +			$pdf->SetXY($posx+2,$posy);
    +			$pdf->SetFont('','', $default_font_size - 1);
    +			$pdf->MultiCell(80, 4, $carac_emetteur, 0, 'L');
    +
    +
    +			// If CUSTOMER contact defined, we use it
    +			$usecontact=false;
    +			$arrayidcontact=$object->getIdContact('external','CUSTOMER');
    +			if (count($arrayidcontact) > 0)
    +			{
    +				$usecontact=true;
    +				$result=$object->fetch_contact($arrayidcontact[0]);
    +			}
    +
    +			//Recipient name
    +			// On peut utiliser le nom de la societe du contact
    +			if ($usecontact && !empty($conf->global->MAIN_USE_COMPANY_NAME_OF_CONTACT)) {
    +				$thirdparty = $object->contact;
    +			} else {
    +				$thirdparty = $object->thirdparty;
    +			}
    +
    +			$carac_client_name= pdfBuildThirdpartyName($thirdparty, $outputlangs);
    +
    +			$carac_client=pdf_build_address($outputlangs,$this->emetteur,$object->thirdparty,($usecontact?$object->contact:''),$usecontact,'target',$object);
    +
    +			// Show recipient
    +			$widthrecbox=100;
    +			if ($this->page_largeur < 210) $widthrecbox=84;	// To work with US executive format
    +			$posy=42+$top_shift;
    +			$posx=$this->page_largeur-$this->marge_droite-$widthrecbox;
    +			if (! empty($conf->global->MAIN_INVERT_SENDER_RECIPIENT)) $posx=$this->marge_gauche;
    +
    +			// Show recipient frame
    +			$pdf->SetTextColor(0,0,0);
    +			$pdf->SetFont('','', $default_font_size - 2);
    +			$pdf->SetXY($posx+2,$posy-5);
    +			$pdf->MultiCell($widthrecbox, 5, $outputlangs->transnoentities("BillTo").":", 0, 'L');
    +			$pdf->Rect($posx, $posy, $widthrecbox, $hautcadre);
    +
    +			// Show recipient name
    +			$pdf->SetXY($posx+2,$posy+3);
    +			$pdf->SetFont('','B', $default_font_size);
    +			$pdf->MultiCell($widthrecbox, 4, $carac_client_name, 0, 'L');
    +
    +			$posy = $pdf->getY();
    +
    +			// Show recipient information
    +			$pdf->SetFont('','', $default_font_size - 1);
    +			$pdf->SetXY($posx+2,$posy);
    +			$pdf->MultiCell($widthrecbox, 4, $carac_client, 0, 'L');
    +		}
    +
    +		$pdf->SetTextColor(0,0,0);
    +		return $top_shift;
    +	}
    +
    +	/**
    +	 *   	Show footer of page. Need this->emetteur object
    +     *
    +	 *   	@param	PDF			$pdf     			PDF
    +	 * 		@param	Object		$object				Object to show
    +	 *      @param	Translate	$outputlangs		Object lang for output
    +	 *      @param	int			$hidefreetext		1=Hide free text
    +	 *      @return	int								Return height of bottom margin including footer text
    +	 */
    +	function _pagefoot(&$pdf,$object,$outputlangs,$hidefreetext=0)
    +	{
    +		global $conf;
    +		$showdetails=$conf->global->MAIN_GENERATE_DOCUMENTS_SHOW_FOOT_DETAILS;
    +		return pdf_pagefoot($pdf,$outputlangs,'PROPOSAL_FREE_TEXT',$this->emetteur,$this->marge_basse,$this->marge_gauche,$this->page_hauteur,$object,$showdetails,$hidefreetext);
    +	}
    +
    +	/**
    +	 *	Show area for the customer to sign
    +	 *
    +	 *	@param	PDF			$pdf            Object PDF
    +	 *	@param  Facture		$object         Object invoice
    +	 *	@param	int			$posy			Position depart
    +	 *	@param	Translate	$outputlangs	Objet langs
    +	 *	@return int							Position pour suite
    +	 */
    +	private function drawSignatureArea(&$pdf, $object, $posy, $outputlangs)
    +	{
    +		global $conf;
    +		$default_font_size = pdf_getPDFFontSize($outputlangs);
    +		$tab_top = $posy + 4;
    +		$tab_hl = 4;
    +
    +		$posx = 120;
    +		$largcol = ($this->page_largeur - $this->marge_droite - $posx);
    +		$useborder=0;
    +		$index = 0;
    +		// Total HT
    +		$pdf->SetFillColor(255,255,255);
    +		$pdf->SetXY($posx, $tab_top + 0);
    +		$pdf->SetFont('','', $default_font_size - 2);
    +		$pdf->MultiCell($largcol, $tab_hl, $outputlangs->transnoentities("ProposalCustomerSignature"), 0, 'L', 1);
    +
    +		$pdf->SetXY($posx, $tab_top + $tab_hl);
    +		$pdf->MultiCell($largcol, $tab_hl*3, '', 1, 'R');
    +		if (! empty($conf->global->MAIN_PDF_PROPAL_USE_ELECTRONIC_SIGNING)) {
    +			$pdf->addEmptySignatureAppearance($posx, $tab_top + $tab_hl, $largcol, $tab_hl*3);
    +		}
    +
    +		return ($tab_hl*7);
    +	}
    +
    +
    +	/**
    +	 *   	Define Array Column Field
    +	 *
    +	 *   	@param	object			$object    		common object
    +	 *   	@param	outputlangs		$outputlangs    langs
    +	 *      @param	int			   $hidedetails		Do not show line details
    +	 *      @param	int			   $hidedesc		Do not show desc
    +	 *      @param	int			   $hideref			Do not show ref
    +	 *      @return	null
    +	 */
    +    function defineColumnField($object,$outputlangs,$hidedetails=0,$hidedesc=0,$hideref=0)
    +    {
    +	    global $conf, $hookmanager;
    +
    +	    // Default field style for content
    +	    $this->defaultContentsFieldsStyle = array(
    +	        'align' => 'R', // R,C,L
    +	        'padding' => array(0.5,0.5,0.5,0.5), // Like css 0 => top , 1 => right, 2 => bottom, 3 => left
    +	    );
    +
    +	    // Default field style for content
    +	    $this->defaultTitlesFieldsStyle = array(
    +	        'align' => 'C', // R,C,L
    +	        'padding' => array(0.5,0,0.5,0), // Like css 0 => top , 1 => right, 2 => bottom, 3 => left
    +	    );
    +
    +	    /*
    +	     * For exemple
    +	     $this->cols['theColKey'] = array(
    +	     'rank' => $rank, // int : use for ordering columns
    +	     'width' => 20, // the column width in mm
    +	     'title' => array(
    +	     'textkey' => 'yourLangKey', // if there is no label, yourLangKey will be translated to replace label
    +	     'label' => ' ', // the final label : used fore final generated text
    +	     'align' => 'L', // text alignement :  R,C,L
    +	     'padding' => array(0.5,0.5,0.5,0.5), // Like css 0 => top , 1 => right, 2 => bottom, 3 => left
    +	     ),
    +	     'content' => array(
    +	     'align' => 'L', // text alignement :  R,C,L
    +	     'padding' => array(0.5,0.5,0.5,0.5), // Like css 0 => top , 1 => right, 2 => bottom, 3 => left
    +	     ),
    +	     );
    +	     */
    +
    +	    $rank=0; // do not use negative rank
    +	    $this->cols['desc'] = array(
    +	        'rank' => $rank,
    +	        'width' => false, // only for desc
    +	        'status' => true,
    +	        'title' => array(
    +	            'textkey' => 'Designation', // use lang key is usefull in somme case with module
    +	            'align' => 'L',
    +	            // 'textkey' => 'yourLangKey', // if there is no label, yourLangKey will be translated to replace label
    +	            // 'label' => ' ', // the final label
    +	            'padding' => array(0.5,0.5,0.5,0.5), // Like css 0 => top , 1 => right, 2 => bottom, 3 => left
    +	        ),
    +	        'content' => array(
    +	            'align' => 'L',
    +	        ),
    +	    );
    +
    +	    $rank = $rank + 10;
    +	    $this->cols['photo'] = array(
    +	        'rank' => $rank,
    +	        'width' => (empty($conf->global->MAIN_DOCUMENTS_WITH_PICTURE_WIDTH)?20:$conf->global->MAIN_DOCUMENTS_WITH_PICTURE_WIDTH), // in mm
    +	        'status' => false,
    +	        'title' => array(
    +	            'textkey' => 'Photo',
    +	            'label' => ' '
    +	        ),
    +	        'content' => array(
    +	            'padding' => array(0,0,0,0), // Like css 0 => top , 1 => right, 2 => bottom, 3 => left
    +	        ),
    +	        'border-left' => false, // remove left line separator
    +	    );
    +
    +	    if (! empty($conf->global->MAIN_GENERATE_PROPOSALS_WITH_PICTURE) && !empty($this->atleastonephoto))
    +	    {
    +	        $this->cols['photo']['status'] = true;
    +	    }
    +
    +
    +	    $rank = $rank + 10;
    +	    $this->cols['vat'] = array(
    +	        'rank' => $rank,
    +	        'status' => false,
    +	        'width' => 16, // in mm
    +	        'title' => array(
    +	            'textkey' => 'VAT'
    +	        ),
    +	        'border-left' => true, // add left line separator
    +	    );
    +
    +	    if (empty($conf->global->MAIN_GENERATE_DOCUMENTS_WITHOUT_VAT) && empty($conf->global->MAIN_GENERATE_DOCUMENTS_WITHOUT_VAT_COLUMN))
    +	    {
    +	        $this->cols['vat']['status'] = true;
    +	    }
    +
    +	    $rank = $rank + 10;
    +	    $this->cols['subprice'] = array(
    +	        'rank' => $rank,
    +	        'width' => 19, // in mm
    +	        'status' => true,
    +	        'title' => array(
    +	            'textkey' => 'PriceUHT'
    +	        ),
    +	        'border-left' => true, // add left line separator
    +	    );
    +
    +	    $rank = $rank + 10;
    +	    $this->cols['qty'] = array(
    +	        'rank' => $rank,
    +	        'width' => 16, // in mm
    +	        'status' => true,
    +	        'title' => array(
    +	            'textkey' => 'Qty'
    +	        ),
    +	        'border-left' => true, // add left line separator
    +	    );
    +
    +	    $rank = $rank + 10;
    +	    $this->cols['progress'] = array(
    +	        'rank' => $rank,
    +	        'width' => 19, // in mm
    +	        'status' => false,
    +	        'title' => array(
    +	            'textkey' => 'Progress'
    +	        ),
    +	        'border-left' => false, // add left line separator
    +	    );
    +
    +	    if($this->situationinvoice)
    +	    {
    +	        $this->cols['progress']['status'] = true;
    +	    }
    +
    +	    $rank = $rank + 10;
    +	    $this->cols['unit'] = array(
    +	        'rank' => $rank,
    +	        'width' => 11, // in mm
    +	        'status' => false,
    +	        'title' => array(
    +	            'textkey' => 'Unit'
    +	        ),
    +	        'border-left' => true, // add left line separator
    +	    );
    +	    if($conf->global->PRODUCT_USE_UNITS){
    +	        $this->cols['unit']['status'] = true;
    +	    }
    +
    +	    $rank = $rank + 10;
    +	    $this->cols['discount'] = array(
    +	        'rank' => $rank,
    +	        'width' => 13, // in mm
    +	        'status' => false,
    +	        'title' => array(
    +	            'textkey' => 'ReductionShort'
    +	        ),
    +	        'border-left' => true, // add left line separator
    +	    );
    +	    if ($this->atleastonediscount){
    +	        $this->cols['discount']['status'] = true;
    +	    }
    +
    +	    $rank = $rank + 10;
    +	    $this->cols['totalexcltax'] = array(
    +	        'rank' => $rank,
    +	        'width' => 26, // in mm
    +	        'status' => true,
    +	        'title' => array(
    +	            'textkey' => 'TotalHT'
    +	        ),
    +	        'border-left' => true, // add left line separator
    +	    );
    +
    +
    +	    $parameters=array(
    +	        'object' => $object,
    +	        'outputlangs' => $outputlangs,
    +	        'hidedetails' => $hidedetails,
    +	        'hidedesc' => $hidedesc,
    +	        'hideref' => $hideref
    +	    );
    +
    +	    $reshook=$hookmanager->executeHooks('defineColumnField',$parameters,$this);    // Note that $object may have been modified by hook
    +	    if ($reshook < 0)
    +	    {
    +	        setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
    +	    }
    +	    elseif (empty($reshook))
    +	    {
    +	        $this->cols = array_replace($this->cols, $hookmanager->resArray); // array_replace is used to preserve keys
    +	    }
    +	    else
    +	    {
    +	        $this->cols = $hookmanager->resArray;
    +	    }
    +	}
    +}
    diff --git a/htdocs/core/modules/supplier_invoice/mod_facture_fournisseur_tulip.php b/htdocs/core/modules/supplier_invoice/mod_facture_fournisseur_tulip.php
    index 6079006d315..8e6dddeebd5 100644
    --- a/htdocs/core/modules/supplier_invoice/mod_facture_fournisseur_tulip.php
    +++ b/htdocs/core/modules/supplier_invoice/mod_facture_fournisseur_tulip.php
    @@ -91,14 +91,18 @@ class mod_facture_fournisseur_tulip extends ModeleNumRefSuppliersInvoices
     		$tooltip.=$langs->trans("GenericMaskCodes5");
     
     		// Parametrage du prefix
    -		$texte.= '<tr><td>'.$langs->trans("Mask");
    -		//$texte.= ' ('.$langs->trans("InvoiceStandard").')';
    +		$texte.= '<tr><td>'.$langs->trans("Mask").' ('.$langs->trans("InvoiceStandard").')';
     		$texte.= ':</td>';
     		$texte.= '<td align="right">'.$form->textwithpicto('<input type="text" class="flat" size="24" name="maskinvoice" value="'.$conf->global->SUPPLIER_INVOICE_TULIP_MASK.'">',$tooltip,1,1).'</td>';
     
     		$texte.= '<td align="left" rowspan="2">&nbsp; <input type="submit" class="button" value="'.$langs->trans("Modify").'" name="Button"></td>';
     
     		$texte.= '</tr>';
    +		
    +		// Parametrage du prefix des avoirs
    +		$texte.= '<tr><td>'.$langs->trans("Mask").' ('.$langs->trans("InvoiceAvoir").'):</td>';
    +		$texte.= '<td align="right">'.$form->textwithpicto('<input type="text" class="flat" size="24" name="maskcredit" value="'.$conf->global->SUPPLIER_CREDIT_TULIP_MASK.'">',$tooltip,1,1).'</td>';
    +		$texte.= '</tr>';
     
     		if ($conf->global->MAIN_FEATURE_LEVEL >= 2)
     		{
    @@ -107,10 +111,6 @@ class mod_facture_fournisseur_tulip extends ModeleNumRefSuppliersInvoices
         		$texte.= '<td align="right">'.$form->textwithpicto('<input type="text" class="flat" size="24" name="maskreplacement" value="'.$conf->global->SUPPLIER_REPLACEMENT_TULIP_MASK.'">',$tooltip,1,1).'</td>';
         		$texte.= '</tr>';
     
    -    		// Parametrage du prefix des avoirs
    -    		$texte.= '<tr><td>'.$langs->trans("Mask").' ('.$langs->trans("InvoiceAvoir").'):</td>';
    -    		$texte.= '<td align="right">'.$form->textwithpicto('<input type="text" class="flat" size="24" name="maskcredit" value="'.$conf->global->SUPPLIER_CREDIT_TULIP_MASK.'">',$tooltip,1,1).'</td>';
    -    		$texte.= '</tr>';
     
         		// Parametrage du prefix des acomptes
         		$texte.= '<tr><td>'.$langs->trans("Mask").' ('.$langs->trans("InvoiceDeposit").'):</td>';
    diff --git a/htdocs/core/tpl/contacts.tpl.php b/htdocs/core/tpl/contacts.tpl.php
    index 99ae9a699a1..cc361be5e60 100644
    --- a/htdocs/core/tpl/contacts.tpl.php
    +++ b/htdocs/core/tpl/contacts.tpl.php
    @@ -199,12 +199,12 @@ if ($permission) {
     			if ($tab[$i]['source']=='internal')
     			{
     				$userstatic->fetch($tab[$i]['id']);
    -				echo $userstatic->getNomUrl(-1);
    +				echo $userstatic->getNomUrl(-1, '', 0, 0, 0, 0, '', 'valignmiddle');
     			}
     			if ($tab[$i]['source']=='external')
     			{
     				$contactstatic->fetch($tab[$i]['id']);
    -				echo $contactstatic->getNomUrl(1);
    +				echo $contactstatic->getNomUrl(1, '', 0, 0, 0, 0, '', 'valignmiddle');
     			}
     			?>
     		</div>
    diff --git a/htdocs/core/tpl/document_actions_post_headers.tpl.php b/htdocs/core/tpl/document_actions_post_headers.tpl.php
    index aa7caaa1e87..429fe8ac682 100644
    --- a/htdocs/core/tpl/document_actions_post_headers.tpl.php
    +++ b/htdocs/core/tpl/document_actions_post_headers.tpl.php
    @@ -52,7 +52,7 @@ if (in_array($modulepart, array('product', 'produit', 'societe', 'user', 'ticket
     if ($action == 'delete')
     {
     	$langs->load("companies");	// Need for string DeleteFile+ConfirmDeleteFiles
    -	$ret = $form->form_confirm(
    +	print $form->formconfirm(
     			$_SERVER["PHP_SELF"] . '?id=' . $object->id . '&urlfile=' . urlencode(GETPOST("urlfile")) . '&linkid=' . GETPOST('linkid', 'int') . (empty($param)?'':$param),
     			$langs->trans('DeleteFile'),
     			$langs->trans('ConfirmDeleteFile'),
    @@ -61,7 +61,6 @@ if ($action == 'delete')
     			0,
     			1
     	);
    -	if ($ret == 'html') print '<br>';
     }
     
     $formfile=new FormFile($db);
    diff --git a/htdocs/core/tpl/extrafields_list_print_fields.tpl.php b/htdocs/core/tpl/extrafields_list_print_fields.tpl.php
    index b506bda0793..6b6d22cf822 100644
    --- a/htdocs/core/tpl/extrafields_list_print_fields.tpl.php
    +++ b/htdocs/core/tpl/extrafields_list_print_fields.tpl.php
    @@ -23,7 +23,7 @@ if (! empty($extrafieldsobjectkey))	// $extrafieldsobject is the $object->table_
     				if ($align) print ' align="'.$align.'"';
     				print '>';
     				$tmpkey='options_'.$key;
    -				if (in_array($extrafields->attributes[$extrafieldsobjectkey]['type'][$key], array('date', 'datetime', 'timestamp')))
    +				if (in_array($extrafields->attributes[$extrafieldsobjectkey]['type'][$key], array('date', 'datetime', 'timestamp')) && !is_numeric($obj->$tmpkey))
     				{
     					$datenotinstring = $obj->$tmpkey;
     					if (! is_numeric($obj->$tmpkey))	// For backward compatibility
    diff --git a/htdocs/core/tpl/filemanager.tpl.php b/htdocs/core/tpl/filemanager.tpl.php
    index 8ca6b6f215a..5ee19aa25a8 100644
    --- a/htdocs/core/tpl/filemanager.tpl.php
    +++ b/htdocs/core/tpl/filemanager.tpl.php
    @@ -28,7 +28,7 @@ if (empty($conf) || ! is_object($conf))
     ?>
     
     <!-- BEGIN PHP TEMPLATE core/tpl/filemanager.tpl.php -->
    -<!-- Doc of fileTree plugin at http://www.abeautifulsite.net/blog/2008/03/jquery-file-tree/ -->
    +<!-- Doc of fileTree plugin at https://www.abeautifulsite.net/jquery-file-tree -->
     
     <?php
     
    @@ -111,7 +111,7 @@ if ((! empty($conf->use_javascript_ajax) && empty($conf->global->MAIN_ECM_DISABL
     		<?php
     	}
     
    -	$sectiondir=GETPOST('file','alpha');
    +	$sectiondir=GETPOST('file','alpha')?GETPOST('file','alpha'):GETPOST('section_dir','alpha');
     	print '<!-- Start form to attach new file in filemanager.tpl.php sectionid='.$section.' sectiondir='.$sectiondir.' -->'."\n";
     	include_once DOL_DOCUMENT_ROOT.'/core/class/html.formfile.class.php';
         $formfile=new FormFile($db);
    @@ -168,14 +168,14 @@ if (empty($action) || $action == 'editfile' || $action == 'file_manager' || preg
     
         	print '<tr><td>';
     
    -    	// Show filemanager tree (will be filled by call of ajax /ecm/tpl/enablefiletreeajax.tpl.php that execute ajaxdirtree.php)
    +    	// Show filemanager tree (will be filled by a call of ajax /ecm/tpl/enablefiletreeajax.tpl.php, later, that executes ajaxdirtree.php)
     	    print '<div id="filetree" class="ecmfiletree"></div>';
     
     	    if ($action == 'deletefile') print $form->formconfirm('eeeee', $langs->trans('DeleteFile'), $langs->trans('ConfirmDeleteFile'), 'confirm_deletefile', '', '', 'deletefile');
     
     	    print '</td></tr>';
         }
    -    else
    +    else	// Show filtree when ajax is disabled (rare)
         {
             print '<tr><td style="padding-left: 20px">';
     
    @@ -186,6 +186,9 @@ if (empty($action) || $action == 'editfile' || $action == 'file_manager' || preg
             // Show filemanager tree (will be filled by direct include of ajaxdirtree.php in mode noajax, this will return all dir - all levels - to show)
             print '<div id="filetree" class="ecmfiletree">';
     
    +        // Variables that may be defined:
    +        // $_GET['modulepart'], $_GET['openeddir'], $_GET['sortfield'], $_GET['sortorder']
    +        // $_POST['dir']
             $mode='noajax';
             if (empty($url)) $url=DOL_URL_ROOT.'/ecm/index.php';
             include DOL_DOCUMENT_ROOT.'/core/ajax/ajaxdirtree.php';
    @@ -211,7 +214,7 @@ if (empty($action) || $action == 'editfile' || $action == 'file_manager' || preg
     
     $mode='noajax';
     if (empty($url)) $url=DOL_URL_ROOT.'/ecm/index.php';
    -include DOL_DOCUMENT_ROOT.'/core/ajax/ajaxdirpreview.php';
    +include DOL_DOCUMENT_ROOT.'/core/ajax/ajaxdirpreview.php';	// Show content of a directory on right side
     
     
     // End right panel
    @@ -224,7 +227,15 @@ include DOL_DOCUMENT_ROOT.'/core/ajax/ajaxdirpreview.php';
     <?php
     
     
    -if (! empty($conf->use_javascript_ajax) && empty($conf->global->MAIN_ECM_DISABLE_JS)) {
    +if (! empty($conf->use_javascript_ajax) && empty($conf->global->MAIN_ECM_DISABLE_JS)) // Show filtree when ajax is enabled
    +{
    +	//var_dump($modulepart);
    +	// Variables that may be defined:
    +	// $_GET['modulepart'], $_GET['openeddir'], $_GET['sortfield'], $_GET['sortorder']
    +	// $_POST['dir']
    +	// $_POST['section_dir'], $_POST['section_id'], $_POST['token'], $_POST['max_file_size'], $_POST['sendit']
    +	if (GETPOST('section_dir','alpha')) { $preopened=GETPOST('section_dir','alpha'); }
    +
     	include DOL_DOCUMENT_ROOT.'/ecm/tpl/enablefiletreeajax.tpl.php';
     }
     
    diff --git a/htdocs/core/tpl/onlinepaymentlinks.tpl.php b/htdocs/core/tpl/onlinepaymentlinks.tpl.php
    index a5c5ce7cf11..37639a5f8e6 100644
    --- a/htdocs/core/tpl/onlinepaymentlinks.tpl.php
    +++ b/htdocs/core/tpl/onlinepaymentlinks.tpl.php
    @@ -1,4 +1,4 @@
    -<<?php
    +<?php
     /* Copyright (C) 2017 Laurent Destailleur <eldy@destailleur.fr>
      *
      * This program is free software; you can redistribute it and/or modify
    diff --git a/htdocs/core/tpl/passwordforgotten.tpl.php b/htdocs/core/tpl/passwordforgotten.tpl.php
    index 0e1942c1c64..101c9ec7e67 100644
    --- a/htdocs/core/tpl/passwordforgotten.tpl.php
    +++ b/htdocs/core/tpl/passwordforgotten.tpl.php
    @@ -184,7 +184,7 @@ if (! empty($morelogincontent)) {
     </form>
     
     
    -<div class="center login_main_home paddingtopbottom<?php echo empty($conf->global->MAIN_LOGIN_BACKGROUND)?'':' backgroundsemitransparent'; ?>" style="max-width: 70%">
    +<div class="center login_main_home divpasswordmessagedesc paddingtopbottom<?php echo empty($conf->global->MAIN_LOGIN_BACKGROUND)?'':' backgroundsemitransparent'; ?>" style="max-width: 70%">
     <?php if ($mode == 'dolibarr' || ! $disabled) { ?>
     	<span class="passwordmessagedesc">
     	<?php echo $langs->trans('SendNewPasswordDesc'); ?>
    diff --git a/htdocs/core/tpl/resource_add.tpl.php b/htdocs/core/tpl/resource_add.tpl.php
    index 688d3aba221..f9daffe33ed 100644
    --- a/htdocs/core/tpl/resource_add.tpl.php
    +++ b/htdocs/core/tpl/resource_add.tpl.php
    @@ -28,7 +28,7 @@ $out .= '<input type="hidden" name="resource_type" value="'.(empty($resource_typ
     $out .= '<div class="tagtd">'.$langs->trans("SelectResource").'</div>';
     $out .= '<div class="tagtd">';
     $events=array();
    -$out .= $formresources->select_resource_list('','fk_resource','',1,1,0,$events,'',2);
    +$out .= $formresources->select_resource_list('','fk_resource','',1,1,0,$events,'',2,null);
     $out .= '</div>';
     
     $out .= '<div class="tagtd"><label>'.$langs->trans('Busy').'</label> '.$form->selectyesno('busy',(isset($_POST['busy'])?$_POST['busy']:1),1).'</div>';
    diff --git a/htdocs/core/triggers/interface_50_modNotification_Notification.class.php b/htdocs/core/triggers/interface_50_modNotification_Notification.class.php
    index 26b36964676..f5995c47c84 100644
    --- a/htdocs/core/triggers/interface_50_modNotification_Notification.class.php
    +++ b/htdocs/core/triggers/interface_50_modNotification_Notification.class.php
    @@ -44,6 +44,7 @@ class InterfaceNotification extends DolibarrTriggers
     	 */
     	public $picto = 'email';
     
    +	// @TODO Defined also into notify.class.php)
     	public $listofmanagedevents=array(
     		'BILL_VALIDATE',
     		'BILL_PAYED',
    @@ -55,8 +56,12 @@ class InterfaceNotification extends DolibarrTriggers
     		'ORDER_SUPPLIER_VALIDATE',
     		'ORDER_SUPPLIER_APPROVE',
     		'ORDER_SUPPLIER_REFUSE',
    -		'SHIPPING_VALIDATE'
    -   	);
    +		'SHIPPING_VALIDATE',
    +		'EXPENSE_REPORT_VALIDATE',
    +		'EXPENSE_REPORT_APPROVE',
    +		'HOLIDAY_VALIDATE',
    +		'HOLIDAY_APPROVE'
    +	);
     
     	/**
     	 * Function called when a Dolibarrr business event is done.
    @@ -112,7 +117,7 @@ class InterfaceNotification extends DolibarrTriggers
     
     				$qualified=0;
     				// Check is this event is supported by notification module
    -				if (in_array($obj->code,$this->listofmanagedevents)) $qualified=1;
    +				if (in_array($obj->code, $this->listofmanagedevents)) $qualified=1;
     				// Check if module for this event is active
     				if ($qualified)
     				{
    @@ -125,7 +130,7 @@ class InterfaceNotification extends DolibarrTriggers
     					elseif ($element == 'withdraw' && empty($conf->prelevement->enabled)) $qualified=0;
     					elseif ($element == 'shipping' && empty($conf->expedition->enabled)) $qualified=0;
     					elseif ($element == 'member' && empty($conf->adherent->enabled)) $qualified=0;
    -					elseif (! in_array($element,array('order_supplier','invoice_supplier','withdraw','shipping','member')) && empty($conf->$element->enabled)) $qualified=0;
    +					elseif (! in_array($element,array('order_supplier','invoice_supplier','withdraw','shipping','member','expensereport')) && empty($conf->$element->enabled)) $qualified=0;
     				}
     
     				if ($qualified)
    diff --git a/htdocs/core/triggers/interface_80_modStripe_Stripe.class.php b/htdocs/core/triggers/interface_80_modStripe_Stripe.class.php
    index 3c86dc805ff..cb03315496a 100644
    --- a/htdocs/core/triggers/interface_80_modStripe_Stripe.class.php
    +++ b/htdocs/core/triggers/interface_80_modStripe_Stripe.class.php
    @@ -17,7 +17,7 @@
      */
     
     /**
    - *  \file       htdocs/core/triggers/interface_50_modStripe_Stripe.class.php
    + *  \file       htdocs/core/triggers/interface_80_modStripe_Stripe.class.php
      *  \ingroup    core
      *  \brief      Fichier
      *  \remarks    Son propre fichier d'actions peut etre cree par recopie de celui-ci:
    @@ -147,19 +147,33 @@ class InterfaceStripe
     				if ($customer)
     				{
     					$namecleaned = $object->name ? $object->name : null;
    -					$vatcleaned = $object->tva_intra ? $object->tva_intra : null;	// We force data to "null" if empty as expected by Stripe
    +					$vatcleaned = $object->tva_intra ? $object->tva_intra : null;
    +
    +					$taxinfo = array('type'=>'vat');
    +					if ($vatcleaned)
    +					{
    +						$taxinfo["tax_id"] = $vatcleaned;
    +					}
    +					// We force data to "null" if not defined as expected by Stripe
    +					if (empty($vatcleaned)) $taxinfo=null;
     
     					// Detect if we change a Stripe info (email, description, vat id)
     					$changerequested = 0;
     					if (! empty($object->email) && $object->email != $customer->email) $changerequested++;
     					if ($namecleaned != $customer->description) $changerequested++;
    -					if ($vatcleaned != $customer->business_vat_id) $changerequested++;
    +					if (! isset($customer->tax_info['tax_id']) && ! is_null($vatcleaned)) $changerequested++;
    +					elseif (isset($customer->tax_info['tax_id']) && is_null($vatcleaned)) $changerequested++;
    +					elseif (isset($customer->tax_info['tax_id']) && ! is_null($vatcleaned))
    +					{
    +						if ($vatcleaned != $customer->tax_info['tax_id']) $changerequested++;
    +					}
     
     					if ($changerequested)
     					{
     						if (! empty($object->email)) $customer->email = $object->email;
     						$customer->description = $namecleaned;
    -						$customer->business_vat_id = $vatcleaned;
    +						if (empty($taxinfo)) $customer->tax_info = array('type'=>'vat', 'tax_id'=>null);
    +						else $customer->tax_info = $taxinfo;
     
     						$customer->save();
     					}
    diff --git a/htdocs/core/website.inc.php b/htdocs/core/website.inc.php
    index ac4d6b35988..1338104de0b 100644
    --- a/htdocs/core/website.inc.php
    +++ b/htdocs/core/website.inc.php
    @@ -19,21 +19,75 @@
     /**
      *	\file			htdocs/core/website.inc.php
      *  \brief			Common file loaded by all website pages (after master.inc.php). It set the new object $weblangs, using parameter 'l'.
    + *  				This file is included in top of all container pages.
      *  			    The global variable $websitekey must be defined.
      */
     
     // Load website class
     include_once DOL_DOCUMENT_ROOT.'/website/class/website.class.php';
    -// Define $website and $weblangs
    +// Define $website
     if (! is_object($website))
     {
     	$website=new Website($db);
     	$website->fetch(0,$websitekey);
     }
    +// Define $weblangs
     if (! is_object($weblangs))
     {
    -	$weblangs = dol_clone($langs);
    +	$weblangs = dol_clone($langs);	// TODO Use an object lang from a language set into $website object instead of backoffice
     }
    +// Define $websitepage if we have $websitepagefile defined
    +if (! $pageid && ! empty($websitepagefile))
    +{
    +	$pageid = str_replace(array('.tpl.php', 'page'), array('', ''), basename($websitepagefile));
    +}
    +if ($pageid > 0)
    +{
    +	include_once DOL_DOCUMENT_ROOT.'/website/class/websitepage.class.php';
    +	$websitepage=new WebsitePage($db);
    +	$websitepage->fetch($pageid);
    +}
    +
    +// A lang was forced, so we change weblangs init
     if (GETPOST('l','aZ09')) $weblangs->setDefaultLang(GETPOST('l','aZ09'));
    +// A lang was forced, so we check to find if we must make a redirect on translation page
    +if ($_SERVER['PHP_SELF'] != DOL_URL_ROOT.'/website/index.php')	// If we browsing page using Dolibarr server or a Native web server
    +{
    +	//print_r(get_defined_constants(true));exit;
    +	if (GETPOST('l','aZ09'))
    +	{
    +		$sql ="SELECT wp.rowid, wp.lang, wp.pageurl, wp.fk_page";
    +		$sql.=" FROM ".MAIN_DB_PREFIX."website_page as wp";
    +		$sql.=" WHERE wp.fk_website = ".$website->id;
    +		$sql.=" AND (wp.fk_page = ".$pageid." OR wp.rowid  = ".$pageid;
    +		if (is_object($websitepage) && $websitepage->fk_page > 0) $sql.=" OR wp.fk_page = ".$websitepage->fk_page." OR wp.rowid = ".$websitepage->fk_page;
    +		$sql.=")";
    +		$sql.= " AND wp.lang = '".$db->escape(GETPOST('l','aZ09'))."'";
    +
    +		$resql = $db->query($sql);
    +		if ($resql)
    +		{
    +			$obj = $db->fetch_object($resql);
    +			if ($obj)
    +			{
    +				$newpageid = $obj->rowid;
    +				if ($newpageid != $pageid) 		// To avoid to make a redirect on same page (infinite loop)
    +				{
    +					if (defined('USEDOLIBARRSERVER')) {
    +						header("Location: ".DOL_URL_ROOT.'/public/website/index.php?website='.$websitekey.'&pageid='.$newpageid.'&l='.GETPOST('l','aZ09'));
    +						exit;
    +					}
    +					else
    +					{
    +						$newpageref = $obj->pageurl;
    +						header("Location: ".$newpageref.'.php?l='.GETPOST('l','aZ09'));
    +						exit;
    +					}
    +				}
    +			}
    +		}
    +	}
    +}
    +
     // Load websitepage class
     include_once DOL_DOCUMENT_ROOT.'/website/class/websitepage.class.php';
    diff --git a/htdocs/cron/class/cronjob.class.php b/htdocs/cron/class/cronjob.class.php
    index a0db4a1f572..a71088f3286 100644
    --- a/htdocs/cron/class/cronjob.class.php
    +++ b/htdocs/cron/class/cronjob.class.php
    @@ -76,10 +76,24 @@ class Cronjob extends CommonObject
     	public $lastoutput;
     	public $unitfrequency;
     	public $frequency;
    +
    +	/**
    +	 * @var int Status
    +	 */
     	public $status;
    +
     	public $processing;
    +
    +	/**
    +     * @var int ID
    +     */
     	public $fk_user_author;
    +
    +	/**
    +     * @var int ID
    +     */
     	public $fk_user_mod;
    +
     	public $nbrun;
     	public $libname;
     	public $test;					// A test condition to know if job is visible/qualified
    @@ -1379,9 +1393,22 @@ class Cronjobline
     	public $lastoutput;
     	public $unitfrequency;
     	public $frequency;
    +
    +	/**
    +	 * @var int Status
    +	 */
     	public $status;
    +
    +	/**
    +     * @var int ID
    +     */
     	public $fk_user_author;
    +
    +	/**
    +     * @var int ID
    +     */
     	public $fk_user_mod;
    +
     	public $note;
     	public $nbrun;
     	public $libname;
    diff --git a/htdocs/datapolicies/langs/en_US/datapolicies.lang b/htdocs/datapolicies/langs/en_US/datapolicies.lang
    deleted file mode 100644
    index 164581bcca5..00000000000
    --- a/htdocs/datapolicies/langs/en_US/datapolicies.lang
    +++ /dev/null
    @@ -1,93 +0,0 @@
    -# Copyright (C) 2018 Nicolas ZABOURI    <info@inovea-conseil.com>
    -#
    -# This program is free software: you can redistribute it and/or modify
    -# it under the terms of the GNU General Public License as published by
    -# the Free Software Foundation, either version 3 of the License, or
    -# (at your option) any later version.
    -#
    -# This program is distributed in the hope that it will be useful,
    -# but WITHOUT ANY WARRANTY; without even the implied warranty of
    -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    -# GNU General Public License for more details.
    -#
    -# You should have received a copy of the GNU General Public License
    -# along with this program.  If not, see <http://www.gnu.org/licenses/>.
    -
    -# Module label 'ModulergpdName'
    -ModulergpdName = GDPR
    -# Module description 'ModulergpdDesc'
    -ModulergpdDesc = Conformity with the GDPR
    -
    -#
    -# Page d'administration
    -#
    -rgpdSetup = Module Setup
    -Settings_DATAPOLICIES = Settings of DATAPOLICIES module
    -rgpdSetupPage = According to <a href="http://www.privacy-regulation.eu/en/5.htm" target="_blank">Article 5</a> of the GDPR, personal data must be kept for a period not exceeding that necessary for the purposes for which they were processed, except for archival purposes.
    -The deletion will be done automatically after a certain duration without event (the duration which you will have indicated below).
    -NB_MONTHS = %s months
    -ONE_YEAR = 1 year
    -NB_YEARS = %s years
    -DATAPOLICIES_TIERS_CLIENT = Customer
    -DATAPOLICIES_TIERS_PROSPECT = Prospect
    -DATAPOLICIES_TIERS_PROSPECT_CLIENT = Prospect/Customer
    -DATAPOLICIES_TIERS_NIPROSPECT_NICLIENT = Nor prospect/Nor customer
    -DATAPOLICIES_TIERS_FOURNISSEUR = Supplier
    -DATAPOLICIES_CONTACT_CLIENT = Customer
    -DATAPOLICIES_CONTACT_PROSPECT = Prospect
    -DATAPOLICIES_CONTACT_PROSPECT_CLIENT = Prospect/Customer
    -DATAPOLICIES_CONTACT_NIPROSPECT_NICLIENT = Nor prospect/Nor customer
    -DATAPOLICIES_CONTACT_FOURNISSEUR = Supplier
    -DATAPOLICIES_ADHERENT = Member
    -DATAPOLICIES_Tooltip_SETUP = Type of contact - Indicate your choices for each type.
    -DATAPOLICIESMail=Emails Setup
    -DATAPOLICIESSUBJECTMAIL=Subject of email
    -DATAPOLICIESCONTENTMAIL=Content of the email
    -DATAPOLICIESSUBSITUTION=You can use the following variables in your email (LINKACCEPT allows to create a link recording the agreement of the person, LINKREFUSED makes it possible to record the refusal of the person):
    -DATAPOLICIESACCEPT=Message after agreement
    -DATAPOLICIESREFUSE=Message after desagreement
    -SendAgreementText=You can send a GDPR email to all your relevant contacts (who have not yet received an email and for which you have not registered anything about their GDPR agreement). To do this, use the following button.
    -SendAgreement=Send emails
    -AllAgreementSend = All emails have been sent
    -TXTLINKDATAPOLICIESACCEPT= Text for the link "agreement" 
    -TXTLINKDATAPOLICIESREFUSE= Text for the link "desagreement" 
    -
    -
    -#
    -# Extrafield
    -#
    -DATAPOLICIES_BLOCKCHECKBOX = GDPR : Processing of personal data
    -DATAPOLICIES_consentement = Consent obtained for the processing of personal data 
    -DATAPOLICIES_opposition_traitement = Opposes the processing of his personal data
    -DATAPOLICIES_opposition_prospection = Opposes the processing of his personal data for the purposes of prospecting
    -
    -#
    -# Popup
    -#
    -DATAPOLICIES_POPUP_ANONYME_TITLE = Anonymize a thirdparty
    -DATAPOLICIES_POPUP_ANONYME_TEXTE = You can not delete this contact from Dolibarr because there are related items. In accordance with the GDPR, you will make all this data anonymous to respect your obligations. Would you like to continue ?
    -
    -#
    -# Bouton portabilité
    -# 
    -DATAPOLICIES_PORTABILITE = Portability GDPR
    -DATAPOLICIES_PORTABILITE_TITLE = Export of personal data
    -DATAPOLICIES_PORTABILITE_CONFIRMATION = You want to export the personal data of this contact. Are you sure ?
    -
    -#
    -# Note ajoutés lors d'une anonymisation
    -#
    -ANONYMISER_AT = Anonymised the %s
    -
    -#V2
    -DATAPOLICIESReturn=GDPR Validation
    -DATAPOLICIES_date = Date of agreement/desagreement GDPR
    -DATAPOLICIES_send = Date sending agreement email
    -DATAPOLICIESReturn = GDPR Return
    -DATAPOLICIES_SEND = Send GDPR email
    -MailSent = Email has been sent
    -
    -#ERROR
    -ErrorSubjectIsRequired= Error : The subject of email is required. Indicate it in the module setup
    -=Due to a technical problem, we were unable to register your choice. We apologize for that. Contact us to send us your choice.
    -NUMBER_MONTH_BEFORE_DELETION = Number of month before deletion
    diff --git a/htdocs/datapolicies/langs/fr_FR/datapolicies.lang b/htdocs/datapolicies/langs/fr_FR/datapolicies.lang
    deleted file mode 100644
    index 916cdffb776..00000000000
    --- a/htdocs/datapolicies/langs/fr_FR/datapolicies.lang
    +++ /dev/null
    @@ -1,97 +0,0 @@
    -# Copyright (C) 2018  INOVEA CONSEil info@inovea-conseil.com
    -#
    -# This program is free software: you can redistribute it and/or modify
    -# it under the terms of the GNU General Public License as published by
    -# the Free Software Foundation, either version 3 of the License, or
    -# (at your option) any later version.
    -#
    -# This program is distributed in the hope that it will be useful,
    -# but WITHOUT ANY WARRANTY; without even the implied warranty of
    -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    -# GNU General Public License for more details.
    -#
    -# You should have received a copy of the GNU General Public License
    -# along with this program.  If not, see <http://www.gnu.org/licenses/>.
    -
    -#
    -# Générique
    -#
    -
    -# Module label 'ModulergpdName'
    -ModulergpdName = DATAPOLICIES
    -# Module description 'ModulergpdDesc'
    -Module432452Desc = Module de mise en conformité avec le DATAPOLICIES
    -
    -#
    -# Page d'administration
    -#
    -rgpdSetup = Configuration du module DATAPOLICIES
    -Settings_DATAPOLICIES = Paramétrage du module DATAPOLICIES
    -rgpdSetupPage = Selon <a href="http://www.privacy-regulation.eu/fr/5.htm" target="_blank">l’article 5</a> du DATAPOLICIES, les données à caractère personnel doivent être conservées pendant une durée n’excédant pas celle nécessaire au regard des finalités pour lesquelles elles ont été traitées, à l’exception de fins archivistiques. La suppression se fera automatiquement après une certaine durée sans évènement (la durée que vous aurez indiquée ci-dessous).
    -NB_MONTHS = %s mois
    -ONE_YEAR = 1 an
    -NB_YEARS = %s ans
    -DATAPOLICIES_TIERS_CLIENT = Client
    -DATAPOLICIES_TIERS_PROSPECT = Prospect
    -DATAPOLICIES_TIERS_PROSPECT_CLIENT = Prospect/Client
    -DATAPOLICIES_TIERS_NIPROSPECT_NICLIENT = Ni prospect / Ni client
    -DATAPOLICIES_TIERS_FOURNISSEUR = Fournisseur
    -DATAPOLICIES_CONTACT_CLIENT = Client
    -DATAPOLICIES_CONTACT_PROSPECT = Prospect
    -DATAPOLICIES_CONTACT_PROSPECT_CLIENT = Prospect/Client
    -DATAPOLICIES_CONTACT_NIPROSPECT_NICLIENT = Ni prospect / Ni client
    -DATAPOLICIES_CONTACT_FOURNISSEUR = Fournisseur
    -DATAPOLICIES_ADHERENT = Adhérent
    -DATAPOLICIES_Tooltip_SETUP = Type du contact - Indiquez vos choix pour chaque type.
    -DATAPOLICIESMail=Paramétrage des emails
    -DATAPOLICIESSUBJECTMAIL=Objet du mail
    -DATAPOLICIESCONTENTMAIL=Contenu du mail
    -DATAPOLICIESSUBSITUTION=Vous pouvez utiliser les variables suivantes dans votre email (LINKACCEPT permet de créer un lien enregistrant l'acceptation de la personne, LINKREFUSED permet d'enregistrer le refus de la personne) :
    -DATAPOLICIESACCEPT=Message suite acceptation
    -DATAPOLICIESREFUSE=Message suite opposition
    -SendAgreementText=Vous pouvez envoyer un email DATAPOLICIES à tous vos contacts concernés (qui n'ont pas encore reçus de mail et pour lesquels vous n'avez rien enregistré concernant leur accord/désaccord DATAPOLICIES). Pour cela, utilisez le bouton suivant.
    -SendAgreement=Envoyer les emails
    -AllAgreementSend = Tous les e-mails de consentement ont été envoyés
    -TXTLINKDATAPOLICIESACCEPT= Texte du lien d'acceptation
    -TXTLINKDATAPOLICIESREFUSE= Texte du lien d'opposition
    -
    -
    -
    -#
    -# Extrafield
    -#
    -DATAPOLICIES_BLOCKCHECKBOX = DATAPOLICIES : Traitement des données à caractère personnel
    -DATAPOLICIES_consentement = Consentement recueilli pour le traitement des données à caractère personnel le concernant
    -DATAPOLICIES_opposition_traitement = S’oppose au traitement de ses données à caractère personnel
    -DATAPOLICIES_opposition_prospection = S’oppose au traitement de ses données à caractère personnel à des fins de prospection
    -
    -#
    -# Popup
    -#
    -DATAPOLICIES_POPUP_ANONYME_TITLE = Anonymiser un tiers
    -DATAPOLICIES_POPUP_ANONYME_TEXTE = Vous ne pouvez pas supprimer ce contact de Dolibarr car des éléments y sont liés. Conformément au DATAPOLICIES, vous allez rendre toutes ces données anonymes afin de respecter vos obligations. Souhaitez-vous continuer ?
    -
    -#
    -# Bouton portabilité
    -# 
    -DATAPOLICIES_PORTABILITE = Portabilité DATAPOLICIES
    -DATAPOLICIES_PORTABILITE_TITLE = Export des données à caractère personnel
    -DATAPOLICIES_PORTABILITE_CONFIRMATION = Vous souhaitez exporter les données à caractère personnel de ce contact. Etes-vous sûr ?
    -
    -#
    -# Note ajoutés lors d'une anonymisation
    -#
    -ANONYMISER_AT = Anonymisé le %s
    -
    -#V2
    -DATAPOLICIESReturn=Validation DATAPOLICIES
    -DATAPOLICIES_date=Date d'accord/opposition au traitement
    -DATAPOLICIES_send=Date envoi consentement
    -DATAPOLICIESReturn=Retour DATAPOLICIES
    -DATAPOLICIES_SEND=Envoyer l'email de consentement
    -MailSent=L'email a bien été envoyé
    -
    -#ERROR
    -ErrorSubjectIsRequired=Erreur : vous n'avez pas indiqué l'objet de l'email dans la configuration
    -=Suite à un problème technique, nous n'avons pas pu enregistrer votre choix. Nous nous en excusons. Contactez-nous pour nous transmettre votre choix.
    -NUMBER_MONTH_BEFORE_DELETION = Nombre de mois avant suppression des données
    diff --git a/htdocs/datapolicies/langs/it_IT/datapolicies.lang b/htdocs/datapolicies/langs/it_IT/datapolicies.lang
    deleted file mode 100644
    index a979c931c41..00000000000
    --- a/htdocs/datapolicies/langs/it_IT/datapolicies.lang
    +++ /dev/null
    @@ -1,80 +0,0 @@
    -# Copyright (C) 2018 INOVEA CONSEIl info@inovea-conseil.com - Thanks to Claudio Aschieri
    -#
    -# # Module label 'ModulergpdName'
    -ModulergpdName = GDPR
    -# Module description 'ModulergpdDesc'
    -ModulergpdDesc = Conformità con GDPR
    -Module432452Name=GDPR
    -Module432452Desc=Conformità con GDPR (Regolamento Generale sulla protezione di dati)
    -
    -#
    -# Page d'administration
    -#
    -rgpdSetup = Module Setup
    -Settings_DATAPOLICIES = Configurazione modulo GDPR 
    -rgpdSetupPage = In accordo con <a href="http://www.privacy-regulation.eu/it/5.htm" target="_blank">l'art 5 del GDPR </a> i dati personali devono essere conservati per un periodo di tempo che .... ed eliminati se non sono più utili agli scopi per cui sono stati processati.
    -NB_MONTHS = %s mesi
    -ONE_YEAR = 1 anno
    -NB_YEARS = %s anni
    -DATAPOLICIES_TIERS_CLIENT = Cliente
    -DATAPOLICIES_TIERS_PROSPECT = Fornitore
    -DATAPOLICIES_TIERS_PROSPECT_CLIENT = Potenziale Cliente / Cliente
    -DATAPOLICIES_TIERS_NIPROSPECT_NICLIENT = Nè potenziale cliente / Nè cliente
    -DATAPOLICIES_TIERS_FOURNISSEUR = Fornitore
    -DATAPOLICIES_CONTACT_CLIENT = Cliente
    -DATAPOLICIES_CONTACT_PROSPECT = Potenziale cliente
    -DATAPOLICIES_CONTACT_PROSPECT_CLIENT = Potenziale Cliente / Cliente
    -DATAPOLICIES_CONTACT_NIPROSPECT_NICLIENT = Nè potenziale cliente / Nè cliente
    -DATAPOLICIES_CONTACT_FOURNISSEUR = Fornitore
    -DATAPOLICIES_ADHERENT = Membri
    -DATAPOLICIES_Tooltip_SETUP = Tipo di contatto - Indica la scelta per ogni tipologia
    -DATAPOLICIESMail=Configurazione Email
    -DATAPOLICIESSUBJECTMAIL=Subject dell'e-mail
    -DATAPOLICIESCONTENTMAIL=Contenuto dell'e-mail
    -DATAPOLICIESSUBSITUTION=Puoi utilizzare le seguenti variabili nella tua email (LINKACCEPT consente di creare un link per registrare l'accettazione della persona, LINKREFUSED consente di registrare il rifiuto della persona):
    -DATAPOLICIESACCEPT= Messaggio dopo il consenso
    -DATAPOLICIESREFUSE=Messaggio dopo il rifiuto
    -SendAgreementText=Puoi inviare un'email GDPR a tutti i tuoi contatti rilevanti (che non hanno ancora ricevuto un'e-mail e per i quali non hai registrato nulla sul loro accordo GDPR). Per fare ciò, utilizzare il seguente pulsante.
    -SendAgreement=Invia emails
    -AllAgreementSend = Tutte le email sono state inviate
    -TXTLINKDATAPOLICIESACCEPT= Testo per il link "Consenso" 
    -TXTLINKDATAPOLICIESREFUSE= Testo per il link "Consenso negato" 
    -
    -#
    -# Extrafield
    -#
    -DATAPOLICIES_BLOCKCHECKBOX = GDPR : Trattamento dei dati personali
    -DATAPOLICIES_consentement = Consenso ottenuto al Trattamento dei dati personali
    -DATAPOLICIES_opposition_traitement = Consenso negato al trattamento dei dati personali
    -DATAPOLICIES_opposition_prospection = Consenso negato al trattamento dei dati personali a fini commerciali
    -
    -#
    -# Popup
    -#
    -DATAPOLICIES_POPUP_ANONYME_TITLE = Anonimizza un soggetto terzo
    -DATAPOLICIES_POPUP_ANONYME_TEXTE = Impossibile eliminare questo contatto da Dolibarr perchè vi sono elementi collegati. In conformità con il GDPR, renderai tutti questi dati anonimi per rispettare i tuoi obblighi. Vuoi continuare?
    -
    -
    -#
    -# Bouton portabilité
    -# 
    -DATAPOLICIES_PORTABILITE = Portabilità GDPR
    -DATAPOLICIES_PORTABILITE_TITLE = Esporta i dati personali
    -DATAPOLICIES_PORTABILITE_CONFIRMATION = Vuoi davvero esportare i dati personali di questo contatto?
    -
    -#
    -# Note ajoutée lors d'une anonymisation
    -#
    -ANONYMISER_AT = Anonimizzato il %s
    -
    -#V2
    -DATAPOLICIESReturn=GDPR Validazione
    -DATAPOLICIES_date = Data di accordo / disaccordo GDPR
    -DATAPOLICIES_send = Data di invio del consenso (e-mail)
    -DATAPOLICIESReturn = GDPR ritorno
    -DATAPOLICIES_SEND = Inviare GDPR e-mail
    -MailSent=L'email è stata inviata
    -
    -#ERROR
    -ErrorSubjectIsRequired= Errore: L'oggetto della mail è obbligatorio. Inserisci l'oggetto nella configurazione del modulo.
    -=A causa di un problema tecnico, non siamo stati in grado di registrare la tua scelta. Ci scusiamo per questo. Contattaci per inviarci la tua scelta.
    diff --git a/htdocs/datapolicies/ChangeLog.md b/htdocs/datapolicy/ChangeLog.md
    similarity index 100%
    rename from htdocs/datapolicies/ChangeLog.md
    rename to htdocs/datapolicy/ChangeLog.md
    diff --git a/htdocs/datapolicies/admin/setup.php b/htdocs/datapolicy/admin/setup.php
    similarity index 71%
    rename from htdocs/datapolicies/admin/setup.php
    rename to htdocs/datapolicy/admin/setup.php
    index f6edd5b3e90..777fa6cb893 100644
    --- a/htdocs/datapolicies/admin/setup.php
    +++ b/htdocs/datapolicy/admin/setup.php
    @@ -17,21 +17,21 @@
      */
     
     /**
    - * \file    datapolicies/admin/setup.php
    - * \ingroup datapolicies
    - * \brief   datapolicies setup page.
    + * \file    datapolicy/admin/setup.php
    + * \ingroup datapolicy
    + * \brief   datapolicy setup page.
      */
     
     require '../../main.inc.php';
     require_once DOL_DOCUMENT_ROOT . "/core/lib/admin.lib.php";
    -require_once '../lib/datapolicies.lib.php';
    +require_once '../lib/datapolicy.lib.php';
     //require_once "../class/myclass.class.php";
     
     // Translations
     $langs->load('admin');
     $langs->load('companies');
     $langs->load('members');
    -$langs->load('datapolicies@datapolicies');
    +$langs->load('datapolicy@datapolicy');
     
     // Access control
     if (! $user->admin) accessforbidden();
    @@ -41,17 +41,17 @@ $action = GETPOST('action', 'alpha');
     $backtopage = GETPOST('backtopage', 'alpha');
     
     $arrayofparameters=array(
    -    'DATAPOLICIES_TIERS_CLIENT'=>array('css'=>'minwidth200'),
    -    'DATAPOLICIES_TIERS_PROSPECT'=>array('css'=>'minwidth200'),
    -    'DATAPOLICIES_TIERS_PROSPECT_CLIENT'=>array('css'=>'minwidth200'),
    -    'DATAPOLICIES_TIERS_NIPROSPECT_NICLIENT'=>array('css'=>'minwidth200'),
    -    'DATAPOLICIES_TIERS_FOURNISSEUR'=>array('css'=>'minwidth200'),
    -    'DATAPOLICIES_CONTACT_CLIENT'=>array('css'=>'minwidth200'),
    -    'DATAPOLICIES_CONTACT_PROSPECT'=>array('css'=>'minwidth200'),
    -    'DATAPOLICIES_CONTACT_PROSPECT_CLIENT'=>array('css'=>'minwidth200'),
    -    'DATAPOLICIES_CONTACT_NIPROSPECT_NICLIENT'=>array('css'=>'minwidth200'),
    -    'DATAPOLICIES_CONTACT_FOURNISSEUR'=>array('css'=>'minwidth200'),
    -    'DATAPOLICIES_ADHERENT'=>array('css'=>'minwidth200'),
    +    'DATAPOLICY_TIERS_CLIENT'=>array('css'=>'minwidth200'),
    +    'DATAPOLICY_TIERS_PROSPECT'=>array('css'=>'minwidth200'),
    +    'DATAPOLICY_TIERS_PROSPECT_CLIENT'=>array('css'=>'minwidth200'),
    +    'DATAPOLICY_TIERS_NIPROSPECT_NICLIENT'=>array('css'=>'minwidth200'),
    +    'DATAPOLICY_TIERS_FOURNISSEUR'=>array('css'=>'minwidth200'),
    +    'DATAPOLICY_CONTACT_CLIENT'=>array('css'=>'minwidth200'),
    +    'DATAPOLICY_CONTACT_PROSPECT'=>array('css'=>'minwidth200'),
    +    'DATAPOLICY_CONTACT_PROSPECT_CLIENT'=>array('css'=>'minwidth200'),
    +    'DATAPOLICY_CONTACT_NIPROSPECT_NICLIENT'=>array('css'=>'minwidth200'),
    +    'DATAPOLICY_CONTACT_FOURNISSEUR'=>array('css'=>'minwidth200'),
    +    'DATAPOLICY_ADHERENT'=>array('css'=>'minwidth200'),
     );
     
     
    @@ -81,26 +81,26 @@ if (DOL_VERSION < '7' && $action == 'update') {
     
     $arrayofparameters=array(
         'ThirdParty' => array(
    -        'DATAPOLICIES_TIERS_CLIENT'=>array('css'=>'minwidth200'),
    -        'DATAPOLICIES_TIERS_PROSPECT'=>array('css'=>'minwidth200'),
    -        'DATAPOLICIES_TIERS_PROSPECT_CLIENT'=>array('css'=>'minwidth200'),
    -        'DATAPOLICIES_TIERS_NIPROSPECT_NICLIENT'=>array('css'=>'minwidth200'),
    -        'DATAPOLICIES_TIERS_FOURNISSEUR'=>array('css'=>'minwidth200'),
    +        'DATAPOLICY_TIERS_CLIENT'=>array('css'=>'minwidth200'),
    +        'DATAPOLICY_TIERS_PROSPECT'=>array('css'=>'minwidth200'),
    +        'DATAPOLICY_TIERS_PROSPECT_CLIENT'=>array('css'=>'minwidth200'),
    +        'DATAPOLICY_TIERS_NIPROSPECT_NICLIENT'=>array('css'=>'minwidth200'),
    +        'DATAPOLICY_TIERS_FOURNISSEUR'=>array('css'=>'minwidth200'),
         ),
         'Contact' => array(
    -        'DATAPOLICIES_CONTACT_CLIENT'=>array('css'=>'minwidth200'),
    -        'DATAPOLICIES_CONTACT_PROSPECT'=>array('css'=>'minwidth200'),
    -        'DATAPOLICIES_CONTACT_PROSPECT_CLIENT'=>array('css'=>'minwidth200'),
    -        'DATAPOLICIES_CONTACT_NIPROSPECT_NICLIENT'=>array('css'=>'minwidth200'),
    -        'DATAPOLICIES_CONTACT_FOURNISSEUR'=>array('css'=>'minwidth200'),
    +        'DATAPOLICY_CONTACT_CLIENT'=>array('css'=>'minwidth200'),
    +        'DATAPOLICY_CONTACT_PROSPECT'=>array('css'=>'minwidth200'),
    +        'DATAPOLICY_CONTACT_PROSPECT_CLIENT'=>array('css'=>'minwidth200'),
    +        'DATAPOLICY_CONTACT_NIPROSPECT_NICLIENT'=>array('css'=>'minwidth200'),
    +        'DATAPOLICY_CONTACT_FOURNISSEUR'=>array('css'=>'minwidth200'),
         ),
         'Member' => array(
    -        'DATAPOLICIES_ADHERENT'=>array('css'=>'minwidth200'),
    +        'DATAPOLICY_ADHERENT'=>array('css'=>'minwidth200'),
         )
     );
     
     $valTab = array(
    -    '' => $langs->trans('None'),
    +    '' => $langs->trans('Never'),
         '6' => $langs->trans('NB_MONTHS', 6),
         '12' => $langs->trans('ONE_YEAR'),
         '24' => $langs->trans('NB_YEARS', 2),
    @@ -108,6 +108,8 @@ $valTab = array(
         '48' => $langs->trans('NB_YEARS', 4),
         '60' => $langs->trans('NB_YEARS', 5),
         '120' => $langs->trans('NB_YEARS', 10),
    +	'180' => $langs->trans('NB_YEARS', 15),
    +	'240' => $langs->trans('NB_YEARS', 20),
     );
     
     
    @@ -115,20 +117,20 @@ $valTab = array(
      * View
      */
     
    -$page_name = "datapoliciesSetup";
    +$page_name = "datapolicySetup";
     llxHeader('', $langs->trans($page_name));
     
     // Subheader
     $linkback = '<a href="'.($backtopage?$backtopage:DOL_URL_ROOT.'/admin/modules.php?restore_lastsearch_values=1').'">'.$langs->trans("BackToModuleList").'</a>';
     
    -print load_fiche_titre($langs->trans($page_name), $linkback, 'object_datapolicies@datapolicies');
    +print load_fiche_titre($langs->trans($page_name), $linkback, 'object_datapolicy@datapolicy');
     
     // Configuration header
    -$head = datapoliciesAdminPrepareHead();
    -dol_fiche_head($head, 'settings', '', -1, "datapolicies@datapolicies");
    +$head = datapolicyAdminPrepareHead();
    +dol_fiche_head($head, 'settings', '', -1, "datapolicy@datapolicy");
     
     // Setup page goes here
    -echo $langs->trans("datapoliciesSetupPage");
    +echo '<span class="opacitymedium">'.$langs->trans("datapolicySetupPage").'</span><br><br>';
     
     
     if ($action == 'edit')
    @@ -180,7 +182,7 @@ else
             foreach($tab as $key => $val)
             {
                 print '<tr class="oddeven"><td>';
    -            print $form->textwithpicto($langs->trans($key),$langs->trans('DATAPOLICIES_Tooltip_SETUP'));
    +            print $form->textwithpicto($langs->trans($key),$langs->trans('DATAPOLICY_Tooltip_SETUP'));
                 print '</td><td>' . ($conf->global->$key == '' ? $langs->trans('None') : $valTab[$conf->global->$key]) . '</td></tr>';
             }
     
    diff --git a/htdocs/datapolicies/admin/setupmail.php b/htdocs/datapolicy/admin/setupmail.php
    similarity index 94%
    rename from htdocs/datapolicies/admin/setupmail.php
    rename to htdocs/datapolicy/admin/setupmail.php
    index a6560c1f7d5..214f673a15f 100644
    --- a/htdocs/datapolicies/admin/setupmail.php
    +++ b/htdocs/datapolicy/admin/setupmail.php
    @@ -22,10 +22,10 @@ require '../../main.inc.php';
     require_once DOL_DOCUMENT_ROOT . "/core/lib/admin.lib.php";
     require_once DOL_DOCUMENT_ROOT . '/core/class/doleditor.class.php';
     require_once DOL_DOCUMENT_ROOT . '/core/class/html.formadmin.class.php';
    -require_once '../lib/datapolicies.lib.php';
    +require_once '../lib/datapolicy.lib.php';
     
     // Translations
    -$langs->loadLangs(array('admin', 'companies', 'members', 'datapolicies'));
    +$langs->loadLangs(array('admin', 'companies', 'members', 'datapolicy'));
     
     
     // Parameters
    @@ -78,17 +78,17 @@ if ($action == 'setvalue' && $user->admin) {
      * View
      */
     
    -$page_name = "datapoliciesSetup";
    +$page_name = "datapolicySetup";
     llxHeader('', $langs->trans($page_name));
     
     // Subheader
     $linkback = '<a href="' . ($backtopage ? $backtopage : DOL_URL_ROOT . '/admin/modules.php?restore_lastsearch_values=1') . '">' . $langs->trans("BackToModuleList") . '</a>';
     
    -print load_fiche_titre($langs->trans($page_name), $linkback, 'object_datapolicies@datapolicies');
    +print load_fiche_titre($langs->trans($page_name), $linkback, 'object_datapolicy@datapolicy');
     
     // Configuration header
    -$head = datapoliciesAdminPrepareHead();
    -dol_fiche_head($head, 'settings', '', -1, "datapolicies@datapolicies");
    +$head = datapolicyAdminPrepareHead();
    +dol_fiche_head($head, 'settings', '', -1, "datapolicy@datapolicy");
     
     
     
    @@ -161,7 +161,7 @@ dol_fiche_end();
     print '<br><br>';
     
     print $langs->trans('SendAgreementText');
    -print '<a class="button" href="'.dol_buildpath('/datapolicies/mailing.php').'">'.$langs->trans('SendAgreement').'</a>';
    +print '<a class="button" href="'.dol_buildpath('/datapolicy/mailing.php').'">'.$langs->trans('SendAgreement').'</a>';
     
     llxFooter();
     $db->close();
    diff --git a/htdocs/datapolicies/class/actions_datapolicies.class.php b/htdocs/datapolicy/class/actions_datapolicy.class.php
    similarity index 72%
    rename from htdocs/datapolicies/class/actions_datapolicies.class.php
    rename to htdocs/datapolicy/class/actions_datapolicy.class.php
    index d65de390b8c..21fcb4a5a44 100644
    --- a/htdocs/datapolicies/class/actions_datapolicies.class.php
    +++ b/htdocs/datapolicy/class/actions_datapolicy.class.php
    @@ -17,15 +17,15 @@
      */
     
     /**
    - * \file    datapolicies/class/actions_datapolicies.class.php
    - * \ingroup datapolicies
    + * \file    datapolicy/class/actions_datapolicy.class.php
    + * \ingroup datapolicy
      * \brief   Example hook overload.
      */
     
     /**
    - * Class ActionsDatapolicies
    + * Class ActionsDatapolicy
      */
    -class ActionsDatapolicies
    +class ActionsDatapolicy
     {
         /**
          * @var DoliDB Database handler.
    @@ -91,7 +91,7 @@ class ActionsDatapolicies
         public function doActions($parameters, &$object, &$action, $hookmanager)
         {
             global $conf, $user, $langs;
    -        $langs->load('datapolicies@datapolicies');
    +        $langs->load('datapolicy@datapolicy');
             $error = 0; // Error counter
     
             if (GETPOST('socid') && $parameters['currentcontext'] == 'thirdpartycard') {
    @@ -129,9 +129,9 @@ class ActionsDatapolicies
                         header('Location:' . $_SERVER["PHP_SELF"] . "?socid=" . $object->id);
                     }
                 }
    -        } elseif ($parameters['currentcontext'] == 'thirdpartycard' && $action == 'datapolicies_portabilite') {
    +        } elseif ($parameters['currentcontext'] == 'thirdpartycard' && $action == 'datapolicy_portabilite') {
                 header('Content-Type: application/csv');
    -            header('Content-Disposition: attachment; filename=datapolicies_portabilite.csv');
    +            header('Content-Disposition: attachment; filename=datapolicy_portabilite.csv');
                 header('Pragma: no-cache');
                 $object->fetch(GETPOST('socid'));
                 echo 'Name;Fistname;Civility;Thirdparty;Function;Address;ZipCode;City;Department;Country;Email;Pro Phone;Perso Phone;Mobile Phone;Instant Mail;Birthday;' . PHP_EOL;
    @@ -152,9 +152,9 @@ class ActionsDatapolicies
                 echo $object->skype . ';';
                 echo ';';
                 exit;
    -        } elseif ($parameters['currentcontext'] == 'membercard' && $action == 'datapolicies_portabilite') {
    +        } elseif ($parameters['currentcontext'] == 'membercard' && $action == 'datapolicy_portabilite') {
                 header('Content-Type: application/csv');
    -            header('Content-Disposition: attachment; filename=datapolicies_portabilite.csv');
    +            header('Content-Disposition: attachment; filename=datapolicy_portabilite.csv');
                 header('Pragma: no-cache');
                 $soc = $object->fetch_thirdparty();
     
    @@ -176,10 +176,10 @@ class ActionsDatapolicies
                 echo $object->skype . ';';
                 echo dol_print_date($object->birth) . ';';
                 exit;
    -        } elseif ($parameters['currentcontext'] == 'contactcard' && $action == 'datapolicies_portabilite') {
    +        } elseif ($parameters['currentcontext'] == 'contactcard' && $action == 'datapolicy_portabilite') {
                 $object->fetch(GETPOST('id'));
                 header('Content-Type: application/csv');
    -            header('Content-Disposition: attachment; filename=datapolicies_portabilite.csv');
    +            header('Content-Disposition: attachment; filename=datapolicy_portabilite.csv');
                 header('Pragma: no-cache');
                 $soc = $object->fetch_thirdparty();
                 echo 'Name;Fistname;Civility;Thirdparty;Function;Address;ZipCode;City;Department;Country;Email;Pro Phone;Perso Phone;Mobile Phone;Instant Mail;Birthday;' . PHP_EOL;
    @@ -200,23 +200,23 @@ class ActionsDatapolicies
                 echo $object->jabberid . ';';
                 echo dol_print_date($object->birth) . ';';
                 exit;
    -        } elseif ($parameters['currentcontext'] == 'contactcard' && $action == 'send_datapolicies') {
    +        } elseif ($parameters['currentcontext'] == 'contactcard' && $action == 'send_datapolicy') {
                 $object->fetch(GETPOST('id'));
     
                 require_once  DOL_DOCUMENT_ROOT . '/contact/class/contact.class.php';
    -            require_once  DOL_DOCUMENT_ROOT . '/datapolicies/class/datapolicies.class.php';
    -            DataPolicies::sendMailDataPoliciesContact($object);
    +            require_once  DOL_DOCUMENT_ROOT . '/datapolicy/class/datapolicy.class.php';
    +            DataPolicy::sendMailDataPolicyContact($object);
             }
    -         elseif ($parameters['currentcontext'] == 'membercard' && $action == 'send_datapolicies') {
    +         elseif ($parameters['currentcontext'] == 'membercard' && $action == 'send_datapolicy') {
                  $object->fetch(GETPOST('id'));
                 require_once  DOL_DOCUMENT_ROOT . '/adherents/class/adherent.class.php';
    -            require_once  DOL_DOCUMENT_ROOT . '/datapolicies/class/datapolicies.class.php';
    -            DataPolicies::sendMailDataPoliciesAdherent($object);
    -        } elseif ($parameters['currentcontext'] == 'thirdpartycard' && $action == 'send_datapolicies') {
    +            require_once  DOL_DOCUMENT_ROOT . '/datapolicy/class/datapolicy.class.php';
    +            DataPolicy::sendMailDataPolicyAdherent($object);
    +        } elseif ($parameters['currentcontext'] == 'thirdpartycard' && $action == 'send_datapolicy') {
                 $object->fetch(GETPOST('socid'));
                 require_once  DOL_DOCUMENT_ROOT . '/societe/class/societe.class.php';
    -            require_once  DOL_DOCUMENT_ROOT . '/datapolicies/class/datapolicies.class.php';
    -            DataPolicies::sendMailDataPoliciesCompany($object);
    +            require_once  DOL_DOCUMENT_ROOT . '/datapolicy/class/datapolicy.class.php';
    +            DataPolicy::sendMailDataPolicyCompany($object);
             }
     
     
    @@ -280,7 +280,7 @@ class ActionsDatapolicies
     
             /* print_r($parameters); print_r($object); echo "action: " . $action; */
             if (in_array($parameters['currentcontext'], array('somecontext1', 'somecontext2'))) {  // do something only for the context 'somecontext1' or 'somecontext2'
    -            $this->resprints = '<option value="0"' . ($disabled ? ' disabled="disabled"' : '') . '>' . $langs->trans("datapoliciesMassAction") . '</option>';
    +            $this->resprints = '<option value="0"' . ($disabled ? ' disabled="disabled"' : '') . '>' . $langs->trans("datapolicyMassAction") . '</option>';
             }
     
             if (!$error) {
    @@ -361,47 +361,50 @@ class ActionsDatapolicies
         function addMoreActionsButtons($parameters, &$object, &$action, $hookmanager)
         {
             global $conf, $user, $langs;
    -        $langs->load('datapolicies@datapolicies');
    +        $langs->load('datapolicy@datapolicy');
     
    -        $dialog = '<div id="dialogdatapolicies" style="display:none;" title="' . $langs->trans('DATAPOLICIES_PORTABILITE_TITLE') . '">';
    -        $dialog .= '<div class="confirmmessage">' . img_help('', '') . ' ' . $langs->trans('DATAPOLICIES_PORTABILITE_CONFIRMATION') . '</div>';
    -        $dialog .= "</div>";
    -        $dialog .= '<script>
    -                  $( function() {
    -                    $("#rpgpdbtn").on("click", function(){
    -                        var href = $(this).attr("href");
    -                        $( "#dialogdatapolicies" ).dialog({
    -                          modal: true,
    -                          buttons: {
    -                            "OK": function() {
    -                              window.open(href);
    -                              $( this ).dialog( "close" );
    -                            },
    -                            "' . $langs->trans('Cancel') . '": function() {
    -                              $( this ).dialog( "close" );
    -                            }
    -                          }
    -                        });
    +        if (! empty($conf->global->DATAPOLICIES_ENABLE_EMAILS))
    +        {
    +	        $dialog = '<div id="dialogdatapolicy" style="display:none;" title="' . $langs->trans('DATAPOLICIES_PORTABILITE_TITLE') . '">';
    +	        $dialog .= '<div class="confirmmessage">' . img_help('', '') . ' ' . $langs->trans('DATAPOLICIES_PORTABILITE_CONFIRMATION') . '</div>';
    +	        $dialog .= "</div>";
    +	        $dialog .= '<script>
    +	                  $( function() {
    +	                    $("#rpgpdbtn").on("click", function(){
    +	                        var href = $(this).attr("href");
    +	                        $( "#dialogdatapolicy" ).dialog({
    +	                          modal: true,
    +	                          buttons: {
    +	                            "OK": function() {
    +	                              window.open(href);
    +	                              $( this ).dialog( "close" );
    +	                            },
    +	                            "' . $langs->trans('Cancel') . '": function() {
    +	                              $( this ).dialog( "close" );
    +	                            }
    +	                          }
    +	                        });
     
     
    -                    return false;
    -                    });
    -                  } );
    -                  </script>';
    -        echo $dialog;
    -        if ($parameters['currentcontext'] == 'thirdpartycard' && in_array($object->forme_juridique_code, array(11, 12, 13, 15, 17, 18, 19, 35, 60, 200, 311, 312, 316, 401, 600, 700, 1005)) || $object->typent_id == 8) {
    -            echo '<div class="inline-block divButAction"><a target="_blank" id="rpgpdbtn" class="butAction" href="' . $_SERVER["PHP_SELF"] . "?socid=" . $object->id . '&action=datapolicies_portabilite" title="' . $langs->trans('DATAPOLICIES_PORTABILITE_TITLE') . '">' . $langs->trans("DATAPOLICIES_PORTABILITE") . '</a></div>';
    -        } elseif ($parameters['currentcontext'] == 'membercard') {
    -            echo '<div class="inline-block divButAction"><a target="_blank" id="rpgpdbtn" class="butAction" href="' . $_SERVER["PHP_SELF"] . "?rowid=" . $object->id . '&action=datapolicies_portabilite" title="' . $langs->trans('DATAPOLICIES_PORTABILITE_TITLE') . '">' . $langs->trans("DATAPOLICIES_PORTABILITE") . '</a></div>';
    -        } elseif ($parameters['currentcontext'] == 'contactcard') {
    -            echo '<div class="inline-block divButAction"><a target="_blank" id="rpgpdbtn" class="butAction" href="' . $_SERVER["PHP_SELF"] . "?id=" . $object->id . '&action=datapolicies_portabilite" title="' . $langs->trans('DATAPOLICIES_PORTABILITE_TITLE') . '">' . $langs->trans("DATAPOLICIES_PORTABILITE") . '</a></div>';
    -        }
    -        if (!empty($object->mail) && empty($object->array_options['options_datapolicies_send']) && $parameters['currentcontext'] == 'thirdpartycard' && in_array($object->forme_juridique_code, array(11, 12, 13, 15, 17, 18, 19, 35, 60, 200, 311, 312, 316, 401, 600, 700, 1005)) || $object->typent_id == 8) {
    -            echo '<div class="inline-block divButAction"><a class="butAction" href="' . $_SERVER["PHP_SELF"] . "?socid=" . $object->id . '&action=send_datapolicies" title="' . $langs->trans('DATAPOLICIES_SEND') . '">' . $langs->trans("DATAPOLICIES_SEND") . '</a></div>';
    -        } elseif (!empty($object->mail) && empty($object->array_options['options_datapolicies_send']) && $parameters['currentcontext'] == 'membercard') {
    -            echo '<div class="inline-block divButAction"><a class="butAction" href="' . $_SERVER["PHP_SELF"] . "?rowid=" . $object->id . '&action=send_datapolicies" title="' . $langs->trans('DATAPOLICIES_SEND') . '">' . $langs->trans("DATAPOLICIES_SEND") . '</a></div>';
    -        } elseif (!empty($object->mail) && empty($object->array_options['options_datapolicies_send']) && $parameters['currentcontext'] == 'contactcard') {
    -            echo '<div class="inline-block divButAction"><a class="butAction" href="' . $_SERVER["PHP_SELF"] . "?id=" . $object->id . '&action=send_datapolicies" title="' . $langs->trans('DATAPOLICIES_SEND') . '">' . $langs->trans("DATAPOLICIES_SEND") . '</a></div>';
    +	                    return false;
    +	                    });
    +	                  } );
    +	                  </script>';
    +	        echo $dialog;
    +	        if ($parameters['currentcontext'] == 'thirdpartycard' && in_array($object->forme_juridique_code, array(11, 12, 13, 15, 17, 18, 19, 35, 60, 200, 311, 312, 316, 401, 600, 700, 1005)) || $object->typent_id == 8) {
    +	            echo '<div class="inline-block divButAction"><a target="_blank" id="rpgpdbtn" class="butAction" href="' . $_SERVER["PHP_SELF"] . "?socid=" . $object->id . '&action=datapolicy_portabilite" title="' . $langs->trans('DATAPOLICIES_PORTABILITE_TITLE') . '">' . $langs->trans("DATAPOLICIES_PORTABILITE") . '</a></div>';
    +	        } elseif ($parameters['currentcontext'] == 'membercard') {
    +	            echo '<div class="inline-block divButAction"><a target="_blank" id="rpgpdbtn" class="butAction" href="' . $_SERVER["PHP_SELF"] . "?rowid=" . $object->id . '&action=datapolicy_portabilite" title="' . $langs->trans('DATAPOLICIES_PORTABILITE_TITLE') . '">' . $langs->trans("DATAPOLICIES_PORTABILITE") . '</a></div>';
    +	        } elseif ($parameters['currentcontext'] == 'contactcard') {
    +	            echo '<div class="inline-block divButAction"><a target="_blank" id="rpgpdbtn" class="butAction" href="' . $_SERVER["PHP_SELF"] . "?id=" . $object->id . '&action=datapolicy_portabilite" title="' . $langs->trans('DATAPOLICIES_PORTABILITE_TITLE') . '">' . $langs->trans("DATAPOLICIES_PORTABILITE") . '</a></div>';
    +	        }
    +	        if (!empty($object->mail) && empty($object->array_options['options_datapolicy_send']) && $parameters['currentcontext'] == 'thirdpartycard' && in_array($object->forme_juridique_code, array(11, 12, 13, 15, 17, 18, 19, 35, 60, 200, 311, 312, 316, 401, 600, 700, 1005)) || $object->typent_id == 8) {
    +	            echo '<div class="inline-block divButAction"><a class="butAction" href="' . $_SERVER["PHP_SELF"] . "?socid=" . $object->id . '&action=send_datapolicy" title="' . $langs->trans('DATAPOLICIES_SEND') . '">' . $langs->trans("DATAPOLICIES_SEND") . '</a></div>';
    +	        } elseif (!empty($object->mail) && empty($object->array_options['options_datapolicy_send']) && $parameters['currentcontext'] == 'membercard') {
    +	            echo '<div class="inline-block divButAction"><a class="butAction" href="' . $_SERVER["PHP_SELF"] . "?rowid=" . $object->id . '&action=send_datapolicy" title="' . $langs->trans('DATAPOLICIES_SEND') . '">' . $langs->trans("DATAPOLICIES_SEND") . '</a></div>';
    +	        } elseif (!empty($object->mail) && empty($object->array_options['options_datapolicy_send']) && $parameters['currentcontext'] == 'contactcard') {
    +	            echo '<div class="inline-block divButAction"><a class="butAction" href="' . $_SERVER["PHP_SELF"] . "?id=" . $object->id . '&action=send_datapolicy" title="' . $langs->trans('DATAPOLICIES_SEND') . '">' . $langs->trans("DATAPOLICIES_SEND") . '</a></div>';
    +	        }
             }
         }
     
    @@ -422,11 +425,14 @@ class ActionsDatapolicies
             if ($parameters['currentcontext'] == 'thirdpartycard') {
                 if (GETPOST('action') == 'create' || GETPOST('action') == 'edit' || GETPOST('action') == '') {
                     $jsscript .= '<script>';
    -                $jsscript .= "var elementToHide = 'tr.societe_extras_datapolicies_consentement, tr.societe_extras_datapolicies_opposition_traitement, tr.societe_extras_datapolicies_opposition_prospection';" . PHP_EOL;
    +                $jsscript .= "var elementToHide = 'tr.societe_extras_datapolicy_consentement, tr.societe_extras_datapolicy_opposition_traitement, tr.societe_extras_datapolicy_opposition_prospection';" . PHP_EOL;
                     $jsscript .= "var forme_juridique = [" . PHP_EOL;
                     $jsscript .= "11, 12, 13, 15, 17, 18, 19, 35, 60, 200, 311, 312, 316, 401, 600, 700, 1005" . PHP_EOL;
                     $jsscript .= "];" . PHP_EOL;
    -                $jsscript .= "function hideRgPD() { if ($('#typent_id').val() == 8 || forme_juridique.indexOf(parseInt($('#forme_juridique_code').val())) > -1) { console.log(elementToHide); $('tr.societe_extras_datapolicies_consentement, tr.societe_extras_datapolicies_opposition_traitement, tr.societe_extras_datapolicies_opposition_prospection').show(); } else { $('tr.societe_extras_datapolicies_consentement, tr.societe_extras_datapolicies_opposition_traitement, tr.societe_extras_datapolicies_opposition_prospection').hide(); }}" . PHP_EOL;
    +                $jsscript .= "function hideRgPD() {" . PHP_EOL;
    +                $jsscript .= " if ($('#typent_id').val() == 8 || forme_juridique.indexOf(parseInt($('#forme_juridique_code').val())) > -1) {" . PHP_EOL;
    +                $jsscript .= " console.log(elementToHide);" . PHP_EOL;
    +                $jsscript .= " $('tr.societe_extras_datapolicy_consentement, tr.societe_extras_datapolicy_opposition_traitement, tr.societe_extras_datapolicy_opposition_prospection').show(); } else { $('tr.societe_extras_datapolicy_consentement, tr.societe_extras_datapolicy_opposition_traitement, tr.societe_extras_datapolicy_opposition_prospection').hide(); }}" . PHP_EOL;
                     $jsscript .= "hideRgPD();" . PHP_EOL;
                     $jsscript .= "$('#forme_juridique_code, #typent_id').change(function(){ hideRgPD(); });" . PHP_EOL;
                     $jsscript .= '</script>';
    @@ -454,7 +460,7 @@ class ActionsDatapolicies
     
                         require_once DOL_DOCUMENT_ROOT . '/core/class/html.form.class.php';
                         $jsscript .= '<script>';
    -                    $jsscript .= "var elementToHide = 'td.societe_extras_datapolicies_opposition_traitement, td.societe_extras_datapolicies_opposition_prospection, td.societe_extras_datapolicies_consentement';" . PHP_EOL;
    +                    $jsscript .= "var elementToHide = 'td.societe_extras_datapolicy_opposition_traitement, td.societe_extras_datapolicy_opposition_prospection, td.societe_extras_datapolicy_consentement';" . PHP_EOL;
                         $jsscript .= "$(elementToHide).parent('tr').hide();" . PHP_EOL;
                         $jsscript .= '</script>';
                     }
    @@ -462,8 +468,8 @@ class ActionsDatapolicies
             } elseif ($parameters['currentcontext'] == 'contactcard') {
                 if (GETPOST('action') == 'create' || GETPOST('action') == 'edit') {
                     $jsscript .= '<script>';
    -                $jsscript .= "$('#options_datapolicies_opposition_traitement, #options_datapolicies_opposition_prospection, input[name=\"options_datapolicies_opposition_traitement\"], input[name=\"options_datapolicies_opposition_prospection\"]').change(function(){
    -                    if($('#options_datapolicies_opposition_traitement').prop('checked') == true || $('input[name=options_datapolicies_opposition_traitement]').prop('checked') || $('#options_datapolicies_opposition_prospection').prop('checked') || $('input[name=options_datapolicies_opposition_prospection]').prop('checked')) {
    +                $jsscript .= "$('#options_datapolicy_opposition_traitement, #options_datapolicy_opposition_prospection, input[name=\"options_datapolicy_opposition_traitement\"], input[name=\"options_datapolicy_opposition_prospection\"]').change(function(){
    +                    if($('#options_datapolicy_opposition_traitement').prop('checked') == true || $('input[name=options_datapolicy_opposition_traitement]').prop('checked') || $('#options_datapolicy_opposition_prospection').prop('checked') || $('input[name=options_datapolicy_opposition_prospection]').prop('checked')) {
                             $('#no_email').val(1);
                         }
                     });";
    diff --git a/htdocs/datapolicies/class/datapolicies.class.php b/htdocs/datapolicy/class/datapolicy.class.php
    similarity index 78%
    rename from htdocs/datapolicies/class/datapolicies.class.php
    rename to htdocs/datapolicy/class/datapolicy.class.php
    index 4b21dba1d9a..3bebdff9302 100644
    --- a/htdocs/datapolicies/class/datapolicies.class.php
    +++ b/htdocs/datapolicy/class/datapolicy.class.php
    @@ -16,11 +16,9 @@
      */
     
     /**
    - * \file    datapolicies/class/actions_datapolicies.class.php
    - * \ingroup datapolicies
    - * \brief   Example hook overload.
    - *
    - * Put detailed description here.
    + * \file    datapolicy/class/datapolicy.class.php
    + * \ingroup datapolicy
    + * \brief   Class to manage feature of Data Policy module.
      */
     include_once DOL_DOCUMENT_ROOT . '/contact/class/contact.class.php';
     include_once DOL_DOCUMENT_ROOT . '/societe/class/societe.class.php';
    @@ -28,9 +26,9 @@ include_once DOL_DOCUMENT_ROOT . '/adherents/class/adherent.class.php';
     
     
     /**
    - * Class DataPolicies
    + * Class DataPolicy
      */
    -Class DataPolicies extends Contact
    +Class DataPolicy extends Contact
     {
     	/**
     	 * getAllContactNotInformed
    @@ -47,8 +45,8 @@ Class DataPolicies extends Contact
             $sql .= " FROM " . MAIN_DB_PREFIX . "socpeople as c";
             $sql .= " LEFT JOIN " . MAIN_DB_PREFIX . "societe as s ON c.fk_soc = s.rowid";
             $sql .= " LEFT JOIN " . MAIN_DB_PREFIX . "socpeople_extrafields as spe ON spe.fk_object = c.rowid";
    -        $sql .= " WHERE (c.statut=1 AND c.no_email=0 AND (spe.datapolicies_consentement=0 OR spe.datapolicies_consentement IS NULL) AND (spe.datapolicies_opposition_traitement=0 OR spe.datapolicies_opposition_traitement IS NULL) AND (spe.datapolicies_opposition_prospection=0 OR spe.datapolicies_opposition_prospection IS NULL))";
    -        $sql .= " AND spe.datapolicies_send IS NULL";
    +        $sql .= " WHERE (c.statut=1 AND c.no_email=0 AND (spe.datapolicy_consentement=0 OR spe.datapolicy_consentement IS NULL) AND (spe.datapolicy_opposition_traitement=0 OR spe.datapolicy_opposition_traitement IS NULL) AND (spe.datapolicy_opposition_prospection=0 OR spe.datapolicy_opposition_prospection IS NULL))";
    +        $sql .= " AND spe.datapolicy_send IS NULL";
             $sql .= " AND c.entity=" . $conf->entity;
             $resql = $this->db->query($sql);
             if ($resql) {
    @@ -59,7 +57,7 @@ Class DataPolicies extends Contact
                     $contact = new Contact($db);
                     $contact->fetch($obj->rowid);
     
    -                DataPolicies::sendMailDataPoliciesContact($contact);
    +                DataPolicy::sendMailDataPolicyContact($contact);
                     $i++;
                 }
             } else {
    @@ -82,8 +80,8 @@ Class DataPolicies extends Contact
             $sql = "SELECT s.rowid";
             $sql .= " FROM " . MAIN_DB_PREFIX . "societe as s";
             $sql .= " LEFT JOIN " . MAIN_DB_PREFIX . "societe_extrafields as se ON se.fk_object = s.rowid";
    -        $sql .= " WHERE s.statut=0 AND (se.datapolicies_consentement=0 OR se.datapolicies_consentement IS NULL) AND (se.datapolicies_opposition_traitement=0 OR se.datapolicies_opposition_traitement IS NULL) AND (se.datapolicies_opposition_prospection=0 OR se.datapolicies_opposition_prospection IS NULL)";
    -        $sql .= " AND se.datapolicies_send IS NULL";
    +        $sql .= " WHERE s.statut=0 AND (se.datapolicy_consentement=0 OR se.datapolicy_consentement IS NULL) AND (se.datapolicy_opposition_traitement=0 OR se.datapolicy_opposition_traitement IS NULL) AND (se.datapolicy_opposition_prospection=0 OR se.datapolicy_opposition_prospection IS NULL)";
    +        $sql .= " AND se.datapolicy_send IS NULL";
             $sql .= " AND s.entity=" . $conf->entity;
             $resql = $this->db->query($sql);
             if ($resql) {
    @@ -94,7 +92,7 @@ Class DataPolicies extends Contact
                     $societe = new Societe($db);
                     $societe->fetch($obj->rowid);
     
    -                DataPolicies::sendMailDataPoliciesCompany($societe);
    +                DataPolicy::sendMailDataPolicyCompany($societe);
                     $i++;
                 }
             } else {
    @@ -117,8 +115,8 @@ Class DataPolicies extends Contact
             $sql = "SELECT a.rowid";
             $sql .= " FROM " . MAIN_DB_PREFIX . "adherent as a";
             $sql .= " LEFT JOIN " . MAIN_DB_PREFIX . "adherent_extrafields as ae ON ae.fk_object = a.rowid";
    -        $sql .= " WHERE a.statut=0 AND (ae.datapolicies_consentement=0 OR ae.datapolicies_consentement IS NULL) AND (ae.datapolicies_opposition_traitement=0 OR ae.datapolicies_opposition_traitement IS NULL) AND (ae.datapolicies_opposition_prospection=0 OR ae.datapolicies_opposition_prospection IS NULL)";
    -        $sql .= " AND ae.datapolicies_send IS NULL";
    +        $sql .= " WHERE a.statut=0 AND (ae.datapolicy_consentement=0 OR ae.datapolicy_consentement IS NULL) AND (ae.datapolicy_opposition_traitement=0 OR ae.datapolicy_opposition_traitement IS NULL) AND (ae.datapolicy_opposition_prospection=0 OR ae.datapolicy_opposition_prospection IS NULL)";
    +        $sql .= " AND ae.datapolicy_send IS NULL";
             $sql .= " AND a.entity=" . $conf->entity;
             $resql = $this->db->query($sql);
             if ($resql) {
    @@ -129,7 +127,7 @@ Class DataPolicies extends Contact
                     $adherent = new Adherent($db);
                     $adherent->fetch($obj->rowid);
     
    -                DataPolicies::sendMailDataPoliciesAdherent($adherent);
    +                DataPolicy::sendMailDataPolicyAdherent($adherent);
                     $i++;
                 }
             } else {
    @@ -139,16 +137,19 @@ Class DataPolicies extends Contact
         }
     
         /**
    -     * sendMailDataPoliciesContact
    +     * sendMailDataPolicyContact
          *
          * @param 	mixed		$contact		Contact
          * @return	void
          */
    -    function sendMailDataPoliciesContact($contact)
    +    function sendMailDataPolicyContact($contact)
         {
          	global $langs, $conf, $db, $user;
    +
    +     	$error = 0;
    +
          	$from = $user->getFullName($langs) . ' <' . $user->email . '>';
    -     	$replyto = $from;
    +
          	$sendto = $contact->email;
          	$code= md5($contact->email);
          	if (!empty($contact->default_lang)) {
    @@ -165,10 +166,13 @@ Class DataPolicies extends Contact
          	$message = $conf->global->$ma;
          	$linka = $conf->global->$la;
          	$linkr = $conf->global->$lr;
    +     	$sendtocc = $sendtobcc = '';
    +     	$filepath = $mimetype = $filename = array();
    +     	$deliveryreceipt = 0;
     
          	$substitutionarray = array(
    -     	'__LINKACCEPT__' => '<a href="'.dol_buildpath('/datapolicies/public/index.php?action=1&c='.$contact->id.'&l='.$l.'&key='.$code,3).'" target="_blank">'.$linka.'</a>',
    -     	'__LINKREFUSED__' => '<a href="'.dol_buildpath('/datapolicies/public/index.php?action=2&c='.$contact->id.'&l='.$l.'&key='.$code,3).'" target="_blank">'.$linkr.'</a>',
    +     	'__LINKACCEPT__' => '<a href="'.dol_buildpath('/datapolicy/public/index.php?action=1&c='.$contact->id.'&l='.$l.'&key='.$code,3).'" target="_blank">'.$linka.'</a>',
    +     	'__LINKREFUSED__' => '<a href="'.dol_buildpath('/datapolicy/public/index.php?action=2&c='.$contact->id.'&l='.$l.'&key='.$code,3).'" target="_blank">'.$linkr.'</a>',
          	'__FIRSTNAME__' => $contact->firstname,
          	'__NAME__' => $contact->lastname,
          	'__CIVILITY__' => $contact->civility,
    @@ -198,7 +202,7 @@ Class DataPolicies extends Contact
          		if (!$error) {
     
          			$resultmasssend .= $langs->trans("MailSent") . ': ' . $sendto . "<br>";
    -     			$contact->array_options['options_datapolicies_send'] = date('Y-m-d', time());
    +     			$contact->array_options['options_datapolicy_send'] = date('Y-m-d', time());
          			$contact->update($contact->id);
     
          		} else {
    @@ -209,16 +213,19 @@ Class DataPolicies extends Contact
         }
     
         /**
    -     * sendMailDataPoliciesCompany
    +     * sendMailDataPolicyCompany
          *
          * @param Societe	$societe	Object societe
          * @return	void
          */
    -    function sendMailDataPoliciesCompany($societe)
    +    function sendMailDataPolicyCompany($societe)
         {
          	global $langs, $conf, $db, $user;
    +
    +     	$error = 0;
    +
          	$from = $user->getFullName($langs) . ' <' . $user->email . '>';
    -     	$replyto = $from;
    +
          	$sendto = $societe->email;
     
          	$code= md5($societe->email);
    @@ -236,11 +243,13 @@ Class DataPolicies extends Contact
          	$message = $conf->global->$ma;
          	$linka = $conf->global->$la;
          	$linkr = $conf->global->$lr;
    -
    +     	$sendtocc = $sendtobcc = '';
    +     	$filepath = $mimetype = $filename = array();
    +     	$deliveryreceipt = 0;
     
          	$substitutionarray = array(
    -            '__LINKACCEPT__' => '<a href="'.dol_buildpath('/datapolicies/public/index.php?action=1&s='.$societe->id.'&l='.$l.'&key='.$code,3).'" target="_blank">'.$linka.'</a>',
    -            '__LINKREFUSED__' => '<a href="'.dol_buildpath('/datapolicies/public/index.php?action=2&s='.$societe->id.'&l='.$l.'&key='.$code,3).'" target="_blank">'.$linkr.'</a>',
    +            '__LINKACCEPT__' => '<a href="'.dol_buildpath('/datapolicy/public/index.php?action=1&s='.$societe->id.'&l='.$l.'&key='.$code,3).'" target="_blank">'.$linka.'</a>',
    +            '__LINKREFUSED__' => '<a href="'.dol_buildpath('/datapolicy/public/index.php?action=2&s='.$societe->id.'&l='.$l.'&key='.$code,3).'" target="_blank">'.$linkr.'</a>',
          	);
          	$subject = make_substitutions($subject, $substitutionarray);
          	$message = make_substitutions($message, $substitutionarray);
    @@ -266,7 +275,7 @@ Class DataPolicies extends Contact
     
          		if (!$error) {
          			$resultmasssend .= $langs->trans("MailSent") . ': ' . $sendto . "<br>";
    -     			$societe->array_options['options_datapolicies_send'] = date('Y-m-d', time());
    +     			$societe->array_options['options_datapolicy_send'] = date('Y-m-d', time());
          			$societe->update($societe->id);
          		} else {
          			dol_print_error($db);
    @@ -276,16 +285,19 @@ Class DataPolicies extends Contact
         }
     
         /**
    -     * sendMailDataPoliciesAdherent
    +     * sendMailDataPolicyAdherent
          *
          * @param Adherent	$adherent		Member
          * @return void
          */
    -    function sendMailDataPoliciesAdherent($adherent)
    +    function sendMailDataPolicyAdherent($adherent)
         {
         	global $langs, $conf, $db, $user;
    +
    +    	$error = 0;
    +
         	$from = $user->getFullName($langs) . ' <' . $user->email . '>';
    -    	$replyto = $from;
    +
         	$sendto = $adherent->email;
     
         	$code= md5($adherent->email);
    @@ -301,11 +313,13 @@ Class DataPolicies extends Contact
         	$message = $conf->global->$ma;
         	$linka = $conf->global->$la;
         	$linkr = $conf->global->$lr;
    -
    +    	$sendtocc = $sendtobcc = '';
    +    	$filepath = $mimetype = $filename = array();
    +    	$deliveryreceipt = 0;
     
         	$substitutionarray = array(
    -            '__LINKACCEPT__' => '<a href="'.dol_buildpath('/datapolicies/public/index.php?action=1&a='.$adherent->id.'&l='.$l.'&key='.$code,3).'" target="_blank">'.$linka.'</a>',
    -            '__LINKREFUSED__' => '<a href="'.dol_buildpath('/datapolicies/public/index.php?action=2&a='.$adherent->id.'&l='.$l.'&key='.$code,3).'" target="_blank">'.$linkr.'</a>',
    +            '__LINKACCEPT__' => '<a href="'.dol_buildpath('/datapolicy/public/index.php?action=1&a='.$adherent->id.'&l='.$l.'&key='.$code,3).'" target="_blank">'.$linka.'</a>',
    +            '__LINKREFUSED__' => '<a href="'.dol_buildpath('/datapolicy/public/index.php?action=2&a='.$adherent->id.'&l='.$l.'&key='.$code,3).'" target="_blank">'.$linkr.'</a>',
         	);
         	$subject = make_substitutions($subject, $substitutionarray);
         	$message = make_substitutions($message, $substitutionarray);
    @@ -332,7 +346,7 @@ Class DataPolicies extends Contact
     
         		if (!$error) {
         			$resultmasssend .= $langs->trans("MailSent") . ': ' . $sendto . "<br>";
    -    			$adherent->array_options['options_datapolicies_send'] = date('Y-m-d', time());
    +    			$adherent->array_options['options_datapolicy_send'] = date('Y-m-d', time());
         			$adherent->update($user);
     
         		} else {
    diff --git a/htdocs/datapolicies/class/datapoliciescron.class.php b/htdocs/datapolicy/class/datapolicycron.class.php
    similarity index 98%
    rename from htdocs/datapolicies/class/datapoliciescron.class.php
    rename to htdocs/datapolicy/class/datapolicycron.class.php
    index c87df67498d..f6de8b9b498 100644
    --- a/htdocs/datapolicies/class/datapoliciescron.class.php
    +++ b/htdocs/datapolicy/class/datapolicycron.class.php
    @@ -17,15 +17,15 @@
      */
     
     /**
    - * \file    datapolicies/class/datapoliciescron.class.php
    - * \ingroup datapolicies
    + * \file    datapolicy/class/datapolicycron.class.php
    + * \ingroup datapolicy
      * \brief   Example hook overload.
      */
     
     /**
    - * Class DataPoliciesCron
    + * Class DataPolicyCron
      */
    -class DataPoliciesCron
    +class DataPolicyCron
     {
     	/**
     	 * Function exec
    @@ -36,7 +36,7 @@ class DataPoliciesCron
         {
             global $conf, $db, $langs, $user;
     
    -        $langs->load('datapolicies@datapolicies');
    +        $langs->load('datapolicy@datapolicy');
     
             // FIXME Removed hardcoded values of id
             $arrayofparameters=array(
    @@ -510,11 +510,11 @@ class DataPoliciesCron
         {
             global $conf, $db, $langs, $user;
     
    -        $langs->load('datapolicies@datapolicies');
    +        $langs->load('datapolicy@datapolicy');
     
    -        require_once DOL_DOCUMENT_ROOT . '/datapolicies/class/datapolicies.class.php';
    +        require_once DOL_DOCUMENT_ROOT . '/datapolicy/class/datapolicy.class.php';
     
    -        $contacts = new DataPolicies($db);
    +        $contacts = new DataPolicy($db);
             $contacts->getAllContactNotInformed();
             $contacts->getAllCompaniesNotInformed();
             $contacts->getAllAdherentsNotInformed();
    diff --git a/htdocs/datapolicies/img/datapolicies.png b/htdocs/datapolicy/img/datapolicy.png
    similarity index 100%
    rename from htdocs/datapolicies/img/datapolicies.png
    rename to htdocs/datapolicy/img/datapolicy.png
    diff --git a/htdocs/datapolicies/img/gfdl.png b/htdocs/datapolicy/img/gfdl.png
    similarity index 100%
    rename from htdocs/datapolicies/img/gfdl.png
    rename to htdocs/datapolicy/img/gfdl.png
    diff --git a/htdocs/datapolicies/img/gplv3.png b/htdocs/datapolicy/img/gplv3.png
    similarity index 100%
    rename from htdocs/datapolicies/img/gplv3.png
    rename to htdocs/datapolicy/img/gplv3.png
    diff --git a/htdocs/datapolicies/img/object_datapolicies.png b/htdocs/datapolicy/img/object_datapolicy.png
    similarity index 100%
    rename from htdocs/datapolicies/img/object_datapolicies.png
    rename to htdocs/datapolicy/img/object_datapolicy.png
    diff --git a/htdocs/datapolicies/img/object_inoveaconseil.png b/htdocs/datapolicy/img/object_inoveaconseil.png
    similarity index 100%
    rename from htdocs/datapolicies/img/object_inoveaconseil.png
    rename to htdocs/datapolicy/img/object_inoveaconseil.png
    diff --git a/htdocs/datapolicy/langs/en_US/datapolicy.lang b/htdocs/datapolicy/langs/en_US/datapolicy.lang
    new file mode 100644
    index 00000000000..ddcd2180cb0
    --- /dev/null
    +++ b/htdocs/datapolicy/langs/en_US/datapolicy.lang
    @@ -0,0 +1,92 @@
    +# Copyright (C) 2018 Nicolas ZABOURI    <info@inovea-conseil.com>
    +#
    +# This program is free software: you can redistribute it and/or modify
    +# it under the terms of the GNU General Public License as published by
    +# the Free Software Foundation, either version 3 of the License, or
    +# (at your option) any later version.
    +#
    +# This program is distributed in the hope that it will be useful,
    +# but WITHOUT ANY WARRANTY; without even the implied warranty of
    +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    +# GNU General Public License for more details.
    +#
    +# You should have received a copy of the GNU General Public License
    +# along with this program.  If not, see <http://www.gnu.org/licenses/>.
    +
    +# Module label 'ModuledatapolicyName'
    +Module4100Name = Data Privacy Policy
    +# Module description 'ModuledatapolicyDesc'
    +Module4100Desc = Module to manage Data Privacy (Conformity with the GDPR)
    +
    +#
    +# Page d'administration
    +#
    +datapolicySetup = Module Data Privacy Policy Setup
    +Deletion = Deletion of data
    +datapolicySetupPage = Depending of laws of your countries (Example <a href="http://www.privacy-regulation.eu/en/5.htm" target="_blank">Article 5</a> of the GDPR), personal data must be kept for a period not exceeding that necessary for the purposes for which they were collected, except for archival purposes.<br>The deletion will be done automatically after a certain duration without event (the duration which you will have indicated below).
    +NB_MONTHS = %s months
    +ONE_YEAR = 1 year
    +NB_YEARS = %s years
    +DATAPOLICY_TIERS_CLIENT = Customer
    +DATAPOLICY_TIERS_PROSPECT = Prospect
    +DATAPOLICY_TIERS_PROSPECT_CLIENT = Prospect/Customer
    +DATAPOLICY_TIERS_NIPROSPECT_NICLIENT = Nor prospect/Nor customer
    +DATAPOLICY_TIERS_FOURNISSEUR = Supplier
    +DATAPOLICY_CONTACT_CLIENT = Customer
    +DATAPOLICY_CONTACT_PROSPECT = Prospect
    +DATAPOLICY_CONTACT_PROSPECT_CLIENT = Prospect/Customer
    +DATAPOLICY_CONTACT_NIPROSPECT_NICLIENT = Nor prospect/Nor customer
    +DATAPOLICY_CONTACT_FOURNISSEUR = Supplier
    +DATAPOLICY_ADHERENT = Member
    +DATAPOLICY_Tooltip_SETUP = Type of contact - Indicate your choices for each type.
    +DATAPOLICYMail=Emails Setup
    +DATAPOLICYSUBJECTMAIL=Subject of email
    +DATAPOLICYCONTENTMAIL=Content of the email
    +DATAPOLICYSUBSITUTION=You can use the following variables in your email (LINKACCEPT allows to create a link recording the agreement of the person, LINKREFUSED makes it possible to record the refusal of the person):
    +DATAPOLICYACCEPT=Message after agreement
    +DATAPOLICYREFUSE=Message after desagreement
    +SendAgreementText=You can send a GDPR email to all your relevant contacts (who have not yet received an email and for which you have not registered anything about their GDPR agreement). To do this, use the following button.
    +SendAgreement=Send emails
    +AllAgreementSend = All emails have been sent
    +TXTLINKDATAPOLICYACCEPT= Text for the link "agreement" 
    +TXTLINKDATAPOLICYREFUSE= Text for the link "desagreement" 
    +
    +
    +#
    +# Extrafield
    +#
    +DATAPOLICY_BLOCKCHECKBOX = GDPR : Processing of personal data
    +DATAPOLICY_consentement = Consent obtained for the processing of personal data 
    +DATAPOLICY_opposition_traitement = Opposes the processing of his personal data
    +DATAPOLICY_opposition_prospection = Opposes the processing of his personal data for the purposes of prospecting
    +
    +#
    +# Popup
    +#
    +DATAPOLICY_POPUP_ANONYME_TITLE = Anonymize a thirdparty
    +DATAPOLICY_POPUP_ANONYME_TEXTE = You can not delete this contact from Dolibarr because there are related items. In accordance with the GDPR, you will make all this data anonymous to respect your obligations. Would you like to continue ?
    +
    +#
    +# Bouton portabilité
    +# 
    +DATAPOLICY_PORTABILITE = Portability GDPR
    +DATAPOLICY_PORTABILITE_TITLE = Export of personal data
    +DATAPOLICY_PORTABILITE_CONFIRMATION = You want to export the personal data of this contact. Are you sure ?
    +
    +#
    +# Note ajoutés lors d'une anonymisation
    +#
    +ANONYMISER_AT = Anonymised the %s
    +
    +#V2
    +DATAPOLICYReturn=GDPR Validation
    +DATAPOLICY_date = Date of agreement/desagreement GDPR
    +DATAPOLICY_send = Date sending agreement email
    +DATAPOLICYReturn = GDPR Return
    +DATAPOLICY_SEND = Send GDPR email
    +MailSent = Email has been sent
    +
    +#ERROR
    +ErrorSubjectIsRequired= Error : The subject of email is required. Indicate it in the module setup
    +=Due to a technical problem, we were unable to register your choice. We apologize for that. Contact us to send us your choice.
    +NUMBER_MONTH_BEFORE_DELETION = Number of month before deletion
    diff --git a/htdocs/datapolicy/langs/fr_FR/datapolicy.lang b/htdocs/datapolicy/langs/fr_FR/datapolicy.lang
    new file mode 100644
    index 00000000000..7ee710aae2e
    --- /dev/null
    +++ b/htdocs/datapolicy/langs/fr_FR/datapolicy.lang
    @@ -0,0 +1,97 @@
    +# Copyright (C) 2018  INOVEA CONSEil info@inovea-conseil.com
    +#
    +# This program is free software: you can redistribute it and/or modify
    +# it under the terms of the GNU General Public License as published by
    +# the Free Software Foundation, either version 3 of the License, or
    +# (at your option) any later version.
    +#
    +# This program is distributed in the hope that it will be useful,
    +# but WITHOUT ANY WARRANTY; without even the implied warranty of
    +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    +# GNU General Public License for more details.
    +#
    +# You should have received a copy of the GNU General Public License
    +# along with this program.  If not, see <http://www.gnu.org/licenses/>.
    +
    +#
    +# Générique
    +#
    +
    +# Module label 'ModuledatapolicyName'
    +Module4100Name = Protection des Données
    +# Module description 'ModuledatapolicyDesc'
    +Module4100Desc = Module de gestion de la protection des données (RGPD)
    +
    +#
    +# Page d'administration
    +#
    +datapolicySetup = Configuration du module Protection des données
    +Settings_DATAPOLICY = Paramétrage du module Protection des données
    +datapolicySetupPage = Selon la loi de votre pays (Exemple <a href="http://www.privacy-regulation.eu/fr/5.htm" target="_blank">l’article 5</a> du RGPD), les données à caractère personnel doivent être conservées pendant une durée n’excédant pas celle nécessaire au regard des finalités pour lesquelles elles ont été traitées, à l’exception de fins archivistiques. La suppression se fera automatiquement après une certaine durée sans évènement (la durée que vous aurez indiquée ci-dessous).
    +NB_MONTHS = %s mois
    +ONE_YEAR = 1 an
    +NB_YEARS = %s ans
    +DATAPOLICY_TIERS_CLIENT = Client
    +DATAPOLICY_TIERS_PROSPECT = Prospect
    +DATAPOLICY_TIERS_PROSPECT_CLIENT = Prospect/Client
    +DATAPOLICY_TIERS_NIPROSPECT_NICLIENT = Ni prospect / Ni client
    +DATAPOLICY_TIERS_FOURNISSEUR = Fournisseur
    +DATAPOLICY_CONTACT_CLIENT = Client
    +DATAPOLICY_CONTACT_PROSPECT = Prospect
    +DATAPOLICY_CONTACT_PROSPECT_CLIENT = Prospect/Client
    +DATAPOLICY_CONTACT_NIPROSPECT_NICLIENT = Ni prospect / Ni client
    +DATAPOLICY_CONTACT_FOURNISSEUR = Fournisseur
    +DATAPOLICY_ADHERENT = Adhérent
    +DATAPOLICY_Tooltip_SETUP = Type du contact - Indiquez vos choix pour chaque type.
    +DATAPOLICYMail=Paramétrage des emails
    +DATAPOLICYSUBJECTMAIL=Objet du mail
    +DATAPOLICYCONTENTMAIL=Contenu du mail
    +DATAPOLICYSUBSITUTION=Vous pouvez utiliser les variables suivantes dans votre email (LINKACCEPT permet de créer un lien enregistrant l'acceptation de la personne, LINKREFUSED permet d'enregistrer le refus de la personne) :
    +DATAPOLICYACCEPT=Message suite acceptation
    +DATAPOLICYREFUSE=Message suite opposition
    +SendAgreementText=Vous pouvez envoyer un email DATAPOLICY à tous vos contacts concernés (qui n'ont pas encore reçus de mail et pour lesquels vous n'avez rien enregistré concernant leur accord/désaccord DATAPOLICY). Pour cela, utilisez le bouton suivant.
    +SendAgreement=Envoyer les emails
    +AllAgreementSend = Tous les e-mails de consentement ont été envoyés
    +TXTLINKDATAPOLICYACCEPT= Texte du lien d'acceptation
    +TXTLINKDATAPOLICYREFUSE= Texte du lien d'opposition
    +
    +
    +
    +#
    +# Extrafield
    +#
    +DATAPOLICY_BLOCKCHECKBOX = DATAPOLICY : Traitement des données à caractère personnel
    +DATAPOLICY_consentement = Consentement recueilli pour le traitement des données à caractère personnel le concernant
    +DATAPOLICY_opposition_traitement = S’oppose au traitement de ses données à caractère personnel
    +DATAPOLICY_opposition_prospection = S’oppose au traitement de ses données à caractère personnel à des fins de prospection
    +
    +#
    +# Popup
    +#
    +DATAPOLICY_POPUP_ANONYME_TITLE = Anonymiser un tiers
    +DATAPOLICY_POPUP_ANONYME_TEXTE = Vous ne pouvez pas supprimer ce contact de Dolibarr car des éléments y sont liés. Conformément au DATAPOLICY, vous allez rendre toutes ces données anonymes afin de respecter vos obligations. Souhaitez-vous continuer ?
    +
    +#
    +# Bouton portabilité
    +# 
    +DATAPOLICY_PORTABILITE = Portabilité DATAPOLICY
    +DATAPOLICY_PORTABILITE_TITLE = Export des données à caractère personnel
    +DATAPOLICY_PORTABILITE_CONFIRMATION = Vous souhaitez exporter les données à caractère personnel de ce contact. Etes-vous sûr ?
    +
    +#
    +# Note ajoutés lors d'une anonymisation
    +#
    +ANONYMISER_AT = Anonymisé le %s
    +
    +#V2
    +DATAPOLICYReturn=Validation DATAPOLICY
    +DATAPOLICY_date=Date d'accord/opposition au traitement
    +DATAPOLICY_send=Date envoi consentement
    +DATAPOLICYReturn=Retour DATAPOLICY
    +DATAPOLICY_SEND=Envoyer l'email de consentement
    +MailSent=L'email a bien été envoyé
    +
    +#ERROR
    +ErrorSubjectIsRequired=Erreur : vous n'avez pas indiqué l'objet de l'email dans la configuration
    +=Suite à un problème technique, nous n'avons pas pu enregistrer votre choix. Nous nous en excusons. Contactez-nous pour nous transmettre votre choix.
    +NUMBER_MONTH_BEFORE_DELETION = Nombre de mois avant suppression des données
    diff --git a/htdocs/datapolicy/langs/it_IT/datapolicy.lang b/htdocs/datapolicy/langs/it_IT/datapolicy.lang
    new file mode 100644
    index 00000000000..d8858b56c5b
    --- /dev/null
    +++ b/htdocs/datapolicy/langs/it_IT/datapolicy.lang
    @@ -0,0 +1,78 @@
    +# Copyright (C) 2018 INOVEA CONSEIl info@inovea-conseil.com - Thanks to Claudio Aschieri
    +#
    +# # Module label 'ModuledatapolicyName'
    +Module4100Name = Data Policy
    +# Module description 'ModuledatapolicyDesc'
    +Module4100Desc = Conformità con GDPR
    +
    +#
    +# Page d'administration
    +#
    +datapolicySetup = Module Setup
    +Settings_DATAPOLICY = Configurazione modulo GDPR 
    +datapolicySetupPage = In accordo con <a href="http://www.privacy-regulation.eu/it/5.htm" target="_blank">l'art 5 del GDPR </a> i dati personali devono essere conservati per un periodo di tempo che .... ed eliminati se non sono più utili agli scopi per cui sono stati processati.
    +NB_MONTHS = %s mesi
    +ONE_YEAR = 1 anno
    +NB_YEARS = %s anni
    +DATAPOLICY_TIERS_CLIENT = Cliente
    +DATAPOLICY_TIERS_PROSPECT = Fornitore
    +DATAPOLICY_TIERS_PROSPECT_CLIENT = Potenziale Cliente / Cliente
    +DATAPOLICY_TIERS_NIPROSPECT_NICLIENT = Nè potenziale cliente / Nè cliente
    +DATAPOLICY_TIERS_FOURNISSEUR = Fornitore
    +DATAPOLICY_CONTACT_CLIENT = Cliente
    +DATAPOLICY_CONTACT_PROSPECT = Potenziale cliente
    +DATAPOLICY_CONTACT_PROSPECT_CLIENT = Potenziale Cliente / Cliente
    +DATAPOLICY_CONTACT_NIPROSPECT_NICLIENT = Nè potenziale cliente / Nè cliente
    +DATAPOLICY_CONTACT_FOURNISSEUR = Fornitore
    +DATAPOLICY_ADHERENT = Membri
    +DATAPOLICY_Tooltip_SETUP = Tipo di contatto - Indica la scelta per ogni tipologia
    +DATAPOLICYMail=Configurazione Email
    +DATAPOLICYSUBJECTMAIL=Subject dell'e-mail
    +DATAPOLICYCONTENTMAIL=Contenuto dell'e-mail
    +DATAPOLICYSUBSITUTION=Puoi utilizzare le seguenti variabili nella tua email (LINKACCEPT consente di creare un link per registrare l'accettazione della persona, LINKREFUSED consente di registrare il rifiuto della persona):
    +DATAPOLICYACCEPT= Messaggio dopo il consenso
    +DATAPOLICYREFUSE=Messaggio dopo il rifiuto
    +SendAgreementText=Puoi inviare un'email GDPR a tutti i tuoi contatti rilevanti (che non hanno ancora ricevuto un'e-mail e per i quali non hai registrato nulla sul loro accordo GDPR). Per fare ciò, utilizzare il seguente pulsante.
    +SendAgreement=Invia emails
    +AllAgreementSend = Tutte le email sono state inviate
    +TXTLINKDATAPOLICYACCEPT= Testo per il link "Consenso" 
    +TXTLINKDATAPOLICYREFUSE= Testo per il link "Consenso negato" 
    +
    +#
    +# Extrafield
    +#
    +DATAPOLICY_BLOCKCHECKBOX = GDPR : Trattamento dei dati personali
    +DATAPOLICY_consentement = Consenso ottenuto al Trattamento dei dati personali
    +DATAPOLICY_opposition_traitement = Consenso negato al trattamento dei dati personali
    +DATAPOLICY_opposition_prospection = Consenso negato al trattamento dei dati personali a fini commerciali
    +
    +#
    +# Popup
    +#
    +DATAPOLICY_POPUP_ANONYME_TITLE = Anonimizza un soggetto terzo
    +DATAPOLICY_POPUP_ANONYME_TEXTE = Impossibile eliminare questo contatto da Dolibarr perchè vi sono elementi collegati. In conformità con il GDPR, renderai tutti questi dati anonimi per rispettare i tuoi obblighi. Vuoi continuare?
    +
    +
    +#
    +# Bouton portabilité
    +# 
    +DATAPOLICY_PORTABILITE = Portabilità GDPR
    +DATAPOLICY_PORTABILITE_TITLE = Esporta i dati personali
    +DATAPOLICY_PORTABILITE_CONFIRMATION = Vuoi davvero esportare i dati personali di questo contatto?
    +
    +#
    +# Note ajoutée lors d'une anonymisation
    +#
    +ANONYMISER_AT = Anonimizzato il %s
    +
    +#V2
    +DATAPOLICYReturn=GDPR Validazione
    +DATAPOLICY_date = Data di accordo / disaccordo GDPR
    +DATAPOLICY_send = Data di invio del consenso (e-mail)
    +DATAPOLICYReturn = GDPR ritorno
    +DATAPOLICY_SEND = Inviare GDPR e-mail
    +MailSent=L'email è stata inviata
    +
    +#ERROR
    +ErrorSubjectIsRequired= Errore: L'oggetto della mail è obbligatorio. Inserisci l'oggetto nella configurazione del modulo.
    +=A causa di un problema tecnico, non siamo stati in grado di registrare la tua scelta. Ci scusiamo per questo. Contattaci per inviarci la tua scelta.
    diff --git a/htdocs/datapolicies/lib/datapolicies.lib.php b/htdocs/datapolicy/lib/datapolicy.lib.php
    similarity index 63%
    rename from htdocs/datapolicies/lib/datapolicies.lib.php
    rename to htdocs/datapolicy/lib/datapolicy.lib.php
    index 59366d1f93d..41c92299989 100644
    --- a/htdocs/datapolicies/lib/datapolicies.lib.php
    +++ b/htdocs/datapolicy/lib/datapolicy.lib.php
    @@ -16,9 +16,9 @@
      */
     
     /**
    - * \file    datapolicies/lib/datapolicies.lib.php
    - * \ingroup datapolicies
    - * \brief   Library files with common functions for datapolicies
    + * \file    datapolicy/lib/datapolicy.lib.php
    + * \ingroup datapolicy
    + * \brief   Library files with common functions for datapolicy
      */
     
     /**
    @@ -26,26 +26,29 @@
      *
      * @return array
      */
    -function datapoliciesAdminPrepareHead()
    +function datapolicyAdminPrepareHead()
     {
     	global $langs, $conf;
     
    -	$langs->load("datapolicies@datapolicies");
    +	$langs->load("datapolicy@datapolicy");
     
     	$h = 0;
     	$head = array();
     
    -	$head[$h][0] = dol_buildpath("/datapolicies/admin/setup.php", 1);
    -	$head[$h][1] = $langs->trans("Settings_DATAPOLICIES");
    +	$head[$h][0] = dol_buildpath("/datapolicy/admin/setup.php", 1);
    +	$head[$h][1] = $langs->trans("Deletion");
     	$head[$h][2] = 'settings';
     	$h++;
     
    -	$head[$h][0] = dol_buildpath("/datapolicies/admin/setupmail.php", 1);
    -	$head[$h][1] = $langs->trans("DATAPOLICIESMail");
    -	$head[$h][2] = 'settings';
    -	$h++;
    +	if (! empty($conf->global->DATAPOLICIES_ENABLE_EMAILS))
    +	{
    +		$head[$h][0] = dol_buildpath("/datapolicy/admin/setupmail.php", 1);
    +		$head[$h][1] = $langs->trans("DATAPOLICIESMail");
    +		$head[$h][2] = 'settings';
    +		$h++;
    +	}
     
    -	complete_head_from_modules($conf, $langs, $object, $head, $h, 'datapolicies');
    +	complete_head_from_modules($conf, $langs, $object, $head, $h, 'datapolicy');
     
     	return $head;
     }
    diff --git a/htdocs/datapolicies/mailing.php b/htdocs/datapolicy/mailing.php
    similarity index 81%
    rename from htdocs/datapolicies/mailing.php
    rename to htdocs/datapolicy/mailing.php
    index 08c24d9aceb..d65b2bdced4 100644
    --- a/htdocs/datapolicies/mailing.php
    +++ b/htdocs/datapolicy/mailing.php
    @@ -16,26 +16,26 @@
      */
     
     /**
    - * \file    datapolicies/mailing.php
    - * \ingroup datapolicies
    - * \brief   datapolicies mailing page.
    + * \file    datapolicy/mailing.php
    + * \ingroup datapolicy
    + * \brief   datapolicy mailing page.
      */
     
     require '../../main.inc.php';
     dol_include_once('/contact/class/contact.class.php');
    -dol_include_once('/datapolicies/class/datapolicies.class.php');
    +dol_include_once('/datapolicy/class/datapolicy.class.php');
     
     $idcontact = GETPOST('idc');
     
     if(!empty($idcontact)){
         $contact = new Contact($db);
         $contact->fetch($idcontact);
    -    DataPolicies::sendMailDataPoliciesContact($contact);
    +    DataPolicy::sendMailDataPolicyContact($contact);
     
     
     }else{
     
    -    $contacts = new DataPolicies($db);
    +    $contacts = new DataPolicy($db);
         $contacts->getAllContactNotInformed();
         $contacts->getAllCompaniesNotInformed();
         $contacts->getAllAdherentsNotInformed();
    diff --git a/htdocs/datapolicies/modulebuilder.txt b/htdocs/datapolicy/modulebuilder.txt
    similarity index 100%
    rename from htdocs/datapolicies/modulebuilder.txt
    rename to htdocs/datapolicy/modulebuilder.txt
    diff --git a/htdocs/datapolicies/public/index.php b/htdocs/datapolicy/public/index.php
    similarity index 63%
    rename from htdocs/datapolicies/public/index.php
    rename to htdocs/datapolicy/public/index.php
    index 4dd07f2ea2d..58f7968f05d 100644
    --- a/htdocs/datapolicies/public/index.php
    +++ b/htdocs/datapolicy/public/index.php
    @@ -17,10 +17,11 @@
      */
     
     /**
    - * \file    datapolicies/admin/setup.php
    - * \ingroup datapolicies
    - * \brief   datapolicies setup page.
    + * \file    datapolicy/admin/setup.php
    + * \ingroup datapolicy
    + * \brief   datapolicy setup page.
      */
    +
     if (!defined('NOLOGIN'))
         define("NOLOGIN", 1);   // This means this output page does not require to be logged.
     if (!defined('NOCSRFCHECK'))
    @@ -33,17 +34,18 @@ dol_include_once('/contact/class/contact.class.php');
     dol_include_once('/societe/class/societe.class.php');
     dol_include_once('/adherents/class/adherent.class.php');
     dol_include_once('/user/class/user.class.php');
    -dol_include_once('/datapolicies/class/datapolicies.class.php');
    +dol_include_once('/datapolicy/class/datapolicy.class.php');
    +
    +$idc = GETPOST('c', 'int');
    +$ids = GETPOST('s', 'int');
    +$ida = GETPOST('a', 'int');
    +$action = GETPOST('action', 'alpha');
    +$lang = GETPOST('l', 'alpha');
    +$code = GETPOST('key', 'alpha');
     
    -$idc = GETPOST('c');
    -$ids = GETPOST('s');
    -$ida = GETPOST('a');
    -$action = GETPOST('action');
    -$lang = GETPOST('l');
    -$code = GETPOST('key');
     $acc = "DATAPOLICIESACCEPT_" . $lang;
     $ref = "DATAPOLICIESREFUSE_" . $lang;
    -$langs->load('datapolicies@datapolicies',0,0,$lang);
    +$langs->load('datapolicy@datapolicy',0,0,$lang);
     
     if (empty($action) || (empty($idc) && empty($ids) && empty($ida))) {
         return 0;
    @@ -54,18 +56,18 @@ if (empty($action) || (empty($idc) && empty($ids) && empty($ida))) {
         if ($check != $code) {
             $return = $langs->trans('ErrorEmailDATAPOLICIES');
         } elseif ($action == 1) {
    -        $contact->array_options['options_datapolicies_consentement'] = 1;
    -        $contact->array_options['options_datapolicies_opposition_traitement'] = 0;
    -        $contact->array_options['options_datapolicies_opposition_prospection'] = 0;
    -        $contact->array_options['options_datapolicies_date'] = date('Y-m-d', time());
    +        $contact->array_options['options_datapolicy_consentement'] = 1;
    +        $contact->array_options['options_datapolicy_opposition_traitement'] = 0;
    +        $contact->array_options['options_datapolicy_opposition_prospection'] = 0;
    +        $contact->array_options['options_datapolicy_date'] = date('Y-m-d', time());
     
             $return = $conf->global->$acc;
         } elseif ($action == 2) {
             $contact->no_email = 1;
    -        $contact->array_options['options_datapolicies_consentement'] = 0;
    -        $contact->array_options['options_datapolicies_opposition_traitement'] = 1;
    -        $contact->array_options['options_datapolicies_opposition_prospection'] = 1;
    -        $contact->array_options['options_datapolicies_date'] = date('Y-m-d', time());
    +        $contact->array_options['options_datapolicy_consentement'] = 0;
    +        $contact->array_options['options_datapolicy_opposition_traitement'] = 1;
    +        $contact->array_options['options_datapolicy_opposition_prospection'] = 1;
    +        $contact->array_options['options_datapolicy_date'] = date('Y-m-d', time());
     
             $return = $conf->global->$ref;
         }
    @@ -77,16 +79,16 @@ if (empty($action) || (empty($idc) && empty($ids) && empty($ida))) {
         if ($check != $code) {
             $return = $langs->trans('ErrorEmailDATAPOLICIES');
         } elseif ($action == 1) {
    -        $societe->array_options['options_datapolicies_consentement'] = 1;
    -        $societe->array_options['options_datapolicies_opposition_traitement'] = 0;
    -        $societe->array_options['options_datapolicies_opposition_prospection'] = 0;
    -        $societe->array_options['options_datapolicies_date'] = date('Y-m-d', time());
    +        $societe->array_options['options_datapolicy_consentement'] = 1;
    +        $societe->array_options['options_datapolicy_opposition_traitement'] = 0;
    +        $societe->array_options['options_datapolicy_opposition_prospection'] = 0;
    +        $societe->array_options['options_datapolicy_date'] = date('Y-m-d', time());
             $return = $conf->global->$acc;
         } elseif ($action == 2) {
    -        $societe->array_options['options_datapolicies_consentement'] = 0;
    -        $societe->array_options['options_datapolicies_opposition_traitement'] = 1;
    -        $societe->array_options['options_datapolicies_opposition_prospection'] = 1;
    -        $societe->array_options['options_datapolicies_date'] = date('Y-m-d', time());
    +        $societe->array_options['options_datapolicy_consentement'] = 0;
    +        $societe->array_options['options_datapolicy_opposition_traitement'] = 1;
    +        $societe->array_options['options_datapolicy_opposition_prospection'] = 1;
    +        $societe->array_options['options_datapolicy_date'] = date('Y-m-d', time());
     
             $return = $conf->global->$ref;
         }
    @@ -98,16 +100,16 @@ if (empty($action) || (empty($idc) && empty($ids) && empty($ida))) {
         if ($check != $code) {
             $return = $langs->trans('ErrorEmailDATAPOLICIES');
         } elseif ($action == 1) {
    -        $adherent->array_options['options_datapolicies_consentement'] = 1;
    -        $adherent->array_options['options_datapolicies_opposition_traitement'] = 0;
    -        $adherent->array_options['options_datapolicies_opposition_prospection'] = 0;
    -        //$adherent->array_options['options_datapolicies_date'] = date('Y-m-d', time());
    +        $adherent->array_options['options_datapolicy_consentement'] = 1;
    +        $adherent->array_options['options_datapolicy_opposition_traitement'] = 0;
    +        $adherent->array_options['options_datapolicy_opposition_prospection'] = 0;
    +        //$adherent->array_options['options_datapolicy_date'] = date('Y-m-d', time());
             $return = $conf->global->$acc;
         } elseif ($action == 2) {
    -        $adherent->array_options['options_datapolicies_consentement'] = 0;
    -        $adherent->array_options['options_datapolicies_opposition_traitement'] = 1;
    -        $adherent->array_options['options_datapolicies_opposition_prospection'] = 1;
    -        //$adherent->array_options['options_datapolicies_date'] = date('Y-m-d', time());
    +        $adherent->array_options['options_datapolicy_consentement'] = 0;
    +        $adherent->array_options['options_datapolicy_opposition_traitement'] = 1;
    +        $adherent->array_options['options_datapolicy_opposition_prospection'] = 1;
    +        //$adherent->array_options['options_datapolicy_date'] = date('Y-m-d', time());
     
             $return = $conf->global->$ref;
         }
    diff --git a/htdocs/don/class/don.class.php b/htdocs/don/class/don.class.php
    index 0723ecb659a..6abd093c8c3 100644
    --- a/htdocs/don/class/don.class.php
    +++ b/htdocs/don/class/don.class.php
    @@ -49,7 +49,11 @@ class Don extends CommonObject
     	 */
     	public $fk_element = 'fk_donation';
     
    -	public $ismultientitymanaged = 1;  	// 0=No test on entity, 1=Test with field entity, 2=Test with link by societe
    +	/**
    +	 * 0=No test on entity, 1=Test with field entity, 2=Test with link by societe
    +	 * @var int
    +	 */
    +	public $ismultientitymanaged = 1;
     
         /**
     	 * @var string String with name of icon for myobject. Must be the part after the 'object_' into object_myobject.png
    @@ -59,13 +63,27 @@ class Don extends CommonObject
         public $date;
         public $amount;
         public $societe;
    -    public $address;
    +
    +    /**
    +	 * @var string Address
    +	 */
    +	public $address;
    +
         public $zip;
         public $town;
         public $email;
         public $public;
    +
    +    /**
    +     * @var int ID
    +     */
         public $fk_project;
    +
    +    /**
    +     * @var int ID
    +     */
         public $fk_typepayment;
    +
     	public $num_payment;
     	public $date_valid;
     	public $modepaymentid = 0;
    diff --git a/htdocs/don/class/paymentdonation.class.php b/htdocs/don/class/paymentdonation.class.php
    index 69c6e8b5501..b0e3a80b082 100644
    --- a/htdocs/don/class/paymentdonation.class.php
    +++ b/htdocs/don/class/paymentdonation.class.php
    @@ -49,7 +49,11 @@ class PaymentDonation extends CommonObject
     	 */
     	public $rowid;
     
    +	/**
    +     * @var int ID
    +     */
     	public $fk_donation;
    +
     	public $datec='';
     	public $tms='';
     	public $datep='';
    @@ -57,8 +61,20 @@ class PaymentDonation extends CommonObject
         public $amounts=array();   // Array of amounts
     	public $typepayment;
     	public $num_payment;
    +
    +	/**
    +     * @var int ID
    +     */
     	public $fk_bank;
    +
    +	/**
    +     * @var int ID
    +     */
     	public $fk_user_creat;
    +
    +	/**
    +     * @var int ID
    +     */
     	public $fk_user_modif;
     
     	/**
    diff --git a/htdocs/ecm/class/ecmdirectory.class.php b/htdocs/ecm/class/ecmdirectory.class.php
    index f477e27b37b..9038b74cb2a 100644
    --- a/htdocs/ecm/class/ecmdirectory.class.php
    +++ b/htdocs/ecm/class/ecmdirectory.class.php
    @@ -52,6 +52,9 @@ class EcmDirectory // extends CommonObject
          */
         public $label;
     
    +    /**
    +     * @var int ID
    +     */
     	public $fk_parent;
     
     	/**
    @@ -62,7 +65,15 @@ class EcmDirectory // extends CommonObject
     	public $cachenbofdoc=-1;	// By default cache initialized with value 'not calculated'
     	public $date_c;
     	public $date_m;
    +
    +	/**
    +     * @var int ID
    +     */
     	public $fk_user_m;
    +
    +	/**
    +     * @var int ID
    +     */
     	public $fk_user_c;
     
     	/**
    diff --git a/htdocs/ecm/class/ecmfiles.class.php b/htdocs/ecm/class/ecmfiles.class.php
    index 50dbcb60dc6..42af7f92635 100644
    --- a/htdocs/ecm/class/ecmfiles.class.php
    +++ b/htdocs/ecm/class/ecmfiles.class.php
    @@ -85,8 +85,17 @@ class EcmFiles extends CommonObject
     	public $extraparams;
     	public $date_c = '';
     	public $date_m = '';
    +
    +	/**
    +     * @var int ID
    +     */
     	public $fk_user_c;
    +
    +	/**
    +     * @var int ID
    +     */
     	public $fk_user_m;
    +
     	public $acl;
     	public $src_object_type;
     	public $src_object_id;
    @@ -879,8 +888,17 @@ class EcmfilesLine
     	public $extraparams;
     	public $date_c = '';
     	public $date_m = '';
    +
    +	/**
    +     * @var int ID
    +     */
     	public $fk_user_c;
    +
    +	/**
    +     * @var int ID
    +     */
     	public $fk_user_m;
    +
     	public $acl;
     	public $src_object_type;
     	public $src_object_id;
    diff --git a/htdocs/ecm/index.php b/htdocs/ecm/index.php
    index ae11ebbd479..faac5eba10d 100644
    --- a/htdocs/ecm/index.php
    +++ b/htdocs/ecm/index.php
    @@ -77,6 +77,10 @@ $error=0;
      *	Actions
      */
     
    +// TODO Replace sendit and confirm_deletefile with
    +//$backtopage=$_SERVER["PHP_SELF"].'?file_manager=1&website='.$websitekey.'&pageid='.$pageid;	// used after a confirm_deletefile into actions_linkedfiles.inc.php
    +//include DOL_DOCUMENT_ROOT.'/core/actions_linkedfiles.inc.php';
    +
     // Upload file (code similar but different than actions_linkedfiles.inc.php)
     if (GETPOST("sendit",'none') && ! empty($conf->global->MAIN_UPLOAD_DOC))
     {
    @@ -105,7 +109,8 @@ if (GETPOST("sendit",'none') && ! empty($conf->global->MAIN_UPLOAD_DOC))
     
     	if (! $error)
     	{
    -	    $res = dol_add_file_process($upload_dir, 0, 1, 'userfile', '', '', '', 0);
    +		$generatethumbs = 0;
    +		$res = dol_add_file_process($upload_dir, 0, 1, 'userfile', '', null, '', $generatethumbs);
     	    if ($res > 0)
     	    {
     	       $result=$ecmdir->changeNbOfFiles('+');
    @@ -113,6 +118,33 @@ if (GETPOST("sendit",'none') && ! empty($conf->global->MAIN_UPLOAD_DOC))
     	}
     }
     
    +// Remove file (code similar but different than actions_linkedfiles.inc.php)
    +if ($action == 'confirm_deletefile')
    +{
    +	if (GETPOST('confirm') == 'yes')
    +	{
    +		// GETPOST('urlfile','alpha') is full relative URL from ecm root dir. Contains path of all sections.
    +		//var_dump(GETPOST('urlfile'));exit;
    +
    +		$upload_dir = $conf->ecm->dir_output.($relativepath?'/'.$relativepath:'');
    +		$file = $upload_dir . "/" . GETPOST('urlfile','alpha');
    +
    +		$ret=dol_delete_file($file);	// This include also the delete from file index in database.
    +		if ($ret)
    +		{
    +			setEventMessages($langs->trans("FileWasRemoved", GETPOST('urlfile','alpha')), null, 'mesgs');
    +			$result=$ecmdir->changeNbOfFiles('-');
    +		}
    +		else
    +		{
    +			setEventMessages($langs->trans("ErrorFailToDeleteFile", GETPOST('urlfile','alpha')), null, 'errors');
    +		}
    +
    +		clearstatcache();
    +	}
    +	$action='file_manager';
    +}
    +
     // Add directory
     if ($action == 'add' && $user->rights->ecm->setup)
     {
    @@ -135,33 +167,6 @@ if ($action == 'add' && $user->rights->ecm->setup)
     	clearstatcache();
     }
     
    -// Remove file (code similar but different than actions_linkedfiles.inc.php)
    -if ($action == 'confirm_deletefile')
    -{
    -    if (GETPOST('confirm') == 'yes')
    -    {
    -    	// GETPOST('urlfile','alpha') is full relative URL from ecm root dir. Contains path of all sections.
    -		//var_dump(GETPOST('urlfile'));exit;
    -
    -    	$upload_dir = $conf->ecm->dir_output.($relativepath?'/'.$relativepath:'');
    -    	$file = $upload_dir . "/" . GETPOST('urlfile','alpha');	// Do not use urldecode here ($_GET and $_POST are already decoded by PHP).
    -
    -    	$ret=dol_delete_file($file);	// This include also the delete from file index in database.
    -    	if ($ret)
    -    	{
    -    		setEventMessages($langs->trans("FileWasRemoved", GETPOST('urlfile','alpha')), null, 'mesgs');
    -    		$result=$ecmdir->changeNbOfFiles('-');
    -    	}
    -    	else
    -    	{
    -    		setEventMessages($langs->trans("ErrorFailToDeleteFile", GETPOST('urlfile','alpha')), null, 'errors');
    -    	}
    -
    -    	clearstatcache();
    -    }
    -   	$action='file_manager';
    -}
    -
     // Remove directory
     if ($action == 'confirm_deletesection' && GETPOST('confirm') == 'yes')
     {
    diff --git a/htdocs/ecm/tpl/enablefiletreeajax.tpl.php b/htdocs/ecm/tpl/enablefiletreeajax.tpl.php
    index b7c20e33d2d..5fe466803fb 100644
    --- a/htdocs/ecm/tpl/enablefiletreeajax.tpl.php
    +++ b/htdocs/ecm/tpl/enablefiletreeajax.tpl.php
    @@ -1,5 +1,6 @@
     <?php
    -/* Copyright (C) 2012	Regis Houssin	<regis.houssin@capnetworks.com>
    +/* Copyright (C) 2012	Regis Houssin			<regis.houssin@capnetworks.com>
    + * Copyright (C) 2018	Laurent Destailleur 	<eldy@users.sourceforge.net>
      *
      * This program is free software; you can redistribute it and/or modify
      * it under the terms of the GNU General Public License as published by
    @@ -27,7 +28,7 @@ if (empty($conf) || ! is_object($conf))
     ?>
     
     <!-- BEGIN PHP TEMPLATE ecm/tpl/enablefiletreeajax.tpl.php -->
    -<!-- Doc of fileTree plugin at https://www.abeautifulsite.net/jquery-file-tree:  http://www.abeautifulsite.net/blog/2008/03/jquery-file-tree/ -->
    +<!-- Doc of fileTree plugin at https://www.abeautifulsite.net/jquery-file-tree -->
     
     <script type="text/javascript">
     
    @@ -35,7 +36,9 @@ if (empty($conf) || ! is_object($conf))
     if (empty($module)) $module='ecm';
     $paramwithoutsection=preg_replace('/&?section=(\d+)/', '', $param);
     
    -$openeddir='/';
    +$openeddir='/';		// The root directory shown
    +// $preopened		// The dir to have preopened
    +
     ?>
     
     $(document).ready(function() {
    @@ -43,7 +46,7 @@ $(document).ready(function() {
     	$('#filetree').fileTree({
     		root: '<?php print dol_escape_js($openeddir); ?>',
     		// Ajax called if we click to expand a dir (not a file). Parameter 'dir' is provided as a POST parameter by fileTree code to this following URL.
    -		script: '<?php echo DOL_URL_ROOT.'/core/ajax/ajaxdirtree.php?modulepart='.$module.'&openeddir='.urlencode($openeddir).(empty($paramwithoutsection)?'':$paramwithoutsection); ?>',
    +		script: '<?php echo DOL_URL_ROOT.'/core/ajax/ajaxdirtree.php?modulepart='.$module.(empty($preopened)?'':'&preopened='.urlencode($preopened)).'&openeddir='.urlencode($openeddir).(empty($paramwithoutsection)?'':$paramwithoutsection); ?>',
     		folderEvent: 'click',	// 'dblclick'
     		multiFolder: false  },
     		// Called if we click on a file (not a dir)
    diff --git a/htdocs/expedition/card.php b/htdocs/expedition/card.php
    index cbe6b36ef73..69deecdf4c0 100644
    --- a/htdocs/expedition/card.php
    +++ b/htdocs/expedition/card.php
    @@ -650,7 +650,7 @@ if (empty($reshook))
     						$qty = "qtyl".$detail_batch->fk_expeditiondet.'_'.$detail_batch->id;
     						$batch_id = GETPOST($batch,'int');
     						$batch_qty = GETPOST($qty, 'int');
    -						if (! empty($batch_id) && ($batch_id != $detail_batch->fk_origin_stock || $batch_qty != $detail_batch->dluo_qty))
    +						if (! empty($batch_id) && ($batch_id != $detail_batch->fk_origin_stock || $batch_qty != $detail_batch->qty))
     						{
     							if ($lotStock->fetch($batch_id) > 0 && $line->fetch($detail_batch->fk_expeditiondet) > 0)	// $line is ExpeditionLine
     							{
    @@ -667,7 +667,7 @@ if (empty($reshook))
     								$line->detail_batch->batch = $lotStock->batch;
     								$line->detail_batch->id = $detail_batch->id;
     								$line->detail_batch->entrepot_id = $lotStock->warehouseid;
    -								$line->detail_batch->dluo_qty = $batch_qty;
    +								$line->detail_batch->qty = $batch_qty;
     								if ($line->update($user) < 0) {
     									setEventMessages($line->error, $line->errors, 'errors');
     									$error++;
    @@ -721,7 +721,7 @@ if (empty($reshook))
     									$line->detail_batch->fk_origin_stock = $batch_id;
     									$line->detail_batch->batch = $lotStock->batch;
     									$line->detail_batch->entrepot_id = $lotStock->warehouseid;
    -									$line->detail_batch->dluo_qty = $batch_qty;
    +									$line->detail_batch->qty = $batch_qty;
     									if ($line->update($user) < 0) {
     										setEventMessages($line->error, $line->errors, 'errors');
     										$error++;
    @@ -742,7 +742,7 @@ if (empty($reshook))
     								$line->detail_batch[0]->fk_origin_stock = $batch_id;
     								$line->detail_batch[0]->batch = $lotStock->batch;
     								$line->detail_batch[0]->entrepot_id = $lotStock->warehouseid;
    -								$line->detail_batch[0]->dluo_qty = $batch_qty;
    +								$line->detail_batch[0]->qty = $batch_qty;
     								if ($object->create_line_batch($line, $line->array_options) < 0)
     								{
     									setEventMessages($object->error, $object->errors, 'errors');
    @@ -1307,6 +1307,7 @@ if ($action == 'create')
     					{
     					    // Product need lot
     						print '<td></td><td></td></tr>';	// end line and start a new one for lot/serial
    +						print '<!-- Case product need lot -->';
     
     						$staticwarehouse=new Entrepot($db);
     						if ($warehouse_id > 0) $staticwarehouse->fetch($warehouse_id);
    @@ -1324,7 +1325,7 @@ if ($action == 'create')
     						print '<input name="idl'.$indiceAsked.'" type="hidden" value="'.$line->id.'">';
     						if (is_object($product->stock_warehouse[$warehouse_id]) && count($product->stock_warehouse[$warehouse_id]->detail_batch))
     						{
    -							foreach ($product->stock_warehouse[$warehouse_id]->detail_batch as $dbatch)
    +							foreach ($product->stock_warehouse[$warehouse_id]->detail_batch as $dbatch)	// $dbatch is instance of Productbatch
     							{
     								//var_dump($dbatch);
     								$batchStock = + $dbatch->qty;		// To get a numeric
    @@ -1345,7 +1346,7 @@ if ($action == 'create')
     								$detail.= $langs->trans("Batch").': '.$dbatch->batch;
     								$detail.= ' - '.$langs->trans("SellByDate").': '.dol_print_date($dbatch->sellby,"day");
     								$detail.= ' - '.$langs->trans("EatByDate").': '.dol_print_date($dbatch->eatby,"day");
    -								$detail.= ' - '.$langs->trans("Qty").': '.$dbatch->dluo_qty;
    +								$detail.= ' - '.$langs->trans("Qty").': '.$dbatch->qty;
     								$detail.= '<br>';
     								print $detail;
     
    @@ -1504,11 +1505,11 @@ if ($action == 'create')
     									print '<!-- Show details of lot -->';
     									print '<input name="batchl'.$indiceAsked.'_'.$subj.'" type="hidden" value="'.$dbatch->id.'">';
     
    -									//print $line->fk_product.' - '.$dbatch->batch;
    +									//print '|'.$line->fk_product.'|'.$dbatch->batch.'|<br>';
     									print $langs->trans("Batch").': ';
     									$result = $productlotObject->fetch(0, $line->fk_product, $dbatch->batch);
     									if ($result > 0) print $productlotObject->getNomUrl(1);
    -									else print 'TableLotIncompleteRunRepair';
    +									else print 'TableLotIncompleteRunRepairWithParamStandardEqualConfirmed';
     									print ' ('.$dbatch->qty.')';
     									$quantityToBeDelivered -= $deliverableQty;
     									if ($quantityToBeDelivered < 0)
    @@ -2242,7 +2243,7 @@ else if ($id || $ref)
     					{
     						print '<tr>';
     						// Qty to ship or shipped
    -						print '<td>' . '<input name="qtyl'.$detail_batch->fk_expeditiondet.'_'.$detail_batch->id.'" id="qtyl'.$line_id.'_'.$detail_batch->id.'" type="text" size="4" value="'.$detail_batch->dluo_qty.'">' . '</td>';
    +						print '<td>' . '<input name="qtyl'.$detail_batch->fk_expeditiondet.'_'.$detail_batch->id.'" id="qtyl'.$line_id.'_'.$detail_batch->id.'" type="text" size="4" value="'.$detail_batch->qty.'">' . '</td>';
     						// Batch number managment
     						if ($lines[$i]->entrepot_id == 0)
     						{
    @@ -2354,12 +2355,12 @@ else if ($id || $ref)
     						if ($lines[$i]->product_tobatch)
     						{
     							$detail = '';
    -							foreach ($lines[$i]->detail_batch as $dbatch)
    +							foreach ($lines[$i]->detail_batch as $dbatch)	// $dbatch is instance of ExpeditionLineBatch
     							{
     								$detail.= $langs->trans("Batch").': '.$dbatch->batch;
     								$detail.= ' - '.$langs->trans("SellByDate").': '.dol_print_date($dbatch->sellby,"day");
     								$detail.= ' - '.$langs->trans("EatByDate").': '.dol_print_date($dbatch->eatby,"day");
    -								$detail.= ' - '.$langs->trans("Qty").': '.$dbatch->dluo_qty;
    +								$detail.= ' - '.$langs->trans("Qty").': '.$dbatch->qty;
     								$detail.= '<br>';
     							}
     							print $form->textwithtooltip(img_picto('', 'object_barcode').' '.$langs->trans("DetailBatchNumber"),$detail);
    diff --git a/htdocs/expedition/class/expedition.class.php b/htdocs/expedition/class/expedition.class.php
    index dee8184ee18..77df09ee276 100644
    --- a/htdocs/expedition/class/expedition.class.php
    +++ b/htdocs/expedition/class/expedition.class.php
    @@ -50,6 +50,9 @@ class Expedition extends CommonObject
     	 */
     	public $element="shipping";
     
    +	/**
    +	 * @var int Field with ID of parent key if this field has a parent
    +	 */
     	public $fk_element="fk_expedition";
     
     	/**
    @@ -62,7 +65,11 @@ class Expedition extends CommonObject
     	 */
     	public $table_element_line="expeditiondet";
     
    -	public $ismultientitymanaged = 1;	// 0=No test on entity, 1=Test with field entity, 2=Test with link by societe
    +	/**
    +	 * 0=No test on entity, 1=Test with field entity, 2=Test with link by societe
    +	 * @var int
    +	 */
    +	public $ismultientitymanaged = 1;
     
     	/**
     	 * @var string String with name of icon for myobject. Must be the part after the 'object_' into object_myobject.png
    @@ -451,7 +458,7 @@ class Expedition extends CommonObject
     		{
     			if ($detbatch->entrepot_id)
     			{
    -				$stockLocationQty[$detbatch->entrepot_id] += $detbatch->dluo_qty;
    +				$stockLocationQty[$detbatch->entrepot_id] += $detbatch->qty;
     			}
     		}
     		// create shipment lines
    @@ -974,7 +981,7 @@ class Expedition extends CommonObject
     						$this->error=$linebatch->error;
     						return -1;
     					}
    -					$linebatch->dluo_qty=$value['q'];
    +					$linebatch->qty=$value['q'];
     					$tab[]=$linebatch;
     
     					if ($conf->global->STOCK_MUST_BE_ENOUGH_FOR_SHIPMENT)
    @@ -983,7 +990,7 @@ class Expedition extends CommonObject
     						$prod_batch = new Productbatch($this->db);
     						$prod_batch->fetch($value['id_batch']);
     
    -						if ($prod_batch->qty < $linebatch->dluo_qty)
    +						if ($prod_batch->qty < $linebatch->qty)
     						{
     							$langs->load("errors");
     							$this->errors[]=$langs->trans('ErrorStockIsNotEnoughToAddProductOnShipment', $prod_batch->fk_product);
    @@ -1207,7 +1214,7 @@ class Expedition extends CommonObject
     						// We use warehouse selected for each line
     						foreach($lotArray as $lot)
     						{
    -							$result=$mouvS->reception($user, $obj->fk_product, $obj->fk_entrepot, $lot->dluo_qty, 0, $langs->trans("ShipmentDeletedInDolibarr", $this->ref), $lot->eatby, $lot->sellby, $lot->batch);  // Price is set to 0, because we don't want to see WAP changed
    +							$result=$mouvS->reception($user, $obj->fk_product, $obj->fk_entrepot, $lot->qty, 0, $langs->trans("ShipmentDeletedInDolibarr", $this->ref), $lot->eatby, $lot->sellby, $lot->batch);  // Price is set to 0, because we don't want to see WAP changed
     							if ($result < 0)
     							{
     								$error++;$this->errors=$this->errors + $mouvS->errors;
    @@ -2336,6 +2343,9 @@ class ExpeditionLigne extends CommonObjectLine
     	 */
     	public $table_element='expeditiondet';
     
    +	/**
    +     * @var int ID
    +     */
     	public $fk_origin_line;
     
     	/**
    @@ -2641,7 +2651,7 @@ class ExpeditionLigne extends CommonObjectLine
     					$this->errors[]='ErrorBadParameters';
     					$error++;
     				}
    -				$qty = price2num($this->detail_batch[0]->dluo_qty);
    +				$qty = price2num($this->detail_batch[0]->qty);
     			}
     		}
     		else if (! empty($this->detail_batch))
    @@ -2655,7 +2665,7 @@ class ExpeditionLigne extends CommonObjectLine
     				$this->errors[]='ErrorBadParameters';
     				$error++;
     			}
    -			$qty = price2num($this->detail_batch->dluo_qty);
    +			$qty = price2num($this->detail_batch->qty);
     		}
     
     		// check parameters
    @@ -2693,7 +2703,7 @@ class ExpeditionLigne extends CommonObjectLine
     				{
     					if ($expedition_batch_id != $lot->id)
     					{
    -						$remainingQty += $lot->dluo_qty;
    +						$remainingQty += $lot->qty;
     					}
     				}
     				$qty += $remainingQty;
    @@ -2721,7 +2731,7 @@ class ExpeditionLigne extends CommonObjectLine
     						$error++;
     					}
     				}
    -				if (! $error && $this->detail_batch->dluo_qty > 0)
    +				if (! $error && $this->detail_batch->qty > 0)
     				{
     					// create lot expedition line
     					if (isset($lot->id))
    @@ -2731,7 +2741,7 @@ class ExpeditionLigne extends CommonObjectLine
     						$shipmentLot->eatby = $lot->eatby;
     						$shipmentLot->sellby = $lot->sellby;
     						$shipmentLot->entrepot_id = $this->detail_batch->entrepot_id;
    -						$shipmentLot->dluo_qty = $this->detail_batch->dluo_qty;
    +						$shipmentLot->qty = $this->detail_batch->qty;
     						$shipmentLot->fk_origin_stock = $batch_id;
     						if ($shipmentLot->create($this->id) < 0)
     						{
    diff --git a/htdocs/expedition/class/expeditionbatch.class.php b/htdocs/expedition/class/expeditionbatch.class.php
    index 611a9a750df..850e4c0dda3 100644
    --- a/htdocs/expedition/class/expeditionbatch.class.php
    +++ b/htdocs/expedition/class/expeditionbatch.class.php
    @@ -38,7 +38,8 @@ class ExpeditionLineBatch extends CommonObject
     	var $sellby;
     	var $eatby;
     	var $batch;
    -	var $dluo_qty;
    +	var $qty;
    +	var $dluo_qty; // deprecated, use qty
     	var $entrepot_id;
     	var $fk_origin_stock;
     	var $fk_expeditiondet;
    @@ -61,41 +62,41 @@ class ExpeditionLineBatch extends CommonObject
     	 */
     	function fetchFromStock($id_stockdluo)
     	{
    -        $sql = "SELECT";
    -        $sql.= " pb.batch,";
    -        $sql.= " pl.sellby,";
    -        $sql.= " pl.eatby,";
    -        $sql.= " ps.fk_entrepot";
    +		$sql = "SELECT";
    +		$sql.= " pb.batch,";
    +		$sql.= " pl.sellby,";
    +		$sql.= " pl.eatby,";
    +		$sql.= " ps.fk_entrepot";
     
    -        $sql.= " FROM ".MAIN_DB_PREFIX."product_batch as pb";
    -        $sql.= " JOIN ".MAIN_DB_PREFIX."product_stock as ps on pb.fk_product_stock=ps.rowid";
    -        $sql.= ' LEFT JOIN '.MAIN_DB_PREFIX."product_lot as pl on pl.batch = pb.batch AND pl.fk_product = ps.fk_product";
    -        $sql.= " WHERE pb.rowid = ".(int) $id_stockdluo;
    +		$sql.= " FROM ".MAIN_DB_PREFIX."product_batch as pb";
    +		$sql.= " JOIN ".MAIN_DB_PREFIX."product_stock as ps on pb.fk_product_stock=ps.rowid";
    +		$sql.= ' LEFT JOIN '.MAIN_DB_PREFIX."product_lot as pl on pl.batch = pb.batch AND pl.fk_product = ps.fk_product";
    +		$sql.= " WHERE pb.rowid = ".(int) $id_stockdluo;
     
    -    	dol_syslog(get_class($this)."::fetch", LOG_DEBUG);
    -        $resql=$this->db->query($sql);
    -        if ($resql)
    -        {
    -            if ($this->db->num_rows($resql))
    -            {
    -                $obj = $this->db->fetch_object($resql);
    +		dol_syslog(get_class($this)."::fetch", LOG_DEBUG);
    +		$resql=$this->db->query($sql);
    +		if ($resql)
    +		{
    +			if ($this->db->num_rows($resql))
    +			{
    +				$obj = $this->db->fetch_object($resql);
     
     				$this->sellby = $this->db->jdate($obj->sellby);
     				$this->eatby = $this->db->jdate($obj->eatby);
     				$this->batch = $obj->batch;
     				$this->entrepot_id= $obj->fk_entrepot;
     				$this->fk_origin_stock=(int) $id_stockdluo;
    -            }
    -            $this->db->free($resql);
    +			}
    +			$this->db->free($resql);
     
    -            return 1;
    -        }
    -        else
    -        {
    -      	    $this->error="Error ".$this->db->lasterror();
    -            return -1;
    -        }
    -    }
    +			return 1;
    +		}
    +		else
    +		{
    +			$this->error="Error ".$this->db->lasterror();
    +			return -1;
    +		}
    +	}
     
     	/**
     	 * Create an expeditiondet_batch DB record link to an expedtiondet record
    @@ -121,7 +122,7 @@ class ExpeditionLineBatch extends CommonObject
     		$sql.= " ".(! isset($this->sellby) || dol_strlen($this->sellby)==0?'NULL':("'".$this->db->idate($this->sellby))."'").",";
     		$sql.= " ".(! isset($this->eatby) || dol_strlen($this->eatby)==0?'NULL':("'".$this->db->idate($this->eatby))."'").",";
     		$sql.= " ".(! isset($this->batch)?'NULL':("'".$this->db->escape($this->batch)."'")).",";
    -		$sql.= " ".(! isset($this->dluo_qty)?'NULL':$this->dluo_qty).",";
    +		$sql.= " ".(! isset($this->qty)?((! isset($this->dluo_qty))?'NULL':$this->dluo_qty):$this->qty).","; // dluo_qty deprecated, use qty
     		$sql.= " ".(! isset($this->fk_origin_stock)?'NULL':$this->fk_origin_stock);
     		$sql.= ")";
     
    @@ -221,7 +222,8 @@ class ExpeditionLineBatch extends CommonObject
     				$tmp->id = $obj->rowid;
     				$tmp->fk_origin_stock = $obj->fk_origin_stock;
     				$tmp->fk_expeditiondet = $obj->fk_expeditiondet;
    -				$tmp->dluo_qty = $obj->qty;
    +				$tmp->dluo_qty = $obj->qty; // dluo_qty deprecated, use qty
    +				$tmp->qty = $obj->qty;
     
     				$ret[]=$tmp;
     				$i++;
    diff --git a/htdocs/expensereport/card.php b/htdocs/expensereport/card.php
    index e19c7a841e1..50205fd12d4 100644
    --- a/htdocs/expensereport/card.php
    +++ b/htdocs/expensereport/card.php
    @@ -356,7 +356,10 @@ if (empty($reshook))
         			$filename=array(); $filedir=array(); $mimetype=array();
     
         			// SUBJECT
    -    			$subject = $langs->transnoentities("ExpenseReportWaitingForApproval");
    +    			$societeName = $conf->global->MAIN_INFO_SOCIETE_NOM;
    +    			if (! empty($conf->global->MAIN_APPLICATION_TITLE)) $societeName = $conf->global->MAIN_APPLICATION_TITLE;
    +
    +    			$subject = $societeName." - ".$langs->transnoentities("ExpenseReportWaitingForApproval");
     
         			// CONTENT
         			$link = $urlwithroot.'/expensereport/card.php?id='.$object->id;
    @@ -375,7 +378,7 @@ if (empty($reshook))
         			*/
     
         			// PREPARE SEND
    -    			$mailfile = new CMailFile($subject,$emailTo,$emailFrom,$message,$filedir,$mimetype,$filename);
    +    			$mailfile = new CMailFile($subject, $emailTo, $emailFrom, $message, $filedir, $mimetype, $filename, '', '', 0, -1);
     
         			if ($mailfile)
         			{
    @@ -472,7 +475,10 @@ if (empty($reshook))
         			$filename=array(); $filedir=array(); $mimetype=array();
     
        			    // SUBJECT
    -    			$subject = $langs->transnoentities("ExpenseReportWaitingForReApproval");
    +    			$societeName = $conf->global->MAIN_INFO_SOCIETE_NOM;
    +    			if (! empty($conf->global->MAIN_APPLICATION_TITLE)) $societeName = $conf->global->MAIN_APPLICATION_TITLE;
    +
    +    			$subject = $societeName." - ".$langs->transnoentities("ExpenseReportWaitingForReApproval");
     
         			// CONTENT
         			$link = $urlwithroot.'/expensereport/card.php?id='.$object->id;
    @@ -496,7 +502,7 @@ if (empty($reshook))
     
     
         			// PREPARE SEND
    -    			$mailfile = new CMailFile($subject,$emailTo,$emailFrom,$message,$filedir,$mimetype,$filename);
    +    			$mailfile = new CMailFile($subject, $emailTo, $emailFrom, $message, $filedir, $mimetype, $filename, '', '', 0, -1);
     
         			if ($mailfile)
         			{
    @@ -594,7 +600,10 @@ if (empty($reshook))
         			$filename=array(); $filedir=array(); $mimetype=array();
     
        			    // SUBJECT
    -       			$subject = $langs->transnoentities("ExpenseReportApproved");
    +    			$societeName = $conf->global->MAIN_INFO_SOCIETE_NOM;
    +    			if (! empty($conf->global->MAIN_APPLICATION_TITLE)) $societeName = $conf->global->MAIN_APPLICATION_TITLE;
    +
    +    			$subject = $societeName." - ".$langs->transnoentities("ExpenseReportApproved");
     
            			// CONTENT
            			$link = $urlwithroot.'/expensereport/card.php?id='.$object->id;
    @@ -615,7 +624,7 @@ if (empty($reshook))
         			}
         			*/
     
    -        		$mailfile = new CMailFile($subject,$emailTo,$emailFrom,$message,$filedir,$mimetype,$filename);
    +        		$mailfile = new CMailFile($subject, $emailTo, $emailFrom, $message, $filedir, $mimetype, $filename, '', '', 0, -1);
     
            			if ($mailfile)
            			{
    @@ -713,7 +722,10 @@ if (empty($reshook))
         			$filename=array(); $filedir=array(); $mimetype=array();
     
         		    // SUBJECT
    -       			$subject = $langs->transnoentities("ExpenseReportRefused");
    +    			$societeName = $conf->global->MAIN_INFO_SOCIETE_NOM;
    +    			if (! empty($conf->global->MAIN_APPLICATION_TITLE)) $societeName = $conf->global->MAIN_APPLICATION_TITLE;
    +
    +    			$subject = $societeName." - ".$langs->transnoentities("ExpenseReportRefused");
     
            			// CONTENT
            			$link = $urlwithroot.'/expensereport/card.php?id='.$object->id;
    @@ -735,7 +747,7 @@ if (empty($reshook))
         			*/
     
             		// PREPARE SEND
    -        		$mailfile = new CMailFile($subject,$emailTo,$emailFrom,$message,$filedir,$mimetype,$filename);
    +        		$mailfile = new CMailFile($subject, $emailTo, $emailFrom, $message, $filedir, $mimetype, $filename, '', '', 0, -1);
     
             		if ($mailfile)
             		{
    @@ -788,126 +800,136 @@ if (empty($reshook))
         }
     
         //var_dump($user->id == $object->fk_user_validator);exit;
    -    if ($action == "confirm_cancel" && GETPOST('confirm', 'alpha')=="yes" && GETPOST('detail_cancel', 'alpha') && $id > 0 && $user->rights->expensereport->creer)
    +    if ($action == "confirm_cancel" && GETPOST('confirm', 'alpha')=="yes" && $id > 0 && $user->rights->expensereport->creer)
         {
    -    	$object = new ExpenseReport($db);
    -    	$object->fetch($id);
    -
    -    	if ($user->id == $object->fk_user_valid || $user->id == $object->fk_user_author)
    +    	if (! GETPOST('detail_cancel', 'alpha'))
         	{
    -    		$result = $object->set_cancel($user, GETPOST('detail_cancel', 'alpha'));
    -
    -    		if ($result > 0)
    -    		{
    -    			// Define output language
    -    			if (empty($conf->global->MAIN_DISABLE_PDF_AUTOUPDATE))
    -    			{
    -    				$outputlangs = $langs;
    -    				$newlang = '';
    -    				if ($conf->global->MAIN_MULTILANGS && empty($newlang) && GETPOST('lang_id','aZ09')) $newlang = GETPOST('lang_id','aZ09');
    -    				if ($conf->global->MAIN_MULTILANGS && empty($newlang))	$newlang = $object->thirdparty->default_lang;
    -    				if (! empty($newlang)) {
    -    					$outputlangs = new Translate("", $conf);
    -    					$outputlangs->setDefaultLang($newlang);
    -    				}
    -    				$model=$object->modelpdf;
    -    				$ret = $object->fetch($id); // Reload to get new records
    -
    -    				$object->generateDocument($model, $outputlangs, $hidedetails, $hidedesc, $hideref);
    -    			}
    -    		}
    -
    -    		if ($result > 0)
    -    		{
    -    			// Send mail
    -
    -    			// TO
    -    			$destinataire = new User($db);
    -    			$destinataire->fetch($object->fk_user_author);
    -    			$emailTo = $destinataire->email;
    -
    -    			// FROM
    -    			$expediteur = new User($db);
    -    			$expediteur->fetch($object->fk_user_cancel);
    -    			$emailFrom = $expediteur->email;
    -
    -    			if ($emailFrom && $emailTo)
    -    			{
    -    			    $filename=array(); $filedir=array(); $mimetype=array();
    -
    -    			    // SUBJECT
    -    				$subject = $langs->transnoentities("ExpenseReportCanceled");
    -
    -    				// CONTENT
    -    				$link = $urlwithroot.'/expensereport/card.php?id='.$object->id;
    -    				$message = $langs->transnoentities("ExpenseReportCanceledMessage", $object->ref, $destinataire->getFullName($langs), $expediteur->getFullName($langs), $_POST['detail_cancel'], $link);
    -
    -    				// Rebuilt pdf
    -    				/*
    -    				$object->setDocModel($user,"");
    -    				$resultPDF = expensereport_pdf_create($db,$object,'',"",$langs);
    -
    -    				if($resultPDF
    -    				{
    -    					// ATTACHMENT
    -    					$filename=array(); $filedir=array(); $mimetype=array();
    -    					array_push($filename,dol_sanitizeFileName($object->ref).".pdf");
    -    					array_push($filedir, $conf->expensereport->dir_output."/".dol_sanitizeFileName($object->ref)."/".dol_sanitizeFileName($object->ref).".pdf");
    -    					array_push($mimetype,"application/pdf");
    -    				}
    -    				*/
    -
    -        			// PREPARE SEND
    -        			$mailfile = new CMailFile($subject,$emailTo,$emailFrom,$message,$filedir,$mimetype,$filename);
    -
    -        			if ($mailfile)
    -        			{
    -        				// SEND
    -        				$result=$mailfile->sendfile();
    -        				if ($result)
    -        				{
    -        					$mesg=$langs->trans('MailSuccessfulySent',$mailfile->getValidAddress($emailFrom,2),$mailfile->getValidAddress($emailTo,2));
    -        					setEventMessages($mesg, null, 'mesgs');
    -        					header("Location: ".$_SERVER["PHP_SELF"]."?id=".$id);
    -        					exit;
    -        				}
    -        				else
    -        				{
    -        					$langs->load("other");
    -        					if ($mailfile->error)
    -        					{
    -        						$mesg='';
    -        						$mesg.=$langs->trans('ErrorFailedToSendMail', $emailFrom, $emailTo);
    -        						$mesg.='<br>'.$mailfile->error;
    -        						setEventMessages($mesg, null, 'errors');
    -        					}
    -        					else
    -        					{
    -        						setEventMessages('No mail sent. Feature is disabled by option MAIN_DISABLE_ALL_MAILS', null, 'warnings');
    -        					}
    -        				}
    -        			}
    -        			else
    -        			{
    -        				setEventMessages($mailfile->error,$mailfile->errors,'errors');
    -        				$action='';
    -        			}
    -    			}
    -    			else
    -    			{
    -    			    setEventMessages($langs->trans("NoEmailSentBadSenderOrRecipientEmail"), null, 'warnings');
    -    			    $action='';
    -    			}
    -    		}
    -    		else
    -    		{
    -    			setEventMessages($langs->trans("FailedToSetToCancel"), null, 'warnings');
    -    			$action='';
    -    		}
    +    		setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("Comment")), null, 'errors');
         	}
         	else
         	{
    -    		setEventMessages($object->error, $object->errors, 'errors');
    +	    	$object = new ExpenseReport($db);
    +	    	$object->fetch($id);
    +
    +	    	if ($user->id == $object->fk_user_valid || $user->id == $object->fk_user_author)
    +	    	{
    +	    		$result = $object->set_cancel($user, GETPOST('detail_cancel', 'alpha'));
    +
    +	    		if ($result > 0)
    +	    		{
    +	    			// Define output language
    +	    			if (empty($conf->global->MAIN_DISABLE_PDF_AUTOUPDATE))
    +	    			{
    +	    				$outputlangs = $langs;
    +	    				$newlang = '';
    +	    				if ($conf->global->MAIN_MULTILANGS && empty($newlang) && GETPOST('lang_id','aZ09')) $newlang = GETPOST('lang_id','aZ09');
    +	    				if ($conf->global->MAIN_MULTILANGS && empty($newlang))	$newlang = $object->thirdparty->default_lang;
    +	    				if (! empty($newlang)) {
    +	    					$outputlangs = new Translate("", $conf);
    +	    					$outputlangs->setDefaultLang($newlang);
    +	    				}
    +	    				$model=$object->modelpdf;
    +	    				$ret = $object->fetch($id); // Reload to get new records
    +
    +	    				$object->generateDocument($model, $outputlangs, $hidedetails, $hidedesc, $hideref);
    +	    			}
    +	    		}
    +
    +	    		if ($result > 0)
    +	    		{
    +	    			// Send mail
    +
    +	    			// TO
    +	    			$destinataire = new User($db);
    +	    			$destinataire->fetch($object->fk_user_author);
    +	    			$emailTo = $destinataire->email;
    +
    +	    			// FROM
    +	    			$expediteur = new User($db);
    +	    			$expediteur->fetch($object->fk_user_cancel);
    +	    			$emailFrom = $expediteur->email;
    +
    +	    			if ($emailFrom && $emailTo)
    +	    			{
    +	    			    $filename=array(); $filedir=array(); $mimetype=array();
    +
    +	    			    // SUBJECT
    +	    			    $societeName = $conf->global->MAIN_INFO_SOCIETE_NOM;
    +	    			    if (! empty($conf->global->MAIN_APPLICATION_TITLE)) $societeName = $conf->global->MAIN_APPLICATION_TITLE;
    +
    +	    			    $subject = $societeName." - ".$langs->transnoentities("ExpenseReportCanceled");
    +
    +	    				// CONTENT
    +	    				$link = $urlwithroot.'/expensereport/card.php?id='.$object->id;
    +	    				$message = $langs->transnoentities("ExpenseReportCanceledMessage", $object->ref, $destinataire->getFullName($langs), $expediteur->getFullName($langs), GETPOST('detail_cancel','alpha'), $link);
    +
    +	    				// Rebuilt pdf
    +	    				/*
    +	    				$object->setDocModel($user,"");
    +	    				$resultPDF = expensereport_pdf_create($db,$object,'',"",$langs);
    +
    +	    				if($resultPDF
    +	    				{
    +	    					// ATTACHMENT
    +	    					$filename=array(); $filedir=array(); $mimetype=array();
    +	    					array_push($filename,dol_sanitizeFileName($object->ref).".pdf");
    +	    					array_push($filedir, $conf->expensereport->dir_output."/".dol_sanitizeFileName($object->ref)."/".dol_sanitizeFileName($object->ref).".pdf");
    +	    					array_push($mimetype,"application/pdf");
    +	    				}
    +	    				*/
    +
    +	        			// PREPARE SEND
    +	        			$mailfile = new CMailFile($subject, $emailTo, $emailFrom, $message, $filedir, $mimetype, $filename, '', '', 0, -1);
    +
    +	        			if ($mailfile)
    +	        			{
    +	        				// SEND
    +	        				$result=$mailfile->sendfile();
    +	        				if ($result)
    +	        				{
    +	        					$mesg=$langs->trans('MailSuccessfulySent',$mailfile->getValidAddress($emailFrom,2),$mailfile->getValidAddress($emailTo,2));
    +	        					setEventMessages($mesg, null, 'mesgs');
    +	        					header("Location: ".$_SERVER["PHP_SELF"]."?id=".$id);
    +	        					exit;
    +	        				}
    +	        				else
    +	        				{
    +	        					$langs->load("other");
    +	        					if ($mailfile->error)
    +	        					{
    +	        						$mesg='';
    +	        						$mesg.=$langs->trans('ErrorFailedToSendMail', $emailFrom, $emailTo);
    +	        						$mesg.='<br>'.$mailfile->error;
    +	        						setEventMessages($mesg, null, 'errors');
    +	        					}
    +	        					else
    +	        					{
    +	        						setEventMessages('No mail sent. Feature is disabled by option MAIN_DISABLE_ALL_MAILS', null, 'warnings');
    +	        					}
    +	        				}
    +	        			}
    +	        			else
    +	        			{
    +	        				setEventMessages($mailfile->error,$mailfile->errors,'errors');
    +	        				$action='';
    +	        			}
    +	    			}
    +	    			else
    +	    			{
    +	    			    setEventMessages($langs->trans("NoEmailSentBadSenderOrRecipientEmail"), null, 'warnings');
    +	    			    $action='';
    +	    			}
    +	    		}
    +	    		else
    +	    		{
    +	    			setEventMessages($langs->trans("FailedToSetToCancel"), null, 'warnings');
    +	    			$action='';
    +	    		}
    +	    	}
    +	    	else
    +	    	{
    +	    		setEventMessages($object->error, $object->errors, 'errors');
    +	    	}
         	}
         }
     
    @@ -1001,25 +1023,21 @@ if (empty($reshook))
         			$filename=array(); $filedir=array(); $mimetype=array();
     
         		    // SUBJECT
    -    			$subject = $langs->transnoentities("ExpenseReportPaid");
    +    			$societeName = $conf->global->MAIN_INFO_SOCIETE_NOM;
    +    			if (! empty($conf->global->MAIN_APPLICATION_TITLE)) $societeName = $conf->global->MAIN_APPLICATION_TITLE;
    +
    +    			$subject = $societeName." - ".$langs->transnoentities("ExpenseReportPaid");
     
         			// CONTENT
         			$link = $urlwithroot.'/expensereport/card.php?id='.$object->id;
         			$message = $langs->transnoentities("ExpenseReportPaidMessage", $object->ref, $destinataire->getFullName($langs), $expediteur->getFullName($langs), $link);
     
    -        		// CONTENT
    -        		$message = "Bonjour {$destinataire->firstname},\n\n";
    -        		$message.= "Votre note de frais \"{$object->ref}\" vient d'être payée.\n";
    -        		$message.= "- Payeur : {$expediteur->firstname} {$expediteur->lastname}\n";
    -        		$message.= "- Lien : {$dolibarr_main_url_root}/expensereport/card.php?id={$object->id}\n\n";
    -        		$message.= "Bien cordialement,\n' SI";
    -
             		// Generate pdf before attachment
             		$object->setDocModel($user,"");
             		$resultPDF = expensereport_pdf_create($db,$object,'',"",$langs);
     
             		// PREPARE SEND
    -        		$mailfile = new CMailFile($subject,$emailTo,$emailFrom,$message,$filedir,$mimetype,$filename);
    +        		$mailfile = new CMailFile($subject, $emailTo, $emailFrom, $message, $filedir, $mimetype, $filename, '', '', 0, -1);
     
             		if ($mailfile)
             		{
    @@ -1589,49 +1607,49 @@ else
     
     				if ($action == 'save')
     				{
    -					$formconfirm=$form->form_confirm($_SERVER["PHP_SELF"]."?id=".$id,$langs->trans("SaveTrip"),$langs->trans("ConfirmSaveTrip"),"confirm_validate","","",1);
    +					$formconfirm=$form->formconfirm($_SERVER["PHP_SELF"]."?id=".$id,$langs->trans("SaveTrip"),$langs->trans("ConfirmSaveTrip"),"confirm_validate","","",1);
     				}
     
     				if ($action == 'save_from_refuse')
     				{
    -					$formconfirm=$form->form_confirm($_SERVER["PHP_SELF"]."?id=".$id,$langs->trans("SaveTrip"),$langs->trans("ConfirmSaveTrip"),"confirm_save_from_refuse","","",1);
    +					$formconfirm=$form->formconfirm($_SERVER["PHP_SELF"]."?id=".$id,$langs->trans("SaveTrip"),$langs->trans("ConfirmSaveTrip"),"confirm_save_from_refuse","","",1);
     				}
     
     				if ($action == 'delete')
     				{
    -					$formconfirm=$form->form_confirm($_SERVER["PHP_SELF"]."?id=".$id,$langs->trans("DeleteTrip"),$langs->trans("ConfirmDeleteTrip"),"confirm_delete","","",1);
    +					$formconfirm=$form->formconfirm($_SERVER["PHP_SELF"]."?id=".$id,$langs->trans("DeleteTrip"),$langs->trans("ConfirmDeleteTrip"),"confirm_delete","","",1);
     				}
     
     				if ($action == 'validate')
     				{
    -					$formconfirm=$form->form_confirm($_SERVER["PHP_SELF"]."?id=".$id,$langs->trans("ValideTrip"),$langs->trans("ConfirmValideTrip"),"confirm_approve","","",1);
    +					$formconfirm=$form->formconfirm($_SERVER["PHP_SELF"]."?id=".$id,$langs->trans("ValideTrip"),$langs->trans("ConfirmValideTrip"),"confirm_approve","","",1);
     				}
     
     				if ($action == 'paid')
     				{
    -					$formconfirm=$form->form_confirm($_SERVER["PHP_SELF"]."?id=".$id,$langs->trans("PaidTrip"),$langs->trans("ConfirmPaidTrip"),"confirm_paid","","",1);
    +					$formconfirm=$form->formconfirm($_SERVER["PHP_SELF"]."?id=".$id,$langs->trans("PaidTrip"),$langs->trans("ConfirmPaidTrip"),"confirm_paid","","",1);
     				}
     
     				if ($action == 'cancel')
     				{
    -					$array_input = array('text'=>$langs->trans("ConfirmCancelTrip"), array('type'=>"text",'label'=>$langs->trans("Comment"),'name'=>"detail_cancel",'size'=>"50",'value'=>""));
    -					$formconfirm=$form->form_confirm($_SEVER["PHP_SELF"]."?id=".$id,$langs->trans("Cancel"),"","confirm_cancel",$array_input,"",1);
    +					$array_input = array('text'=>$langs->trans("ConfirmCancelTrip"), array('type'=>"text",'label'=>'<strong>'.$langs->trans("Comment").'</strong>','name'=>"detail_cancel",'size'=>"50",'value'=>""));
    +					$formconfirm=$form->formconfirm($_SEVER["PHP_SELF"]."?id=".$id,$langs->trans("Cancel"),"","confirm_cancel",$array_input,"",1);
     				}
     
     				if ($action == 'brouillonner')
     				{
    -				    $formconfirm=$form->form_confirm($_SERVER["PHP_SELF"]."?id=".$id,$langs->trans("BrouillonnerTrip"),$langs->trans("ConfirmBrouillonnerTrip"),"confirm_brouillonner","","",1);
    +				    $formconfirm=$form->formconfirm($_SERVER["PHP_SELF"]."?id=".$id,$langs->trans("BrouillonnerTrip"),$langs->trans("ConfirmBrouillonnerTrip"),"confirm_brouillonner","","",1);
     				}
     
     				if ($action == 'refuse')		// Deny
     				{
     					$array_input = array('text'=>$langs->trans("ConfirmRefuseTrip"), array('type'=>"text",'label'=>$langs->trans("Comment"),'name'=>"detail_refuse",'size'=>"50",'value'=>""));
    -					$formconfirm=$form->form_confirm($_SERVER["PHP_SELF"]."?id=".$id,$langs->trans("Deny"),'',"confirm_refuse",$array_input,"yes",1);
    +					$formconfirm=$form->formconfirm($_SERVER["PHP_SELF"]."?id=".$id,$langs->trans("Deny"),'',"confirm_refuse",$array_input,"yes",1);
     				}
     
     				if ($action == 'delete_line')
     				{
    -					$formconfirm=$form->form_confirm($_SERVER["PHP_SELF"]."?id=".$id."&rowid=".GETPOST('rowid','int'),$langs->trans("DeleteLine"),$langs->trans("ConfirmDeleteLine"),"confirm_delete_line",'','yes',1);
    +					$formconfirm=$form->formconfirm($_SERVER["PHP_SELF"]."?id=".$id."&rowid=".GETPOST('rowid','int'),$langs->trans("DeleteLine"),$langs->trans("ConfirmDeleteLine"),"confirm_delete_line",'','yes',1);
     				}
     
     				// Print form confirm
    diff --git a/htdocs/expensereport/class/expensereport.class.php b/htdocs/expensereport/class/expensereport.class.php
    index f5d2a4145e2..6cc7b13ee7c 100644
    --- a/htdocs/expensereport/class/expensereport.class.php
    +++ b/htdocs/expensereport/class/expensereport.class.php
    @@ -2416,22 +2416,41 @@ class ExpenseReportLine
     	 */
     	public $error='';
     
    -    var $rowid;
    -    var $comments;
    -    var $qty;
    -    var $value_unit;
    -    var $date;
    +    /**
    +	 * @var int ID
    +	 */
    +	public $rowid;
     
    -    var $fk_c_type_fees;
    -    var $fk_c_exp_tax_cat;
    -    var $fk_projet;
    -    var $fk_expensereport;
    +    public $comments;
    +    public $qty;
    +    public $value_unit;
    +    public $date;
     
    -    var $type_fees_code;
    -    var $type_fees_libelle;
    +    /**
    +     * @var int ID
    +     */
    +    public $fk_c_type_fees;
     
    -    var $projet_ref;
    -    var $projet_title;
    +    /**
    +     * @var int ID
    +     */
    +    public $fk_c_exp_tax_cat;
    +
    +    /**
    +     * @var int ID
    +     */
    +    public $fk_projet;
    +
    +    /**
    +     * @var int ID
    +     */
    +    public $fk_expensereport;
    +
    +    public $type_fees_code;
    +    public $type_fees_libelle;
    +
    +    public $projet_ref;
    +    public $projet_title;
     
         var $vatrate;
         var $total_ht;
    diff --git a/htdocs/expensereport/class/expensereport_ik.class.php b/htdocs/expensereport/class/expensereport_ik.class.php
    index 425851cb6e4..9eaa8970a5b 100644
    --- a/htdocs/expensereport/class/expensereport_ik.class.php
    +++ b/htdocs/expensereport/class/expensereport_ik.class.php
    @@ -39,6 +39,9 @@ class ExpenseReportIk extends CoreObject
     	 */
     	public $table_element='expensereport_ik';
     
    +	/**
    +	 * @var int Field with ID of parent key if this field has a parent
    +	 */
     	public $fk_element='fk_expense_ik';
     
     	/**
    diff --git a/htdocs/expensereport/class/expensereport_rule.class.php b/htdocs/expensereport/class/expensereport_rule.class.php
    index 8599cfcc810..6d2a99d2101 100644
    --- a/htdocs/expensereport/class/expensereport_rule.class.php
    +++ b/htdocs/expensereport/class/expensereport_rule.class.php
    @@ -33,12 +33,15 @@ class ExpenseReportRule extends CoreObject
     	 * @var string ID to identify managed object
     	 */
     	public $element='expenserule';
    -	
    +
     	/**
     	 * @var string Name of table without prefix where object is stored
     	 */
     	public $table_element='expensereport_rules';
    -	
    +
    +	/**
    +	 * @var int Field with ID of parent key if this field has a parent
    +	 */
     	public $fk_element='fk_expense_rule';
     
     	/**
    diff --git a/htdocs/expensereport/class/paymentexpensereport.class.php b/htdocs/expensereport/class/paymentexpensereport.class.php
    index f2275676049..35f1fef7b5b 100644
    --- a/htdocs/expensereport/class/paymentexpensereport.class.php
    +++ b/htdocs/expensereport/class/paymentexpensereport.class.php
    @@ -45,19 +45,44 @@ class PaymentExpenseReport extends CommonObject
     	 */
     	public $picto = 'payment';
     
    +	/**
    +	 * @var int ID
    +	 */
     	public $rowid;
     
    +	/**
    +     * @var int ID
    +     */
     	public $fk_expensereport;
    +
     	public $datec='';
     	public $tms='';
     	public $datep='';
         public $amount;            // Total amount of payment
         public $amounts=array();   // Array of amounts
    +
    +    /**
    +     * @var int ID
    +     */
     	public $fk_typepayment;
    +
     	public $num_payment;
    +
    +	/**
    +     * @var int ID
    +     */
     	public $fk_bank;
    +
    +	/**
    +     * @var int ID
    +     */
     	public $fk_user_creat;
    +
    +	/**
    +     * @var int ID
    +     */
     	public $fk_user_modif;
    +
         //Unknow field
         public $chid;
         public $total;
    diff --git a/htdocs/expensereport/payment/card.php b/htdocs/expensereport/payment/card.php
    index 2c053d5cc35..88272072ada 100644
    --- a/htdocs/expensereport/payment/card.php
    +++ b/htdocs/expensereport/payment/card.php
    @@ -42,6 +42,13 @@ if ($user->societe_id) $socid=$user->societe_id;
     
     $object = new PaymentExpenseReport($db);
     
    +if ($id > 0)
    +{
    +	$result=$object->fetch($id);
    +	if (! $result) dol_print_error($db,'Failed to get payment id '.$id);
    +}
    +
    +
     /*
      * Actions
      */
    @@ -77,10 +84,10 @@ if ($action == 'confirm_valide' && $confirm == 'yes' && $user->rights->expensere
     		$db->commit();
     
     		$factures=array();	// TODO Get all id of invoices linked to this payment
    -		foreach($factures as $id)
    +		foreach($factures as $invoiceid)
     		{
     			$fac = new Facture($db);
    -			$fac->fetch($id);
    +			$fac->fetch($invoiceid);
     
     			$outputlangs = $langs;
     			if (! empty($_REQUEST['lang_id']))
    @@ -110,12 +117,6 @@ if ($action == 'confirm_valide' && $confirm == 'yes' && $user->rights->expensere
     
     llxHeader('', $langs->trans("ExpenseReportPayment"));
     
    -if ($id > 0)
    -{
    -	$result=$object->fetch($id);
    -	if (! $result) dol_print_error($db,'Failed to get payment id '.$id);
    -}
    -
     $form = new Form($db);
     
     $head = payment_expensereport_prepare_head($object);
    @@ -265,9 +266,11 @@ if ($resql)
     			print '<td align="center">'.$expensereport->getLibStatut(4,$objp->amount).'</td>';
     
     			print "</tr>\n";
    +
     			if ($objp->paid == 1)	// If at least one invoice is paid, disable delete
     			{
    -				$disable_delete = 1;
    +				$disable_delete = 2;
    +				$title_button = $langs->trans("CantRemovePaymentWithOneInvoicePaid");
     			}
     			$total = $total + $objp->amount;
     			$i++;
    @@ -303,7 +306,7 @@ if ($action == '')
     		}
     		else
     		{
    -			print '<a class="butActionRefused" href="#" title="'.dol_escape_htmltag($langs->trans("CantRemovePaymentWithOneInvoicePaid")).'">'.$langs->trans('Delete').'</a>';
    +			print '<a class="butActionRefused" href="#" title="'.dol_escape_htmltag($title_button).'">'.$langs->trans('Delete').'</a>';
     		}
     	}
     }
    diff --git a/htdocs/fichinter/card-rec.php b/htdocs/fichinter/card-rec.php
    index 8ef79639e05..66f693858c9 100644
    --- a/htdocs/fichinter/card-rec.php
    +++ b/htdocs/fichinter/card-rec.php
    @@ -60,7 +60,7 @@ $result = restrictedArea($user, 'ficheinter', $id, $objecttype);
     if ($page == -1)
     	$page = 0 ;
     
    -$limit = GETPOST('limit')?GETPOST('limit', 'int'):$conf->liste_limit;
    +$limit = GETPOST('limit', 'int')?GETPOST('limit', 'int'):$conf->liste_limit;
     $offset = $limit * $page ;
     
     if ($sortorder == "")
    diff --git a/htdocs/fichinter/class/fichinter.class.php b/htdocs/fichinter/class/fichinter.class.php
    index 48cbdbf7715..d8be14c298a 100644
    --- a/htdocs/fichinter/class/fichinter.class.php
    +++ b/htdocs/fichinter/class/fichinter.class.php
    @@ -82,8 +82,16 @@ class Fichinter extends CommonObject
     	 */
     	public $description;
     
    +	/**
    +     * @var int ID
    +     */
     	public $fk_contrat = 0;
    +
    +	/**
    +     * @var int ID
    +     */
     	public $fk_project = 0;
    +
     	public $extraparams=array();
     
     	public $lines = array();
    @@ -1360,7 +1368,11 @@ class FichinterLigne extends CommonObjectLine
     	public $error='';
     
     	// From llx_fichinterdet
    +	/**
    +     * @var int ID
    +     */
     	public $fk_fichinter;
    +
     	public $desc;          	// Description ligne
     	public $datei;           // Date intervention
     	public $duration;        // Duree de l'intervention
    diff --git a/htdocs/filefunc.inc.php b/htdocs/filefunc.inc.php
    index 18c5dd4962a..f886266a701 100644
    --- a/htdocs/filefunc.inc.php
    +++ b/htdocs/filefunc.inc.php
    @@ -31,7 +31,7 @@
      */
     
     if (! defined('DOL_APPLICATION_TITLE')) define('DOL_APPLICATION_TITLE','Dolibarr');
    -if (! defined('DOL_VERSION')) define('DOL_VERSION','9.0.0-alpha');		// a.b.c-alpha, a.b.c-beta, a.b.c-rcX or a.b.c
    +if (! defined('DOL_VERSION')) define('DOL_VERSION','9.0.0-beta');		// a.b.c-alpha, a.b.c-beta, a.b.c-rcX or a.b.c
     
     if (! defined('EURO')) define('EURO',chr(128));
     
    diff --git a/htdocs/fourn/class/fournisseur.commande.class.php b/htdocs/fourn/class/fournisseur.commande.class.php
    index b52fd4a4a58..ce9665cc6c8 100644
    --- a/htdocs/fourn/class/fournisseur.commande.class.php
    +++ b/htdocs/fourn/class/fournisseur.commande.class.php
    @@ -128,10 +128,20 @@ class CommandeFournisseur extends CommonOrder
     	public $note_private;
         public $note_public;
         public $model_pdf;
    +
    +    /**
    +     * @var int ID
    +     */
         public $fk_project;
    +
         public $cond_reglement_id;
         public $cond_reglement_code;
    +
    +    /**
    +     * @var int ID
    +     */
         public $fk_account;
    +
         public $mode_reglement_id;
         public $mode_reglement_code;
         public $user_author_id;
    @@ -157,7 +167,11 @@ class CommandeFournisseur extends CommonOrder
         public $linked_objects=array();
     
     	// Multicurrency
    +	/**
    +     * @var int ID
    +     */
         public $fk_multicurrency;
    +
         public $multicurrency_code;
         public $multicurrency_tx;
         public $multicurrency_total_ht;
    @@ -3154,7 +3168,14 @@ class CommandeFournisseurLigne extends CommonOrderLine
         public $fk_commande;
     
         // From llx_commande_fournisseurdet
    +    /**
    +     * @var int ID
    +     */
         public $fk_parent_line;
    +
    +    /**
    +     * @var int ID
    +     */
         public $fk_facture;
     
         /**
    diff --git a/htdocs/fourn/class/fournisseur.commande.dispatch.class.php b/htdocs/fourn/class/fournisseur.commande.dispatch.class.php
    index 309c5f2deff..2bcdce36b3c 100644
    --- a/htdocs/fourn/class/fournisseur.commande.dispatch.class.php
    +++ b/htdocs/fourn/class/fournisseur.commande.dispatch.class.php
    @@ -65,10 +65,26 @@ class CommandeFournisseurDispatch extends CommonObject
     	 */
     	public $id;
     
    +	/**
    +     * @var int ID
    +     */
     	public $fk_commande;
    +
    +	/**
    +     * @var int ID
    +     */
     	public $fk_product;
    +
    +	/**
    +     * @var int ID
    +     */
     	public $fk_commandefourndet;
    +
     	public $qty;
    +
    +	/**
    +     * @var int ID
    +     */
     	public $fk_entrepot;
     
     	/**
    @@ -78,7 +94,12 @@ class CommandeFournisseurDispatch extends CommonObject
     
     	public $datec='';
     	public $comment;
    +
    +	/**
    +	 * @var int Status
    +	 */
     	public $status;
    +
     	public $tms='';
     	public $batch;
     	public $eatby='';
    diff --git a/htdocs/fourn/class/fournisseur.facture.class.php b/htdocs/fourn/class/fournisseur.facture.class.php
    index e3943ed7415..f4c37a1113c 100644
    --- a/htdocs/fourn/class/fournisseur.facture.class.php
    +++ b/htdocs/fourn/class/fournisseur.facture.class.php
    @@ -138,7 +138,12 @@ class FactureFournisseur extends CommonInvoice
         public $propalid;
         public $cond_reglement_id;
         public $cond_reglement_code;
    +
    +    /**
    +     * @var int ID
    +     */
         public $fk_account;
    +
         public $mode_reglement_id;
         public $mode_reglement_code;
     
    @@ -153,21 +158,31 @@ class FactureFournisseur extends CommonInvoice
     	 */
         public $fournisseur;
     
    -	//Incorterms
    +	/**
    +     * @var int ID Incorterms
    +     */
         public $fk_incoterms;
    +
         public $location_incoterms;
         public $libelle_incoterms;  //Used into tooltip
     
         public $extraparams=array();
     
     	// Multicurrency
    +	/**
    +     * @var int ID
    +     */
         public $fk_multicurrency;
    +
         public $multicurrency_code;
         public $multicurrency_tx;
         public $multicurrency_total_ht;
         public $multicurrency_total_tva;
         public $multicurrency_total_ttc;
         //! id of source invoice if replacement invoice or credit note
    +    /**
    +     * @var int ID
    +     */
         public $fk_facture_source;
     
         /**
    @@ -2722,18 +2737,32 @@ class SupplierInvoiceLine extends CommonObjectLine
     	public $total_ttc;
     	public $total_localtax1;
     	public $total_localtax2;
    +
    +	/**
    +     * @var int ID
    +     */
     	public $fk_product;
    +
     	public $product_type;
     	public $product_label;
     	public $info_bits;
    +
    +	/**
    +     * @var int ID
    +     */
     	public $fk_parent_line;
    +
     	public $special_code;
     	public $rang;
     	public $localtax1_type;
     	public $localtax2_type;
     
     	// Multicurrency
    +	/**
    +     * @var int ID
    +     */
     	public $fk_multicurrency;
    +
     	public $multicurrency_code;
     	public $multicurrency_subprice;
     	public $multicurrency_total_ht;
    diff --git a/htdocs/fourn/class/fournisseur.product.class.php b/htdocs/fourn/class/fournisseur.product.class.php
    index f97a6c4f4ba..a86e728e028 100644
    --- a/htdocs/fourn/class/fournisseur.product.class.php
    +++ b/htdocs/fourn/class/fournisseur.product.class.php
    @@ -72,12 +72,21 @@ class ProductFournisseur extends Product
         public $fourn_remise_percent;    // discount for quantity (percent)
         public $fourn_remise;            // discount for quantity (amount)
         public $product_fourn_id;        // supplier id
    -    public $fk_availability;         // availability delay - visible/used if option FOURN_PRODUCT_AVAILABILITY is on (duplicate information compared to delivery delay)
    +
    +    /**
    +     * @var int ID availability delay - visible/used if option FOURN_PRODUCT_AVAILABILITY is on (duplicate information compared to delivery delay)
    +     */
    +    public $fk_availability;
    +
         public $fourn_unitprice;
         public $fourn_tva_tx;
         public $fourn_tva_npr;
     
    +    /**
    +     * @var int ID
    +     */
         public $fk_supplier_price_expression;
    +
         public $supplier_reputation;     // reputation of supplier
         public $reputations=array();     // list of available supplier reputations
     
    diff --git a/htdocs/fourn/commande/dispatch.php b/htdocs/fourn/commande/dispatch.php
    index 44b10bf6f88..7f2e5ba4139 100644
    --- a/htdocs/fourn/commande/dispatch.php
    +++ b/htdocs/fourn/commande/dispatch.php
    @@ -533,7 +533,6 @@ if ($id > 0 || ! empty($ref)) {
     			$nbproduct = 0;			// Nb of predefined product lines to dispatch (already done or not) if SUPPLIER_ORDER_DISABLE_STOCK_DISPATCH_WHEN_TOTAL_REACHED is off (default)
     									// or nb of line that remain to dispatch if SUPPLIER_ORDER_DISABLE_STOCK_DISPATCH_WHEN_TOTAL_REACHED is on.
     
    -			$var = false;
     			while ( $i < $num ) {
     				$objp = $db->fetch_object($resql);
     
    @@ -794,8 +793,6 @@ if ($id > 0 || ! empty($ref)) {
     			print '<td>' . $langs->trans("Date") . '</td>';
     			print "</tr>\n";
     
    -			$var = false;
    -
     			while ( $i < $num ) {
     				$objp = $db->fetch_object($resql);
     
    @@ -869,7 +866,6 @@ if ($id > 0 || ! empty($ref)) {
     				print "</tr>\n";
     
     				$i ++;
    -				$var = ! $var;
     			}
     			$db->free($resql);
     
    diff --git a/htdocs/fourn/facture/paiement.php b/htdocs/fourn/facture/paiement.php
    index fdd358933d9..7946f98cb66 100644
    --- a/htdocs/fourn/facture/paiement.php
    +++ b/htdocs/fourn/facture/paiement.php
    @@ -473,14 +473,14 @@ if ($action == 'create' || $action == 'confirm_paiement' || $action == 'add_paie
     	             * Autres factures impayees
     	             */
     	            $sql = 'SELECT f.rowid as facid, f.ref, f.ref_supplier, f.total_ht, f.total_ttc, f.multicurrency_total_ttc, f.datef as df,';
    -	            $sql.= ' SUM(pf.amount) as am, SUM(pf.multicurrency_amount) as multicurrency_am';
    +	            $sql.= ' SUM(pf.amount) as am, SUM(pf.multicurrency_amount) as multicurrency_am, f.date_lim_reglement as dlr';
     	            $sql.= ' FROM '.MAIN_DB_PREFIX.'facture_fourn as f';
     	            $sql.= ' LEFT JOIN '.MAIN_DB_PREFIX.'paiementfourn_facturefourn as pf ON pf.fk_facturefourn = f.rowid';
     	            $sql.= " WHERE f.entity = ".$conf->entity;
     	            $sql.= ' AND f.fk_soc = '.$object->socid;
     	            $sql.= ' AND f.paye = 0';
     	            $sql.= ' AND f.fk_statut = 1';  // Statut=0 => non validee, Statut=2 => annulee
    -	            $sql.= ' GROUP BY f.rowid, f.ref, f.ref_supplier, f.total_ht, f.total_ttc, f.multicurrency_total_ttc, f.datef';
    +	            $sql.= ' GROUP BY f.rowid, f.ref, f.ref_supplier, f.total_ht, f.total_ttc, f.multicurrency_total_ttc, f.datef, f.date_lim_reglement';
     	            $resql = $db->query($sql);
     	            if ($resql)
     	            {
    @@ -511,6 +511,7 @@ if ($action == 'create' || $action == 'confirm_paiement' || $action == 'add_paie
     	                    print '<td>'.$langs->trans('Invoice').'</td>';
     	                    print '<td>'.$langs->trans('RefSupplier').'</td>';
     	                    print '<td align="center">'.$langs->trans('Date').'</td>';
    +	                    print '<td align="center">'.$langs->trans('DateMaxPayment').'</td>';
     	                    if (!empty($conf->multicurrency->enabled)) print '<td>'.$langs->trans('Currency').'</td>';
     						if (!empty($conf->multicurrency->enabled)) print '<td align="right">'.$langs->trans('MulticurrencyAmountTTC').'</td>';
     						if (!empty($conf->multicurrency->enabled)) print '<td align="right">'.$langs->trans('MulticurrencyAlreadyPaid').'</td>';
    @@ -569,7 +570,25 @@ if ($action == 'create' || $action == 'confirm_paiement' || $action == 'add_paie
     	                        {
     	                            print '<td align="center"><b>!!!</b></td>';
     	                        }
    -
    +	                        
    +	                        // Date Max Payment
    +	                        if ($objp->dlr > 0 )
    +	                        {
    +	                            print '<td align="center">';
    +	                            print dol_print_date($db->jdate($objp->dlr), 'day');
    +	                            
    +	                            if ($invoice->hasDelay())
    +	                            {
    +	                                print img_warning($langs->trans('Late'));
    +	                            }
    +	                            
    +	                            print '</td>';
    +	                        }
    +	                        else
    +	                        {
    +	                            print '<td align="center"><b>--</b></td>';
    +	                        }
    +	                        
     	                        // Multicurrency
     	                        if (!empty($conf->multicurrency->enabled))
     	                        {
    @@ -661,7 +680,7 @@ if ($action == 'create' || $action == 'confirm_paiement' || $action == 'add_paie
     	                    {
     	                        // Print total
     	                        print '<tr class="liste_total">';
    -	                        print '<td colspan="3" align="left">'.$langs->trans('TotalTTC').':</td>';
    +	                        print '<td colspan="4" align="left">'.$langs->trans('TotalTTC').':</td>';
     							if (!empty($conf->multicurrency->enabled)) print '<td>&nbsp;</td>';
     							if (!empty($conf->multicurrency->enabled)) print '<td>&nbsp;</td>';
     							if (!empty($conf->multicurrency->enabled)) print '<td>&nbsp;</td>';
    diff --git a/htdocs/holiday/card.php b/htdocs/holiday/card.php
    index be365c52351..9c89124c577 100644
    --- a/htdocs/holiday/card.php
    +++ b/htdocs/holiday/card.php
    @@ -214,7 +214,7 @@ if ($action == 'update')
         $object->fetch($id);
     
     	// If under validation
    -    if ($object->statut == 1)
    +    if ($object->statut == Holiday::STATUS_DRAFT)
         {
             // If this is the requestor or has read/write rights
             if ($cancreate)
    @@ -298,7 +298,7 @@ if ($action == 'confirm_delete' && GETPOST('confirm') == 'yes' && $user->rights-
     	$object->fetch($id);
     
         // If this is a rough draft, approved, canceled or refused
    -	if ($object->statut == 1 || $object->statut == 4 || $object->statut == 5)
    +	if ($object->statut == Holiday::STATUS_DRAFT || $object->statut == Holiday::STATUS_CANCELED || $object->statut == Holiday::STATUS_REFUSED)
     	{
     		// Si l'utilisateur à le droit de lire cette demande, il peut la supprimer
     		if ($candelete)
    @@ -332,11 +332,13 @@ if ($action == 'confirm_send')
         $object->fetch($id);
     
         // Si brouillon et créateur
    -    if($object->statut == 1 && $cancreate)
    +    if($object->statut == Holiday::STATUS_DRAFT && $cancreate)
         {
    -        $object->statut = 2;
    +    	$object->oldcopy = dol_clone($object);
     
    -        $verif = $object->update($user);
    +    	$object->statut = Holiday::STATUS_VALIDATED;
    +
    +        $verif = $object->validate($user);
     
             // Si pas d'erreur SQL on redirige vers la fiche de la demande
             if ($verif > 0)
    @@ -435,13 +437,15 @@ if ($action == 'confirm_valid')
         $object->fetch($id);
     
         // Si statut en attente de validation et valideur = utilisateur
    -    if ($object->statut == 2 && $user->id == $object->fk_validator)
    +    if ($object->statut == Holiday::STATUS_VALIDATED && $user->id == $object->fk_validator)
         {
    +    	$object->oldcopy = dol_clone($object);
    +
             $object->date_valid = dol_now();
             $object->fk_user_valid = $user->id;
    -        $object->statut = 3;
    +        $object->statut = Holiday::STATUS_APPROVED;
     
    -        $verif = $object->update($user);
    +        $verif = $object->approve($user);
     
             // Si pas d'erreur SQL on redirige vers la fiche de la demande
             if ($verif > 0)
    @@ -530,11 +534,11 @@ if ($action == 'confirm_refuse' && GETPOST('confirm','alpha') == 'yes')
             $object->fetch($id);
     
             // Si statut en attente de validation et valideur = utilisateur
    -        if ($object->statut == 2 && $user->id == $object->fk_validator)
    +        if ($object->statut == Holiday::STATUS_VALIDATED && $user->id == $object->fk_validator)
             {
                 $object->date_refuse = dol_print_date('dayhour', dol_now());
                 $object->fk_user_refuse = $user->id;
    -            $object->statut = 5;
    +            $object->statut = Holiday::STATUS_REFUSED;
                 $object->detail_refuse = GETPOST('detail_refuse','alphanohtml');
     
                 $verif = $object->update($user);
    @@ -615,7 +619,7 @@ if ($action == 'confirm_draft' && GETPOST('confirm') == 'yes')
         $object->fetch($id);
     
         $oldstatus = $object->statut;
    -    $object->statut = 1;
    +    $object->statut = Holiday::STATUS_DRAFT;
     
         $result = $object->update($user);
         if ($result < 0)
    @@ -646,18 +650,18 @@ if ($action == 'confirm_cancel' && GETPOST('confirm') == 'yes')
         $object->fetch($id);
     
         // Si statut en attente de validation et valideur = valideur ou utilisateur, ou droits de faire pour les autres
    -    if (($object->statut == 2 || $object->statut == 3) && ($user->id == $object->fk_validator || in_array($object->fk_user, $childids) || ! empty($user->rights->holiday->write_all)))
    +    if (($object->statut == Holiday::STATUS_VALIDATED || $object->statut == Holiday::STATUS_APPROVED) && ($user->id == $object->fk_validator || in_array($object->fk_user, $childids) || ! empty($user->rights->holiday->write_all)))
         {
         	$db->begin();
     
         	$oldstatus = $object->statut;
             $object->date_cancel = dol_now();
             $object->fk_user_cancel = $user->id;
    -        $object->statut = 4;
    +        $object->statut = Holiday::STATUS_CANCELED;
     
             $result = $object->update($user);
     
    -        if ($result >= 0 && $oldstatus == 3)	// holiday was already validated, status 3, so we must increase back sold
    +        if ($result >= 0 && $oldstatus == Holiday::STATUS_APPROVED)	// holiday was already validated, status 3, so we must increase back sold
             {
             	// Calculcate number of days consummed
             	$nbopenedday=num_open_day($object->date_debut_gmt,$object->date_fin_gmt,0,1,$object->halfday);
    diff --git a/htdocs/holiday/class/holiday.class.php b/htdocs/holiday/class/holiday.class.php
    index 5107ffb09ab..bc964ec7fc6 100644
    --- a/htdocs/holiday/class/holiday.class.php
    +++ b/htdocs/holiday/class/holiday.class.php
    @@ -42,8 +42,17 @@ class Holiday extends CommonObject
     	 */
     	public $table_element='holiday';
     
    -	public $ismultientitymanaged = 0;	// 0=No test on entity, 1=Test with field entity, 2=Test with link by societe
    +	/**
    +	 * 0=No test on entity, 1=Test with field entity, 2=Test with link by societe
    +	 * @var int
    +	 */
    +	public $ismultientitymanaged = 0;
    +
    +	/**
    +	 * @var int Field with ID of parent key if this field has a parent
    +	 */
     	public $fk_element = 'fk_holiday';
    +
     	public $picto = 'holiday';
     
     	/**
    @@ -70,14 +79,38 @@ class Holiday extends CommonObject
     	public $date_fin_gmt='';		// Date end in GMT
     	public $halfday='';			// 0:Full days, 2:Start afternoon end morning, -1:Start afternoon end afternoon, 1:Start morning end morning
     	public $statut='';				// 1=draft, 2=validated, 3=approved
    +
    +	/**
    +     * @var int ID
    +     */
     	public $fk_validator;
    +
     	public $date_valid='';
    +
    +	/**
    +     * @var int ID
    +     */
     	public $fk_user_valid;
    +
     	public $date_refuse='';
    +
    +	/**
    +     * @var int ID
    +     */
     	public $fk_user_refuse;
    +
     	public $date_cancel='';
    +
    +	/**
    +     * @var int ID
    +     */
     	public $fk_user_cancel;
    +
     	public $detail_refuse='';
    +
    +	/**
    +     * @var int ID
    +     */
     	public $fk_type;
     
     	public $holiday = array();
    @@ -565,6 +598,234 @@ class Holiday extends CommonObject
     		}
     	}
     
    +
    +	/**
    +	 *	Validate leave request
    +	 *
    +	 *  @param	User	$user        	User that validate
    +	 *  @param  int		$notrigger	    0=launch triggers after, 1=disable triggers
    +	 *  @return int         			<0 if KO, >0 if OK
    +	 */
    +	function validate($user=null, $notrigger=0)
    +	{
    +		global $conf, $langs;
    +		$error=0;
    +
    +		// Update request
    +		$sql = "UPDATE ".MAIN_DB_PREFIX."holiday SET";
    +
    +		$sql.= " description= '".$this->db->escape($this->description)."',";
    +
    +		if(!empty($this->date_debut)) {
    +			$sql.= " date_debut = '".$this->db->idate($this->date_debut)."',";
    +		} else {
    +			$error++;
    +		}
    +		if(!empty($this->date_fin)) {
    +			$sql.= " date_fin = '".$this->db->idate($this->date_fin)."',";
    +		} else {
    +			$error++;
    +		}
    +		$sql.= " halfday = ".$this->halfday.",";
    +		if(!empty($this->statut) && is_numeric($this->statut)) {
    +			$sql.= " statut = ".$this->statut.",";
    +		} else {
    +			$error++;
    +		}
    +		if(!empty($this->fk_validator)) {
    +			$sql.= " fk_validator = '".$this->db->escape($this->fk_validator)."',";
    +		} else {
    +			$error++;
    +		}
    +		if(!empty($this->date_valid)) {
    +			$sql.= " date_valid = '".$this->db->idate($this->date_valid)."',";
    +		} else {
    +			$sql.= " date_valid = NULL,";
    +		}
    +		if(!empty($this->fk_user_valid)) {
    +			$sql.= " fk_user_valid = '".$this->db->escape($this->fk_user_valid)."',";
    +		} else {
    +			$sql.= " fk_user_valid = NULL,";
    +		}
    +		if(!empty($this->date_refuse)) {
    +			$sql.= " date_refuse = '".$this->db->idate($this->date_refuse)."',";
    +		} else {
    +			$sql.= " date_refuse = NULL,";
    +		}
    +		if(!empty($this->fk_user_refuse)) {
    +			$sql.= " fk_user_refuse = '".$this->db->escape($this->fk_user_refuse)."',";
    +		} else {
    +			$sql.= " fk_user_refuse = NULL,";
    +		}
    +		if(!empty($this->date_cancel)) {
    +			$sql.= " date_cancel = '".$this->db->idate($this->date_cancel)."',";
    +		} else {
    +			$sql.= " date_cancel = NULL,";
    +		}
    +		if(!empty($this->fk_user_cancel)) {
    +			$sql.= " fk_user_cancel = '".$this->db->escape($this->fk_user_cancel)."',";
    +		} else {
    +			$sql.= " fk_user_cancel = NULL,";
    +		}
    +		if(!empty($this->detail_refuse)) {
    +			$sql.= " detail_refuse = '".$this->db->escape($this->detail_refuse)."'";
    +		} else {
    +			$sql.= " detail_refuse = NULL";
    +		}
    +
    +		$sql.= " WHERE rowid= ".$this->id;
    +
    +		$this->db->begin();
    +
    +		dol_syslog(get_class($this)."::validate", LOG_DEBUG);
    +		$resql = $this->db->query($sql);
    +		if (! $resql) {
    +			$error++; $this->errors[]="Error ".$this->db->lasterror();
    +		}
    +
    +		if (! $error)
    +		{
    +			if (! $notrigger)
    +			{
    +				// Call trigger
    +				$result=$this->call_trigger('HOLIDAY_VALIDATE',$user);
    +				if ($result < 0) { $error++; }
    +				// End call triggers
    +			}
    +		}
    +
    +		// Commit or rollback
    +		if ($error)
    +		{
    +			foreach($this->errors as $errmsg)
    +			{
    +				dol_syslog(get_class($this)."::validate ".$errmsg, LOG_ERR);
    +				$this->error.=($this->error?', '.$errmsg:$errmsg);
    +			}
    +			$this->db->rollback();
    +			return -1*$error;
    +		}
    +		else
    +		{
    +			$this->db->commit();
    +			return 1;
    +		}
    +	}
    +
    +
    +	/**
    +	 *	Approve leave request
    +	 *
    +	 *  @param	User	$user        	User that approve
    +	 *  @param  int		$notrigger	    0=launch triggers after, 1=disable triggers
    +	 *  @return int         			<0 if KO, >0 if OK
    +	 */
    +	function approve($user=null, $notrigger=0)
    +	{
    +		global $conf, $langs;
    +		$error=0;
    +
    +		// Update request
    +		$sql = "UPDATE ".MAIN_DB_PREFIX."holiday SET";
    +
    +		$sql.= " description= '".$this->db->escape($this->description)."',";
    +
    +		if(!empty($this->date_debut)) {
    +			$sql.= " date_debut = '".$this->db->idate($this->date_debut)."',";
    +		} else {
    +			$error++;
    +		}
    +		if(!empty($this->date_fin)) {
    +			$sql.= " date_fin = '".$this->db->idate($this->date_fin)."',";
    +		} else {
    +			$error++;
    +		}
    +		$sql.= " halfday = ".$this->halfday.",";
    +		if(!empty($this->statut) && is_numeric($this->statut)) {
    +			$sql.= " statut = ".$this->statut.",";
    +		} else {
    +			$error++;
    +		}
    +		if(!empty($this->fk_validator)) {
    +			$sql.= " fk_validator = '".$this->db->escape($this->fk_validator)."',";
    +		} else {
    +			$error++;
    +		}
    +		if(!empty($this->date_valid)) {
    +			$sql.= " date_valid = '".$this->db->idate($this->date_valid)."',";
    +		} else {
    +			$sql.= " date_valid = NULL,";
    +		}
    +		if(!empty($this->fk_user_valid)) {
    +			$sql.= " fk_user_valid = '".$this->db->escape($this->fk_user_valid)."',";
    +		} else {
    +			$sql.= " fk_user_valid = NULL,";
    +		}
    +		if(!empty($this->date_refuse)) {
    +			$sql.= " date_refuse = '".$this->db->idate($this->date_refuse)."',";
    +		} else {
    +			$sql.= " date_refuse = NULL,";
    +		}
    +		if(!empty($this->fk_user_refuse)) {
    +			$sql.= " fk_user_refuse = '".$this->db->escape($this->fk_user_refuse)."',";
    +		} else {
    +			$sql.= " fk_user_refuse = NULL,";
    +		}
    +		if(!empty($this->date_cancel)) {
    +			$sql.= " date_cancel = '".$this->db->idate($this->date_cancel)."',";
    +		} else {
    +			$sql.= " date_cancel = NULL,";
    +		}
    +		if(!empty($this->fk_user_cancel)) {
    +			$sql.= " fk_user_cancel = '".$this->db->escape($this->fk_user_cancel)."',";
    +		} else {
    +			$sql.= " fk_user_cancel = NULL,";
    +		}
    +		if(!empty($this->detail_refuse)) {
    +			$sql.= " detail_refuse = '".$this->db->escape($this->detail_refuse)."'";
    +		} else {
    +			$sql.= " detail_refuse = NULL";
    +		}
    +
    +		$sql.= " WHERE rowid= ".$this->id;
    +
    +		$this->db->begin();
    +
    +		dol_syslog(get_class($this)."::approve", LOG_DEBUG);
    +		$resql = $this->db->query($sql);
    +		if (! $resql) {
    +			$error++; $this->errors[]="Error ".$this->db->lasterror();
    +		}
    +
    +		if (! $error)
    +		{
    +			if (! $notrigger)
    +			{
    +				// Call trigger
    +				$result=$this->call_trigger('HOLIDAY_APPROVE',$user);
    +				if ($result < 0) { $error++; }
    +				// End call triggers
    +			}
    +		}
    +
    +		// Commit or rollback
    +		if ($error)
    +		{
    +			foreach($this->errors as $errmsg)
    +			{
    +				dol_syslog(get_class($this)."::approve ".$errmsg, LOG_ERR);
    +				$this->error.=($this->error?', '.$errmsg:$errmsg);
    +			}
    +			$this->db->rollback();
    +			return -1*$error;
    +		}
    +		else
    +		{
    +			$this->db->commit();
    +			return 1;
    +		}
    +	}
    +
     	/**
     	 *	Update database
     	 *
    diff --git a/htdocs/hrm/class/establishment.class.php b/htdocs/hrm/class/establishment.class.php
    index 457fca3ac21..4153972d27c 100644
    --- a/htdocs/hrm/class/establishment.class.php
    +++ b/htdocs/hrm/class/establishment.class.php
    @@ -49,7 +49,12 @@ class Establishment extends CommonObject
     	 */
     	public $fk_element = 'fk_establishment';
     
    -	public $ismultientitymanaged = 1;	// 0=No test on entity, 1=Test with field entity, 2=Test with link by societe
    +	/**
    +	 * 0=No test on entity, 1=Test with field entity, 2=Test with link by societe
    +	 * @var int
    +	 */
    +	public $ismultientitymanaged = 1;
    +
         public $picto='building';
     
         /**
    @@ -68,10 +73,19 @@ class Establishment extends CommonObject
     	public $rowid;
     
     	public $name;
    +
    +	/**
    +	 * @var string Address
    +	 */
     	public $address;
    +
     	public $zip;
     	public $town;
    -	public $status;		// 0=open, 1=closed
    +
    +	/**
    +	 * @var int Status 0=open, 1=closed
    +	 */
    +	public $status;
     
     	/**
     	 * @var int Entity
    diff --git a/htdocs/includes/tcpdi/tcpdi_parser.php b/htdocs/includes/tcpdi/tcpdi_parser.php
    index 038994568ac..cdeaf4f94e6 100644
    --- a/htdocs/includes/tcpdi/tcpdi_parser.php
    +++ b/htdocs/includes/tcpdi/tcpdi_parser.php
    @@ -484,7 +484,7 @@ class tcpdi_parser {
     			$v = $sarr[$key];
     			if (($key == '/Type') AND ($v[0] == PDF_TYPE_TOKEN AND ($v[1] == 'XRef'))) {
     				$valid_crs = true;
    -			} elseif (($key == '/Index') AND ($v[0] == PDF_TYPE_ARRAY AND count($v[1] >= 2))) {
    +			} elseif (($key == '/Index') AND ($v[0] == PDF_TYPE_ARRAY AND count($v[1]) >= 2)) {
     				// first object number in the subsection
     				$index_first = intval($v[1][0][1]);
     				// number of entries in the subsection
    diff --git a/htdocs/install/mysql/data/llx_c_action_trigger.sql b/htdocs/install/mysql/data/llx_c_action_trigger.sql
    index 435d98a7a88..6f3bb5461f8 100644
    --- a/htdocs/install/mysql/data/llx_c_action_trigger.sql
    +++ b/htdocs/install/mysql/data/llx_c_action_trigger.sql
    @@ -101,6 +101,8 @@ insert into llx_c_action_trigger (code,label,description,elementtype,rang) value
     insert into llx_c_action_trigger (code,label,description,elementtype,rang) values ('EXPENSE_REPORT_APPROVE','Expense report approved','Executed when an expense report is approved','expensereport',203);
     insert into llx_c_action_trigger (code,label,description,elementtype,rang) values ('EXPENSE_REPORT_PAYED','Expense report billed','Executed when an expense report is set as billed','expensereport',204);
     insert into llx_c_action_trigger (code,label,description,elementtype,rang) values ('EXPENSE_DELETE','Expense report deleted','Executed when an expense report is deleted','expensereport',204);
    +insert into llx_c_action_trigger (code,label,description,elementtype,rang) values ('HOLIDAY_VALIDATE','Expense report validated','Executed when an expense report is validated','expensereport',202);
    +insert into llx_c_action_trigger (code,label,description,elementtype,rang) values ('HOLIDAY_APPROVE','Expense report approved','Executed when an expense report is approved','expensereport',203);
     insert into llx_c_action_trigger (code,label,description,elementtype,rang) values ('PROJECT_VALIDATE','Project validation','Executed when a project is validated','project',141);
     insert into llx_c_action_trigger (code,label,description,elementtype,rang) values ('PROJECT_DELETE','Project deleted','Executed when a project is deleted','project',143);
     -- actions not enabled by default (no constant created for that) when we enable module agenda 
    diff --git a/htdocs/install/mysql/data/llx_c_currencies.sql b/htdocs/install/mysql/data/llx_c_currencies.sql
    index db1ba19aa6e..5f561f26ba0 100644
    --- a/htdocs/install/mysql/data/llx_c_currencies.sql
    +++ b/htdocs/install/mysql/data/llx_c_currencies.sql
    @@ -80,7 +80,7 @@ INSERT INTO llx_c_currencies ( code_iso, unicode, active, label ) VALUES ( 'HNL'
     INSERT INTO llx_c_currencies ( code_iso, unicode, active, label ) VALUES ( 'HKD', '[36]', 1,				'Hong Kong Dollar');
     INSERT INTO llx_c_currencies ( code_iso, unicode, active, label ) VALUES ( 'HUF', '[70,116]', 1,			'Hungary Forint');
     INSERT INTO llx_c_currencies ( code_iso, unicode, active, label ) VALUES ( 'ISK', '[107,114]', 1,			'Iceland Krona');
    -INSERT INTO llx_c_currencies ( code_iso, unicode, active, label ) VALUES ( 'INR', NULL, 1,					'India Rupee'); 
    +INSERT INTO llx_c_currencies ( code_iso, unicode, active, label ) VALUES ( 'INR', '[8377]', 1,				'India Rupee'); 
     INSERT INTO llx_c_currencies ( code_iso, unicode, active, label ) VALUES ( 'IDR', '[82,112]', 1,			'Indonesia Rupiah');
     INSERT INTO llx_c_currencies ( code_iso, unicode, active, label ) VALUES ( 'IRR', '[65020]', 1,				'Iran Rial');
     INSERT INTO llx_c_currencies ( code_iso, unicode, active, label ) VALUES ( 'IMP', '[163]', 1,				'Isle of Man Pound');
    diff --git a/htdocs/install/mysql/migration/7.0.0-8.0.0.sql b/htdocs/install/mysql/migration/7.0.0-8.0.0.sql
    index 18b6440f45b..f29830f29e0 100644
    --- a/htdocs/install/mysql/migration/7.0.0-8.0.0.sql
    +++ b/htdocs/install/mysql/migration/7.0.0-8.0.0.sql
    @@ -60,6 +60,7 @@ DROP TABLE llx_c_accountancy_category;
     DROP TABLE llx_c_accountingaccount;
     
     -- drop old postgresql unique key
    +-- VPGSQL8.2 ALTER TABLE llx_usergroup_rights DROP CONSTRAINT llx_usergroup_rights_fk_usergroup_fk_id_key;
     -- VPGSQL8.2 DROP INDEX llx_usergroup_rights_fk_usergroup_fk_id_key;
     
     update llx_propal set fk_statut = 1 where fk_statut = -1;
    diff --git a/htdocs/install/mysql/migration/8.0.0-9.0.0.sql b/htdocs/install/mysql/migration/8.0.0-9.0.0.sql
    index 0d3f823cb52..9048c681aa1 100644
    --- a/htdocs/install/mysql/migration/8.0.0-9.0.0.sql
    +++ b/htdocs/install/mysql/migration/8.0.0-9.0.0.sql
    @@ -35,6 +35,7 @@ ALTER TABLE llx_accounting_system MODIFY COLUMN pcg_version varchar(32) NOT NULL
     ALTER TABLE llx_accounting_account ADD CONSTRAINT fk_accounting_account_fk_pcg_version    FOREIGN KEY (fk_pcg_version)    REFERENCES llx_accounting_system (pcg_version);
     
     ALTER TABLE llx_facture ADD COLUMN module_source varchar(32);
    +ALTER TABLE llx_facture ADD COLUMN pos_source varchar(32);
     
     create table llx_facture_rec_extrafields
     (
    @@ -53,6 +54,7 @@ ALTER TABLE llx_product_fournisseur_price ADD COLUMN desc_fourn text after ref_f
     
     ALTER TABLE llx_user ADD COLUMN dateemploymentend date after dateemployment;
     
    +ALTER TABLE llx_stock_mouvement ADD COLUMN fk_project integer;
     
     ALTER TABLE llx_c_field_list ADD COLUMN visible tinyint	DEFAULT 1 NOT NULL AFTER search;
     
    @@ -67,11 +69,16 @@ insert into llx_c_action_trigger (code,label,description,elementtype,rang) value
     insert into llx_c_action_trigger (code,label,description,elementtype,rang) values ('CONTRACT_DELETE','Contract deleted','Executed when a contract is deleted','contrat',18);
     insert into llx_c_action_trigger (code,label,description,elementtype,rang) values ('FICHINTER_DELETE','Intervention is deleted','Executed when a intervention is deleted','ficheinter',35);
     insert into llx_c_action_trigger (code,label,description,elementtype,rang) values ('EXPENSE_DELETE','Expense report deleted','Executed when an expense report is deleted','expensereport',204);
    +insert into llx_c_action_trigger (code,label,description,elementtype,rang) values ('HOLIDAY_VALIDATE','Expense report validated','Executed when an expense report is validated','expensereport',202);
    +insert into llx_c_action_trigger (code,label,description,elementtype,rang) values ('HOLIDAY_APPROVE','Expense report approved','Executed when an expense report is approved','expensereport',203);
     
     ALTER TABLE llx_payment_salary ADD COLUMN fk_projet integer DEFAULT NULL after amount;
     
     ALTER TABLE llx_categorie ADD COLUMN ref_ext varchar(255);
     
    +ALTER TABLE llx_paiement ADD COLUMN ext_payment_id varchar(128);
    +ALTER TABLE llx_paiement ADD COLUMN ext_payment_site varchar(128);
    +
     ALTER TABLE llx_societe ADD COLUMN twitter  varchar(255) after skype;
     ALTER TABLE llx_societe ADD COLUMN facebook varchar(255) after skype;
     ALTER TABLE llx_societe ADD COLUMN instagram  varchar(255) after skype;
    diff --git a/htdocs/install/mysql/tables/llx_accounting_bookkeeping.sql b/htdocs/install/mysql/tables/llx_accounting_bookkeeping.sql
    index 4169b858536..af6cd66826d 100644
    --- a/htdocs/install/mysql/tables/llx_accounting_bookkeeping.sql
    +++ b/htdocs/install/mysql/tables/llx_accounting_bookkeeping.sql
    @@ -22,8 +22,8 @@ CREATE TABLE llx_accounting_bookkeeping
       rowid                 integer NOT NULL AUTO_INCREMENT PRIMARY KEY,
       entity                integer DEFAULT 1 NOT NULL,	-- 					| multi company id
       doc_date              date NOT NULL,				-- FEC:PieceDate
    -  doc_type              varchar(30) NOT NULL,		-- FEC:PieceRef		| facture_client/reglement_client/facture_fournisseur/reglement_fournisseur
    -  doc_ref               varchar(300) NOT NULL,		-- 					| facture_client/reglement_client/... reference number
    +  doc_type              varchar(30) NOT NULL,		-- 					| facture_client/reglement_client/facture_fournisseur/reglement_fournisseur
    +  doc_ref               varchar(300) NOT NULL,		-- FEC:PieceRef		| facture_client/reglement_client/... reference number
       fk_doc                integer NOT NULL,			-- 					| facture_client/reglement_client/... rowid
       fk_docdet             integer NOT NULL,			-- 					| facture_client/reglement_client/... line rowid
       thirdparty_code       varchar(32),                -- Third party code (customer or supplier) when record is saved (may help debug) 
    diff --git a/htdocs/install/mysql/tables/llx_facture.sql b/htdocs/install/mysql/tables/llx_facture.sql
    index 6f326450f7f..c001d459b48 100644
    --- a/htdocs/install/mysql/tables/llx_facture.sql
    +++ b/htdocs/install/mysql/tables/llx_facture.sql
    @@ -64,6 +64,7 @@ create table llx_facture
       fk_user_valid			integer,								-- user validating
     
       module_source			varchar(32),							-- name of module when invoice generated by a dedicated module (POS, ...)
    +  pos_source			varchar(32),							-- name of POS station when invoice is generated by a POS module
       fk_fac_rec_source		integer,								-- facture rec source
       fk_facture_source		integer,								-- facture origin if credit notes or replacement invoice
       fk_projet				integer DEFAULT NULL,					-- project invoice is linked to
    diff --git a/htdocs/install/mysql/tables/llx_facturedet.sql b/htdocs/install/mysql/tables/llx_facturedet.sql
    index 05c68e92751..bf008d41f03 100644
    --- a/htdocs/install/mysql/tables/llx_facturedet.sql
    +++ b/htdocs/install/mysql/tables/llx_facturedet.sql
    @@ -52,7 +52,7 @@ create table llx_facturedet
       date_end						datetime   DEFAULT NULL,			-- date end if service
       info_bits						integer    DEFAULT 0,				-- VAT NPR or not (for france only)
     
    -  buy_price_ht					double(24,8) DEFAULT 0,				-- buying price
    +  buy_price_ht					double(24,8) DEFAULT 0,				-- buying price. Note: this value is saved as an always positive value, even on credit notes (it is price we bought the product before selling it).
       fk_product_fournisseur_price	integer      DEFAULT NULL,			-- reference of supplier price when line was added (may be used to update buy_price_ht current price when future invoice will be created)
     
       fk_code_ventilation			integer    DEFAULT 0 NOT NULL,		-- Id in table llx_accounting_bookeeping to know accounting account for product line
    diff --git a/htdocs/install/mysql/tables/llx_paiement.sql b/htdocs/install/mysql/tables/llx_paiement.sql
    index 2a287ac7e89..6eb6b28f695 100644
    --- a/htdocs/install/mysql/tables/llx_paiement.sql
    +++ b/htdocs/install/mysql/tables/llx_paiement.sql
    @@ -31,9 +31,11 @@ create table llx_paiement
       fk_paiement      integer NOT NULL,
       num_paiement     varchar(50),
       note             text,
    +  ext_payment_id   varchar(128),						-- external id of payment (for example Stripe charge id)
    +  ext_payment_site varchar(128),						-- name of external paymentmode (for example 'stripe')
       fk_bank          integer NOT NULL DEFAULT 0,
       fk_user_creat    integer,								-- utilisateur qui a cree l'info
       fk_user_modif    integer,								-- utilisateur qui a modifie l'info
    -  statut           smallint DEFAULT 0 NOT NULL,		-- Satut, 0 ou 1, 1 n'est plus supprimable
    +  statut           smallint DEFAULT 0 NOT NULL,			-- Satut, 0 ou 1, 1 n'est plus supprimable
       fk_export_compta integer DEFAULT 0 NOT NULL			-- fk_export_compta 0 pas exporte
     )ENGINE=innodb;
    diff --git a/htdocs/install/mysql/tables/llx_stock_mouvement.sql b/htdocs/install/mysql/tables/llx_stock_mouvement.sql
    index 1e78e7a9820..fdeab913268 100644
    --- a/htdocs/install/mysql/tables/llx_stock_mouvement.sql
    +++ b/htdocs/install/mysql/tables/llx_stock_mouvement.sql
    @@ -33,6 +33,7 @@ create table llx_stock_mouvement
       fk_user_author  integer,							-- Id user making movement
       label           varchar(255),						-- Comment on movement
       inventorycode   varchar(128),						-- Code used to group different movement line into one operation (may be an inventory, a mass picking)
    +  fk_project	  integer,
       fk_origin       integer,
       origintype      varchar(32),
       model_pdf       varchar(255)
    diff --git a/htdocs/install/mysql/tables/llx_user.sql b/htdocs/install/mysql/tables/llx_user.sql
    index 4cf3ea020a5..56a03f81782 100644
    --- a/htdocs/install/mysql/tables/llx_user.sql
    +++ b/htdocs/install/mysql/tables/llx_user.sql
    @@ -49,7 +49,6 @@ create table llx_user
       fk_country        integer        DEFAULT 0,
       birth             date,						-- birthday
       job				varchar(128),
    -  skype             varchar(255),
       office_phone      varchar(20),
       office_fax        varchar(20),
       user_mobile       varchar(20),
    diff --git a/htdocs/install/repair.php b/htdocs/install/repair.php
    index c51f8c8d1b1..8fa24a97a69 100644
    --- a/htdocs/install/repair.php
    +++ b/htdocs/install/repair.php
    @@ -810,7 +810,7 @@ if ($ok && GETPOST('clean_product_stock_batch','alpha'))
     }
     
     
    -// clean_linked_elements: Check and clean linked elements
    +// clean_product_stock_negative_if_batch
     if ($ok && GETPOST('clean_product_stock_negative_if_batch','alpha'))
     {
         print '<tr><td colspan="2"><br>Clean table product_batch, methodtofix='.$methodtofix.' (possible values: updatestock or updatebatch)</td></tr>';
    @@ -834,12 +834,13 @@ if ($ok && GETPOST('clean_product_stock_negative_if_batch','alpha'))
                     $obj=$db->fetch_object($resql);
                     print '<tr><td>'.$obj->rowid.'-'.$obj->ref.'-'.$obj->fk_entrepot.' -> '.$obj->psrowid.': '.$obj->reel.' != '.$obj->reelbatch;
     
    +                // TODO
                 }
             }
         }
     }
     
    -// clean_linked_elements: Check and clean linked elements
    +// set_empty_time_spent_amount
     if ($ok && GETPOST('set_empty_time_spent_amount','alpha'))
     {
         print '<tr><td colspan="2"><br>*** Set value of time spent without amount</td></tr>';
    @@ -900,7 +901,7 @@ if ($ok && GETPOST('set_empty_time_spent_amount','alpha'))
     }
     
     
    -// clean_old_module_entries: Clean data into const when files of module were removed without being
    +// force_disable_of_modules_not_found
     if ($ok && GETPOST('force_disable_of_modules_not_found','alpha'))
     {
         print '<tr><td colspan="2"><br>*** Force modules not found to be disabled (only modules adding js, css or hooks can be detected as removed)</td></tr>';
    @@ -1071,7 +1072,7 @@ if ($ok && GETPOST('clean_perm_table','alpha'))
     
     
     
    -// clean_linked_elements: Check and clean linked elements
    +// force utf8 on tables
     if ($ok && GETPOST('force_utf8_on_tables','alpha'))
     {
         print '<tr><td colspan="2"><br>*** Force page code and collation of tables into utf8/utf8_unicode_ci (for mysql/mariadb only)</td></tr>';
    diff --git a/htdocs/langs/ar_SA/languages.lang b/htdocs/langs/ar_SA/languages.lang
    index 7b27cc35010..4519ef6078d 100644
    --- a/htdocs/langs/ar_SA/languages.lang
    +++ b/htdocs/langs/ar_SA/languages.lang
    @@ -1,6 +1,6 @@
     # Dolibarr language file - Source file is en_US - languages
     Language_ar_AR=العربية
    -Language_ar_EG=Arabic (Egypt)
    +Language_ar_EG=العربيه مصر
     Language_ar_SA=العربية
     Language_bn_BD=بنغالي
     Language_bg_BG=البلغارية
    @@ -86,3 +86,4 @@ Language_uz_UZ=الأوزبكي
     Language_vi_VN=الفيتنامية
     Language_zh_CN=الصينية
     Language_zh_TW=الصينية (التقليدية)
    +Language_bh_MY=الماليزية
    diff --git a/htdocs/langs/en_US/accountancy.lang b/htdocs/langs/en_US/accountancy.lang
    index e1fe73d0383..e2f6083e6a6 100644
    --- a/htdocs/langs/en_US/accountancy.lang
    +++ b/htdocs/langs/en_US/accountancy.lang
    @@ -38,6 +38,10 @@ GroupIsEmptyCheckSetup=Group is empty, check setup of the personalized accountin
     DetailByAccount=Show detail by account
     AccountWithNonZeroValues=Accounts with non-zero values
     ListOfAccounts=List of accounts
    +CountriesInEEC=Countries in EEC
    +CountriesNotInEEC=Countries not in EEC
    +CountriesInEECExceptMe=Countries in EEC except %s
    +CountriesExceptMe=All countries except %s
     
     MainAccountForCustomersNotDefined=Main accounting account for customers not defined in setup
     MainAccountForSuppliersNotDefined=Main accounting account for vendors not defined in setup
    @@ -54,19 +58,19 @@ AccountancyAreaDescJournalSetup=STEP %s: Create or check content of your journal
     AccountancyAreaDescChartModel=STEP %s: Create a model of chart of account from menu %s
     AccountancyAreaDescChart=STEP %s: Create or check content of your chart of account from menu %s
     
    -AccountancyAreaDescVat=STEP %s: Define accounting accounts for each VAT Rates. For this, use the menu entry %s.    
    +AccountancyAreaDescVat=STEP %s: Define accounting accounts for each VAT Rates. For this, use the menu entry %s.
     AccountancyAreaDescDefault=STEP %s: Define default accounting accounts. For this, use the menu entry %s.
     AccountancyAreaDescExpenseReport=STEP %s: Define default accounting accounts for each type of expense report. For this, use the menu entry %s.
    -AccountancyAreaDescSal=STEP %s: Define default accounting accounts for payment of salaries. For this, use the menu entry %s.    
    +AccountancyAreaDescSal=STEP %s: Define default accounting accounts for payment of salaries. For this, use the menu entry %s.
     AccountancyAreaDescContrib=STEP %s: Define default accounting accounts for special expenses (miscellaneous taxes). For this, use the menu entry %s.
     AccountancyAreaDescDonation=STEP %s: Define default accounting accounts for donation. For this, use the menu entry %s.
     AccountancyAreaDescMisc=STEP %s: Define mandatory default account and default accounting accounts for miscellaneous transactions. For this, use the menu entry %s.
    -AccountancyAreaDescLoan=STEP %s: Define default accounting accounts for loans. For this, use the menu entry %s. 
    +AccountancyAreaDescLoan=STEP %s: Define default accounting accounts for loans. For this, use the menu entry %s.
     AccountancyAreaDescBank=STEP %s: Define accounting accounts and journal code for each bank and financial accounts. For this, use the menu entry %s.
     AccountancyAreaDescProd=STEP %s: Define accounting accounts on your products/services. For this, use the menu entry %s.
     
     AccountancyAreaDescBind=STEP %s: Check the binding between existing %s lines and accounting account is done, so application will be able to journalize transactions in Ledger in one click. Complete missing bindings. For this, use the menu entry %s.
    -AccountancyAreaDescWriteRecords=STEP %s: Write transactions into the Ledger. For this, go into menu <strong>%s</strong>, and click into button <strong>%s</strong>. 
    +AccountancyAreaDescWriteRecords=STEP %s: Write transactions into the Ledger. For this, go into menu <strong>%s</strong>, and click into button <strong>%s</strong>.
     AccountancyAreaDescAnalyze=STEP %s: Add or edit existing transactions and generate reports and exports.
     
     AccountancyAreaDescClosePeriod=STEP %s: Close period so we can't make modification in a future.
    @@ -156,12 +160,13 @@ Docref=Reference
     LabelAccount=Label account
     LabelOperation=Label operation
     Sens=Sens
    +LetteringCode=Lettering code
     Codejournal=Journal
     NumPiece=Piece number
     TransactionNumShort=Num. transaction
     AccountingCategory=Personalized groups
     GroupByAccountAccounting=Group by accounting account
    -AccountingAccountGroupsDesc=You can define here some groups of accounting account. They will be used for personalized accounting reports.  
    +AccountingAccountGroupsDesc=You can define here some groups of accounting account. They will be used for personalized accounting reports.
     ByAccounts=By accounts
     ByPredefinedAccountGroups=By predefined groups
     ByPersonalizedAccountGroups=By personalized groups
    @@ -187,7 +192,7 @@ NewAccountingMvt=New transaction
     NumMvts=Numero of transaction
     ListeMvts=List of movements
     ErrorDebitCredit=Debit and Credit cannot have a value at the same time
    -AddCompteFromBK=Add accounting accounts to the group 
    +AddCompteFromBK=Add accounting accounts to the group
     ReportThirdParty=List third party account
     DescThirdPartyReport=Consult here the list of the third party customers and vendors and their accounting accounts
     ListAccounts=List of the accounting accounts
    @@ -221,6 +226,7 @@ AutomaticBindingDone=Automatic binding done
     
     ErrorAccountancyCodeIsAlreadyUse=Error, you cannot delete this accounting account because it is used
     MvtNotCorrectlyBalanced=Movement not correctly balanced. Debit = %s | Credit = %s
    +Balancing=Balancing
     FicheVentilation=Binding card
     GeneralLedgerIsWritten=Transactions are written in the Ledger
     GeneralLedgerSomeRecordWasNotRecorded=Some of the transactions could not be journalized. If there is no other error message, this is probably because they were already journalized.
    @@ -262,7 +268,8 @@ Modelcsv_quadratus=Export towards Quadratus QuadraCompta
     Modelcsv_ebp=Export towards EBP
     Modelcsv_cogilog=Export towards Cogilog
     Modelcsv_agiris=Export towards Agiris
    -Modelcsv_configurable=Export Configurable
    +Modelcsv_configurable=Export CSV Configurable
    +Modelcsv_FEC=Export FEC (Art. L47 A) (Test)
     ChartofaccountsId=Chart of accounts Id
     
     ## Tools - Init accounting account on product / service
    diff --git a/htdocs/langs/en_US/admin.lang b/htdocs/langs/en_US/admin.lang
    index bbb42399db0..190b7cded97 100644
    --- a/htdocs/langs/en_US/admin.lang
    +++ b/htdocs/langs/en_US/admin.lang
    @@ -23,7 +23,7 @@ FilesUpdated=Updated Files
     FilesModified=Modified Files
     FilesAdded=Added Files
     FileCheckDolibarr=Check integrity of application files
    -AvailableOnlyOnPackagedVersions=The local file for integrity checking is only available when application is installed from an official package 
    +AvailableOnlyOnPackagedVersions=The local file for integrity checking is only available when application is installed from an official package
     XmlNotFound=Xml Integrity File of application not found
     SessionId=Session ID
     SessionSaveHandler=Handler to save sessions
    @@ -96,9 +96,9 @@ NoMaxSizeByPHPLimit=Note: No limit is set in your PHP configuration
     MaxSizeForUploadedFiles=Maximum size for uploaded files (0 to disallow any upload)
     UseCaptchaCode=Use graphical code (CAPTCHA) on login page
     AntiVirusCommand= Full path to antivirus command
    -AntiVirusCommandExample= Example for ClamWin: c:\Progra~1\ClamWin\bin\clamscan.exe<br>Example for ClamAv: /usr/bin/clamscan
    +AntiVirusCommandExample= Example for ClamWin: c:\\Progra~1\\ClamWin\\bin\\clamscan.exe<br>Example for ClamAv: /usr/bin/clamscan
     AntiVirusParam= More parameters on command line
    -AntiVirusParamExample= Example for ClamWin: --database="C:\Program Files (x86)\ClamWin\lib"
    +AntiVirusParamExample= Example for ClamWin: --database="C:\\Program Files (x86)\\ClamWin\\lib"
     ComptaSetup=Accounting module setup
     UserSetup=User management setup
     MultiCurrencySetup=Multi-currency setup
    @@ -184,7 +184,7 @@ AddDropTable=Add DROP TABLE command
     ExportStructure=Structure
     NameColumn=Name columns
     ExtendedInsert=Extended INSERT
    -NoLockBeforeInsert=No lock commands around INSERT 
    +NoLockBeforeInsert=No lock commands around INSERT
     DelayedInsert=Delayed insert
     EncodeBinariesInHexa=Encode binary data in hexadecimal
     IgnoreDuplicateRecords=Ignore errors of duplicate record (INSERT IGNORE)
    @@ -199,7 +199,7 @@ ModulesDeployDesc=If permissions on your file system allow it, you can use this
     ModulesMarketPlaces=Find external app/modules
     ModulesDevelopYourModule=Develop your own app/modules
     ModulesDevelopDesc=You may also develop your own module or find a partner to develop one for you.
    -DOLISTOREdescriptionLong=Instead of switching on <a href="https://www.dolistore.com">www.dolistore.com</a> web site to find an external module, you can use this embedded tool that will make the seach on the external market place for you (may be slow, need an internet access)...
    +DOLISTOREdescriptionLong=Instead of switching on <a href="https://www.dolistore.com">www.dolistore.com</a> web site to find an external module, you can use this embedded tool that will perform the search on the external market place for you (may be slow, need an internet access)...
     NewModule=New
     FreeModule=Free
     CompatibleUpTo=Compatible with version %s
    @@ -208,7 +208,7 @@ CompatibleAfterUpdate=This module requires an update to your Dolibarr %s (Min %s
     SeeInMarkerPlace=See in Market place
     Updated=Updated
     Nouveauté=Novelty
    -AchatTelechargement=Buy / Download 
    +AchatTelechargement=Buy / Download
     GoModuleSetupArea=To deploy/install a new module, go onto the Module setup area at <a href="%s">%s</a>.
     DoliStoreDesc=DoliStore, the official market place for Dolibarr ERP/CRM external modules
     DoliPartnersDesc=List of companies providing custom-developed modules or features.<br>Note: since Dolibarr is an open source application, <i>anyone</i> experienced in PHP programming may develop a module.
    @@ -229,7 +229,7 @@ DoNotStoreClearPassword=Do no store clear passwords in database but store only e
     MainDbPasswordFileConfEncrypted=Database password encrypted in conf.php (Activated recommended)
     InstrucToEncodePass=To have password encoded into the <b>conf.php</b> file, replace the line <br><b>$dolibarr_main_db_pass="...";</b><br>by<br><b>$dolibarr_main_db_pass="crypted:%s";</b>
     InstrucToClearPass=To have password decoded (clear) into the <b>conf.php</b> file, replace the line <br><b>$dolibarr_main_db_pass="crypted:...";</b><br>by<br><b>$dolibarr_main_db_pass="%s";</b>
    -ProtectAndEncryptPdfFiles=Protection of generated PDF files NOT recommended, breaks mass PDF generation)
    +ProtectAndEncryptPdfFiles=Protection of generated PDF files NOT recommended (breaks mass PDF generation)
     ProtectAndEncryptPdfFilesDesc=Protection of a PDF document keeps it available to read and print with any PDF browser. However, editing and copying is not possible anymore. Note that using this feature makes building of a global merged PDFs not working.
     Feature=Feature
     DolibarrLicense=License
    @@ -286,7 +286,7 @@ MAIN_MAIL_DEFAULT_FROMTYPE=Default sender email for manual sending (User email o
     UserEmail=User email
     CompanyEmail=Company email
     FeatureNotAvailableOnLinux=Feature not available on Unix like systems. Test your sendmail program locally.
    -SubmitTranslation=If translation for this language is not complete or you find errors, you can correct this by editing files into directory <b>langs/%s</b> and submit your change to www.transifex.com/dolibarr-association/dolibarr/
    +SubmitTranslation=If translation for this language is not complete or you find errors, you can correct this by editing files in directory <b>langs/%s</b> and submit your change to www.transifex.com/dolibarr-association/dolibarr/
     SubmitTranslationENUS=If translation for this language is not complete or you find errors, you can correct this by editing files into directory <b>langs/%s</b> and submit modified files on dolibarr.org/forum or for developers on github.com/Dolibarr/dolibarr.
     ModuleSetup=Module setup
     ModulesSetup=Modules/Application setup
    @@ -309,11 +309,11 @@ DoNotUseInProduction=Do not use in production
     ThisIsProcessToFollow=This is steps to process:
     ThisIsAlternativeProcessToFollow=This is an alternative setup to process manually:
     StepNb=Step %s
    -FindPackageFromWebSite=Find a package that provides feature you want (for example on official web site %s).
    +FindPackageFromWebSite=Find a package that provides features you want (for example on official web site %s).
     DownloadPackageFromWebSite=Download package (for example from official web site %s).
     UnpackPackageInDolibarrRoot=Unpack/unzip the packaged files into the server directory dedicated to Dolibarr: <b>%s</b>
     UnpackPackageInModulesRoot=To deploy/install an external module, unpack/unzip the packaged files into the server directory dedicated to external modules:<br><b>%s</b>
    -SetupIsReadyForUse=Module deployment is finished. You must however enable and setup the module in your application by going on the page to setup modules: <a href="%s">%s</a>.
    +SetupIsReadyForUse=Module deployment is finished. You must however enable and setup the module in your application by going to the page setup modules: <a href="%s">%s</a>.
     NotExistsDirect=The alternative root directory is not defined to an existing directory.<br>
     InfDirAlt=Since version 3, it is possible to define an alternative root directory. This allows you to store, into a dedicated directory, plug-ins and custom templates.<br>Just create a directory at the root of Dolibarr (eg: custom).<br>
     InfDirExample=<br>Then declare it in the file <strong>conf.php</strong><br> $dolibarr_main_url_root_alt='/custom'<br>$dolibarr_main_document_root_alt='/path/of/dolibarr/htdocs/custom'<br>If these lines are commented with "#", to enable them, just uncomment by removing the "#" character.
    @@ -333,7 +333,7 @@ GenericMaskCodes4a=<u>Example on the 99th %s of the third party TheCompany, with
     GenericMaskCodes4b=<u>Example on third party created on 2007-03-01:</u><br>
     GenericMaskCodes4c=<u>Example on product created on 2007-03-01:</u><br>
     GenericMaskCodes5=<b>ABC{yy}{mm}-{000000}</b> will give <b>ABC0701-000099</b><br><b>{0000+100@1}-ZZZ/{dd}/XXX</b> will give <b>0199-ZZZ/31/XXX</b><br><b>IN{yy}{mm}-{0000}-{t}</b> will give <b>IN0701-0099-A</b> if the type of company is 'Responsable Inscripto' with code for type that is 'A_RI'
    -GenericNumRefModelDesc=Returns a customizable number according to a defined mask. 
    +GenericNumRefModelDesc=Returns a customizable number according to a defined mask.
     ServerAvailableOnIPOrPort=Server is available at address <b>%s</b> on port <b>%s</b>
     ServerNotAvailableOnIPOrPort=Server is not available at address <b>%s</b> on port <b>%s</b>
     DoTestServerAvailability=Test server connectivity
    @@ -347,25 +347,25 @@ SeeWikiForAllTeam=Take a look at the wiki page for full list of all actors and t
     UseACacheDelay= Delay for caching export response in seconds (0 or empty for no cache)
     DisableLinkToHelpCenter=Hide link "<b>Need help or support</b>" on login page
     DisableLinkToHelp=Hide link to online help "<b>%s</b>"
    -AddCRIfTooLong=There is no automatic wrapping, so if line is out of page on documents because too long, you must add yourself carriage returns in the textarea.
    -ConfirmPurge=Are you sure you want to execute this purge?<br>This will delete definitely all your data files with no way to restore them (ECM files, attached files...). 
    +AddCRIfTooLong=There is no automatic text wrapping, text that is too long will not display on documents. Please add carriage returns in the text area if needed.
    +ConfirmPurge=Are you sure you want to execute this purge?<br>This will permanently delete all your data files with no way to restore them (ECM files, attached files...).
     MinLength=Minimum length
     LanguageFilesCachedIntoShmopSharedMemory=Files .lang loaded in shared memory
     LanguageFile=Language file
     ExamplesWithCurrentSetup=Examples with current configuration
     ListOfDirectories=List of OpenDocument templates directories
    -ListOfDirectoriesForModelGenODT=List of directories containing templates files with OpenDocument format.<br><br>Put here full path of directories.<br>Add a carriage return between eah directory.<br>To add a directory of the GED module, add here <b>DOL_DATA_ROOT/ecm/yourdirectoryname</b>.<br><br>Files in those directories must end with <b>.odt</b> or <b>.ods</b>. 
    +ListOfDirectoriesForModelGenODT=List of directories containing templates files with OpenDocument format.<br><br>Put here full path of directories.<br>Add a carriage return between eah directory.<br>To add a directory of the GED module, add here <b>DOL_DATA_ROOT/ecm/yourdirectoryname</b>.<br><br>Files in those directories must end with <b>.odt</b> or <b>.ods</b>.
     NumberOfModelFilesFound=Number of ODT/ODS template files found in these directories
    -ExampleOfDirectoriesForModelGen=Examples of syntax:<br>c:\mydir<br>/home/mydir<br>DOL_DATA_ROOT/ecm/ecmdir
    -FollowingSubstitutionKeysCanBeUsed=<br>To know how to create your odt document templates, before storing them in those directories, read wiki documentation: 
    +ExampleOfDirectoriesForModelGen=Examples of syntax:<br>c:\\mydir<br>/home/mydir<br>DOL_DATA_ROOT/ecm/ecmdir
    +FollowingSubstitutionKeysCanBeUsed=<br>To know how to create your odt document templates, before storing them in those directories, read wiki documentation:
     FullListOnOnlineDocumentation=http://wiki.dolibarr.org/index.php/Create_an_ODT_document_template
     FirstnameNamePosition=Position of Name/Lastname
     DescWeather=The following pictures will be shown on dashboard when number of late actions reach the following values:
     KeyForWebServicesAccess=Key to use Web Services (parameter "dolibarrkey" in webservices)
     TestSubmitForm=Input test form
    -ThisForceAlsoTheme=Using this menu manager will also use its own theme whatever is user choice. Also this menu manager specialized for smartphones does not works on all smartphone. Use another menu manager if you experience problems on yours. 
    +ThisForceAlsoTheme=Using this menu manager will also use its own theme whatever is user choice. Also this menu manager specialized for smartphones does not works on all smartphone. Use another menu manager if you experience problems on yours.
     ThemeDir=Skins directory
    -ConnectionTimeout=Connexion timeout
    +ConnectionTimeout=Connection timeout
     ResponseTimeout=Response timeout
     SmsTestMessage=Test message from __PHONEFROM__ to __PHONETO__
     ModuleMustBeEnabledFirst=Module <b>%s</b> must be enabled first if you need this feature.
    @@ -377,7 +377,7 @@ PDFAddressForging=Rules to forge address boxes
     HideAnyVATInformationOnPDF=Hide all information related to Sales tax / VAT on generated PDF
     PDFRulesForSalesTax=Rules for Sales Tax / VAT
     PDFLocaltax=Rules for %s
    -HideLocalTaxOnPDF=Hide %s rate into pdf column tax sale
    +HideLocalTaxOnPDF=Hide %s rate in pdf column tax sale
     HideDescOnPDF=Hide products description on generated PDF
     HideRefOnPDF=Hide products ref. on generated PDF
     HideDetailsOnPDF=Hide product lines details on generated PDF
    @@ -387,7 +387,7 @@ UrlGenerationParameters=Parameters to secure URLs
     SecurityTokenIsUnique=Use a unique securekey parameter for each URL
     EnterRefToBuildUrl=Enter reference for object %s
     GetSecuredUrl=Get calculated URL
    -ButtonHideUnauthorized=Hide buttons to non-admin users for unauthorized actions instead of showing greyed disabled buttons
    +ButtonHideUnauthorized=Hide buttons for non-admin users for unauthorized actions instead of showing greyed disabled buttons
     OldVATRates=Old VAT rate
     NewVATRates=New VAT rate
     PriceBaseTypeToChange=Modify on prices with base reference value defined on
    @@ -408,13 +408,13 @@ ExtrafieldSelect = Select list
     ExtrafieldSelectList = Select from table
     ExtrafieldSeparator=Separator (not a field)
     ExtrafieldPassword=Password
    -ExtrafieldRadio=Radio buttons (on choice only)
    +ExtrafieldRadio=Radio buttons (one choice only)
     ExtrafieldCheckBox=Checkboxes
     ExtrafieldCheckBoxFromList=Checkboxes from table
     ExtrafieldLink=Link to an object
     ComputedFormula=Computed field
     ComputedFormulaDesc=You can enter here a formula using other properties of object or any PHP coding to get a dynamic computed value. You can use any PHP compatible formulas including the "?" condition operator, and following global object: <strong>$db, $conf, $langs, $mysoc, $user, $object</strong>.<br><strong>WARNING</strong>: Only some properties of $object may be available. If you need a properties not loaded, just fetch yourself the object into your formula like in the second example.<br>Using a computed field means you can't enter yourself any value from interface. Also, if there is a syntax error, the formula may return nothing.<br><br>Example of formula:<br>$object->id < 10 ? round($object->id / 2, 2) : ($object->id + 2 * $user->id) * (int) substr($mysoc->zip, 1, 2)<br><br>Example to reload object<br>(($reloadedobj = new Societe($db)) && ($reloadedobj->fetch($obj->id ? $obj->id : ($obj->rowid ? $obj->rowid : $object->id)) > 0)) ? $reloadedobj->array_options['options_extrafieldkey'] * $reloadedobj->capital / 5 : '-1'<br><br>Other example of formula to force load of object and its parent object:<br>(($reloadedobj = new Task($db)) && ($reloadedobj->fetch($object->id) > 0) && ($secondloadedobj = new Project($db)) && ($secondloadedobj->fetch($reloadedobj->fk_project) > 0)) ? $secondloadedobj->ref : 'Parent project not found'
    -ExtrafieldParamHelpPassword=Keep this field empty means value will be stored without encryption (field must be only hidden with star on screen).<br>Set here value 'auto' to use the default encryption rule to save password into database (then value read will be the hash only, no way to retreive original value)
    +ExtrafieldParamHelpPassword=Leaving this field blank means this value will be stored without encryption (field must be only hidden with star on screen).<br>Set  'auto' to use the default encryption rule to save password into database (then value read will be the hash only, no way to retrieve original value)
     ExtrafieldParamHelpselect=List of values must be lines with format key,value (where key can't be '0')<br><br> for example : <br>1,value1<br>2,value2<br>code3,value3<br>...<br><br>In order to have the list depending on another complementary attribute list :<br>1,value1|options_<i>parent_list_code</i>:parent_key<br>2,value2|options_<i>parent_list_code</i>:parent_key <br><br>In order to have the list depending on another list :<br>1,value1|<i>parent_list_code</i>:parent_key<br>2,value2|<i>parent_list_code</i>:parent_key
     ExtrafieldParamHelpcheckbox=List of values must be lines with format key,value (where key can't be '0')<br><br> for example : <br>1,value1<br>2,value2<br>3,value3<br>...
     ExtrafieldParamHelpradio=List of values must be lines with format key,value (where key can't be '0')<br><br> for example : <br>1,value1<br>2,value2<br>3,value3<br>...
    @@ -439,7 +439,7 @@ InitEmptyBarCode=Init value for next %s empty records
     EraseAllCurrentBarCode=Erase all current barcode values
     ConfirmEraseAllCurrentBarCode=Are you sure you want to erase all current barcode values?
     AllBarcodeReset=All barcode values have been removed
    -NoBarcodeNumberingTemplateDefined=No numbering barcode template enabled into barcode module setup.
    +NoBarcodeNumberingTemplateDefined=No numbering barcode template enabled in the barcode module setup.
     EnableFileCache=Enable file cache
     ShowDetailsInPDFPageFoot=Add more details into footer of PDF files, like your company address, or manager names (to complete professional ids, company capital and VAT number).
     NoDetails=No more details in footer
    @@ -450,22 +450,22 @@ EnableAndSetupModuleCron=If you want to have this recurring invoice generated au
     ModuleCompanyCodeCustomerAquarium=%s followed by customer code for a customer accounting code
     ModuleCompanyCodeSupplierAquarium=%s followed by supplier code for a supplier accounting code
     ModuleCompanyCodePanicum=Return an empty accounting code.
    -ModuleCompanyCodeDigitaria=Accounting code depends on third party code. The code is composed of the character "C" in the first position followed by the first 5 characters of the third party code.  
    -Use3StepsApproval=By default, Purchase Orders need to be created and approved by 2 different users (one step/user to create and one step/user to approve. Note that if user has both permission to create and approve, one step/user will be enough). You can ask with this option to introduce a third step/user approval, if amount is higher than a dedicated value (so 3 steps will be necessary: 1=validation, 2=first approval and 3=second approval if amount is enough).<br>Set this to empty if one approval (2 steps) is enough, set it to a very low value (0.1) if a second approval (3 steps) is always required.  
    +ModuleCompanyCodeDigitaria=Accounting code depends on third party code. The code is composed of the character "C" in the first position followed by the first 5 characters of the third party code.
    +Use3StepsApproval=By default, Purchase Orders need to be created and approved by 2 different users (one step/user to create and one step/user to approve. Note that if user has both permission to create and approve, one step/user will be enough). You can ask with this option to introduce a third step/user approval, if amount is higher than a dedicated value (so 3 steps will be necessary: 1=validation, 2=first approval and 3=second approval if amount is enough).<br>Set this to empty if one approval (2 steps) is enough, set it to a very low value (0.1) if a second approval (3 steps) is always required.
     UseDoubleApproval=Use a 3 steps approval when amount (without tax) is higher than...
    -WarningPHPMail=WARNING: It is often better to setup outgoing emails to use the email server of your provider instead of the default setup. Some email providers (like Yahoo) do not allow you to send an email from another server than their own server. Your current setup uses the server of the application to send email and not the server of your email provider, so some recipients (the one compatible with the restrictive DMARC protocol), will ask your email provider if they can accept your email and some email providers (like Yahoo) may respond "no" because the server is not a server of them, so few of your sent Emails may not be accepted (be careful also to your email provider sending quota).<br>If your Email provider (like Yahoo) has this restriction, you must change Email setup to choose the other method "SMTP server" and enter the SMTP server and credentials provided by your Email provider (ask your EMail provider to get SMTP credentials for your account).
    +WarningPHPMail=WARNING: It is often better to setup outgoing emails to use the email server of your provider instead of the default setup. Some email providers (like Yahoo) do not allow you to send an email from another server than their own server. Your current setup uses the server of the application to send email and not the server of your email provider, so some recipients (the one compatible with the restrictive DMARC protocol), will ask your email provider if they can accept your email and some email providers (like Yahoo) may respond "no" because the server is not their, so few of your sent Emails may not be accepted (be careful also of your email provider's sending quota).<br>If your Email provider (like Yahoo) has this restriction, you must change Email setup to choose the other method "SMTP server" and enter the SMTP server and credentials provided by your Email provider (ask your Email provider to get SMTP credentials for your account).
     WarningPHPMail2=If your email SMTP provider need to restrict email client to some IP addresses (very rare), this is the IP address of the mail user agent (MUA) for your ERP CRM application: <strong>%s</strong>.
     ClickToShowDescription=Click to show description
    -DependsOn=This module need the module(s)
    +DependsOn=This module needs the module(s)
     RequiredBy=This module is required by module(s)
    -TheKeyIsTheNameOfHtmlField=This is the name of the HTML field. This need to have technical knowledges to read the content of the HTML page to get the key name of a field.
    -PageUrlForDefaultValues=You must enter here the relative url of the page. If you include parameters in URL, the default values will be effective if all parameters are set to same value. Examples:
    +TheKeyIsTheNameOfHtmlField=This is the name of the HTML field. Technical knowledge is required to read the content of the HTML page to get the key name of a field.
    +PageUrlForDefaultValues=You must enter the relative url of the page. If you include parameters in URL, the default values will be effective if all parameters are set to same value. Examples:
     PageUrlForDefaultValuesCreate=<br>For form to create a new thirdparty, it is <strong>%s</strong>,<br>If you want default value only if url has some parameter, you can use <strong>%s</strong>
     PageUrlForDefaultValuesList=<br>For page that list third-parties, it is <strong>%s</strong>,<br>If you want default value only if url has some parameter, you can use <strong>%s</strong>
     EnableDefaultValues=Enable usage of personalized default values
    -EnableOverwriteTranslation=Enable usage of overwrote translation
    +EnableOverwriteTranslation=Enable usage of overwritten translation
     GoIntoTranslationMenuToChangeThis=A translation has been found for the key with this code. To change this value, you must edit it from Home-Setup-translation.
    -WarningSettingSortOrder=Warning, setting a default sort order may result in a technical error when going on the list page if field is an unknown field. If you experience such an error, come back to this page to remove the default sort order and restore default behavior. 
    +WarningSettingSortOrder=Warning, setting a default sort order may result in a technical error when going on the list page if field is an unknown field. If you experience such an error, come back to this page to remove the default sort order and restore default behavior.
     Field=Field
     ProductDocumentTemplates=Document templates to generate product document
     FreeLegalTextOnExpenseReports=Free legal text on expense reports
    @@ -476,7 +476,7 @@ SendEmailsReminders=Send agenda reminders by emails
     davDescription=Add a component to be a DAV server
     DAVSetup=Setup of module DAV
     DAV_ALLOW_PUBLIC_DIR=Enable the public directory (WebDav directory with no login required)
    -DAV_ALLOW_PUBLIC_DIRTooltip=The WebDav public directory is a WebDAV directory everybody can access to (in read and write mode), with no need to have/use an existing login/password account.
    +DAV_ALLOW_PUBLIC_DIRTooltip=The WebDav public directory is a WebDAV directory everybody can access  (in read and write mode), with no need to have/use an existing login/password account.
     DAV_ALLOW_ECM_DIR=Enable the root directy of DMS/ECM module (login required)
     DAV_ALLOW_ECM_DIRTooltip=The root directory where all files are manually uploaded when using the DMS/ECM module. Like for the feature from the web interface, you will need a valid login/password with granted permissions to access it.
     # Modules
    @@ -487,7 +487,7 @@ Module1Desc=Companies and contact management (customers, prospects...)
     Module2Name=Commercial
     Module2Desc=Commercial management
     Module10Name=Accounting
    -Module10Desc=Simple accounting reports (journals, turnover) based onto database content. Does not use any ledger table.
    +Module10Desc=Simple accounting reports (journals, turnover) based on database content. Does not use any ledger table.
     Module20Name=Proposals
     Module20Desc=Commercial proposal management
     Module22Name=Mass E-mailings
    @@ -541,9 +541,9 @@ Module200Desc=LDAP directory synchronization
     Module210Name=PostNuke
     Module210Desc=PostNuke integration
     Module240Name=Data exports
    -Module240Desc=Tool to export Dolibarr data (with assistants)
    +Module240Desc=Tool to export Dolibarr data (with assistance)
     Module250Name=Data imports
    -Module250Desc=Tool to import data into Dolibarr (with assistants)
    +Module250Desc=Tool to import data into Dolibarr (with assistance)
     Module310Name=Members
     Module310Desc=Foundation members management
     Module320Name=RSS Feed
    @@ -584,7 +584,7 @@ Module2200Desc=Enable the usage of math expressions for prices
     Module2300Name=Scheduled jobs
     Module2300Desc=Scheduled jobs management (alias cron or chrono table)
     Module2400Name=Events/Agenda
    -Module2400Desc=Track events. Let Dolibarr log automatic events for tracking purposes or record manual events or meetings. This is the main important module for a good Customer or Supplier Relationship Management.
    +Module2400Desc=Track events. Let Dolibarr log automatic events for tracking purposes or record manual events or meetings. This is the main module for good Customer or Supplier Relationship Management.
     Module2500Name=DMS / ECM
     Module2500Desc=Document Management System / Electronic Content Management. Automatic organization of your generated or stored documents. Share them when you need.
     Module2600Name=API/Web services (SOAP server)
    @@ -592,9 +592,9 @@ Module2600Desc=Enable the Dolibarr SOAP server providing API services
     Module2610Name=API/Web services (REST server)
     Module2610Desc=Enable the Dolibarr REST server providing API services
     Module2660Name=Call WebServices (SOAP client)
    -Module2660Desc=Enable the Dolibarr web services client (Can be used to push data/requests to external servers. Supplier orders supported only for the moment)
    +Module2660Desc=Enable the Dolibarr web services client (Can be used to push data/requests to external servers. Only Supplier orders currently supported.)
     Module2700Name=Gravatar
    -Module2700Desc=Use online Gravatar service (www.gravatar.com) to show photo of users/members (found with their emails). Need an internet access
    +Module2700Desc=Use online Gravatar service (www.gravatar.com) to show photo of users/members (found with their emails). Needs Internet access
     Module2800Desc=FTP Client
     Module2900Name=GeoIPMaxmind
     Module2900Desc=GeoIP Maxmind conversions capabilities
    @@ -620,12 +620,12 @@ Module50000Name=PayBox
     Module50000Desc=Offer customers a PayBox online payment page (credit/debit cards). This can be used to allow your customers to make free payments or for a payment on a particular Dolibarr object (invoice, order, ...)
     Module50100Name=Point of sales
     Module50100Desc=Point of sales module (POS).
    -Module50150Name=Point of salesaa
    +Module50150Name=Point of sales
     Module50150Desc=Point of sales module (Touch screen POS).
     Module50200Name=Paypal
     Module50200Desc=Offer customers a PayPal online payment page (PayPal account or credit/debit cards). This can be used to allow your customers to make free payments or for a payment on a particular Dolibarr object (invoice, order, ...)
     Module50400Name=Accounting (advanced)
    -Module50400Desc=Accounting management (double entries, support general and auxiliary ledgers). Export the ledger in several other accounting software format.
    +Module50400Desc=Accounting management (double entries, support general and auxiliary ledgers). Export the ledger in several other accounting software formats.
     Module54000Name=PrintIPP
     Module54000Desc=Direct print (without opening the documents) using Cups IPP interface (Printer must be visible from server, and CUPS must be installed on server).
     Module55000Name=Poll, Survey or Vote
    @@ -692,7 +692,7 @@ Permission109=Delete sendings
     Permission111=Read financial accounts
     Permission112=Create/modify/delete and compare transactions
     Permission113=Setup financial accounts (create, manage categories)
    -Permission114=Reconciliate transactions
    +Permission114=Reconcile transactions
     Permission115=Export transactions and account statements
     Permission116=Transfers between accounts
     Permission117=Manage cheques dispatching
    @@ -700,25 +700,25 @@ Permission121=Read third parties linked to user
     Permission122=Create/modify third parties linked to user
     Permission125=Delete third parties linked to user
     Permission126=Export third parties
    -Permission141=Read all projects and tasks (also private projects i am not contact for)
    -Permission142=Create/modify all projects and tasks (also private projects i am not contact for)
    +Permission141=Read all projects and tasks (also private projects I am not a contact for)
    +Permission142=Create/modify all projects and tasks (also private projects I am not a contact for)
     Permission144=Delete all projects and tasks (also private projects i am not contact for)
     Permission146=Read providers
     Permission147=Read stats
     Permission151=Read direct debit payment orders
     Permission152=Create/modify a direct debit payment orders
     Permission153=Send/Transmit direct debit payment orders
    -Permission154=Record Credits/Rejects of direct debit payment orders
    +Permission154=Record Credits/Rejections of direct debit payment orders
     Permission161=Read contracts/subscriptions
     Permission162=Create/modify contracts/subscriptions
     Permission163=Activate a service/subscription of a contract
     Permission164=Disable a service/subscription of a contract
     Permission165=Delete contracts/subscriptions
     Permission167=Export contracts
    -Permission171=Read trips and expenses (yours and your subordinates) 
    +Permission171=Read trips and expenses (yours and your subordinates)
     Permission172=Create/modify trips and expenses
     Permission173=Delete trips and expenses
    -Permission174=Read all trips and expenses 
    +Permission174=Read all trips and expenses
     Permission178=Export trips and expenses
     Permission180=Read suppliers
     Permission181=Read supplier orders
    @@ -761,7 +761,7 @@ PermissionAdvanced253=Create/modify internal/external users and permissions
     Permission254=Create/modify external users only
     Permission255=Modify other users password
     Permission256=Delete or disable other users
    -Permission262=Extend access to all third parties (not only third parties that user is a sale representative).<br>Not effective for external users (always limited to themselves for proposals, orders, invoices, contracts, etc.).<br>Not effective for projects (only rules on project permissions, visibility and assignment matters).
    +Permission262=Extend access to all third parties (not only third parties that user is a sale representative for).<br>Not effective for external users (always limited to themselves for proposals, orders, invoices, contracts, etc.).<br>Not effective for projects (only rules on project permissions, visibility and assignment matters).
     Permission271=Read CA
     Permission272=Read invoices
     Permission273=Issue invoices
    @@ -771,7 +771,7 @@ Permission283=Delete contacts
     Permission286=Export contacts
     Permission291=Read tariffs
     Permission292=Set permissions on the tariffs
    -Permission293=Modify costumers tariffs
    +Permission293=Modify customers tariffs
     Permission300=Read bar codes
     Permission301=Create/modify bar codes
     Permission302=Delete bar codes
    @@ -810,7 +810,7 @@ Permission538=Export services
     Permission701=Read donations
     Permission702=Create/modify donations
     Permission703=Delete donations
    -Permission771=Read expense reports (yours and your subordinates) 
    +Permission771=Read expense reports (yours and your subordinates)
     Permission772=Create/modify expense reports
     Permission773=Delete expense reports
     Permission774=Read all expense reports (even for user not subordinates)
    @@ -848,8 +848,8 @@ Permission1251=Run mass imports of external data into database (data load)
     Permission1321=Export customer invoices, attributes and payments
     Permission1322=Reopen a paid bill
     Permission1421=Export customer orders and attributes
    -Permission20001=Read leave requests (your leaves and the one of your subordinates)
    -Permission20002=Create/modify your leave requests (yours leaves and the one of your subordinates)
    +Permission20001=Read leave requests (your leave and that of your subordinates)
    +Permission20002=Create/modify your leave requests (your leave and that of your subordinates)
     Permission20003=Delete leave requests
     Permission20004=Read all leave requests (even of user not subordinates)
     Permission20005=Create/modify leave requests for everybody (even of user not subordinates)
    @@ -898,7 +898,7 @@ DictionaryVAT=VAT Rates or Sales Tax Rates
     DictionaryRevenueStamp=Amount of tax stamps
     DictionaryPaymentConditions=Payment terms
     DictionaryPaymentModes=Payment modes
    -DictionaryTypeContact=Contact/Address types
    +DictionaryTypeContact=Contact address types
     DictionaryTypeOfContainer=Type of website pages/containers
     DictionaryEcotaxe=Ecotax (WEEE)
     DictionaryPaperFormat=Paper formats
    @@ -915,7 +915,7 @@ DictionaryAccountancyJournal=Accounting journals
     DictionaryEMailTemplates=Email Templates
     DictionaryUnits=Units
     DictionaryProspectStatus=Prospection status
    -DictionaryHolidayTypes=Types of leaves
    +DictionaryHolidayTypes=Types of leave
     DictionaryOpportunityStatus=Lead status for project/lead
     DictionaryExpenseTaxCat=Expense report - Transportation categories
     DictionaryExpenseTaxRange=Expense report - Range by transportation category
    @@ -924,35 +924,35 @@ SetupNotSaved=Setup not saved
     BackToModuleList=Back to modules list
     BackToDictionaryList=Back to list of Dictionaries
     TypeOfRevenueStamp=Type of tax stamp
    -VATManagement=VAT Management
    -VATIsUsedDesc=By default when creating prospects, invoices, orders etc. the VAT rate follows the active standard rule:<br>If the seller is not subject to VAT, then VAT defaults to 0. End of rule.<br><p>If the (seller's country = buyer's country), then the VAT by default equals the VAT of the product in the seller's country. End of rule.</p><p>If the seller and buyer are both in the European Community and goods are transport-related products (haulage, shipping, airline), the default VAT is 0. This rule is dependant on the seller's country - please consult with your accountant. The VAT should be paid by the buyer to their customs office in their country and not to the seller. End of rule.</p><p>If the seller and buyer are both in the European Community and the buyer is not a company (with a registered intra-Community VAT number) then the VAT by defaults to the VAT of the seller's country. End of rule.</p><p>If the seller and buyer are both in the European Community and the buyer is a company (with a registered intra-Community VAT number), then the VAT is 0 by default. End of rule.</p><p>In any other case the proposed default is VAT=0. End of rule.</p>
    -VATIsNotUsedDesc=By default the proposed VAT is 0 which can be used for cases like associations, individuals or small companies.
    -VATIsUsedExampleFR=In France, it means companies or organizations having a real fiscal system (Simplified real or normal real).  A system in which VAT is declared.
    -VATIsNotUsedExampleFR=In France, it means associations that are non VAT declared or companies, organizations or liberal professions that have chosen the micro enterprise fiscal system (VAT in franchise) and paid a franchise VAT without any VAT declaration.  This choice will display the reference "Non applicable VAT - art-293B of CGI" on invoices.
    +VATManagement=Sale Tax Management
    +VATIsUsedDesc=By default when creating prospects, invoices, orders etc. the Sale Tax rate follows the active standard rule:<br>If the seller is not subject to Sale tax, then Sale tax defaults to 0. End of rule.<br>If the (seller's country = buyer's country), then the Sale tax by default equals the Sale tax of the product in the seller's country. End of rule.<br>If the seller and buyer are both in the European Community and goods are transport-related products (haulage, shipping, airline), the default Sale tax is 0. This rule is dependant on the seller's country - please consult with your accountant. The Sale tax should be paid by the buyer to their customs office in their country and not to the seller. End of rule.<br>If the seller and buyer are both in the European Community and the buyer is not a company (with a registered intra-Community Sale tax number) then the Sale tax by defaults to the Sale tax of the seller's country. End of rule.<br>If the seller and buyer are both in the European Community and the buyer is a company (with a registered intra-Community Sale tax number), then the Sale tax is 0 by default. End of rule.<br>In any other case the proposed default is Sale tax=0. End of rule.
    +VATIsNotUsedDesc=By default the proposed Sale tax is 0 which can be used for cases like associations, individuals or small companies.
    +VATIsUsedExampleFR=In France, it means companies or organizations having a real fiscal system (Simplified real or normal real).  A system in which Sale tax is declared.
    +VATIsNotUsedExampleFR=In France, it means associations that are non Sale tax declared or companies, organizations or liberal professions that have chosen the micro enterprise fiscal system (Sale tax in franchise) and paid a franchise Sale tax without any Sale tax declaration.  This choice will display the reference "Non applicable Sale tax - art-293B of CGI" on invoices.
     ##### Local Taxes #####
     LTRate=Rate
     LocalTax1IsNotUsed=Do not use second tax
    -LocalTax1IsUsedDesc=Use a second type of tax (other than VAT)
    -LocalTax1IsNotUsedDesc=Do not use other type of tax (other than VAT)
    +LocalTax1IsUsedDesc=Use a second type of tax (other than first one)
    +LocalTax1IsNotUsedDesc=Do not use other type of tax (other than first one)
     LocalTax1Management=Second type of tax
     LocalTax1IsUsedExample=
     LocalTax1IsNotUsedExample=
     LocalTax2IsNotUsed=Do not use third tax
    -LocalTax2IsUsedDesc=Use a third type of tax (other than VAT)
    -LocalTax2IsNotUsedDesc=Do not use other type of tax (other than VAT)
    +LocalTax2IsUsedDesc=Use a third type of tax (other than first one)
    +LocalTax2IsNotUsedDesc=Do not use other type of tax (other than first one)
     LocalTax2Management=Third type of tax
     LocalTax2IsUsedExample=
     LocalTax2IsNotUsedExample=
    -LocalTax1ManagementES= RE Management
    -LocalTax1IsUsedDescES= The RE rate by default when creating prospects, invoices, orders etc. follow the active standard rule:<br>If the buyer is not subjected to RE, RE by default=0. End of rule.<br>If the buyer is subjected to RE then the RE by default. End of rule.<br>
    -LocalTax1IsNotUsedDescES= By default the proposed RE is 0. End of rule.
    -LocalTax1IsUsedExampleES= In Spain they are professionals subject to some specific sections of the Spanish IAE.
    -LocalTax1IsNotUsedExampleES= In Spain they are professional and societies and subject to certain sections of the Spanish IAE.
    -LocalTax2ManagementES= IRPF Management
    -LocalTax2IsUsedDescES= The RE rate by default when creating prospects, invoices, orders etc. follow the active standard rule:<br>If the seller is not subjected to IRPF, then IRPF by default=0. End of rule.<br>If the seller is subjected to IRPF then the IRPF by default. End of rule.<br>
    -LocalTax2IsNotUsedDescES= By default the proposed IRPF is 0. End of rule.
    -LocalTax2IsUsedExampleES= In Spain, freelancers and independent professionals who provide services and companies who have chosen the tax system of modules.
    -LocalTax2IsNotUsedExampleES= In Spain they are businesses not subject to tax system of modules.
    +LocalTax1ManagementES=RE Management
    +LocalTax1IsUsedDescES=The RE rate by default when creating prospects, invoices, orders etc. follow the active standard rule:<br>If the buyer is not subjected to RE, RE by default=0. End of rule.<br>If the buyer is subjected to RE then the RE by default. End of rule.<br>
    +LocalTax1IsNotUsedDescES=By default the proposed RE is 0. End of rule.
    +LocalTax1IsUsedExampleES=In Spain they are professionals subject to some specific sections of the Spanish IAE.
    +LocalTax1IsNotUsedExampleES=In Spain they are professional and societies and subject to certain sections of the Spanish IAE.
    +LocalTax2ManagementES=IRPF Management
    +LocalTax2IsUsedDescES=The IRPF rate by default when creating prospects, invoices, orders etc. follow the active standard rule:<br>If the seller is not subjected to IRPF, then IRPF by default=0. End of rule.<br>If the seller is subjected to IRPF then the IRPF by default. End of rule.<br>
    +LocalTax2IsNotUsedDescES=By default the proposed IRPF is 0. End of rule.
    +LocalTax2IsUsedExampleES=In Spain, freelancers and independent professionals who provide services and companies who have chosen the tax system of modules.
    +LocalTax2IsNotUsedExampleES=In Spain they are businesses not subject to tax system of modules.
     CalcLocaltax=Reports on local taxes
     CalcLocaltax1=Sales - Purchases
     CalcLocaltax1Desc=Local Taxes reports are calculated with the difference between localtaxes sales and localtaxes purchases
    @@ -962,7 +962,7 @@ CalcLocaltax3=Sales
     CalcLocaltax3Desc=Local Taxes reports are the total of localtaxes sales
     LabelUsedByDefault=Label used by default if no translation can be found for code
     LabelOnDocuments=Label on documents
    -LabelOrTranslationKey=Label or translation key 
    +LabelOrTranslationKey=Label or translation key
     NbOfDays=No. of days
     AtEndOfMonth=At end of month
     CurrentNext=Current/Next
    @@ -1007,7 +1007,7 @@ MessageLogin=Login page message
     LoginPage=Login page
     BackgroundImageLogin=Background image
     PermanentLeftSearchForm=Permanent search form on left menu
    -DefaultLanguage=Default language to use (variant)
    +DefaultLanguage=Default language to use (language code)
     EnableMultilangInterface=Enable multilingual interface
     EnableShowLogo=Show logo on left menu
     CompanyInfo=Company/Organization
    @@ -1072,7 +1072,7 @@ DisplayDesc=You can choose each parameter related to the Dolibarr look and feel
     AvailableModules=Available app/modules
     ToActivateModule=To activate modules, go on setup Area (Home->Setup->Modules).
     SessionTimeOut=Time out for session
    -SessionExplanation=This number guarantee that session will never expire before this delay, if the session cleaner is done by Internal PHP session cleaner (and nothing else). Internal PHP session cleaner does not guaranty that session will expire just after this delay. It will expire, after this delay, and when the session cleaner is ran, so every <b>%s/%s</b> access, but only during access made by other sessions.<br>Note: on some servers with an external session cleaning mechanism (cron under debian, ubuntu ...), the sessions can be destroyed after a period defined by the default <strong>session.gc_maxlifetime</strong>, no matter what the value entered here. 
    +SessionExplanation=This number guarantees that the session will never expire before this delay, if the session cleaner is done by Internal PHP session cleaner (and nothing else). Internal PHP session cleaner does not guarantee that the session will expire after this delay. It will expire, after this delay, and when the session cleaner is run, so every <b>%s/%s</b> access, but only during access made by other sessions.<br>Note: on some servers with an external session cleaning mechanism (cron under debian, ubuntu ...), the sessions can be destroyed after a period defined by the default <strong>session.gc_maxlifetime</strong>, no matter what the value entered here is.
     TriggersAvailable=Available triggers
     TriggersDesc=Triggers are files that will modify the behavior of Dolibarr workflow once copied into the directory <b>htdocs/core/triggers</b>. They realize new actions, activated on Dolibarr events (new company creation, invoice validation, ...).
     TriggerDisabledByName=Triggers in this file are disabled by the <b>-NORUN</b> suffix in their name.
    @@ -1097,17 +1097,17 @@ NoEventFoundWithCriteria=No security event has been found for this search criter
     SeeLocalSendMailSetup=See your local sendmail setup
     BackupDesc=To make a complete backup of Dolibarr, you must:
     BackupDesc2=Save content of documents directory (<b>%s</b>) that contains all uploaded and generated files (So it includes all dump files generated at step 1).
    -BackupDesc3=Save content of your database (<b>%s</b>) into a dump file. For this, you can use following assistant.
    +BackupDesc3=Save content of your database (<b>%s</b>) into a dump file. For this, you can use the following assistant.
     BackupDescX=Archived directory should be stored in a secure place.
     BackupDescY=The generated dump file should be stored in a secure place.
    -BackupPHPWarning=Backup cannot be guaranteed with this method. Prefer previous one
    +BackupPHPWarning=Backup cannot be guaranteed with this method. Previous one recommended.
     RestoreDesc=To restore a Dolibarr backup, you must:
     RestoreDesc2=Restore archive file (zip file for example) of documents directory to extract tree of files in documents directory of a new Dolibarr installation or into this current documents directory (<b>%s</b>).
     RestoreDesc3=Restore the data, from a backup dump file, into the database of the new Dolibarr installation or into the database of this current installation (<b>%s</b>). Warning, once restore is finished, you must use a login/password, that existed when backup was made, to connect again. To restore a backup database into this current installation, you can follow this assistant.
     RestoreMySQL=MySQL import
     ForcedToByAModule= This rule is forced to <b>%s</b> by an activated module
     PreviousDumpFiles=Generated database backup files
    -WeekStartOnDay=First day of week 
    +WeekStartOnDay=First day of week
     RunningUpdateProcessMayBeRequired=Running the upgrade process seems to be required (Programs version %s differs from database version %s)
     YouMustRunCommandFromCommandLineAfterLoginToUser=You must run this command from command line after login to a shell with user <b>%s</b> or you must add -W option at end of command line to provide <b>%s</b> password.
     YourPHPDoesNotHaveSSLSupport=SSL functions not available in your PHP
    @@ -1130,14 +1130,14 @@ MAIN_PROXY_HOST=Name/Address of proxy server
     MAIN_PROXY_PORT=Port of proxy server
     MAIN_PROXY_USER=Login to use the proxy server
     MAIN_PROXY_PASS=Password to use the proxy server
    -DefineHereComplementaryAttributes=Define here any attributes not already available by default, that you want to be supported for %s.
    +DefineHereComplementaryAttributes=Define any attributes not already available by default, that you want to be supported for %s here.
     ExtraFields=Complementary attributes
     ExtraFieldsLines=Complementary attributes (lines)
     ExtraFieldsLinesRec=Complementary attributes (templates invoices lines)
     ExtraFieldsSupplierOrdersLines=Complementary attributes (order lines)
     ExtraFieldsSupplierInvoicesLines=Complementary attributes (invoice lines)
     ExtraFieldsThirdParties=Complementary attributes (thirdparty)
    -ExtraFieldsContacts=Complementary attributes (contact/address)
    +ExtraFieldsContacts=Complementary attributes (contact address)
     ExtraFieldsMember=Complementary attributes (member)
     ExtraFieldsMemberType=Complementary attributes (member type)
     ExtraFieldsCustomerInvoices=Complementary attributes (invoices)
    @@ -1151,13 +1151,13 @@ AlphaNumOnlyLowerCharsAndNoSpace=only alphanumericals and lower case characters
     SendmailOptionNotComplete=Warning, on some Linux systems, to send email from your email, sendmail execution setup must contains option -ba (parameter mail.force_extra_parameters into your php.ini file). If some recipients never receive emails, try to edit this PHP parameter with mail.force_extra_parameters = -ba).
     PathToDocuments=Path to documents
     PathDirectory=Directory
    -SendmailOptionMayHurtBuggedMTA=Feature to send mails using method "PHP mail direct" will generate a mail message that might be not correctly parsed by some receiving mail servers. Result is that some mails can't be read by people hosted by those bugged platforms. It's case for some Internet providers (Ex: Orange in France). This is not a problem into Dolibarr nor into PHP but onto receiving mail server. You can however add option MAIN_FIX_FOR_BUGGED_MTA to 1 into setup - other to modify Dolibarr to avoid this. However, you may experience problem with other servers that respect strictly the SMTP standard. The other solution (recommended) is to use the method "SMTP socket library" that has no disadvantages.
    +SendmailOptionMayHurtBuggedMTA=Feature to send mails using method "PHP mail direct" will generate a mail message that might not be parsed correctly by some receiving mail servers. The result is that some mails can't be read by people hosted by those bugged platforms. This is the case for some Internet providers (Ex: Orange in France). This is not a problem with Dolibarr or PHP but with the receiving mail server. You can however add an option MAIN_FIX_FOR_BUGGED_MTA to 1 in Setup - Other to modify Dolibarr to avoid this. However, you may experience problems with other servers that strictly use the SMTP standard. The other solution (recommended) is to use the method "SMTP socket library" which has no disadvantages.
     TranslationSetup=Setup of translation
     TranslationKeySearch=Search a translation key or string
     TranslationOverwriteKey=Overwrite a translation string
     TranslationDesc=How to set displayed application language :<br>* Systemwide: menu <strong>Home - Setup - Display</strong><br>* Per user: Use the <strong>User display setup</strong> tab on user card (click on username at the top of the screen).
     TranslationOverwriteDesc=You can also override strings filling the following table. Choose your language from "%s" dropdown, insert the translation key string into "%s" and your new translation into "%s"
    -TranslationOverwriteDesc2=You can use the other tab to help you know translation key to use
    +TranslationOverwriteDesc2=You can use the other tab to help you know which translation key to use
     TranslationString=Translation string
     CurrentTranslationString=Current translation string
     WarningAtLeastKeyOrTranslationRequired=A search criteria is required at least for key or translation string
    @@ -1166,16 +1166,16 @@ OriginalValueWas=The original translation is overwritten. Original value was:<br
     TransKeyWithoutOriginalValue=You forced a new translation for the translation key '<strong>%s</strong>' that does not exist in any language files
     TotalNumberOfActivatedModules=Activated application/modules: <b>%s</b> / <b>%s</b>
     YouMustEnableOneModule=You must at least enable 1 module
    -ClassNotFoundIntoPathWarning=Class %s not found into PHP path
    +ClassNotFoundIntoPathWarning=Class %s not found in PHP path
     YesInSummer=Yes in summer
     OnlyFollowingModulesAreOpenedToExternalUsers=Note, only the following modules are opened to external users (whatever the permissions of such users) and only if permissions are granted:
     SuhosinSessionEncrypt=Session storage encrypted by Suhosin
     ConditionIsCurrently=Condition is currently %s
    -YouUseBestDriver=You use driver %s that is best driver available currently.
    +YouUseBestDriver=You use driver %s which is the best driver available currently.
     YouDoNotUseBestDriver=You use driver %s but driver %s is recommended.
     NbOfProductIsLowerThanNoPb=You have only %s products/services in the database. This does not require any particular optimization.
     SearchOptim=Search optimization
    -YouHaveXProductUseSearchOptim=You have %s product into database. You should add the constant PRODUCT_DONOTSEARCH_ANYWHERE to 1 into Home-Setup-Other, you limit the search to the beginning of strings making possible for database to use index and you should get an immediate response.
    +YouHaveXProductUseSearchOptim=You have %s products in the database. You should add the constant PRODUCT_DONOTSEARCH_ANYWHERE to 1 in Home-Setup-Other. Limit the search to the beginning of strings which makes it possible for the database to use indexes and you should get an immediate response.
     BrowserIsOK=You are using the %s web browser. This browser is ok for security and performance.
     BrowserIsKO=You are using the %s web browser. This browser is known to be a bad choice for security, performance and reliability. We recommend using Firefox, Chrome, Opera or Safari.
     XDebugInstalled=XDebug is loaded.
    @@ -1188,7 +1188,7 @@ FillThisOnlyIfRequired=Example: +2 (fill only if timezone offset problems are ex
     GetBarCode=Get barcode
     ##### Module password generation
     PasswordGenerationStandard=Return a password generated according to internal Dolibarr algorithm: 8 characters containing shared numbers and characters in lowercase.
    -PasswordGenerationNone=Do not suggest any generated password. Password must be typed in manually.
    +PasswordGenerationNone=Do not suggest a generated password. Password must be typed in manually.
     PasswordGenerationPerso=Return a password according to your personally defined configuration.
     SetupPerso=According to your configuration
     PasswordPatternDesc=Password pattern description
    @@ -1213,11 +1213,11 @@ WatermarkOnDraft=Watermark on draft document
     JSOnPaimentBill=Activate feature to autofill payment lines on payment form
     CompanyIdProfChecker=Rules for Professional IDs
     MustBeUnique=Must be unique?
    -MustBeMandatory=Mandatory to create third parties?
    +MustBeMandatory=Mandatory to create third parties (if vat number or type of company defined) ?
     MustBeInvoiceMandatory=Mandatory to validate invoices?
     TechnicalServicesProvided=Technical services provided
     #####DAV #####
    -WebDAVSetupDesc=This is the links to access the WebDAV directory. It contains a "public" dir open to any user knowing the URL (if public directory access allowed) and a "private" directory that need an existing login account/password to access to.
    +WebDAVSetupDesc=This is the links to access the WebDAV directory. It contains a "public" dir open to any user knowing the URL (if public directory access allowed) and a "private" directory that need an existing login account/password to access.
     WebDavServer=Root URL of %s server : %s
     ##### Webcal setup #####
     WebCalUrlForVCalExport=An export link to <b>%s</b> format is available at following link: %s
    @@ -1225,6 +1225,7 @@ WebCalUrlForVCalExport=An export link to <b>%s</b> format is available at follow
     BillsSetup=Invoices module setup
     BillsNumberingModule=Invoices and credit notes numbering model
     BillsPDFModules=Invoice documents models
    +BillsPDFModulesAccordindToInvoiceType=Invoice documents models according to invoice type
     PaymentsPDFModules=Payment documents models
     CreditNote=Credit note
     CreditNotes=Credit notes
    @@ -1366,8 +1367,8 @@ LDAPFieldLoginSamba=Login (samba, activedirectory)
     LDAPFieldLoginSambaExample=Example : samaccountname
     LDAPFieldFullname=Full name
     LDAPFieldFullnameExample=Example : cn
    -LDAPFieldPasswordNotCrypted=Password not crypted
    -LDAPFieldPasswordCrypted=Password crypted
    +LDAPFieldPasswordNotCrypted=Password not encrypted
    +LDAPFieldPasswordCrypted=Password encrypted
     LDAPFieldPasswordExample=Example : userPassword
     LDAPFieldCommonNameExample=Example : cn
     LDAPFieldName=Name
    @@ -1415,10 +1416,10 @@ LDAPDescMembersTypes=This page allows you to define LDAP attributes name in LDAP
     LDAPDescValues=Example values are designed for <b>OpenLDAP</b> with following loaded schemas: <b>core.schema, cosine.schema, inetorgperson.schema</b>). If you use thoose values and OpenLDAP, modify your LDAP config file <b>slapd.conf</b> to have all thoose schemas loaded.
     ForANonAnonymousAccess=For an authenticated access (for a write access for example)
     PerfDolibarr=Performance setup/optimizing report
    -YouMayFindPerfAdviceHere=You will find on this page some checks or advice related to performance.
    -NotInstalled=Not installed, so your server is not slow down by this.
    +YouMayFindPerfAdviceHere=This page provides some checks or advice related to performance.
    +NotInstalled=Not installed, so your server is not slowed down by this.
     ApplicativeCache=Applicative cache
    -MemcachedNotAvailable=No applicative cache found. You can enhance performance by installing a cache server Memcached and a module able to use this cache server.<br>More information here <a href="http://wiki.dolibarr.org/index.php/Module_MemCached_EN">http://wiki.dolibarr.org/index.php/Module_MemCached_EN</a>.<br>Note that a lot of web hosting provider does not provide such cache server. 
    +MemcachedNotAvailable=No applicative cache found. You can enhance performance by installing a cache server Memcached and a module able to use this cache server.<br>More information here <a href="http://wiki.dolibarr.org/index.php/Module_MemCached_EN">http://wiki.dolibarr.org/index.php/Module_MemCached_EN</a>.<br>Note that a lot of web hosting provider does not provide such cache server.
     MemcachedModuleAvailableButNotSetup=Module memcached for applicative cache found but setup of module is not complete.
     MemcachedAvailableAndSetup=Module memcached dedicated to use memcached server is enabled.
     OPCodeCache=OPCode cache
    @@ -1433,9 +1434,9 @@ CacheByServerDesc=For example using the Apache directive "ExpiresByType image/gi
     CacheByClient=Cache by browser
     CompressionOfResources=Compression of HTTP responses
     CompressionOfResourcesDesc=For example using the Apache directive "AddOutputFilterByType DEFLATE"
    -TestNotPossibleWithCurrentBrowsers=Such an automatic detection is not possible with current browsers 
    -DefaultValuesDesc=You can define/force here the default value you want to get when you create a new record, and/or default filters or sort order when your list record.
    -DefaultCreateForm=Default values (on forms to create)
    +TestNotPossibleWithCurrentBrowsers=Such an automatic detection is not possible with current browsers
    +DefaultValuesDesc=Here you can define/force the default value you want to have when you create a new record, and/or default filters or sort order when your list records.
    +DefaultCreateForm=Default values (to create on forms)
     DefaultSearchFilters=Default search filters
     DefaultSortOrder=Default sort orders
     DefaultFocus=Default focus fields
    @@ -1445,11 +1446,11 @@ ProductSetup=Products module setup
     ServiceSetup=Services module setup
     ProductServiceSetup=Products and Services modules setup
     NumberOfProductShowInSelect=Max number of products in combos select lists (0=no limit)
    -ViewProductDescInFormAbility=Visualization of product descriptions in the forms (otherwise as popup tooltip)
    +ViewProductDescInFormAbility=Display product descriptions in forms (otherwise as popup tooltip)
     MergePropalProductCard=Activate in product/service Attached Files tab an option to merge product PDF document to proposal PDF azur if product/service is in the proposal
    -ViewProductDescInThirdpartyLanguageAbility=Visualization of products descriptions in the language of the third party
    +ViewProductDescInThirdpartyLanguageAbility=Display products descriptions in the language of the third party
     UseSearchToSelectProductTooltip=Also if you have a large number of products (> 100 000), you can increase speed by setting constant PRODUCT_DONOTSEARCH_ANYWHERE to 1 in Setup->Other. Search will then be limited to start of string.
    -UseSearchToSelectProduct=Wait you press a key before loading content of product combo list (This may increase performance if you have a large number of products, but it is less convenient)
    +UseSearchToSelectProduct=Wait until you press a key before loading content of product combo list (This may increase performance if you have a large number of products, but it is less convenient)
     SetDefaultBarcodeTypeProducts=Default barcode type to use for products
     SetDefaultBarcodeTypeThirdParties=Default barcode type to use for third parties
     UseUnits=Define a unit of measure for Quantity during order, proposal or invoice lines edition
    @@ -1465,7 +1466,7 @@ SyslogFilename=File name and path
     YouCanUseDOL_DATA_ROOT=You can use DOL_DATA_ROOT/dolibarr.log for a log file in Dolibarr "documents" directory. You can set a different path to store this file.
     ErrorUnknownSyslogConstant=Constant %s is not a known Syslog constant
     OnlyWindowsLOG_USER=Windows only supports LOG_USER
    -CompressSyslogs=Compression and backup of debug log files (generated by module Log for debug) 
    +CompressSyslogs=Compression and backup of debug log files (generated by module Log for debug)
     SyslogFileNumberOfSaves=Log backups
     ConfigureCleaningCronjobToSetFrequencyOfSaves=Configure cleaning scheduled job to set log backup frequency
     ##### Donations #####
    @@ -1486,7 +1487,7 @@ BarcodeDescC39=Barcode of type C39
     BarcodeDescC128=Barcode of type C128
     BarcodeDescDATAMATRIX=Barcode of type Datamatrix
     BarcodeDescQRCODE=Barcode of type QR code
    -GenbarcodeLocation=Bar code generation command line tool (used by internal engine for some bar code types). Must be compatible with "genbarcode".<br>For example: /usr/local/bin/genbarcode 
    +GenbarcodeLocation=Bar code generation command line tool (used by internal engine for some bar code types). Must be compatible with "genbarcode".<br>For example: /usr/local/bin/genbarcode
     BarcodeInternalEngine=Internal engine
     BarCodeNumberManager=Manager to auto define barcode numbers
     ##### Prelevements #####
    @@ -1529,7 +1530,7 @@ FCKeditorForMail=WYSIWIG creation/edition for all mail (except Tools->eMailing)
     ##### OSCommerce 1 #####
     OSCommerceErrorConnectOkButWrongDatabase=Connection succeeded but database does not appear to be an OSCommerce database (Key %s not found in table %s).
     OSCommerceTestOk=Connection to server '%s' on database '%s' with user '%s' successful.
    -OSCommerceTestKo1=Connection to server '%s' succeed but database '%s' could not be reached.
    +OSCommerceTestKo1=Connection to server '%s' succeeded but database '%s' could not be reached.
     OSCommerceTestKo2=Connection to server '%s' with user '%s' failed.
     ##### Stock #####
     StockSetup=Stock module setup
    @@ -1563,7 +1564,7 @@ ConfirmDeleteMenu=Are you sure you want to delete menu entry <b>%s</b>?
     FailedToInitializeMenu=Failed to initialize menu
     ##### Tax #####
     TaxSetup=Taxes, social or fiscal taxes and dividends module setup
    -OptionVatMode=VAT due 
    +OptionVatMode=VAT due
     OptionVATDefault=Standard basis
     OptionVATDebitOption=Accrual basis
     OptionVatDefaultDesc=VAT is due:<br>- on delivery for goods (we use invoice date)<br>- on payments for services
    @@ -1582,15 +1583,15 @@ InvoiceDateUsed=Invoice date used
     YourCompanyDoesNotUseVAT=Your company has been defined to not use VAT (Home - Setup - Company/Organization), so there is no VAT options to setup.
     AccountancyCode=Accounting Code
     AccountancyCodeSell=Sale account. code
    -AccountancyCodeBuy=Purchase account. code 
    +AccountancyCodeBuy=Purchase account. code
     ##### Agenda #####
     AgendaSetup=Events and agenda module setup
     PasswordTogetVCalExport=Key to authorize export link
     PastDelayVCalExport=Do not export event older than
    -AGENDA_USE_EVENT_TYPE=Use events types (managed into menu Setup -> Dictionaries -> Type of agenda events)
    -AGENDA_USE_EVENT_TYPE_DEFAULT=Set automatically this default value for type of event into event create form
    -AGENDA_DEFAULT_FILTER_TYPE=Set automatically this type of event into search filter of agenda view
    -AGENDA_DEFAULT_FILTER_STATUS=Set automatically this status for events into search filter of agenda view
    +AGENDA_USE_EVENT_TYPE=Use events types (managed in menu Setup -> Dictionaries -> Type of agenda events)
    +AGENDA_USE_EVENT_TYPE_DEFAULT=Automatically set this default value for type of event in event create form
    +AGENDA_DEFAULT_FILTER_TYPE=Automatically set this type of event in search filter of agenda view
    +AGENDA_DEFAULT_FILTER_STATUS=Automatically set this status for events in search filter of agenda view
     AGENDA_DEFAULT_VIEW=Which tab do you want to open by default when selecting menu Agenda
     AGENDA_REMINDER_EMAIL=Enable event reminder <b>by emails</b> (remind option/delay can be defined on each event). Note: Module <strong>%s</strong> must be enabled and correctly setup to have reminder sent at the correct frequency.
     AGENDA_REMINDER_BROWSER=Enable event reminder <b>on user's browser</b> (when event date is reached, each user is able to refuse this from the browser confirmation question)
    @@ -1599,17 +1600,17 @@ AGENDA_SHOW_LINKED_OBJECT=Show linked object into agenda view
     ##### Clicktodial #####
     ClickToDialSetup=Click To Dial module setup
     ClickToDialUrlDesc=Url called when a click on phone picto is done.  In URL, you can use tags<br><b>__PHONETO__</b> that will be replaced with the phone number of person to call<br><b>__PHONEFROM__</b> that will be replaced with phone number of calling person (yours)<br><b>__LOGIN__</b> that will be replaced with clicktodial login (defined on user card)<br><b>__PASS__</b> that will be replaced with clicktodial password (defined on user card).
    -ClickToDialDesc=This module allows to make phone numbers clickable. A click on this icon will call make your phone to call the phone number. This can be used to call a call center system from Dolibarr that can call the phone number on a SIP system for example.
    +ClickToDialDesc=This module allows to make phone numbers clickable. A click on this icon will call make your phone call the phone number. This can be used to call a call center system from Dolibarr that can call the phone number on a SIP system for example.
     ClickToDialUseTelLink=Use just a link "tel:" on phone numbers
    -ClickToDialUseTelLinkDesc=Use this method if your users have a softphone or a software interface installed on the same computer as the browser, and called when you click on a link in your browser that start with "tel:". If you need a full server solution (no need of local software installation), you must set this to "No" and fill next field.
    +ClickToDialUseTelLinkDesc=Use this method if your users have a softphone or a software interface installed on the same computer as the browser, and called when you click on a link in your browser that starts with "tel:". If you need a full server solution (no need of local software installation), you must set this to "No" and fill next field.
     ##### Point Of Sales (CashDesk) #####
     CashDesk=Point of sales
     CashDeskSetup=Point of sales module setup
    -CashDeskThirdPartyForSell=Default generic third party to use for sells
    +CashDeskThirdPartyForSell=Default generic third party to use for sales
     CashDeskBankAccountForSell=Default account to use to receive cash payments
     CashDeskBankAccountForCheque= Default account to use to receive payments by cheque
     CashDeskBankAccountForCB= Default account to use to receive payments by credit cards
    -CashDeskDoNotDecreaseStock=Disable stock decrease when a sell is done from Point of Sale (if "no", stock decrease is done for each sell done from POS, whatever is option set into module Stock).
    +CashDeskDoNotDecreaseStock=Disable stock decrease when a sale is done from Point of Sale (if "no", stock decrease is done for each sale done from POS, irrespective of the option set in module Stock).
     CashDeskIdWareHouse=Force and restrict warehouse to use for stock decrease
     StockDecreaseForPointOfSaleDisabled=Stock decrease from Point of Sale disabled
     StockDecreaseForPointOfSaleDisabledbyBatch=Stock decrease in POS is not compatible with lot management
    @@ -1630,7 +1631,7 @@ ApiProductionMode=Enable production mode (this will activate use of a cache for
     ApiExporerIs=You can explore and test the APIs at URL
     OnlyActiveElementsAreExposed=Only elements from enabled modules are exposed
     ApiKey=Key for API
    -WarningAPIExplorerDisabled=The API explorer has been disabled. API explorer is not required to provide API services. It is a tool for developer to find/test REST APIs. If you need this tool, go into setup of module API REST to activate it. 
    +WarningAPIExplorerDisabled=The API explorer has been disabled. API explorer is not required to provide API services. It is a tool for developer to find/test REST APIs. If you need this tool, go into setup of module API REST to activate it.
     ##### Bank #####
     BankSetupModule=Bank module setup
     FreeLegalTextOnChequeReceipts=Free text on cheque receipts
    @@ -1682,7 +1683,7 @@ NoAmbiCaracAutoGeneration=Do not use ambiguous characters ("1","l","i","|","0","
     SalariesSetup=Setup of module salaries
     SortOrder=Sort order
     Format=Format
    -TypePaymentDesc=0:Customer payment type, 1:Vendor payment type, 2:Both customers and vendors payment type 
    +TypePaymentDesc=0:Customer payment type, 1:Vendor payment type, 2:Both customers and vendors payment type
     IncludePath=Include path (defined into variable %s)
     ExpenseReportsSetup=Setup of module Expense Reports
     TemplatePDFExpenseReports=Document templates to generate expense report document
    @@ -1694,14 +1695,14 @@ YouMayFindNotificationsFeaturesIntoModuleNotification=You may find options for E
     ListOfNotificationsPerUser=List of notifications per user*
     ListOfNotificationsPerUserOrContact=List of notifications per user* or per contact**
     ListOfFixedNotifications=List of fixed notifications
    -GoOntoUserCardToAddMore=Go on the tab "Notifications" of a user to add or remove notifications for users
    -GoOntoContactCardToAddMore=Go on the tab "Notifications" of a third party to add or remove notifications for contacts/addresses
    +GoOntoUserCardToAddMore=Go to the tab "Notifications" of a user to add or remove notifications for users
    +GoOntoContactCardToAddMore=Go on the tab "Notifications" of a third party to add or remove notifications for contact addresses
     Threshold=Threshold
     BackupDumpWizard=Wizard to build database backup dump file
     SomethingMakeInstallFromWebNotPossible=Installation of external module is not possible from the web interface for the following reason:
    -SomethingMakeInstallFromWebNotPossible2=For this reason, process to upgrade described here is only manual steps a privileged user can do. 
    +SomethingMakeInstallFromWebNotPossible2=For this reason, process to upgrade described here is only manual steps a privileged user can do.
     InstallModuleFromWebHasBeenDisabledByFile=Install of external module from application has been disabled by your administrator. You must ask him to remove the file <strong>%s</strong> to allow this feature.
    -ConfFileMustContainCustom=Installing or building an external module from application need to save the module files into directory <strong>%s</strong>. To have this directory processed by Dolibarr, you must setup your <strong>conf/conf.php</strong> to add the 2 directive lines:<br><strong>$dolibarr_main_url_root_alt='/custom';</strong><br><strong>$dolibarr_main_document_root_alt='%s/custom';</strong> 
    +ConfFileMustContainCustom=Installing or building an external module from application need to save the module files into directory <strong>%s</strong>. To have this directory processed by Dolibarr, you must setup your <strong>conf/conf.php</strong> to add the 2 directive lines:<br><strong>$dolibarr_main_url_root_alt='/custom';</strong><br><strong>$dolibarr_main_document_root_alt='%s/custom';</strong>
     HighlightLinesOnMouseHover=Highlight table lines when mouse move passes over
     HighlightLinesColor=Highlight color of the line when the mouse passes over (keep empty for no highlight)
     HighlightLinesChecked=Highlight color of the line when it is checked (keep empty for no highlight)
    @@ -1729,7 +1730,7 @@ UrlTrackingDesc=If the provider or transport service offer a page or web site to
     OpportunityPercent=When you create a lead, you will define an estimated amount of project/lead. According to status of lead, this amount may be multiplied by this rate to evaluate global amount all your opportunities may generate. Value is percent (between 0 and 100).
     TemplateForElement=This template record is dedicated to which element
     TypeOfTemplate=Type of template
    -TemplateIsVisibleByOwnerOnly=Template is visible by owner only
    +TemplateIsVisibleByOwnerOnly=Template is visible to owner only
     VisibleEverywhere=Visible everywhere
     VisibleNowhere=Visible nowhere
     FixTZ=TimeZone fix
    @@ -1755,10 +1756,10 @@ YouUseLastStableVersion=You use the latest stable version
     TitleExampleForMajorRelease=Example of message you can use to announce this major release (feel free to use it on your web sites)
     TitleExampleForMaintenanceRelease=Example of message you can use to announce this maintenance release (feel free to use it on your web sites)
     ExampleOfNewsMessageForMajorRelease=Dolibarr ERP & CRM %s is available. Version %s is a major release with a lot of new features for both users and developers. You can download it from the download area of https://www.dolibarr.org portal (subdirectory Stable versions). You can read <a href="https://github.com/Dolibarr/dolibarr/blob/develop/ChangeLog">ChangeLog</a> for complete list of changes.
    -ExampleOfNewsMessageForMaintenanceRelease=Dolibarr ERP & CRM %s is available. Version %s is a maintenance version, so it contains only fixes of bugs. We recommend everybody using an older version to upgrade to this one. As any maintenance release, no new features, nor data structure change is present into this version. You can download it from the download area of https://www.dolibarr.org portal (subdirectory Stable versions). You can read <a href="https://github.com/Dolibarr/dolibarr/blob/develop/ChangeLog">ChangeLog</a> for complete list of changes.
    -MultiPriceRuleDesc=When option "Several level of prices per product/service" is on, you can define different prices (one per price level) for each product. To save you time, you can enter here rule to have price for each level autocalculated according to price of first level, so you will have to enter only price for first level on each product. This page is here to save you time and can be useful only if your prices for each level are relative to first level. You can ignore this page in most cases.
    +ExampleOfNewsMessageForMaintenanceRelease=Dolibarr ERP & CRM %s is available. Version %s is a maintenance version, so it contains only fixes of bugs. We recommend everybody using an older version to upgrade to this one. As any maintenance release, no new features or data structure change is present in this version. You can download it from the download area of https://www.dolibarr.org portal (subdirectory Stable versions). You can read <a href="https://github.com/Dolibarr/dolibarr/blob/develop/ChangeLog">ChangeLog</a> for complete list of changes.
    +MultiPriceRuleDesc=When option "Several level of prices per product/service" is on, you can define different prices (one per price level) for each product. To save you time, here you can enter a rule to have a price for each level autocalculated according to the price of first level, so you will have to only enter a price for the first level on each product. This page is here to save you time and can be useful only if your prices for each level are relative to first level. You can ignore this page in most cases.
     ModelModulesProduct=Templates for product documents
    -ToGenerateCodeDefineAutomaticRuleFirst=To be able to generate automatically codes, you must first define a manager to auto define barcode number.
    +ToGenerateCodeDefineAutomaticRuleFirst=To be able to generate codes automatically, you must first define a manager to auto define barcode number.
     SeeSubstitutionVars=See * note for list of possible substitution variables
     SeeChangeLog=See ChangeLog file (english only)
     AllPublishers=All publishers
    @@ -1779,19 +1780,19 @@ AddOtherPagesOrServices=Add other pages or services
     AddModels=Add document or numbering templates
     AddSubstitutions=Add keys substitutions
     DetectionNotPossible=Detection not possible
    -UrlToGetKeyToUseAPIs=Url to get token to use API (once token has been received it is saved on database user table and must be provided on each API call) 
    +UrlToGetKeyToUseAPIs=Url to get token to use API (once token has been received it is saved in database user table and must be provided on each API call)
     ListOfAvailableAPIs=List of available APIs
     activateModuleDependNotSatisfied=Module "%s" depends on module "%s", that is missing, so module "%1$s" may not work correctly. Please install module "%2$s" or disable module "%1$s" if you want to be safe from any surprise
    -CommandIsNotInsideAllowedCommands=The command you try to run is not in the list of allowed commands defined into parameter <strong>$dolibarr_main_restrict_os_commands</strong> in the <strong>conf.php</strong> file.
    +CommandIsNotInsideAllowedCommands=The command you are trying to run is not in the list of allowed commands defined in parameter <strong>$dolibarr_main_restrict_os_commands</strong> in the <strong>conf.php</strong> file.
     LandingPage=Landing page
    -SamePriceAlsoForSharedCompanies=If you use a multicompany module, with the choice "Single price", price will be also the same for all companies if products are shared between environments
    +SamePriceAlsoForSharedCompanies=If you use a multicompany module, with the choice "Single price", the price will also be the same for all companies if products are shared between environments
     ModuleEnabledAdminMustCheckRights=Module has been activated. Permissions for activated module(s) were given to admin users only. You may need to grant permissions to other users or groups manually if necessary.
    -UserHasNoPermissions=This user has no permission defined
    +UserHasNoPermissions=This user has no permissions defined
     TypeCdr=Use "None" if the date of payment term is date of invoice plus a delta in days (delta is field "%s")<br>Use "At end of month", if, after delta, the date must be increased to reach the end of month (+ an optional "%s" in days)<br>Use "Current/Next" to have payment term date being the first Nth of the month after delta (delta is field "%s", N is stored into field "%s")
     BaseCurrency=Reference currency of the company (go into setup of company to change this)
    -WarningNoteModuleInvoiceForFrenchLaw=This module %s is compliant with french laws (Loi Finance 2016). 
    -WarningNoteModulePOSForFrenchLaw=This module %s is compliant with french laws (Loi Finance 2016) because module Non Reversible Logs is automatically activated. 
    -WarningInstallationMayBecomeNotCompliantWithLaw=You are trying to install module %s that is an external module. Activating an external module means you trust the publisher of that module and that you are sure that this module does not impact adversely the behavior of your application, and is compliant with laws of your country (%s). If the module introduces an illegal feature, you become responsible for the use of a illegal software.
    +WarningNoteModuleInvoiceForFrenchLaw=This module %s is compliant with French laws (Loi Finance 2016).
    +WarningNoteModulePOSForFrenchLaw=This module %s is compliant with French laws (Loi Finance 2016) because module Non Reversible Logs is automatically activated.
    +WarningInstallationMayBecomeNotCompliantWithLaw=You are trying to install module %s that is an external module. Activating an external module means you trust the publisher of that module and that you are sure that this module does not adversely impact the behavior of your application, and is compliant with laws of your country (%s). If the module introduces an illegal feature, you become responsible for the use of illegal software.
     MAIN_PDF_MARGIN_LEFT=Left margin on PDF
     MAIN_PDF_MARGIN_RIGHT=Right margin on PDF
     MAIN_PDF_MARGIN_TOP=Top margin on PDF
    @@ -1802,10 +1803,10 @@ EnterCalculationRuleIfPreviousFieldIsYes=Enter calculation rule if previous fiel
     SeveralLangugeVariatFound=Several language variants found
     COMPANY_AQUARIUM_REMOVE_SPECIAL=Remove special characters
     COMPANY_AQUARIUM_CLEAN_REGEX=Regex filter to clean value (COMPANY_AQUARIUM_CLEAN_REGEX)
    -GDPRContact=Privacy Policies or GDPR contact
    -GDPRContactDesc=If you store data about European companies/citizen, you can store here the contact who is responsible for the General Data Protection Regulation
    +GDPRContact=Data Protection Officer (DPO, Data Privacy or GDPR contact)
    +GDPRContactDesc=If you store data about European companies/citizen, you can store the contact who is responsible for the General Data Protection Regulation here
     HelpOnTooltip=Help text to show on tooltip
    -HelpOnTooltipDesc=Put here a text or a translation key for a text to show on a tooltip when this field appears into a form
    +HelpOnTooltipDesc=Put text or a translation key here for the text to show on a tooltip when this field appears in a form
     YouCanDeleteFileOnServerWith=You can delete this file on server with Command Line:<br>%s
     ChartLoaded=Chart of account loaded
     SocialNetworkSetup=Setup of module Social Networks
    @@ -1814,9 +1815,10 @@ VATIsUsedIsOff=Note: The option to use sales Tax or VAT has been set to <strong>
     SwapSenderAndRecipientOnPDF=Swap sender and recipient address on PDF
     FeatureSupportedOnTextFieldsOnly=Warning, feature supported on text fields only
     ##### Resource ####
    -ResourceSetup=Configuration du module Resource 
    +ResourceSetup=Configuration du module Resource
     UseSearchToSelectResource=Use a search form to choose a resource (rather than a drop-down list).
     DisabledResourceLinkUser=Disable feature to link a resource to users
     DisabledResourceLinkContact=Disable feature to link a resource to contacts
     ConfirmUnactivation=Confirm module reset
     OnMobileOnly=On small screen (smartphone) only
    +DisableProspectCustomerType=Disable the "Prospect + Customer" third party type (so third party must be Prospect or Customer but can't be both)
    diff --git a/htdocs/langs/en_US/agenda.lang b/htdocs/langs/en_US/agenda.lang
    index a68bac6d961..cd39a43abe8 100644
    --- a/htdocs/langs/en_US/agenda.lang
    +++ b/htdocs/langs/en_US/agenda.lang
    @@ -1,12 +1,12 @@
    -# Dolibarr language file - Source file is en_US - agenda 
    +# Dolibarr language file - Source file is en_US - agenda
     IdAgenda=ID event
     Actions=Events
     Agenda=Agenda
     TMenuAgenda=Agenda
     Agendas=Agendas
     LocalAgenda=Internal calendar
    -ActionsOwnedBy=Event owned by 
    -ActionsOwnedByShort=Owner 
    +ActionsOwnedBy=Event owned by
    +ActionsOwnedByShort=Owner
     AffectedTo=Assigned to
     Event=Event
     Events=Events
    @@ -31,8 +31,8 @@ ViewWeek=Week view
     ViewPerUser=Per user view
     ViewPerType=Per type view
     AutoActions= Automatic filling
    -AgendaAutoActionDesc= Define here events for which you want Dolibarr to create automatically an event in agenda. If nothing is checked, only manual actions will be included in logged and visible into agenda. Automatic tracking of business actions done on objects (validation, status change) will not be saved. 
    -AgendaSetupOtherDesc= This page provides options to allow export of your Dolibarr events into an external calendar (thunderbird, google calendar, ...)
    +AgendaAutoActionDesc= Here you can define events which you want Dolibarr to create automatically  in Agenda. If nothing is checked, only manual actions will be included in logs and displayed in Agenda. Automatic tracking of business actions done on objects (validation, status change) will not be saved.
    +AgendaSetupOtherDesc= This page provides options to allow exports of your Dolibarr events into an external calendar (thunderbird, google calendar, ...)
     AgendaExtSitesDesc=This page allows to declare external sources of calendars to see their events into Dolibarr agenda.
     ActionsEvents=Events for which Dolibarr will create an action in agenda automatically
     EventRemindersByEmailNotEnabled=Event reminders by email was not enabled into %s module setup.
    @@ -111,7 +111,7 @@ DefaultWorkingHours=Default working hours in day (Example: 9-18)
     # External Sites ical
     ExportCal=Export calendar
     ExtSites=Import external calendars
    -ExtSitesEnableThisTool=Show external calendars (defined into global setup) into agenda. Does not affect external calendars defined by users.
    +ExtSitesEnableThisTool=Show external calendars (defined in global setup) in Agenda. Does not affect external calendars defined by users.
     ExtSitesNbOfAgenda=Number of calendars
     AgendaExtNb=Calendar no. %s
     ExtSiteUrlAgenda=URL to access .ical file
    diff --git a/htdocs/langs/en_US/banks.lang b/htdocs/langs/en_US/banks.lang
    index 4b9e95877aa..7650613341e 100644
    --- a/htdocs/langs/en_US/banks.lang
    +++ b/htdocs/langs/en_US/banks.lang
    @@ -46,7 +46,7 @@ BankAccountDomiciliation=Account address
     BankAccountCountry=Account country
     BankAccountOwner=Account owner name
     BankAccountOwnerAddress=Account owner address
    -RIBControlError=Integrity check of values fails. This means information for this account number are not complete or wrong (check country, numbers and IBAN).
    +RIBControlError=Integrity check of values fails. This means the information for this account number is incomplete or incorrect (check country, numbers and IBAN).
     CreateAccount=Create account
     NewBankAccount=New account
     NewFinancialAccount=New financial account
    @@ -76,6 +76,7 @@ TransactionsToConciliate=Entries to reconcile
     Conciliable=Can be reconciled
     Conciliate=Reconcile
     Conciliation=Reconciliation
    +SaveStatementOnly=Save statement only
     ReconciliationLate=Reconciliation late
     IncludeClosedAccount=Include closed accounts
     OnlyOpenedAccount=Only open accounts
    @@ -104,7 +105,7 @@ SocialContributionPayment=Social/fiscal tax payment
     BankTransfer=Bank transfer
     BankTransfers=Bank transfers
     MenuBankInternalTransfer=Internal transfer
    -TransferDesc=Transfer from one account to another one, Dolibarr will write two record (a debit in source account and a credit in target account. The same amount (except sign), label and date will be used for this transaction)
    +TransferDesc=Transfer from one account to another one, Dolibarr will write two records (a debit in source account and a credit in target account). The same amount (except sign), label and date will be used for this transaction)
     TransferFrom=From
     TransferTo=To
     TransferFromToDone=A transfer from <b>%s</b> to <b>%s</b> of <b>%s</b> %s has been recorded.
    @@ -135,8 +136,8 @@ BankTransactionLine=Bank entry
     AllAccounts=All bank and cash accounts
     BackToAccount=Back to account
     ShowAllAccounts=Show for all accounts
    -FutureTransaction=Transaction in futur. No way to conciliate.
    -SelectChequeTransactionAndGenerate=Select/filter checks to include into the check deposit receipt and click on "Create".
    +FutureTransaction=Transaction in future. No way to reconcile.
    +SelectChequeTransactionAndGenerate=Select/filter checks to include in the check deposit receipt and click on "Create".
     InputReceiptNumber=Choose the bank statement related with the conciliation. Use a sortable numeric value: YYYYMM or YYYYMMDD
     EventualyAddCategory=Eventually, specify a category in which to classify the records
     ToConciliate=To reconcile?
    @@ -162,4 +163,4 @@ ShowVariousPayment=Show miscellaneous payments
     AddVariousPayment=Add miscellaneous payments
     SEPAMandate=SEPA mandate
     YourSEPAMandate=Your SEPA mandate
    -FindYourSEPAMandate=This is your SEPA mandate to authorize our company to make direct debit order to your bank. Thanks to return it signed (scan of the signed document) or sent it by mail to 
    +FindYourSEPAMandate=This is your SEPA mandate to authorize our company to make direct debit order to your bank. Return it signed (scan of the signed document) or send it by mail to
    diff --git a/htdocs/langs/en_US/bills.lang b/htdocs/langs/en_US/bills.lang
    index 0eb53d1af98..9e3d2a4af98 100644
    --- a/htdocs/langs/en_US/bills.lang
    +++ b/htdocs/langs/en_US/bills.lang
    @@ -25,12 +25,12 @@ InvoiceProFormaAsk=Proforma invoice
     InvoiceProFormaDesc=<b>Proforma invoice</b> is an image of a true invoice but has no accountancy value.
     InvoiceReplacement=Replacement invoice
     InvoiceReplacementAsk=Replacement invoice for invoice
    -InvoiceReplacementDesc=<b>Replacement invoice</b> is used to cancel and replace completely an invoice with no payment already received.<br><br>Note: Only invoices with no payment on it can be replaced. If the invoice you replace is not yet closed, it will be automatically closed to 'abandoned'.
    +InvoiceReplacementDesc=<b>Replacement invoice</b> is used to cancel and completely replace an invoice with no payment already received.<br><br>Note: Only invoices with no payment on it can be replaced. If the invoice you replace is not yet closed, it will be automatically closed to 'abandoned'.
     InvoiceAvoir=Credit note
     InvoiceAvoirAsk=Credit note to correct invoice
    -InvoiceAvoirDesc=The <b>credit note</b> is a negative invoice used to solve fact that an invoice has an amount that differs than amount really paid (because customer paid too much by error, or will not paid completely since he returned some products for example).
    +InvoiceAvoirDesc=The <b>credit note</b> is a negative invoice used to correct the fact that an invoice has an amount that differs from the amount really paid (eg customer paid too much by mistake, or will not pay completely since he returned some products).
     invoiceAvoirWithLines=Create Credit Note with lines from the origin invoice
    -invoiceAvoirWithPaymentRestAmount=Create Credit Note with remaining unpaid of origin invoice 
    +invoiceAvoirWithPaymentRestAmount=Create Credit Note with remaining unpaid of origin invoice
     invoiceAvoirLineWithPaymentRestAmount=Credit Note for remaining unpaid amount
     ReplaceInvoice=Replace invoice %s
     ReplacementInvoice=Replacement invoice
    @@ -66,12 +66,12 @@ paymentInInvoiceCurrency=in invoices currency
     PaidBack=Paid back
     DeletePayment=Delete payment
     ConfirmDeletePayment=Are you sure you want to delete this payment?
    -ConfirmConvertToReduc=Do you want to convert this %s into an absolute discount ?<br>The amount will so be saved among all discounts and could be used as a discount for a current or a future invoice for this customer.
    -ConfirmConvertToReducSupplier=Do you want to convert this %s into an absolute discount ?<br>The amount will so be saved among all discounts and could be used as a discount for a current or a future invoice for this supplier.
    +ConfirmConvertToReduc=Do you want to convert this %s into an absolute discount?<br>The amount will be saved among all discounts and could be used as a discount for a current or a future invoice for this customer.
    +ConfirmConvertToReducSupplier=Do you want to convert this %s into an absolute discount?<br>The amount will be saved among all discounts and could be used as a discount for a current or a future invoice for this supplier.
     SupplierPayments=Suppliers payments
     ReceivedPayments=Received payments
     ReceivedCustomersPayments=Payments received from customers
    -PayedSuppliersPayments=Payments payed to suppliers
    +PayedSuppliersPayments=Payments paid to suppliers
     ReceivedCustomersPaymentsToValid=Received customers payments to validate
     PaymentsReportsForYear=Payments reports for %s
     PaymentsReports=Payments reports
    @@ -91,8 +91,8 @@ PaymentConditionsShort=Payment terms
     PaymentAmount=Payment amount
     ValidatePayment=Validate payment
     PaymentHigherThanReminderToPay=Payment higher than reminder to pay
    -HelpPaymentHigherThanReminderToPay=Attention, the payment amount of one or more bills is higher than the rest to pay. <br> Edit your entry, otherwise confirm and think about creating a credit note of the excess received for each overpaid invoice.
    -HelpPaymentHigherThanReminderToPaySupplier=Attention, the payment amount of one or more bills is higher than the rest to pay. <br> Edit your entry, otherwise confirm and think about creating a credit note of the excess paid for each overpaid invoice.
    +HelpPaymentHigherThanReminderToPay=Attention, the payment amount of one or more bills is higher than the outstanding amount to pay. <br> Edit your entry, otherwise confirm and consider creating a credit note for the excess received for each overpaid invoice.
    +HelpPaymentHigherThanReminderToPaySupplier=Attention, the payment amount of one or more bills is higher than the outstanding amount to pay. <br> Edit your entry, otherwise confirm and consider creating a credit note for the excess paid for each overpaid invoice.
     ClassifyPaid=Classify 'Paid'
     ClassifyPaidPartially=Classify 'Paid partially'
     ClassifyCanceled=Classify 'Abandoned'
    @@ -146,7 +146,7 @@ ErrorVATIntraNotConfigured=Intra-Community VAT number not yet defined
     ErrorNoPaiementModeConfigured=No default payment mode defined. Go to Invoice module setup to fix this.
     ErrorCreateBankAccount=Create a bank account, then go to Setup panel of Invoice module to define payment modes
     ErrorBillNotFound=Invoice %s does not exist
    -ErrorInvoiceAlreadyReplaced=Error, you try to validate an invoice to replace invoice %s. But this one has already been replaced by invoice %s.
    +ErrorInvoiceAlreadyReplaced=Error, you tried to validate an invoice to replace invoice %s. But this one has already been replaced by invoice %s.
     ErrorDiscountAlreadyUsed=Error, discount already used
     ErrorInvoiceAvoirMustBeNegative=Error, correct invoice must have a negative amount
     ErrorInvoiceOfThisTypeMustBePositive=Error, this type of invoice must have a positive amount
    @@ -180,20 +180,20 @@ ConfirmClassifyPaidBill=Are you sure you want to change invoice <b>%s</b> to sta
     ConfirmCancelBill=Are you sure you want to cancel invoice <b>%s</b>?
     ConfirmCancelBillQuestion=Why do you want to classify this invoice 'abandoned'?
     ConfirmClassifyPaidPartially=Are you sure you want to change invoice <b>%s</b> to status paid?
    -ConfirmClassifyPaidPartiallyQuestion=This invoice has not been paid completely. What are reasons for you to close this invoice?
    +ConfirmClassifyPaidPartiallyQuestion=This invoice has not been paid completely. What is the reason/s for you closing this invoice?
     ConfirmClassifyPaidPartiallyReasonAvoir=Remaining unpaid <b>(%s %s)</b> is a discount granted because payment was made before term. I regularize the VAT with a credit note.
     ConfirmClassifyPaidPartiallyReasonDiscount=Remaining unpaid <b>(%s %s)</b> is a discount granted because payment was made before term.
     ConfirmClassifyPaidPartiallyReasonDiscountNoVat=Remaining unpaid <b>(%s %s)</b> is a discount granted because payment was made before term. I accept to lose the VAT on this discount.
    -ConfirmClassifyPaidPartiallyReasonDiscountVat=Remaining unpaid <b>(%s %s)</b> is a discount granted because payment was made before term. I recover the VAT on this discount without a credit note. 
    +ConfirmClassifyPaidPartiallyReasonDiscountVat=Remaining unpaid <b>(%s %s)</b> is a discount granted because payment was made before term. I recover the VAT on this discount without a credit note.
     ConfirmClassifyPaidPartiallyReasonBadCustomer=Bad customer
     ConfirmClassifyPaidPartiallyReasonProductReturned=Products partially returned
     ConfirmClassifyPaidPartiallyReasonOther=Amount abandoned for other reason
    -ConfirmClassifyPaidPartiallyReasonDiscountNoVatDesc=This choice is possible if your invoice has been provided with suitable comment. (Example «Only the tax corresponding to the price that has been actually paid gives rights to deduction»)
    -ConfirmClassifyPaidPartiallyReasonDiscountVatDesc=In some countries, this choice might be possible only if your invoice contains correct note.
    +ConfirmClassifyPaidPartiallyReasonDiscountNoVatDesc=This choice is possible if your invoice has been provided with suitable comments. (Example «Only the tax corresponding to the price that has been actually paid gives rights to deduction»)
    +ConfirmClassifyPaidPartiallyReasonDiscountVatDesc=In some countries, this choice might be possible only if your invoice contains correct notes.
     ConfirmClassifyPaidPartiallyReasonAvoirDesc=Use this choice if all other does not suit
    -ConfirmClassifyPaidPartiallyReasonBadCustomerDesc=A <b>bad customer</b> is a customer that refuse to pay his debt.
    +ConfirmClassifyPaidPartiallyReasonBadCustomerDesc=A <b>bad customer</b> is a customer that refuses to pay his debt.
     ConfirmClassifyPaidPartiallyReasonProductReturnedDesc=This choice is used when payment is not complete because some of products were returned
    -ConfirmClassifyPaidPartiallyReasonOtherDesc=Use this choice if all other does not suit, for example in following situation:<br>- payment not complete because some products were shipped back<br>- amount claimed too important because a discount was forgotten<br>In all cases, amount over-claimed must be corrected in accountancy system by creating a credit note.
    +ConfirmClassifyPaidPartiallyReasonOtherDesc=Use this choice if all others are not suitable, for example in following situation:<br>- payment not complete because some products were shipped back<br>- amount claimed too important because a discount was forgotten<br>In all cases, amount over-claimed must be corrected in accountancy system by creating a credit note.
     ConfirmClassifyAbandonReasonOther=Other
     ConfirmClassifyAbandonReasonOtherDesc=This choice will be used in all other cases. For example because you plan to create a replacing invoice.
     ConfirmCustomerPayment=Do you confirm this payment input for <b>%s</b> %s?
    @@ -304,8 +304,8 @@ DiscountAlreadyCounted=Discounts or credits already consumed
     CustomerDiscounts=Customer discounts
     SupplierDiscounts=Vendors discounts
     BillAddress=Bill address
    -HelpEscompte=This discount is a discount granted to customer because its payment was made before term.
    -HelpAbandonBadCustomer=This amount has been abandoned (customer said to be a bad customer) and is considered as an exceptional loose.
    +HelpEscompte=This discount is a discount granted to customer because payment was made before term.
    +HelpAbandonBadCustomer=This amount has been abandoned (customer said to be a bad customer) and is considered as an exceptional loss.
     HelpAbandonOther=This amount has been abandoned since it was an error (wrong customer or invoice replaced by another for example)
     IdSocialContribution=Social/fiscal tax payment id
     PaymentId=Payment id
    @@ -323,19 +323,19 @@ InvoiceNotChecked=No invoice selected
     CloneInvoice=Clone invoice
     ConfirmCloneInvoice=Are you sure you want to clone this invoice <b>%s</b>?
     DisabledBecauseReplacedInvoice=Action disabled because invoice has been replaced
    -DescTaxAndDividendsArea=This area presents a summary of all payments made for special expenses. Only record with payment during the fixed year are included here.
    +DescTaxAndDividendsArea=This area presents a summary of all payments made for special expenses. Only records with payment during the fixed year are included here.
     NbOfPayments=No. of payments
     SplitDiscount=Split discount in two
    -ConfirmSplitDiscount=Are you sure you want to split this discount of <b>%s</b> %s into 2 lower discounts?
    +ConfirmSplitDiscount=Are you sure you want to split this discount of <b>%s</b> %s into 2 smaller discounts?
     TypeAmountOfEachNewDiscount=Input amount for each of two parts:
    -TotalOfTwoDiscountMustEqualsOriginal=Total of two new discount must be equal to original discount amount. 
    +TotalOfTwoDiscountMustEqualsOriginal=Total of two new discounts must be equal to original discount amount.
     ConfirmRemoveDiscount=Are you sure you want to remove this discount?
     RelatedBill=Related invoice
     RelatedBills=Related invoices
     RelatedCustomerInvoices=Related customer invoices
     RelatedSupplierInvoices=Related supplier invoices
     LatestRelatedBill=Latest related invoice
    -WarningBillExist=Warning, one or more invoice already exist
    +WarningBillExist=Warning, one or more invoices already exist
     MergingPDFTool=Merging PDF tool
     AmountPaymentDistributedOnInvoice=Payment amount distributed on invoice
     PaymentOnDifferentThirdBills=Allow payments on different third parties bills but same parent company
    @@ -346,7 +346,7 @@ ListOfSituationInvoices=List of situation invoices
     CurrentSituationTotal=Total current situation
     DisabledBecauseNotEnouthCreditNote=To remove a situation invoice from cycle, this invoice's credit note total must cover this invoice total
     RemoveSituationFromCycle=Remove this invoice from cycle
    -ConfirmRemoveSituationFromCycle=Remove this invoice %s from cycle ? 
    +ConfirmRemoveSituationFromCycle=Remove this invoice %s from cycle ?
     ConfirmOuting=Confirm outing
     FrequencyPer_d=Every %s days
     FrequencyPer_m=Every %s months
    @@ -410,8 +410,8 @@ PaymentTypeCHQ=Check
     PaymentTypeShortCHQ=Check
     PaymentTypeTIP=TIP (Documents against Payment)
     PaymentTypeShortTIP=TIP Payment
    -PaymentTypeVAD=On line payment
    -PaymentTypeShortVAD=On line payment
    +PaymentTypeVAD=Online payment
    +PaymentTypeShortVAD=Online payment
     PaymentTypeTRA=Bank draft
     PaymentTypeShortTRA=Draft
     PaymentTypeFAC=Factor
    @@ -438,7 +438,7 @@ NetToBePaid=Net to be paid
     PhoneNumber=Tel
     FullPhoneNumber=Telephone
     TeleFax=Fax
    -PrettyLittleSentence=Accept the amount of payments due by checks issued in my name as a Member of an accounting association approved by the Fiscal Administration.  
    +PrettyLittleSentence=Accept the amount of payments due by checks issued in my name as a Member of an accounting association approved by the Fiscal Administration.
     IntracommunityVATNumber=Intracommunity number of VAT
     PaymentByChequeOrderedTo=Check payment (including tax) are payable to %s send to
     PaymentByChequeOrderedToShort=Check payment (including tax) are payable to
    @@ -447,7 +447,7 @@ PaymentByTransferOnThisBankAccount=Payment by transfer on the following bank acc
     VATIsNotUsedForInvoice=* Non applicable VAT art-293B of CGI
     LawApplicationPart1=By application of the law 80.335 of 12/05/80
     LawApplicationPart2=the goods remain the property of
    -LawApplicationPart3=the seller until the complete cashing of
    +LawApplicationPart3=the seller until full payment of
     LawApplicationPart4=their price.
     LimitedLiabilityCompanyCapital=SARL with Capital of
     UseLine=Apply
    @@ -476,21 +476,22 @@ Reported=Delayed
     DisabledBecausePayments=Not possible since there are some payments
     CantRemovePaymentWithOneInvoicePaid=Can't remove payment since there is at least one invoice classified paid
     ExpectedToPay=Expected payment
    -CantRemoveConciliatedPayment=Can't remove conciliated payment
    +CantRemoveConciliatedPayment=Can't remove reconciled payment
     PayedByThisPayment=Paid by this payment
    -ClosePaidInvoicesAutomatically=Classify "Paid" all standard, down payment or replacement invoices entirely paid.
    +ClosePaidInvoicesAutomatically=Classify "Paid" all standard, down payment or replacement invoices paid entirely.
     ClosePaidCreditNotesAutomatically=Classify "Paid" all credit notes entirely paid back.
    -ClosePaidContributionsAutomatically=Classify "Paid" all social or fiscal contributions entirely paid.
    -AllCompletelyPayedInvoiceWillBeClosed=All invoice with no remain to pay will be automatically closed to status "Paid".
    +ClosePaidContributionsAutomatically=Classify "Paid" all social or fiscal contributions paid entirely.
    +AllCompletelyPayedInvoiceWillBeClosed=All invoice with no remainder to pay will be automatically closed with status "Paid".
     ToMakePayment=Pay
     ToMakePaymentBack=Pay back
     ListOfYourUnpaidInvoices=List of unpaid invoices
     NoteListOfYourUnpaidInvoices=Note: This list contains only invoices for third parties you are linked to as a sale representative.
     RevenueStamp=Revenue stamp
    -YouMustCreateInvoiceFromThird=This option is only available when creating invoice from tab "customer" of third party
    -YouMustCreateInvoiceFromSupplierThird=This option is only available when creating invoice from tab "supplier" of third party
    +YouMustCreateInvoiceFromThird=This option is only available when creating invoices from tab "customer" of third party
    +YouMustCreateInvoiceFromSupplierThird=This option is only available when creating invoices from tab "supplier" of third party
     YouMustCreateStandardInvoiceFirstDesc=You have to create a standard invoice first and convert it to "template" to create a new template invoice
     PDFCrabeDescription=Invoice PDF template Crabe. A complete invoice template (recommended Template)
    +PDFSpongeDescription=Invoice PDF template Sponge. A complete invoice template
     PDFCrevetteDescription=Invoice PDF template Crevette. A complete invoice template for situation invoices
     TerreNumRefModelDesc1=Return number with format %syymm-nnnn for standard invoices and %syymm-nnnn for credit notes where yy is year, mm is month and nnnn is a sequence with no break and no return to 0
     MarsNumRefModelDesc1=Return number with format %syymm-nnnn for standard invoices, %syymm-nnnn for replacement invoices, %syymm-nnnn for down payment invoices and %syymm-nnnn for credit notes where yy is year, mm is month and nnnn is a sequence with no break and no return to 0
    @@ -535,7 +536,7 @@ invoiceLineProgressError=Invoice line progress can't be greater than or equal to
     updatePriceNextInvoiceErrorUpdateline=Error : update price on invoice line : %s
     ToCreateARecurringInvoice=To create a recurring invoice for this contract, first create this draft invoice, then convert it into an invoice template and define the frequency for generation of future invoices.
     ToCreateARecurringInvoiceGene=To generate future invoices regularly and manually, just go on menu <strong>%s - %s - %s</strong>.
    -ToCreateARecurringInvoiceGeneAuto=If you need to have such invoices generated automatically, ask you administrator to enable and setup module <strong>%s</strong>. Note that both method (manual and automatic) can be used together with no risk of duplication.
    +ToCreateARecurringInvoiceGeneAuto=If you need to have such invoices generated automatically, ask your administrator to enable and setup module <strong>%s</strong>. Note that both method (manual and automatic) can be used together with no risk of duplication.
     DeleteRepeatableInvoice=Delete template invoice
     ConfirmDeleteRepeatableInvoice=Are your sure you want to delete the template invoice?
     CreateOneBillByThird=Create one invoice per third party (otherwise, one invoice per order)
    diff --git a/htdocs/langs/en_US/blockedlog.lang b/htdocs/langs/en_US/blockedlog.lang
    index fb52e8476ee..88d3662be9c 100644
    --- a/htdocs/langs/en_US/blockedlog.lang
    +++ b/htdocs/langs/en_US/blockedlog.lang
    @@ -8,7 +8,7 @@ BrowseBlockedLog=Unalterable logs
     ShowAllFingerPrintsMightBeTooLong=Show all archived logs (might be long)
     ShowAllFingerPrintsErrorsMightBeTooLong=Show all non-valid archive logs (might be long)
     DownloadBlockChain=Download fingerprints
    -KoCheckFingerprintValidity=Archived log is not valid. It means someone (a hacker?) has modified some datas of this archived log after it was recorded, or has erased the previous archived record (check that line with previous # exists).
    +KoCheckFingerprintValidity=Archived log is not valid. It means someone (a hacker?) has modified some data of this archived log after it was recorded, or has erased the previous archived record (check that line with previous # exists).
     OkCheckFingerprintValidity=Archived log is valid. It means all data on this line were not modified and record follow the previous one.
     OkCheckFingerprintValidityButChainIsKo=Archived log seems valid compared to previous one but the chain was corrupted previously.
     AddedByAuthority=Stored into remote authority
    @@ -22,7 +22,7 @@ logPAYMENT_CUSTOMER_CREATE=Customer payment created
     logPAYMENT_CUSTOMER_DELETE=Customer payment logical deletion
     logDONATION_PAYMENT_CREATE=Donation payment created
     logDONATION_PAYMENT_DELETE=Donation payment logical deletion
    -logBILL_PAYED=Customer invoice payed
    +logBILL_PAYED=Customer invoice paid
     logBILL_UNPAYED=Customer invoice set unpaid
     logBILL_VALIDATE=Customer invoice validated
     logBILL_SENTBYMAIL=Customer invoice send by mail
    @@ -49,5 +49,5 @@ BlockedLogAreRequiredByYourCountryLegislation=Unalterable Logs module may be req
     BlockedLogActivatedBecauseRequiredByYourCountryLegislation=Unalterable Logs module was activated because of the legislation of your country. Disabling this module may render any future transactions invalid with respect to the law and the use of legal software as they cannot be validated by a tax audit.
     BlockedLogDisableNotAllowedForCountry=List of countries where usage of this module is mandatory (just to prevent to disable the module by error, if your country is in this list, disable of module is not possible without editing this list first. Note also that enabling/disabling this module will keep a track into the unalterable log).
     OnlyNonValid=Non-valid
    -TooManyRecordToScanRestrictFilters=Too many record to scan/analyze. Please restrict list with more restrictive filters.
    +TooManyRecordToScanRestrictFilters=Too many records to scan/analyze. Please restrict list with more restrictive filters.
     RestrictYearToExport=Restrict month / year to export
    diff --git a/htdocs/langs/en_US/boxes.lang b/htdocs/langs/en_US/boxes.lang
    index 4254c2cacaf..8a519879ac3 100644
    --- a/htdocs/langs/en_US/boxes.lang
    +++ b/htdocs/langs/en_US/boxes.lang
    @@ -83,4 +83,4 @@ ForCustomersOrders=Customers orders
     ForProposals=Proposals
     LastXMonthRolling=The latest %s month rolling
     ChooseBoxToAdd=Add widget to your dashboard
    -BoxAdded=Widget was added in your dashboard
    \ No newline at end of file
    +BoxAdded=Widget was added in your dashboard
    diff --git a/htdocs/langs/en_US/categories.lang b/htdocs/langs/en_US/categories.lang
    index 47b5ea92d12..cef3eaa2815 100644
    --- a/htdocs/langs/en_US/categories.lang
    +++ b/htdocs/langs/en_US/categories.lang
    @@ -16,6 +16,7 @@ MembersCategoriesArea=Members tags/categories area
     ContactsCategoriesArea=Contacts tags/categories area
     AccountsCategoriesArea=Accounts tags/categories area
     ProjectsCategoriesArea=Projects tags/categories area
    +UsersCategoriesArea=Users tags/categories area
     SubCats=Sub-categories
     CatList=List of tags/categories
     NewCategory=New tag/category
    @@ -54,12 +55,13 @@ MembersCategoryShort=Members tag/category
     SuppliersCategoriesShort=Suppliers tags/categories
     CustomersCategoriesShort=Customers tags/categories
     ProspectsCategoriesShort=Prospects tags/categories
    -CustomersProspectsCategoriesShort=Cust./Prosp. categories
    +CustomersProspectsCategoriesShort=Cust./Prosp. tags/categories
     ProductsCategoriesShort=Products tags/categories
     MembersCategoriesShort=Members tags/categories
     ContactCategoriesShort=Contacts tags/categories
     AccountsCategoriesShort=Accounts tags/categories
     ProjectsCategoriesShort=Projects tags/categories
    +UsersCategoriesShort=Users tags/categories
     ThisCategoryHasNoProduct=This category does not contain any product.
     ThisCategoryHasNoSupplier=This category does not contain any supplier.
     ThisCategoryHasNoCustomer=This category does not contain any customer.
    diff --git a/htdocs/langs/en_US/commercial.lang b/htdocs/langs/en_US/commercial.lang
    index a130ce82f79..0a0deb99a1f 100644
    --- a/htdocs/langs/en_US/commercial.lang
    +++ b/htdocs/langs/en_US/commercial.lang
    @@ -76,4 +76,4 @@ WelcomeOnOnlineSignaturePage=Welcome to the page to accept commercial proposals
     ThisScreenAllowsYouToSignDocFrom=This screen allow you to accept and sign, or refuse, a quote/commercial proposal
     ThisIsInformationOnDocumentToSign=This is information on document to accept or refuse
     SignatureProposalRef=Signature of quote/commercial proposal %s
    -FeatureOnlineSignDisabled=Feature for online signing disabled or document generated before the feature was enabled  
    \ No newline at end of file
    +FeatureOnlineSignDisabled=Feature for online signing disabled or document generated before the feature was enabled
    diff --git a/htdocs/langs/en_US/companies.lang b/htdocs/langs/en_US/companies.lang
    index 30a7ebbfddc..e026ac5673d 100644
    --- a/htdocs/langs/en_US/companies.lang
    +++ b/htdocs/langs/en_US/companies.lang
    @@ -38,9 +38,9 @@ ThirdPartyCustomers=Customers
     ThirdPartyCustomersStats=Customers
     ThirdPartyCustomersWithIdProf12=Customers with %s or %s
     ThirdPartySuppliers=Vendors
    -ThirdPartyType=Third Party Type
    +ThirdPartyType=Type of company
     Individual=Private individual
    -ToCreateContactWithSameName=Will create automatically a contact/address with same information as the third party under the third party. In most cases, even if your third party is a physical person, creating a third party alone is enough.
    +ToCreateContactWithSameName=Will create a Third Party and a linked Contact/Address with same information as the Third Party. In most cases, even if your Third Party is a physical person, creating a Third Party alone is enough.
     ParentCompany=Parent company
     Subsidiaries=Subsidiaries
     ReportByMonth=Report by month
    @@ -274,8 +274,8 @@ CompanyHasRelativeDiscount=This customer has a default discount of <b>%s%%</b>
     CompanyHasNoRelativeDiscount=This customer has no relative discount by default
     HasRelativeDiscountFromSupplier=You have a default discount of <b>%s%%</b> from this supplier
     HasNoRelativeDiscountFromSupplier=You have no default relative discount from this supplier
    -CompanyHasAbsoluteDiscount=This customer has discount available (credits notes or down payments) for <b>%s</b> %s
    -CompanyHasDownPaymentOrCommercialDiscount=This customer has discount available (commercial, down payments) for <b>%s</b> %s
    +CompanyHasAbsoluteDiscount=This customer has discounts available (credits notes or down payments) for <b>%s</b> %s
    +CompanyHasDownPaymentOrCommercialDiscount=This customer has discounts available (commercial, down payments) for <b>%s</b> %s
     CompanyHasCreditNote=This customer still has credit notes for <b>%s</b> %s
     HasNoAbsoluteDiscountFromSupplier=You have no discount credit available from this supplier
     HasAbsoluteDiscountFromSupplier=You have discounts available (credits notes or down payments) for <b>%s</b> %s from this supplier
    @@ -312,7 +312,7 @@ SupplierCodeDesc=Vendor Code, unique for all vendors
     RequiredIfCustomer=Required if third party is a customer or prospect
     RequiredIfSupplier=Required if third party is a vendor
     ValidityControledByModule=Validity controlled by module
    -ThisIsModuleRules=This is rules for this module
    +ThisIsModuleRules=Rules for this module
     ProspectToContact=Prospect to contact
     CompanyDeleted=Company "%s" deleted from database.
     ListOfContacts=List of contacts/addresses
    @@ -338,14 +338,14 @@ MyContacts=My contacts
     Capital=Capital
     CapitalOf=Capital of %s
     EditCompany=Edit company
    -ThisUserIsNot=This user is not a prospect, customer nor vendor
    +ThisUserIsNot=This user is not a prospect, customer or vendor
     VATIntraCheck=Check
     VATIntraCheckDesc=The link <b>%s</b> uses the European VAT checker service (VIES). An external internet access from server is required for this service to work.
     VATIntraCheckURL=http://ec.europa.eu/taxation_customs/vies/vieshome.do
     VATIntraCheckableOnEUSite=Check intra-Community VAT on the European Commission website
     VATIntraManualCheck=You can also check manually on the European Commission website <a href="%s" target="_blank">%s</a>
     ErrorVATCheckMS_UNAVAILABLE=Check not possible. Check service is not provided by the member state (%s).
    -NorProspectNorCustomer=Nor prospect, nor customer
    +NorProspectNorCustomer=Not prospect, or customer
     JuridicalStatus=Legal Entity Type
     Staff=Staff
     ProspectLevelShort=Potential
    diff --git a/htdocs/langs/en_US/compta.lang b/htdocs/langs/en_US/compta.lang
    index 32ea8dbaa52..6ad5e357b35 100644
    --- a/htdocs/langs/en_US/compta.lang
    +++ b/htdocs/langs/en_US/compta.lang
    @@ -6,7 +6,7 @@ OptionMode=Option for accountancy
     OptionModeTrue=Option Incomes-Expenses
     OptionModeVirtual=Option Claims-Debts
     OptionModeTrueDesc=In this context, the turnover is calculated over payments (date of payments). The validity of the figures is assured only if the book-keeping is scrutinized through the input/output on the accounts via invoices.
    -OptionModeVirtualDesc=In this context, the turnover is calculated over invoices (date of validation). When these invoices are due, whether they have been paid or not, they are listed in the turnover output. 
    +OptionModeVirtualDesc=In this context, the turnover is calculated over invoices (date of validation). When these invoices are due, whether they have been paid or not, they are listed in the turnover output.
     FeatureIsSupportedInInOutModeOnly=Feature only available in CREDITS-DEBTS accountancy mode (See Accountancy module configuration)
     VATReportBuildWithOptionDefinedInModule=Amounts shown here are calculated using rules defined by Tax module setup.
     LTReportBuildWithOptionDefinedInModule=Amounts shown here are calculated using rules defined by Company setup.
    @@ -29,7 +29,7 @@ BalanceBefore=Balance (before)
     Balance=Balance
     Debit=Debit
     Credit=Credit
    -Piece=Accounting Doc. 
    +Piece=Accounting Doc.
     AmountHTVATRealReceived=Net collected
     AmountHTVATRealPaid=Net paid
     VATToPay=Tax sales
    @@ -167,7 +167,7 @@ RulesAmountOnInOutBookkeepingRecord=It includes record in your Ledger with accou
     RulesResultBookkeepingPredefined=It includes record in your Ledger with accounting accounts that has the group "EXPENSE" or "INCOME"
     RulesResultBookkeepingPersonalized=It show record in your Ledger with accounting accounts <b>grouped by personalized groups</b>
     SeePageForSetup=See menu <a href="%s">%s</a> for setup
    -DepositsAreNotIncluded=- Down payment invoices are nor included
    +DepositsAreNotIncluded=- Down payment invoices are not included
     DepositsAreIncluded=- Down payment invoices are included
     LT1ReportByCustomers=Report tax 2 by third party
     LT2ReportByCustomers=Report tax 3 by third party
    @@ -191,7 +191,7 @@ RulesVATInProducts=- For material assets, the report includes the VAT received o
     RulesVATDueServices=- For services, the report includes VAT invoices due, paid or not, based on the invoice date.
     RulesVATDueProducts=- For material assets, the report includes the VAT invoices, based on the invoice date.
     OptionVatInfoModuleComptabilite=Note: For material assets, it should use the date of delivery to be more fair.
    -ThisIsAnEstimatedValue=This is a preview, based on business events and not from the final ledger table, so final results may differ from this preview values 
    +ThisIsAnEstimatedValue=This is a preview, based on business events and not from the final ledger table, so final results may differ from this preview values
     PercentOfInvoice=%%/invoice
     NotUsedForGoods=Not used on goods
     ProposalStats=Statistics on proposals
    @@ -203,7 +203,7 @@ ToDispatch=To dispatch
     ThirdPartyMustBeEditAsCustomer=Third party must be defined as a customer
     SellsJournal=Sales Journal
     PurchasesJournal=Purchases Journal
    -DescSellsJournal=Sales Journal 
    +DescSellsJournal=Sales Journal
     DescPurchasesJournal=Purchases Journal
     InvoiceRef=Invoice ref.
     CodeNotDef=Not defined
    @@ -256,4 +256,4 @@ PaidDuringThisPeriod=Paid during this period
     ByVatRate=By sale tax rate
     TurnoverbyVatrate=Turnover invoiced by sale tax rate
     TurnoverCollectedbyVatrate=Turnover collected by sale tax rate
    -PurchasebyVatrate=Purchase by sale tax rate
    \ No newline at end of file
    +PurchasebyVatrate=Purchase by sale tax rate
    diff --git a/htdocs/langs/en_US/cron.lang b/htdocs/langs/en_US/cron.lang
    index f968d2ac1fb..63d56feca61 100644
    --- a/htdocs/langs/en_US/cron.lang
    +++ b/htdocs/langs/en_US/cron.lang
    @@ -11,11 +11,11 @@ URLToLaunchCronJobs=URL to check and launch qualified cron jobs
     OrToLaunchASpecificJob=Or to check and launch a specific job
     KeyForCronAccess=Security key for URL to launch cron jobs
     FileToLaunchCronJobs=Command line to check and launch qualified cron jobs
    -CronExplainHowToRunUnix=On Unix environment you should use the following crontab entry to run the command line each 5 minutes 
    +CronExplainHowToRunUnix=On Unix environment you should use the following crontab entry to run the command line each 5 minutes
     CronExplainHowToRunWin=On Microsoft(tm) Windows environment you can use Scheduled Task tools to run the command line each 5 minutes
     CronMethodDoesNotExists=Class %s does not contains any method %s
     CronJobDefDesc=Cron job profiles are defined into the module descriptor file. When module is activated, they are loaded and available so you can administer the jobs from the admin tools menu %s.
    -CronJobProfiles=List of predefined cron job profiles 
    +CronJobProfiles=List of predefined cron job profiles
     # Menu
     EnabledAndDisabled=Enabled and disabled
     # Page list
    diff --git a/htdocs/langs/en_US/deliveries.lang b/htdocs/langs/en_US/deliveries.lang
    index 1c9cb791900..0d432c3f426 100644
    --- a/htdocs/langs/en_US/deliveries.lang
    +++ b/htdocs/langs/en_US/deliveries.lang
    @@ -17,11 +17,11 @@ DeliveryNotValidated=Delivery not validated
     StatusDeliveryCanceled=Canceled
     StatusDeliveryDraft=Draft
     StatusDeliveryValidated=Received
    -# merou PDF model						   
    -NameAndSignature=Name and Signature : 
    +# merou PDF model
    +NameAndSignature=Name and Signature :
     ToAndDate=To___________________________________ on ____/_____/__________
     GoodStatusDeclaration=Have received the goods above in good condition,
    -Deliverer=Deliverer : 
    +Deliverer=Deliverer :
     Sender=Sender
     Recipient=Recipient
     ErrorStockIsNotEnough=There's not enough stock
    diff --git a/htdocs/langs/en_US/dict.lang b/htdocs/langs/en_US/dict.lang
    index 9a8ee71106b..59e7cc058f4 100644
    --- a/htdocs/langs/en_US/dict.lang
    +++ b/htdocs/langs/en_US/dict.lang
    @@ -295,7 +295,7 @@ CurrencyCentINR=paisa
     CurrencyCentSingINR=paise
     CurrencyThousandthSingTND=thousandth
     #### Input reasons #####
    -DemandReasonTypeSRC_INTE=Internet
    +DemandReasonTypeSRC_INTE=Internetaaa
     DemandReasonTypeSRC_CAMP_MAIL=Mailing campaign
     DemandReasonTypeSRC_CAMP_EMAIL=EMailing campaign
     DemandReasonTypeSRC_CAMP_PHO=Phone campaign
    @@ -354,4 +354,4 @@ ExpAuto13PCV=13 CV and more
     ExpCyclo=Capacity lower to 50cm3
     ExpMoto12CV=Motorbike 1 or 2 CV
     ExpMoto345CV=Motorbike 3, 4 or 5 CV
    -ExpMoto5PCV=Motorbike 5 CV and more
    \ No newline at end of file
    +ExpMoto5PCV=Motorbike 5 CV and more
    diff --git a/htdocs/langs/en_US/donations.lang b/htdocs/langs/en_US/donations.lang
    index 748057cc9cc..5edc8d62033 100644
    --- a/htdocs/langs/en_US/donations.lang
    +++ b/htdocs/langs/en_US/donations.lang
    @@ -27,7 +27,7 @@ IConfirmDonationReception=The recipient declare reception, as a donation, of the
     MinimumAmount=Minimum amount is  %s
     FreeTextOnDonations=Free text to show in footer
     FrenchOptions=Options for France
    -DONATION_ART200=Show article 200 from CGI if you are concerned 
    +DONATION_ART200=Show article 200 from CGI if you are concerned
     DONATION_ART238=Show article 238 from CGI if you are concerned
     DONATION_ART885=Show article 885 from CGI if you are concerned
     DonationPayment=Donation payment
    diff --git a/htdocs/langs/en_US/errors.lang b/htdocs/langs/en_US/errors.lang
    index 9e179519739..29dbf4b4287 100644
    --- a/htdocs/langs/en_US/errors.lang
    +++ b/htdocs/langs/en_US/errors.lang
    @@ -74,7 +74,7 @@ ErrorLDAPSetupNotComplete=Dolibarr-LDAP matching is not complete.
     ErrorLDAPMakeManualTest=A .ldif file has been generated in directory %s. Try to load it manually from command line to have more information on errors.
     ErrorCantSaveADoneUserWithZeroPercentage=Can't save an action with "status not started" if field "done by" is also filled.
     ErrorRefAlreadyExists=Ref used for creation already exists.
    -ErrorPleaseTypeBankTransactionReportName=Please enter the bank statement name where the entry has to be reported (Format YYYYMM or YYYYMMDD) 
    +ErrorPleaseTypeBankTransactionReportName=Please enter the bank statement name where the entry has to be reported (Format YYYYMM or YYYYMMDD)
     ErrorRecordHasChildren=Failed to delete record since it has some child records.
     ErrorRecordHasAtLeastOneChildOfType=Object has at least one child of type %s
     ErrorRecordIsUsedCantDelete=Can't delete record. It is already used or included into another object.
    @@ -116,7 +116,7 @@ ErrorLoginDoesNotExists=User with login <b>%s</b> could not be found.
     ErrorLoginHasNoEmail=This user has no email address. Process aborted.
     ErrorBadValueForCode=Bad value for security code. Try again with new value...
     ErrorBothFieldCantBeNegative=Fields %s and %s can't be both negative
    -ErrorFieldCantBeNegativeOnInvoice=Field <strong>%s</strong> can't be negative on such type of invoice. If you want to add a discount line, just create the discount first with link %s on screen and apply it to invoice. You can also ask your admin to set option FACTURE_ENABLE_NEGATIVE_LINES to 1 to restore old behaviour. 
    +ErrorFieldCantBeNegativeOnInvoice=Field <strong>%s</strong> can't be negative on such type of invoice. If you want to add a discount line, just create the discount first with link %s on screen and apply it to invoice. You can also ask your admin to set option FACTURE_ENABLE_NEGATIVE_LINES to 1 to restore old behaviour.
     ErrorQtyForCustomerInvoiceCantBeNegative=Quantity for line into customer invoices can't be negative
     ErrorWebServerUserHasNotPermission=User account <b>%s</b> used to execute web server has no permission for that
     ErrorNoActivatedBarcode=No barcode type activated
    @@ -140,7 +140,7 @@ ErrorBadFormat=Bad format!
     ErrorMemberNotLinkedToAThirpartyLinkOrCreateFirst=Error, this member is not yet linked to any third party. Link member to an existing third party or create a new third party before creating subscription with invoice.
     ErrorThereIsSomeDeliveries=Error, there is some deliveries linked to this shipment. Deletion refused.
     ErrorCantDeletePaymentReconciliated=Can't delete a payment that had generated a bank entry that was reconciled
    -ErrorCantDeletePaymentSharedWithPayedInvoice=Can't delete a payment shared by at least one invoice with status Payed
    +ErrorCantDeletePaymentSharedWithPayedInvoice=Can't delete a payment shared by at least one invoice with status Paid
     ErrorPriceExpression1=Cannot assign to constant '%s'
     ErrorPriceExpression2=Cannot redefine built-in function '%s'
     ErrorPriceExpression3=Undefined variable '%s' in function definition
    @@ -198,7 +198,7 @@ ErrorModuleFileSeemsToHaveAWrongFormat=The module package seems to have a wrong
     ErrorFilenameDosNotMatchDolibarrPackageRules=The name of the module package (<strong>%s</strong>) does not match expected name syntax: <strong>%s</strong>
     ErrorDuplicateTrigger=Error, duplicate trigger name %s. Already loaded from %s.
     ErrorNoWarehouseDefined=Error, no warehouses defined.
    -ErrorBadLinkSourceSetButBadValueForRef=The link you use is not valid. A 'source' for payment is defined, but value for 'ref' is not valid. 
    +ErrorBadLinkSourceSetButBadValueForRef=The link you use is not valid. A 'source' for payment is defined, but value for 'ref' is not valid.
     ErrorTooManyErrorsProcessStopped=Too many errors. Process was stopped.
     ErrorMassValidationNotAllowedWhenStockIncreaseOnAction=Mass validation is not possible when option to increase/decrease stock is set on this action (you must validate one by one so you can define the warehouse to increase/decrease)
     ErrorObjectMustHaveStatusDraftToBeValidated=Object %s must have status 'Draft' to be validated.
    @@ -213,7 +213,7 @@ ErrorDescRequiredForFreeProductLines=Description is mandatory for lines with fre
     ErrorAPageWithThisNameOrAliasAlreadyExists=The page/container <strong>%s</strong> has the same name or alternative alias that the one your try to use
     
     # Warnings
    -WarningPasswordSetWithNoAccount=A password was set for this member. However, no user account was created. So this password is stored but can't be used to login to Dolibarr. It may be used by an external module/interface but if you don't need to define any login nor password for a member, you can disable option "Manage a login for each member" from Member module setup. If you need to manage a login but don't need any password, you can keep this field empty to avoid this warning. Note: Email can also be used as a login if the member is linked to a user.  
    +WarningPasswordSetWithNoAccount=A password was set for this member. However, no user account was created. So this password is stored but can't be used to login to Dolibarr. It may be used by an external module/interface but if you don't need to define any login nor password for a member, you can disable option "Manage a login for each member" from Member module setup. If you need to manage a login but don't need any password, you can keep this field empty to avoid this warning. Note: Email can also be used as a login if the member is linked to a user.
     WarningMandatorySetupNotComplete=Mandatory setup parameters are not yet defined
     WarningSafeModeOnCheckExecDir=Warning, PHP option <b>safe_mode</b> is on so command must be stored inside a directory declared by php parameter <b>safe_mode_exec_dir</b>.
     WarningBookmarkAlreadyExists=A bookmark with this title or this target (URL) already exists.
    @@ -221,14 +221,14 @@ WarningPassIsEmpty=Warning, database password is empty. This is a security hole.
     WarningConfFileMustBeReadOnly=Warning, your config file (<b>htdocs/conf/conf.php</b>) can be overwritten by the web server. This is a serious security hole. Modify permissions on file to be in read only mode for operating system user used by Web server. If you use Windows and FAT format for your disk, you must know that this file system does not allow to add permissions on file, so can't be completely safe.
     WarningsOnXLines=Warnings on <b>%s</b> source record(s)
     WarningNoDocumentModelActivated=No model, for document generation, has been activated. A model will be chosen by default until you check your module setup.
    -WarningLockFileDoesNotExists=Warning, once setup is finished, you must disable install/migrate tools by adding a file <b>install.lock</b> into directory <b>%s</b>. Missing this file is a security hole. 
    +WarningLockFileDoesNotExists=Warning, once setup is finished, you must disable install/migrate tools by adding a file <b>install.lock</b> into directory <b>%s</b>. Missing this file is a security hole.
     WarningUntilDirRemoved=All security warnings (visible by admin users only) will remain active as long as the vulnerability is present (or that constant MAIN_REMOVE_INSTALL_WARNING is added in Setup->Other Setup).
     WarningCloseAlways=Warning, closing is done even if amount differs between source and target elements. Enable this feature with caution.
     WarningUsingThisBoxSlowDown=Warning, using this box slow down seriously all pages showing the box.
     WarningClickToDialUserSetupNotComplete=Setup of ClickToDial information for your user are not complete (see tab ClickToDial onto your user card).
     WarningFeatureDisabledWithDisplayOptimizedForBlindNoJs=Feature disabled when display setup is optimized for blind person or text browsers.
    -WarningPaymentDateLowerThanInvoiceDate=Payment date (%s) is earlier than invoice date (%s) for invoice %s. 
    -WarningTooManyDataPleaseUseMoreFilters=Too many data (more than %s lines). Please use more filters or set the constant %s to a higher limit. 
    +WarningPaymentDateLowerThanInvoiceDate=Payment date (%s) is earlier than invoice date (%s) for invoice %s.
    +WarningTooManyDataPleaseUseMoreFilters=Too many data (more than %s lines). Please use more filters or set the constant %s to a higher limit.
     WarningSomeLinesWithNullHourlyRate=Some times were recorded by some users while their hourly rate was not defined. A value of 0 %s per hour was used but this may result in wrong valuation of time spent.
     WarningYourLoginWasModifiedPleaseLogin=Your login was modified. For security purpose you will have to login with your new login before next action.
     WarningAnEntryAlreadyExistForTransKey=An entry already exists for the translation key for this language
    diff --git a/htdocs/langs/en_US/exports.lang b/htdocs/langs/en_US/exports.lang
    index fa34b7f49ae..179556ddb19 100644
    --- a/htdocs/langs/en_US/exports.lang
    +++ b/htdocs/langs/en_US/exports.lang
    @@ -84,7 +84,7 @@ TooMuchErrors=There are still <b>%s</b> other source lines with errors but outpu
     TooMuchWarnings=There are still <b>%s</b> other source lines with warnings but output has been limited.
     EmptyLine=Empty line (will be discarded)
     CorrectErrorBeforeRunningImport=You <b>must</b> correct all errors <b>before</b> running the definitive import.
    -FileWasImported=File was imported with number <b>%s</b>. 
    +FileWasImported=File was imported with number <b>%s</b>.
     YouCanUseImportIdToFindRecord=You can find all the imported records in your database by filtering on field <b>import_key='%s'</b>.
     NbOfLinesOK=Number of lines with no errors and no warnings: <b>%s</b>.
     NbOfLinesImported=Number of lines successfully imported: <b>%s</b>.
    @@ -118,7 +118,7 @@ SetThisValueTo2ToExcludeFirstLine=For example, set this value to 3 to exclude th
     KeepEmptyToGoToEndOfFile=Keep this field empty to go up to the end of file
     SelectPrimaryColumnsForUpdateAttempt=Select column(s) to use as primary key for update attempt
     UpdateNotYetSupportedForThisImport=Update is not supported for this type of import (only insert)
    -NoUpdateAttempt=No update attempt was performed, only insert 
    +NoUpdateAttempt=No update attempt was performed, only insert
     ImportDataset_user_1=Users (employees or not) and properties
     ComputedField=Computed field
     ## filters
    @@ -130,4 +130,4 @@ FormatControlRule=Format control rule
     KeysToUseForUpdates=Key (column) to use for <b>updating</b> existing data
     NbInsert=Number of inserted lines: %s
     NbUpdate=Number of updated lines: %s
    -MultipleRecordFoundWithTheseFilters=Multiple records have been found with these filters: %s
    \ No newline at end of file
    +MultipleRecordFoundWithTheseFilters=Multiple records have been found with these filters: %s
    diff --git a/htdocs/langs/en_US/externalsite.lang b/htdocs/langs/en_US/externalsite.lang
    index afec761f5fe..da4853df0df 100644
    --- a/htdocs/langs/en_US/externalsite.lang
    +++ b/htdocs/langs/en_US/externalsite.lang
    @@ -2,4 +2,4 @@
     ExternalSiteSetup=Setup link to external website
     ExternalSiteURL=External Site URL
     ExternalSiteModuleNotComplete=Module ExternalSite was not configured properly.
    -ExampleMyMenuEntry=My menu entry
    \ No newline at end of file
    +ExampleMyMenuEntry=My menu entry
    diff --git a/htdocs/langs/en_US/ftp.lang b/htdocs/langs/en_US/ftp.lang
    index d6b9d2ca070..8ecb0c55cad 100644
    --- a/htdocs/langs/en_US/ftp.lang
    +++ b/htdocs/langs/en_US/ftp.lang
    @@ -11,4 +11,4 @@ FTPFailedToRemoveFile=Failed to remove file <b>%s</b>.
     FTPFailedToRemoveDir=Failed to remove directory <b>%s</b> (Check permissions and that directory is empty).
     FTPPassiveMode=Passive mode
     ChooseAFTPEntryIntoMenu=Choose a FTP entry into menu...
    -FailedToGetFile=Failed to get files %s
    \ No newline at end of file
    +FailedToGetFile=Failed to get files %s
    diff --git a/htdocs/langs/en_US/holiday.lang b/htdocs/langs/en_US/holiday.lang
    index 5c9c9e04200..1411ae3ad56 100644
    --- a/htdocs/langs/en_US/holiday.lang
    +++ b/htdocs/langs/en_US/holiday.lang
    @@ -1,10 +1,10 @@
     # Dolibarr language file - Source file is en_US - holiday
     HRM=HRM
    -Holidays=Leaves
    -CPTitreMenu=Leaves
    +Holidays=Leave
    +CPTitreMenu=Leave
     MenuReportMonth=Monthly statement
     MenuAddCP=New leave request
    -NotActiveModCP=You must enable the module Leaves to view this page.
    +NotActiveModCP=You must enable the module Leave to view this page.
     AddCP=Make a leave request
     DateDebCP=Start date
     DateFinCP=End date
    @@ -15,7 +15,7 @@ ApprovedCP=Approved
     CancelCP=Canceled
     RefuseCP=Refused
     ValidatorCP=Approbator
    -ListeCP=List of leaves
    +ListeCP=List of leave
     LeaveId=Leave ID
     ReviewedByCP=Will be approved by
     UserForApprovalID=User for approval ID
    @@ -25,8 +25,8 @@ UserForApprovalLogin=Login of approval user
     DescCP=Description
     SendRequestCP=Create leave request
     DelayToRequestCP=Leave requests must be made at least <b>%s day(s)</b> before them.
    -MenuConfCP=Balance of leaves
    -SoldeCPUser=Leaves balance is <b>%s</b> days.
    +MenuConfCP=Balance of leave
    +SoldeCPUser=Leave balance is <b>%s</b> days.
     ErrorEndDateCP=You must select an end date greater than the start date.
     ErrorSQLCreateCP=An SQL error occurred during the creation:
     ErrorIDFicheCP=An error has occurred, the leave request does not exist.
    @@ -85,7 +85,7 @@ NewSoldeCP=New Balance
     alreadyCPexist=A leave request has already been done on this period.
     FirstDayOfHoliday=First day of vacation
     LastDayOfHoliday=Last day of vacation
    -BoxTitleLastLeaveRequests=Latest %s modified leave requests 
    +BoxTitleLastLeaveRequests=Latest %s modified leave requests
     HolidaysMonthlyUpdate=Monthly update
     ManualUpdate=Manual update
     HolidaysCancelation=Leave request cancelation
    @@ -101,8 +101,8 @@ LEAVE_SICK=Sick leave
     LEAVE_OTHER=Other leave
     LEAVE_PAID_FR=Paid vacation
     ## Configuration du Module ##
    -LastUpdateCP=Latest automatic update of leaves allocation
    -MonthOfLastMonthlyUpdate=Month of latest automatic update of leaves allocation
    +LastUpdateCP=Latest automatic update of leave allocation
    +MonthOfLastMonthlyUpdate=Month of latest automatic update of leave allocation
     UpdateConfCPOK=Updated successfully.
     Module27130Name= Management of leave requests
     Module27130Desc= Management of leave requests
    @@ -121,4 +121,4 @@ HolidaysCanceled=Canceled leaved request
     HolidaysCanceledBody=Your leave request for %s to %s has been canceled.
     FollowedByACounter=1: This type of leave need to be followed by a counter. Counter is incremented manually or automatically and when a leave request is validated, counter is decremented.<br>0: Not followed by a counter.
     NoLeaveWithCounterDefined=There is no leave types defined that need to be followed by a counter
    -GoIntoDictionaryHolidayTypes=Go into <strong>Home - Setup - Dictionaries - Type of leaves</strong> to setup the different types of leaves.
    +GoIntoDictionaryHolidayTypes=Go into <strong>Home - Setup - Dictionaries - Type of leave</strong> to setup the different types of leaves.
    diff --git a/htdocs/langs/en_US/install.lang b/htdocs/langs/en_US/install.lang
    index e8a89657b6a..bcca348c861 100644
    --- a/htdocs/langs/en_US/install.lang
    +++ b/htdocs/langs/en_US/install.lang
    @@ -127,9 +127,9 @@ OpenBaseDir=PHP openbasedir parameter
     YouAskToCreateDatabaseSoRootRequired=You checked the box "Create database". For this, you need to provide the login/password of superuser (bottom of form).
     YouAskToCreateDatabaseUserSoRootRequired=You checked the box "Create database owner". For this, you need to provide the login/password of superuser (bottom of form).
     NextStepMightLastALongTime=The current step may take several minutes. Please wait until the next screen is shown completely before continuing.
    -MigrationCustomerOrderShipping=Migrate shipping for customer orders storage 
    -MigrationShippingDelivery=Upgrade storage of shipping 
    -MigrationShippingDelivery2=Upgrade storage of shipping 2 
    +MigrationCustomerOrderShipping=Migrate shipping for customer orders storage
    +MigrationShippingDelivery=Upgrade storage of shipping
    +MigrationShippingDelivery2=Upgrade storage of shipping 2
     MigrationFinished=Migration finished
     LastStepDesc=<strong>Last step</strong>: Define here the login and password you wish to use to connect to Dolibarr. <b>Do not lose this as it is the master account to administer all other/additional user accounts.</b>
     ActivateModule=Activate module %s
    @@ -208,4 +208,4 @@ ErrorFoundDuringMigration=Error(s) were reported during the migration process so
     YouTryInstallDisabledByDirLock=The application tried to self-upgrade, but the install/upgrade pages have been disabled for security (directory renamed with .lock suffix).<br>
     YouTryInstallDisabledByFileLock=The application tried to self-upgrade, but the install/upgrade pages have been disabled for security (by the existence of a lock file <strong>install.lock</strong> in the dolibarr documents directory).<br>
     ClickHereToGoToApp=Click here to go to your application
    -ClickOnLinkOrRemoveManualy=Click on the following link. If you always see this same page, you must remove/rename the file install.lock in the documents directory.
    \ No newline at end of file
    +ClickOnLinkOrRemoveManualy=Click on the following link. If you always see this same page, you must remove/rename the file install.lock in the documents directory.
    diff --git a/htdocs/langs/en_US/languages.lang b/htdocs/langs/en_US/languages.lang
    index a062883d667..99c9b6486e0 100644
    --- a/htdocs/langs/en_US/languages.lang
    +++ b/htdocs/langs/en_US/languages.lang
    @@ -86,3 +86,4 @@ Language_uz_UZ=Uzbek
     Language_vi_VN=Vietnamese
     Language_zh_CN=Chinese
     Language_zh_TW=Chinese (Traditional)
    +Language_bh_MY=Malay
    diff --git a/htdocs/langs/en_US/ldap.lang b/htdocs/langs/en_US/ldap.lang
    index 67824ccd237..abe11602147 100644
    --- a/htdocs/langs/en_US/ldap.lang
    +++ b/htdocs/langs/en_US/ldap.lang
    @@ -24,4 +24,4 @@ MemberTypeSynchronized=Member type synchronized
     ContactSynchronized=Contact synchronized
     ForceSynchronize=Force synchronizing Dolibarr -> LDAP
     ErrorFailedToReadLDAP=Failed to read LDAP database. Check LDAP module setup and database accessibility.
    -PasswordOfUserInLDAP=Password of user in LDAP
    \ No newline at end of file
    +PasswordOfUserInLDAP=Password of user in LDAP
    diff --git a/htdocs/langs/en_US/link.lang b/htdocs/langs/en_US/link.lang
    index 77a1814f1ca..fdcf07aeff4 100644
    --- a/htdocs/langs/en_US/link.lang
    +++ b/htdocs/langs/en_US/link.lang
    @@ -7,4 +7,4 @@ ErrorFileNotLinked=The file could not be linked
     LinkRemoved=The link %s has been removed
     ErrorFailedToDeleteLink= Failed to remove link '<b>%s</b>'
     ErrorFailedToUpdateLink= Failed to update link '<b>%s</b>'
    -URLToLink=URL to link
    \ No newline at end of file
    +URLToLink=URL to link
    diff --git a/htdocs/langs/en_US/mails.lang b/htdocs/langs/en_US/mails.lang
    index 8f9c49d8bff..d4f835874e7 100644
    --- a/htdocs/langs/en_US/mails.lang
    +++ b/htdocs/langs/en_US/mails.lang
    @@ -45,7 +45,7 @@ MailingStatusReadAndUnsubscribe=Read and unsubscribe
     ErrorMailRecipientIsEmpty=Email recipient is empty
     WarningNoEMailsAdded=No new Email to add to recipient's list.
     ConfirmValidMailing=Are you sure you want to validate this emailing?
    -ConfirmResetMailing=Warning, by reinitializing emailing <b>%s</b>, you will allow resending this email in a mass mailing. Are you sure you this is what you want to do?
    +ConfirmResetMailing=Warning, by re-initializing emailing <b>%s</b> , you will allow resending this email in a mass mailing. Are you sure you want to do this?
     ConfirmDeleteMailing=Are you sure you want to delete this emailing?
     NbOfUniqueEMails=No. of unique emails
     NbOfEMails=No. of EMails
    @@ -75,7 +75,7 @@ OnlyPDFattachmentSupported=If the PDF documents were already generated for the o
     AllRecipientSelected=The recipients of the %s record selected (if their email is known).
     GroupEmails=Group emails
     OneEmailPerRecipient=One email per recipient (by default, one email per record selected)
    -WarningIfYouCheckOneRecipientPerEmail=Warning, if you check this box, it means only one email will be sent for several different record selected, so, if your message contains substitution variables that refers to data of a record, it becomes not possible to replace them. 
    +WarningIfYouCheckOneRecipientPerEmail=Warning, if you check this box, it means only one email will be sent for several different record selected, so, if your message contains substitution variables that refers to data of a record, it becomes not possible to replace them.
     ResultOfMailSending=Result of mass EMail sending
     NbSelected=No. selected
     NbIgnored=No. ignored
    @@ -105,7 +105,7 @@ SearchAMailing=Search mailing
     SendMailing=Send emailing
     SentBy=Sent by
     MailingNeedCommand=Sending an emailing can be performed from command line. Ask your server administrator to launch the following command to send the emailing to all recipients:
    -MailingNeedCommand2=You can however send them online by adding parameter MAILING_LIMIT_SENDBYWEB with value of max number of emails you want to send by session. For this, go on Home - Setup - Other. 
    +MailingNeedCommand2=You can however send them online by adding parameter MAILING_LIMIT_SENDBYWEB with value of max number of emails you want to send by session. For this, go on Home - Setup - Other.
     ConfirmSendingEmailing=If you want to send emailing directly from this screen, please confirm you are sure you want to send emailing now from your browser ?
     LimitSendingEmailing=Note: Sending of emailings from web interface is done in several times for security and timeout reasons, <b>%s</b> recipients at a time for each sending session.
     TargetsReset=Clear list
    @@ -121,7 +121,7 @@ TagUnsubscribe=Unsubscribe link
     TagSignature=Signature of sending user
     EMailRecipient=Recipient EMail
     TagMailtoEmail=Recipient EMail (including html "mailto:" link)
    -NoEmailSentBadSenderOrRecipientEmail=No email sent. Bad sender or recipient email. Verify user profile. 
    +NoEmailSentBadSenderOrRecipientEmail=No email sent. Bad sender or recipient email. Verify user profile.
     # Module Notifications
     Notifications=Notifications
     NoNotificationsWillBeSent=No email notifications are planned for this event and company
    @@ -133,7 +133,7 @@ ListOfNotificationsDone=List all email notifications sent
     MailSendSetupIs=Configuration of email sending has been setup to '%s'. This mode can't be used to send mass emailing.
     MailSendSetupIs2=You must first go, with an admin account, into menu %sHome - Setup - EMails%s to change parameter <strong>'%s'</strong> to use mode '%s'. With this mode, you can enter setup of the SMTP server provided by your Internet Service Provider and use Mass emailing feature.
     MailSendSetupIs3=If you have any questions on how to setup your SMTP server, you can ask to %s.
    -YouCanAlsoUseSupervisorKeyword=You can also add the keyword <strong>__SUPERVISOREMAIL__</strong> to have email being sent to the supervisor of user (works only if an email is defined for this supervisor) 
    +YouCanAlsoUseSupervisorKeyword=You can also add the keyword <strong>__SUPERVISOREMAIL__</strong> to have email being sent to the supervisor of user (works only if an email is defined for this supervisor)
     NbOfTargetedContacts=Current number of targeted contact emails
     UseFormatFileEmailToTarget=Imported file must have format <strong>email;name;firstname;other</strong>
     UseFormatInputEmailToTarget=Enter a string with format <strong>email;name;firstname;other</strong>
    diff --git a/htdocs/langs/en_US/main.lang b/htdocs/langs/en_US/main.lang
    index b1c51659b07..03d65917a97 100644
    --- a/htdocs/langs/en_US/main.lang
    +++ b/htdocs/langs/en_US/main.lang
    @@ -50,21 +50,21 @@ ErrorFailedToSendMail=Failed to send mail (sender=%s, receiver=%s)
     ErrorFileNotUploaded=File was not uploaded. Check that size does not exceed maximum allowed, that free space is available on disk and that there is not already a file with same name in this directory.
     ErrorInternalErrorDetected=Error detected
     ErrorWrongHostParameter=Wrong host parameter
    -ErrorYourCountryIsNotDefined=Your country is not defined. Go to Home-Setup-Edit and post again the form.
    -ErrorRecordIsUsedByChild=Failed to delete this record. This record is used by at least one child records.
    +ErrorYourCountryIsNotDefined=Your country is not defined. Go to Home-Setup-Edit and post the form again.
    +ErrorRecordIsUsedByChild=Failed to delete this record. This record is used by at least one child record.
     ErrorWrongValue=Wrong value
     ErrorWrongValueForParameterX=Wrong value for parameter %s
     ErrorNoRequestInError=No request in error
    -ErrorServiceUnavailableTryLater=Service not available for the moment. Try again later.
    +ErrorServiceUnavailableTryLater=Service not available at the moment. Try again later.
     ErrorDuplicateField=Duplicate value in a unique field
    -ErrorSomeErrorWereFoundRollbackIsDone=Some errors were found. We rollback changes.
    -ErrorConfigParameterNotDefined=Parameter <b>%s</b> is not defined inside Dolibarr config file <b>conf.php</b>.
    +ErrorSomeErrorWereFoundRollbackIsDone=Some errors were found. Changes have been rolled back.
    +ErrorConfigParameterNotDefined=Parameter <b>%s</b> is not defined in Dolibarr config file <b>conf.php</b>.
     ErrorCantLoadUserFromDolibarrDatabase=Failed to find user <b>%s</b> in Dolibarr database.
     ErrorNoVATRateDefinedForSellerCountry=Error, no vat rates defined for country '%s'.
     ErrorNoSocialContributionForSellerCountry=Error, no social/fiscal taxes type defined for country '%s'.
     ErrorFailedToSaveFile=Error, failed to save file.
    -ErrorCannotAddThisParentWarehouse=You are trying to add a parent warehouse which is already a child of current one
    -MaxNbOfRecordPerPage=Max number of record per page
    +ErrorCannotAddThisParentWarehouse=You are trying to add a parent warehouse which is already a child of a current one
    +MaxNbOfRecordPerPage=Max number of records per page
     NotAuthorized=You are not authorized to do that.
     SetDate=Set date
     SelectDate=Select a date
    @@ -78,7 +78,7 @@ FileRenamed=The file was successfully renamed
     FileGenerated=The file was successfully generated
     FileSaved=The file was successfully saved
     FileUploaded=The file was successfully uploaded
    -FileTransferComplete=File(s) was uploaded successfully
    +FileTransferComplete=File(s) uploaded successfully
     FilesDeleted=File(s) successfully deleted
     FileWasNotUploaded=A file is selected for attachment but was not yet uploaded. Click on "Attach file" for this.
     NbOfEntries=No. of entries
    @@ -154,7 +154,7 @@ Update=Update
     Close=Close
     CloseBox=Remove widget from your dashboard
     Confirm=Confirm
    -ConfirmSendCardByMail=Do you really want to send content of this card by mail to <b>%s</b>?
    +ConfirmSendCardByMail=Do you really want to send the content of this card by mail to <b>%s</b>?
     Delete=Delete
     Remove=Remove
     Resiliate=Terminate
    @@ -232,7 +232,7 @@ Numero=Number
     Limit=Limit
     Limits=Limits
     Logout=Logout
    -NoLogoutProcessWithAuthMode=No applicative disconnect feature with authentication mode <b>%s</b> 
    +NoLogoutProcessWithAuthMode=No applicative disconnect feature with authentication mode <b>%s</b>
     Connection=Login
     Setup=Setup
     Alert=Alert
    @@ -348,7 +348,7 @@ AmountTTCShort=Amount (inc. tax)
     AmountHT=Amount (net of tax)
     AmountTTC=Amount (inc. tax)
     AmountVAT=Amount tax
    -MulticurrencyAlreadyPaid=Already payed, original currency
    +MulticurrencyAlreadyPaid=Already paid, original currency
     MulticurrencyRemainderToPay=Remain to pay, original currency
     MulticurrencyPaymentAmount=Payment amount, original currency
     MulticurrencyAmountHT=Amount (net of tax), original currency
    @@ -429,7 +429,7 @@ ActionNotApplicable=Not applicable
     ActionRunningNotStarted=To start
     ActionRunningShort=In progress
     ActionDoneShort=Finished
    -ActionUncomplete=Uncomplete
    +ActionUncomplete=Incomplete
     LatestLinkedEvents=Latest %s linked events
     CompanyFoundation=Company/Organization
     Accountant=Accountant
    @@ -445,7 +445,7 @@ Completed=Completed
     Running=In progress
     RequestAlreadyDone=Request already recorded
     Filter=Filter
    -FilterOnInto=Search criteria '<strong>%s</strong>' into fields %s 
    +FilterOnInto=Search criteria '<strong>%s</strong>' into fields %s
     RemoveFilter=Remove filter
     ChartGenerated=Chart generated
     ChartNotGenerated=Chart not generated
    @@ -507,7 +507,7 @@ None=None
     NoneF=None
     NoneOrSeveral=None or several
     Late=Late
    -LateDesc=Delay to define if a record is late or not depends on your setup. Ask your admin to change delay from menu Home - Setup - Alerts.
    +LateDesc=The delay to define if a record is late or not depends on your setup. Ask your admin to change the delay from menu Home - Setup - Alerts.
     NoItemLate=No late item
     Photo=Picture
     Photos=Pictures
    @@ -659,14 +659,14 @@ Method=Method
     Receive=Receive
     CompleteOrNoMoreReceptionExpected=Complete or nothing more expected
     ExpectedValue=Expected Value
    -CurrentValue=Current Value
    +CurrentValue=Current value
     PartialWoman=Partial
     TotalWoman=Total
     NeverReceived=Never received
     Canceled=Canceled
     YouCanChangeValuesForThisListFromDictionarySetup=You can change values for this list from menu Setup - Dictionaries
     YouCanChangeValuesForThisListFrom=You can change values for this list from menu %s
    -YouCanSetDefaultValueInModuleSetup=You can set the default value used when creating a new record into module setup
    +YouCanSetDefaultValueInModuleSetup=You can set the default value used when creating a new record in module setup
     Color=Color
     Documents=Linked files
     Documents2=Documents
    @@ -692,7 +692,7 @@ DateOfSignature=Date of signature
     HidePassword=Show command with password hidden
     UnHidePassword=Show real command with clear password
     Root=Root
    -Informations=Informations
    +Informations=Information
     Page=Page
     Notes=Notes
     AddNewLine=Add new line
    @@ -705,14 +705,14 @@ Merge=Merge
     DocumentModelStandardPDF=Standard PDF template
     PrintContentArea=Show page to print main content area
     MenuManager=Menu manager
    -WarningYouAreInMaintenanceMode=Warning, you are in a maintenance mode, so only login <b>%s</b> is allowed to use the application at the moment.
    +WarningYouAreInMaintenanceMode=Warning, you are in maintenance mode, so only login <b>%s</b> is allowed to use the application at this time.
     CoreErrorTitle=System error
     CoreErrorMessage=Sorry, an error occurred. Contact your system administrator to check the logs or disable $dolibarr_main_prod=1 to get more information.
     CreditCard=Credit card
     ValidatePayment=Validate payment
     CreditOrDebitCard=Credit or debit card
     FieldsWithAreMandatory=Fields with <b>%s</b> are mandatory
    -FieldsWithIsForPublic=Fields with <b>%s</b> are shown on public list of members. If you don't want this, check off the "public" box.
    +FieldsWithIsForPublic=Fields with <b>%s</b> are shown in public list of members. If you don't want this, uncheck the "public" box.
     AccordingToGeoIPDatabase=(according to GeoIP conversion)
     Line=Line
     NotSupported=Not supported
    @@ -794,7 +794,7 @@ PrintFile=Print File %s
     ShowTransaction=Show entry on bank account
     ShowIntervention=Show intervention
     ShowContract=Show contract
    -GoIntoSetupToChangeLogo=Go into Home - Setup - Company to change logo or go into Home - Setup - Display to hide.
    +GoIntoSetupToChangeLogo=Go to Home - Setup - Company to change logo or go to Home - Setup - Display to hide.
     Deny=Deny
     Denied=Denied
     ListOf=List of %s
    @@ -870,6 +870,8 @@ NewLeadOrProject=New lead or project
     Rights=Permissions
     LineNb=Line no.
     IncotermLabel=Incoterms
    +TabLetteringCustomer=Customer lettering
    +TabLetteringSupplier=Supplier lettering
     # Week day
     Monday=Monday
     Tuesday=Tuesday
    @@ -926,15 +928,15 @@ SearchIntoInterventions=Interventions
     SearchIntoContracts=Contracts
     SearchIntoCustomerShipments=Customer shipments
     SearchIntoExpenseReports=Expense reports
    -SearchIntoLeaves=Leaves
    +SearchIntoLeaves=Leave
     CommentLink=Comments
     NbComments=Number of comments
     CommentPage=Comments space
     CommentAdded=Comment added
     CommentDeleted=Comment deleted
     Everybody=Everybody
    -PayedBy=Payed by
    -PayedTo=Payed to
    +PayedBy=Paid by
    +PayedTo=Paid to
     Monthly=Monthly
     Quarterly=Quarterly
     Annual=Annual
    diff --git a/htdocs/langs/en_US/members.lang b/htdocs/langs/en_US/members.lang
    index 44599d15451..e28f242d964 100644
    --- a/htdocs/langs/en_US/members.lang
    +++ b/htdocs/langs/en_US/members.lang
    @@ -33,7 +33,7 @@ DateSubscription=Subscription date
     DateEndSubscription=Subscription end date
     EndSubscription=End subscription
     SubscriptionId=Subscription id
    -MemberId=Member id 
    +MemberId=Member id
     NewMember=New member
     MemberType=Member type
     MemberTypeId=Member type id
    @@ -61,7 +61,7 @@ ConfirmDeleteMemberType=Are you sure you want to delete this member type?
     MemberTypeDeleted=Member type deleted
     MemberTypeCanNotBeDeleted=Member type can not be deleted
     NewSubscription=New subscription
    -NewSubscriptionDesc=This form allows you to record your subscription as a new member of the foundation. If you want to renew your subscription (if already a member), please contact foundation board instead by email %s. 
    +NewSubscriptionDesc=This form allows you to record your subscription as a new member of the foundation. If you want to renew your subscription (if already a member), please contact foundation board instead by email %s.
     Subscription=Subscription
     Subscriptions=Subscriptions
     SubscriptionLate=Late
    @@ -115,7 +115,7 @@ SendingReminderForExpiredSubscription=Sending reminder for expired subscriptions
     SendingEmailOnCancelation=Sending email on cancelation
     # Topic of email templates
     YourMembershipRequestWasReceived=Your membership was received.
    -YourMembershipWasValidated=Your membership was validated 
    +YourMembershipWasValidated=Your membership was validated
     YourSubscriptionWasRecorded=Your new subscription was recorded
     SubscriptionReminderEmail=Subscription reminder
     YourMembershipWasCanceled=Your membership was canceled
    @@ -124,8 +124,8 @@ CardContent=Content of your member card
     ThisIsContentOfYourMembershipRequestWasReceived=We want to let you know that your membership request was received.<br><br>
     ThisIsContentOfYourMembershipWasValidated=We want to let you know that your membership was validated with the following information:<br><br>
     ThisIsContentOfYourSubscriptionWasRecorded=We want to let you know that your new subscription was recorded.<br><br>
    -ThisIsContentOfSubscriptionReminderEmail=We want to let you know thet your subscription is about to expire. We hope you can make a renewal of it.<br><br>
    -ThisIsContentOfYourCard=This is a remind of the information we get about you. Feel free to contact us if something looks wrong.<br><br> 
    +ThisIsContentOfSubscriptionReminderEmail=We want to let you know that your subscription is about to expire or is already expired (__MEMBER_LAST_SUBSCRIPTION_DATE_END__). We hope you can make a renewal of it.<br><br>
    +ThisIsContentOfYourCard=This is a remind of the information we get about you. Feel free to contact us if something looks wrong.<br><br>
     DescADHERENT_AUTOREGISTER_NOTIF_MAIL_SUBJECT=Subject of the e-mail received in case of auto-inscription of a guest
     DescADHERENT_AUTOREGISTER_NOTIF_MAIL=E-mail received in case of auto-inscription of a guest
     DescADHERENT_EMAIL_TEMPLATE_AUTOREGISTER=Template Email to use to send email to a member on member autosubscription
    @@ -194,4 +194,4 @@ SubscriptionRecorded=Subscription recorded
     NoEmailSentToMember=No email sent to member
     EmailSentToMember=Email sent to member at %s
     SendReminderForExpiredSubscriptionTitle=Send reminder by email for expired subscription
    -SendReminderForExpiredSubscription=Send reminder by email to members when subscription is about to expire (parameter is number of days before end of subscription to send the remind)
    +SendReminderForExpiredSubscription=Send reminder by email to members when subscription is about to expire (parameter is number of days before end of subscription to send the remind. It can be a list of days separated by a semicolon, for example '10;5;0;-5')
    diff --git a/htdocs/langs/en_US/modulebuilder.lang b/htdocs/langs/en_US/modulebuilder.lang
    index ffbb345fb1c..6aef75a5746 100644
    --- a/htdocs/langs/en_US/modulebuilder.lang
    +++ b/htdocs/langs/en_US/modulebuilder.lang
    @@ -4,7 +4,7 @@ EnterNameOfModuleDesc=Enter name of the module/application to create with no spa
     EnterNameOfObjectDesc=Enter name of the object to create with no spaces. Use uppercase to separate words (For example: MyObject, Student, Teacher...). The CRUD class file, but also API file, pages to list/add/edit/delete object and SQL files will be generated.
     ModuleBuilderDesc2=Path where modules are generated/edited (first alternative directory defined into %s): <strong>%s</strong>
     ModuleBuilderDesc3=Generated/editable modules found: <strong>%s</strong>
    -ModuleBuilderDesc4=A module is detected as 'editable' when the file <strong>%s</strong> exists in root of module directory 
    +ModuleBuilderDesc4=A module is detected as 'editable' when the file <strong>%s</strong> exists in root of module directory
     NewModule=New module
     NewObject=New object
     ModuleKey=Module key
    @@ -49,7 +49,7 @@ SpecificationFile=File with business rules
     LanguageFile=File for language
     ConfirmDeleteProperty=Are you sure you want to delete the property <strong>%s</strong>? This will change code in PHP class but also remove column from table definition of object.
     NotNull=Not NULL
    -NotNullDesc=1=Set database to NOT NULL. -1=Allow null values and force value to NULL if empty ('' or 0). 
    +NotNullDesc=1=Set database to NOT NULL. -1=Allow null values and force value to NULL if empty ('' or 0).
     SearchAll=Used for 'search all'
     DatabaseIndex=Database index
     FileAlreadyExists=File %s already exists
    @@ -95,7 +95,8 @@ YouCanUseTranslationKey=You can use here a key that is the translation key found
     DropTableIfEmpty=(Delete table if empty)
     TableDoesNotExists=The table %s does not exists
     TableDropped=Table %s deleted
    -InitStructureFromExistingTable=Build the structure array string of an existing table 
    +InitStructureFromExistingTable=Build the structure array string of an existing table
     UseAboutPage=Disable the about page
     UseDocFolder=Disable the documentation folder
    -UseSpecificReadme=Use a specific ReadMe
    \ No newline at end of file
    +UseSpecificReadme=Use a specific ReadMe
    +RealPathOfModule=Real path of module
    diff --git a/htdocs/langs/en_US/multicurrency.lang b/htdocs/langs/en_US/multicurrency.lang
    index 048e6721310..47c5590b862 100644
    --- a/htdocs/langs/en_US/multicurrency.lang
    +++ b/htdocs/langs/en_US/multicurrency.lang
    @@ -17,4 +17,4 @@ rate=rate
     MulticurrencyReceived=Received, original currency
     MulticurrencyRemainderToTake=Remaining amount, original currency
     MulticurrencyPaymentAmount=Payment amount, original currency
    -AmountToOthercurrency=Amount To (in currency of receiving account)
    \ No newline at end of file
    +AmountToOthercurrency=Amount To (in currency of receiving account)
    diff --git a/htdocs/langs/en_US/opensurvey.lang b/htdocs/langs/en_US/opensurvey.lang
    index 356f1ff6efe..906de8c2f37 100644
    --- a/htdocs/langs/en_US/opensurvey.lang
    +++ b/htdocs/langs/en_US/opensurvey.lang
    @@ -19,7 +19,7 @@ SelectedDays=Selected days
     TheBestChoice=The best choice currently is
     TheBestChoices=The best choices currently are
     with=with
    -OpenSurveyHowTo=If you agree to vote in this poll, you have to give your name, choose the values that fit best for you and validate with the plus button at the end of the line. 
    +OpenSurveyHowTo=If you agree to vote in this poll, you have to give your name, choose the values that fit best for you and validate with the plus button at the end of the line.
     CommentsOfVoters=Comments of voters
     ConfirmRemovalOfPoll=Are you sure you want to remove this poll (and all votes)
     RemovePoll=Remove poll
    @@ -58,4 +58,4 @@ MoreChoices=Enter more choices for the voters
     SurveyExpiredInfo=The poll has been closed or voting delay has expired.
     EmailSomeoneVoted=%s has filled a line.\nYou can find your poll at the link: \n%s
     ShowSurvey=Show survey
    -UserMustBeSameThanUserUsedToVote=You must have voted and use the same user name that the one used to vote, to post a comment
    \ No newline at end of file
    +UserMustBeSameThanUserUsedToVote=You must have voted and use the same user name that the one used to vote, to post a comment
    diff --git a/htdocs/langs/en_US/orders.lang b/htdocs/langs/en_US/orders.lang
    index e5518951222..66073b8f0c9 100644
    --- a/htdocs/langs/en_US/orders.lang
    +++ b/htdocs/langs/en_US/orders.lang
    @@ -56,7 +56,7 @@ StatusOrderReceivedAll=All products received
     ShippingExist=A shipment exists
     QtyOrdered=Qty ordered
     ProductQtyInDraft=Product quantity into draft orders
    -ProductQtyInDraftOrWaitingApproved=Product quantity into draft or approved orders, not yet ordered 
    +ProductQtyInDraftOrWaitingApproved=Product quantity into draft or approved orders, not yet ordered
     MenuOrdersToBill=Orders delivered
     MenuOrdersToBill2=Billable orders
     ShipProduct=Ship product
    @@ -141,18 +141,19 @@ OrderByWWW=Online
     OrderByPhone=Phone
     # Documents models
     PDFEinsteinDescription=A complete order model (logo...)
    +PDFEratostheneDescription=A complete order model (logo...)
     PDFEdisonDescription=A simple order model
     PDFProformaDescription=A complete proforma invoice (logo…)
     CreateInvoiceForThisCustomer=Bill orders
     NoOrdersToInvoice=No orders billable
    -CloseProcessedOrdersAutomatically=Classify "Processed" all selected orders. 
    +CloseProcessedOrdersAutomatically=Classify "Processed" all selected orders.
     OrderCreation=Order creation
     Ordered=Ordered
     OrderCreated=Your orders have been created
     OrderFail=An error happened during your orders creation
     CreateOrders=Create orders
     ToBillSeveralOrderSelectCustomer=To create an invoice for several orders, click first onto customer, then choose "%s".
    -OptionToSetOrderBilledNotEnabled=Option (from module Workflow) to set order to 'Billed' automatically when invoice is validated is off, so you will have to set status of order to 'Billed' manually.  
    +OptionToSetOrderBilledNotEnabled=Option (from module Workflow) to set order to 'Billed' automatically when invoice is validated is off, so you will have to set status of order to 'Billed' manually.
     IfValidateInvoiceIsNoOrderStayUnbilled=If invoice validation is 'No', the order will remain to status 'Unbilled' until the invoice is validated.
     CloseReceivedSupplierOrdersAutomatically=Close order to "%s" automatically if all products are received.
    -SetShippingMode=Set shipping mode
    \ No newline at end of file
    +SetShippingMode=Set shipping mode
    diff --git a/htdocs/langs/en_US/other.lang b/htdocs/langs/en_US/other.lang
    index d9197b04383..91442bbd05d 100644
    --- a/htdocs/langs/en_US/other.lang
    +++ b/htdocs/langs/en_US/other.lang
    @@ -31,9 +31,6 @@ NextYearOfInvoice=Following year of invoice date
     DateNextInvoiceBeforeGen=Date of next invoice (before generation)
     DateNextInvoiceAfterGen=Date of next invoice (after generation)
     
    -Notify_FICHINTER_ADD_CONTACT=Added contact to Intervention
    -Notify_FICHINTER_VALIDATE=Intervention validated
    -Notify_FICHINTER_SENTBYMAIL=Intervention sent by mail
     Notify_ORDER_VALIDATE=Customer order validated
     Notify_ORDER_SENTBYMAIL=Customer order sent by mail
     Notify_ORDER_SUPPLIER_SENTBYMAIL=Supplier order sent by mail
    @@ -51,15 +48,17 @@ Notify_COMPANY_CREATE=Third party created
     Notify_COMPANY_SENTBYMAIL=Mails sent from third party card
     Notify_BILL_VALIDATE=Customer invoice validated
     Notify_BILL_UNVALIDATE=Customer invoice unvalidated
    -Notify_BILL_PAYED=Customer invoice payed
    +Notify_BILL_PAYED=Customer invoice paid
     Notify_BILL_CANCEL=Customer invoice canceled
     Notify_BILL_SENTBYMAIL=Customer invoice sent by mail
     Notify_BILL_SUPPLIER_VALIDATE=Supplier invoice validated
    -Notify_BILL_SUPPLIER_PAYED=Supplier invoice payed
    +Notify_BILL_SUPPLIER_PAYED=Supplier invoice paid
     Notify_BILL_SUPPLIER_SENTBYMAIL=Supplier invoice sent by mail
     Notify_BILL_SUPPLIER_CANCELED=Supplier invoice cancelled
     Notify_CONTRACT_VALIDATE=Contract validated
     Notify_FICHEINTER_VALIDATE=Intervention validated
    +Notify_FICHINTER_ADD_CONTACT=Added contact to Intervention
    +Notify_FICHINTER_SENTBYMAIL=Intervention sent by mail
     Notify_SHIPPING_VALIDATE=Shipping validated
     Notify_SHIPPING_SENTBYMAIL=Shipping sent by mail
     Notify_MEMBER_VALIDATE=Member validated
    @@ -71,6 +70,10 @@ Notify_PROJECT_CREATE=Project creation
     Notify_TASK_CREATE=Task created
     Notify_TASK_MODIFY=Task modified
     Notify_TASK_DELETE=Task deleted
    +Notify_EXPENSE_REPORT_VALIDATE=Expense report validated (approval required)
    +Notify_EXPENSE_REPORT_APPROVE=Expense report approved
    +Notify_HOLIDAY_VALIDATE=Leave request validated (approval required)
    +Notify_HOLIDAY_APPROVE=Leave request approved
     SeeModuleSetup=See setup of module %s
     NbOfAttachedFiles=Number of attached files/documents
     TotalSizeOfAttachedFiles=Total size of attached files/documents
    @@ -80,15 +83,15 @@ LinkedObject=Linked object
     NbOfActiveNotifications=Number of notifications (no. of recipient emails)
     PredefinedMailTest=__(Hello)__\nThis is a test mail sent to __EMAIL__.\nThe two lines are separated by a carriage return.\n\n__USER_SIGNATURE__
     PredefinedMailTestHtml=__(Hello)__\nThis is a <b>test</b> mail (the word test must be in bold).<br>The two lines are separated by a carriage return.<br><br>__USER_SIGNATURE__
    -PredefinedMailContentSendInvoice=__(Hello)__\n\nYou will find here the invoice __REF__\n\n__ONLINE_PAYMENT_TEXT_AND_URL__\n\n__(Sincerely)__\n\n__USER_SIGNATURE__
    -PredefinedMailContentSendInvoiceReminder=__(Hello)__\n\nWe would like to warn you that the invoice  __REF__ seems to not be payed. So this is the invoice in attachment again, as a reminder.\n\n__ONLINE_PAYMENT_TEXT_AND_URL__\n\n__(Sincerely)__\n\n__USER_SIGNATURE__
    -PredefinedMailContentSendProposal=__(Hello)__\n\nYou will find here the commercial proposal __REF__\n\n\n__(Sincerely)__\n\n__USER_SIGNATURE__
    -PredefinedMailContentSendSupplierProposal=__(Hello)__\n\nYou will find here the price request __REF__\n\n\n__(Sincerely)__\n\n__USER_SIGNATURE__
    -PredefinedMailContentSendOrder=__(Hello)__\n\nYou will find here the order __REF__\n\n\n__(Sincerely)__\n\n__USER_SIGNATURE__
    -PredefinedMailContentSendSupplierOrder=__(Hello)__\n\nYou will find here our order __REF__\n\n\n__(Sincerely)__\n\n__USER_SIGNATURE__
    -PredefinedMailContentSendSupplierInvoice=__(Hello)__\n\nYou will find here the invoice __REF__\n\n\n__(Sincerely)__\n\n__USER_SIGNATURE__
    -PredefinedMailContentSendShipping=__(Hello)__\n\nYou will find here the shipping __REF__\n\n\n__(Sincerely)__\n\n__USER_SIGNATURE__
    -PredefinedMailContentSendFichInter=__(Hello)__\n\nYou will find here the intervention __REF__\n\n\n__(Sincerely)__\n\n__USER_SIGNATURE__
    +PredefinedMailContentSendInvoice=__(Hello)__\n\nPlease find attached invoice __REF__\n\n__ONLINE_PAYMENT_TEXT_AND_URL__\n\n__(Sincerely)__\n\n__USER_SIGNATURE__
    +PredefinedMailContentSendInvoiceReminder=__(Hello)__\n\nWe would like to warn you that the invoice  __REF__ seems to have not been paid. The invoice is attached, as a reminder.\n\n__ONLINE_PAYMENT_TEXT_AND_URL__\n\n__(Sincerely)__\n\n__USER_SIGNATURE__
    +PredefinedMailContentSendProposal=__(Hello)__\n\nPlease find attached commercial proposal __REF__\n\n\n__(Sincerely)__\n\n__USER_SIGNATURE__
    +PredefinedMailContentSendSupplierProposal=__(Hello)__\n\nPlease find attached price request __REF__\n\n\n__(Sincerely)__\n\n__USER_SIGNATURE__
    +PredefinedMailContentSendOrder=__(Hello)__\n\nPlease find attached order __REF__\n\n\n__(Sincerely)__\n\n__USER_SIGNATURE__
    +PredefinedMailContentSendSupplierOrder=__(Hello)__\n\nPlease find attached our order __REF__\n\n\n__(Sincerely)__\n\n__USER_SIGNATURE__
    +PredefinedMailContentSendSupplierInvoice=__(Hello)__\n\nPlease find attached invoice __REF__\n\n\n__(Sincerely)__\n\n__USER_SIGNATURE__
    +PredefinedMailContentSendShipping=__(Hello)__\n\nPlease find attached shipping __REF__\n\n\n__(Sincerely)__\n\n__USER_SIGNATURE__
    +PredefinedMailContentSendFichInter=__(Hello)__\n\nPlease find attached intervention __REF__\n\n\n__(Sincerely)__\n\n__USER_SIGNATURE__
     PredefinedMailContentThirdparty=__(Hello)__\n\n\n__(Sincerely)__\n\n__USER_SIGNATURE__
     PredefinedMailContentUser=__(Hello)__\n\n\n__(Sincerely)__\n\n__USER_SIGNATURE__
     PredefinedMailContentLink=You can click on the link below to make your payment if it is not already done.\n\n%s\n\n
    @@ -188,7 +191,7 @@ NumberOfUnitsSupplierInvoices=Number of units on supplier invoices
     EMailTextInterventionAddedContact=A new intervention %s has been assigned to you.
     EMailTextInterventionValidated=The intervention %s has been validated.
     EMailTextInvoiceValidated=The invoice %s has been validated.
    -EMailTextInvoicePayed=The invoice %s has been payed.
    +EMailTextInvoicePayed=The invoice %s has been paid.
     EMailTextProposalValidated=The proposal %s has been validated.
     EMailTextProposalClosedSigned=The proposal %s has been closed signed.
     EMailTextOrderValidated=The order %s has been validated.
    @@ -198,6 +201,10 @@ EMailTextOrderApprovedBy=The order %s has been approved by %s.
     EMailTextOrderRefused=The order %s has been refused.
     EMailTextOrderRefusedBy=The order %s has been refused by %s.
     EMailTextExpeditionValidated=The shipping %s has been validated.
    +EMailTextExpenseReportValidated=The expense report %s has been validated.
    +EMailTextExpenseReportApproved=The expensereport %s has been approved.
    +EMailTextHolidayValidated=The leave request %s has been validated.
    +EMailTextHolidayApproved=The leave request %s has been approved.
     ImportedWithSet=Importation data set
     DolibarrNotification=Automatic notification
     ResizeDesc=Enter new width <b>OR</b> new height. Ratio will be kept during resizing...
    diff --git a/htdocs/langs/en_US/paybox.lang b/htdocs/langs/en_US/paybox.lang
    index 89e7ff48b79..cf0bd40b716 100644
    --- a/htdocs/langs/en_US/paybox.lang
    +++ b/htdocs/langs/en_US/paybox.lang
    @@ -35,4 +35,4 @@ NewPayboxPaymentFailed=New Paybox payment tried but failed
     PAYBOX_PAYONLINE_SENDEMAIL=EMail to warn after a payment (success or failed)
     PAYBOX_PBX_SITE=Value for PBX SITE
     PAYBOX_PBX_RANG=Value for PBX Rang
    -PAYBOX_PBX_IDENTIFIANT=Value for PBX ID
    \ No newline at end of file
    +PAYBOX_PBX_IDENTIFIANT=Value for PBX ID
    diff --git a/htdocs/langs/en_US/paypal.lang b/htdocs/langs/en_US/paypal.lang
    index c088debc518..d34bb4baf18 100644
    --- a/htdocs/langs/en_US/paypal.lang
    +++ b/htdocs/langs/en_US/paypal.lang
    @@ -18,7 +18,7 @@ NewOnlinePaymentReceived=New online payment received
     NewOnlinePaymentFailed=New online payment tried but failed
     ONLINE_PAYMENT_SENDEMAIL=EMail to warn after a payment (success or not)
     ReturnURLAfterPayment=Return URL after payment
    -ValidationOfOnlinePaymentFailed=Validation of online payment failed 
    +ValidationOfOnlinePaymentFailed=Validation of online payment failed
     PaymentSystemConfirmPaymentPageWasCalledButFailed=Payment confirmation page was called by payment system returned an error
     SetExpressCheckoutAPICallFailed=SetExpressCheckout API call failed.
     DoExpressCheckoutPaymentAPICallFailed=DoExpressCheckoutPayment API call failed.
    @@ -31,4 +31,4 @@ PaypalLiveEnabled=PayPal live enabled (otherwise test/sandbox mode)
     PaypalImportPayment=Import PayPal payments
     PostActionAfterPayment=Post actions after payments
     ARollbackWasPerformedOnPostActions=A rollback was performed on all Post actions. You must complete post actions manually if they are necessary.
    -ValidationOfPaymentFailed=Validation of payment has failed
    \ No newline at end of file
    +ValidationOfPaymentFailed=Validation of payment has failed
    diff --git a/htdocs/langs/en_US/productbatch.lang b/htdocs/langs/en_US/productbatch.lang
    index f0eafc807cf..54270c4a23b 100644
    --- a/htdocs/langs/en_US/productbatch.lang
    +++ b/htdocs/langs/en_US/productbatch.lang
    @@ -21,4 +21,4 @@ ProductDoesNotUseBatchSerial=This product does not use lot/serial number
     ProductLotSetup=Setup of module lot/serial
     ShowCurrentStockOfLot=Show current stock for couple product/lot
     ShowLogOfMovementIfLot=Show log of movements for couple product/lot
    -StockDetailPerBatch=Stock detail per lot
    \ No newline at end of file
    +StockDetailPerBatch=Stock detail per lot
    diff --git a/htdocs/langs/en_US/products.lang b/htdocs/langs/en_US/products.lang
    index 0dde8ad538a..95b93aba4e9 100644
    --- a/htdocs/langs/en_US/products.lang
    +++ b/htdocs/langs/en_US/products.lang
    @@ -130,7 +130,7 @@ DiscountQtyMin=Default discount for qty
     NoPriceDefinedForThisSupplier=No price/qty defined for this supplier/product
     NoSupplierPriceDefinedForThisProduct=No supplier price/qty defined for this product
     PredefinedProductsToSell=Predefined products to sell
    -PredefinedServicesToSell=Predefined services to sell 
    +PredefinedServicesToSell=Predefined services to sell
     PredefinedProductsAndServicesToSell=Predefined products/services to sell
     PredefinedProductsToPurchase=Predefined product to purchase
     PredefinedServicesToPurchase=Predefined services to purchase
    @@ -269,7 +269,7 @@ GlobalVariableUpdaterHelpFormat1=Format for request is {"URL": "http://example.c
     UpdateInterval=Update interval (minutes)
     LastUpdated=Latest update
     CorrectlyUpdated=Correctly updated
    -PropalMergePdfProductActualFile=Files use to add into PDF Azur are/is 
    +PropalMergePdfProductActualFile=Files use to add into PDF Azur are/is
     PropalMergePdfProductChooseFile=Select PDF files
     IncludingProductWithTag=Including product/service with tag
     DefaultPriceRealPriceMayDependOnCustomer=Default price, real price may depend on customer
    @@ -292,7 +292,7 @@ SubProduct=Sub product
     ProductSheet=Product sheet
     ServiceSheet=Service sheet
     PossibleValues=Possible values
    -GoOnMenuToCreateVairants=Go on menu %s - %s to prepare attribute variants (like colors, size, ...) 
    +GoOnMenuToCreateVairants=Go on menu %s - %s to prepare attribute variants (like colors, size, ...)
     UseProductFournDesc=Use supplier descriptions of products in supplier documents
     ProductSupplierDescription=Supplier description for the product
     #Attributes
    @@ -330,6 +330,8 @@ NbOfDifferentValues=No. of different values
     NbProducts=No. of products
     ParentProduct=Parent product
     HideChildProducts=Hide variant products
    +ShowChildProducts=Show variant products
    +NoEditVariants=Go to Parent product card and edit variants price impact in the variants tab
     ConfirmCloneProductCombinations=Would you like to copy all the product variants to the other parent product with the given reference?
     CloneDestinationReference=Destination product reference
     ErrorCopyProductCombinations=There was an error while copying the product variants
    diff --git a/htdocs/langs/en_US/projects.lang b/htdocs/langs/en_US/projects.lang
    index 29216b7d8b3..ce94a6dcc46 100644
    --- a/htdocs/langs/en_US/projects.lang
    +++ b/htdocs/langs/en_US/projects.lang
    @@ -7,7 +7,7 @@ ProjectsArea=Projects Area
     ProjectStatus=Project status
     SharedProject=Everybody
     PrivateProject=Project contacts
    -ProjectsImContactFor=Projects I'm explicitely a contact of 
    +ProjectsImContactFor=Projects I'm explicitely a contact of
     AllAllowedProjects=All project I can read (mine + public)
     AllProjects=All projects
     MyProjectsDesc=This view is limited to projects you are a contact for
    @@ -126,7 +126,7 @@ TaskRessourceLinks=Contacts task
     ProjectsDedicatedToThisThirdParty=Projects dedicated to this third party
     NoTasks=No tasks for this project
     LinkedToAnotherCompany=Linked to other third party
    -TaskIsNotAssignedToUser=Task not assigned to user. Use button '<strong>%s</strong>' to assign task now. 
    +TaskIsNotAssignedToUser=Task not assigned to user. Use button '<strong>%s</strong>' to assign task now.
     ErrorTimeSpentIsEmpty=Time spent is empty
     ThisWillAlsoRemoveTasks=This action will also delete all tasks of project (<b>%s</b> tasks at the moment) and all inputs of time spent.
     IfNeedToUseOhterObjectKeepEmpty=If some objects (invoice, order, ...), belonging to another third party, must be linked to the project to create, keep this empty to have the project being multi third parties.
    diff --git a/htdocs/langs/en_US/propal.lang b/htdocs/langs/en_US/propal.lang
    index 2d2f1bb2ff0..fd1240e3ea6 100644
    --- a/htdocs/langs/en_US/propal.lang
    +++ b/htdocs/langs/en_US/propal.lang
    @@ -33,7 +33,7 @@ PropalStatusSigned=Signed (needs billing)
     PropalStatusNotSigned=Not signed (closed)
     PropalStatusBilled=Billed
     PropalStatusDraftShort=Draft
    -PropalStatusValidatedShort=Validated
    +PropalStatusValidatedShort=Validated (open)
     PropalStatusClosedShort=Closed
     PropalStatusSignedShort=Signed
     PropalStatusNotSignedShort=Not signed
    @@ -78,8 +78,9 @@ TypeContact_propal_external_CUSTOMER=Customer contact following-up proposal
     TypeContact_propal_external_SHIPPING=Customer contact for delivery
     # Document models
     DocModelAzurDescription=A complete proposal model (logo...)
    +DocModelCyanDescription=A complete proposal model (logo...)
     DefaultModelPropalCreate=Default model creation
     DefaultModelPropalToBill=Default template when closing a business proposal (to be invoiced)
     DefaultModelPropalClosed=Default template when closing a business proposal (unbilled)
     ProposalCustomerSignature=Written acceptance, company stamp, date and signature
    -ProposalsStatisticsSuppliers=Supplier proposals statistics 
    +ProposalsStatisticsSuppliers=Supplier proposals statistics
    diff --git a/htdocs/langs/en_US/salaries.lang b/htdocs/langs/en_US/salaries.lang
    index 2ba84f19514..620517b5324 100644
    --- a/htdocs/langs/en_US/salaries.lang
    +++ b/htdocs/langs/en_US/salaries.lang
    @@ -16,4 +16,4 @@ THMDescription=This value may be used to calculate cost of time consumed on a pr
     TJMDescription=This value is currently as information only and is not used for any calculation
     LastSalaries=Latest %s salary payments
     AllSalaries=All salary payments
    -SalariesStatistics=Salary statistics
    \ No newline at end of file
    +SalariesStatistics=Salary statistics
    diff --git a/htdocs/langs/en_US/sendings.lang b/htdocs/langs/en_US/sendings.lang
    index b8474775e75..2b46ada5ee9 100644
    --- a/htdocs/langs/en_US/sendings.lang
    +++ b/htdocs/langs/en_US/sendings.lang
    @@ -56,7 +56,7 @@ ProductQtyInCustomersOrdersRunning=Product quantity into open customer orders
     ProductQtyInSuppliersOrdersRunning=Product quantity into open purchase orders
     ProductQtyInShipmentAlreadySent=Product quantity from open customer order already sent
     ProductQtyInSuppliersShipmentAlreadyRecevied=Product quantity from open supplier order already received
    -NoProductToShipFoundIntoStock=No product to ship found into warehouse <b>%s</b>. Correct stock or go back to choose another warehouse. 
    +NoProductToShipFoundIntoStock=No product to ship found in warehouse <b>%s</b>. Correct stock or go back to choose another warehouse.
     WeightVolShort=Weight/Vol.
     ValidateOrderFirstBeforeShipment=You must first validate the order before being able to make shipments.
     
    diff --git a/htdocs/langs/en_US/sms.lang b/htdocs/langs/en_US/sms.lang
    index bf92a7b63cf..79bd8827198 100644
    --- a/htdocs/langs/en_US/sms.lang
    +++ b/htdocs/langs/en_US/sms.lang
    @@ -48,4 +48,4 @@ SmsInfoNumero= (international format ie : +33899701761)
     DelayBeforeSending=Delay before sending (minutes)
     SmsNoPossibleSenderFound=No sender available. Check setup of your SMS provider.
     SmsNoPossibleRecipientFound=No target available. Check setup of your SMS provider.
    -DisableStopIfSupported=Disable STOP message (if supported) 
    +DisableStopIfSupported=Disable STOP message (if supported)
    diff --git a/htdocs/langs/en_US/stocks.lang b/htdocs/langs/en_US/stocks.lang
    index 951178b8183..fbbc00887aa 100644
    --- a/htdocs/langs/en_US/stocks.lang
    +++ b/htdocs/langs/en_US/stocks.lang
    @@ -44,7 +44,6 @@ TransferStock=Transfer stock
     MassStockTransferShort=Mass stock transfer
     StockMovement=Stock movement
     StockMovements=Stock movements
    -LabelMovement=Movement label
     NumberOfUnit=Number of units
     UnitPurchaseValue=Unit purchase price
     StockTooLow=Stock too low
    @@ -78,7 +77,7 @@ StockLimit=Stock limit for alert
     StockLimitDesc=(empty) means no warning.<br>0 can be used for a warning as soon as stock is empty.
     PhysicalStock=Physical stock
     RealStock=Real Stock
    -RealStockDesc=Physical or real stock is the stock you currently have into your internal warehouses/emplacements. 
    +RealStockDesc=Physical or real stock is the stock you currently have into your internal warehouses/emplacements.
     RealStockWillAutomaticallyWhen=The real stock will automatically change according to this rules (see stock module setup to change this):
     VirtualStock=Virtual stock
     VirtualStockDesc=Virtual stock is the stock you will get once all open pending actions that affect stocks will be closed (supplier order received, customer order shipped, ...)
    @@ -134,10 +133,11 @@ StockMustBeEnoughForInvoice=Stock level must be enough to add product/service to
     StockMustBeEnoughForOrder=Stock level must be enough to add product/service to order (check is done on current real stock when adding a line into order whatever the rule for automatic stock change)
     StockMustBeEnoughForShipment= Stock level must be enough to add product/service to shipment (check is done on current real stock when adding a line into shipment whatever the rule for automatic stock change)
     MovementLabel=Label of movement
    +TypeMovement=Type of movement
     DateMovement=Date of movement
     InventoryCode=Movement or inventory code
     IsInPackage=Contained into package
    -WarehouseAllowNegativeTransfer=Stock can be negative 
    +WarehouseAllowNegativeTransfer=Stock can be negative
     qtyToTranferIsNotEnough=You don't have enough stock from your source warehouse and your setup does not allow negative stocks.
     ShowWarehouse=Show warehouse
     MovementCorrectStock=Stock correction for product %s
    @@ -177,7 +177,7 @@ inventoryMvtStock=By inventory
     inventoryWarningProductAlreadyExists=This product is already into list
     SelectCategory=Category filter
     SelectFournisseur=Supplier filter
    -inventoryOnDate=Inventory 
    +inventoryOnDate=Inventory
     INVENTORY_DISABLE_VIRTUAL=Allow to not destock child product from a kit on inventory
     INVENTORY_USE_MIN_PA_IF_NO_LAST_PA=Use the buy price if no last buy price can be found
     INVENTORY_USE_INVENTORY_DATE_FROM_DATEMVT=Stock movement have date of inventory
    @@ -203,4 +203,8 @@ RegulateStock=Regulate Stock
     ListInventory=List
     StockSupportServices=Stock management supports Services
     StockSupportServicesDesc=By default, you can stock only product with type "product". If on, and if module service is on, you can also stock a product with type "service"
    -ReceiveProducts=Receive items
    \ No newline at end of file
    +ReceiveProducts=Receive items
    +StockIncreaseAfterCorrectTransfer=Increase by correction/transfer
    +StockDecreaseAfterCorrectTransfer=Decrease by correction/transfer
    +StockIncrease=Stock increase
    +StockDecrease=Stock decrease
    diff --git a/htdocs/langs/en_US/trips.lang b/htdocs/langs/en_US/trips.lang
    index 0f9fcac1d02..2ede3bc474e 100644
    --- a/htdocs/langs/en_US/trips.lang
    +++ b/htdocs/langs/en_US/trips.lang
    @@ -33,7 +33,7 @@ ExpenseReportCanceledMessage=The expense report %s was canceled.<br> - User: %s<
     ExpenseReportPaid=An expense report was paid
     ExpenseReportPaidMessage=The expense report %s was paid.<br> - User: %s<br> - Paid by: %s<br>Click here to show the expense report: %s
     TripId=Id expense report
    -AnyOtherInThisListCanValidate=Person to inform for validation. 
    +AnyOtherInThisListCanValidate=Person to inform for validation.
     TripSociete=Information company
     TripNDF=Informations expense report
     PDFStandardExpenseReports=Standard template to generate a PDF document for expense report
    @@ -154,4 +154,4 @@ nolimitbyEX_EXP=by line (no limitation)
     
     CarCategory=Category of car
     ExpenseRangeOffset=Offset amount: %s
    -RangeIk=Mileage range
    \ No newline at end of file
    +RangeIk=Mileage range
    diff --git a/htdocs/langs/en_US/users.lang b/htdocs/langs/en_US/users.lang
    index 20c3e90ae41..68fffde3bb0 100644
    --- a/htdocs/langs/en_US/users.lang
    +++ b/htdocs/langs/en_US/users.lang
    @@ -35,7 +35,7 @@ SuperAdministrator=Super Administrator
     SuperAdministratorDesc=Global administrator
     AdministratorDesc=Administrator
     DefaultRights=Default permissions
    -DefaultRightsDesc=Define here <u>default</u> permissions that are automatically granted to a <u>new created</u> user (Go on user card to change permission of an existing user).
    +DefaultRightsDesc=Define here <u>default</u> permissions that are automatically granted to a <u>new created</u> user (Go to user card to change permission of an existing user).
     DolibarrUsers=Dolibarr users
     LastName=Last name
     FirstName=First name
    @@ -108,4 +108,4 @@ UserAccountancyCode=User accounting code
     UserLogoff=User logout
     UserLogged=User logged
     DateEmployment=Date of Employment
    -DateEmploymentEnd=End date of Employment
    \ No newline at end of file
    +DateEmploymentEnd=End date of Employment
    diff --git a/htdocs/langs/en_US/website.lang b/htdocs/langs/en_US/website.lang
    index 9ed064b5d1e..bee23264d7a 100644
    --- a/htdocs/langs/en_US/website.lang
    +++ b/htdocs/langs/en_US/website.lang
    @@ -1,4 +1,4 @@
    -# Dolibarr language file - Source file is en_US - website 
    +# Dolibarr language file - Source file is en_US - website
     Shortname=Code
     WebsiteSetupDesc=Create here the websites you wish to use. Then go into menu Websites to edit them.
     DeleteWebsite=Delete website
    @@ -16,7 +16,7 @@ WEBSITE_ROBOT=Robot file (robots.txt)
     WEBSITE_HTACCESS=Web site .htaccess file
     HtmlHeaderPage=HTML header (specific to this page only)
     PageNameAliasHelp=Name or alias of the page.<br>This alias is also used to forge a SEO URL when website is ran from a Virtual host of a Web server (like Apacke, Nginx, ...). Use the button "<strong>%s</strong>" to edit this alias.
    -EditTheWebSiteForACommonHeader=Note: If you want to define a personalized header for all pages, edit the header on the site level instead of on the page/container.   
    +EditTheWebSiteForACommonHeader=Note: If you want to define a personalized header for all pages, edit the header on the site level instead of on the page/container.
     MediaFiles=Media library
     EditCss=Edit website properties
     EditMenu=Edit menu
    @@ -45,13 +45,13 @@ CheckVirtualHostPerms=Check also that virtual host has permission <strong>%s</st
     ReadPerm=Read
     WritePerm=Write
     PreviewSiteServedByWebServer=<u>Preview %s in a new tab.</u><br><br>The %s will be served by an external web server (like Apache, Nginx, IIS). You must install and setup this server before to point to directory:<br><strong>%s</strong><br>URL served by external server:<br><strong>%s</strong>
    -PreviewSiteServedByDolibarr=<u>Preview %s in a new tab.</u><br><br>The %s will be served by Dolibarr server so it does not need any extra web server (like Apache, Nginx, IIS) to be installed.<br>The inconvenient is that URL of pages are not user friendly and start with path of your Dolibarr.<br>URL served by Dolibarr:<br><strong>%s</strong><br><br>To use your own external web server to serve this web site, create a virtual host on your web server that point on directory<br><strong>%s</strong><br>then enter the name of this virtual server and click on the other preview button.  
    +PreviewSiteServedByDolibarr=<u>Preview %s in a new tab.</u><br><br>The %s will be served by Dolibarr server so it does not need any extra web server (like Apache, Nginx, IIS) to be installed.<br>The inconvenient is that URL of pages are not user friendly and start with path of your Dolibarr.<br>URL served by Dolibarr:<br><strong>%s</strong><br><br>To use your own external web server to serve this web site, create a virtual host on your web server that point on directory<br><strong>%s</strong><br>then enter the name of this virtual server and click on the other preview button.
     VirtualHostUrlNotDefined=URL of the virtual host served by external web server not defined
     NoPageYet=No pages yet
     YouCanCreatePageOrImportTemplate=You can create a new page or import a full website template
     SyntaxHelp=Help on specific syntax tips
    -YouCanEditHtmlSourceckeditor=You can edit HTML source code using the "Source" button in editor. 
    -YouCanEditHtmlSource=<br><span class="fa fa-bug"></span> You can include PHP code into this source using tags <strong>&lt;?php ?&gt;</strong>. The following global variables are available: $conf, $db, $mysoc, $user, $website, $weblangs.<br><br><span class="fa fa-bug"></span> You can also include content of another Page/Container with the following syntax:<br><strong>&lt;?php includeContainer('alias_of_container_to_include'); ?&gt;</strong><br><br><span class="fa fa-bug"></span> You can make a redirect to another Page/Container with the following syntax (Note: do not output any content before a redirect):<br><strong>&lt;?php redirectToContainer('alias_of_container_to_redirect_to'); ?&gt;</strong><br><br><span class="fa fa-link"></span> To add a link to another page, use the syntax:<br><strong>&lt;a href="alias_of_page_to_link_to.php"&gt;mylink&lt;a&gt;</strong><br><br><span class="fa fa-download"></span> To include a <strong>link to download</strong> a file stored into the <strong>documents</strong> directory, use the <strong>document.php</strong> wrapper:<br>Example, for a file into documents/ecm (need to be logged), syntax is:<br><strong>&lt;a href="/document.php?modulepart=ecm&file=[relative_dir/]filename.ext"&gt;</strong><br>For a file into documents/medias (open directory for public access), syntax is:<br><strong>&lt;a href="/document.php?modulepart=medias&file=[relative_dir/]filename.ext"&gt;</strong><br>For a file shared with a share link (open access using the sharing hash key of file), syntax is:<br><strong>&lt;a href="/document.php?hashp=publicsharekeyoffile"&gt;</strong><br><br><span class="fa fa-picture-o"></span> To include an <strong>image</strong> stored into the <strong>documents</strong> directory, use the <strong>viewimage.php</strong> wrapper:<br>Example, for an image into documents/medias (open directory for public access), syntax is:<br><strong>&lt;img src="/viewimage.php?modulepart=medias&amp;file=[relative_dir/]filename.ext"&gt;</strong><br>
    +YouCanEditHtmlSourceckeditor=You can edit HTML source code using the "Source" button in editor.
    +YouCanEditHtmlSource=<br><span class="fa fa-bug"></span> You can include PHP code into this source using tags <strong>&lt;?php ?&gt;</strong>. The following global variables are available: $conf, $db, $mysoc, $user, $website, $websitepage, $weblangs.<br><br><span class="fa fa-bug"></span> You can also include content of another Page/Container with the following syntax:<br><strong>&lt;?php includeContainer('alias_of_container_to_include'); ?&gt;</strong><br><br><span class="fa fa-bug"></span> You can make a redirect to another Page/Container with the following syntax (Note: do not output any content before a redirect):<br><strong>&lt;?php redirectToContainer('alias_of_container_to_redirect_to'); ?&gt;</strong><br><br><span class="fa fa-link"></span> To add a link to another page, use the syntax:<br><strong>&lt;a href="alias_of_page_to_link_to.php"&gt;mylink&lt;a&gt;</strong><br><br><span class="fa fa-download"></span> To include a <strong>link to download</strong> a file stored into the <strong>documents</strong> directory, use the <strong>document.php</strong> wrapper:<br>Example, for a file into documents/ecm (need to be logged), syntax is:<br><strong>&lt;a href="/document.php?modulepart=ecm&file=[relative_dir/]filename.ext"&gt;</strong><br>For a file into documents/medias (open directory for public access), syntax is:<br><strong>&lt;a href="/document.php?modulepart=medias&file=[relative_dir/]filename.ext"&gt;</strong><br>For a file shared with a share link (open access using the sharing hash key of file), syntax is:<br><strong>&lt;a href="/document.php?hashp=publicsharekeyoffile"&gt;</strong><br><br><span class="fa fa-picture-o"></span> To include an <strong>image</strong> stored into the <strong>documents</strong> directory, use the <strong>viewimage.php</strong> wrapper:<br>Example, for an image into documents/medias (open directory for public access), syntax is:<br><strong>&lt;img src="/viewimage.php?modulepart=medias&amp;file=[relative_dir/]filename.ext"&gt;</strong><br>
     ClonePage=Clone page/container
     CloneSite=Clone site
     SiteAdded=Web site added
    @@ -90,4 +90,6 @@ EmptyPage=Empty page
     ExternalURLMustStartWithHttp=External URL must start with http:// or https://
     ZipOfWebsitePackageToImport=Zip file of website package
     ShowSubcontainers=Show included containers
    -InternalURLOfPage=Internal URL of page
    \ No newline at end of file
    +InternalURLOfPage=Internal URL of page
    +ThisPageIsTranslationOf=This page/container is translation of
    +ThisPageHasTranslationPages=This page/container has translation
    \ No newline at end of file
    diff --git a/htdocs/langs/en_US/withdrawals.lang b/htdocs/langs/en_US/withdrawals.lang
    index 6162bfe6aa1..c2c384793c4 100644
    --- a/htdocs/langs/en_US/withdrawals.lang
    +++ b/htdocs/langs/en_US/withdrawals.lang
    @@ -61,7 +61,7 @@ CreateAll=Create direct debit file (all)
     CreateGuichet=Only office
     CreateBanque=Only bank
     OrderWaiting=Waiting for treatment
    -NotifyTransmision=Withdrawal Transmission 
    +NotifyTransmision=Withdrawal Transmission
     NotifyCredit=Withdrawal Credit
     NumeroNationalEmetter=National Transmitter Number
     WithBankUsingRIB=For bank accounts using RIB
    @@ -80,7 +80,7 @@ RUM=UMR
     RUMLong=Unique Mandate Reference
     RUMWillBeGenerated=If empty, UMR number will be generated once bank account information are saved
     WithdrawMode=Direct debit mode (FRST or RECUR)
    -WithdrawRequestAmount=Amount of Direct debit request: 
    +WithdrawRequestAmount=Amount of Direct debit request:
     WithdrawRequestErrorNilAmount=Unable to create direct debit request for empty amount.
     SepaMandate=SEPA Direct Debit Mandate
     SepaMandateShort=SEPA Mandate
    @@ -103,7 +103,7 @@ SEPAFRST=SEPA FRST
     ExecutionDate=Execution date
     CreateForSepa=Create direct debit file
     
    -### Notifications 
    +### Notifications
     InfoCreditSubject=Payment of direct debit payment order %s by the bank
     InfoCreditMessage=The direct debit payment order %s has been paid by the bank<br>Data of payment: %s
     InfoTransSubject=Transmission of direct debit payment order %s to bank
    diff --git a/htdocs/langs/en_US/workflow.lang b/htdocs/langs/en_US/workflow.lang
    index 3dab69667c4..c16caf44765 100644
    --- a/htdocs/langs/en_US/workflow.lang
    +++ b/htdocs/langs/en_US/workflow.lang
    @@ -1,4 +1,4 @@
    -# Dolibarr language file - Source file is en_US - workflow 
    +# Dolibarr language file - Source file is en_US - workflow
     WorkflowSetup=Workflow module setup
     WorkflowDesc=This module provides some automatic actions. By default, the workflow is open (you can do things in the order you want) but here you can activate some automatic actions.
     ThereIsNoWorkflowToModify=There is no workflow modifications available with the activated modules.
    @@ -17,4 +17,4 @@ descWORKFLOW_ORDER_CLASSIFY_SHIPPED_SHIPPING=Classify linked source customer ord
     descWORKFLOW_ORDER_CLASSIFY_BILLED_SUPPLIER_PROPOSAL=Classify linked source vendor proposal as billed when vendor invoice is validated (and if the amount of the invoice is the same as the total amount of the linked proposal)
     descWORKFLOW_INVOICE_AMOUNT_CLASSIFY_BILLED_SUPPLIER_ORDER=Classify linked source purchase order as billed when vendor invoice is validated (and if the amount of the invoice is the same as the total amount of the linked order)
     AutomaticCreation=Automatic creation
    -AutomaticClassification=Automatic classification
    \ No newline at end of file
    +AutomaticClassification=Automatic classification
    diff --git a/htdocs/langs/es_ES/other.lang b/htdocs/langs/es_ES/other.lang
    index 137bbac42d6..acdc769a7c5 100644
    --- a/htdocs/langs/es_ES/other.lang
    +++ b/htdocs/langs/es_ES/other.lang
    @@ -188,6 +188,7 @@ NumberOfUnitsSupplierInvoices=Número de unidades en las facturas de proveedores
     EMailTextInterventionAddedContact=Se le ha asignado la intervención %s
     EMailTextInterventionValidated=Ficha intervención %s validada
     EMailTextInvoiceValidated=Factura %s validada
    +EMailTextInvoicePayed=La factura %s ha sido pagada.
     EMailTextProposalValidated=El presupuesto %s que le concierne ha sido validado.
     EMailTextProposalClosedSigned=El presupuesto %s ha sido cerrado y firmado.
     EMailTextOrderValidated=El pedido %s que le concierne ha sido validado.
    diff --git a/htdocs/langs/fr_FR/admin.lang b/htdocs/langs/fr_FR/admin.lang
    index 72bc5acd097..e81fbfcdbb8 100644
    --- a/htdocs/langs/fr_FR/admin.lang
    +++ b/htdocs/langs/fr_FR/admin.lang
    @@ -1208,7 +1208,7 @@ WatermarkOnDraft=Filigrane sur les documents brouillons
     JSOnPaimentBill=Activer la fonctionnalité de remplissage automatique des lignes de paiement sur le formulaire de paiement
     CompanyIdProfChecker=Règles sur les Identifiants professionnels
     MustBeUnique=Doit être unique ?
    -MustBeMandatory=Obligatoire pour créer des tiers ?
    +MustBeMandatory=Obligatoire pour créer des tiers (si num tva ou type de société défini) ?
     MustBeInvoiceMandatory=Obligatoire pour valider des factures ?
     TechnicalServicesProvided=Services techniques fournis
     #####DAV #####
    diff --git a/htdocs/langs/fr_FR/companies.lang b/htdocs/langs/fr_FR/companies.lang
    index fbd8bb87e4e..548a7f6e0dd 100644
    --- a/htdocs/langs/fr_FR/companies.lang
    +++ b/htdocs/langs/fr_FR/companies.lang
    @@ -38,7 +38,7 @@ ThirdPartyCustomers=Clients
     ThirdPartyCustomersStats=Clients
     ThirdPartyCustomersWithIdProf12=Clients avec %s ou %s
     ThirdPartySuppliers=Fournisseurs
    -ThirdPartyType=Type du tiers
    +ThirdPartyType=Type du société
     Individual=Individu privé
     ToCreateContactWithSameName=Crée automatiquement un contact/adresse, sous le tiers, avec la même information que le tiers. Dans la plupart des cas, même si votre tiers est une personne physique, la création d'un tiers seul suffit.
     ParentCompany=Maison mère
    diff --git a/htdocs/langs/fr_FR/propal.lang b/htdocs/langs/fr_FR/propal.lang
    index f35f63cf34d..a575824fc72 100644
    --- a/htdocs/langs/fr_FR/propal.lang
    +++ b/htdocs/langs/fr_FR/propal.lang
    @@ -33,7 +33,7 @@ PropalStatusSigned=Signée (à facturer)
     PropalStatusNotSigned=Non signée (fermée)
     PropalStatusBilled=Facturée
     PropalStatusDraftShort=Brouillon
    -PropalStatusValidatedShort=Validé
    +PropalStatusValidatedShort=Validée (ouverte)
     PropalStatusClosedShort=Fermée
     PropalStatusSignedShort=Signée
     PropalStatusNotSignedShort=Non signée
    diff --git a/htdocs/langs/fr_FR/users.lang b/htdocs/langs/fr_FR/users.lang
    index e0f461cd196..fa5e772fe7e 100644
    --- a/htdocs/langs/fr_FR/users.lang
    +++ b/htdocs/langs/fr_FR/users.lang
    @@ -6,7 +6,7 @@ Permission=Droit
     Permissions=Droits
     EditPassword=Modifier mot de passe
     SendNewPassword=Régénérer et envoyer mot de passe
    -SendNewPasswordLink=Envoyer le lien pour réinitialiser le mot de passe
    +SendNewPasswordLink=Réinitialiser le mot de passe
     ReinitPassword=Régénérer mot de passe
     PasswordChangedTo=Mot de passe modifié en: %s
     SubjectNewPassword=Votre mot de passe pour %s
    diff --git a/htdocs/livraison/card.php b/htdocs/livraison/card.php
    index 44eb12299d9..2fee2e100ba 100644
    --- a/htdocs/livraison/card.php
    +++ b/htdocs/livraison/card.php
    @@ -292,6 +292,7 @@ elseif ($action == 'remove_file')
     }
     */
     
    +include DOL_DOCUMENT_ROOT.'/core/actions_printing.inc.php';
     
     /*
      *	View
    diff --git a/htdocs/loan/calcmens.php b/htdocs/loan/calcmens.php
    index fbe1cecab2d..df6db76e1f2 100644
    --- a/htdocs/loan/calcmens.php
    +++ b/htdocs/loan/calcmens.php
    @@ -50,7 +50,7 @@ $echance++;
     $capital=$cap_rest;
     while ($echance<=$nbterm) {
     
    -	$mens = round($object->calc_mens($capital,$rate,$nbterm-$echance+1),2,PHP_ROUND_HALF_UP);
    +	$mens = round($object->calcMonthlyPayments($capital, $rate, $nbterm-$echance+1), 2, PHP_ROUND_HALF_UP);
     
     	$int = ($capital*($rate/12));
     	$int = round($int,2,PHP_ROUND_HALF_UP);
    @@ -63,4 +63,3 @@ while ($echance<=$nbterm) {
     }
     
     echo json_encode($output);
    -
    diff --git a/htdocs/loan/class/loan.class.php b/htdocs/loan/class/loan.class.php
    index dd066f0064c..0e4542b1d20 100644
    --- a/htdocs/loan/class/loan.class.php
    +++ b/htdocs/loan/class/loan.class.php
    @@ -51,7 +51,7 @@ class Loan extends CommonObject
     	public $datestart;
     	public $dateend;
     
    -	/**
    +    /**
          * @var string Loan label
          */
         public $label;
    @@ -66,9 +66,25 @@ class Loan extends CommonObject
     	public $date_creation;
     	public $date_modification;
     	public $date_validation;
    +
    +	/**
    +     * @var int Bank ID
    +     */
     	public $fk_bank;
    +
    +	/**
    +     * @var int ID
    +     */
     	public $fk_user_creat;
    +
    +	/**
    +     * @var int ID
    +     */
     	public $fk_user_modif;
    +
    +	/**
    +     * @var int ID
    +     */
     	public $fk_project;
     
     
    @@ -158,10 +174,10 @@ class Loan extends CommonObject
     		if (isset($this->account_capital)) $this->account_capital = trim($this->account_capital);
     		if (isset($this->account_insurance)) $this->account_insurance = trim($this->account_insurance);
     		if (isset($this->account_interest)) $this->account_interest = trim($this->account_interest);
    -		if (isset($this->fk_bank)) $this->fk_bank=trim($this->fk_bank);
    -		if (isset($this->fk_user_creat)) $this->fk_user_creat=trim($this->fk_user_creat);
    -		if (isset($this->fk_user_modif)) $this->fk_user_modif=trim($this->fk_user_modif);
    -		if (isset($this->fk_project)) $this->fk_project=trim($this->fk_project);
    +		if (isset($this->fk_bank)) $this->fk_bank = (int) $this->fk_bank;
    +		if (isset($this->fk_user_creat)) $this->fk_user_creat = (int) $this->fk_user_creat;
    +		if (isset($this->fk_user_modif)) $this->fk_user_modif = (int) $this->fk_user_modif;
    +		if (isset($this->fk_project)) $this->fk_project = (int) $this->fk_project;
     
     		// Check parameters
     		if (! $newcapital > 0 || empty($this->datestart) || empty($this->dateend))
    @@ -445,9 +461,9 @@ class Loan extends CommonObject
     
     		$tooltip = '<u>' . $langs->trans("ShowLoan") . '</u>';
     		if (! empty($this->ref))
    -			$tooltip .= '<br><b>' . $langs->trans('Ref') . ':</b> ' . $this->ref;
    +			$tooltip .= '<br><strong>' . $langs->trans('Ref') . ':</strong> ' . $this->ref;
     		if (! empty($this->label))
    -			$tooltip .= '<br><b>' . $langs->trans('Label') . ':</b> ' . $this->label;
    +			$tooltip .= '<br><strong>' . $langs->trans('Label') . ':</strong> ' . $this->label;
     
     		$linkstart = '<a href="'.DOL_URL_ROOT.'/loan/card.php?id='.$this->id.'" title="'.str_replace('\n', '', dol_escape_htmltag($tooltip, 1)).'" class="classfortooltip">';
     		$linkend = '</a>';
    diff --git a/htdocs/loan/class/loanschedule.class.php b/htdocs/loan/class/loanschedule.class.php
    index 2f37b1a870c..208f325a384 100644
    --- a/htdocs/loan/class/loanschedule.class.php
    +++ b/htdocs/loan/class/loanschedule.class.php
    @@ -1,5 +1,6 @@
     <?php
    -/* Copyright (C) 2017	Florian HENRY <florian.henry@atm-consulting.fr>
    +/* Copyright (C) 2017       Florian HENRY           <florian.henry@atm-consulting.fr>
    + * Copyright (C) 2018       Frédéric France         <frederic.france@netlogic.fr>
      *
      * This program is free software; you can redistribute it and/or modify
      * it under the terms of the GNU General Public License as published by
    @@ -39,20 +40,53 @@ class LoanSchedule extends CommonObject
     	 */
     	public $table_element='loan_schedule';
     
    -	var $fk_loan;
    -	var $datec='';
    -	var $tms='';
    -	var $datep='';
    -    var $amounts=array();   // Array of amounts
    -    var $amount_capital;    // Total amount of payment
    -	var $amount_insurance;
    -	var $amount_interest;
    -	var $fk_typepayment;
    -	var $num_payment;
    -	var $fk_bank;
    -	var $fk_user_creat;
    -	var $fk_user_modif;
    -	var $lines=array();
    +    /**
    +     * @var int Loan ID
    +     */
    +    public $fk_loan;
    +
    +    /**
    +     * @var string Create date
    +     */
    +    public $datec='';
    +	public $tms='';
    +
    +    /**
    +     * @var string Payment date
    +     */
    +    public $datep='';
    +
    +    public $amounts=array();   // Array of amounts
    +    public $amount_capital;    // Total amount of payment
    +	public $amount_insurance;
    +	public $amount_interest;
    +
    +    /**
    +     * @var int Payment Type ID
    +     */
    +    public $fk_typepayment;
    +
    +    /**
    +     * @var int Payment ID
    +     */
    +    public $num_payment;
    +
    +    /**
    +     * @var int Bank ID
    +     */
    +    public $fk_bank;
    +
    +    /**
    +     * @var int Bank ID
    +     */
    +    public $fk_user_creat;
    +
    +    /**
    +     * @var int User ID
    +     */
    +    public $fk_user_modif;
    +
    +	public $lines=array();
     
     	/**
     	 * @deprecated
    @@ -65,7 +99,7 @@ class LoanSchedule extends CommonObject
     	 *
     	 *  @param		DoliDB		$db      Database handler
     	 */
    -	function __construct($db)
    +	public function __construct($db)
     	{
     		$this->db = $db;
     	}
    @@ -77,7 +111,7 @@ class LoanSchedule extends CommonObject
     	 *  @param      User		$user   User making payment
     	 *  @return     int     			<0 if KO, id of payment if OK
     	 */
    -	function create($user)
    +	public function create($user)
     	{
     		global $conf, $langs;
     
    @@ -86,21 +120,21 @@ class LoanSchedule extends CommonObject
             $now=dol_now();
     
             // Validate parameters
    -		if (! $this->datepaid)
    +		if (! $this->datep)
     		{
     			$this->error='ErrorBadValueForParameter';
     			return -1;
     		}
     
     		// Clean parameters
    -		if (isset($this->fk_loan)) 			$this->fk_loan = trim($this->fk_loan);
    +		if (isset($this->fk_loan)) $this->fk_loan = (int) $this->fk_loan;
     		if (isset($this->amount_capital))	$this->amount_capital = trim($this->amount_capital?$this->amount_capital:0);
     		if (isset($this->amount_insurance))	$this->amount_insurance = trim($this->amount_insurance?$this->amount_insurance:0);
     		if (isset($this->amount_interest))	$this->amount_interest = trim($this->amount_interest?$this->amount_interest:0);
    -		if (isset($this->fk_typepayment))	$this->fk_typepayment = trim($this->fk_typepayment);
    -		if (isset($this->fk_bank))			$this->fk_bank = trim($this->fk_bank);
    -		if (isset($this->fk_user_creat))	$this->fk_user_creat = trim($this->fk_user_creat);
    -		if (isset($this->fk_user_modif))	$this->fk_user_modif = trim($this->fk_user_modif);
    +		if (isset($this->fk_typepayment)) $this->fk_typepayment = (int) $this->fk_typepayment;
    +		if (isset($this->fk_bank)) $this->fk_bank = (int) $this->fk_bank;
    +		if (isset($this->fk_user_creat)) $this->fk_user_creat = (int) $this->fk_user_creat;
    +		if (isset($this->fk_user_modif)) $this->fk_user_modif = (int) $this->fk_user_modif;
     
             $totalamount = $this->amount_capital + $this->amount_insurance + $this->amount_interest;
             $totalamount = price2num($totalamount);
    @@ -119,7 +153,7 @@ class LoanSchedule extends CommonObject
     			$sql = "INSERT INTO ".MAIN_DB_PREFIX.$this->table_element." (fk_loan, datec, datep, amount_capital, amount_insurance, amount_interest,";
     			$sql.= " fk_typepayment, fk_user_creat, fk_bank)";
     			$sql.= " VALUES (".$this->fk_loan.", '".$this->db->idate($now)."',";
    -			$sql.= " '".$this->db->idate($this->datepaid)."',";
    +			$sql.= " '".$this->db->idate($this->datep)."',";
     			$sql.= " ".$this->amount_capital.",";
     			$sql.= " ".$this->amount_insurance.",";
     			$sql.= " ".$this->amount_interest.",";
    @@ -162,7 +196,7 @@ class LoanSchedule extends CommonObject
     	 *  @param	int		$id         Id object
     	 *  @return int         		<0 if KO, >0 if OK
     	 */
    -	function fetch($id)
    +	public function fetch($id)
     	{
     		global $langs;
     		$sql = "SELECT";
    @@ -215,8 +249,8 @@ class LoanSchedule extends CommonObject
                     $this->type_code = $obj->type_code;
                     $this->type_libelle = $obj->type_libelle;
     
    -                $this->bank_account   = $obj->fk_account;
    -                $this->bank_line      = $obj->fk_bank;
    +                $this->bank_account = $obj->fk_account;
    +                $this->bank_line = $obj->fk_bank;
                 }
                 $this->db->free($resql);
     
    @@ -237,7 +271,7 @@ class LoanSchedule extends CommonObject
     	 *  @param  int		$notrigger	    0=launch triggers after, 1=disable triggers
     	 *  @return int         			<0 if KO, >0 if OK
     	 */
    -	function update($user=0, $notrigger=0)
    +	public function update($user=0, $notrigger=0)
     	{
     		global $conf, $langs;
     		$error=0;
    @@ -321,7 +355,7 @@ class LoanSchedule extends CommonObject
     	 *  @param  int		$notrigger		0=launch triggers after, 1=disable triggers
     	 *  @return int						<0 if KO, >0 if OK
     	 */
    -	function delete($user, $notrigger=0)
    +	public function delete($user, $notrigger=0)
     	{
     		global $conf, $langs;
     		$error=0;
    @@ -372,18 +406,16 @@ class LoanSchedule extends CommonObject
     		}
     	}
     
    -	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
     	/**
    -	 * Calculate mensuality
    +	 * Calculate Monthly Payments
     	 *
     	 * @param   double  $capital        Capital
     	 * @param   double  $rate           rate
     	 * @param   int     $nbterm         nb term
     	 * @return  double                  mensuality
     	 */
    -	function calc_mens($capital, $rate, $nbterm)
    +	public function calcMonthlyPayments($capital, $rate, $nbterm)
     	{
    -        // phpcs:enable
     		$result='';
     
     		if (!empty($capital) && !empty($rate) && !empty($nbterm)) {
    @@ -400,7 +432,7 @@ class LoanSchedule extends CommonObject
     	 *  @param	int		$loanid     Id object
     	 *  @return int         		<0 if KO, >0 if OK
     	 */
    -	function fetchAll($loanid)
    +	public function fetchAll($loanid)
     	{
     		global $langs;
     
    @@ -461,15 +493,13 @@ class LoanSchedule extends CommonObject
     		}
     	}
     
    -    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
     	/**
    -	 *  trans_paiment
    +	 *  transPayment
     	 *
     	 *  @return void
     	 */
    -	function trans_paiment()
    +	private function transPayment()
     	{
    -        // phpcs:enable
     		require_once DOL_DOCUMENT_ROOT.'/loan/class/loan.class.php';
     		require_once DOL_DOCUMENT_ROOT.'/core/lib/loan.lib.php';
     		require_once DOL_DOCUMENT_ROOT.'/core/lib/date.lib.php';
    @@ -483,7 +513,7 @@ class LoanSchedule extends CommonObject
     
     		if($resql){
     			while($obj = $this->db->fetch_object($resql)){
    -				$lastrecorded = $this->lastpaiment($obj->rowid);
    +				$lastrecorded = $this->lastPayment($obj->rowid);
     				$toinsert = $this->paimenttorecord($obj->rowid, $lastrecorded);
     				if(count($toinsert)>0){
     					foreach ($toinsert as $echid){
    @@ -505,12 +535,12 @@ class LoanSchedule extends CommonObject
     
     
     	/**
    -	 *  trans_paiment
    +	 *  lastpayment
     	 *
     	 *  @param  int    $loanid     Loan id
     	 *  @return int                < 0 if KO, Date > 0 if OK
     	 */
    -	function lastpaiment($loanid)
    +	private function lastPayment($loanid)
     	{
     		$sql = "SELECT p.datep";
     		$sql.= " FROM ".MAIN_DB_PREFIX."payment_loan as p ";
    @@ -535,7 +565,7 @@ class LoanSchedule extends CommonObject
     	 *  @param  int        $datemax    Date max
     	 *  @return array                  Array of id
     	 */
    -	function paimenttorecord($loanid, $datemax)
    +	public function paimenttorecord($loanid, $datemax)
     	{
     		$sql = "SELECT p.rowid";
     		$sql.= " FROM ".MAIN_DB_PREFIX.$this->table_element." as p ";
    diff --git a/htdocs/loan/class/paymentloan.class.php b/htdocs/loan/class/paymentloan.class.php
    index add1aef496d..c4c29c99dce 100644
    --- a/htdocs/loan/class/paymentloan.class.php
    +++ b/htdocs/loan/class/paymentloan.class.php
    @@ -1,6 +1,6 @@
     <?php
     /* Copyright (C) 2014-2018  Alexandre Spangaro   <aspangaro@zendsi.com>
    - * Copyright (C) 2015       Frederic France      <frederic.france@free.fr>
    + * Copyright (C) 2015-2018  Frederic France      <frederic.france@netlogic.fr>
      *
      * This program is free software; you can redistribute it and/or modify
      * it under the terms of the GNU General Public License as published by
    @@ -40,32 +40,68 @@ class PaymentLoan extends CommonObject
     	 */
     	public $table_element='payment_loan';
     
    -	var $fk_loan;
    -	var $datec='';
    -	var $tms='';
    -	var $datep='';
    -	var $amounts=array();   // Array of amounts
    -	var $amount_capital;    // Total amount of payment
    -	var $amount_insurance;
    -	var $amount_interest;
    -	var $fk_typepayment;
    -	var $num_payment;
    -	var $fk_bank;
    -	var $fk_user_creat;
    -	var $fk_user_modif;
    +    /**
    +     * @var int Loan ID
    +     */
    +    public $fk_loan;
    +
    +    /**
    +     * @var string Create date
    +     */
    +    public $datec='';
    +
    +    public $tms='';
    +
    +    /**
    +     * @var string Payment date
    +     */
    +    public $datep='';
    +
    +    public $amounts=array();   // Array of amounts
    +
    +    public $amount_capital;    // Total amount of payment
    +
    +    public $amount_insurance;
    +
    +    public $amount_interest;
    +
    +    /**
    +     * @var int Payment type ID
    +     */
    +    public $fk_typepayment;
    +
    +    /**
    +     * @var int Payment ID
    +     */
    +    public $num_payment;
    +
    +    /**
    +     * @var int Bank ID
    +     */
    +    public $fk_bank;
    +
    +    /**
    +     * @var int User ID
    +     */
    +    public $fk_user_creat;
    +
    +    /**
    +     * @var int user ID
    +     */
    +    public $fk_user_modif;
     
     	/**
     	 * @deprecated
     	 * @see amount, amounts
     	 */
    -	var $total;
    +    public $total;
     
     	/**
     	 *	Constructor
     	 *
     	 *  @param		DoliDB		$db      Database handler
     	 */
    -	function __construct($db)
    +	public function __construct($db)
     	{
     		$this->db = $db;
     	}
    @@ -86,24 +122,24 @@ class PaymentLoan extends CommonObject
     		$now=dol_now();
     
     		// Validate parameters
    -		if (! $this->datepaid)
    +		if (! $this->datep)
     		{
     			$this->error='ErrorBadValueForParameter';
     			return -1;
     		}
     
     		// Clean parameters
    -		if (isset($this->fk_loan)) 			$this->fk_loan = trim($this->fk_loan);
    +		if (isset($this->fk_loan)) $this->fk_loan = (int) $this->fk_loan;
     		if (isset($this->amount_capital))	$this->amount_capital = price2num($this->amount_capital?$this->amount_capital:0);
    -		if (isset($this->amount_insurance))	$this->amount_insurance = price2num($this->amount_insurance?$this->amount_insurance:0);
    +		if (isset($this->amount_insurance)) $this->amount_insurance = price2num($this->amount_insurance?$this->amount_insurance:0);
     		if (isset($this->amount_interest))	$this->amount_interest = price2num($this->amount_interest?$this->amount_interest:0);
    -		if (isset($this->fk_typepayment))	$this->fk_typepayment = trim($this->fk_typepayment);
    -		if (isset($this->num_payment))		$this->num_payment = trim($this->num_payment);
    +		if (isset($this->fk_typepayment)) $this->fk_typepayment = (int) $this->fk_typepayment;
    +		if (isset($this->num_payment)) $this->num_payment = (int) $this->num_payment;
     		if (isset($this->note_private))     $this->note_private = trim($this->note_private);
     		if (isset($this->note_public))      $this->note_public = trim($this->note_public);
    -		if (isset($this->fk_bank))			$this->fk_bank = trim($this->fk_bank);
    -		if (isset($this->fk_user_creat))	$this->fk_user_creat = trim($this->fk_user_creat);
    -		if (isset($this->fk_user_modif))	$this->fk_user_modif = trim($this->fk_user_modif);
    +		if (isset($this->fk_bank)) $this->fk_bank = (int) $this->fk_bank;
    +		if (isset($this->fk_user_creat)) $this->fk_user_creat = (int) $this->fk_user_creat;
    +		if (isset($this->fk_user_modif)) $this->fk_user_modif = (int) $this->fk_user_modif;
     
     		$totalamount = $this->amount_capital + $this->amount_insurance + $this->amount_interest;
     		$totalamount = price2num($totalamount);
    @@ -119,7 +155,7 @@ class PaymentLoan extends CommonObject
     			$sql = "INSERT INTO ".MAIN_DB_PREFIX."payment_loan (fk_loan, datec, datep, amount_capital, amount_insurance, amount_interest,";
     			$sql.= " fk_typepayment, num_payment, note_private, note_public, fk_user_creat, fk_bank)";
     			$sql.= " VALUES (".$this->chid.", '".$this->db->idate($now)."',";
    -			$sql.= " '".$this->db->idate($this->datepaid)."',";
    +			$sql.= " '".$this->db->idate($this->datep)."',";
     			$sql.= " ".$this->amount_capital.",";
     			$sql.= " ".$this->amount_insurance.",";
     			$sql.= " ".$this->amount_interest.",";
    @@ -244,17 +280,17 @@ class PaymentLoan extends CommonObject
     		$error=0;
     
     		// Clean parameters
    -		if (isset($this->fk_loan)) $this->fk_loan=trim($this->fk_loan);
    +		if (isset($this->fk_loan)) $this->fk_loan = (int) $this->fk_loan;
     		if (isset($this->amount_capital)) $this->amount_capital=trim($this->amount_capital);
     		if (isset($this->amount_insurance)) $this->amount_insurance=trim($this->amount_insurance);
     		if (isset($this->amount_interest)) $this->amount_interest=trim($this->amount_interest);
    -		if (isset($this->fk_typepayment)) $this->fk_typepayment=trim($this->fk_typepayment);
    -		if (isset($this->num_payment)) $this->num_payment=trim($this->num_payment);
    +		if (isset($this->fk_typepayment)) $this->fk_typepayment = (int) $this->fk_typepayment;
    +		if (isset($this->num_payment)) $this->num_payment = (int) $this->num_payment;
     		if (isset($this->note_private)) $this->note=trim($this->note_private);
     		if (isset($this->note_public)) $this->note=trim($this->note_public);
    -		if (isset($this->fk_bank)) $this->fk_bank=trim($this->fk_bank);
    -		if (isset($this->fk_user_creat)) $this->fk_user_creat=trim($this->fk_user_creat);
    -		if (isset($this->fk_user_modif)) $this->fk_user_modif=trim($this->fk_user_modif);
    +		if (isset($this->fk_bank)) $this->fk_bank = (int) $this->fk_bank;
    +		if (isset($this->fk_user_creat)) $this->fk_user_creat = (int) $this->fk_user_creat;
    +		if (isset($this->fk_user_modif)) $this->fk_user_modif = (int) $this->fk_user_modif;
     
     		// Check parameters
     
    @@ -418,7 +454,7 @@ class PaymentLoan extends CommonObject
     
     			// Insert payment into llx_bank
     			$bank_line_id = $acc->addline(
    -				$this->datepaid,
    +				$this->datep,
     				$this->paymenttype,  // Payment mode id or code ("CHQ or VIR for example")
     				$label,
     				$total,
    diff --git a/htdocs/loan/createschedule.php b/htdocs/loan/createschedule.php
    index 08ca019f00e..7cfd54ab998 100644
    --- a/htdocs/loan/createschedule.php
    +++ b/htdocs/loan/createschedule.php
    @@ -51,7 +51,7 @@ if ($action == 'createecheancier') {
     		$echeance->fk_loan = $object->id;
     		$echeance->datec = dol_now();
     		$echeance->tms = dol_now();
    -		$echeance->datepaid = $date;
    +		$echeance->datep = $date;
     		$echeance->amount_capital = $mens-$int;
     		$echeance->amount_insurance = 0;
     		$echeance->amount_interest = $int;
    @@ -61,7 +61,7 @@ if ($action == 'createecheancier') {
     		$echeance->fk_user_modif = $user->id;
     		$result=$echeance->create($user);
     		if ($result<0) {
    -			setEventMessages(null, $echeance->errors,'errors');
    +			setEventMessages($echeance->error, $echeance->errors,'errors');
     		}
     		$i++;
     	}
    @@ -165,7 +165,7 @@ if ($object->nbterm > 0 && count($echeance->lines)==0)
     	$capital = $object->capital;
     	while($i <$object->nbterm+1)
     	{
    -		$mens = price2num($echeance->calc_mens($capital, $object->rate/100, $object->nbterm-$i+1), 'MT');
    +		$mens = price2num($echeance->calcMonthlyPayments($capital, $object->rate/100, $object->nbterm-$i+1), 'MT');
     		$int = ($capital*($object->rate/12))/100;
     		$int = price2num($int, 'MT');
     		$cap_rest = price2num($capital - ($mens-$int), 'MT');
    @@ -213,6 +213,3 @@ print '</form>';
     // End of page
     llxFooter();
     $db->close();
    -
    -
    -
    diff --git a/htdocs/loan/payment/payment.php b/htdocs/loan/payment/payment.php
    index d84ea4ae26b..08937c1f389 100644
    --- a/htdocs/loan/payment/payment.php
    +++ b/htdocs/loan/payment/payment.php
    @@ -93,12 +93,12 @@ if ($action == 'add_payment')
         		// Create a line of payments
         		$payment = new PaymentLoan($db);
         		$payment->chid				= $chid;
    -    		$payment->datepaid			= $datepaid;
    +    		$payment->datep = $datepaid;
                 $payment->label             = $loan->label;
     			$payment->amount_capital	= GETPOST('amount_capital');
     			$payment->amount_insurance	= GETPOST('amount_insurance');
     			$payment->amount_interest	= GETPOST('amount_interest');
    -			$payment->paymenttype		= GETPOST('paymenttype');
    +			$payment->paymenttype = GETPOST('paymenttype', 'int');
         		$payment->num_payment		= GETPOST('num_payment');
         		$payment->note_private      = GETPOST('note_private','none');
         		$payment->note_public       = GETPOST('note_public','none');
    diff --git a/htdocs/mailmanspip/class/mailmanspip.class.php b/htdocs/mailmanspip/class/mailmanspip.class.php
    index 139183e0375..2e6cae459c1 100644
    --- a/htdocs/mailmanspip/class/mailmanspip.class.php
    +++ b/htdocs/mailmanspip/class/mailmanspip.class.php
    @@ -1,11 +1,12 @@
     <?php
    -/* Copyright (C) 2002-2003 Rodolphe Quiedeville <rodolphe@quiedeville.org>
    - * Copyright (C) 2002-2003 Jean-Louis Bergamo   <jlb@j1b.org>
    - * Copyright (C) 2004-2013 Laurent Destailleur  <eldy@users.sourceforge.net>
    - * Copyright (C) 2004      Sebastien Di Cintio  <sdicintio@ressource-toi.org>
    - * Copyright (C) 2004      Benoit Mortier       <benoit.mortier@opensides.be>
    - * Copyright (C) 2009      Regis Houssin        <regis.houssin@capnetworks.com>
    - * Copyright (C) 2012      Marcos García        <marcosgdf@gmail.com>
    +/* Copyright (C) 2002-2003  Rodolphe Quiedeville    <rodolphe@quiedeville.org>
    + * Copyright (C) 2002-2003  Jean-Louis Bergamo      <jlb@j1b.org>
    + * Copyright (C) 2004-2013  Laurent Destailleur     <eldy@users.sourceforge.net>
    + * Copyright (C) 2004       Sebastien Di Cintio     <sdicintio@ressource-toi.org>
    + * Copyright (C) 2004       Benoit Mortier          <benoit.mortier@opensides.be>
    + * Copyright (C) 2009       Regis Houssin           <regis.houssin@capnetworks.com>
    + * Copyright (C) 2012       Marcos García           <marcosgdf@gmail.com>
    + * Copyright (C) 2018       Frédéric France         <frederic.france@netlogic.fr>
      *
      * This program is free software; you can redistribute it and/or modify
      * it under the terms of the GNU General Public License as published by
    @@ -48,10 +49,15 @@ class MailmanSpip
     	 */
     	public $error='';
     
    -    var $mladded_ok;
    -    var $mladded_ko;
    -    var $mlremoved_ok;
    -    var $mlremoved_ko;
    +    /**
    +     * @var string[]	Array of error strings
    +     */
    +    public $errors = array();
    +
    +    public $mladded_ok;
    +    public $mladded_ko;
    +    public $mlremoved_ok;
    +    public $mlremoved_ko;
     
     
         /**
    diff --git a/htdocs/margin/tabs/productMargins.php b/htdocs/margin/tabs/productMargins.php
    index b8360c7ca6c..5659be448de 100644
    --- a/htdocs/margin/tabs/productMargins.php
    +++ b/htdocs/margin/tabs/productMargins.php
    @@ -135,9 +135,9 @@ if ($id > 0 || ! empty($ref))
                 $sql.= " f.datef, f.paye, f.fk_statut as statut, f.type,";
                 if (!$user->rights->societe->client->voir && !$socid) $sql.= " sc.fk_soc, sc.fk_user,";
                 $sql.= " sum(d.total_ht) as selling_price,";							// may be negative or positive
    -            $sql.= " sum(d.qty) as qty,";
    -            $sql.= " sum(d.qty * d.buy_price_ht) as buying_price,";					// always positive
    -            $sql.= " sum(abs(d.total_ht) - (d.buy_price_ht * d.qty)) as marge" ;	// always positive
    +            $sql.= " IF(f.type = 2, -1, 1) * sum(d.qty) as qty,";						// not always positive in case of Credit note
    +            $sql.= " IF(f.type = 2, -1, 1) * sum(d.qty * d.buy_price_ht) as buying_price,";			// not always positive in case of Credit note
    +            $sql.= " IF(f.type = 2, -1, 1) * sum(abs(d.total_ht) - (d.buy_price_ht * d.qty)) as marge" ;	// not always positive in case of Credit note
                 $sql.= " FROM ".MAIN_DB_PREFIX."societe as s";
                 $sql.= ", ".MAIN_DB_PREFIX."facture as f";
                 $sql.= ", ".MAIN_DB_PREFIX."facturedet as d";
    diff --git a/htdocs/modulebuilder/index.php b/htdocs/modulebuilder/index.php
    index d325e52a343..b533c369cbd 100644
    --- a/htdocs/modulebuilder/index.php
    +++ b/htdocs/modulebuilder/index.php
    @@ -1154,9 +1154,16 @@ elseif (! empty($module))
     		$head2[$h][2] = 'buildpackage';
     		$h++;
     
    +		// Link to enable / disable
     		print $modulestatusinfo;
     		print ' '.$linktoenabledisable;
    -		print '<br><br>';
    +		print '<br>';
    +
    +		if (realpath($dirread.'/'.$modulelowercase) != $dirread.'/'.$modulelowercase)
    +		{
    +			print $langs->trans("RealPathOfModule").' : <strong>'.realpath($dirread.'/'.$modulelowercase).'</strong><br>';
    +		}
    +		print '<br>';
     
     		if ($tab == 'description')
     		{
    @@ -1579,7 +1586,7 @@ elseif (! empty($module))
     
     						print '<br>';
     
    -						print '<span class="fa fa-file-o"></span> '.$langs->trans("PageForLib").' : <strong>'.($realpathtolib?'':'<strike>').$pathtolib.($realpathtodocument?'':'</strike>').'</strong>';
    +						print '<span class="fa fa-file-o"></span> '.$langs->trans("PageForLib").' : <strong>'.($realpathtolib?'':'<strike>').$pathtolib.($realpathtolib?'':'</strike>').'</strong>';
     						print ' <a href="'.$_SERVER['PHP_SELF'].'?tab='.$tab.'&tabobj='.$tabobj.'&module='.$module.($forceddirread?'@'.$dirread:'').'&action=editfile&format=php&file='.urlencode($pathtolib).'">'.img_picto($langs->trans("Edit"), 'edit').'</a>';
     						print '<br>';
     						print '<span class="fa fa-file-image-o"></span> '.$langs->trans("Image").' : <strong>'.($realpathtopicto?'':'<strike>').$pathtopicto.($realpathtopicto?'':'</strike>').'</strong>';
    diff --git a/htdocs/modulebuilder/template/class/myobject.class.php b/htdocs/modulebuilder/template/class/myobject.class.php
    index 0439f78f3a5..9f180343f5b 100644
    --- a/htdocs/modulebuilder/template/class/myobject.class.php
    +++ b/htdocs/modulebuilder/template/class/myobject.class.php
    @@ -93,7 +93,7 @@ class MyObject extends CommonObject
     		'note_private'  =>array('type'=>'html',			'label'=>'NotePrivate',		 'enabled'=>1, 'visible'=>0,  'position'=>62),
     		'date_creation' =>array('type'=>'datetime',     'label'=>'DateCreation',     'enabled'=>1, 'visible'=>-2, 'notnull'=>1,  'position'=>500),
     	    'tms'           =>array('type'=>'timestamp',    'label'=>'DateModification', 'enabled'=>1, 'visible'=>-2, 'notnull'=>1,  'position'=>501),
    -		//'date_valid'    =>array('type'=>'datetime',     'label'=>'DateCreation',     'enabled'=>1, 'visible'=>-2, 'position'=>502),
    +		//'date_validation'    =>array('type'=>'datetime',     'label'=>'DateCreation',     'enabled'=>1, 'visible'=>-2, 'position'=>502),
     		'fk_user_creat' =>array('type'=>'integer',      'label'=>'UserAuthor',       'enabled'=>1, 'visible'=>-2, 'notnull'=>1,  'position'=>510, 'foreignkey'=>'llx_user.rowid'),
     		'fk_user_modif' =>array('type'=>'integer',      'label'=>'UserModif',        'enabled'=>1, 'visible'=>-2, 'notnull'=>-1, 'position'=>511),
     		//'fk_user_valid' =>array('type'=>'integer',      'label'=>'UserValidation',        'enabled'=>1, 'visible'=>-1, 'position'=>512),
    @@ -122,11 +122,25 @@ class MyObject extends CommonObject
         public $label;
     
     	public $amount;
    +
    +	/**
    +	 * @var int Status
    +	 */
     	public $status;
    +
     	public $date_creation;
     	public $tms;
    +
    +	/**
    +     * @var int ID
    +     */
     	public $fk_user_creat;
    +
    +	/**
    +     * @var int ID
    +     */
     	public $fk_user_modif;
    +
     	public $import_key;
     	// END MODULEBUILDER PROPERTIES
     
    @@ -377,7 +391,7 @@ class MyObject extends CommonObject
     		$result .= $linkend;
     		//if ($withpicto != 2) $result.=(($addlabel && $this->label) ? $sep . dol_trunc($this->label, ($addlabel > 1 ? $addlabel : 0)) : '');
     
    -		global $action;
    +		global $action,$hookmanager;
     		$hookmanager->initHooks(array('myobjectdao'));
     		$parameters=array('id'=>$this->id, 'getnomurl'=>$result);
     		$reshook=$hookmanager->executeHooks('getNomUrl',$parameters,$this,$action);    // Note that $action and $object may have been modified by some hooks
    diff --git a/htdocs/modulebuilder/template/core/modules/modMyModule.class.php b/htdocs/modulebuilder/template/core/modules/modMyModule.class.php
    index b83580f4017..e81b75c1815 100644
    --- a/htdocs/modulebuilder/template/core/modules/modMyModule.class.php
    +++ b/htdocs/modulebuilder/template/core/modules/modMyModule.class.php
    @@ -72,7 +72,7 @@ class modMyModule extends DolibarrModules
     		$this->version = '1.0';
     
             //Url to the file with your last numberversion of this module
    -        $this->url_last_version = 'http://www.example.com/versionmodule.txt';
    +        //$this->url_last_version = 'http://www.example.com/versionmodule.txt';
     		// Key used in llx_const table to save module status enabled/disabled (where MYMODULE is value of property name of module in uppercase)
     		$this->const_name = 'MAIN_MODULE_'.strtoupper($this->name);
     		// Name of image file used for this module.
    diff --git a/htdocs/paybox/admin/paybox.php b/htdocs/paybox/admin/paybox.php
    index dd9676a6813..11329042da4 100644
    --- a/htdocs/paybox/admin/paybox.php
    +++ b/htdocs/paybox/admin/paybox.php
    @@ -71,6 +71,9 @@ if ($action == 'setvalue' && $user->admin)
     	if (! $result > 0) $error++;
     	$result=dolibarr_set_const($db, "PAYMENT_SECURITY_TOKEN_UNIQUE",GETPOST('PAYMENT_SECURITY_TOKEN_UNIQUE','alpha'),'chaine',0,'',$conf->entity);
     	if (! $result > 0) $error++;
    +        $result=dolibarr_set_const($db, "PAYBOX_HMAC_KEY", dol_encode(GETPOST('PAYBOX_HMAC_KEY','alpha')),'chaine',0,'',$conf->entity);
    +	if (! $result > 0) $error++;
    +        
     
         if (! $error)
       	{
    @@ -145,6 +148,12 @@ print '<input size="32" type="text" name="PAYBOX_PBX_IDENTIFIANT" value="'.$conf
     print '<br>'.$langs->trans("Example").': 2 ('.$langs->trans("Test").')';
     print '</td></tr>';
     
    +print '<tr class="oddeven"><td>';
    +print '<span class="fieldrequired">'.$langs->trans("PAYBOX_HMAC_KEY").'</span></td><td>';
    +print '<input size="100" type="text" name="PAYBOX_HMAC_KEY" value="'.dol_decode($conf->global->PAYBOX_HMAC_KEY).'">';
    +print '<br>'.$langs->trans("Example").': 2 ('.$langs->trans("Test").')';
    +print '</td></tr>';
    +
     print '<tr class="liste_titre">';
     print '<td>'.$langs->trans("UsageParameter").'</td>';
     print '<td>'.$langs->trans("Value").'</td>';
    diff --git a/htdocs/paybox/lib/paybox.lib.php b/htdocs/paybox/lib/paybox.lib.php
    index a4106488f53..a904c372099 100644
    --- a/htdocs/paybox/lib/paybox.lib.php
    +++ b/htdocs/paybox/lib/paybox.lib.php
    @@ -92,16 +92,41 @@ function print_paybox_redirect($PRICE,$CURRENCY,$EMAIL,$urlok,$urlko,$TAG)
         $IBS_REFUSE=$urlko;
         $IBS_BKGD="#FFFFFF";
         $IBS_WAIT="2000";
    -	$IBS_LANG="GBR"; 	// By default GBR=english (FRA, GBR, ESP, ITA et DEU...)
    -	if (preg_match('/^FR/i',$langs->defaultlang)) $IBS_LANG="FRA";
    -	if (preg_match('/^ES/i',$langs->defaultlang)) $IBS_LANG="ESP";
    -	if (preg_match('/^IT/i',$langs->defaultlang)) $IBS_LANG="ITA";
    -	if (preg_match('/^DE/i',$langs->defaultlang)) $IBS_LANG="DEU";
    -	if (preg_match('/^NL/i',$langs->defaultlang)) $IBS_LANG="NLD";
    -	if (preg_match('/^SE/i',$langs->defaultlang)) $IBS_LANG="SWE";
    -	$IBS_OUTPUT='E';
    -	$PBX_SOURCE='HTML';
    -	$PBX_TYPEPAIEMENT='CARTE';
    +    $IBS_LANG="GBR"; 	// By default GBR=english (FRA, GBR, ESP, ITA et DEU...)
    +    if (preg_match('/^FR/i',$langs->defaultlang)) $IBS_LANG="FRA";
    +    if (preg_match('/^ES/i',$langs->defaultlang)) $IBS_LANG="ESP";
    +    if (preg_match('/^IT/i',$langs->defaultlang)) $IBS_LANG="ITA";
    +    if (preg_match('/^DE/i',$langs->defaultlang)) $IBS_LANG="DEU";
    +    if (preg_match('/^NL/i',$langs->defaultlang)) $IBS_LANG="NLD";
    +    if (preg_match('/^SE/i',$langs->defaultlang)) $IBS_LANG="SWE";
    +    $IBS_OUTPUT='E';
    +    $PBX_SOURCE='HTML';
    +    $PBX_TYPEPAIEMENT='CARTE';
    +    
    +    $msg = "PBX_IDENTIFIANT=".$PBX_IDENTIFIANT.
    +           "&PBX_MODE=".$IBS_MODE.
    +           "&PBX_SITE=".$IBS_SITE.
    +           "&PBX_RANG=".$IBS_RANG.
    +           "&PBX_TOTAL=".$IBS_TOTAL.
    +           "&PBX_DEVISE=".$IBS_DEVISE.
    +           "&PBX_CMD=".$IBS_CMD.
    +           "&PBX_PORTEUR=".$IBS_PORTEUR.
    +           "&PBX_RETOUR=".$IBS_RETOUR.
    +           "&PBX_EFFECTUE=".$IBS_EFFECTUE.
    +           "&PBX_ANNULE=".$IBS_ANNULE.
    +           "&PBX_REFUSE=".$IBS_REFUSE.
    +           "&PBX_TXT=".$IBS_TXT.
    +           "&PBX_BKGD=".$IBS_BKGD.
    +           "&PBX_WAIT=".$IBS_WAIT.
    +           "&PBX_LANGUE=".$IBS_LANG.
    +           "&PBX_OUTPUT=".$IBS_OUTPUT.
    +           "&PBX_SOURCE=".$PBX_SOURCE.
    +           "&PBX_TYPEPAIEMENT=".$PBX_TYPEPAIEMENT;
    +    
    +    $binKey = pack("H*", dol_decode($conf->global->PAYBOX_HMAC_KEY));
    +            
    +    $hmac = strtoupper(hash_hmac('sha512', $msg, $binKey));
    +           
     
         dol_syslog("Soumission Paybox", LOG_DEBUG);
         dol_syslog("IBS_MODE: $IBS_MODE", LOG_DEBUG);
    @@ -157,7 +182,7 @@ function print_paybox_redirect($PRICE,$CURRENCY,$EMAIL,$urlok,$urlko,$TAG)
         print '<input type="hidden" name="PBX_OUTPUT" value="'.$IBS_OUTPUT.'">'."\n";
         print '<input type="hidden" name="PBX_SOURCE" value="'.$PBX_SOURCE.'">'."\n";
         print '<input type="hidden" name="PBX_TYPEPAIEMENT" value="'.$PBX_TYPEPAIEMENT.'">'."\n";
    -
    +    print '<input type="hidden" name="PBX_HMAC" value="'.$hmac.'">'."\n";
         print '</form>'."\n";
     
     
    diff --git a/htdocs/product/class/product.class.php b/htdocs/product/class/product.class.php
    index 12ddfb9e6d7..44222dc3c9e 100644
    --- a/htdocs/product/class/product.class.php
    +++ b/htdocs/product/class/product.class.php
    @@ -4,7 +4,7 @@
      * Copyright (C) 2005-2015	Regis Houssin			<regis.houssin@capnetworks.com>
      * Copyright (C) 2006		Andre Cianfarani		<acianfa@free.fr>
      * Copyright (C) 2007-2011	Jean Heimburger			<jean@tiaris.info>
    - * Copyright (C) 2010-2013	Juanjo Menent			<jmenent@2byte.es>
    + * Copyright (C) 2010-2018	Juanjo Menent			<jmenent@2byte.es>
      * Copyright (C) 2012       Cedric Salvador         <csalvador@gpcsolutions.fr>
      * Copyright (C) 2013-2014	Cedric GROSS			<c.gross@kreiz-it.fr>
      * Copyright (C) 2013-2016	Marcos García			<marcosgdf@gmail.com>
    @@ -12,7 +12,7 @@
      * Copyright (C) 2014		Henry Florian			<florian.henry@open-concept.pro>
      * Copyright (C) 2014-2016	Philippe Grand			<philippe.grand@atoo-net.com>
      * Copyright (C) 2014		Ion agorria			    <ion@agorria.com>
    - * Copyright (C) 2016-2017	Ferran Marcet			<fmarcet@2byte.es>
    + * Copyright (C) 2016-2018	Ferran Marcet			<fmarcet@2byte.es>
      * Copyright (C) 2017		Gustavo Novaro
      *
      * This program is free software; you can redistribute it and/or modify
    @@ -59,7 +59,12 @@ class Product extends CommonObject
     	public $fk_element='fk_product';
     
     	protected $childtables=array('supplier_proposaldet', 'propaldet','commandedet','facturedet','contratdet','facture_fourn_det','commande_fournisseurdet');    // To test if we can delete object
    -	public $ismultientitymanaged = 1;	// 0=No test on entity, 1=Test with field entity, 2=Test with link by societe
    +
    +	/**
    +	 * 0=No test on entity, 1=Test with field entity, 2=Test with link by societe
    +	 * @var int
    +	 */
    +	public $ismultientitymanaged = 1;
     
     	/**
     	 * {@inheritdoc}
    @@ -285,6 +290,9 @@ class Product extends CommonObject
     
     	public $oldcopy;
     
    +	/**
    +     * @var int ID
    +     */
         public $fk_price_expression;
     
         /* To store supplier price found */
    @@ -294,7 +302,7 @@ class Product extends CommonObject
     
     	/**
     	 * @deprecated
    -	 * @see ref_supplier
    +	 * @see $ref_supplier
     	 */
     	public $ref_fourn;
     	public $ref_supplier;
    @@ -1089,7 +1097,7 @@ class Product extends CommonObject
     				$sql.= " WHERE fk_product_stock IN (";
     				$sql.= "SELECT rowid FROM ".MAIN_DB_PREFIX.'product_stock';
     				$sql.= " WHERE fk_product = ".$id.")";
    -				dol_syslog(get_class($this).'::delete', LOG_DEBUG);
    +
     				$result = $this->db->query($sql);
     				if (! $result)
     				{
    @@ -1108,7 +1116,7 @@ class Product extends CommonObject
         				{
         					$sql = "DELETE FROM ".MAIN_DB_PREFIX.$table;
         					$sql.= " WHERE fk_product = ".$id;
    -    					dol_syslog(get_class($this).'::delete', LOG_DEBUG);
    +
         					$result = $this->db->query($sql);
         					if (! $result)
         					{
    @@ -1139,12 +1147,25 @@ class Product extends CommonObject
     				}
     			}
     
    +			// Delete from product_association
    +			if (!$error){
    +				$sql = "DELETE FROM ".MAIN_DB_PREFIX."product_association";
    +				$sql.= " WHERE fk_product_pere = ".$id." OR fk_product_fils = ".$id;
    +
    +				$result = $this->db->query($sql);
    +				if (! $result)
    +				{
    +					$error++;
    +					$this->errors[] = $this->db->lasterror();
    +				}
    +			}
    +
     			// Delete product
     			if (! $error)
     			{
     				$sqlz = "DELETE FROM ".MAIN_DB_PREFIX."product";
     				$sqlz.= " WHERE rowid = ".$id;
    -				dol_syslog(get_class($this).'::delete', LOG_DEBUG);
    +
     				$resultz = $this->db->query($sqlz);
     				if ( ! $resultz )
     				{
    @@ -3277,7 +3298,7 @@ class Product extends CommonObject
     	 *
     	 *  @param	int		$fromId     Id product source
     	 *  @param  int		$toId       Id product target
    -	 *  @return nt         			< 0 if KO, > 0 if OK
    +	 *  @return int         			< 0 if KO, > 0 if OK
     	 */
     	function clone_price($fromId, $toId)
     	{
    @@ -3467,7 +3488,7 @@ class Product extends CommonObject
     	 *
     	 *  @return 	int			Nb of father + child
     	 */
    -	function hasFatherOrChild()
    +	public function hasFatherOrChild()
     	{
     		$nb = 0;
     
    @@ -3488,12 +3509,61 @@ class Product extends CommonObject
     		return $nb;
     	}
     
    +	/**
    +	 * Return if a product has variants or not
    +	 *
    +	 * @return 	int		Number of variants
    +	 */
    +	public function hasVariants()
    +	{
    +		$nb = 0;
    +		$sql = "SELECT count(rowid) as nb FROM ".MAIN_DB_PREFIX."product_attribute_combination WHERE fk_product_parent = ".$this->id;
    +		$sql.= " AND entity IN (".getEntity('product').")";
    +
    +		$resql = $this->db->query($sql);
    +		if ($resql) {
    +			$obj = $this->db->fetch_object($resql);
    +			if ($obj) $nb = $obj->nb;
    +		}
    +
    +		return $nb;
    +	}
    +
    +
    +	/**
    +	 * Return if loaded product is a variant
    +	 *
    +	 * @return int
    +	 */
    +	public function isVariant()
    +	{
    +		global $conf;
    +		if (!empty($conf->variants->enabled)) {
    +			$sql = "SELECT rowid FROM " . MAIN_DB_PREFIX . "product_attribute_combination WHERE fk_product_child = " . $this->id . " AND entity IN (" . getEntity('product') . ")";
    +
    +			$query = $this->db->query($sql);
    +
    +			if ($query) {
    +				if (!$this->db->num_rows($query)) {
    +					return false;
    +				}
    +				return true;
    +			} else {
    +				dol_print_error($this->db);
    +				return -1;
    +			}
    +
    +		} else {
    +			return false;
    +		}
    +	}
    +
     	/**
     	 *  Return all parent products for current product (first level only)
     	 *
     	 *  @return 	array 		Array of product
     	 */
    -	function getFather()
    +	public function getFather()
     	{
     		$sql = "SELECT p.rowid, p.label as label, p.ref as ref, pa.fk_product_pere as id, p.fk_product_type, pa.qty, pa.incdec, p.entity";
     		$sql.= " FROM ".MAIN_DB_PREFIX."product_association as pa,";
    @@ -3534,7 +3604,7 @@ class Product extends CommonObject
     	 *  @param		int		$level				Level of recursing call (start to 1)
     	 *  @return     array       				Return array(prodid=>array(0=prodid, 1=>qty, 2=> ...)
     	 */
    -	function getChildsArbo($id, $firstlevelonly=0, $level=1)
    +	public function getChildsArbo($id, $firstlevelonly=0, $level=1)
     	{
     		global $alreadyfound;
     
    @@ -3622,7 +3692,7 @@ class Product extends CommonObject
          *  @param      int     $save_lastsearch_value		-1=Auto, 0=No save of lastsearch_values when clicking, 1=Save lastsearch_values whenclicking
     	 *	@return		string								String with URL
     	 */
    -	function getNomUrl($withpicto=0, $option='', $maxlength=0, $save_lastsearch_value=-1)
    +	public function getNomUrl($withpicto=0, $option='', $maxlength=0, $save_lastsearch_value=-1)
     	{
     		global $conf, $langs, $hookmanager;
     		include_once DOL_DOCUMENT_ROOT.'/core/lib/product.lib.php';
    @@ -3778,7 +3848,7 @@ class Product extends CommonObject
     	 *	@param      int	$type       0=Sell, 1=Buy, 2=Batch Number management
     	 *	@return     string      	Label of status
     	 */
    -	function getLibStatut($mode=0, $type=0)
    +	public function getLibStatut($mode=0, $type=0)
     	{
     		switch ($type)
     		{
    @@ -4000,7 +4070,7 @@ class Product extends CommonObject
     	 *										'warehouseclosed' = Load stock from closed warehouses only,
     	 *										'warehouseinternal' = Load stock from warehouses for internal correction/transfer only
     	 *    @return     int                   < 0 if KO, > 0 if OK
    -	 *    @see		  load_virtual_stock, getBatchInfo
    +	 *    @see		  load_virtual_stock(), loadBatchInfo()
     	 */
     	function load_stock($option='')
     	{
    @@ -4069,68 +4139,80 @@ class Product extends CommonObject
     		}
     	}
     
    -    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
    +	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
     	/**
     	 *    Load value ->stock_theorique of a product. Property this->id must be defined.
     	 *    This function need a lot of load. If you use it on list, use a cache to execute it one for each product id.
     	 *
     	 *    @return   int             < 0 if KO, > 0 if OK
    -	 *    @see		load_stock, getBatchInfo
    +	 *    @see		load_stock(), loadBatchInfo()
     	 */
    -    function load_virtual_stock()
    -    {
    -        // phpcs:enable
    -        global $conf;
    +	function load_virtual_stock()
    +	{
    +		// phpcs:enable
    +		global $conf, $hookmanager, $action;
     
    -        $stock_commande_client=0;
    -        $stock_commande_fournisseur=0;
    -        $stock_sending_client=0;
    -        $stock_reception_fournisseur=0;
    +		$stock_commande_client=0;
    +		$stock_commande_fournisseur=0;
    +		$stock_sending_client=0;
    +		$stock_reception_fournisseur=0;
     
    -        if (! empty($conf->commande->enabled))
    -        {
    -            $result=$this->load_stats_commande(0,'1,2', 1);
    -            if ($result < 0) dol_print_error($this->db,$this->error);
    -            $stock_commande_client=$this->stats_commande['qty'];
    -        }
    -        if (! empty($conf->expedition->enabled))
    -        {
    -            $result=$this->load_stats_sending(0,'1,2', 1);
    -            if ($result < 0) dol_print_error($this->db,$this->error);
    -            $stock_sending_client=$this->stats_expedition['qty'];
    -        }
    -        if (! empty($conf->fournisseur->enabled))
    -        {
    -            $result=$this->load_stats_commande_fournisseur(0,'1,2,3,4', 1);
    -            if ($result < 0) dol_print_error($this->db,$this->error);
    -            $stock_commande_fournisseur=$this->stats_commande_fournisseur['qty'];
    +		if (! empty($conf->commande->enabled))
    +		{
    +			$result=$this->load_stats_commande(0,'1,2', 1);
    +			if ($result < 0) dol_print_error($this->db,$this->error);
    +			$stock_commande_client=$this->stats_commande['qty'];
    +		}
    +		if (! empty($conf->expedition->enabled))
    +		{
    +			$result=$this->load_stats_sending(0,'1,2', 1);
    +			if ($result < 0) dol_print_error($this->db,$this->error);
    +			$stock_sending_client=$this->stats_expedition['qty'];
    +		}
    +		if (! empty($conf->fournisseur->enabled))
    +		{
    +			$result=$this->load_stats_commande_fournisseur(0,'1,2,3,4', 1);
    +			if ($result < 0) dol_print_error($this->db,$this->error);
    +			$stock_commande_fournisseur=$this->stats_commande_fournisseur['qty'];
     
    -            $result=$this->load_stats_reception(0,'4', 1);
    -            if ($result < 0) dol_print_error($this->db,$this->error);
    -            $stock_reception_fournisseur=$this->stats_reception['qty'];
    -        }
    +			$result=$this->load_stats_reception(0,'4', 1);
    +			if ($result < 0) dol_print_error($this->db,$this->error);
    +			$stock_reception_fournisseur=$this->stats_reception['qty'];
    +		}
     
    -        // Stock decrease mode
    -        if (! empty($conf->global->STOCK_CALCULATE_ON_SHIPMENT) || ! empty($conf->global->STOCK_CALCULATE_ON_SHIPMENT_CLOSE)) {
    -            $this->stock_theorique=$this->stock_reel-$stock_commande_client+$stock_sending_client;
    -        }
    -        if (! empty($conf->global->STOCK_CALCULATE_ON_VALIDATE_ORDER)) {
    -            $this->stock_theorique=$this->stock_reel;
    -        }
    -        if (! empty($conf->global->STOCK_CALCULATE_ON_BILL)) {
    -            $this->stock_theorique=$this->stock_reel-$stock_commande_client;
    -        }
    -        // Stock Increase mode
    -        if (! empty($conf->global->STOCK_CALCULATE_ON_SUPPLIER_DISPATCH_ORDER)) {
    -            $this->stock_theorique+=$stock_commande_fournisseur-$stock_reception_fournisseur;
    -        }
    -        if (! empty($conf->global->STOCK_CALCULATE_ON_SUPPLIER_VALIDATE_ORDER)) {
    -            $this->stock_theorique-=$stock_reception_fournisseur;
    -        }
    -        if (! empty($conf->global->STOCK_CALCULATE_ON_SUPPLIER_BILL)) {
    -            $this->stock_theorique+=$stock_commande_fournisseur-$stock_reception_fournisseur;
    -        }
    -    }
    +		// Stock decrease mode
    +		if (! empty($conf->global->STOCK_CALCULATE_ON_SHIPMENT) || ! empty($conf->global->STOCK_CALCULATE_ON_SHIPMENT_CLOSE)) {
    +			$this->stock_theorique=$this->stock_reel-$stock_commande_client+$stock_sending_client;
    +		}
    +		if (! empty($conf->global->STOCK_CALCULATE_ON_VALIDATE_ORDER)) {
    +			$this->stock_theorique=$this->stock_reel;
    +		}
    +		if (! empty($conf->global->STOCK_CALCULATE_ON_BILL)) {
    +			$this->stock_theorique=$this->stock_reel-$stock_commande_client;
    +		}
    +		// Stock Increase mode
    +		if (! empty($conf->global->STOCK_CALCULATE_ON_SUPPLIER_DISPATCH_ORDER)) {
    +			$this->stock_theorique+=$stock_commande_fournisseur-$stock_reception_fournisseur;
    +		}
    +		if (! empty($conf->global->STOCK_CALCULATE_ON_SUPPLIER_VALIDATE_ORDER)) {
    +			$this->stock_theorique-=$stock_reception_fournisseur;
    +		}
    +		if (! empty($conf->global->STOCK_CALCULATE_ON_SUPPLIER_BILL)) {
    +			$this->stock_theorique+=$stock_commande_fournisseur-$stock_reception_fournisseur;
    +		}
    +
    +		if (! is_object($hookmanager)) {
    +			include_once DOL_DOCUMENT_ROOT.'/core/class/hookmanager.class.php';
    +			$hookmanager=new HookManager($this->db);
    +		}
    +		$hookmanager->initHooks(array('productdao'));
    +		$parameters=array('id'=>$this->id);
    +		// Note that $action and $object may have been modified by some hooks
    +		$reshook=$hookmanager->executeHooks('loadvirtualstock', $parameters, $this, $action);
    +		if ($reshook > 0) $this->stock_theorique = $hookmanager->resArray['stock_theorique'];
    +
    +		return 1;
    +	}
     
     
     	/**
    @@ -4138,7 +4220,7 @@ class Product extends CommonObject
     	 *
     	 *	@param		string		$batch		Lot/serial number
     	 *  @return     array					Array with record into product_batch
    -	 *  @see		load_stock, load_virtual_stock
    +	 *  @see		load_stock(), load_virtual_stock()
     	 */
         function loadBatchInfo($batch)
         {
    @@ -4734,51 +4816,51 @@ class Product extends CommonObject
     		}
     	}
     
    -    /**
    -     *  Load information for tab info
    -     *
    -     *  @param  int		$id     Id of thirdparty to load
    -     *  @return	void
    -     */
    -    function info($id)
    -    {
    -        $sql = "SELECT p.rowid, p.ref, p.datec as date_creation, p.tms as date_modification,";
    -        $sql.= " p.fk_user_author, p.fk_user_modif";
    -        $sql.= " FROM ".MAIN_DB_PREFIX.$this->table_element." as p";
    -        $sql.= " WHERE p.rowid = ".$id;
    +	/**
    +	 *  Load information for tab info
    +	 *
    +	 *  @param  int		$id     Id of thirdparty to load
    +	 *  @return	void
    +	 */
    +	function info($id)
    +	{
    +		$sql = "SELECT p.rowid, p.ref, p.datec as date_creation, p.tms as date_modification,";
    +		$sql.= " p.fk_user_author, p.fk_user_modif";
    +		$sql.= " FROM ".MAIN_DB_PREFIX.$this->table_element." as p";
    +		$sql.= " WHERE p.rowid = ".$id;
     
    -        $result=$this->db->query($sql);
    -        if ($result)
    -        {
    -            if ($this->db->num_rows($result))
    -            {
    -                $obj = $this->db->fetch_object($result);
    -
    -                $this->id = $obj->rowid;
    -
    -                if ($obj->fk_user_author) {
    -                    $cuser = new User($this->db);
    -                    $cuser->fetch($obj->fk_user_author);
    -                    $this->user_creation     = $cuser;
    -                }
    -
    -                if ($obj->fk_user_modif) {
    -                    $muser = new User($this->db);
    -                    $muser->fetch($obj->fk_user_modif);
    -                    $this->user_modification = $muser;
    -                }
    -
    -                $this->ref			     = $obj->ref;
    -                $this->date_creation     = $this->db->jdate($obj->date_creation);
    -                $this->date_modification = $this->db->jdate($obj->date_modification);
    -            }
    -
    -            $this->db->free($result);
    -
    -        }
    -        else
    +		$result=$this->db->query($sql);
    +		if ($result)
     		{
    -            dol_print_error($this->db);
    -        }
    -    }
    +			if ($this->db->num_rows($result))
    +			{
    +				$obj = $this->db->fetch_object($result);
    +
    +				$this->id = $obj->rowid;
    +
    +				if ($obj->fk_user_author) {
    +					$cuser = new User($this->db);
    +					$cuser->fetch($obj->fk_user_author);
    +					$this->user_creation     = $cuser;
    +				}
    +
    +				if ($obj->fk_user_modif) {
    +					$muser = new User($this->db);
    +					$muser->fetch($obj->fk_user_modif);
    +					$this->user_modification = $muser;
    +				}
    +
    +				$this->ref			     = $obj->ref;
    +				$this->date_creation     = $this->db->jdate($obj->date_creation);
    +				$this->date_modification = $this->db->jdate($obj->date_modification);
    +			}
    +
    +			$this->db->free($result);
    +
    +		}
    +		else
    +		{
    +			dol_print_error($this->db);
    +		}
    +	}
     }
    diff --git a/htdocs/product/class/productbatch.class.php b/htdocs/product/class/productbatch.class.php
    index f6a7df212eb..eb4fc32baed 100644
    --- a/htdocs/product/class/productbatch.class.php
    +++ b/htdocs/product/class/productbatch.class.php
    @@ -37,13 +37,17 @@ class Productbatch extends CommonObject
     
     	private static $_table_element='product_batch';		//!< Name of table without prefix where object is stored
     
    -	var $tms='';
    -	var $fk_product_stock;
    -	var $sellby='';
    -	var $eatby='';
    -	var $batch='';
    -	var $qty;
    +	public $tms='';
    +	public $fk_product_stock;
    +	public $sellby='';
    +	public $eatby='';
    +	public $batch='';
    +	public $qty;
     	public $warehouseid;
    +
    +	/**
    +     * @var int ID
    +     */
     	public $fk_product;
     
     
    diff --git a/htdocs/product/class/productcustomerprice.class.php b/htdocs/product/class/productcustomerprice.class.php
    index 7f9e5a0b383..3079fef5412 100644
    --- a/htdocs/product/class/productcustomerprice.class.php
    +++ b/htdocs/product/class/productcustomerprice.class.php
    @@ -38,9 +38,17 @@ class Productcustomerprice extends CommonObject
     	 */
     	public $table_element = 'product_customer_price';
     
    +	/**
    +	 * @var int Entity
    +	 */
     	public $entity;
    +
     	public $datec = '';
     	public $tms = '';
    +
    +	/**
    +     * @var int ID
    +     */
     	public $fk_product;
     
     	/**
    @@ -976,15 +984,23 @@ class PriceByCustomerLine
     	 */
     	public $id;
     
    +	/**
    +	 * @var int Entity
    +	 */
     	public $entity;
    +
     	public $datec = '';
     	public $tms = '';
    +
    +	/**
    +     * @var int ID
    +     */
     	public $fk_product;
     
     	/**
     	 * @var int Thirdparty ID
     	 */
    -  public $fk_soc;
    +    public $fk_soc;
     
     	public $price;
     	public $price_ttc;
    diff --git a/htdocs/product/class/propalmergepdfproduct.class.php b/htdocs/product/class/propalmergepdfproduct.class.php
    index 3a7f3fb586d..f2aabb86876 100644
    --- a/htdocs/product/class/propalmergepdfproduct.class.php
    +++ b/htdocs/product/class/propalmergepdfproduct.class.php
    @@ -647,11 +647,24 @@ class PropalmergepdfproductLine
     	 */
     	public $id;
     
    +	/**
    +     * @var int ID
    +     */
     	public $fk_product;
    +
     	public $file_name;
     	public $lang;
    +
    +	/**
    +     * @var int ID
    +     */
     	public $fk_user_author;
    +
    +	/**
    +     * @var int ID
    +     */
     	public $fk_user_mod;
    +
     	public $datec='';
     	public $tms='';
     	public $import_key;
    diff --git a/htdocs/product/dynamic_price/class/price_global_variable_updater.class.php b/htdocs/product/dynamic_price/class/price_global_variable_updater.class.php
    index b06a249ccc6..c4dda3481bb 100644
    --- a/htdocs/product/dynamic_price/class/price_global_variable_updater.class.php
    +++ b/htdocs/product/dynamic_price/class/price_global_variable_updater.class.php
    @@ -60,7 +60,12 @@ class PriceGlobalVariableUpdater
     	public $description;
     
         public $parameters;
    +
    +    /**
    +     * @var int ID
    +     */
         public $fk_variable;
    +
         public $update_interval;				//!< Interval in mins
         public $next_update;					//!< Next update timestamp
         public $last_status;
    diff --git a/htdocs/product/inventory/class/inventory.class.php b/htdocs/product/inventory/class/inventory.class.php
    index 5b0bbb99a65..39df52a8208 100644
    --- a/htdocs/product/inventory/class/inventory.class.php
    +++ b/htdocs/product/inventory/class/inventory.class.php
    @@ -114,16 +114,38 @@ class Inventory extends CommonObject
     	 */
     	public $entity;
     
    +	/**
    +     * @var int ID
    +     */
     	public $fk_warehouse;
    +
     	public $date_inventory;
     	public $title;
    +
    +	/**
    +	 * @var int Status
    +	 */
     	public $status;
    +
     	public $date_creation;
     	public $date_validation;
     	public $tms;
    +
    +	/**
    +     * @var int ID
    +     */
     	public $fk_user_creat;
    +
    +	/**
    +     * @var int ID
    +     */
     	public $fk_user_modif;
    +
    +	/**
    +     * @var int ID
    +     */
     	public $fk_user_valid;
    +
     	public $import_key;
     	// END MODULEBUILDER PROPERTIES
     
    diff --git a/htdocs/product/list.php b/htdocs/product/list.php
    index 28f08035198..562d09056c7 100644
    --- a/htdocs/product/list.php
    +++ b/htdocs/product/list.php
    @@ -3,7 +3,7 @@
      * Copyright (C) 2004-2018  Laurent Destailleur     <eldy@users.sourceforge.net>
      * Copyright (C) 2005-2012  Regis Houssin           <regis.houssin@capnetworks.com>
      * Copyright (C) 2012-2016  Marcos García           <marcosgdf@gmail.com>
    - * Copyright (C) 2013-2016	Juanjo Menent           <jmenent@2byte.es>
    + * Copyright (C) 2013-2018	Juanjo Menent           <jmenent@2byte.es>
      * Copyright (C) 2013-2015  Raphaël Doursenaud      <rdoursenaud@gpcsolutions.fr>
      * Copyright (C) 2013       Jean Heimburger         <jean@tiaris.info>
      * Copyright (C) 2013       Cédric Salvador         <csalvador@gpcsolutions.fr>
    @@ -53,7 +53,7 @@ $sall=trim((GETPOST('search_all', 'alphanohtml')!='')?GETPOST('search_all', 'alp
     $search_ref=GETPOST("search_ref");
     $search_barcode=GETPOST("search_barcode");
     $search_label=GETPOST("search_label");
    -$search_type = GETPOST("search_type",'int');
    +$search_type = GETPOST("search_type", 'int');
     $search_sale = GETPOST("search_sale");
     $search_categ = GETPOST("search_categ",'int');
     $search_tosell = GETPOST("search_tosell", 'int');
    @@ -66,11 +66,11 @@ $search_accountancy_code_buy = GETPOST("search_accountancy_code_buy",'alpha');
     $optioncss = GETPOST('optioncss','alpha');
     $type=GETPOST("type","int");
     
    -//Show/hide child products. Hidden by default
    -if (!$_POST) {
    -	$search_hidechildproducts = 'on';
    +//Show/hide child products
    +if (!empty($conf->variants->enabled) && ! empty($conf->global->PRODUIT_ATTRIBUTES_HIDECHILD)) {
    +	$show_childproducts = GETPOST('search_show_childproducts');
     } else {
    -	$search_hidechildproducts = GETPOST('search_hidechildproducts');
    +	$show_childproducts = '';
     }
     
     $diroutputmassaction=$conf->product->dir_output . '/temp/massgeneration/'.$user->id;
    @@ -219,6 +219,8 @@ if (empty($reshook))
     		$search_tobuy="";
     		$search_tobatch='';
     		//$search_type='';						// There is 2 types of list: a list of product and a list of services. No list with both. So when we clear search criteria, we must keep the filter on type.
    +
    +		$show_childproducts = '';
     		$search_accountancy_code_sell='';
     		$search_accountancy_code_buy='';
     		$search_array_options=array();
    @@ -265,7 +267,7 @@ $sql.= ' p.fk_product_type, p.duration, p.tosell, p.tobuy, p.seuil_stock_alerte,
     $sql.= ' p.tobatch, p.accountancy_code_sell, p.accountancy_code_sell_intra, p.accountancy_code_sell_export, p.accountancy_code_buy,';
     $sql.= ' p.datec as date_creation, p.tms as date_update, p.pmp,';
     $sql.= ' MIN(pfp.unitprice) as minsellprice';
    -if (!empty($conf->variants->enabled) && $search_hidechildproducts && ($search_type === 0)) {
    +if (!empty($conf->variants->enabled) && (!empty($conf->global->PRODUIT_ATTRIBUTES_HIDECHILD) && ! $show_childproducts )) {
     	$sql .= ', pac.rowid prod_comb_id';
     }
     // Add fields from extrafields
    @@ -282,10 +284,12 @@ if (! empty($search_categ) || ! empty($catid)) $sql.= ' LEFT JOIN '.MAIN_DB_PREF
     $sql.= " LEFT JOIN ".MAIN_DB_PREFIX."product_fournisseur_price as pfp ON p.rowid = pfp.fk_product";
     // multilang
     if (! empty($conf->global->MAIN_MULTILANGS)) $sql.= " LEFT JOIN ".MAIN_DB_PREFIX."product_lang as pl ON pl.fk_product = p.rowid AND pl.lang = '".$langs->getDefaultLang() ."'";
    -if (!empty($conf->variants->enabled) && $search_hidechildproducts && ($search_type === 0)) {
    +
    +if (!empty($conf->variants->enabled) && (!empty($conf->global->PRODUIT_ATTRIBUTES_HIDECHILD) && ! $show_childproducts )) {
     	$sql .= " LEFT JOIN ".MAIN_DB_PREFIX."product_attribute_combination pac ON pac.fk_product_child = p.rowid";
     }
     
    +
     $sql.= ' WHERE p.entity IN ('.getEntity('product').')';
     if ($sall) $sql .= natural_search(array_keys($fieldstosearchall), $sall);
     // if the type is not 1, we show all products (type = 0,2,3)
    @@ -294,6 +298,11 @@ if (dol_strlen($search_type) && $search_type != '-1')
     	if ($search_type == 1) $sql.= " AND p.fk_product_type = 1";
     	else $sql.= " AND p.fk_product_type <> 1";
     }
    +
    +if (!empty($conf->variants->enabled) && (!empty($conf->global->PRODUIT_ATTRIBUTES_HIDECHILD) && ! $show_childproducts )) {
    +	$sql .= " AND pac.rowid IS NULL";
    +}
    +
     if ($search_ref)     $sql .= natural_search('p.ref', $search_ref);
     if ($search_label)   $sql .= natural_search('p.label', $search_label);
     if ($search_barcode) $sql .= natural_search('p.barcode', $search_barcode);
    @@ -308,7 +317,7 @@ if ($fourn_id > 0)  $sql.= " AND pfp.fk_soc = ".$fourn_id;
     if ($search_tobatch != '' && $search_tobatch >= 0)   $sql.= " AND p.tobatch = ".$db->escape($search_tobatch);
     if ($search_accountancy_code_sell) $sql.= natural_search('p.accountancy_code_sell', $search_accountancy_code_sell);
     if ($search_accountancy_code_buy)  $sql.= natural_search('p.accountancy_code_buy', $search_accountancy_code_buy);
    -if (!empty($conf->variants->enabled) && $search_hidechildproducts && ($search_type === 0)) $sql .= " AND pac.rowid IS NULL";
    +
     // Add where from extra fields
     include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_list_search_sql.tpl.php';
     // Add where from hooks
    @@ -318,7 +327,10 @@ $sql.=$hookmanager->resPrint;
     $sql.= " GROUP BY p.rowid, p.ref, p.label, p.barcode, p.price, p.price_ttc, p.price_base_type,";
     $sql.= " p.fk_product_type, p.duration, p.tosell, p.tobuy, p.seuil_stock_alerte, p.desiredstock,";
     $sql.= ' p.datec, p.tms, p.entity, p.tobatch, p.accountancy_code_sell, p.accountancy_code_sell_intra, p.accountancy_code_sell_export, p.accountancy_code_buy, p.pmp';
    -if (!empty($conf->variants->enabled) && $search_hidechildproducts && ($search_type === 0)) $sql .= ', pac.rowid';
    +
    +if (!empty($conf->variants->enabled) && (!empty($conf->global->PRODUIT_ATTRIBUTES_HIDECHILD) && ! $show_childproducts )) {
    +	$sql .= ', pac.rowid';
    +}
     // Add fields from extrafields
     if (! empty($extrafields->attributes[$object->table_element]['label'])) {
     	foreach ($extrafields->attributes[$object->table_element]['label'] as $key => $val) $sql.=($extrafields->attributes[$object->table_element]['type'][$key] != 'separate' ? ", ef.".$key : '');
    @@ -392,6 +404,7 @@ if ($resql)
     	if ($search_tobuy != '') $param.="&search_tobuy=".urlencode($search_tobuy);
     	if ($fourn_id > 0) $param.=($fourn_id?"&fourn_id=".$fourn_id:"");
     	if ($seach_categ) $param.=($search_categ?"&search_categ=".urlencode($search_categ):"");
    +	if ($show_childproducts) $param.=($show_childproducts?"&search_show_childproducts=".urlencode($show_childproducts):"");
     	if ($type != '') $param.='&type='.urlencode($type);
     	if ($search_type != '') $param.='&search_type='.urlencode($search_type);
     	if ($optioncss != '') $param.='&optioncss='.urlencode($optioncss);
    @@ -467,10 +480,10 @@ if ($resql)
     	}
     
     	//Show/hide child products. Hidden by default
    -	if (!empty($conf->variants->enabled) && $search_type === 0) {
    +	if (!empty($conf->variants->enabled) && !empty($conf->global->PRODUIT_ATTRIBUTES_HIDECHILD )) {
     		$moreforfilter.='<div class="divsearchfield">';
    -		$moreforfilter.= '<input type="checkbox" id="search_hidechildproducts" name="search_hidechildproducts" value="on"'.($search_hidechildproducts ? 'checked="checked"' : '').'>';
    -		$moreforfilter.= ' <label for="search_hidechildproducts">'.$langs->trans('HideChildProducts').'</label>';
    +		$moreforfilter.= '<input type="checkbox" id="search_show_childproducts" name="search_show_childproducts"'.($show_childproducts ? 'checked="checked"':'').'>';
    +		$moreforfilter.= ' <label for="search_show_childproducts">'.$langs->trans('ShowChildProducts').'</label>';
     		$moreforfilter.='</div>';
     	}
     
    @@ -744,34 +757,34 @@ if ($resql)
     			if (! $i) $totalarray['nbfield']++;
     		}
     
    -			// Duration
    -			if (! empty($arrayfields['p.duration']['checked']))
    +		// Duration
    +		if (! empty($arrayfields['p.duration']['checked']))
    +		{
    +			print '<td align="center">';
    +
    +			if (preg_match('/([^a-z]+)[a-z]$/i',$obj->duration))
     			{
    -				print '<td align="center">';
    +				$duration_value	= substr($obj->duration,0,dol_strlen($obj->duration)-1);
    +				$duration_unit	= substr($obj->duration,-1);
     
    -				if (preg_match('/([^a-z]+)[a-z]$/i',$obj->duration))
    +				if ((float) $duration_value > 1)
     				{
    -					$duration_value	= substr($obj->duration,0,dol_strlen($obj->duration)-1);
    -					$duration_unit	= substr($obj->duration,-1);
    -
    -					if ((float) $duration_value > 1)
    -					{
    -					    $dur=array("i"=>$langs->trans("Minutes"),"h"=>$langs->trans("Hours"),"d"=>$langs->trans("Days"),"w"=>$langs->trans("Weeks"),"m"=>$langs->trans("Months"),"y"=>$langs->trans("Years"));
    -					}
    -					else if ((float) $duration_value > 0)
    -					{
    -					    $dur=array("i"=>$langs->trans("Minute"),"h"=>$langs->trans("Hour"),"d"=>$langs->trans("Day"),"w"=>$langs->trans("Week"),"m"=>$langs->trans("Month"),"y"=>$langs->trans("Year"));
    -					}
    -					print $duration_value;
    -					print (! empty($duration_unit) && isset($dur[$duration_unit]) ? ' '.$langs->trans($dur[$duration_unit]) : '');
    +				    $dur=array("i"=>$langs->trans("Minutes"),"h"=>$langs->trans("Hours"),"d"=>$langs->trans("Days"),"w"=>$langs->trans("Weeks"),"m"=>$langs->trans("Months"),"y"=>$langs->trans("Years"));
     				}
    -				else
    +				else if ((float) $duration_value > 0)
     				{
    -					print $obj->duration;
    +				    $dur=array("i"=>$langs->trans("Minute"),"h"=>$langs->trans("Hour"),"d"=>$langs->trans("Day"),"w"=>$langs->trans("Week"),"m"=>$langs->trans("Month"),"y"=>$langs->trans("Year"));
     				}
    -				print '</td>';
    -				if (! $i) $totalarray['nbfield']++;
    +				print $duration_value;
    +				print (! empty($duration_unit) && isset($dur[$duration_unit]) ? ' '.$langs->trans($dur[$duration_unit]) : '');
     			}
    +			else
    +			{
    +				print $obj->duration;
    +			}
    +			print '</td>';
    +			if (! $i) $totalarray['nbfield']++;
    +		}
     
     		// Sell price
     		if (! empty($arrayfields['p.sellprice']['checked']))
    diff --git a/htdocs/product/price.php b/htdocs/product/price.php
    index a72ea28928b..9fb67aaa86c 100644
    --- a/htdocs/product/price.php
    +++ b/htdocs/product/price.php
    @@ -5,7 +5,7 @@
      * Copyright (C) 2005-2017	Regis Houssin			<regis.houssin@capnetworks.com>
      * Copyright (C) 2006		Andre Cianfarani			<acianfa@free.fr>
      * Copyright (C) 2014		Florian Henry			<florian.henry@open-concept.pro>
    - * Copyright (C) 2014-2016	Juanjo Menent			<jmenent@2byte.es>
    + * Copyright (C) 2014-2018	Juanjo Menent			<jmenent@2byte.es>
      * Copyright (C) 2014-2018 	Philippe Grand 		    <philippe.grand@atoo-net.com>
      * Copyright (C) 2014		Ion agorria				<ion@agorria.com>
      * Copyright (C) 2015		Alexandre Spangaro		<aspangaro.dolibarr@gmail.com>
    @@ -1109,30 +1109,33 @@ if (! $action || $action == 'delete' || $action == 'showlog_customer_price' || $
     {
     	print "\n" . '<div class="tabsAction">' . "\n";
     
    -	if (empty($conf->global->PRODUIT_MULTIPRICES) && empty($conf->global->PRODUIT_CUSTOMER_PRICES_BY_QTY_MULTIPRICES))
    -	{
    -    	if ($user->rights->produit->creer || $user->rights->service->creer) {
    -    		print '<div class="inline-block divButAction"><a class="butAction" href="' . $_SERVER['PHP_SELF'] . '?action=edit_price&amp;id=' . $object->id . '">' . $langs->trans("UpdateDefaultPrice") . '</a></div>';
    -    	}
    -	}
    +    if ($object->isVariant()) {
    +		if ($user->rights->produit->creer || $user->rights->service->creer) {
    +			print '<div class="inline-block divButAction"><a class="butActionRefused" href="#" title="'.dol_escape_htmltag($langs->trans("NoEditVariants")).'">'.$langs->trans("UpdateDefaultPrice").'</a></div>';
    +		}
    +	} else {
    +		if (empty($conf->global->PRODUIT_MULTIPRICES) && empty($conf->global->PRODUIT_CUSTOMER_PRICES_BY_QTY_MULTIPRICES)) {
    +			if ($user->rights->produit->creer || $user->rights->service->creer) {
    +				print '<div class="inline-block divButAction"><a class="butAction" href="' . $_SERVER['PHP_SELF'] . '?action=edit_price&amp;id=' . $object->id . '">' . $langs->trans("UpdateDefaultPrice") . '</a></div>';
    +			}
    +		}
     
    -	if (! empty($conf->global->PRODUIT_CUSTOMER_PRICES))
    -	{
    -	    if ($user->rights->produit->creer || $user->rights->service->creer) {
    -	 		print '<div class="inline-block divButAction"><a class="butAction" href="' . $_SERVER["PHP_SELF"] . '?action=add_customer_price&amp;id=' . $object->id . '">' . $langs->trans("AddCustomerPrice") . '</a></div>';
    -	  	}
    -	}
    +		if (!empty($conf->global->PRODUIT_CUSTOMER_PRICES)) {
    +			if ($user->rights->produit->creer || $user->rights->service->creer) {
    +				print '<div class="inline-block divButAction"><a class="butAction" href="' . $_SERVER["PHP_SELF"] . '?action=add_customer_price&amp;id=' . $object->id . '">' . $langs->trans("AddCustomerPrice") . '</a></div>';
    +			}
    +		}
     
    -	if (! empty($conf->global->PRODUIT_MULTIPRICES) || ! empty($conf->global->PRODUIT_CUSTOMER_PRICES_BY_QTY_MULTIPRICES))
    -	{
    -	    if ($user->rights->produit->creer || $user->rights->service->creer) {
    -    		print '<div class="inline-block divButAction"><a class="butAction" href="' . $_SERVER['PHP_SELF'] . '?action=edit_vat&amp;id=' . $object->id . '">' . $langs->trans("UpdateVAT") . '</a></div>';
    -    	}
    +		if (!empty($conf->global->PRODUIT_MULTIPRICES) || !empty($conf->global->PRODUIT_CUSTOMER_PRICES_BY_QTY_MULTIPRICES)) {
    +			if ($user->rights->produit->creer || $user->rights->service->creer) {
    +				print '<div class="inline-block divButAction"><a class="butAction" href="' . $_SERVER['PHP_SELF'] . '?action=edit_vat&amp;id=' . $object->id . '">' . $langs->trans("UpdateVAT") . '</a></div>';
    +			}
     
    -	    if ($user->rights->produit->creer || $user->rights->service->creer) {
    -    		print '<div class="inline-block divButAction"><a class="butAction" href="' . $_SERVER['PHP_SELF'] . '?action=edit_price&amp;id=' . $object->id . '">' . $langs->trans("UpdateLevelPrices") . '</a></div>';
    -    	}
    -	}
    +			if ($user->rights->produit->creer || $user->rights->service->creer) {
    +				print '<div class="inline-block divButAction"><a class="butAction" href="' . $_SERVER['PHP_SELF'] . '?action=edit_price&amp;id=' . $object->id . '">' . $langs->trans("UpdateLevelPrices") . '</a></div>';
    +			}
    +		}
    +    }
     
     	print "\n</div>\n";
     }
    diff --git a/htdocs/product/reassort.php b/htdocs/product/reassort.php
    index 14c2a00d477..27ac0c4d522 100644
    --- a/htdocs/product/reassort.php
    +++ b/htdocs/product/reassort.php
    @@ -54,6 +54,7 @@ $fourn_id = GETPOST("fourn_id",'int');
     $sortfield = GETPOST("sortfield",'alpha');
     $sortorder = GETPOST("sortorder",'alpha');
     $page = GETPOST("page",'int');
    +if (empty($page) || $page < 0) $page = 0;
     if (! $sortfield) $sortfield="p.ref";
     if (! $sortorder) $sortorder="ASC";
     $limit = GETPOST('limit','int')?GETPOST('limit','int'):$conf->liste_limit;
    @@ -92,11 +93,15 @@ if (GETPOST('button_removefilter_x','alpha') || GETPOST('button_removefilter.x',
         $sref="";
         $snom="";
         $sall="";
    +	$tosell="";
    +	$tobuy="";
         $search_sale="";
         $search_categ="";
         $type="";
         $catid='';
         $toolowstock='';
    +	$fourn_id='';
    +	$sbarcode='';
     }
     
     
    @@ -122,7 +127,7 @@ $sql.= ' LEFT JOIN '.MAIN_DB_PREFIX.'product_stock as s on p.rowid = s.fk_produc
     if ($search_categ) $sql.= ", ".MAIN_DB_PREFIX."categorie_product as cp";
     $sql.= " WHERE p.entity IN (".getEntity('product').")";
     if ($search_categ) $sql.= " AND p.rowid = cp.fk_product";	// Join for the needed table to filter by categ
    -if ($sall) $sql.=natural_search(array('p.ref', 'p.label', 'p.description', 'p.note'), $all);
    +if ($sall) $sql.=natural_search(array('p.ref', 'p.label', 'p.description', 'p.note'), $sall);
     // if the type is not 1, we show all products (type = 0,2,3)
     if (dol_strlen($type))
     {
    @@ -188,6 +193,20 @@ if ($resql)
     	}
     	$texte.=' ('.$langs->trans("Stocks").')';
     
    +	$param='';
    +	if ($limit > 0 && $limit != $conf->liste_limit) $param.='&limit='.$limit;
    +	if ($sall)	$param.="&sall=".$sall;
    +	if ($tosell)	$param.="&tosell=".$tosell;
    +	if ($tobuy)		$param.="&tobuy=".$tobuy;
    +	if ($type)		$param.="&type=".$type;
    +	if ($fourn_id)	$param.="&fourn_id=".$fourn_id;
    +	if ($snom)		$param.="&snom=".$snom;
    +	if ($sref)		$param.="&sref=".$sref;
    +	if ($search_sale) $param.="&search_sale=".$search_sale;
    +	if ($search_categ) $param.="&search_categ=".$search_categ;
    +	if ($toolowstock) $param.="&toolowstock=".$toolowstock;
    +	if ($sbarcode) $param.="&sbarcode=".$sbarcode;
    +	if ($catid) $param.="&catid=".$catid;
     
     	llxHeader("", $texte, $helpurl);
     
    @@ -198,14 +217,7 @@ if ($resql)
         print '<input type="hidden" name="page" value="'.$page.'">';
     	print '<input type="hidden" name="type" value="'.$type.'">';
     
    -	if ($sref || $snom || $sall || GETPOST('search'))
    -	{
    -	    print_barre_liste($texte, $page, $_SERVER["PHP_SELF"], "&sref=".$sref."&snom=".$snom."&amp;sall=".$sall."&amp;tosell=".$tosell."&amp;tobuy=".$tobuy.(!empty($search_categ) ? '&amp;search_categ='.$search_categ : '').(!empty($toolowstock) ? '&amp;toolowstock='.$toolowstock : ''), $sortfield, $sortorder,'',$num, $nbtotalofrecords, 'title_products', 0, '', '', $limit);
    -	}
    -	else
    -	{
    -	    print_barre_liste($texte, $page, $_SERVER["PHP_SELF"], "&sref=$sref&snom=$snom&fourn_id=$fourn_id".(isset($type)?"&amp;type=$type":"").(!empty($search_categ) ? '&amp;search_categ='.$search_categ : '').(!empty($toolowstock) ? '&amp;toolowstock='.$toolowstock : ''), $sortfield, $sortorder,'',$num, $nbtotalofrecords, 'title_products', 0, '', '', $limit);
    -	}
    +	print_barre_liste($texte, $page, $_SERVER["PHP_SELF"], $param, $sortfield, $sortorder,'',$num, $nbtotalofrecords, 'title_products', 0, '', '', $limit);
     
     	if (! empty($catid))
     	{
    @@ -345,7 +357,7 @@ if ($resql)
     		// Real stock
     		print '<td align="right">';
             if ($objp->seuil_stock_alerte != '' && ($objp->stock_physique < $objp->seuil_stock_alerte)) print img_warning($langs->trans("StockTooLow")).' ';
    -		print $objp->stock_physique;
    +		print $objp->stock_physique|0;
     		print '</td>';
     
     		// Details per warehouse
    @@ -369,7 +381,7 @@ if ($resql)
     			print $product->stock_theorique;
     			print '</td>';
     		}
    -		print '<td align="right"><a href="'.DOL_URL_ROOT.'/product/stock/mouvement.php?idproduct='.$product->id.'">'.$langs->trans("Movements").'</a></td>';
    +		print '<td align="right"><a href="'.DOL_URL_ROOT.'/product/stock/movement_list.php?idproduct='.$product->id.'">'.$langs->trans("Movements").'</a></td>';
     		print '<td align="right" class="nowrap">'.$product->LibStatut($objp->statut,5,0).'</td>';
             print '<td align="right" class="nowrap">'.$product->LibStatut($objp->tobuy,5,1).'</td>';
     		print '<td></td>';
    diff --git a/htdocs/product/reassortlot.php b/htdocs/product/reassortlot.php
    index e4ec3854fb5..518a19d8407 100644
    --- a/htdocs/product/reassortlot.php
    +++ b/htdocs/product/reassortlot.php
    @@ -58,6 +58,7 @@ $fourn_id = GETPOST("fourn_id",'int');
     $sortfield = GETPOST("sortfield",'alpha');
     $sortorder = GETPOST("sortorder",'alpha');
     $page = GETPOST("page",'int');
    +if (empty($page) || $page < 0) $page = 0;
     if (! $sortfield) $sortfield="p.ref";
     if (! $sortorder) $sortorder="ASC";
     $limit = GETPOST('limit','int')?GETPOST('limit','int'):$conf->liste_limit;
    @@ -89,6 +90,8 @@ if (GETPOST('button_removefilter_x','alpha') || GETPOST('button_removefilter.x',
         $sref="";
         $snom="";
         $sall="";
    +	$tosell="";
    +	$tobuy="";
         $search_sale="";
         $search_categ="";
         $type="";
    @@ -96,6 +99,8 @@ if (GETPOST('button_removefilter_x','alpha') || GETPOST('button_removefilter.x',
         $toolowstock='';
         $search_batch='';
         $search_warehouse='';
    +	$fourn_id='';
    +	$sbarcode='';
     }
     
     
    @@ -199,6 +204,24 @@ if ($resql)
     	}
     	$texte.=' ('.$langs->trans("StocksByLotSerial").')';
     
    +	$param='';
    +	if ($limit > 0 && $limit != $conf->liste_limit) $param.='&limit='.$limit;
    +	if ($sall)		$param.="&sall=".$sall;
    +	if ($tosell)		$param.="&tosell=".$tosell;
    +	if ($tobuy)			$param.="&tobuy=".$tobuy;
    +	if ($type)			$param.="&type=".$type;
    +	if ($fourn_id)		$param.="&fourn_id=".$fourn_id;
    +	if ($snom)			$param.="&snom=".$snom;
    +	if ($sref)			$param.="&sref=".$sref;
    +	if ($search_batch)	$param.="&search_batch=".$search_batch;
    +	if ($sbarcode)		$param.="&sbarcode=".$sbarcode;
    +	if ($search_warehouse)	$param.="&search_warehouse=".$search_warehouse;
    +	if ($catid)			$param.="&catid=".$catid;
    +	if ($toolowstock)	$param.="&toolowstock=".$toolowstock;
    +	if ($search_sale)	$param.="&search_sale=".$search_sale;
    +	if ($search_categ)	$param.="&search_categ=".$search_categ;
    +	/*if ($eatby)		$param.="&eatby=".$eatby;
    +	if ($sellby)	$param.="&sellby=".$sellby;*/
     
     	llxHeader("",$title,$helpurl,$texte);
     
    @@ -209,14 +232,8 @@ if ($resql)
         print '<input type="hidden" name="page" value="'.$page.'">';
     	print '<input type="hidden" name="type" value="'.$type.'">';
     
    -	if ($sref || $snom || $sall || GETPOST('search'))
    -	{
    -		print_barre_liste($texte, $page, $_SERVER["PHP_SELF"], "&sref=".$sref."&snom=".$snom."&amp;sall=".$sall."&amp;tosell=".$tosell."&amp;tobuy=".$tobuy, $sortfield, $sortorder,'',$num, $nbtotalofrecords, 'title_products', 0, '', '', $limit);
    -	}
    -	else
    -	{
    -		print_barre_liste($texte, $page, $_SERVER["PHP_SELF"], "&sref=$sref&snom=$snom&fourn_id=$fourn_id".(isset($type)?"&amp;type=$type":""), $sortfield, $sortorder,'',$num, $nbtotalofrecords, 'title_products', 0, '', '', $limit);
    -	}
    +	print_barre_liste($texte, $page, $_SERVER["PHP_SELF"], $param, $sortfield, $sortorder,'',$num, $nbtotalofrecords, 'title_products', 0, '', '', $limit);
    +
     
     	if (! empty($catid))
     	{
    @@ -250,17 +267,6 @@ if ($resql)
         }
     
     
    -	$param='';
    -	if ($tosell)		$param.="&tosell=".$tosell;
    -	if ($tobuy)			$param.="&tobuy=".$tobuy;
    -	if ($type)			$param.="&type=".$type;
    -	if ($fourn_id)		$param.="&fourn_id=".$fourn_id;
    -	if ($snom)			$param.="&snom=".$snom;
    -	if ($sref)			$param.="&sref=".$sref;
    -	if ($search_batch)	$param.="&search_batch=".$search_batch;
    -	/*if ($eatby)		$param.="&eatby=".$eatby;
    -	if ($sellby)	$param.="&sellby=".$sellby;*/
    -
         print '<div class="div-table-responsive">';
     	print '<table class="tagtable liste'.($moreforfilter?" listwithfilterbefore":"").'">';
     
    @@ -342,6 +348,7 @@ if ($resql)
             $product_static->label = $objp->label;
     		$product_static->type=$objp->fk_product_type;
     		$product_static->entity=$objp->entity;
    +		$product_static->status_batch=$objp->tobatch;
     
     		$product_lot_static->batch=$objp->batch;
     		$product_lot_static->product_id=$objp->rowid;
    @@ -401,7 +408,7 @@ if ($resql)
             //if ($objp->seuil_stock_alerte && ($objp->stock_physique < $objp->seuil_stock_alerte)) print img_warning($langs->trans("StockTooLow")).' ';
     		print $objp->stock_physique;
     		print '</td>';
    -		print '<td align="right"><a href="'.DOL_URL_ROOT.'/product/stock/mouvement.php?idproduct='.$product_static->id.'&search_warehouse='.$objp->fk_entrepot.'&search_batch='.($objp->batch != 'Undefined' ? $objp->batch : 'Undefined').'">'.$langs->trans("Movements").'</a></td>';
    +		print '<td align="right"><a href="'.DOL_URL_ROOT.'/product/stock/movement_list.php?idproduct='.$product_static->id.'&search_warehouse='.$objp->fk_entrepot.'&search_batch='.($objp->batch != 'Undefined' ? $objp->batch : 'Undefined').'">'.$langs->trans("Movements").'</a></td>';
     		print '<td align="right" class="nowrap">'.$product_static->LibStatut($objp->statut,5,0).'</td>';
             print '<td align="right" class="nowrap">'.$product_static->LibStatut($objp->tobuy,5,1).'</td>';
             print '<td></td>';
    diff --git a/htdocs/product/stock/card.php b/htdocs/product/stock/card.php
    index 334ccdb0b65..b24a37c4fe2 100644
    --- a/htdocs/product/stock/card.php
    +++ b/htdocs/product/stock/card.php
    @@ -384,7 +384,7 @@ else
     			if ($lastmovementdate)
     			{
     			    print dol_print_date($lastmovementdate,'dayhour').' ';
    -			    print '(<a href="'.DOL_URL_ROOT.'/product/stock/mouvement.php?id='.$object->id.'">'.$langs->trans("FullList").'</a>)';
    +			    print '(<a href="'.DOL_URL_ROOT.'/product/stock/movement_list.php?id='.$object->id.'">'.$langs->trans("FullList").'</a>)';
     			}
     			else
     			{
    diff --git a/htdocs/product/stock/class/entrepot.class.php b/htdocs/product/stock/class/entrepot.class.php
    index 59e3f2fb057..b2a78a9cd3e 100644
    --- a/htdocs/product/stock/class/entrepot.class.php
    +++ b/htdocs/product/stock/class/entrepot.class.php
    @@ -69,10 +69,19 @@ class Entrepot extends CommonObject
     
     	public $statut;
     	public $lieu;
    +
    +	/**
    +	 * @var string Address
    +	 */
     	public $address;
    +
     	//! Code Postal
     	public $zip;
     	public $town;
    +
    +	/**
    +     * @var int ID
    +     */
     	public $fk_parent;
     
     	// List of short language codes for status
    diff --git a/htdocs/product/stock/class/mouvementstock.class.php b/htdocs/product/stock/class/mouvementstock.class.php
    index 0d8338c4d9f..395c192311f 100644
    --- a/htdocs/product/stock/class/mouvementstock.class.php
    +++ b/htdocs/product/stock/class/mouvementstock.class.php
    @@ -44,11 +44,22 @@ class MouvementStock extends CommonObject
     	public $product_id;
     	public $warehouse_id;
     	public $qty;
    +
    +	/**
    +	 * @var int Type of movement
    +	 * 0=input (stock increase by a stock transfer), 1=output (stock decrease after by a stock transfer),
    +	 * 2=output (stock decrease), 3=input (stock increase)
    +	 * Note that qty should be > 0 with 0 or 3, < 0 with 1 or 2.
    +	 */
     	public $type;
     
     	public $tms = '';
     	public $datem = '';
     	public $price;
    +
    +	/**
    +     * @var int ID
    +     */
     	public $fk_user_author;
     
     	/**
    @@ -56,7 +67,11 @@ class MouvementStock extends CommonObject
          */
         public $label;
     
    +    /**
    +     * @var int ID
    +     */
     	public $fk_origin;
    +
     	public $origintype;
     	public $inventorycode;
     	public $batch;
    @@ -993,7 +1008,7 @@ class MouvementStock extends CommonObject
     		$label.= '<br><b>' . $langs->trans('Qty') . ':</b> ' .$this->qty;
     		$label.= '</div>';
     
    -		$link = '<a href="'.DOL_URL_ROOT.'/product/stock/mouvement.php?id='.$this->warehouse_id.'&msid='.$this->id.'"';
    +		$link = '<a href="'.DOL_URL_ROOT.'/product/stock/movement_list.php?id='.$this->warehouse_id.'&msid='.$this->id.'"';
     		$link.= ($notooltip?'':' title="'.dol_escape_htmltag($label, 1).'" class="classfortooltip'.($morecss?' '.$morecss:'').'"');
     		$link.= '>';
     		$linkend='</a>';
    diff --git a/htdocs/product/stock/class/productlot.class.php b/htdocs/product/stock/class/productlot.class.php
    index 7eb3593de35..d61630eb88e 100644
    --- a/htdocs/product/stock/class/productlot.class.php
    +++ b/htdocs/product/stock/class/productlot.class.php
    @@ -3,7 +3,7 @@
      * Copyright (C) 2014       Juanjo Menent       <jmenent@2byte.es>
      * Copyright (C) 2015       Florian Henry       <florian.henry@open-concept.pro>
      * Copyright (C) 2015       Raphaël Doursenaud  <rdoursenaud@gpcsolutions.fr>
    - * Copyright (C) ---Put here your own copyright and developer email---
    + * Copyright (C) 2018       Frédéric France     <frederic.france@netlogic.fr>
      *
      * This program is free software; you can redistribute it and/or modify
      * it under the terms of the GNU General Public License as published by
    @@ -47,6 +47,10 @@ class Productlot extends CommonObject
     
     	public $picto='barcode';
     
    +	/**
    +	 * 0=No test on entity, 1=Test with field entity, 2=Test with link by societe
    +	 * @var int
    +	 */
         public $ismultientitymanaged = 1;
     
     	/**
    @@ -59,14 +63,27 @@ class Productlot extends CommonObject
     	 */
     	public $entity;
     
    +	/**
    +     * @var int ID
    +     */
     	public $fk_product;
    +
     	public $batch;
     	public $eatby = '';
     	public $sellby = '';
     	public $datec = '';
     	public $tms = '';
    +
    +	/**
    +     * @var int ID
    +     */
     	public $fk_user_creat;
    +
    +	/**
    +     * @var int ID
    +     */
     	public $fk_user_modif;
    +
     	public $import_key;
     
     
    @@ -98,19 +115,19 @@ class Productlot extends CommonObject
     		// Clean parameters
     
     		if (isset($this->entity)) {
    -			 $this->entity = trim($this->entity);
    +			 $this->entity = (int) $this->entity;
     		}
     		if (isset($this->fk_product)) {
    -			 $this->fk_product = trim($this->fk_product);
    +			 $this->fk_product = (int) $this->fk_product;
     		}
     		if (isset($this->batch)) {
     			 $this->batch = trim($this->batch);
     		}
     		if (isset($this->fk_user_creat)) {
    -			 $this->fk_user_creat = trim($this->fk_user_creat);
    +			 $this->fk_user_creat = (int) $this->fk_user_creat;
     		}
     		if (isset($this->fk_user_modif)) {
    -			 $this->fk_user_modif = trim($this->fk_user_modif);
    +			 $this->fk_user_modif = (int) $this->fk_user_modif;
     		}
     		if (isset($this->import_key)) {
     			 $this->import_key = trim($this->import_key);
    @@ -279,19 +296,19 @@ class Productlot extends CommonObject
     		// Clean parameters
     
     		if (isset($this->entity)) {
    -			 $this->entity = trim($this->entity);
    +			 $this->entity = (int) $this->entity;
     		}
     		if (isset($this->fk_product)) {
    -			 $this->fk_product = trim($this->fk_product);
    +			 $this->fk_product = (int) $this->fk_product;
     		}
     		if (isset($this->batch)) {
     			 $this->batch = trim($this->batch);
     		}
     		if (isset($this->fk_user_creat)) {
    -			 $this->fk_user_creat = trim($this->fk_user_creat);
    +			 $this->fk_user_creat = (int) $this->fk_user_creat;
     		}
     		if (isset($this->fk_user_modif)) {
    -			 $this->fk_user_modif = trim($this->fk_user_modif);
    +			 $this->fk_user_modif = (int) $this->fk_user_modif;
     		}
     		if (isset($this->import_key)) {
     			 $this->import_key = trim($this->import_key);
    @@ -341,9 +358,6 @@ class Productlot extends CommonObject
     		}
     
     		if (!$error && !$notrigger) {
    -			// Uncomment this and change MYOBJECT to your own tag if you
    -			// want this action calls a trigger.
    -
     			// Call triggers
     			$result=$this->call_trigger('PRODUCTLOT_MODIFY',$user);
     			if ($result < 0) { $error++; }
    @@ -378,8 +392,8 @@ class Productlot extends CommonObject
     
     		$this->db->begin();
     
    -		if (!$error) {
    -			if (!$notrigger) {
    +		//if (!$error) {
    +			//if (!$notrigger) {
     				// Uncomment this and change MYOBJECT to your own tag if you
     				// want this action calls a trigger.
     
    @@ -387,8 +401,8 @@ class Productlot extends CommonObject
     				//$result=$this->call_trigger('MYOBJECT_DELETE',$user);
     				//if ($result < 0) { $error++; //Do also what you must do to rollback action if trigger fail}
     				//// End call triggers
    -			}
    -		}
    +			//}
    +		//}
     
     		if (!$error) {
     			$sql = 'DELETE FROM ' . MAIN_DB_PREFIX . $this->table_element;
    @@ -570,15 +584,15 @@ class Productlot extends CommonObject
     	{
     		$this->id = 0;
     
    -		$this->entity = '';
    -		$this->fk_product = '';
    +		$this->entity = null;
    +		$this->fk_product = null;
     		$this->batch = '';
     		$this->eatby = '';
     		$this->sellby = '';
     		$this->datec = '';
     		$this->tms = '';
    -		$this->fk_user_creat = '';
    -		$this->fk_user_modif = '';
    +		$this->fk_user_creat = null;
    +		$this->fk_user_modif = null;
     		$this->import_key = '';
     	}
     }
    diff --git a/htdocs/product/stock/class/productstockentrepot.class.php b/htdocs/product/stock/class/productstockentrepot.class.php
    index 1ab24b553d8..740afcb5f04 100644
    --- a/htdocs/product/stock/class/productstockentrepot.class.php
    +++ b/htdocs/product/stock/class/productstockentrepot.class.php
    @@ -51,8 +51,17 @@ class ProductStockEntrepot extends CommonObject
     	public $table_element = 'product_warehouse_properties';
     
     	public $tms = '';
    +
    +	/**
    +     * @var int ID
    +     */
     	public $fk_product;
    +
    +	/**
    +     * @var int ID
    +     */
     	public $fk_entrepot;
    +
     	public $seuil_stock_alerte;
     	public $desiredstock;
     	public $import_key;
    @@ -84,8 +93,8 @@ class ProductStockEntrepot extends CommonObject
     
     		// Clean parameters
     
    -		if (isset($this->fk_product)) $this->fk_product = trim($this->fk_product);
    -		if (isset($this->fk_entrepot)) $this->fk_entrepot = trim($this->fk_entrepot);
    +		if (isset($this->fk_product)) $this->fk_product = (int) $this->fk_product;
    +		if (isset($this->fk_entrepot)) $this->fk_entrepot = (int) $this->fk_entrepot;
     		if (isset($this->seuil_stock_alerte)) $this->seuil_stock_alerte = trim($this->seuil_stock_alerte);
     		if (isset($this->desiredstock)) $this->desiredstock = trim($this->desiredstock);
     		if (isset($this->import_key)) $this->import_key = trim($this->import_key);
    @@ -308,8 +317,8 @@ class ProductStockEntrepot extends CommonObject
     
     		// Clean parameters
     
    -		if (isset($this->fk_product)) $this->fk_product = trim($this->fk_product);
    -		if (isset($this->fk_entrepot)) $this->fk_entrepot = trim($this->fk_entrepot);
    +		if (isset($this->fk_product)) $this->fk_product = (int) $this->fk_product;
    +		if (isset($this->fk_entrepot)) $this->fk_entrepot = (int) $this->fk_entrepot;
     		if (isset($this->seuil_stock_alerte)) $this->seuil_stock_alerte = trim($this->seuil_stock_alerte);
     		if (isset($this->desiredstock)) $this->desiredstock = trim($this->desiredstock);
     		if (isset($this->import_key)) $this->import_key = trim($this->import_key);
    @@ -566,8 +575,8 @@ class ProductStockEntrepot extends CommonObject
     		$this->id = 0;
     
     		$this->tms = '';
    -		$this->fk_product = '';
    -		$this->fk_entrepot = '';
    +		$this->fk_product = null;
    +		$this->fk_entrepot = null;
     		$this->seuil_stock_alerte = '';
     		$this->desiredstock = '';
     		$this->import_key = '';
    diff --git a/htdocs/product/stock/index.php b/htdocs/product/stock/index.php
    index e658b794d4b..20054d8896b 100644
    --- a/htdocs/product/stock/index.php
    +++ b/htdocs/product/stock/index.php
    @@ -143,7 +143,7 @@ if ($resql)
     		print '<th>'.$langs->trans("EatByDate").'</th>';
     	}
     	print '<th>'.$langs->trans("Warehouse").'</th>';
    -	print '<th align="right"><a class="notasortlink" href="'.DOL_URL_ROOT.'/product/stock/mouvement.php">'.$langs->trans("FullList").'</a></th>';
    +	print '<th align="right"><a class="notasortlink" href="'.DOL_URL_ROOT.'/product/stock/movement_list.php">'.$langs->trans("FullList").'</a></th>';
     	print "</tr>\n";
     
     	$i=0;
    diff --git a/htdocs/product/stock/massstockmove.php b/htdocs/product/stock/massstockmove.php
    index c585b7a7e89..e456f966cf5 100644
    --- a/htdocs/product/stock/massstockmove.php
    +++ b/htdocs/product/stock/massstockmove.php
    @@ -161,7 +161,7 @@ if ($action == 'createmovements')
     	if (! GETPOST("label"))
     	{
     		$error++;
    -		setEventMessages($langs->trans("ErrorFieldRequired"),$langs->transnoentitiesnoconv("LabelMovement"), null, 'errors');
    +		setEventMessages($langs->trans("ErrorFieldRequired"),$langs->transnoentitiesnoconv("MovementLabel"), null, 'errors');
     	}
     
     	$db->begin();
    @@ -451,7 +451,7 @@ print '<table class="noborder" width="100%">';
     	print '</td>';
     	print '</tr>';
     	print '<tr>';
    -	print '<td>'.$langs->trans("LabelMovement").'</td>';
    +	print '<td>'.$langs->trans("MovementLabel").'</td>';
     	print '<td>';
     	print '<input type="text" name="label" class="quatrevingtpercent" value="'.dol_escape_htmltag($labelmovement).'">';
     	print '</td>';
    diff --git a/htdocs/product/stock/mouvement.php b/htdocs/product/stock/movement_list.php
    similarity index 96%
    rename from htdocs/product/stock/mouvement.php
    rename to htdocs/product/stock/movement_list.php
    index 07432766fbc..27c50d075aa 100644
    --- a/htdocs/product/stock/mouvement.php
    +++ b/htdocs/product/stock/movement_list.php
    @@ -20,7 +20,7 @@
      */
     
     /**
    - *	\file       htdocs/product/stock/mouvement.php
    + *	\file       htdocs/product/stock/movement_list.php
      *	\ingroup    stock
      *	\brief      Page to list stock movements
      */
    @@ -43,7 +43,7 @@ if (! empty($conf->projet->enabled))
     }
     
     // Load translation files required by the page
    -$langs->loadLangs(array('products', 'stocks'));
    +$langs->loadLangs(array('products', 'stocks', 'orders'));
     if (! empty($conf->productbatch->enabled)) $langs->load("productbatch");
     
     // Security check
    @@ -103,8 +103,8 @@ $arrayfields=array(
         'e.ref'=>array('label'=>$langs->trans("Warehouse"), 'checked'=>1, 'enabled'=>(! $id > 0)),	// If we are on specific warehouse, we hide it
         'm.fk_user_author'=>array('label'=>$langs->trans("Author"), 'checked'=>0),
         'm.inventorycode'=>array('label'=>$langs->trans("InventoryCodeShort"), 'checked'=>1),
    -    'm.label'=>array('label'=>$langs->trans("LabelMovement"), 'checked'=>1),
    -    'm.type_mouvement'=>array('label'=>$langs->trans("Type Mouvement"), 'checked'=>1),
    +    'm.label'=>array('label'=>$langs->trans("MovementLabel"), 'checked'=>1),
    +    'm.type_mouvement'=>array('label'=>$langs->trans("TypeMovement"), 'checked'=>1),
         'origin'=>array('label'=>$langs->trans("Origin"), 'checked'=>1),
     	'm.value'=>array('label'=>$langs->trans("Qty"), 'checked'=>1),
     	'm.price'=>array('label'=>$langs->trans("UnitPurchaseValue"), 'checked'=>0),
    @@ -385,7 +385,7 @@ if ($action == "transfert_stock" && ! $cancel)
                     }
                     else
                     {
    -                    header("Location: mouvement.php?id=".$object->id);
    +                    header("Location: movement_list.php?id=".$object->id);
                         exit;
                     }
                 }
    @@ -478,11 +478,11 @@ if (! empty($search_movement))      $sql.= natural_search('m.label', $search_mov
     if (! empty($search_inventorycode)) $sql.= natural_search('m.inventorycode', $search_inventorycode);
     if (! empty($search_product_ref))   $sql.= natural_search('p.ref', $search_product_ref);
     if (! empty($search_product))       $sql.= natural_search('p.label', $search_product);
    -if ($search_warehouse > 0)          $sql.= " AND e.rowid = '".$db->escape($search_warehouse)."'";
    +if ($search_warehouse != '' && $search_warehouse != '-1')          $sql.= natural_search('e.rowid', $search_warehouse, 2);
     if (! empty($search_user))          $sql.= natural_search('u.login', $search_user);
     if (! empty($search_batch))         $sql.= natural_search('m.batch', $search_batch);
     if ($search_qty != '')				$sql.= natural_search('m.value', $search_qty, 1);
    -if ($search_type_mouvement)	$sql.= " AND m.type_mouvement = '".$db->escape($search_type_mouvement)."'";
    +if ($search_type_mouvement != '' && $search_type_mouvement != '-1')	$sql.= natural_search('m.type_mouvement', $search_type_mouvement, 2);
     // Add where from extra fields
     include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_list_search_sql.tpl.php';
     // Add where from hooks
    @@ -579,8 +579,10 @@ if ($resql)
     
             print '<table class="border" width="100%">';
     
    +        print '<tr>';
    +
             // Description
    -        print '<tr><td class="titlefield tdtop">'.$langs->trans("Description").'</td><td>'.dol_htmlentitiesbr($object->description).'</td></tr>';
    +        print '<td class="titlefield tdtop">'.$langs->trans("Description").'</td><td>'.dol_htmlentitiesbr($object->description).'</td></tr>';
     
             $calcproductsunique=$object->nb_different_products();
             $calcproducts=$object->nb_products();
    @@ -841,13 +843,14 @@ if ($resql)
     	    // Type of movement
     	    print '<td class="liste_titre" align="center">';
     	    //print '<input class="flat" type="text" size="3" name="search_type_mouvement" value="'.dol_escape_htmltag($search_type_mouvement).'">';
    -		print '<select name="search_type_mouvement">';
    +		print '<select id="search_type_mouvement" name="search_type_mouvement" class="maxwidth150">';
     		print '<option value="" '.(($search_type_mouvement=="")?'selected="selected"':'').'></option>';
    -		print '<option value="0" '.(($search_type_mouvement=="0")?'selected="selected"':'').'>0</option>';
    -		print '<option value="1" '.(($search_type_mouvement=="1")?'selected="selected"':'').'>1</option>';
    -		print '<option value="2" '.(($search_type_mouvement=="2")?'selected="selected"':'').'>2</option>';
    -		print '<option value="3" '.(($search_type_mouvement=="3")?'selected="selected"':'').'>3</option>';
    +		print '<option value="0" '.(($search_type_mouvement=="0")?'selected="selected"':'').'>'.$langs->trans('StockIncreaseAfterCorrectTransfer').'</option>';
    +		print '<option value="1" '.(($search_type_mouvement=="1")?'selected="selected"':'').'>'.$langs->trans('StockDecreaseAfterCorrectTransfer').'</option>';
    +		print '<option value="2" '.(($search_type_mouvement=="2")?'selected="selected"':'').'>'.$langs->trans('StockDecrease').'</option>';
    +		print '<option value="3" '.(($search_type_mouvement=="3")?'selected="selected"':'').'>'.$langs->trans('StockIncrease').'</option>';
     		print '</select>';
    +		print ajax_combobox('search_type_mouvement');
     		// TODO: add new function $formentrepot->selectTypeOfMovement(...) like
     		// print $formproduct->selectWarehouses($search_warehouse, 'search_warehouse', 'warehouseopen,warehouseinternal', 1, 0, 0, '', 0, 0, null, 'maxwidth200');
     	    print '</td>';
    @@ -966,7 +969,7 @@ if ($resql)
     			$origin = '';
     		}
     
    -        print "<tr>";
    +        print '<tr class="oddeven">';
             // Id movement
             if (! empty($arrayfields['m.rowid']['checked']))
             {
    @@ -980,7 +983,7 @@ if ($resql)
             if (! empty($arrayfields['p.ref']['checked']))
             {
     	        // Product ref
    -	        print '<td>';
    +	        print '<td class="nowraponall">';
     	        print $productstatic->getNomUrl(1,'stock',16);
     	        print "</td>\n";
             }
    @@ -997,7 +1000,7 @@ if ($resql)
             }
             if (! empty($arrayfields['m.batch']['checked']))
             {
    -	    	print '<td align="center">';
    +	    	print '<td class="center nowraponall">';
     	    	if ($productlot->id > 0) print $productlot->getNomUrl(1);
     	    	else print $productlot->batch;		// the id may not be defined if movement was entered when lot was not saved or if lot was removed after movement.
     	    	print '</td>';
    @@ -1028,7 +1031,7 @@ if ($resql)
             {
     	        // Inventory code
     	        print '<td>'.'<a href="'
    -								.DOL_URL_ROOT.'/product/stock/mouvement.php'
    +								.DOL_URL_ROOT.'/product/stock/movement_list.php'
     								.'?id='.$objp->entrepot_id
     								.'&amp;search_inventorycode='.$objp->inventorycode
     							    .'&amp;search_type_mouvement='.$objp->type_mouvement
    @@ -1050,7 +1053,7 @@ if ($resql)
             if (! empty($arrayfields['origin']['checked']))
             {
             	// Origin of movement
    -        	print '<td>'.$origin.'</td>';
    +        	print '<td class="nowraponall">'.$origin.'</td>';
             }
             if (! empty($arrayfields['m.value']['checked']))
             {
    diff --git a/htdocs/product/stock/product.php b/htdocs/product/stock/product.php
    index 324e14047d4..07b4f5dcac3 100644
    --- a/htdocs/product/stock/product.php
    +++ b/htdocs/product/stock/product.php
    @@ -5,7 +5,7 @@
      * Copyright (C) 2005      Simon TOSSER         <simon@kornog-computing.com>
      * Copyright (C) 2005-2009 Regis Houssin        <regis.houssin@capnetworks.com>
      * Copyright (C) 2013      Cédric Salvador      <csalvador.gpcsolutions.fr>
    - * Copyright (C) 2013-2015 Juanjo Menent	    <jmenent@2byte.es>
    + * Copyright (C) 2013-2018 Juanjo Menent	    <jmenent@2byte.es>
      * Copyright (C) 2014-2015 Cédric Gross         <c.gross@kreiz-it.fr>
      * Copyright (C) 2015      Marcos García        <marcosgdf@gmail.com>
      * Copyright (C) 2018       Frédéric France         <frederic.france@netlogic.fr>
    @@ -45,6 +45,13 @@ if (! empty($conf->projet->enabled))
     	require_once DOL_DOCUMENT_ROOT.'/projet/class/project.class.php';
     }
     
    +if (! empty($conf->variants->enabled)) {
    +	require_once DOL_DOCUMENT_ROOT . '/variants/class/ProductAttribute.class.php';
    +	require_once DOL_DOCUMENT_ROOT . '/variants/class/ProductAttributeValue.class.php';
    +	require_once DOL_DOCUMENT_ROOT . '/variants/class/ProductCombination.class.php';
    +	require_once DOL_DOCUMENT_ROOT . '/variants/class/ProductCombination2ValuePair.class.php';
    +}
    +
     // Load translation files required by the page
     $langs->loadlangs(array('products', 'orders', 'bills', 'stocks', 'sendings'));
     if (! empty($conf->productbatch->enabled)) $langs->load("productbatch");
    @@ -518,6 +525,8 @@ if ($id > 0 || $ref)
     	$object = new Product($db);
     	$result = $object->fetch($id,$ref);
     
    +	$variants = $object->hasVariants();
    +
     	$object->load_stock();
     
     	$title = $langs->trans('ProductServiceCard');
    @@ -558,174 +567,161 @@ if ($id > 0 || $ref)
             print '<div class="underbanner clearboth"></div>';
             print '<table class="border tableforfield" width="100%">';
     
    -		if ($conf->productbatch->enabled)
    -		{
    -			print '<tr><td class="titlefield">'.$langs->trans("ManageLotSerial").'</td><td>';
    -			print $object->getLibStatut(0,2);
    -			print '</td></tr>';
    -		}
    +		if (! $variants) {
     
    -		// PMP
    -		print '<tr><td class="titlefield">'.$langs->trans("AverageUnitPricePMP").'</td>';
    -		print '<td>';
    -		if ($object->pmp > 0) print price($object->pmp).' '.$langs->trans("HT");
    -		print '</td>';
    -		print '</tr>';
    +			if ($conf->productbatch->enabled) {
    +				print '<tr><td class="titlefield">' . $langs->trans("ManageLotSerial") . '</td><td>';
    +				print $object->getLibStatut(0, 2);
    +				print '</td></tr>';
    +			}
     
    -		// Minimum Price
    -		print '<tr><td>'.$langs->trans("BuyingPriceMin").'</td>';
    -		print '<td>';
    -		$product_fourn = new ProductFournisseur($db);
    -		if ($product_fourn->find_min_price_product_fournisseur($object->id) > 0)
    -		{
    -			if ($product_fourn->product_fourn_price_id > 0) print $product_fourn->display_price_product_fournisseur();
    -			else print $langs->trans("NotDefined");
    -		}
    -		print '</td></tr>';
    +			// PMP
    +			print '<tr><td class="titlefield">' . $langs->trans("AverageUnitPricePMP") . '</td>';
    +			print '<td>';
    +			if ($object->pmp > 0) print price($object->pmp) . ' ' . $langs->trans("HT");
    +			print '</td>';
    +			print '</tr>';
     
    -		if (empty($conf->global->PRODUIT_MULTIPRICES))
    -		{
    -			// Price
    -			print '<tr><td>' . $langs->trans("SellingPrice") . '</td><td>';
    -			if ($object->price_base_type == 'TTC') {
    -				print price($object->price_ttc) . ' ' . $langs->trans($object->price_base_type);
    -			} else {
    -				print price($object->price) . ' ' . $langs->trans($object->price_base_type);
    +			// Minimum Price
    +			print '<tr><td>' . $langs->trans("BuyingPriceMin") . '</td>';
    +			print '<td>';
    +			$product_fourn = new ProductFournisseur($db);
    +			if ($product_fourn->find_min_price_product_fournisseur($object->id) > 0) {
    +				if ($product_fourn->product_fourn_price_id > 0) print $product_fourn->display_price_product_fournisseur();
    +				else print $langs->trans("NotDefined");
     			}
     			print '</td></tr>';
     
    -			// Price minimum
    -			print '<tr><td>' . $langs->trans("MinPrice") . '</td><td>';
    -			if ($object->price_base_type == 'TTC') {
    -				print price($object->price_min_ttc) . ' ' . $langs->trans($object->price_base_type);
    +			if (empty($conf->global->PRODUIT_MULTIPRICES)) {
    +				// Price
    +				print '<tr><td>' . $langs->trans("SellingPrice") . '</td><td>';
    +				if ($object->price_base_type == 'TTC') {
    +					print price($object->price_ttc) . ' ' . $langs->trans($object->price_base_type);
    +				} else {
    +					print price($object->price) . ' ' . $langs->trans($object->price_base_type);
    +				}
    +				print '</td></tr>';
    +
    +				// Price minimum
    +				print '<tr><td>' . $langs->trans("MinPrice") . '</td><td>';
    +				if ($object->price_base_type == 'TTC') {
    +					print price($object->price_min_ttc) . ' ' . $langs->trans($object->price_base_type);
    +				} else {
    +					print price($object->price_min) . ' ' . $langs->trans($object->price_base_type);
    +				}
    +				print '</td></tr>';
     			} else {
    -				print price($object->price_min) . ' ' . $langs->trans($object->price_base_type);
    +				// Price
    +				print '<tr><td>' . $langs->trans("SellingPrice") . '</td><td>';
    +				print $langs->trans("Variable");
    +				print '</td></tr>';
    +
    +				// Price minimum
    +				print '<tr><td>' . $langs->trans("MinPrice") . '</td><td>';
    +				print $langs->trans("Variable");
    +				print '</td></tr>';
     			}
    -			print '</td></tr>';
    -		}
    -		else
    -		{
    -			// Price
    -			print '<tr><td>' . $langs->trans("SellingPrice") . '</td><td>';
    -			print $langs->trans("Variable");
    +
    +			// Stock alert threshold
    +			print '<tr><td>' . $form->editfieldkey($form->textwithpicto($langs->trans("StockLimit"), $langs->trans("StockLimitDesc"), 1), 'seuil_stock_alerte', $object->seuil_stock_alerte, $object, $user->rights->produit->creer) . '</td><td>';
    +			print $form->editfieldval("StockLimit", 'seuil_stock_alerte', $object->seuil_stock_alerte, $object, $user->rights->produit->creer, 'string');
     			print '</td></tr>';
     
    -			// Price minimum
    -			print '<tr><td>' . $langs->trans("MinPrice") . '</td><td>';
    -			print $langs->trans("Variable");
    +			// Hook formObject
    +			$parameters = array();
    +			$reshook = $hookmanager->executeHooks('formObjectOptions', $parameters, $object, $action);    // Note that $action and $object may have been modified by hook
    +			print $hookmanager->resPrint;
    +
    +			// Desired stock
    +			print '<tr><td>' . $form->editfieldkey($form->textwithpicto($langs->trans("DesiredStock"), $langs->trans("DesiredStockDesc"), 1), 'desiredstock', $object->desiredstock, $object, $user->rights->produit->creer);
    +			print '</td><td>';
    +			print $form->editfieldval("DesiredStock", 'desiredstock', $object->desiredstock, $object, $user->rights->produit->creer, 'string');
     			print '</td></tr>';
    +
    +			// Real stock
    +			$text_stock_options = $langs->trans("RealStockDesc") . '<br>';
    +			$text_stock_options .= $langs->trans("RealStockWillAutomaticallyWhen") . '<br>';
    +			$text_stock_options .= (!empty($conf->global->STOCK_CALCULATE_ON_SHIPMENT) || !empty($conf->global->STOCK_CALCULATE_ON_SHIPMENT_CLOSE) ? $langs->trans("DeStockOnShipment") . '<br>' : '');
    +			$text_stock_options .= (!empty($conf->global->STOCK_CALCULATE_ON_VALIDATE_ORDER) ? $langs->trans("DeStockOnValidateOrder") . '<br>' : '');
    +			$text_stock_options .= (!empty($conf->global->STOCK_CALCULATE_ON_BILL) ? $langs->trans("DeStockOnBill") . '<br>' : '');
    +			$text_stock_options .= (!empty($conf->global->STOCK_CALCULATE_ON_SUPPLIER_BILL) ? $langs->trans("ReStockOnBill") . '<br>' : '');
    +			$text_stock_options .= (!empty($conf->global->STOCK_CALCULATE_ON_SUPPLIER_VALIDATE_ORDER) ? $langs->trans("ReStockOnValidateOrder") . '<br>' : '');
    +			$text_stock_options .= (!empty($conf->global->STOCK_CALCULATE_ON_SUPPLIER_DISPATCH_ORDER) ? $langs->trans("ReStockOnDispatchOrder") . '<br>' : '');
    +			print '<tr><td>';
    +			print $form->textwithpicto($langs->trans("PhysicalStock"), $text_stock_options, 1);
    +			print '</td>';
    +			print '<td>' . price2num($object->stock_reel, 'MS');
    +			if ($object->seuil_stock_alerte != '' && ($object->stock_reel < $object->seuil_stock_alerte)) print ' ' . img_warning($langs->trans("StockLowerThanLimit", $object->seuil_stock_alerte));
    +			print '</td>';
    +			print '</tr>';
    +
    +			$stocktheo = price2num($object->stock_theorique, 'MS');
    +
    +			$found = 0;
    +			$helpondiff = '<strong>' . $langs->trans("StockDiffPhysicTeoric") . ':</strong><br>';
    +			// Number of customer orders running
    +			if (!empty($conf->commande->enabled)) {
    +				if ($found) $helpondiff .= '<br>'; else $found = 1;
    +				$helpondiff .= $langs->trans("ProductQtyInCustomersOrdersRunning") . ': ' . $object->stats_commande['qty'];
    +				$result = $object->load_stats_commande(0, '0', 1);
    +				if ($result < 0) dol_print_error($db, $object->error);
    +				$helpondiff .= ' (' . $langs->trans("ProductQtyInDraft") . ': ' . $object->stats_commande['qty'] . ')';
    +			}
    +
    +			// Number of product from customer order already sent (partial shipping)
    +			if (!empty($conf->expedition->enabled)) {
    +				if ($found) $helpondiff .= '<br>'; else $found = 1;
    +				$result = $object->load_stats_sending(0, '2', 1);
    +				$helpondiff .= $langs->trans("ProductQtyInShipmentAlreadySent") . ': ' . $object->stats_expedition['qty'];
    +			}
    +
    +			// Number of supplier order running
    +			if (!empty($conf->fournisseur->enabled)) {
    +				if ($found) $helpondiff .= '<br>'; else $found = 1;
    +				$result = $object->load_stats_commande_fournisseur(0, '3,4', 1);
    +				$helpondiff .= $langs->trans("ProductQtyInSuppliersOrdersRunning") . ': ' . $object->stats_commande_fournisseur['qty'];
    +				$result = $object->load_stats_commande_fournisseur(0, '0,1,2', 1);
    +				if ($result < 0) dol_print_error($db, $object->error);
    +				$helpondiff .= ' (' . $langs->trans("ProductQtyInDraftOrWaitingApproved") . ': ' . $object->stats_commande_fournisseur['qty'] . ')';
    +			}
    +
    +			// Number of product from supplier order already received (partial receipt)
    +			if (!empty($conf->fournisseur->enabled)) {
    +				if ($found) $helpondiff .= '<br>'; else $found = 1;
    +				$helpondiff .= $langs->trans("ProductQtyInSuppliersShipmentAlreadyRecevied") . ': ' . $object->stats_reception['qty'];
    +			}
    +
    +			// Calculating a theorical value
    +			print '<tr><td>';
    +			print $form->textwithpicto($langs->trans("VirtualStock"), $langs->trans("VirtualStockDesc"));
    +			print '</td>';
    +			print "<td>";
    +			//print (empty($stocktheo)?0:$stocktheo);
    +			print $form->textwithpicto((empty($stocktheo) ? 0 : $stocktheo), $helpondiff);
    +			if ($object->seuil_stock_alerte != '' && ($object->stock_theorique < $object->seuil_stock_alerte)) print ' ' . img_warning($langs->trans("StockLowerThanLimit", $object->seuil_stock_alerte));
    +			print '</td>';
    +			print '</tr>';
    +
    +			// Last movement
    +			$sql = "SELECT max(m.datem) as datem";
    +			$sql .= " FROM " . MAIN_DB_PREFIX . "stock_mouvement as m";
    +			$sql .= " WHERE m.fk_product = '" . $object->id . "'";
    +			$resqlbis = $db->query($sql);
    +			if ($resqlbis) {
    +				$obj = $db->fetch_object($resqlbis);
    +				$lastmovementdate = $db->jdate($obj->datem);
    +			} else {
    +				dol_print_error($db);
    +			}
    +			print '<tr><td class="tdtop">' . $langs->trans("LastMovement") . '</td><td>';
    +			if ($lastmovementdate) {
    +				print dol_print_date($lastmovementdate, 'dayhour') . ' ';
    +				print '(<a href="' . DOL_URL_ROOT . '/product/stock/movement_list.php?idproduct=' . $object->id . '">' . $langs->trans("FullList") . '</a>)';
    +			} else {
    +				print '<a href="' . DOL_URL_ROOT . '/product/stock/movement_list.php?idproduct=' . $object->id . '">' . $langs->trans("None") . '</a>';
    +			}
    +			print "</td></tr>";
     		}
    -
    -        // Stock alert threshold
    -        print '<tr><td>'.$form->editfieldkey($form->textwithpicto($langs->trans("StockLimit"), $langs->trans("StockLimitDesc"), 1),'seuil_stock_alerte',$object->seuil_stock_alerte,$object,$user->rights->produit->creer).'</td><td>';
    -        print $form->editfieldval("StockLimit",'seuil_stock_alerte',$object->seuil_stock_alerte,$object,$user->rights->produit->creer,'string');
    -        print '</td></tr>';
    -
    -		// Hook formObject
    -		$parameters=array();
    -		$reshook=$hookmanager->executeHooks('formObjectOptions',$parameters,$object,$action);    // Note that $action and $object may have been modified by hook
    -		print $hookmanager->resPrint;
    -
    -        // Desired stock
    -        print '<tr><td>'.$form->editfieldkey($form->textwithpicto($langs->trans("DesiredStock"), $langs->trans("DesiredStockDesc"), 1),'desiredstock',$object->desiredstock,$object,$user->rights->produit->creer);
    -        print '</td><td>';
    -        print $form->editfieldval("DesiredStock",'desiredstock',$object->desiredstock,$object,$user->rights->produit->creer,'string');
    -        print '</td></tr>';
    -
    -        // Real stock
    -        $text_stock_options = $langs->trans("RealStockDesc").'<br>';
    -        $text_stock_options.= $langs->trans("RealStockWillAutomaticallyWhen").'<br>';
    -        $text_stock_options.= (! empty($conf->global->STOCK_CALCULATE_ON_SHIPMENT) || ! empty($conf->global->STOCK_CALCULATE_ON_SHIPMENT_CLOSE)?$langs->trans("DeStockOnShipment").'<br>':'');
    -        $text_stock_options.= (! empty($conf->global->STOCK_CALCULATE_ON_VALIDATE_ORDER)?$langs->trans("DeStockOnValidateOrder").'<br>':'');
    -        $text_stock_options.= (! empty($conf->global->STOCK_CALCULATE_ON_BILL)?$langs->trans("DeStockOnBill").'<br>':'');
    -        $text_stock_options.= (! empty($conf->global->STOCK_CALCULATE_ON_SUPPLIER_BILL)?$langs->trans("ReStockOnBill").'<br>':'');
    -        $text_stock_options.= (! empty($conf->global->STOCK_CALCULATE_ON_SUPPLIER_VALIDATE_ORDER)?$langs->trans("ReStockOnValidateOrder").'<br>':'');
    -        $text_stock_options.= (! empty($conf->global->STOCK_CALCULATE_ON_SUPPLIER_DISPATCH_ORDER)?$langs->trans("ReStockOnDispatchOrder").'<br>':'');
    -        print '<tr><td>';
    -        print $form->textwithpicto($langs->trans("PhysicalStock"), $text_stock_options, 1);
    -        print '</td>';
    -		print '<td>'.price2num($object->stock_reel, 'MS');
    -		if ($object->seuil_stock_alerte != '' && ($object->stock_reel < $object->seuil_stock_alerte)) print ' '.img_warning($langs->trans("StockLowerThanLimit", $object->seuil_stock_alerte));
    -		print '</td>';
    -		print '</tr>';
    -
    -		$stocktheo = price2num($object->stock_theorique, 'MS');
    -
    -		$found=0;
    -		$helpondiff='<strong>'.$langs->trans("StockDiffPhysicTeoric").':</strong><br>';
    -		// Number of customer orders running
    -		if (! empty($conf->commande->enabled))
    -		{
    -		    if ($found) $helpondiff.='<br>'; else $found=1;
    -		    $helpondiff.=$langs->trans("ProductQtyInCustomersOrdersRunning").': '.$object->stats_commande['qty'];
    -		    $result=$object->load_stats_commande(0,'0', 1);
    -		    if ($result < 0) dol_print_error($db,$object->error);
    -		    $helpondiff.=' ('.$langs->trans("ProductQtyInDraft").': '.$object->stats_commande['qty'].')';
    -		}
    -
    -		// Number of product from customer order already sent (partial shipping)
    -		if (! empty($conf->expedition->enabled))
    -		{
    -		    if ($found) $helpondiff.='<br>'; else $found=1;
    -		    $result=$object->load_stats_sending(0,'2', 1);
    -		    $helpondiff.=$langs->trans("ProductQtyInShipmentAlreadySent").': '.$object->stats_expedition['qty'];
    -		}
    -
    -		// Number of supplier order running
    -		if (! empty($conf->fournisseur->enabled))
    -		{
    -		    if ($found) $helpondiff.='<br>'; else $found=1;
    -		    $result=$object->load_stats_commande_fournisseur(0,'3,4', 1);
    -		    $helpondiff.=$langs->trans("ProductQtyInSuppliersOrdersRunning").': '.$object->stats_commande_fournisseur['qty'];
    -		    $result=$object->load_stats_commande_fournisseur(0,'0,1,2', 1);
    -		    if ($result < 0) dol_print_error($db,$object->error);
    -		    $helpondiff.=' ('.$langs->trans("ProductQtyInDraftOrWaitingApproved").': '.$object->stats_commande_fournisseur['qty'].')';
    -		}
    -
    -		// Number of product from supplier order already received (partial receipt)
    -		if (! empty($conf->fournisseur->enabled))
    -		{
    -		    if ($found) $helpondiff.='<br>'; else $found=1;
    -		    $helpondiff.=$langs->trans("ProductQtyInSuppliersShipmentAlreadyRecevied").': '.$object->stats_reception['qty'];
    -		}
    -
    -        // Calculating a theorical value
    -        print '<tr><td>';
    -        print $form->textwithpicto($langs->trans("VirtualStock"), $langs->trans("VirtualStockDesc"));
    -        print '</td>';
    -        print "<td>";
    -        //print (empty($stocktheo)?0:$stocktheo);
    -        print $form->textwithpicto((empty($stocktheo)?0:$stocktheo), $helpondiff);
    -        if ($object->seuil_stock_alerte != '' && ($object->stock_theorique < $object->seuil_stock_alerte)) print ' '.img_warning($langs->trans("StockLowerThanLimit", $object->seuil_stock_alerte));
    -        print '</td>';
    -        print '</tr>';
    -
    -		// Last movement
    -		$sql = "SELECT max(m.datem) as datem";
    -		$sql.= " FROM ".MAIN_DB_PREFIX."stock_mouvement as m";
    -		$sql.= " WHERE m.fk_product = '".$object->id."'";
    -		$resqlbis = $db->query($sql);
    -		if ($resqlbis)
    -		{
    -			$obj = $db->fetch_object($resqlbis);
    -			$lastmovementdate=$db->jdate($obj->datem);
    -		}
    -		else
    -		{
    -			dol_print_error($db);
    -		}
    -		print '<tr><td class="tdtop">'.$langs->trans("LastMovement").'</td><td>';
    -		if ($lastmovementdate)
    -		{
    -		    print dol_print_date($lastmovementdate,'dayhour').' ';
    -		    print '(<a href="'.DOL_URL_ROOT.'/product/stock/mouvement.php?idproduct='.$object->id.'">'.$langs->trans("FullList").'</a>)';
    -		}
    -		else
    -		{
    -		     print '<a href="'.DOL_URL_ROOT.'/product/stock/mouvement.php?idproduct='.$object->id.'">'.$langs->trans("None").'</a>';
    -		}
    -		print "</td></tr>";
    -
     		print "</table>";
     
             print '</div>';
    @@ -770,15 +766,35 @@ if (empty($reshook))
     	{
     	    print "<div class=\"tabsAction\">\n";
     
    -	    if ($user->rights->stock->mouvement->creer)
    -	    {
    -	        print '<a class="butAction" href="'.$_SERVER["PHP_SELF"].'?id='.$object->id.'&amp;action=correction">'.$langs->trans("CorrectStock").'</a>';
    -	    }
    -
    -	    //if (($user->rights->stock->mouvement->creer) && ! $object->hasbatch())
    -	    if ($user->rights->stock->mouvement->creer)
    +		if ($user->rights->stock->mouvement->creer)
     		{
    -			print '<a class="butAction" href="'.$_SERVER["PHP_SELF"].'?id='.$object->id.'&amp;action=transfert">'.$langs->trans("TransferStock").'</a>';
    +			if (! $variants) {
    +				print '<a class="butAction" href="' . $_SERVER["PHP_SELF"] . '?id=' . $object->id . '&amp;action=correction">' . $langs->trans("CorrectStock") . '</a>';
    +			}
    +			else
    +			{
    +				print '<a class="butActionRefused" href="#" title="'.$langs->trans("ActionAvailableOnVariantProductOnly").'">' . $langs->trans("CorrectStock") . '</a>';
    +			}
    +		}
    +		else
    +		{
    +			print '<a class="butActionRefused" href="#" title="'.$langs->trans("NotEnoughPermissions").'">' . $langs->trans("CorrectStock") . '</a>';
    +		}
    +
    +		//if (($user->rights->stock->mouvement->creer) && ! $object->hasbatch())
    +		if ($user->rights->stock->mouvement->creer)
    +		{
    +			if (! $variants) {
    +				print '<a class="butAction" href="' . $_SERVER["PHP_SELF"] . '?id=' . $object->id . '&amp;action=transfert">' . $langs->trans("TransferStock") . '</a>';
    +			}
    +			else
    +			{
    +				print '<a class="butActionRefused" href="#" title="'.$langs->trans("ActionAvailableOnVariantProductOnly").'">' . $langs->trans("TransferStock") . '</a>';
    +			}
    +		}
    +		else
    +		{
    +			print '<a class="butActionRefused" href="#" title="'.$langs->trans("NotEnoughPermissions").'">' . $langs->trans("CorrectStock") . '</a>';
     		}
     
     		print '</div>';
    @@ -787,212 +803,288 @@ if (empty($reshook))
     }
     
     
    -/*
    - * Stock detail (by warehouse). May go down into batch details.
    - */
    +if (! $variants) {
    +	/*
    +	 * Stock detail (by warehouse). May go down into batch details.
    +	 */
     
    -print '<div class="div-table-responsive">';
    -print '<table class="noborder" width="100%">';
    -print '<tr class="liste_titre">';
    -print '<td colspan="4">'.$langs->trans("Warehouse").'</td>';
    -print '<td align="right">'.$langs->trans("NumberOfUnit").'</td>';
    -print '<td align="right">'.$langs->trans("AverageUnitPricePMPShort").'</td>';
    -print '<td align="right">'.$langs->trans("EstimatedStockValueShort").'</td>';
    -print '<td align="right">'.$langs->trans("SellPriceMin").'</td>';
    -print '<td align="right">'.$langs->trans("EstimatedStockValueSellShort").'</td>';
    -print '</tr>';
    -if ((! empty($conf->productbatch->enabled)) && $object->hasbatch())
    -{
    -	print '<tr class="liste_titre"><td width="10%"></td>';
    -	print '<td align="right" width="10%">'.$langs->trans("batch_number").'</td>';
    -	print '<td align="center" width="10%">'.$langs->trans("EatByDate").'</td>';
    -	print '<td align="center" width="10%">'.$langs->trans("SellByDate").'</td>';
    -	print '<td></td>';
    -	print '<td></td>';
    -	print '<td></td>';
    -	print '<td></td>';
    -	print '<td></td>';
    -	print '</tr>';
    -}
    -
    -$sql = "SELECT e.rowid, e.ref as label, e.lieu, ps.reel, ps.rowid as product_stock_id, p.pmp";
    -$sql.= " FROM ".MAIN_DB_PREFIX."entrepot as e,";
    -$sql.= " ".MAIN_DB_PREFIX."product_stock as ps";
    -$sql.= " LEFT JOIN ".MAIN_DB_PREFIX."product as p ON p.rowid = ps.fk_product";
    -$sql.= " WHERE ps.reel != 0";
    -$sql.= " AND ps.fk_entrepot = e.rowid";
    -$sql.= " AND e.entity IN (".getEntity('stock').")";
    -$sql.= " AND ps.fk_product = ".$object->id;
    -$sql.= " ORDER BY e.ref";
    -
    -$entrepotstatic=new Entrepot($db);
    -$product_lot_static=new Productlot($db);
    -
    -$total=0;
    -$totalvalue=$totalvaluesell=0;
    -
    -$resql=$db->query($sql);
    -if ($resql)
    -{
    -	$num = $db->num_rows($resql);
    -	$total=$totalwithpmp;
    -	$i=0; $var=false;
    -	while ($i < $num)
    -	{
    -		$obj = $db->fetch_object($resql);
    -		$entrepotstatic->id=$obj->rowid;
    -		$entrepotstatic->libelle=$obj->label;
    -		$entrepotstatic->lieu=$obj->lieu;
    -		$stock_real = price2num($obj->reel, 'MS');
    -		print '<tr class="oddeven">';
    -		print '<td colspan="4">'.$entrepotstatic->getNomUrl(1).'</td>';
    -		print '<td align="right">'.$stock_real.($stock_real < 0 ?' '.img_warning():'').'</td>';
    -		// PMP
    -		print '<td align="right">'.(price2num($object->pmp)?price2num($object->pmp,'MU'):'').'</td>';
    -		// Value purchase
    -		print '<td align="right">'.(price2num($object->pmp)?price(price2num($object->pmp*$obj->reel,'MT')):'').'</td>';
    -        // Sell price
    -		print '<td align="right">';
    -        if (empty($conf->global->PRODUIT_MULTIPRICES)) print price(price2num($object->price,'MU'),1);
    -        else print $langs->trans("Variable");
    -        print '</td>';
    -        // Value sell
    -        print '<td align="right">';
    -        if (empty($conf->global->PRODUIT_MULTIPRICES)) print price(price2num($object->price*$obj->reel,'MT'),1).'</td>';
    -        else print $langs->trans("Variable");
    -		print '</tr>'; ;
    -		$total += $obj->reel;
    -		if (price2num($object->pmp)) $totalwithpmp += $obj->reel;
    -		$totalvalue = $totalvalue + ($object->pmp*$obj->reel);
    -        $totalvaluesell = $totalvaluesell + ($object->price*$obj->reel);
    -		// Batch Detail
    -		if ((! empty($conf->productbatch->enabled)) && $object->hasbatch())
    -		{
    -			$details=Productbatch::findAll($db, $obj->product_stock_id, 0, $object->id);
    -			if ($details<0) dol_print_error($db);
    -			foreach ($details as $pdluo)
    -			{
    -				$product_lot_static->id = $pdluo->lotid;
    -				$product_lot_static->batch = $pdluo->batch;
    -				$product_lot_static->eatby = $pdluo->eatby;
    -				$product_lot_static->sellby = $pdluo->sellby;
    -
    -			    if ($action == 'editline' && GETPOST('lineid','int') == $pdluo->id)
    -			    { //Current line edit
    -			        print "\n".'<tr>';
    -			        print '<td colspan="9">';
    -			        print '<form action="'.$_SERVER["PHP_SELF"].'" method="POST">';
    -			        print '<input type="hidden" name="pdluoid" value="'.$pdluo->id.'"><input type="hidden" name="action" value="updateline"><input type="hidden" name="id" value="'.$id.'"><table class="noborder" width="100%"><tr><td width="10%"></td>';
    -			        print '<td align="right" width="10%"><input type="text" name="batch_number" value="'.$pdluo->batch.'"></td>';
    -			        print '<td align="center" width="10%">';
    -			        print $form->selectDate($pdluo->eatby,'eatby','','',1,'',1,0);
    -			        print '</td>';
    -			        print '<td align="center" width="10%">';
    -			        print $form->selectDate($pdluo->sellby,'sellby','','',1,'',1,0);
    -			        print '</td>';
    -			        print '<td align="right" width="10%">'.$pdluo->qty.($pdluo->qty<0?' '.img_warning():'').'</td>';
    -			        print '<td colspan="4"><input type="submit" class="button" id="savelinebutton" name="save" value="'.$langs->trans("Save").'">';
    -		            print '<input type="submit" class="button" id="cancellinebutton" name="Cancel" value="'.$langs->trans("Cancel").'"></td></tr>';
    -			        print '</table>';
    -			        print '</form>';
    -			        print '</td></tr>';
    -			    }
    -			    else
    -				{
    -                    print "\n".'<tr><td align="right">';
    -                    print img_picto($langs->trans("Tranfer"),'uparrow','class="hideonsmartphone"').' ';
    -					print '<a href="'.$_SERVER["PHP_SELF"].'?id='.$object->id.'&amp;id_entrepot='.$entrepotstatic->id.'&amp;action=transfert&amp;pdluoid='.$pdluo->id.'">'.$langs->trans("TransferStock").'</a>';
    -					// Disabled, because edition of stock content must use the "Correct stock menu".
    -					// Do not use this, or data will be wrong (bad tracking of movement label, inventory code, ...
    -                    //print '<a href="'.$_SERVER["PHP_SELF"].'?id='.$id.'&amp;action=editline&amp;lineid='.$pdluo->id.'#'.$pdluo->id.'">';
    -                    //print img_edit().'</a></td>';
    -                    print '<td align="right">';
    -                    print $product_lot_static->getNomUrl(1);
    -                    print '</td>';
    -                    print '<td align="center">'. dol_print_date($pdluo->eatby,'day') .'</td>';
    -                    print '<td align="center">'. dol_print_date($pdluo->sellby,'day') .'</td>';
    -                    print '<td align="right">'.$pdluo->qty.($pdluo->qty<0?' '.img_warning():'').'</td>';
    -                    print '<td colspan="4"></td></tr>';
    -			    }
    -			}
    -		}
    -		$i++;
    -
    -	}
    -}
    -else dol_print_error($db);
    -
    -print '<tr class="liste_total"><td align="right" class="liste_total" colspan="4">'.$langs->trans("Total").':</td>';
    -print '<td class="liste_total" align="right">'.price2num($total, 'MS').'</td>';
    -print '<td class="liste_total" align="right">';
    -print ($totalwithpmp?price(price2num($totalvalue/$totalwithpmp,'MU')):'&nbsp;');	// This value may have rounding errors
    -print '</td>';
    -// Value purchase
    -print '<td class="liste_total" align="right">';
    -print $totalvalue?price(price2num($totalvalue,'MT'),1):'&nbsp;';
    -print '</td>';
    -print '<td class="liste_total" align="right">';
    -if (empty($conf->global->PRODUIT_MULTIPRICES)) print ($total?price($totalvaluesell/$total,1):'&nbsp;');
    -else print $langs->trans("Variable");
    -print '</td>';
    -// Value to sell
    -print '<td class="liste_total" align="right">';
    -if (empty($conf->global->PRODUIT_MULTIPRICES)) print price(price2num($totalvaluesell,'MT'),1);
    -else print $langs->trans("Variable");
    -print '</td>';
    -print "</tr>";
    -print "</table>";
    -print '</div>';
    -
    -if (!empty($conf->global->STOCK_ALLOW_ADD_LIMIT_STOCK_BY_WAREHOUSE))
    -{
    -	print '<br><br>';
    -	print_titre($langs->trans('AddNewProductStockWarehouse'));
    -
    -	if (!empty($user->rights->produit->creer)){
    -		print '<form action="'.$_SERVER["PHP_SELF"].'" method="POST">';
    -		print '<input type="hidden" name="action" value="addlimitstockwarehouse">';
    -		print '<input type="hidden" name="id" value="'.$id.'">';
    -	}
    +	print '<div class="div-table-responsive">';
     	print '<table class="noborder" width="100%">';
    -	if (!empty($user->rights->produit->creer)){
    -		print '<tr class="liste_titre"><td width="40%">'.$formproduct->selectWarehouses('', 'fk_entrepot').'</td>';
    -		print '<td align="right"><input name="seuil_stock_alerte" type="text" placeholder="'.$langs->trans("StockLimit").'" /></td>';
    -		print '<td align="right"><input name="desiredstock" type="text" placeholder="'.$langs->trans("DesiredStock").'" /></td>';
    -		print '<td align="right"><input type="submit" value="'.$langs->trans('Save').'" class="button" /></td>';
    -		print '</tr>';
    -	}else{
    -		print '<tr class="liste_titre"><td width="40%">'.$langs->trans("Warehouse").'</td>';
    -		print '<td align="right">'.$langs->trans("StockLimit").'</td>';
    -		print '<td align="right">'.$langs->trans("DesiredStock").'</td>';
    +	print '<tr class="liste_titre">';
    +	print '<td colspan="4">' . $langs->trans("Warehouse") . '</td>';
    +	print '<td align="right">' . $langs->trans("NumberOfUnit") . '</td>';
    +	print '<td align="right">' . $langs->trans("AverageUnitPricePMPShort") . '</td>';
    +	print '<td align="right">' . $langs->trans("EstimatedStockValueShort") . '</td>';
    +	print '<td align="right">' . $langs->trans("SellPriceMin") . '</td>';
    +	print '<td align="right">' . $langs->trans("EstimatedStockValueSellShort") . '</td>';
    +	print '</tr>';
    +	if ((!empty($conf->productbatch->enabled)) && $object->hasbatch()) {
    +		print '<tr class="liste_titre"><td width="10%"></td>';
    +		print '<td align="right" width="10%">' . $langs->trans("batch_number") . '</td>';
    +		print '<td align="center" width="10%">' . $langs->trans("EatByDate") . '</td>';
    +		print '<td align="center" width="10%">' . $langs->trans("SellByDate") . '</td>';
    +		print '<td></td>';
    +		print '<td></td>';
    +		print '<td></td>';
    +		print '<td></td>';
    +		print '<td></td>';
     		print '</tr>';
     	}
     
    -	$pse = new ProductStockEntrepot($db);
    -	$lines = $pse->fetchAll($id);
    +	$sql = "SELECT e.rowid, e.ref as label, e.lieu, ps.reel, ps.rowid as product_stock_id, p.pmp";
    +	$sql .= " FROM " . MAIN_DB_PREFIX . "entrepot as e,";
    +	$sql .= " " . MAIN_DB_PREFIX . "product_stock as ps";
    +	$sql .= " LEFT JOIN " . MAIN_DB_PREFIX . "product as p ON p.rowid = ps.fk_product";
    +	$sql .= " WHERE ps.reel != 0";
    +	$sql .= " AND ps.fk_entrepot = e.rowid";
    +	$sql .= " AND e.entity IN (" . getEntity('stock') . ")";
    +	$sql .= " AND ps.fk_product = " . $object->id;
    +	$sql .= " ORDER BY e.ref";
     
    -	if (!empty($lines))
    -	{
    -		$var=false;
    -		foreach($lines as $line)
    -		{
    -			$ent = new Entrepot($db);
    -			$ent->fetch($line['fk_entrepot']);
    -			print '<tr class="oddeven"><td width="40%">'.$ent->getNomUrl(3).'</td>';
    -			print '<td align="right">'.$line['seuil_stock_alerte'].'</td>';
    -			print '<td align="right">'.$line['desiredstock'].'</td>';
    -			if (!empty($user->rights->produit->creer)){
    -			    print '<td align="right"><a href="?id='.$id.'&fk_productstockwarehouse='.$line['id'].'&action=delete_productstockwarehouse">'.img_delete().'</a></td>';
    +	$entrepotstatic = new Entrepot($db);
    +	$product_lot_static = new Productlot($db);
    +
    +	$total = 0;
    +	$totalvalue = $totalvaluesell = 0;
    +
    +	$resql = $db->query($sql);
    +	if ($resql) {
    +		$num = $db->num_rows($resql);
    +		$total = $totalwithpmp;
    +		$i = 0;
    +		$var = false;
    +		while ($i < $num) {
    +			$obj = $db->fetch_object($resql);
    +			$entrepotstatic->id = $obj->rowid;
    +			$entrepotstatic->libelle = $obj->label;
    +			$entrepotstatic->lieu = $obj->lieu;
    +			$stock_real = price2num($obj->reel, 'MS');
    +			print '<tr class="oddeven">';
    +			print '<td colspan="4">' . $entrepotstatic->getNomUrl(1) . '</td>';
    +			print '<td align="right">' . $stock_real . ($stock_real < 0 ? ' ' . img_warning() : '') . '</td>';
    +			// PMP
    +			print '<td align="right">' . (price2num($object->pmp) ? price2num($object->pmp, 'MU') : '') . '</td>';
    +			// Value purchase
    +			print '<td align="right">' . (price2num($object->pmp) ? price(price2num($object->pmp * $obj->reel, 'MT')) : '') . '</td>';
    +			// Sell price
    +			print '<td align="right">';
    +			if (empty($conf->global->PRODUIT_MULTIPRICES)) print price(price2num($object->price, 'MU'), 1);
    +			else print $langs->trans("Variable");
    +			print '</td>';
    +			// Value sell
    +			print '<td align="right">';
    +			if (empty($conf->global->PRODUIT_MULTIPRICES)) print price(price2num($object->price * $obj->reel, 'MT'), 1) . '</td>';
    +			else print $langs->trans("Variable");
    +			print '</tr>';;
    +			$total += $obj->reel;
    +			if (price2num($object->pmp)) $totalwithpmp += $obj->reel;
    +			$totalvalue = $totalvalue + ($object->pmp * $obj->reel);
    +			$totalvaluesell = $totalvaluesell + ($object->price * $obj->reel);
    +			// Batch Detail
    +			if ((!empty($conf->productbatch->enabled)) && $object->hasbatch()) {
    +				$details = Productbatch::findAll($db, $obj->product_stock_id, 0, $object->id);
    +				if ($details < 0) dol_print_error($db);
    +				foreach ($details as $pdluo) {
    +					$product_lot_static->id = $pdluo->lotid;
    +					$product_lot_static->batch = $pdluo->batch;
    +					$product_lot_static->eatby = $pdluo->eatby;
    +					$product_lot_static->sellby = $pdluo->sellby;
    +
    +					if ($action == 'editline' && GETPOST('lineid', 'int') == $pdluo->id) { //Current line edit
    +						print "\n" . '<tr>';
    +						print '<td colspan="9">';
    +						print '<form action="' . $_SERVER["PHP_SELF"] . '" method="POST">';
    +						print '<input type="hidden" name="pdluoid" value="' . $pdluo->id . '"><input type="hidden" name="action" value="updateline"><input type="hidden" name="id" value="' . $id . '"><table class="noborder" width="100%"><tr><td width="10%"></td>';
    +						print '<td align="right" width="10%"><input type="text" name="batch_number" value="' . $pdluo->batch . '"></td>';
    +						print '<td align="center" width="10%">';
    +						print $form->selectDate($pdluo->eatby, 'eatby', '', '', 1, '', 1, 0);
    +						print '</td>';
    +						print '<td align="center" width="10%">';
    +						print $form->selectDate($pdluo->sellby, 'sellby', '', '', 1, '', 1, 0);
    +						print '</td>';
    +						print '<td align="right" width="10%">' . $pdluo->qty . ($pdluo->qty < 0 ? ' ' . img_warning() : '') . '</td>';
    +						print '<td colspan="4"><input type="submit" class="button" id="savelinebutton" name="save" value="' . $langs->trans("Save") . '">';
    +						print '<input type="submit" class="button" id="cancellinebutton" name="Cancel" value="' . $langs->trans("Cancel") . '"></td></tr>';
    +						print '</table>';
    +						print '</form>';
    +						print '</td></tr>';
    +					} else {
    +						print "\n" . '<tr><td align="right">';
    +						print img_picto($langs->trans("Tranfer"), 'uparrow', 'class="hideonsmartphone"') . ' ';
    +						print '<a href="' . $_SERVER["PHP_SELF"] . '?id=' . $object->id . '&amp;id_entrepot=' . $entrepotstatic->id . '&amp;action=transfert&amp;pdluoid=' . $pdluo->id . '">' . $langs->trans("TransferStock") . '</a>';
    +						// Disabled, because edition of stock content must use the "Correct stock menu".
    +						// Do not use this, or data will be wrong (bad tracking of movement label, inventory code, ...
    +						//print '<a href="'.$_SERVER["PHP_SELF"].'?id='.$id.'&amp;action=editline&amp;lineid='.$pdluo->id.'#'.$pdluo->id.'">';
    +						//print img_edit().'</a></td>';
    +						print '<td align="right">';
    +						print $product_lot_static->getNomUrl(1);
    +						print '</td>';
    +						print '<td align="center">' . dol_print_date($pdluo->eatby, 'day') . '</td>';
    +						print '<td align="center">' . dol_print_date($pdluo->sellby, 'day') . '</td>';
    +						print '<td align="right">' . $pdluo->qty . ($pdluo->qty < 0 ? ' ' . img_warning() : '') . '</td>';
    +						print '<td colspan="4"></td></tr>';
    +					}
    +				}
     			}
    +			$i++;
    +
    +		}
    +	} else dol_print_error($db);
    +
    +	print '<tr class="liste_total"><td align="right" class="liste_total" colspan="4">' . $langs->trans("Total") . ':</td>';
    +	print '<td class="liste_total" align="right">' . price2num($total, 'MS') . '</td>';
    +	print '<td class="liste_total" align="right">';
    +	print ($totalwithpmp ? price(price2num($totalvalue / $totalwithpmp, 'MU')) : '&nbsp;');    // This value may have rounding errors
    +	print '</td>';
    +// Value purchase
    +	print '<td class="liste_total" align="right">';
    +	print $totalvalue ? price(price2num($totalvalue, 'MT'), 1) : '&nbsp;';
    +	print '</td>';
    +	print '<td class="liste_total" align="right">';
    +	if (empty($conf->global->PRODUIT_MULTIPRICES)) print ($total ? price($totalvaluesell / $total, 1) : '&nbsp;');
    +	else print $langs->trans("Variable");
    +	print '</td>';
    +// Value to sell
    +	print '<td class="liste_total" align="right">';
    +	if (empty($conf->global->PRODUIT_MULTIPRICES)) print price(price2num($totalvaluesell, 'MT'), 1);
    +	else print $langs->trans("Variable");
    +	print '</td>';
    +	print "</tr>";
    +	print "</table>";
    +	print '</div>';
    +
    +	if (!empty($conf->global->STOCK_ALLOW_ADD_LIMIT_STOCK_BY_WAREHOUSE)) {
    +		print '<br><br>';
    +		print_titre($langs->trans('AddNewProductStockWarehouse'));
    +
    +		if (!empty($user->rights->produit->creer)) {
    +			print '<form action="' . $_SERVER["PHP_SELF"] . '" method="POST">';
    +			print '<input type="hidden" name="action" value="addlimitstockwarehouse">';
    +			print '<input type="hidden" name="id" value="' . $id . '">';
    +		}
    +		print '<table class="noborder" width="100%">';
    +		if (!empty($user->rights->produit->creer)) {
    +			print '<tr class="liste_titre"><td width="40%">' . $formproduct->selectWarehouses('', 'fk_entrepot') . '</td>';
    +			print '<td align="right"><input name="seuil_stock_alerte" type="text" placeholder="' . $langs->trans("StockLimit") . '" /></td>';
    +			print '<td align="right"><input name="desiredstock" type="text" placeholder="' . $langs->trans("DesiredStock") . '" /></td>';
    +			print '<td align="right"><input type="submit" value="' . $langs->trans('Save') . '" class="button" /></td>';
    +			print '</tr>';
    +		} else {
    +			print '<tr class="liste_titre"><td width="40%">' . $langs->trans("Warehouse") . '</td>';
    +			print '<td align="right">' . $langs->trans("StockLimit") . '</td>';
    +			print '<td align="right">' . $langs->trans("DesiredStock") . '</td>';
     			print '</tr>';
     		}
    -	}
     
    -	print "</table>";
    +		$pse = new ProductStockEntrepot($db);
    +		$lines = $pse->fetchAll($id);
     
    -	if (!empty($user->rights->produit->creer)){
    -	    print '</form>';
    +		if (!empty($lines)) {
    +			$var = false;
    +			foreach ($lines as $line) {
    +				$ent = new Entrepot($db);
    +				$ent->fetch($line['fk_entrepot']);
    +				print '<tr class="oddeven"><td width="40%">' . $ent->getNomUrl(3) . '</td>';
    +				print '<td align="right">' . $line['seuil_stock_alerte'] . '</td>';
    +				print '<td align="right">' . $line['desiredstock'] . '</td>';
    +				if (!empty($user->rights->produit->creer)) {
    +					print '<td align="right"><a href="?id=' . $id . '&fk_productstockwarehouse=' . $line['id'] . '&action=delete_productstockwarehouse">' . img_delete() . '</a></td>';
    +				}
    +				print '</tr>';
    +			}
    +		}
    +
    +		print "</table>";
    +
    +		if (!empty($user->rights->produit->creer)) {
    +			print '</form>';
    +		}
     	}
    +} else {
    +	// List of variants
    +
    +	$prodstatic = new Product($db);
    +	$prodcomb = new ProductCombination($db);
    +	$comb2val = new ProductCombination2ValuePair($db);
    +	$productCombinations = $prodcomb->fetchAllByFkProductParent($object->id);
    +
    +	print '<form method="POST" action="'.$_SERVER["PHP_SELF"].'">';
    +	print '<input type="hidden" name="token" value="'.$_SESSION['newtoken'].'">';
    +	print '<input type="hidden" name="action" value="massaction">';
    +	print '<input type="hidden" name="id" value="'.$id.'">';
    +	print '<input type="hidden" name="backtopage" value="'.$backtopage.'">';
    +
    +	// load variants
    +	$title = $langs->trans("ProductCombinations");
    +
    +	print_barre_liste($title, 0, $_SERVER["PHP_SELF"], '', $sortfield, $sortorder, '', 0);
    +
    +	print '<div class="div-table-responsive">';
    +	?>
    +	<table class="liste">
    +		<tr class="liste_titre">
    +			<td class="liste_titre"><?php echo $langs->trans('Product') ?></td>
    +			<td class="liste_titre"><?php echo $langs->trans('Combination') ?></td>
    +			<td class="liste_titre center"><?php echo $langs->trans('OnSell') ?></td>
    +			<td class="liste_titre center"><?php echo $langs->trans('OnBuy') ?></td>
    +			<td class="liste_titre right"><?php echo $langs->trans('Stock') ?></td>
    +			<td class="liste_titre"></td>
    +		</tr>
    +		<?php
    +
    +		if (count($productCombinations))
    +		{
    +			$stock_total= 0;
    +			foreach ($productCombinations as $currcomb)
    +			{
    +				$prodstatic->fetch($currcomb->fk_product_child);
    +				$prodstatic->load_stock();
    +				$stock_total+=$prodstatic->stock_reel;
    +				?>
    +				<tr class="oddeven">
    +					<td><?php echo $prodstatic->getNomUrl(1) ?></td>
    +					<td>
    +						<?php
    +
    +						$productCombination2ValuePairs = $comb2val->fetchByFkCombination($currcomb->id);
    +						$iMax = count($productCombination2ValuePairs);
    +
    +						for ($i = 0; $i < $iMax; $i++) {
    +							echo dol_htmlentities($productCombination2ValuePairs[$i]);
    +
    +							if ($i !== ($iMax - 1)) {
    +								echo ', ';
    +							}
    +						} ?>
    +					</td>
    +					<td style="text-align: center;"><?php echo $prodstatic->getLibStatut(2, 0) ?></td>
    +					<td style="text-align: center;"><?php echo $prodstatic->getLibStatut(2, 1) ?></td>
    +					<td class="right"><?php echo $prodstatic->stock_reel ?></td>
    +					<td class="right">
    +						<a class="paddingleft paddingright" href="<?php echo dol_buildpath('/product/stock/product.php?id='.$currcomb->fk_product_child, 2) ?>"><?php echo img_edit() ?></a>
    +					</td>
    +					<?php
    +					?>
    +				</tr>
    +				<?php
    +			}
    +
    +			print '<tr class="liste_total">';
    +			print '<td colspan="4" align="left">'.$langs->trans("Total").'</td>';
    +			print '<td align="right">'.$stock_total.'</td>';
    +			print '</tr>';
    +		}
    +		else
    +		{
    +			print '<tr><td colspan="8"><span class="opacitymedium">'.$langs->trans("None").'</span></td></tr>';
    +		}
    +		?>
    +	</table>
    +
    +	<?php
    +	print '</div>';
    +
    +	print '</form>';
     }
     
     // End of page
    diff --git a/htdocs/product/stock/productlot_card.php b/htdocs/product/stock/productlot_card.php
    index 334ab91ebc4..5ee52ce337a 100644
    --- a/htdocs/product/stock/productlot_card.php
    +++ b/htdocs/product/stock/productlot_card.php
    @@ -388,8 +388,9 @@ if ($object->id > 0 && (empty($action) || ($action != 'edit' && $action != 'crea
     
     	print '<a href="'.DOL_URL_ROOT.'/product/reassortlot.php?sref='.urlencode($producttmp->ref).'&search_batch='.urlencode($object->batch).'">'.$langs->trans("ShowCurrentStockOfLot").'</a><br>';
     	print '<br>';
    -	print '<a href="'.DOL_URL_ROOT.'/product/stock/mouvement.php?search_product_ref='.urlencode($producttmp->ref).'&search_batch='.urlencode($object->batch).'">'.$langs->trans("ShowLogOfMovementIfLot").'</a><br>';
    +	print '<a href="'.DOL_URL_ROOT.'/product/stock/movement_list.php?search_product_ref='.urlencode($producttmp->ref).'&search_batch='.urlencode($object->batch).'">'.$langs->trans("ShowLogOfMovementIfLot").'</a><br>';
     
    +	print '<br>';
     }
     
     
    diff --git a/htdocs/product/stock/productlot_list.php b/htdocs/product/stock/productlot_list.php
    index 912720c747b..4d9916bfa9c 100644
    --- a/htdocs/product/stock/productlot_list.php
    +++ b/htdocs/product/stock/productlot_list.php
    @@ -38,6 +38,7 @@ $id			= GETPOST('id','int');
     $action		= GETPOST('action','alpha');
     $backtopage = GETPOST('backtopage','alpha');
     $myparam	= GETPOST('myparam','alpha');
    +$toselect = GETPOST('toselect', 'array');
     
     
     $search_entity=GETPOST('search_entity','int');
    @@ -143,7 +144,7 @@ if (GETPOST('button_removefilter_x','alpha') || GETPOST('button_removefilter.x',
     	$search_import_key='';
     	$search_date_creation='';
     	$search_date_update='';
    -	$toselect='';
    +	$toselect=array();
     	$search_array_options=array();
     }
     
    @@ -207,7 +208,8 @@ $sql.= " t.fk_user_modif,";
     $sql.= " t.import_key,";
     $sql.= " p.fk_product_type as product_type,";
     $sql.= " p.ref as product_ref,";
    -$sql.= " p.label as product_label";
    +$sql.= " p.label as product_label,";
    +$sql.= " p.tobatch";
     // Add fields for extrafields
     foreach ($extrafields->attribute_list as $key => $val) $sql.=",ef.".$key.' as options_'.$key;
     // Add fields from hooks
    @@ -424,6 +426,7 @@ if ($resql)
     				$productstatic->type=$obj->product_type;
     				$productstatic->ref=$obj->product_ref;
     				$productstatic->label=$obj->product_label;
    +				$productstatic->status_batch = $obj->tobatch;
     				print '<td>'.$productstatic->getNomUrl(1).'</td>';
     				if (! $i) $totalarray['nbfield']++;
     			}
    diff --git a/htdocs/projet/card.php b/htdocs/projet/card.php
    index dd18a115ab6..e2632fe244e 100644
    --- a/htdocs/projet/card.php
    +++ b/htdocs/projet/card.php
    @@ -765,7 +765,7 @@ elseif ($object->id > 0)
     
     		// Label
     		print '<tr><td class="fieldrequired">'.$langs->trans("Label").'</td>';
    -		print '<td><input class="quatrevingtpercent" name="title" value="'.$object->title.'"></td></tr>';
    +		print '<td><input class="quatrevingtpercent" name="title" value="'.dol_escape_htmltag($object->title).'"></td></tr>';
     
     		// Status
     		print '<tr><td class="fieldrequired">'.$langs->trans("Status").'</td><td>';
    diff --git a/htdocs/projet/class/project.class.php b/htdocs/projet/class/project.class.php
    index 9af52721787..eaf1ad6ea67 100644
    --- a/htdocs/projet/class/project.class.php
    +++ b/htdocs/projet/class/project.class.php
    @@ -53,7 +53,12 @@ class Project extends CommonObject
     	 */
     	public $fk_element = 'fk_projet';
     
    -    public $ismultientitymanaged = 1;  // 0=No test on entity, 1=Test with field entity, 2=Test with link by societe
    +	/**
    +	 * 0=No test on entity, 1=Test with field entity, 2=Test with link by societe
    +	 * @var int
    +	 */
    +    public $ismultientitymanaged = 1;
    +
         public $picto = 'projectpub';
     
         /**
    @@ -657,9 +662,10 @@ class Project extends CommonObject
     
             // Set fk_projet into elements to null
             $listoftables=array(
    -        		'facture'=>'fk_projet','propal'=>'fk_projet','commande'=>'fk_projet',
    -                'facture_fourn'=>'fk_projet','commande_fournisseur'=>'fk_projet','supplier_proposal'=>'fk_projet',
    -        		'expensereport_det'=>'fk_projet','contrat'=>'fk_projet','fichinter'=>'fk_projet','don'=>'fk_projet'
    +        		'propal'=>'fk_projet', 'commande'=>'fk_projet', 'facture'=>'fk_projet',
    +        		'supplier_proposal'=>'fk_projet', 'commande_fournisseur'=>'fk_projet', 'facture_fourn'=>'fk_projet',
    +        		'expensereport_det'=>'fk_projet', 'contrat'=>'fk_projet', 'fichinter'=>'fk_projet', 'don'=>'fk_projet',
    +        		'actioncomm'=>'fk_project'
             		);
             foreach($listoftables as $key => $value)
             {
    diff --git a/htdocs/projet/class/task.class.php b/htdocs/projet/class/task.class.php
    index a3fd5fb1703..a4ef7965851 100644
    --- a/htdocs/projet/class/task.class.php
    +++ b/htdocs/projet/class/task.class.php
    @@ -2,6 +2,7 @@
     /* Copyright (C) 2008-2014	Laurent Destailleur	<eldy@users.sourceforge.net>
      * Copyright (C) 2010-2012	Regis Houssin		<regis.houssin@capnetworks.com>
      * Copyright (C) 2014       Marcos García       <marcosgdf@gmail.com>
    + * Copyright (C) 2018       Frédéric France     <frederic.france@netlogic.fr>
      *
      * This program is free software; you can redistribute it and/or modify
      * it under the terms of the GNU General Public License as published by
    @@ -49,6 +50,9 @@ class Task extends CommonObject
     	public $picto = 'task';
     	protected $childtables=array('projet_task_time');    // To test if we can delete object
     
    +	/**
    +     * @var int ID parent task
    +     */
         public $fk_task_parent;
     
         /**
    @@ -67,10 +71,24 @@ class Task extends CommonObject
     	public $date_start;
     	public $date_end;
     	public $progress;
    +
    +	/**
    +     * @var int ID
    +     */
     	public $fk_statut;
    +
     	public $priority;
    +
    +	/**
    +     * @var int ID
    +     */
     	public $fk_user_creat;
    +
    +	/**
    +     * @var int ID
    +     */
     	public $fk_user_valid;
    +
     	public $rang;
     
     	public $timespent_min_date;
    @@ -323,7 +341,7 @@ class Task extends CommonObject
     		// Clean parameters
     		if (isset($this->fk_project)) $this->fk_project=trim($this->fk_project);
     		if (isset($this->ref)) $this->ref=trim($this->ref);
    -		if (isset($this->fk_task_parent)) $this->fk_task_parent=trim($this->fk_task_parent);
    +		if (isset($this->fk_task_parent)) $this->fk_task_parent = (int) $this->fk_task_parent;
     		if (isset($this->label)) $this->label=trim($this->label);
     		if (isset($this->description)) $this->description=trim($this->description);
     		if (isset($this->duration_effective)) $this->duration_effective=trim($this->duration_effective);
    @@ -688,12 +706,12 @@ class Task extends CommonObject
     
     		$this->fk_projet='';
     		$this->ref='TK01';
    -		$this->fk_task_parent='';
    +		$this->fk_task_parent=null;
     		$this->label='Specimen task TK01';
     		$this->duration_effective='';
    -		$this->fk_user_creat='';
    +		$this->fk_user_creat=null;
     		$this->progress='25';
    -		$this->fk_statut='';
    +		$this->fk_statut=null;
     		$this->note='This is a specimen task not';
     	}
     
    @@ -1982,4 +2000,4 @@ class Task extends CommonObject
     
     		return ($datetouse > 0 && ($datetouse < ($now - $conf->projet->task->warning_delay)));
     	}
    -}
    \ No newline at end of file
    +}
    diff --git a/htdocs/projet/element.php b/htdocs/projet/element.php
    index 1da887ea7a9..489c5d04be4 100644
    --- a/htdocs/projet/element.php
    +++ b/htdocs/projet/element.php
    @@ -618,6 +618,10 @@ foreach ($listofreferent as $key => $value)
     				{
     					if (! empty($element->close_code) && $element->close_code == 'replaced') $qualifiedfortotal=false;	// Replacement invoice, do not include into total
     				}
    +				if ($key == 'propal')
    +				{
    +					if ($element->statut == Propal::STATUS_NOTSIGNED) $qualifiedfortotal=false;	// Refused proposal must not be included in total
    +				}
     
     				if ($qualifiedfortotal) $total_ht = $total_ht + $total_ht_by_line;
     
    diff --git a/htdocs/public/payment/newpayment.php b/htdocs/public/payment/newpayment.php
    index 0eff61cd9fa..47cdc8bb31e 100644
    --- a/htdocs/public/payment/newpayment.php
    +++ b/htdocs/public/payment/newpayment.php
    @@ -413,12 +413,12 @@ if ($action == 'charge' && ! empty($conf->stripe->enabled))
     	$dol_type=(GETPOST('s', 'alpha') ? GETPOST('s', 'alpha') : GETPOST('source', 'alpha'));
       	$dol_id=GETPOST('dol_id', 'int');
       	$vatnumber = GETPOST('vatnumber','alpha');
    -	$savesource=GETPOST('savesource', 'int');
    +	$savesource=GETPOSTISSET('savesource')?GETPOST('savesource', 'int'):1;
     
    -	dol_syslog("stripeToken = ".$stripeToken, LOG_DEBUG, 0, '_stripe');
    -	dol_syslog("email = ".$email, LOG_DEBUG, 0, '_stripe');
    -	dol_syslog("thirdparty_id = ".$thirdparty_id, LOG_DEBUG, 0, '_stripe');
    -	dol_syslog("vatnumber = ".$vatnumber, LOG_DEBUG, 0, '_stripe');
    +	dol_syslog("POST stripeToken = ".$stripeToken, LOG_DEBUG, 0, '_stripe');
    +	dol_syslog("POST email = ".$email, LOG_DEBUG, 0, '_stripe');
    +	dol_syslog("POST thirdparty_id = ".$thirdparty_id, LOG_DEBUG, 0, '_stripe');
    +	dol_syslog("POST vatnumber = ".$vatnumber, LOG_DEBUG, 0, '_stripe');
     
     	$error = 0;
     
    @@ -444,7 +444,6 @@ if ($action == 'charge' && ! empty($conf->stripe->enabled))
     				$servicestatus = 1;
     			}
     
    -
     			$thirdparty = new Societe($db);
     			$thirdparty->fetch($thirdparty_id);
     
    @@ -455,9 +454,11 @@ if ($action == 'charge' && ! empty($conf->stripe->enabled))
     			$customer = $stripe->customerStripe($thirdparty, $stripeacc, $servicestatus, 1);
     
     			// Create Stripe card from Token
    -			if (! empty($savesource)) {
    -			$card = $customer->sources->create(array("source" => $stripeToken, "metadata" => $metadata));
    -			} else { $card = $stripeToken; }
    +			if ($savesource) {
    +				$card = $customer->sources->create(array("source" => $stripeToken, "metadata" => $metadata));
    +			} else {
    +				$card = $stripeToken;
    +			}
     
     			if (empty($card))
     			{
    @@ -468,21 +469,21 @@ if ($action == 'charge' && ! empty($conf->stripe->enabled))
     			}
     			else
     			{
    -        if (! empty($FULLTAG))       $metadata["FULLTAG"] = $FULLTAG;
    -        if (! empty($dol_id))        $metadata["dol_id"] = $dol_id;
    -        if (! empty($dol_type))      $metadata["dol_type"] = $dol_type;
    +				if (! empty($FULLTAG))       $metadata["FULLTAG"] = $FULLTAG;
    +				if (! empty($dol_id))        $metadata["dol_id"] = $dol_id;
    +				if (! empty($dol_type))      $metadata["dol_type"] = $dol_type;
     
     				dol_syslog("Create charge on card ".$card->id, LOG_DEBUG, 0, '_stripe');
     				$charge = \Stripe\Charge::create(array(
     					'amount'   => price2num($amountstripe, 'MU'),
     					'currency' => $currency,
     					'capture'  => true,							// Charge immediatly
    -					'description' => 'Stripe payment: '.$FULLTAG,
    +					'description' => 'Stripe payment: '.$FULLTAG.' ref='.$ref,
     					'metadata' => $metadata,
     					'customer' => $customer->id,
     					'source' => $card,
     					'statement_descriptor' => dol_trunc(dol_trunc(dol_string_unaccent($mysoc->name), 6, 'right', 'UTF-8', 1).' '.$FULLTAG, 22, 'right', 'UTF-8', 1)     // 22 chars that appears on bank receipt
    -				),array("idempotency_key" => "$ref","stripe_account" => "$stripeacc"));
    +				),array("idempotency_key" => "$ref", "stripe_account" => "$stripeacc"));
     				// Return $charge = array('id'=>'ch_XXXX', 'status'=>'succeeded|pending|failed', 'failure_code'=>, 'failure_message'=>...)
     				if (empty($charge))
     				{
    @@ -495,19 +496,29 @@ if ($action == 'charge' && ! empty($conf->stripe->enabled))
     		}
     		else
     		{
    +			$vatcleaned = $vatnumber ? $vatnumber : null;
    +
    +			$taxinfo = array('type'=>'vat');
    +			if ($vatcleaned)
    +			{
    +				$taxinfo["tax_id"] = $vatcleaned;
    +			}
    +			// We force data to "null" if not defined as expected by Stripe
    +			if (empty($vatcleaned)) $taxinfo=null;
    +
     			dol_syslog("Create anonymous customer card profile", LOG_DEBUG, 0, '_stripe');
     			$customer = \Stripe\Customer::create(array(
     				'email' => $email,
     				'description' => ($email?'Anonymous customer for '.$email:'Anonymous customer'),
     				'metadata' => $metadata,
    -				'business_vat_id' => ($vatnumber?$vatnumber:null),
    +				'tax_info' => $taxinfo,
     				'source'  => $stripeToken           // source can be a token OR array('object'=>'card', 'exp_month'=>xx, 'exp_year'=>xxxx, 'number'=>xxxxxxx, 'cvc'=>xxx, 'name'=>'Cardholder's full name', zip ?)
     			));
     			// Return $customer = array('id'=>'cus_XXXX', ...)
     
    -        if (! empty($FULLTAG))       $metadata["FULLTAG"] = $FULLTAG;
    -        if (! empty($dol_id))        $metadata["dol_id"] = $dol_id;
    -        if (! empty($dol_type))      $metadata["dol_type"] = $dol_type;
    +			if (! empty($FULLTAG))       $metadata["FULLTAG"] = $FULLTAG;
    +			if (! empty($dol_id))        $metadata["dol_id"] = $dol_id;
    +			if (! empty($dol_type))      $metadata["dol_type"] = $dol_type;
     
     			// The customer was just created with a source, so we can make a charge
     			// with no card defined, the source just used for customer creation will be used.
    @@ -517,10 +528,10 @@ if ($action == 'charge' && ! empty($conf->stripe->enabled))
     				'amount'   => price2num($amountstripe, 'MU'),
     				'currency' => $currency,
     				'capture'  => true,							// Charge immediatly
    -				'description' => 'Stripe payment: '.$FULLTAG,
    +				'description' => 'Stripe payment: '.$FULLTAG.' ref='.$ref,
     				'metadata' => $metadata,
     				'statement_descriptor' => dol_trunc(dol_trunc(dol_string_unaccent($mysoc->name), 6, 'right', 'UTF-8', 1).' '.$FULLTAG, 22, 'right', 'UTF-8', 1)     // 22 chars that appears on bank receipt
    -			),array("idempotency_key" => "$ref","stripe_account" => "$stripeacc"));
    +			),array("idempotency_key" => "$ref", "stripe_account" => "$stripeacc"));
     			// Return $charge = array('id'=>'ch_XXXX', 'status'=>'succeeded|pending|failed', 'failure_code'=>, 'failure_message'=>...)
     			if (empty($charge))
     			{
    @@ -813,7 +824,7 @@ if ($source == 'order')
     		$amount=price2num($amount);
     	}
     
    -	$fulltag='ORD='.$order->ref.'.CUS='.$order->thirdparty->id;
    +	$fulltag='ORD='.$order->id.'.CUS='.$order->thirdparty->id;
     	//$fulltag.='.NAM='.strtr($order->thirdparty->name,"-"," ");
     	if (! empty($TAG)) { $tag=$TAG; $fulltag.='.TAG='.$TAG; }
     	$fulltag=dol_string_unaccent($fulltag);
    @@ -933,7 +944,7 @@ if ($source == 'invoice')
     		$amount=price2num($amount);
     	}
     
    -	$fulltag='INV='.$invoice->ref.'.CUS='.$invoice->thirdparty->id;
    +	$fulltag='INV='.$invoice->id.'.CUS='.$invoice->thirdparty->id;
     	//$fulltag.='.NAM='.strtr($invoice->thirdparty->name,"-"," ");
     	if (! empty($TAG)) { $tag=$TAG; $fulltag.='.TAG='.$TAG; }
     	$fulltag=dol_string_unaccent($fulltag);
    @@ -1115,7 +1126,7 @@ if ($source == 'contractline')
     		$amount=price2num($amount);
     	}
     
    -	$fulltag='COL='.$contractline->ref.'.CON='.$contract->ref.'.CUS='.$contract->thirdparty->id.'.DAT='.dol_print_date(dol_now(),'%Y%m%d%H%M');
    +	$fulltag='COL='.$contractline->id.'.CON='.$contract->id.'.CUS='.$contract->thirdparty->id.'.DAT='.dol_print_date(dol_now(),'%Y%m%d%H%M');
     	//$fulltag.='.NAM='.strtr($contract->thirdparty->name,"-"," ");
     	if (! empty($TAG)) { $tag=$TAG; $fulltag.='.TAG='.$TAG; }
     	$fulltag=dol_string_unaccent($fulltag);
    @@ -1429,7 +1440,7 @@ if ($action != 'dopayment')
     	{
     		if ($source == 'invoice' && $object->paye)
     		{
    -			print '<br><br>'.$langs->trans("InvoicePaid");
    +			print '<br><br><span class="amountpaymentcomplete">'.$langs->trans("InvoicePaid").'</span>';
     		}
     		else
     		{
    diff --git a/htdocs/public/payment/paymentok.php b/htdocs/public/payment/paymentok.php
    index 9f6ebaf99b6..36723658946 100644
    --- a/htdocs/public/payment/paymentok.php
    +++ b/htdocs/public/payment/paymentok.php
    @@ -313,7 +313,7 @@ if ($ispaymentok)
     		$adht = new AdherentType($db);
     		$object = new Adherent($db);
     
    -		$result1 = $object->fetch(0, $tmptag['MEM']);
    +		$result1 = $object->fetch($tmptag['MEM']);
     		$result2 = $adht->fetch($object->typeid);
     
     		if ($result1 > 0 && $result2 > 0)
    @@ -588,7 +588,7 @@ if ($ispaymentok)
     		// Record payment
     		include_once DOL_DOCUMENT_ROOT.'/compta/facture/class/facture.class.php';
     		$invoice = new Facture($db);
    -		$result = $invoice->fetch(0, $tmptag['INV']);
    +		$result = $invoice->fetch($tmptag['INV']);
     		if ($result)
     		{
     			$FinalPaymentAmt    = $_SESSION["FinalPaymentAmt"];
    @@ -629,7 +629,9 @@ if ($ispaymentok)
     				}
     				$paiement->paiementid   = $paymentTypeId;
     				$paiement->num_paiement = '';
    -				$paiement->note_public  = 'Online payment '.dol_print_date($now, 'standard').' using '.$paymentmethod.' from '.$ipaddress.' - Transaction ID = '.$TRANSACTIONID;
    +				$paiement->note_public  = 'Online payment '.dol_print_date($now, 'standard').' from '.$ipaddress;
    +				$paiement->ext_payment_id = $TRANSACTIONID;
    +				$paiement->ext_payment_site = $paymentmethod;
     
     				if (! $error)
     				{
    @@ -651,8 +653,8 @@ if ($ispaymentok)
     				{
     					$bankaccountid = 0;
     					if ($paymentmethod == 'paybox') $bankaccountid = $conf->global->PAYBOX_BANK_ACCOUNT_FOR_PAYMENTS;
    -					if ($paymentmethod == 'paypal') $bankaccountid = $conf->global->PAYPAL_BANK_ACCOUNT_FOR_PAYMENTS;
    -					if ($paymentmethod == 'stripe') $bankaccountid = $conf->global->STRIPE_BANK_ACCOUNT_FOR_PAYMENTS;
    +					elseif ($paymentmethod == 'paypal') $bankaccountid = $conf->global->PAYPAL_BANK_ACCOUNT_FOR_PAYMENTS;
    +					elseif ($paymentmethod == 'stripe') $bankaccountid = $conf->global->STRIPE_BANK_ACCOUNT_FOR_PAYMENTS;
     
     					if ($bankaccountid > 0)
     					{
    @@ -776,9 +778,9 @@ if ($ispaymentok)
     		}
     		elseif (in_array('INV', array_keys($tmptag)))
     		{
    -			$url=$urlwithroot."/compta/facture/card.php?ref=".$tmptag['INV'];
    +			$url=$urlwithroot."/compta/facture/card.php?id=".$tmptag['INV'];
     			$content.='<strong>'.$companylangs->trans("Payment")."</strong><br><br>\n";
    -			$content.=$companylangs->trans("Invoice").': <strong>'.$tmptag['INV']."</strong><br>\n";
    +			$content.=$companylangs->trans("InvoiceId").': <strong>'.$tmptag['INV']."</strong><br>\n";
     			//$content.=$companylangs->trans("ThirdPartyId").': '.$tmptag['CUS']."<br>\n";
     			$content.=$companylangs->trans("Link").': <a href="'.$url.'">'.$url.'</a>'."<br>\n";
     		}
    @@ -871,8 +873,8 @@ else
         if (! empty($conf->global->PAYMENTONLINE_SENDEMAIL)) $sendemail=$conf->global->PAYMENTONLINE_SENDEMAIL;
         // TODO Remove local option to keep only the generic one ?
         if ($paymentmethod == 'paypal' && ! empty($conf->global->PAYPAL_PAYONLINE_SENDEMAIL)) $sendemail=$conf->global->PAYPAL_PAYONLINE_SENDEMAIL;
    -    if ($paymentmethod == 'paybox' && ! empty($conf->global->PAYBOX_PAYONLINE_SENDEMAIL)) $sendemail=$conf->global->PAYBOX_PAYONLINE_SENDEMAIL;
    -    if ($paymentmethod == 'stripe' && ! empty($conf->global->STRIPE_PAYONLINE_SENDEMAIL)) $sendemail=$conf->global->STRIPE_PAYONLINE_SENDEMAIL;
    +    elseif ($paymentmethod == 'paybox' && ! empty($conf->global->PAYBOX_PAYONLINE_SENDEMAIL)) $sendemail=$conf->global->PAYBOX_PAYONLINE_SENDEMAIL;
    +    elseif ($paymentmethod == 'stripe' && ! empty($conf->global->STRIPE_PAYONLINE_SENDEMAIL)) $sendemail=$conf->global->STRIPE_PAYONLINE_SENDEMAIL;
     
         // Send an email
         if ($sendemail)
    diff --git a/htdocs/public/ticket/view.php b/htdocs/public/ticket/view.php
    index b2bb0100d6d..b5288b97a25 100644
    --- a/htdocs/public/ticket/view.php
    +++ b/htdocs/public/ticket/view.php
    @@ -1,5 +1,6 @@
     <?php
    -/*  Copyright (C) - 2013-2016    Jean-François FERRY    <hello@librethic.io>
    +/* Copyright (C) 2013-2016  Jean-François FERRY     <hello@librethic.io>
    + * Copyright (C) 2018       Frédéric France         <frederic.france@netlogic.fr>
      *
      * This program is free software; you can redistribute it and/or modify
      * it under the terms of the GNU General Public License as published by
    @@ -145,10 +146,7 @@ if ($action == "view_ticket" || $action == "add_message" || $action == "close" |
         if ($display_ticket) {
             // Confirmation close
             if ($action == 'close') {
    -            $ret = $form->form_confirm($_SERVER["PHP_SELF"] . "?track_id=" . $track_id, $langs->trans("CloseATicket"), $langs->trans("ConfirmCloseAticket"), "confirm_public_close", '', '', 1);
    -            if ($ret == 'html') {
    -                print '<br>';
    -            }
    +            print $form->form_confirm($_SERVER["PHP_SELF"] . "?track_id=" . $track_id, $langs->trans("CloseATicket"), $langs->trans("ConfirmCloseAticket"), "confirm_public_close", '', '', 1);
             }
     
             print '<div id="form_view_ticket">';
    diff --git a/htdocs/public/website/index.php b/htdocs/public/website/index.php
    index 862d8ada71a..19abc48094b 100644
    --- a/htdocs/public/website/index.php
    +++ b/htdocs/public/website/index.php
    @@ -18,8 +18,7 @@
     /**
      *     	\file       htdocs/public/website/index.php
      *		\ingroup    website
    - *		\brief      Page to output pages
    - *		\author	    Laurent Destailleur
    + *		\brief      Wrapper to output pages when website is powered by Dolibarr instead of a native web server
      */
     
     if (! defined('NOTOKENRENEWAL')) define('NOTOKENRENEWAL',1); // Disables token renewal
    @@ -59,88 +58,91 @@ $accessallowed = 1;
     $type='';
     
     
    -/*
    - * View
    - */
    +if (empty($pageid))
    +{
    +	require_once DOL_DOCUMENT_ROOT.'/website/class/website.class.php';
    +	require_once DOL_DOCUMENT_ROOT.'/website/class/websitepage.class.php';
    +
    +	$object=new Website($db);
    +	$object->fetch(0, $websitekey);
    +
    +	if (empty($object->id))
    +	{
    +		if (empty($pageid))
    +		{
    +			// Return header 404
    +			header($_SERVER["SERVER_PROTOCOL"]." 404 Not Found", true, 404);
    +
    +			include DOL_DOCUMENT_ROOT.'/public/error-404.php';
    +			exit;
    +		}
    +	}
    +
    +	$objectpage=new WebsitePage($db);
    +
    +	if ($pageref)
    +	{
    +		$result=$objectpage->fetch(0, $object->id, $pageref);
    +		if ($result > 0)
    +		{
    +			$pageid = $objectpage->id;
    +		}
    +		elseif($result == 0)
    +		{
    +			// Page not found from ref=pageurl, we try using alternative alias
    +			$result=$objectpage->fetch(0, $object->id, null, $pageref);
    +			if ($result > 0)
    +			{
    +				$pageid = $objectpage->id;
    +			}
    +		}
    +	}
    +	else
    +	{
    +		if ($object->fk_default_home > 0)
    +		{
    +			$result=$objectpage->fetch($object->fk_default_home);
    +			if ($result > 0)
    +			{
    +				$pageid = $objectpage->id;
    +			}
    +		}
    +
    +		if (empty($pageid))
    +		{
    +			$array=$objectpage->fetchAll($object->id);
    +			if (is_array($array) && count($array) > 0)
    +			{
    +				$firstrep=reset($array);
    +				$pageid=$firstrep->id;
    +			}
    +		}
    +	}
    +}
    +if (empty($pageid))
    +{
    +	// Return header 404
    +	header($_SERVER["SERVER_PROTOCOL"]." 404 Not Found", true, 404);
    +
    +	$langs->load("website");
    +
    +	if (! GETPOSTISSET('pageref')) print $langs->trans("PreviewOfSiteNotYetAvailable", $websitekey);
    +
    +	include DOL_DOCUMENT_ROOT.'/public/error-404.php';
    +	exit;
    +}
     
     $appli=constant('DOL_APPLICATION_TITLE');
     if (!empty($conf->global->MAIN_APPLICATION_TITLE)) $appli=$conf->global->MAIN_APPLICATION_TITLE;
     
    +
    +
    +/*
    + * View
    + */
    +
     //print 'Directory with '.$appli.' websites.<br>';
     
    -if (empty($pageid))
    -{
    -    require_once DOL_DOCUMENT_ROOT.'/website/class/website.class.php';
    -    require_once DOL_DOCUMENT_ROOT.'/website/class/websitepage.class.php';
    -
    -    $object=new Website($db);
    -    $object->fetch(0, $websitekey);
    -
    -	if (empty($object->id))
    -    {
    -        if (empty($pageid))
    -        {
    -            // Return header 404
    -            header($_SERVER["SERVER_PROTOCOL"]." 404 Not Found", true, 404);
    -
    -            include DOL_DOCUMENT_ROOT.'/public/error-404.php';
    -            exit;
    -        }
    -    }
    -
    -    $objectpage=new WebsitePage($db);
    -
    -    if ($pageref)
    -    {
    -    	$result=$objectpage->fetch(0, $object->id, $pageref);
    -    	if ($result > 0)
    -	    {
    -	        $pageid = $objectpage->id;
    -	    }
    -	    elseif($result == 0)
    -	    {
    -	    	// Page not found from ref=pageurl, we try using alternative alias
    -	    	$result=$objectpage->fetch(0, $object->id, null, $pageref);
    -	    	if ($result > 0)
    -	    	{
    -	    		$pageid = $objectpage->id;
    -	    	}
    -	    }
    -    }
    -    else
    -    {
    -	    if ($object->fk_default_home > 0)
    -	    {
    -	        $result=$objectpage->fetch($object->fk_default_home);
    -	        if ($result > 0)
    -	        {
    -	            $pageid = $objectpage->id;
    -	        }
    -	    }
    -
    -	    if (empty($pageid))
    -	    {
    -	        $array=$objectpage->fetchAll($object->id);
    -	        if (is_array($array) && count($array) > 0)
    -	        {
    -	            $firstrep=reset($array);
    -	            $pageid=$firstrep->id;
    -	        }
    -	    }
    -    }
    -}
    -if (empty($pageid))
    -{
    -    // Return header 404
    -    header($_SERVER["SERVER_PROTOCOL"]." 404 Not Found", true, 404);
    -
    -    $langs->load("website");
    -
    -    if (! GETPOSTISSET('pageref')) print $langs->trans("PreviewOfSiteNotYetAvailable", $websitekey);
    -
    -    include DOL_DOCUMENT_ROOT.'/public/error-404.php';
    -    exit;
    -}
     
     // Security: Delete string ../ into $original_file
     global $dolibarr_main_data_root;
    diff --git a/htdocs/resource/class/dolresource.class.php b/htdocs/resource/class/dolresource.class.php
    index 1c04a5633ec..c6e25c4d837 100644
    --- a/htdocs/resource/class/dolresource.class.php
    +++ b/htdocs/resource/class/dolresource.class.php
    @@ -47,7 +47,12 @@ class Dolresource extends CommonObject
     	public $element_type;
     	public $busy;
     	public $mandatory;
    +
    +	/**
    +     * @var int ID
    +     */
     	public $fk_user_create;
    +
     	public $type_label;
     	public $tms='';
     
    diff --git a/htdocs/resource/class/html.formresource.class.php b/htdocs/resource/class/html.formresource.class.php
    index f541a7728cb..c118643aa7d 100644
    --- a/htdocs/resource/class/html.formresource.class.php
    +++ b/htdocs/resource/class/html.formresource.class.php
    @@ -38,8 +38,9 @@ class FormResource
          */
         public $db;
     
    -    var $substit=array();
    -    var $param=array();
    +    public $substit=array();
    +
    +    public $param=array();
     
         /**
     	 * @var string Error code (or message)
    diff --git a/htdocs/societe/admin/societe.php b/htdocs/societe/admin/societe.php
    index 3a7b26505c7..49a9538e225 100644
    --- a/htdocs/societe/admin/societe.php
    +++ b/htdocs/societe/admin/societe.php
    @@ -211,6 +211,21 @@ if ($action=="setaskforshippingmet") {
     	}
     }
     
    +//Activate "Disable prospect/customer type"
    +if ($action=="setdisableprospectcustomer") {
    +    $setdisableprospectcustomer = GETPOST('value','int');
    +    $res = dolibarr_set_const($db, "SOCIETE_DISABLE_PROSPECTSCUSTOMERS", $setdisableprospectcustomer,'yesno',0,'',$conf->entity);
    +    if (! $res > 0) $error++;
    +    if (! $error)
    +    {
    +        setEventMessages($langs->trans("SetupSaved"), null, 'mesgs');
    +    }
    +    else
    +    {
    +        setEventMessages($langs->trans("Error"), null, 'errors');
    +    }
    +}
    +
     //Activate ProfId unique
     if ($action == 'setprofid')
     {
    @@ -821,6 +836,25 @@ else
     print '</a></td>';
     print '</tr>';
     
    +// Disable Prospect/Customer thirdparty type
    +print '<tr class="oddeven">';
    +print '<td width="80%">'.$langs->trans("DisableProspectCustomerType").'</td>';
    +print '<td>&nbsp</td>';
    +print '<td align="center">';
    +if (!empty($conf->global->SOCIETE_DISABLE_PROSPECTSCUSTOMERS))
    +{
    +    print '<a href="'.$_SERVER['PHP_SELF'].'?action=setdisableprospectcustomer&value=0">';
    +    print img_picto($langs->trans("Activated"),'switch_on');
    +    
    +}
    +else
    +{
    +    print '<a href="'.$_SERVER['PHP_SELF'].'?action=setdisableprospectcustomer&value=1">';
    +    print img_picto($langs->trans("Disabled"),'switch_off');
    +}
    +print '</a></td>';
    +print '</tr>';
    +
     /*print '<tr class="oddeven">';
     print '<td width="80%">'.$langs->trans("OnSearchAndListGoOnCustomerOrSupplierCard").'</td>';
     print '<td>&nbsp</td>';
    diff --git a/htdocs/societe/card.php b/htdocs/societe/card.php
    index ee4d05231ee..1fbabc01462 100644
    --- a/htdocs/societe/card.php
    +++ b/htdocs/societe/card.php
    @@ -1063,6 +1063,39 @@ else
                             	$("#TypeName").html(document.formsoc.LastName.value);
                             	document.formsoc.private.value=1;
                             });
    +
    +						init_customer_categ();
    +			  			$("#customerprospect").change(function() {
    +								init_customer_categ();
    +						});
    +						function init_customer_categ() {
    +								console.log("is customer or prospect = "+jQuery("#customerprospect").val());
    +								if (jQuery("#customerprospect").val() == 0 && (jQuery("#fournisseur").val() == 0 || '.(empty($conf->global->THIRDPARTY_CAN_HAVE_CATEGORY_EVEN_IF_NOT_CUSTOMER_PROSPECT_SUPPLIER)?'1':'0').'))
    +								{
    +									jQuery(".visibleifcustomer").hide();
    +								}
    +								else
    +								{
    +									jQuery(".visibleifcustomer").show();
    +								}
    +						}
    +
    +						init_supplier_categ();
    +			       		$("#fournisseur").change(function() {
    +							init_supplier_categ();
    +						});
    +						function init_supplier_categ() {
    +								console.log("is supplier = "+jQuery("#fournisseur").val());
    +								if (jQuery("#fournisseur").val() == 0)
    +								{
    +									jQuery(".visibleifsupplier").hide();
    +								}
    +								else
    +								{
    +									jQuery(".visibleifsupplier").show();
    +								}
    +						}
    +
                             $("#selectcountry_id").change(function() {
                             	document.formsoc.action.value="create";
                             	document.formsoc.submit();
    @@ -1421,22 +1454,20 @@ else
     			$langs->load('categories');
     
     			// Customer
    -			if ($object->prospect || $object->client || (! $object->fournisseur && ! empty($conf->global->THIRDPARTY_CAN_HAVE_CATEGORY_EVEN_IF_NOT_CUSTOMER_PROSPECT_SUPPLIER))) {
    -				print '<tr><td class="toptd">' . fieldLabel('CustomersCategoriesShort', 'custcats') . '</td><td colspan="3">';
    -				$cate_arbo = $form->select_all_categories(Categorie::TYPE_CUSTOMER, null, 'parent', null, null, 1);
    -				print $form->multiselectarray('custcats', $cate_arbo, GETPOST('custcats', 'array'), null, null, null,
    -					null, "90%");
    -				print "</td></tr>";
    -			}
    +			//if ($object->prospect || $object->client || (! $object->fournisseur && ! empty($conf->global->THIRDPARTY_CAN_HAVE_CATEGORY_EVEN_IF_NOT_CUSTOMER_PROSPECT_SUPPLIER))) {
    +			print '<tr class="visibleifcustomer"><td class="toptd">' . fieldLabel('CustomersCategoriesShort', 'custcats') . '</td><td colspan="3">';
    +			$cate_arbo = $form->select_all_categories(Categorie::TYPE_CUSTOMER, null, 'parent', null, null, 1);
    +			print $form->multiselectarray('custcats', $cate_arbo, GETPOST('custcats', 'array'), null, null, null, null, "90%");
    +			print "</td></tr>";
    +			//}
     
     			// Supplier
    -			if ($object->fournisseur) {
    -				print '<tr><td class="toptd">' . fieldLabel('SuppliersCategoriesShort', 'suppcats') . '</td><td colspan="3">';
    -				$cate_arbo = $form->select_all_categories(Categorie::TYPE_SUPPLIER, null, 'parent', null, null, 1);
    -				print $form->multiselectarray('suppcats', $cate_arbo, GETPOST('suppcats', 'array'), null, null, null,
    -					null, "90%");
    -				print "</td></tr>";
    -			}
    +			//if ($object->fournisseur) {
    +			print '<tr class="visibleifsupplier"><td class="toptd">' . fieldLabel('SuppliersCategoriesShort', 'suppcats') . '</td><td colspan="3">';
    +			$cate_arbo = $form->select_all_categories(Categorie::TYPE_SUPPLIER, null, 'parent', null, null, 1);
    +			print $form->multiselectarray('suppcats', $cate_arbo, GETPOST('suppcats', 'array'), null, null, null, null, "90%");
    +			print "</td></tr>";
    +			//}
     		}
     
     		// Multicurrency
    @@ -1488,11 +1519,6 @@ else
         }
         elseif ($action == 'edit')
         {
    -        /*
    -         * Edition
    -         */
    -
    -
             //print load_fiche_titre($langs->trans("EditCompany"));
     
             if ($socid)
    @@ -1612,8 +1638,10 @@ else
                 	$sub2=0;
                 }else{$sub2=1;}
     
    -            print "\n".'<script type="text/javascript">';
    -            print '$(document).ready(function () {
    +            if ($conf->use_javascript_ajax)
    +            {
    +            	print "\n".'<script type="text/javascript">';
    +            	print '$(document).ready(function () {
         			var val='.$sub.';
         			var val2='.$sub2.';
         			if("#localtax1assuj_value".value==undefined){
    @@ -1647,19 +1675,44 @@ else
         				}
         			});
     
    -               });';
    -            print '</script>'."\n";
    +				init_customer_categ();
    +	  			$("#customerprospect").change(function() {
    +					init_customer_categ();
    +				});
    +       			function init_customer_categ() {
    +					console.log("is customer or prospect = "+jQuery("#customerprospect").val());
    +					if (jQuery("#customerprospect").val() == 0 && (jQuery("#fournisseur").val() == 0 || '.(empty($conf->global->THIRDPARTY_CAN_HAVE_CATEGORY_EVEN_IF_NOT_CUSTOMER_PROSPECT_SUPPLIER)?'1':'0').'))
    +					{
    +						jQuery(".visibleifcustomer").hide();
    +					}
    +					else
    +					{
    +						jQuery(".visibleifcustomer").show();
    +					}
    +				}
     
    +				init_supplier_categ();
    +	  			$("#fournisseur").change(function() {
    +					init_supplier_categ();
    +				});
    +       			function init_supplier_categ() {
    +					console.log("is supplier = "+jQuery("#fournisseur").val());
    +					if (jQuery("#fournisseur").val() == 0)
    +					{
    +						jQuery(".visibleifsupplier").hide();
    +					}
    +					else
    +					{
    +						jQuery(".visibleifsupplier").show();
    +					}
    +				};
     
    -            if ($conf->use_javascript_ajax)
    -            {
    -                print "\n".'<script type="text/javascript" language="javascript">';
    -                print '$(document).ready(function () {
    -                			$("#selectcountry_id").change(function() {
    -                				document.formsoc.action.value="edit";
    -                				document.formsoc.submit();
    -                			});
    -                       })';
    +       			$("#selectcountry_id").change(function() {
    +       				document.formsoc.action.value="edit";
    +      				document.formsoc.submit();
    +        			});
    +
    +                })';
                     print '</script>'."\n";
                 }
     
    @@ -2022,34 +2075,30 @@ else
     			if (! empty($conf->categorie->enabled)  && ! empty($user->rights->categorie->lire))
     			{
     				// Customer
    -				if ($object->prospect || $object->client || (! $object->fournisseur && ! empty($conf->global->THIRDPARTY_CAN_HAVE_CATEGORY_EVEN_IF_NOT_CUSTOMER_PROSPECT_SUPPLIER))) {
    -					print '<tr><td>' . fieldLabel('CustomersCategoriesShort', 'custcats') . '</td>';
    -					print '<td colspan="3">';
    -					$cate_arbo = $form->select_all_categories(Categorie::TYPE_CUSTOMER, null, null, null, null, 1);
    -					$c = new Categorie($db);
    -					$cats = $c->containing($object->id, Categorie::TYPE_CUSTOMER);
    -					$arrayselected=array();
    -					foreach ($cats as $cat) {
    -						$arrayselected[] = $cat->id;
    -					}
    -					print $form->multiselectarray('custcats', $cate_arbo, $arrayselected, '', 0, '', 0, '90%');
    -					print "</td></tr>";
    +				print '<tr class="visibleifcustomer"><td>' . fieldLabel('CustomersCategoriesShort', 'custcats') . '</td>';
    +				print '<td colspan="3">';
    +				$cate_arbo = $form->select_all_categories(Categorie::TYPE_CUSTOMER, null, null, null, null, 1);
    +				$c = new Categorie($db);
    +				$cats = $c->containing($object->id, Categorie::TYPE_CUSTOMER);
    +				$arrayselected=array();
    +				foreach ($cats as $cat) {
    +					$arrayselected[] = $cat->id;
     				}
    +				print $form->multiselectarray('custcats', $cate_arbo, $arrayselected, '', 0, '', 0, '90%');
    +				print "</td></tr>";
     
     				// Supplier
    -				if ($object->fournisseur) {
    -					print '<tr><td>' . fieldLabel('SuppliersCategoriesShort', 'suppcats') . '</td>';
    -					print '<td colspan="3">';
    -					$cate_arbo = $form->select_all_categories(Categorie::TYPE_SUPPLIER, null, null, null, null, 1);
    -					$c = new Categorie($db);
    -					$cats = $c->containing($object->id, Categorie::TYPE_SUPPLIER);
    -					$arrayselected=array();
    -					foreach ($cats as $cat) {
    -						$arrayselected[] = $cat->id;
    -					}
    -					print $form->multiselectarray('suppcats', $cate_arbo, $arrayselected, '', 0, '', 0, '90%');
    -					print "</td></tr>";
    +				print '<tr class="visibleifsupplier"><td>' . fieldLabel('SuppliersCategoriesShort', 'suppcats') . '</td>';
    +				print '<td colspan="3">';
    +				$cate_arbo = $form->select_all_categories(Categorie::TYPE_SUPPLIER, null, null, null, null, 1);
    +				$c = new Categorie($db);
    +				$cats = $c->containing($object->id, Categorie::TYPE_SUPPLIER);
    +				$arrayselected=array();
    +				foreach ($cats as $cat) {
    +					$arrayselected[] = $cat->id;
     				}
    +				print $form->multiselectarray('suppcats', $cate_arbo, $arrayselected, '', 0, '', 0, '90%');
    +				print "</td></tr>";
     			}
     
     			// Multicurrency
    diff --git a/htdocs/societe/class/address.class.php b/htdocs/societe/class/address.class.php
    index 37a350b81ff..63b23d42f9e 100644
    --- a/htdocs/societe/class/address.class.php
    +++ b/htdocs/societe/class/address.class.php
    @@ -47,7 +47,12 @@ class Address
     
     	public $socid;
     	public $name;
    +
    +	/**
    +	 * @var string Address
    +	 */
     	public $address;
    +
     	public $zip;
     	public $town;
     	public $country_id;
    @@ -522,7 +527,12 @@ class AddressLine
         public $label;
     
     	public $name;
    +
    +	/**
    +	 * @var string Address
    +	 */
     	public $address;
    +
     	public $zip;
     	public $town;
     	public $country_id;
    diff --git a/htdocs/societe/class/api_thirdparties.class.php b/htdocs/societe/class/api_thirdparties.class.php
    index 0b640fe1085..365073726bc 100644
    --- a/htdocs/societe/class/api_thirdparties.class.php
    +++ b/htdocs/societe/class/api_thirdparties.class.php
    @@ -52,6 +52,7 @@ class Thirdparties extends DolibarrApi
     		require_once DOL_DOCUMENT_ROOT.'/societe/class/societe.class.php';
     		require_once DOL_DOCUMENT_ROOT.'/societe/class/societeaccount.class.php';
     		require_once DOL_DOCUMENT_ROOT.'/categories/class/categorie.class.php';
    +		require_once DOL_DOCUMENT_ROOT.'/societe/class/companybankaccount.class.php';
     
     		$this->company = new Societe($this->db);
     
    diff --git a/htdocs/societe/class/companypaymentmode.class.php b/htdocs/societe/class/companypaymentmode.class.php
    index f5ef70c2407..83303a3a41d 100644
    --- a/htdocs/societe/class/companypaymentmode.class.php
    +++ b/htdocs/societe/class/companypaymentmode.class.php
    @@ -127,7 +127,7 @@ class CompanyPaymentMode extends CommonObject
     	/**
     	 * @var int Thirdparty ID
     	 */
    -  public $fk_soc;
    +    public $fk_soc;
     
     	/**
          * @var string company payment mode label
    @@ -161,7 +161,12 @@ class CompanyPaymentMode extends CommonObject
     	public $preapproval_key;
     	public $total_amount_of_all_payments;
     	public $stripe_card_ref;
    +
    +	/**
    +	 * @var int Status
    +	 */
     	public $status;
    +
     	public $starting_date;
     	public $ending_date;
     	public $datec;
    diff --git a/htdocs/societe/class/societe.class.php b/htdocs/societe/class/societe.class.php
    index a6dec311d0d..c91593b079f 100644
    --- a/htdocs/societe/class/societe.class.php
    +++ b/htdocs/societe/class/societe.class.php
    @@ -66,6 +66,7 @@ class Societe extends CommonObject
     	 * @var int
     	 */
     	public $ismultientitymanaged = 1;
    +
     	/**
     	 * 0=Default, 1=View may be restricted to sales representative only if no permission to see all or to company of external user if external user
     	 * @var integer
    @@ -103,7 +104,7 @@ class Societe extends CommonObject
     	 * Thirdparty name
     	 * @var string
     	 * @deprecated Use $name instead
    -	 * @see name
    +	 * @see $name
     	 */
     	public $nom;
     
    @@ -119,7 +120,12 @@ class Societe extends CommonObject
     	public $name_alias;
     
     	public $particulier;
    +
    +	/**
    +	 * @var string Address
    +	 */
     	public $address;
    +
     	public $zip;
     	public $town;
     
    @@ -148,21 +154,21 @@ class Societe extends CommonObject
     	 * State code
     	 * @var string
     	 * @deprecated Use state_code instead
    -	 * @see state_code
    +	 * @see $state_code
     	 */
     	public $departement_code;
     
     	/**
     	 * @var string
     	 * @deprecated Use state instead
    -	 * @see state
    +	 * @see $state
     	 */
     	public $departement;
     
     	/**
     	 * @var string
     	 * @deprecated Use country instead
    -	 * @see country
    +	 * @see $country
     	 */
     	public $pays;
     
    @@ -275,7 +281,12 @@ class Societe extends CommonObject
     	public $remise_supplier_percent;
     	public $mode_reglement_supplier_id;
     	public $cond_reglement_supplier_id;
    +
    +	/**
    +     * @var int ID
    +     */
     	public $fk_prospectlevel;
    +
     	public $name_bis;
     
     	//Log data
    @@ -353,7 +364,7 @@ class Societe extends CommonObject
     	/**
     	 * @var string
     	 * @deprecated Note is split in public and private notes
    -	 * @see note_public, note_private
    +	 * @see $note_public, $note_private
     	 */
     	public $note;
     
    @@ -443,12 +454,20 @@ class Societe extends CommonObject
     	public $array_options;
     
     	// Incoterms
    +	/**
    +     * @var int ID
    +     */
     	public $fk_incoterms;
    +
     	public $location_incoterms;
     	public $libelle_incoterms;  //Used into tooltip
     
     	// Multicurrency
    +	/**
    +     * @var int ID
    +     */
     	public $fk_multicurrency;
    +
     	public $multicurrency_code;
     
     
    @@ -1052,10 +1071,26 @@ class Societe extends CommonObject
     			$resql=$this->db->query($sql);
     			if ($resql)
     			{
    -				unset($this->country_code);		// We clean this because it may have been changed after an update of country_id
    -				unset($this->country);
    -				unset($this->state_code);
    -				unset($this->state);
    +				if (is_object($this->oldcopy))	// If we have information on old values
    +				{
    +					if ($this->oldcopy->country_id != $this->country_id)
    +					{
    +						unset($this->country_code);
    +						unset($this->country);
    +					}
    +					if ($this->oldcopy->state_id != $this->state_id)
    +					{
    +						unset($this->state_code);
    +						unset($this->state);
    +					}
    +				}
    +				else
    +				{
    +					unset($this->country_code);	// We clean this, in the doubt, because it may have been changed after an update of country_id
    +					unset($this->country);
    +					unset($this->state_code);
    +					unset($this->state);
    +				}
     
     				$nbrowsaffected = $this->db->affected_rows($resql);
     
    @@ -1708,10 +1743,13 @@ class Societe extends CommonObject
     
     			$discount = new DiscountAbsolute($this->db);
     			$discount->fk_soc=$this->id;
    +
     			$discount->discount_type=$discount_type;
    -			$discount->amount_ht=price2num($remise,'MT');
    -			$discount->amount_tva=price2num($remise*$tva_tx/100,'MT');
    -			$discount->amount_ttc=price2num($discount->amount_ht+$discount->amount_tva,'MT');
    +
    +			$discount->amount_ht=$discount->multicurrency_amount_ht=price2num($remise,'MT');
    +			$discount->amount_tva=$discount->multicurrency_amount_tva=price2num($remise*$tva_tx/100,'MT');
    +			$discount->amount_ttc=$discount->multicurrency_amount_ttc=price2num($discount->amount_ht+$discount->amount_tva,'MT');
    +
     			$discount->tva_tx=price2num($tva_tx,'MT');
     			$discount->description=$desc;
     
    @@ -1950,24 +1988,33 @@ class Societe extends CommonObject
     
     		if (! empty($conf->global->SOCIETE_ADD_REF_IN_LIST) && (!empty($withpicto)))
     		{
    +			$code = '';
     			if (($this->client) && (! empty ( $this->code_client ))
     				&& ($conf->global->SOCIETE_ADD_REF_IN_LIST == 1
     				|| $conf->global->SOCIETE_ADD_REF_IN_LIST == 2
     				)
     			)
    -			$code = $this->code_client . ' - ';
    +			{
    +				$code = $this->code_client . ' - ';
    +			}
     
     			if (($this->fournisseur) && (! empty ( $this->code_fournisseur ))
     				&& ($conf->global->SOCIETE_ADD_REF_IN_LIST == 1
     				|| $conf->global->SOCIETE_ADD_REF_IN_LIST == 3
     				)
     			)
    -			$code .= $this->code_fournisseur . ' - ';
    +			{
    +				$code .= $this->code_fournisseur . ' - ';
    +			}
     
     			if ($conf->global->SOCIETE_ADD_REF_IN_LIST == 1)
    +			{
     				$name =$code.' '.$name;
    +			}
     			else
    +			{
     				$name =$code;
    +			}
     		}
     
     		if (!empty($this->name_alias)) $name .= ' ('.$this->name_alias.')';
    @@ -3150,8 +3197,12 @@ class Societe extends CommonObject
     		// Define if third party is treated as company (or not) when nature is unknown
     		$isacompany=empty($conf->global->MAIN_UNKNOWN_CUSTOMERS_ARE_COMPANIES)?0:1; // 0 by default
     		if (! empty($this->tva_intra)) $isacompany=1;
    -		else if (! empty($this->typent_code) && in_array($this->typent_code,array('TE_PRIVATE'))) $isacompany=0;
    -		else if (! empty($this->typent_code) && in_array($this->typent_code,array('TE_SMALL','TE_MEDIUM','TE_LARGE','TE_GROUP'))) $isacompany=1;
    +		else if (! empty($this->typent_code) && $this->typent_code != 'TE_UNKNOWN')
    +		{
    +			// TODO Add a field is_a_company into dictionary
    +			if (preg_match('/^TE_PRIVATE/', $this->typent_code)) $isacompany=0;
    +			else $isacompany=1;
    +		}
     
     		return $isacompany;
     	}
    @@ -3312,6 +3363,7 @@ class Societe extends CommonObject
     		$this->town=empty($conf->global->MAIN_INFO_SOCIETE_TOWN)?'':$conf->global->MAIN_INFO_SOCIETE_TOWN;
     		$this->state_id=empty($conf->global->MAIN_INFO_SOCIETE_STATE)?'':$conf->global->MAIN_INFO_SOCIETE_STATE;
     		$this->region_code=empty($conf->global->MAIN_INFO_SOCIETE_REGION)?'':$conf->global->MAIN_INFO_SOCIETE_REGION;
    +		$this->object=empty($conf->global->MAIN_INFO_SOCIETE_OBJECT)?'':$conf->global->MAIN_INFO_SOCIETE_OBJECT;
     
     		$this->note_private=empty($conf->global->MAIN_INFO_SOCIETE_NOTE)?'':$conf->global->MAIN_INFO_SOCIETE_NOTE;
     
    diff --git a/htdocs/societe/class/societeaccount.class.php b/htdocs/societe/class/societeaccount.class.php
    index 422dd4ddb8e..de228c576b5 100644
    --- a/htdocs/societe/class/societeaccount.class.php
    +++ b/htdocs/societe/class/societeaccount.class.php
    @@ -99,6 +99,10 @@ class SocieteAccount extends CommonObject
     		'import_key' => array('type'=>'varchar(14)', 'label'=>'ImportId', 'visible'=>-2, 'enabled'=>1, 'position'=>1000, 'notnull'=>-1, 'index'=>1,),
     		'status' => array('type'=>'integer', 'label'=>'Status', 'visible'=>1, 'enabled'=>1, 'position'=>1000, 'notnull'=>1, 'index'=>1, 'default'=>1, 'arrayofkeyval'=>array('1'=>'Active','0'=>'Disabled')),
     	);
    +
    +	/**
    +	 * @var int ID
    +	 */
     	public $rowid;
     
     	/**
    @@ -123,10 +127,24 @@ class SocieteAccount extends CommonObject
     	public $note_private;
     	public $date_creation;
     	public $tms;
    +
    +	/**
    +     * @var int ID
    +     */
     	public $fk_user_creat;
    +
    +	/**
    +     * @var int ID
    +     */
     	public $fk_user_modif;
    +
     	public $import_key;
    +
    +	/**
    +	 * @var int Status
    +	 */
     	public $status;
    +
     	// END MODULEBUILDER PROPERTIES
     
     
    @@ -270,8 +288,6 @@ class SocieteAccount extends CommonObject
     	 */
     	public function getCustomerAccount($id, $site, $status=0)
     	{
    -		global $conf;
    -
     		$sql = "SELECT sa.key_account as key_account, sa.entity";
     		$sql.= " FROM " . MAIN_DB_PREFIX . "societe_account as sa";
     		$sql.= " WHERE sa.fk_soc = " . $id;
    @@ -280,7 +296,7 @@ class SocieteAccount extends CommonObject
     		$sql.= " AND key_account IS NOT NULL AND key_account <> ''";
     		//$sql.= " ORDER BY sa.key_account DESC";
     
    -		dol_syslog(get_class($this) . "::getCustomerAccount Try to find the system customer id of thirdparty id=".$id." (exemple: cus_.... for stripe)", LOG_DEBUG);
    +		dol_syslog(get_class($this) . "::getCustomerAccount Try to find the first system customer id for ".$site." of thirdparty id=".$id." (exemple: cus_.... for stripe)", LOG_DEBUG);
     		$result = $this->db->query($sql);
     		if ($result) {
     			if ($this->db->num_rows($result)) {
    diff --git a/htdocs/societe/index.php b/htdocs/societe/index.php
    index f53a9042fca..0759008c435 100644
    --- a/htdocs/societe/index.php
    +++ b/htdocs/societe/index.php
    @@ -1,6 +1,6 @@
     <?php
     /* Copyright (C) 2001-2006 Rodolphe Quiedeville <rodolphe@quiedeville.org>
    - * Copyright (C) 2004-2015 Laurent Destailleur  <eldy@users.sourceforge.net>
    + * Copyright (C) 2004-2018 Laurent Destailleur  <eldy@users.sourceforge.net>
      * Copyright (C) 2005-2012 Regis Houssin        <regis.houssin@capnetworks.com>
      * Copyright (C) 2014      Charles-Fr Benke	    <charles.fr@benke.fr>
      * Copyright (C) 2015      Jean-François Ferry	<jfefe@aternatik.fr>
    diff --git a/htdocs/societe/paymentmodes.php b/htdocs/societe/paymentmodes.php
    index 604012a24c3..13fdf048382 100644
    --- a/htdocs/societe/paymentmodes.php
    +++ b/htdocs/societe/paymentmodes.php
    @@ -557,7 +557,7 @@ if (empty($reshook))
     			$sql.= " SET key_account = '".$db->escape(GETPOST('key_account', 'alpha'))."'";
     			$sql.= " WHERE site = 'stripe' AND fk_soc = ".$object->id." AND status = ".$servicestatus." AND entity = ".$conf->entity;	// Keep = here for entity. Only 1 record must be modified !
                     }
    -     
    +
     			$resql = $db->query($sql);
     			$num = $db->num_rows($resql);
     			if (empty($num) && !empty($newcu))
    @@ -959,9 +959,17 @@ if ($socid && $action != 'edit' && $action != 'create' && $action != 'editcard'
     					print '<td>';
     					print '</td>';
     				}
    +				// Src ID
     				print '<td>';
    -				print $src->id;
    +				if (!empty($stripeacc)) $connect=$stripeacc.'/';
    +				$url='https://dashboard.stripe.com/'.$connect.'test/sources/'.$src->id;
    +				if ($servicestatus)
    +				{
    +					$url='https://dashboard.stripe.com/'.$connect.'sources/'.$src->id;
    +				}
    +				print $src->id." <a href='".$url."' target='_stripe'>".img_picto($langs->trans('ShowInStripe'), 'object_globe')."</a>";
     				print '</td>';
    +				// Img of credit card
     				print '<td>';
     				if ($src->object=='card')
     				{
    @@ -975,8 +983,8 @@ if ($socid && $action != 'edit' && $action != 'create' && $action != 'editcard'
     				{
     					print '<span class="fa fa-university fa-2x fa-fw"></span>';
     				}
    -
    -				print'</td><td valign="middle">';
    +				print'</td>';
    +				print '<td valign="middle">';
     				if ($src->object=='card')
     				{
     					print '....'.$src->last4.' - '.$src->exp_month.'/'.$src->exp_year.'';
    diff --git a/htdocs/stripe/class/stripe.class.php b/htdocs/stripe/class/stripe.class.php
    index 901997cef3b..0e9c3cbb4a8 100644
    --- a/htdocs/stripe/class/stripe.class.php
    +++ b/htdocs/stripe/class/stripe.class.php
    @@ -36,8 +36,11 @@ class Stripe extends CommonObject
     	/**
     	 * @var int Thirdparty ID
     	 */
    -  public $fk_soc;
    +    public $fk_soc;
     
    +    /**
    +     * @var int ID
    +     */
     	public $fk_key;
     
     	/**
    @@ -119,8 +122,6 @@ class Stripe extends CommonObject
     	 */
     	public function getStripeCustomerAccount($id, $status=0)
     	{
    -		global $conf;
    -
     		include_once DOL_DOCUMENT_ROOT.'/societe/class/societeaccount.class.php';
     		$societeaccount = new SocieteAccount($this->db);
     		return $societeaccount->getCustomerAccount($id, 'stripe', $status);		// Get thirdparty cus_...
    @@ -186,11 +187,22 @@ class Stripe extends CommonObject
     			{
     				$dataforcustomer = array(
     					"email" => $object->email,
    -					"business_vat_id" => $object->tva_intra,
     					"description" => $object->name,
     					"metadata" => array('dol_id'=>$object->id, 'dol_version'=>DOL_VERSION, 'dol_entity'=>$conf->entity, 'ipaddress'=>(empty($_SERVER['REMOTE_ADDR'])?'':$_SERVER['REMOTE_ADDR']))
     				);
     
    +				$vatcleaned = $object->tva_intra ? $object->tva_intra : null;
    +
    +				$taxinfo = array('type'=>'vat');
    +				if ($vatcleaned)
    +				{
    +					$taxinfo["tax_id"] = $vatcleaned;
    +				}
    +				// We force data to "null" if not defined as expected by Stripe
    +				if (empty($vatcleaned)) $taxinfo=null;
    +
    +				$dataforcustomer["tax_info"] = $taxinfo;
    +
     				//$a = \Stripe\Stripe::getApiKey();
     				//var_dump($a);var_dump($key);exit;
     				try {
    diff --git a/htdocs/stripe/config.php b/htdocs/stripe/config.php
    index 7aa22678d7a..6141c2a32f8 100644
    --- a/htdocs/stripe/config.php
    +++ b/htdocs/stripe/config.php
    @@ -55,4 +55,4 @@ else
     
     \Stripe\Stripe::setApiKey($stripearrayofkeys['secret_key']);
     \Stripe\Stripe::setAppInfo("Dolibarr Stripe", DOL_VERSION, "https://www.dolibarr.org"); // add dolibarr version
    -\Stripe\Stripe::setApiVersion("2018-07-27"); // force version API
    +\Stripe\Stripe::setApiVersion("2018-09-24"); // force version API
    diff --git a/htdocs/supplier_proposal/class/supplier_proposal.class.php b/htdocs/supplier_proposal/class/supplier_proposal.class.php
    index ecd940fea96..adc2c8643ac 100644
    --- a/htdocs/supplier_proposal/class/supplier_proposal.class.php
    +++ b/htdocs/supplier_proposal/class/supplier_proposal.class.php
    @@ -60,6 +60,9 @@ class SupplierProposal extends CommonObject
     	 */
     	public $table_element_line='supplier_proposaldet';
     
    +	/**
    +	 * @var int Field with ID of parent key if this field has a parent
    +	 */
         public $fk_element='fk_supplier_proposal';
     
         public $picto='propal';
    @@ -163,7 +166,11 @@ class SupplierProposal extends CommonObject
         public $specimen;
     
     	// Multicurrency
    +	/**
    +     * @var int ID
    +     */
     	public $fk_multicurrency;
    +
     	public $multicurrency_code;
     	public $multicurrency_tx;
     	public $multicurrency_total_ht;
    @@ -2709,9 +2716,21 @@ class SupplierProposalLine extends CommonObjectLine
     	 */
     	public $id;
     
    +	/**
    +     * @var int ID
    +     */
         public $fk_supplier_proposal;
    +
    +    /**
    +     * @var int ID
    +     */
         public $fk_parent_line;
    +
         public $desc;          	// Description ligne
    +
    +    /**
    +     * @var int ID
    +     */
         public $fk_product;		// Id produit predefini
     
     	/**
    @@ -2730,11 +2749,19 @@ class SupplierProposalLine extends CommonObjectLine
         public $tva_tx;
         public $subprice;
         public $remise_percent;
    +
    +    /**
    +     * @var int ID
    +     */
         public $fk_remise_except;
     
         public $rang = 0;
     
    +    /**
    +     * @var int ID
    +     */
     	public $fk_fournprice;
    +
     	public $pa_ht;
     	public $marge_tx;
     	public $marque_tx;
    @@ -2808,7 +2835,11 @@ class SupplierProposalLine extends CommonObjectLine
         public $ref_supplier;
     
     	// Multicurrency
    +	/**
    +     * @var int ID
    +     */
     	public $fk_multicurrency;
    +
     	public $multicurrency_code;
     	public $multicurrency_subprice;
     	public $multicurrency_total_ht;
    diff --git a/htdocs/takepos/invoice.php b/htdocs/takepos/invoice.php
    index 939d1ea2189..c71f7f861a3 100644
    --- a/htdocs/takepos/invoice.php
    +++ b/htdocs/takepos/invoice.php
    @@ -77,12 +77,14 @@ if ($action == 'valid' && $user->rights->facture->creer){
     
     if (($action=="addline" || $action=="freezone") and $placeid==0)
     {
    +	// $place is id of POS, $placeid is id of invoice
     	if ($placeid==0) {
     		$invoice = new Facture($db);
     		$invoice->socid=$conf->global->CASHDESK_ID_THIRDPARTY;
     		$invoice->date=dol_now();
     		$invoice->ref="(PROV-POS)";
     		$invoice->module_source = 'takepos';
    +		$invoice->pos_source = (string) (empty($place)?'0':$place);
     
     		$placeid=$invoice->create($user);
     		$sql="UPDATE ".MAIN_DB_PREFIX."facture set facnumber='(PROV-POS-".$place.")' where rowid=".$placeid;
    @@ -113,7 +115,7 @@ if ($action=="deleteline"){
             $row = $db->fetch_array ($resql);
             $deletelineid=$row[0];
             $invoice->deleteline($deletelineid);
    -        $invoice->fetch($deletelineid);
    +        $invoice->fetch($placeid);
         }
     }
     
    diff --git a/htdocs/theme/eldy/style.css.php b/htdocs/theme/eldy/style.css.php
    index 82f50a5771c..d9ad2a590ac 100644
    --- a/htdocs/theme/eldy/style.css.php
    +++ b/htdocs/theme/eldy/style.css.php
    @@ -696,6 +696,9 @@ textarea.centpercent {
     	height: 28px;
     	vertical-align: middle;
     }
    +.divsocialnetwork:not(:first-child) {
    +    padding-left: 20px;
    +}
     div.divsearchfield {
     	float: <?php print $left; ?>;
     	margin-<?php print $right; ?>: 12px;
    @@ -3268,7 +3271,7 @@ ul.noborder li:nth-child(even):not(.liste_titre) {
     .boxstats130 {
         width: 158px;
         height: 48px;
    -    padding: 3px
    +    padding: 3px;
     }
     .boxstats {
         padding: 3px;
    diff --git a/htdocs/theme/md/style.css.php b/htdocs/theme/md/style.css.php
    index 23575680acf..2b760fcd894 100644
    --- a/htdocs/theme/md/style.css.php
    +++ b/htdocs/theme/md/style.css.php
    @@ -689,6 +689,9 @@ textarea.centpercent {
     	height: 28px;
     	vertical-align: middle;
     }
    +.divsocialnetwork:not(:first-child) {
    +    padding-left: 20px;
    +}
     div.divsearchfield {
     	float: <?php print $left; ?>;
     	margin-<?php print $right; ?>: 12px;
    @@ -1202,6 +1205,13 @@ td.showDragHandle {
     .side-nav-vert {
     	margin-left: 228px;
     }
    +<?php if (empty($conf->global->THEME_DISABLE_STICKY_TOPMENU)) {  ?>
    +.side-nav-vert {
    +	position: sticky;
    +	top: 0px;
    +	z-index: 210;
    +}
    +<?php } ?>
     
     /* For smartphone (testmenuhider is on) */
     <?php if (in_array($conf->browser->layout, array('phone','tablet')) && ((GETPOST('testmenuhider') || ! empty($conf->global->MAIN_TESTMENUHIDER)) && empty($conf->global->MAIN_OPTIMIZEFORTEXTBROWSER))) { ?>
    @@ -1233,6 +1243,11 @@ div.backgroundsemitransparent {
     	padding-left: 10px;
     	padding-right: 10px;
     }
    +
    +
    +
    +/* Login */
    +
     div.login_block {
     	/* position: initial !important;*/
     	display: none;
    @@ -1247,6 +1262,10 @@ div.login_block {
     	color: #333 !important;
     	font-weight: normal !important;
     }
    +
    +
    +
    +
     #id-right {
     	padding-left: 0 ! important;
     }
    @@ -1510,7 +1529,7 @@ div#tmenu_tooltip {
     <?php } else { ?>
     	background: rgb(<?php echo $colorbackhmenu1 ?>);
     	/*
    -	background-image: linear-gradient(top, rgba(255,255,255,.3) 0%, rgba(128,128,128,.3) 100%);
    +	background-image: linear-gradient(to top, rgba(255,255,255,.3) 0%, rgba(128,128,128,.3) 100%);
     	background-image: -o-linear-gradient(top, rgba(255,255,255,.3) 0%, rgba(128,128,128,.3) 100%);
     	background-image: -moz-linear-gradient(top, rgba(255,255,255,.3) 0%, rgba(128,128,128,.3) 100%);
     	background-image: -webkit-linear-gradient(top, rgba(255,255,255,.3) 0%, rgba(128,128,128,.3) 100%);
    @@ -1591,7 +1610,7 @@ ul.tmenu {	/* t r b l */
     ul.tmenu li {
     	background: rgb(<?php echo $colorbackhmenu1 ?>);
     	/*
    -	background-image: linear-gradient(top, rgba(255,255,255,.3) 0%, rgba(0,0,0,.3) 100%);
    +	background-image: linear-gradient(to top, rgba(255,255,255,.3) 0%, rgba(0,0,0,.3) 100%);
     	background-image: -o-linear-gradient(top, rgba(255,255,255,.3) 0%, rgba(0,0,0,.3) 100%);
     	background-image: -moz-linear-gradient(top, rgba(255,255,255,.3) 0%, rgba(0,0,0,.3) 100%);
     	background-image: -webkit-linear-gradient(top, rgba(255,255,255,.3) 0%, rgba(0,0,0,.3) 100%);
    @@ -2887,7 +2906,7 @@ div.pagination li.paginationafterarrows {
     
     /* Prepare to remove class pair - impair
     .noborder > tbody > tr:nth-child(even) td {
    -	background: linear-gradient(bottom, rgb(<?php echo $colorbacklineimpair1; ?>) 85%, rgb(<?php echo $colorbacklineimpair2; ?>) 100%);
    +	background: linear-gradient(to bottom, rgb(<?php echo $colorbacklineimpair1; ?>) 85%, rgb(<?php echo $colorbacklineimpair2; ?>) 100%);
     	background: -o-linear-gradient(bottom, rgb(<?php echo $colorbacklineimpair1; ?>) 85%, rgb(<?php echo $colorbacklineimpair2; ?>) 100%);
     	background: -moz-linear-gradient(bottom, rgb(<?php echo $colorbacklineimpair1; ?>) 85%, rgb(<?php echo $colorbacklineimpair2; ?>) 100%);
     	background: -webkit-linear-gradient(bottom, rgb(<?php echo $colorbacklineimpair1; ?>) 85%, rgb(<?php echo $colorbacklineimpair2; ?>) 100%);
    @@ -2900,7 +2919,7 @@ div.pagination li.paginationafterarrows {
     }
     
     .noborder > tbody > tr:nth-child(odd) td {
    -	background: linear-gradient(bottom, rgb(<?php echo $colorbacklinepair1; ?>) 85%, rgb(<?php echo $colorbacklinepair2; ?>) 100%);
    +	background: linear-gradient(to bottom, rgb(<?php echo $colorbacklinepair1; ?>) 85%, rgb(<?php echo $colorbacklinepair2; ?>) 100%);
     	background: -o-linear-gradient(bottom, rgb(<?php echo $colorbacklinepair1; ?>) 85%, rgb(<?php echo $colorbacklinepair2; ?>) 100%);
     	background: -moz-linear-gradient(bottom, rgb(<?php echo $colorbacklinepair1; ?>) 85%, rgb(<?php echo $colorbacklinepair2; ?>) 100%);
     	background: -webkit-linear-gradient(bottom, rgb(<?php echo $colorbacklinepair1; ?>) 85%, rgb(<?php echo $colorbacklinepair2; ?>) 100%);
    @@ -3165,7 +3184,7 @@ div .tdtop {
     /* Prepare to remove class pair - impair */
     
     .noborder > tbody > tr:nth-child(even):not(.liste_titre), .liste > tbody > tr:nth-child(even):not(.liste_titre) {
    -	background: linear-gradient(bottom, rgb(<?php echo $colorbacklineimpair1; ?>) 85%, rgb(<?php echo $colorbacklineimpair2; ?>) 100%);
    +	background: linear-gradient(to bottom, rgb(<?php echo $colorbacklineimpair1; ?>) 85%, rgb(<?php echo $colorbacklineimpair2; ?>) 100%);
     	background: -o-linear-gradient(bottom, rgb(<?php echo $colorbacklineimpair1; ?>) 85%, rgb(<?php echo $colorbacklineimpair2; ?>) 100%);
     	background: -moz-linear-gradient(bottom, rgb(<?php echo $colorbacklineimpair1; ?>) 85%, rgb(<?php echo $colorbacklineimpair2; ?>) 100%);
     	background: -webkit-linear-gradient(bottom, rgb(<?php echo $colorbacklineimpair1; ?>) 85%, rgb(<?php echo $colorbacklineimpair2; ?>) 100%);
    @@ -3176,7 +3195,7 @@ div .tdtop {
     }
     
     .noborder > tbody > tr:nth-child(odd):not(.liste_titre), .liste > tbody > tr:nth-child(odd):not(.liste_titre) {
    -	background: linear-gradient(bottom, rgb(<?php echo $colorbacklinepair1; ?>) 85%, rgb(<?php echo $colorbacklinepair2; ?>) 100%);
    +	background: linear-gradient(to bottom, rgb(<?php echo $colorbacklinepair1; ?>) 85%, rgb(<?php echo $colorbacklinepair2; ?>) 100%);
     	background: -o-linear-gradient(bottom, rgb(<?php echo $colorbacklinepair1; ?>) 85%, rgb(<?php echo $colorbacklinepair2; ?>) 100%);
     	background: -moz-linear-gradient(bottom, rgb(<?php echo $colorbacklinepair1; ?>) 85%, rgb(<?php echo $colorbacklinepair2; ?>) 100%);
     	background: -webkit-linear-gradient(bottom, rgb(<?php echo $colorbacklinepair1; ?>) 85%, rgb(<?php echo $colorbacklinepair2; ?>) 100%);
    @@ -3222,7 +3241,7 @@ div .tdtop {
     .boxstats130 {
         width: 135px;
         height: 48px;
    -    padding: 3px
    +    padding: 3px;
     }
     @media only screen and (max-width: 767px)
     {
    diff --git a/htdocs/ticket/class/actions_ticket.class.php b/htdocs/ticket/class/actions_ticket.class.php
    index 2fd26b5797b..7e8ae39564a 100644
    --- a/htdocs/ticket/class/actions_ticket.class.php
    +++ b/htdocs/ticket/class/actions_ticket.class.php
    @@ -70,6 +70,9 @@ class ActionsTicket
     	 */
     	public $description;
     
    +	/**
    +     * @var int ID
    +     */
         public $fk_statut;
     
         /**
    diff --git a/htdocs/ticket/class/api_tickets.class.php b/htdocs/ticket/class/api_tickets.class.php
    index c75ab7e2450..110c27a5cce 100644
    --- a/htdocs/ticket/class/api_tickets.class.php
    +++ b/htdocs/ticket/class/api_tickets.class.php
    @@ -473,190 +473,6 @@ class Tickets extends DolibarrApi
             );
         }
     
    -
    -    /**
    -     * Get the list of tickets categories.
    -     *
    -     * @param string    $sortfield  Sort field
    -     * @param string    $sortorder  Sort order
    -     * @param int       $limit      Number of items per page
    -     * @param int       $page       Page number (starting from zero)
    -     * @param string    $sqlfilters Other criteria to filter answers separated by a comma. Syntax example "(t.code:like:'A%') and (t.active:>=:0)"
    -     * @return List of events types
    -     *
    -     * @url     GET setup/dictionary/categories
    -     *
    -     * @throws RestException
    -     */
    -    function getTicketsCategories($sortfield = "code", $sortorder = 'ASC', $limit = 100, $page = 0, $sqlfilters = '')
    -    {
    -    	$list = array();
    -
    -    	$sql = "SELECT rowid, code, pos,  label, use_default, description";
    -    	$sql.= " FROM ".MAIN_DB_PREFIX."c_ticket_category as t";
    -    	$sql.= " WHERE t.active = 1";
    -    	// Add sql filters
    -    	if ($sqlfilters)
    -    	{
    -    		if (! DolibarrApi::_checkFilters($sqlfilters))
    -    		{
    -    			throw new RestException(503, 'Error when validating parameter sqlfilters '.$sqlfilters);
    -    		}
    -    		$regexstring='\(([^:\'\(\)]+:[^:\'\(\)]+:[^:\(\)]+)\)';
    -    		$sql.=" AND (".preg_replace_callback('/'.$regexstring.'/', 'DolibarrApi::_forge_criteria_callback', $sqlfilters).")";
    -    	}
    -
    -
    -    	$sql.= $this->db->order($sortfield, $sortorder);
    -
    -    	if ($limit) {
    -    		if ($page < 0) {
    -    			$page = 0;
    -    		}
    -    		$offset = $limit * $page;
    -
    -    		$sql .= $this->db->plimit($limit, $offset);
    -    	}
    -
    -    	$result = $this->db->query($sql);
    -
    -    	if ($result) {
    -    		$num = $this->db->num_rows($result);
    -    		$min = min($num, ($limit <= 0 ? $num : $limit));
    -    		for ($i = 0; $i < $min; $i++) {
    -    			$list[] = $this->db->fetch_object($result);
    -    		}
    -    	} else {
    -    		throw new RestException(503, 'Error when retrieving list of ticket categories : '.$this->db->lasterror());
    -    	}
    -
    -    	return $list;
    -    }
    -
    -    /**
    -     * Get the list of tickets severity.
    -     *
    -     * @param string    $sortfield  Sort field
    -     * @param string    $sortorder  Sort order
    -     * @param int       $limit      Number of items per page
    -     * @param int       $page       Page number (starting from zero)
    -     * @param string    $sqlfilters Other criteria to filter answers separated by a comma. Syntax example "(t.code:like:'A%') and (t.active:>=:0)"
    -     * @return List of events types
    -     *
    -     * @url     GET setup/dictionary/severities
    -     *
    -     * @throws RestException
    -     */
    -    function getTicketsSeverities($sortfield = "code", $sortorder = 'ASC', $limit = 100, $page = 0, $sqlfilters = '')
    -    {
    -    	$list = array();
    -
    -    	$sql = "SELECT rowid, code, pos,  label, use_default, color, description";
    -    	$sql.= " FROM ".MAIN_DB_PREFIX."c_ticket_severity as t";
    -    	$sql.= " WHERE t.active = 1";
    -    	// Add sql filters
    -    	if ($sqlfilters)
    -    	{
    -    		if (! DolibarrApi::_checkFilters($sqlfilters))
    -    		{
    -    			throw new RestException(503, 'Error when validating parameter sqlfilters '.$sqlfilters);
    -    		}
    -    		$regexstring='\(([^:\'\(\)]+:[^:\'\(\)]+:[^:\(\)]+)\)';
    -    		$sql.=" AND (".preg_replace_callback('/'.$regexstring.'/', 'DolibarrApi::_forge_criteria_callback', $sqlfilters).")";
    -    	}
    -
    -
    -    	$sql.= $this->db->order($sortfield, $sortorder);
    -
    -    	if ($limit) {
    -    		if ($page < 0) {
    -    			$page = 0;
    -    		}
    -    		$offset = $limit * $page;
    -
    -    		$sql .= $this->db->plimit($limit, $offset);
    -    	}
    -
    -    	$result = $this->db->query($sql);
    -
    -    	if ($result) {
    -    		$num = $this->db->num_rows($result);
    -    		$min = min($num, ($limit <= 0 ? $num : $limit));
    -    		for ($i = 0; $i < $min; $i++) {
    -    			$list[] = $this->db->fetch_object($result);
    -    		}
    -    	} else {
    -    		throw new RestException(503, 'Error when retrieving list of ticket severities : '.$this->db->lasterror());
    -    	}
    -
    -    	return $list;
    -    }
    -
    -    /**
    -     * Get the list of tickets types.
    -     *
    -     * @param string    $sortfield  Sort field
    -     * @param string    $sortorder  Sort order
    -     * @param int       $limit      Number of items per page
    -     * @param int       $page       Page number (starting from zero)
    -     * @param string    $sqlfilters Other criteria to filter answers separated by a comma. Syntax example "(t.code:like:'A%') and (t.active:>=:0)"
    -     * @return List of events types
    -     *
    -     * @url     GET setup/dictionary/types
    -     *
    -     * @throws RestException
    -     */
    -    function getTicketsTypes($sortfield = "code", $sortorder = 'ASC', $limit = 100, $page = 0, $sqlfilters = '')
    -    {
    -    	$list = array();
    -
    -    	$sql = "SELECT rowid, code, pos,  label, use_default, description";
    -    	$sql.= " FROM ".MAIN_DB_PREFIX."c_ticket_type as t";
    -    	$sql.= " WHERE t.active = 1";
    -    	if ($type) $sql.=" AND t.type LIKE '%" . $this->db->escape($type) . "%'";
    -    	if ($module)    $sql.=" AND t.module LIKE '%" . $this->db->escape($module) . "%'";
    -    	// Add sql filters
    -    	if ($sqlfilters)
    -    	{
    -    		if (! DolibarrApi::_checkFilters($sqlfilters))
    -    		{
    -    			throw new RestException(503, 'Error when validating parameter sqlfilters '.$sqlfilters);
    -    		}
    -    		$regexstring='\(([^:\'\(\)]+:[^:\'\(\)]+:[^:\(\)]+)\)';
    -    		$sql.=" AND (".preg_replace_callback('/'.$regexstring.'/', 'DolibarrApi::_forge_criteria_callback', $sqlfilters).")";
    -    	}
    -
    -
    -    	$sql.= $this->db->order($sortfield, $sortorder);
    -
    -    	if ($limit) {
    -    		if ($page < 0) {
    -    			$page = 0;
    -    		}
    -    		$offset = $limit * $page;
    -
    -    		$sql .= $this->db->plimit($limit, $offset);
    -    	}
    -
    -    	$result = $this->db->query($sql);
    -
    -    	if ($result) {
    -    		$num = $this->db->num_rows($result);
    -    		$min = min($num, ($limit <= 0 ? $num : $limit));
    -    		for ($i = 0; $i < $min; $i++) {
    -    			$list[] = $this->db->fetch_object($result);
    -    		}
    -    	} else {
    -    		throw new RestException(503, 'Error when retrieving list of ticket types : '.$this->db->lasterror());
    -    	}
    -
    -    	return $list;
    -    }
    -
    -
    -
    -
    -
         /**
          * Validate fields before create or update object
          *
    diff --git a/htdocs/ticket/class/ticketlogs.class.php b/htdocs/ticket/class/ticketlogs.class.php
    index 01ba7972ced..66cecd6eb5e 100644
    --- a/htdocs/ticket/class/ticketlogs.class.php
    +++ b/htdocs/ticket/class/ticketlogs.class.php
    @@ -1,5 +1,6 @@
     <?php
    -/* Copyright (C) - 2013-2016    Jean-François FERRY    <hello@librethic.io>
    +/* Copyright (C) 2013-2016  Jean-François FERRY     <hello@librethic.io>
    + * Copyright (C) 2018       Frédéric France         <frederic.france@netlogic.fr>
      *
      * This program is free software; you can redistribute it and/or modify
      * it under the terms of the GNU General Public License as published by
    @@ -62,8 +63,16 @@ class Ticketlogs// extends CommonObject
     	 */
     	public $id;
     
    +	/**
    +     * @var string trackid
    +     */
         public $fk_track_id;
    +
    +    /**
    +     * @var int user create ID
    +     */
         public $fk_user_create;
    +
         public $datec = '';
         public $message;
     
    @@ -96,7 +105,7 @@ class Ticketlogs// extends CommonObject
             }
     
             if (isset($this->fk_user_create)) {
    -            $this->fk_user_create = trim($this->fk_user_create);
    +            $this->fk_user_create = (int) $this->fk_user_create;
             }
     
             if (isset($this->message)) {
    @@ -135,7 +144,7 @@ class Ticketlogs// extends CommonObject
             if (!$error) {
                 $this->id = $this->db->last_insert_id(MAIN_DB_PREFIX . "ticket_logs");
     
    -            if (!$notrigger) {
    +            //if (!$notrigger) {
                     // Uncomment this and change MYOBJECT to your own tag if you
                     // want this action calls a trigger.
     
    @@ -145,7 +154,7 @@ class Ticketlogs// extends CommonObject
                     //$result=$interface->run_triggers('MYOBJECT_CREATE',$this,$user,$langs,$conf);
                     //if ($result < 0) { $error++; $this->errors=$interface->errors; }
                     //// End call triggers
    -            }
    +            //}
             }
     
             // Commit or rollback
    @@ -224,7 +233,7 @@ class Ticketlogs// extends CommonObject
             }
     
             if (isset($this->fk_user_create)) {
    -            $this->fk_user_create = trim($this->fk_user_create);
    +            $this->fk_user_create = (int) $this->fk_user_create;
             }
     
             if (isset($this->message)) {
    @@ -253,8 +262,8 @@ class Ticketlogs// extends CommonObject
                 $this->errors[] = "Error " . $this->db->lasterror();
             }
     
    -        if (!$error) {
    -            if (!$notrigger) {
    +        //if (!$error) {
    +            //if (!$notrigger) {
                     // Uncomment this and change MYOBJECT to your own tag if you
                     // want this action calls a trigger.
     
    @@ -264,8 +273,8 @@ class Ticketlogs// extends CommonObject
                     //$result=$interface->run_triggers('MYOBJECT_MODIFY',$this,$user,$langs,$conf);
                     //if ($result < 0) { $error++; $this->errors=$interface->errors; }
                     //// End call triggers
    -            }
    -        }
    +            //}
    +        //}
     
             // Commit or rollback
             if ($error) {
    @@ -295,8 +304,8 @@ class Ticketlogs// extends CommonObject
     
             $this->db->begin();
     
    -        if (!$error) {
    -            if (!$notrigger) {
    +        //if (!$error) {
    +            //if (!$notrigger) {
                     // Uncomment this and change MYOBJECT to your own tag if you
                     // want this action calls a trigger.
     
    @@ -306,8 +315,8 @@ class Ticketlogs// extends CommonObject
                     //$result=$interface->run_triggers('MYOBJECT_DELETE',$this,$user,$langs,$conf);
                     //if ($result < 0) { $error++; $this->errors=$interface->errors; }
                     //// End call triggers
    -            }
    -        }
    +            //}
    +        //}
     
             if (!$error) {
                 $sql = "DELETE FROM " . MAIN_DB_PREFIX . "ticket_logs";
    @@ -343,10 +352,12 @@ class Ticketlogs// extends CommonObject
          */
         public function initAsSpecimen()
         {
    +	global $user;
    +	    
             $this->id = 0;
     
             $this->fk_track_id = '';
    -        $this->fk_user_create = '';
    +        $this->fk_user_create = $user->id;
             $this->datec = '';
             $this->message = '';
         }
    diff --git a/htdocs/user/agenda_extsites.php b/htdocs/user/agenda_extsites.php
    index 3146f1095b0..2eb2ede000b 100644
    --- a/htdocs/user/agenda_extsites.php
    +++ b/htdocs/user/agenda_extsites.php
    @@ -157,17 +157,22 @@ dol_fiche_head($head, 'extsites', $langs->trans("User"), -1, 'user');
     $linkback = '';
     
     if ($user->rights->user->user->lire || $user->admin) {
    -	$linkback = '<a href="'.DOL_URL_ROOT.'/user/list.php">'.$langs->trans("BackToList").'</a>';
    +	$linkback = '<a href="'.DOL_URL_ROOT.'/user/list.php?restore_lastsearch_values=1">'.$langs->trans("BackToList").'</a>';
     }
     
     dol_banner_tab($object,'id',$linkback,$user->rights->user->user->lire || $user->admin);
     
    -print $langs->trans("AgendaExtSitesDesc")."<br>\n";
    +
    +print '<div class="underbanner clearboth"></div>';
    +
    +print '<br>';
    +print '<span class="opacitymedium">'.$langs->trans("AgendaExtSitesDesc")."</span><br>\n";
     print "<br>\n";
     
     $selectedvalue=$conf->global->AGENDA_DISABLE_EXT;
     if ($selectedvalue==1) $selectedvalue=0; else $selectedvalue=1;
     
    +
     print '<div class="div-table-responsive">';
     print "<table class=\"noborder\" width=\"100%\">";
     
    @@ -210,12 +215,13 @@ while ($i <= $MAXAGENDA)
     print '</table>';
     print '</div>';
     
    -dol_fiche_end();
     
     print '<div class="center">';
     print "<input type=\"submit\" id=\"save\" name=\"save\" class=\"button hideifnotset\" value=\"".$langs->trans("Save")."\">";
     print "</div>";
     
    +dol_fiche_end();
    +
     print "</form>\n";
     
     // End of page
    diff --git a/htdocs/user/bank.php b/htdocs/user/bank.php
    index 2820e9e4690..13b555b6d5c 100644
    --- a/htdocs/user/bank.php
    +++ b/htdocs/user/bank.php
    @@ -194,7 +194,7 @@ if ($action != 'edit' && $action != 'create')		// If not bank account yet, $acco
     	$linkback = '';
     
     	if ($user->rights->user->user->lire || $user->admin) {
    -		$linkback = '<a href="'.DOL_URL_ROOT.'/user/list.php">'.$langs->trans("BackToList").'</a>';
    +		$linkback = '<a href="'.DOL_URL_ROOT.'/user/list.php?restore_lastsearch_values=1">'.$langs->trans("BackToList").'</a>';
     	}
     
         dol_banner_tab($object,'id',$linkback,$user->rights->user->user->lire || $user->admin);
    diff --git a/htdocs/user/card.php b/htdocs/user/card.php
    index dc2437af825..6a8e0d4f14a 100644
    --- a/htdocs/user/card.php
    +++ b/htdocs/user/card.php
    @@ -201,6 +201,8 @@ if (empty($reshook)) {
     			$object->office_fax = GETPOST("office_fax", 'alpha');
     			$object->user_mobile = GETPOST("user_mobile");
     			$object->skype = GETPOST("skype", 'alpha');
    +			$object->twitter = GETPOST("twitter", 'alpha');
    +			$object->facebook = GETPOST("facebook", 'alpha');
     			$object->email = preg_replace('/\s+/', '', GETPOST("email", 'alpha'));
     			$object->job = GETPOST("job", 'alpha');
     			$object->signature = GETPOST("signature");
    @@ -348,6 +350,8 @@ if (empty($reshook)) {
     				$object->office_fax = GETPOST("office_fax", 'alpha');
     				$object->user_mobile = GETPOST("user_mobile");
     				$object->skype = GETPOST("skype", 'alpha');
    +				$object->twitter = GETPOST("twitter", 'alpha');
    +				$object->facebook = GETPOST("facebook", 'alpha');
     				$object->email = preg_replace('/\s+/', '', GETPOST("email", 'alpha'));
     				$object->job = GETPOST("job", 'alpha');
     				$object->signature = GETPOST("signature",'none');
    @@ -588,6 +592,8 @@ if (empty($reshook)) {
     					$ldap_fax = $attribute[$conf->global->LDAP_FIELD_FAX];
     					$ldap_mobile = $attribute[$conf->global->LDAP_FIELD_MOBILE];
     					$ldap_skype = $attribute[$conf->global->LDAP_FIELD_SKYPE];
    +					$ldap_twitter = $attribute[$conf->global->LDAP_FIELD_TWITTER];
    +					$ldap_facebook = $attribute[$conf->global->LDAP_FIELD_FACEBOOK];
     					$ldap_mail = $attribute[$conf->global->LDAP_FIELD_MAIL];
     					$ldap_sid = $attribute[$conf->global->LDAP_FIELD_SID];
     				}
    @@ -1000,7 +1006,7 @@ if ($action == 'create' || $action == 'adduserldap')
     	print '</td></tr>';
     
     	// Skype
    -	if (! empty($conf->skype->enabled))
    +	if (! empty($conf->socialnetworks->enabled))
     	{
     		print '<tr><td>'.$langs->trans("Skype").'</td>';
     		print '<td>';
    @@ -1011,7 +1017,41 @@ if ($action == 'create' || $action == 'adduserldap')
     		}
     		else
     		{
    -			print '<input class="maxwidth200" type="text" name="skype" value="'.GETPOST('skype').'">';
    +			print '<input class="maxwidth200" type="text" name="skype" value="'.GETPOST('skype','alpha').'">';
    +		}
    +		print '</td></tr>';
    +	}
    +
    +	// Twitter
    +	if (! empty($conf->socialnetworks->enabled))
    +	{
    +		print '<tr><td>'.$langs->trans("Twitter").'</td>';
    +		print '<td>';
    +		if (! empty($ldap_twitter))
    +		{
    +			print '<input type="hidden" name="twitter" value="'.$ldap_twitter.'">';
    +			print $ldap_twitter;
    +		}
    +		else
    +		{
    +			print '<input class="maxwidth200" type="text" name="twitter" value="'.GETPOST('twitter','alpha').'">';
    +		}
    +		print '</td></tr>';
    +	}
    +
    +	// Facebook
    +	if (! empty($conf->socialnetworks->enabled))
    +	{
    +		print '<tr><td>'.$langs->trans("Facebook").'</td>';
    +		print '<td>';
    +		if (! empty($ldap_facebook))
    +		{
    +			print '<input type="hidden" name="facebook" value="'.$ldap_facebook.'">';
    +			print $ldap_facebook;
    +		}
    +		else
    +		{
    +			print '<input class="maxwidth200" type="text" name="facebook" value="'.GETPOST('facebook','alpha').'">';
     		}
     		print '</td></tr>';
     	}
    @@ -1343,7 +1383,7 @@ else
     			// Password
     			print '<tr><td>'.$langs->trans("Password").'</td>';
     
    -			print '<td>';
    +			print '<td class="wordbreak">';
     			$valuetoshow='';
     			if (preg_match('/ldap/',$dolibarr_main_authentication))
     			{
    @@ -2195,7 +2235,7 @@ else
     			print '</td></tr>';
     
     			// Skype
    -			if (! empty($conf->skype->enabled))
    +			if (! empty($conf->socialnetworks->enabled))
     			{
     				print '<tr><td>'.$langs->trans("Skype").'</td>';
     				print '<td>';
    @@ -2211,6 +2251,40 @@ else
     				print '</td></tr>';
     			}
     
    +			// Twitter
    +			if (! empty($conf->socialnetworks->enabled))
    +			{
    +				print '<tr><td>'.$langs->trans("Twitter").'</td>';
    +				print '<td>';
    +				if ($caneditfield  && empty($object->ldap_sid))
    +				{
    +					print '<input size="40" type="text" name="twitter" class="flat" value="'.$object->twitter.'">';
    +				}
    +				else
    +				{
    +					print '<input type="hidden" name="twitter" value="'.$object->twitter.'">';
    +					print $object->twitter;
    +				}
    +				print '</td></tr>';
    +			}
    +
    +			// Skype
    +			if (! empty($conf->socialnetworks->enabled))
    +			{
    +				print '<tr><td>'.$langs->trans("Facebook").'</td>';
    +				print '<td>';
    +				if ($caneditfield  && empty($object->ldap_sid))
    +				{
    +					print '<input size="40" type="text" name="facebook" class="flat" value="'.$object->facebook.'">';
    +				}
    +				else
    +				{
    +					print '<input type="hidden" name="facebook" value="'.$object->facebook.'">';
    +					print $object->facebook;
    +				}
    +				print '</td></tr>';
    +			}
    +
     			// EMail
     			print "<tr>".'<td'.(! empty($conf->global->USER_MAIL_REQUIRED)?' class="fieldrequired"':'').'>'.$langs->trans("EMail").'</td>';
     			print '<td>';
    @@ -2285,7 +2359,7 @@ else
     			{
     				print '<tr><td>' . fieldLabel( 'Categories', 'usercats' ) . '</td>';
     				print '<td>';
    -				$cate_arbo = $form->select_all_categories( Categorie::TYPE_CONTACT, null, null, null, null, 1 );
    +				$cate_arbo = $form->select_all_categories( Categorie::TYPE_USER, null, null, null, null, 1 );
     				$c = new Categorie( $db );
     				$cats = $c->containing($object->id, Categorie::TYPE_USER);
     				foreach ($cats as $cat) {
    diff --git a/htdocs/user/class/user.class.php b/htdocs/user/class/user.class.php
    index 9020cd3a4bc..d2afacce54a 100644
    --- a/htdocs/user/class/user.class.php
    +++ b/htdocs/user/class/user.class.php
    @@ -50,8 +50,16 @@ class User extends CommonObject
     	 */
     	public $table_element='user';
     
    +	/**
    +	 * @var int Field with ID of parent key if this field has a parent
    +	 */
     	public $fk_element='fk_user';
    -	public $ismultientitymanaged = 1;	// 0=No test on entity, 1=Test with field entity, 2=Test with link by societe
    +
    +	/**
    +	 * 0=No test on entity, 1=Test with field entity, 2=Test with link by societe
    +	 * @var int
    +	 */
    +	public $ismultientitymanaged = 1;
     
     	public $id=0;
     	public $statut;
    @@ -61,10 +69,19 @@ class User extends CommonObject
     	public $gender;
     	public $birth;
     	public $email;
    +
     	public $skype;
    +	public $twitter;
    +	public $facebook;
    +
     	public $job;			// job position
     	public $signature;
    +
    +	/**
    +	 * @var string Address
    +	 */
     	public $address;
    +
     	public $zip;
     	public $town;
     	public $state_id;		// The state/department
    @@ -106,6 +123,9 @@ class User extends CommonObject
     	public $socid;
     	public $contactid;
     
    +	/**
    +     * @var int ID
    +     */
     	public $fk_member;
     
     	/**
    @@ -207,7 +227,8 @@ class User extends CommonObject
     		$login=trim($login);
     
     		// Get user
    -		$sql = "SELECT u.rowid, u.lastname, u.firstname, u.employee, u.gender, u.birth, u.email, u.job, u.skype, u.signature, u.office_phone, u.office_fax, u.user_mobile,";
    +		$sql = "SELECT u.rowid, u.lastname, u.firstname, u.employee, u.gender, u.birth, u.email, u.job, u.skype, u.twitter, u.facebook,";
    +		$sql.= " u.signature, u.office_phone, u.office_fax, u.user_mobile,";
     		$sql.= " u.address, u.zip, u.town, u.fk_state as state_id, u.fk_country as country_id,";
     		$sql.= " u.admin, u.login, u.note,";
     		$sql.= " u.pass, u.pass_crypted, u.pass_temp, u.api_key,";
    @@ -312,6 +333,8 @@ class User extends CommonObject
     				$this->user_mobile  = $obj->user_mobile;
     				$this->email		= $obj->email;
     				$this->skype		= $obj->skype;
    +				$this->twitter		= $obj->twitter;
    +				$this->facebook		= $obj->facebook;
     				$this->job			= $obj->job;
     				$this->signature	= $obj->signature;
     				$this->admin		= $obj->admin;
    @@ -1207,6 +1230,8 @@ class User extends CommonObject
     		$this->gender		= $contact->gender;
     		$this->email		= $contact->email;
     		$this->skype 		= $contact->skype;
    +		$this->twitter 		= $contact->twitter;
    +		$this->facebook		= $contact->facebook;
     		$this->office_phone	= $contact->phone_pro;
     		$this->office_fax	= $contact->fax;
     		$this->user_mobile	= $contact->phone_mobile;
    @@ -1420,7 +1445,11 @@ class User extends CommonObject
     		$this->office_fax   = trim($this->office_fax);
     		$this->user_mobile  = trim($this->user_mobile);
     		$this->email        = trim($this->email);
    +
     		$this->skype        = trim($this->skype);
    +		$this->twitter      = trim($this->twitter);
    +		$this->facebook     = trim($this->facebook);
    +
     		$this->job    		= trim($this->job);
     		$this->signature    = trim($this->signature);
     		$this->note         = trim($this->note);
    @@ -1470,6 +1499,8 @@ class User extends CommonObject
     		$sql.= ", user_mobile = '".$this->db->escape($this->user_mobile)."'";
     		$sql.= ", email = '".$this->db->escape($this->email)."'";
     		$sql.= ", skype = '".$this->db->escape($this->skype)."'";
    +		$sql.= ", twitter = '".$this->db->escape($this->twitter)."'";
    +		$sql.= ", facebook = '".$this->db->escape($this->facebook)."'";
     		$sql.= ", job = '".$this->db->escape($this->job)."'";
     		$sql.= ", signature = '".$this->db->escape($this->signature)."'";
     		$sql.= ", accountancy_code = '".$this->db->escape($this->accountancy_code)."'";
    @@ -1554,7 +1585,11 @@ class User extends CommonObject
     						$adh->country_id=$this->country_id;
     
     						$adh->email=$this->email;
    +
     						$adh->skype=$this->skype;
    +						$adh->twitter=$this->twitter;
    +						$adh->facebook=$this->facebook;
    +
     						$adh->phone=$this->office_phone;
     						$adh->phone_mobile=$this->user_mobile;
     
    @@ -1602,7 +1637,11 @@ class User extends CommonObject
     						//$tmpobj->societe=(empty($tmpobj->societe) && $this->societe_id ? $this->societe_id : $tmpobj->societe);
     
     						$tmpobj->email=$this->email;
    +
     						$tmpobj->skype=$this->skype;
    +						$tmpobj->twitter=$this->twitter;
    +						$tmpobj->facebook=$this->facebook;
    +
     						$tmpobj->phone_pro=$this->office_phone;
     						$tmpobj->phone_mobile=$this->user_mobile;
     						$tmpobj->fax=$this->office_fax;
    @@ -2461,13 +2500,15 @@ class User extends CommonObject
     			'LDAP_FIELD_NAME'		=> 'lastname',
     			'LDAP_FIELD_FIRSTNAME'	=> 'firstname',
     			'LDAP_FIELD_LOGIN'		=> 'login',
    -			'LDAP_FIELD_LOGIN_SAMBA'	=> 'login',
    +			'LDAP_FIELD_LOGIN_SAMBA'=> 'login',
     			'LDAP_FIELD_PHONE'		=> 'office_phone',
     			'LDAP_FIELD_MOBILE'		=> 'user_mobile',
    -			'LDAP_FIELD_FAX'			=> 'office_fax',
    +			'LDAP_FIELD_FAX'		=> 'office_fax',
     			'LDAP_FIELD_MAIL'		=> 'email',
    -			'LDAP_FIELD_SID'			=> 'ldap_sid',
    -			'LDAP_FIELD_SKYPE'		=> 'skype'
    +			'LDAP_FIELD_SID'		=> 'ldap_sid',
    +			'LDAP_FIELD_SKYPE'		=> 'skype',
    +			'LDAP_FIELD_TWITTER'	=> 'twitter',
    +			'LDAP_FIELD_FACEBOOK'	=> 'facebook'
     		);
     
     		// Champs
    @@ -2578,7 +2619,9 @@ class User extends CommonObject
     		$this->gender='man';
     		$this->note='This is a note';
     		$this->email='email@specimen.com';
    -		$this->skype='tom.hanson';
    +		$this->skype='skypepseudo';
    +		$this->twitter='twitterpseudo';
    +		$this->facebook='facebookpseudo';
     		$this->office_phone='0999999999';
     		$this->office_fax='0999999998';
     		$this->user_mobile='0999999997';
    @@ -2732,6 +2775,8 @@ class User extends CommonObject
     		$this->office_fax=$ldapuser->{$conf->global->LDAP_FIELD_FAX};
     		$this->email=$ldapuser->{$conf->global->LDAP_FIELD_MAIL};
     		$this->skype=$ldapuser->{$conf->global->LDAP_FIELD_SKYPE};
    +		$this->twitter=$ldapuser->{$conf->global->LDAP_FIELD_TWITTER};
    +		$this->facebook=$ldapuser->{$conf->global->LDAP_FIELD_FACEBOOK};
     		$this->ldap_sid=$ldapuser->{$conf->global->LDAP_FIELD_SID};
     
     		$this->job=$ldapuser->{$conf->global->LDAP_FIELD_TITLE};
    diff --git a/htdocs/user/class/usergroup.class.php b/htdocs/user/class/usergroup.class.php
    index e3ada6efcac..6f3e333f6f5 100644
    --- a/htdocs/user/class/usergroup.class.php
    +++ b/htdocs/user/class/usergroup.class.php
    @@ -45,7 +45,11 @@ class UserGroup extends CommonObject
     	 */
     	public $table_element='usergroup';
     
    -	public $ismultientitymanaged = 1;	// 0=No test on entity, 1=Test with field entity, 2=Test with link by societe
    +	/**
    +	 * 0=No test on entity, 1=Test with field entity, 2=Test with link by societe
    +	 * @var int
    +	 */
    +	public $ismultientitymanaged = 1;
     
         public $picto='group';
     
    diff --git a/htdocs/user/clicktodial.php b/htdocs/user/clicktodial.php
    index bfab243bbaf..6719d6ca120 100644
    --- a/htdocs/user/clicktodial.php
    +++ b/htdocs/user/clicktodial.php
    @@ -102,7 +102,7 @@ if ($id > 0)
     	$linkback = '';
     
     	if ($user->rights->user->user->lire || $user->admin) {
    -		$linkback = '<a href="'.DOL_URL_ROOT.'/user/list.php">'.$langs->trans("BackToList").'</a>';
    +		$linkback = '<a href="'.DOL_URL_ROOT.'/user/list.php?restore_lastsearch_values=1">'.$langs->trans("BackToList").'</a>';
     	}
     
         dol_banner_tab($object,'id',$linkback,$user->rights->user->user->lire || $user->admin);
    diff --git a/htdocs/user/document.php b/htdocs/user/document.php
    index 3088320e50c..decc53a379c 100644
    --- a/htdocs/user/document.php
    +++ b/htdocs/user/document.php
    @@ -133,7 +133,7 @@ if ($object->id)
     
     	$linkback = '';
     	if ($user->rights->user->user->lire || $user->admin) {
    -		$linkback = '<a href="'.DOL_URL_ROOT.'/user/list.php">'.$langs->trans("BackToList").'</a>';
    +		$linkback = '<a href="'.DOL_URL_ROOT.'/user/list.php?restore_lastsearch_values=1">'.$langs->trans("BackToList").'</a>';
     	}
     
         dol_banner_tab($object,'id',$linkback,$user->rights->user->user->lire || $user->admin);
    diff --git a/htdocs/user/info.php b/htdocs/user/info.php
    index 8fba36a3e8a..bb262804d33 100644
    --- a/htdocs/user/info.php
    +++ b/htdocs/user/info.php
    @@ -72,7 +72,7 @@ dol_fiche_head($head, 'info', $title, -1, 'user');
     $linkback = '';
     
     if ($user->rights->user->user->lire || $user->admin) {
    -	$linkback = '<a href="'.DOL_URL_ROOT.'/user/list.php">'.$langs->trans("BackToList").'</a>';
    +	$linkback = '<a href="'.DOL_URL_ROOT.'/user/list.php?restore_lastsearch_values=1">'.$langs->trans("BackToList").'</a>';
     }
     
     dol_banner_tab($object, 'id', $linkback, $user->rights->user->user->lire || $user->admin);
    diff --git a/htdocs/user/ldap.php b/htdocs/user/ldap.php
    index 4a4ffeb875d..fa5e5e023eb 100644
    --- a/htdocs/user/ldap.php
    +++ b/htdocs/user/ldap.php
    @@ -98,7 +98,7 @@ dol_fiche_head($head, 'ldap', $title, 0, 'user');
     $linkback = '';
     
     if ($user->rights->user->user->lire || $user->admin) {
    -	$linkback = '<a href="'.DOL_URL_ROOT.'/user/list.php">'.$langs->trans("BackToList").'</a>';
    +	$linkback = '<a href="'.DOL_URL_ROOT.'/user/list.php?restore_lastsearch_values=1">'.$langs->trans("BackToList").'</a>';
     }
     
     dol_banner_tab($object,'id',$linkback,$user->rights->user->user->lire || $user->admin);
    diff --git a/htdocs/user/list.php b/htdocs/user/list.php
    index 088148ba4af..64c63c05426 100644
    --- a/htdocs/user/list.php
    +++ b/htdocs/user/list.php
    @@ -26,6 +26,9 @@
      */
     
     require '../main.inc.php';
    +require_once DOL_DOCUMENT_ROOT.'/core/class/html.formother.class.php';
    +if (! empty($conf->categorie->enabled))
    +	require_once DOL_DOCUMENT_ROOT.'/categories/class/categorie.class.php';
     
     if (! $user->rights->user->user->lire && ! $user->admin)
     	accessforbidden();
    @@ -123,10 +126,12 @@ $search_thirdparty=GETPOST('search_thirdparty','alpha');
     $search_supervisor=GETPOST('search_supervisor','intcomma');
     $search_previousconn=GETPOST('search_previousconn','alpha');
     $optioncss = GETPOST('optioncss','alpha');
    +$search_categ = GETPOST("search_categ",'int');
    +$catid = GETPOST('catid','int');
     
     // Default search
     if ($search_statut == '') $search_statut='1';
    -if ($mode == 'employee') $search_employee=1;
    +if ($mode == 'employee' && ! GETPOSTISSET('search_employee')) $search_employee=1;
     
     
     
    @@ -165,6 +170,7 @@ if (empty($reshook))
     		$search_date_creation="";
     		$search_date_update="";
     		$search_array_options=array();
    +        $search_categ=0;
     	}
     }
     
    @@ -173,6 +179,8 @@ if (empty($reshook))
      * View
      */
     
    +$htmlother=new FormOther($db);
    +
     $user2=new User($db);
     
     $buttonviewhierarchy='<form action="'.DOL_URL_ROOT.'/user/hierarchy.php'.(($search_statut != '' && $search_statut >= 0) ? '?search_statut='.$search_statut : '').'" method="POST"><input type="submit" class="button" style="width:120px" name="viewcal" value="'.dol_escape_htmltag($langs->trans("HierarchicView")).'"></form>';
    @@ -193,6 +201,7 @@ $sql.= " FROM ".MAIN_DB_PREFIX."user as u";
     if (is_array($extrafields->attribute_label) && count($extrafields->attribute_label)) $sql.= " LEFT JOIN ".MAIN_DB_PREFIX."user_extrafields as ef on (u.rowid = ef.fk_object)";
     $sql.= " LEFT JOIN ".MAIN_DB_PREFIX."societe as s ON u.fk_soc = s.rowid";
     $sql.= " LEFT JOIN ".MAIN_DB_PREFIX."user as u2 ON u.fk_user = u2.rowid";
    +if (! empty($search_categ) || ! empty($catid)) $sql.= ' LEFT JOIN '.MAIN_DB_PREFIX."categorie_user as cu ON u.rowid = cu.fk_user"; // We'll need this table joined to the select in order to filter by categ
     // Add fields from hooks
     $parameters=array();
     $reshook=$hookmanager->executeHooks('printUserListWhere',$parameters);    // Note that $action and $object may have been modified by hook
    @@ -216,6 +225,10 @@ if ($search_accountancy_code != '')  $sql.= natural_search("u.accountancy_code",
     if ($search_email != '')             $sql.= natural_search("u.email", $search_email);
     if ($search_statut != '' && $search_statut >= 0) $sql.= " AND u.statut IN (".$db->escape($search_statut).")";
     if ($sall)                           $sql.= natural_search(array_keys($fieldstosearchall), $sall);
    +if ($catid > 0)     $sql.= " AND cu.fk_categorie = ".$catid;
    +if ($catid == -2)   $sql.= " AND cu.fk_categorie IS NULL";
    +if ($search_categ > 0)   $sql.= " AND cu.fk_categorie = ".$db->escape($search_categ);
    +if ($search_categ == -2) $sql.= " AND cu.fk_categorie IS NULL";
     // Add where from extra fields
     include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_list_search_sql.tpl.php';
     // Add where from hooks
    @@ -268,6 +281,7 @@ if ($search_supervisor > 0) $param.="&search_supervisor=".$search_supervisor;
     if ($search_statut != '') $param.="&search_statut=".$search_statut;
     if ($optioncss != '') $param.='&optioncss='.$optioncss;
     if ($mode != '')      $param.='&mode='.$mode;
    +if ($search_categ > 0) $param.="&search_categ=".urlencode($search_categ);
     // Add $param from extra fields
     include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_list_search_param.tpl.php';
     
    @@ -296,6 +310,15 @@ $morehtmlright = '<a class="nohover" href="'.DOL_URL_ROOT.'/user/hierarchy.php'.
     
     print_barre_liste($text, $page, $_SERVER["PHP_SELF"], $param, $sortfield, $sortorder, "", $num, $nbtotalofrecords, 'title_generic', 0, $morehtmlright.' '.$newcardbutton, '', $limit);
     
    +if (! empty($catid))
    +{
    +    print "<div id='ways'>";
    +    $c = new Categorie($db);
    +    $ways = $c->print_all_ways(' &gt; ','user/list.php');
    +    print " &gt; ".$ways[0]."<br>\n";
    +    print "</div><br>";
    +}
    +
     if ($sall)
     {
     	foreach($fieldstosearchall as $key => $val) $fieldstosearchall[$key]=$langs->trans($val);
    @@ -304,7 +327,29 @@ if ($sall)
     
     $moreforfilter='';
     
    +// Filter on categories
    +if (! empty($conf->categorie->enabled))
    +{
    +    $moreforfilter.='<div class="divsearchfield">';
    +    $moreforfilter.=$langs->trans('Categories'). ': ';
    +    $moreforfilter.=$htmlother->select_categories(Categorie::TYPE_USER,$search_categ,'search_categ',1);
    +    $moreforfilter.='</div>';
    +}
    +
    +$parameters=array();
    +$reshook=$hookmanager->executeHooks('printFieldPreListTitle',$parameters);    // Note that $action and $object may have been modified by hook
    +if (empty($reshook)) $moreforfilter.=$hookmanager->resPrint;
    +else $moreforfilter=$hookmanager->resPrint;
    +
    +if ($moreforfilter)
    +{
    +    print '<div class="liste_titre liste_titre_bydiv centpercent">';
    +    print $moreforfilter;
    +    print '</div>';
    +}
    +
     $varpage=empty($contextpage)?$_SERVER["PHP_SELF"]:$contextpage;
    +
     $selectedfields=$form->multiSelectArrayWithCheckbox('selectedfields', $arrayfields, $varpage);	// This also change content of $arrayfields
     
     
    diff --git a/htdocs/user/note.php b/htdocs/user/note.php
    index 5e1c33cb57d..1cf994db9e9 100644
    --- a/htdocs/user/note.php
    +++ b/htdocs/user/note.php
    @@ -93,7 +93,7 @@ if ($id)
     	$linkback = '';
     
     	if ($user->rights->user->user->lire || $user->admin) {
    -		$linkback = '<a href="'.DOL_URL_ROOT.'/user/list.php">'.$langs->trans("BackToList").'</a>';
    +		$linkback = '<a href="'.DOL_URL_ROOT.'/user/list.php?restore_lastsearch_values=1">'.$langs->trans("BackToList").'</a>';
     	}
     
         dol_banner_tab($object,'id',$linkback,$user->rights->user->user->lire || $user->admin);
    diff --git a/htdocs/user/notify/card.php b/htdocs/user/notify/card.php
    index 575af204618..f4e06075e79 100644
    --- a/htdocs/user/notify/card.php
    +++ b/htdocs/user/notify/card.php
    @@ -137,7 +137,7 @@ if ($result > 0)
     
         dol_fiche_head($head, 'notify', $langs->trans("User"), -1, 'user');
     
    -    $linkback = '<a href="'.DOL_URL_ROOT.'/user/list.php">'.$langs->trans("BackToList").'</a>';
    +    $linkback = '<a href="'.DOL_URL_ROOT.'/user/list.php?restore_lastsearch_values=1">'.$langs->trans("BackToList").'</a>';
     
         dol_banner_tab($object, 'id', $linkback, $user->rights->user->user->lire || $user->admin, 'rowid', 'ref', '', '', 0, '', '', 0, '');
     
    diff --git a/htdocs/user/param_ihm.php b/htdocs/user/param_ihm.php
    index 563ff54c490..521b0e4022e 100644
    --- a/htdocs/user/param_ihm.php
    +++ b/htdocs/user/param_ihm.php
    @@ -195,7 +195,7 @@ if ($action == 'edit')
     	$linkback = '';
     
     	if ($user->rights->user->user->lire || $user->admin) {
    -		$linkback = '<a href="'.DOL_URL_ROOT.'/user/list.php">'.$langs->trans("BackToList").'</a>';
    +		$linkback = '<a href="'.DOL_URL_ROOT.'/user/list.php?restore_lastsearch_values=1">'.$langs->trans("BackToList").'</a>';
     	}
     
         dol_banner_tab($object,'id',$linkback,$user->rights->user->user->lire || $user->admin);
    diff --git a/htdocs/user/perms.php b/htdocs/user/perms.php
    index e6487cba47c..8b7599f3707 100644
    --- a/htdocs/user/perms.php
    +++ b/htdocs/user/perms.php
    @@ -239,13 +239,13 @@ else
     $linkback = '';
     
     if ($user->rights->user->user->lire || $user->admin) {
    -	$linkback = '<a href="'.DOL_URL_ROOT.'/user/list.php">'.$langs->trans("BackToList").'</a>';
    +	$linkback = '<a href="'.DOL_URL_ROOT.'/user/list.php?restore_lastsearch_values=1">'.$langs->trans("BackToList").'</a>';
     }
     
     dol_banner_tab($object,'id',$linkback,$user->rights->user->user->lire || $user->admin);
     
     
    -//print '<div class="underbanner clearboth"></div>';
    +print '<div class="underbanner clearboth"></div>';
     
     if ($user->admin) print info_admin($langs->trans("WarningOnlyPermissionOfActivatedModules"));
     // Show warning about external users
    @@ -257,6 +257,7 @@ if ($reshook < 0) setEventMessages($hookmanager->error, $hookmanager->errors, 'e
     
     
     print "\n";
    +print '<div class="div-table-responsive">';
     print '<table width="100%" class="noborder">';
     print '<tr class="liste_titre">';
     print '<td>'.$langs->trans("Module").'</td>';
    @@ -392,6 +393,7 @@ if ($result)
     }
     else dol_print_error($db);
     print '</table>';
    +print '</div>';
     
     $parameters=array();
     $reshook=$hookmanager->executeHooks('insertExtraFooter',$parameters,$object,$action);    // Note that $action and $object may have been modified by some hooks
    diff --git a/htdocs/variants/card.php b/htdocs/variants/card.php
    index be73db1fff0..8cb4e13b33e 100644
    --- a/htdocs/variants/card.php
    +++ b/htdocs/variants/card.php
    @@ -133,7 +133,6 @@ if ($confirm == 'yes') {
     $langs->load('products');
     
     $title = $langs->trans('ProductAttributeName', dol_htmlentities($object->label));
    -$var = false;
     
     llxHeader('', $title);
     
    diff --git a/htdocs/variants/class/ProductCombination.class.php b/htdocs/variants/class/ProductCombination.class.php
    index 58eb2178da4..a0aed832eac 100644
    --- a/htdocs/variants/class/ProductCombination.class.php
    +++ b/htdocs/variants/class/ProductCombination.class.php
    @@ -1,6 +1,7 @@
     <?php
     
     /* Copyright (C) 2016	Marcos García	<marcosgdf@gmail.com>
    + * Copyright (C) 2018	Juanjo Menent	<jmenent@2byte.es>
      *
      * This program is free software; you can redistribute it and/or modify
      * it under the terms of the GNU General Public License as published by
    @@ -329,6 +330,8 @@ class ProductCombination
     		$child->price_autogen = $parent->price_autogen;
     		$child->weight = $parent->weight + $this->variation_weight;
     		$child->weight_units = $parent->weight_units;
    +		$varlabel = $this->getCombinationLabel($this->fk_product_child);
    +		$child->label = $parent->label.$varlabel;
     
     		if ($child->update($child->id, $user) > 0) {
     
    @@ -337,14 +340,33 @@ class ProductCombination
     
     			// MultiPrix
     			if (! empty($conf->global->PRODUIT_MULTIPRICES)) {
    -				$new_type = $parent->multiprices_base_type[1];
    -				$new_min_price = $parent->multiprices_min[1];
    -				$new_psq = $parent->multiprices_recuperableonly[1];
    +				for ($i=1; $i <= $conf->global->PRODUIT_MULTIPRICES_LIMIT; $i++)
    +				{
    +					if ($parent->multiprices[$i] != '') {
    +						$new_type = $parent->multiprices_base_type[$i];
    +						$new_min_price = $parent->multiprices_min[$i];
    +						if ($parent->prices_by_qty_list[$i]) {
    +							$new_psq = 1;
    +						} else {
    +							$new_psq = 0;
    +						}
     
    -				if ($new_type == 'TTC') {
    -					$new_price = $parent->multiprices_ttc[1];
    -				} else {
    -					$new_price = $parent->multiprices[1];
    +						if ($new_type == 'TTC') {
    +							$new_price = $parent->multiprices_ttc[$i];
    +						} else {
    +							$new_price = $parent->multiprices[$i];
    +						}
    +
    +						if ($this->variation_price_percentage) {
    +							if ($new_price != 0) {
    +								$new_price *= 1 + ($this->variation_price / 100);
    +							}
    +						} else {
    +							$new_price += $this->variation_price;
    +						}
    +
    +						$child->updatePrice($new_price, $new_type, $user, $new_vat, $new_min_price, $i, $new_npr, $new_psq);
    +					}
     				}
     			} else {
     				$new_type = $parent->price_base_type;
    @@ -356,15 +378,17 @@ class ProductCombination
     				} else {
     					$new_price = $parent->price;
     				}
    -			}
     
    -			if ($this->variation_price_percentage) {
    -				$new_price *= 1 + ($this->variation_price/100);
    -			} else {
    -				$new_price += $this->variation_price;
    -			}
    +				if ($this->variation_price_percentage) {
    +					if ($new_price != 0) {
    +						$new_price *= 1 + ($this->variation_price / 100);
    +					}
    +				} else {
    +					$new_price += $this->variation_price;
    +				}
     
    -			$child->updatePrice($new_price, $new_type, $user, $new_vat, $new_min_price, 1, $new_npr, $new_psq);
    +				$child->updatePrice($new_price, $new_type, $user, $new_vat, $new_min_price, 1, $new_npr, $new_psq);
    +			}
     
     			$this->db->commit();
     
    @@ -634,7 +658,7 @@ WHERE c.fk_product_parent = ".(int) $productid." AND p.tosell = 1";
     		}
     
     		$db->commit();
    -		return 1;
    +		return $newproduct->id;
     	}
     
     	/**
    @@ -681,4 +705,39 @@ WHERE c.fk_product_parent = ".(int) $productid." AND p.tosell = 1";
     
     		return 1;
     	}
    +
    +	/**
    +	 * Return label for combinations
    +	 * @param 	int 	$prod_child		id of child
    +	 * @return 	string					combination label
    +	 */
    +	public function getCombinationLabel($prod_child)
    +	{
    +		$label = '';
    +		$sql = 'SELECT pav.value AS label';
    +		$sql.= ' FROM '.MAIN_DB_PREFIX.'product_attribute_combination pac';
    +		$sql.= ' INNER JOIN '.MAIN_DB_PREFIX.'product_attribute_combination2val pac2v ON pac2v.fk_prod_combination=pac.rowid';
    +		$sql.= ' INNER JOIN '.MAIN_DB_PREFIX.'product_attribute_value pav ON pav.rowid=pac2v.fk_prod_attr_val';
    +		$sql.= ' WHERE pac.fk_product_child='.$prod_child;
    +
    +		$resql = $this->db->query($sql);
    +		if ($resql) {
    +			$num = $this->db->num_rows($resql);
    +
    +			$i = 0;
    +
    +			while ($i < $num)
    +			{
    +				$obj = $this->db->fetch_object($resql);
    +
    +				if ($obj->label)
    +				{
    +					$label.=' '.$obj->label;
    +				}
    +				$i++;
    +			}
    +
    +		}
    +		return $label;
    +	}
     }
    diff --git a/htdocs/variants/combinations.php b/htdocs/variants/combinations.php
    index 0d1ea7af03b..fb23921be25 100644
    --- a/htdocs/variants/combinations.php
    +++ b/htdocs/variants/combinations.php
    @@ -27,7 +27,6 @@ require_once DOL_DOCUMENT_ROOT.'/variants/class/ProductCombination2ValuePair.cla
     
     $langs->loadLangs(array("products", "other"));
     
    -$var = false;
     $id = GETPOST('id', 'int');
     $valueid = GETPOST('valueid', 'int');
     $ref = GETPOST('ref');
    @@ -319,6 +318,66 @@ if (! empty($id) || ! empty($ref))
     
         dol_banner_tab($object, 'ref', $linkback, ($user->societe_id?0:1), 'ref', '', '', '', 0, '', '', 1);
     
    +	print '<div class="fichecenter">';
    +
    +	print '<div class="underbanner clearboth"></div>';
    +	print '<table class="border tableforfield" width="100%">';
    +
    +    // TVA
    +    print '<tr><td class="titlefield">' . $langs->trans("DefaultTaxRate") . '</td><td>';
    +
    +    $positiverates='';
    +    if (price2num($object->tva_tx))       $positiverates.=($positiverates?'/':'').price2num($object->tva_tx);
    +    if (price2num($object->localtax1_type)) $positiverates.=($positiverates?'/':'').price2num($object->localtax1_tx);
    +    if (price2num($object->localtax2_type)) $positiverates.=($positiverates?'/':'').price2num($object->localtax2_tx);
    +    if (empty($positiverates)) $positiverates='0';
    +    echo vatrate($positiverates.($object->default_vat_code?' ('.$object->default_vat_code.')':''), '%', $object->tva_npr);
    +    /*
    +    if ($object->default_vat_code)
    +    {
    +        print vatrate($object->tva_tx, true) . ' ('.$object->default_vat_code.')';
    +    }
    +    else print vatrate($object->tva_tx, true, $object->tva_npr, true);*/
    +    print '</td></tr>';
    +
    +    // Price
    +    print '<tr><td>' . $langs->trans("SellingPrice") . '</td><td>';
    +    if ($object->price_base_type == 'TTC') {
    +        print price($object->price_ttc) . ' ' . $langs->trans($object->price_base_type);
    +    } else {
    +        print price($object->price) . ' ' . $langs->trans($object->price_base_type);
    +    }
    +    print '</td></tr>';
    +
    +    // Price minimum
    +    print '<tr><td>' . $langs->trans("MinPrice") . '</td><td>';
    +    if ($object->price_base_type == 'TTC') {
    +        print price($object->price_min_ttc) . ' ' . $langs->trans($object->price_base_type);
    +    } else {
    +        print price($object->price_min) . ' ' . $langs->trans($object->price_base_type);
    +    }
    +    print '</td></tr>';
    +
    +	// Weight
    +	print '<tr><td>'.$langs->trans("Weight").'</td><td>';
    +	if ($object->weight != '')
    +	{
    +		print $object->weight." ".measuring_units_string($object->weight_units,"weight");
    +	}
    +	else
    +	{
    +		print '&nbsp;';
    +	}
    +	print "</td></tr>\n";
    +
    +
    +
    +
    +	print "</table>\n";
    +
    +	print '</div>';
    +	print '<div style="clear:both"></div>';
    +
     	dol_fiche_end();
     
     
    @@ -327,7 +386,7 @@ if (! empty($id) || ! empty($ref))
     
     		if ($action == 'add') {
     			$title = $langs->trans('NewProductCombination');
    -			print dol_fiche_head();
    +			//print dol_fiche_head();
     			$features = $_SESSION['addvariant_'.$object->id];
     			//First, sanitize
     			print '<div id="parttoaddvariant">';
    @@ -348,7 +407,8 @@ if (! empty($id) || ! empty($ref))
     				}
     			}
     			print '</div>';
    -			print dol_fiche_end();
    +			print '<br><br>';
    +			//print dol_fiche_end();
     		} else {
     			$title = $langs->trans('EditProductCombination');
     		}
    @@ -634,12 +694,14 @@ if (! empty($id) || ! empty($ref))
     		print '<div class="tabsAction">';
     
     		print '	<div class="inline-block divButAction">';
    -		if ($productCombinations) {
    -		    print '<a href="combinations.php?id='.$object->id.'&action=copy" class="butAction">'.$langs->trans('PropagateVariant').'</a>';
    -		}
     
     		print '<a href="combinations.php?id='.$object->id.'&action=add" class="butAction">'.$langs->trans('NewProductCombination').'</a>'; // NewVariant
     
    +		if ($productCombinations)
    +		{
    +			print '<a href="combinations.php?id='.$object->id.'&action=copy" class="butAction">'.$langs->trans('PropagateVariant').'</a>';
    +		}
    +
     		// Too much bugged page.
     		/*
     		print '<a href="generator.php?id='.$object->id.'" class="butAction">'.$langs->trans('ProductCombinationGenerator').'</a>';
    diff --git a/htdocs/website/class/website.class.php b/htdocs/website/class/website.class.php
    index 843304fbe45..3f51f669829 100644
    --- a/htdocs/website/class/website.class.php
    +++ b/htdocs/website/class/website.class.php
    @@ -1079,20 +1079,72 @@ class Website extends CommonObject
     	}
     
     	/**
    -	 * Component to select language (Full CSS Only)
    +	 * Component to select language inside a container (Full CSS Only)
     	 *
    -	 * @param	array		$languagecodes			Language codes array. Example: array('en_US','fr_FR','de_DE','es_ES')
    -	 * @param	Translate	$weblangs				Language Object
    -	 * @param	string		$morecss				More CSS class on component
    -	 * @param	string		$htmlname				Suffix for HTML name
    -	 * @return 	string								HTML select component
    +	 * @param	array|string	$languagecodes			'auto' to show all languages available for page, or language codes array like array('en_US','fr_FR','de_DE','es_ES')
    +	 * @param	Translate		$weblangs				Language Object
    +	 * @param	string			$morecss				More CSS class on component
    +	 * @param	string			$htmlname				Suffix for HTML name
    +	 * @return 	string									HTML select component
     	 */
     	public function componentSelectLang($languagecodes, $weblangs, $morecss='', $htmlname='')
     	{
    +		global $websitepagefile, $website;
    +
     		if (! is_object($weblangs)) return 'ERROR componentSelectLang called with parameter $weblangs not defined';
     
    -		$languagecodeselected = $weblangs->defaultlang;
    +		// Load tmppage if we have $websitepagefile defined
    +		$tmppage=new WebsitePage($this->db);
    +
    +		$pageid = 0;
    +		if (! empty($websitepagefile))
    +		{
    +			$pageid = str_replace(array('.tpl.php', 'page'), array('', ''), basename($websitepagefile));
    +			if ($pageid > 0)
    +			{
    +				$tmppage->fetch($pageid);
    +			}
    +		}
    +
    +		// Fill with existing translation, nothing if none
    +		if (! is_array($languagecodes) && $pageid > 0)
    +		{
    +			$languagecodes = array();
    +
    +			$sql ="SELECT wp.rowid, wp.lang, wp.pageurl, wp.fk_page";
    +			$sql.=" FROM ".MAIN_DB_PREFIX."website_page as wp";
    +			$sql.=" WHERE wp.fk_website = ".$website->id;
    +			$sql.=" AND (wp.fk_page = ".$pageid." OR wp.rowid  = ".$pageid;
    +			if ($tmppage->fk_page > 0) $sql.=" OR wp.fk_page = ".$tmppage->fk_page." OR wp.rowid = ".$tmppage->fk_page;
    +			$sql.=")";
    +
    +			$resql = $this->db->query($sql);
    +			if ($resql)
    +			{
    +				while ($obj = $this->db->fetch_object($resql))
    +				{
    +					$newlang = $obj->lang;
    +					if ($obj->rowid == $pageid) $newlang = $obj->lang;
    +					if (! in_array($newlang, $languagecodes)) $languagecodes[]=$newlang;
    +				}
    +			}
    +		}
    +		// Now $languagecodes is always an array
    +
    +		$languagecodeselected= $weblangs->defaultlang;	// Because we must init with a value, but real value is the lang of main parent container
    +		if (! empty($websitepagefile))
    +		{
    +			$pageid = str_replace(array('.tpl.php', 'page'), array('', ''), basename($websitepagefile));
    +			if ($pageid > 0)
    +			{
    +
    +				$languagecodeselected=$tmppage->lang;
    +				if (! in_array($tmppage->lang, $languagecodes)) $languagecodes[]=$tmppage->lang;	// We add language code of page into combo list
    +			}
    +		}
    +
     		$weblangs->load('languages');
    +		//var_dump($weblangs->defaultlang);
     
     		$url = $_SERVER["REQUEST_URI"];
     		$url = preg_replace('/(\?|&)l=([a-zA-Z_]*)/', '', $url);	// We remove param l from url
    @@ -1103,7 +1155,8 @@ class Website extends CommonObject
     		$MAXHEIGHT = 4 * $HEIGHTOPTION;
     		$nboflanguage = count($languagecodes);
     
    -		$out.='<!-- componentSelectLang'.$htmlname.' -->'."\n";
    +		$out ='<!-- componentSelectLang'.$htmlname.' -->'."\n";
    +
     		$out.= '<style>';
     		$out.= '.componentSelectLang'.$htmlname.':hover { height: '.min($MAXHEIGHT, ($HEIGHTOPTION * $nboflanguage)).'px; overflow-x: hidden; overflow-y: '.((($HEIGHTOPTION * $nboflanguage) > $MAXHEIGHT) ? ' scroll' : 'hidden').'; }'."\n";
     		$out.= '.componentSelectLang'.$htmlname.' li { line-height: '.$HEIGHTOPTION.'px; }'."\n";
    diff --git a/htdocs/website/class/websitepage.class.php b/htdocs/website/class/websitepage.class.php
    index 97aba5e6ac2..6f8713b5adc 100644
    --- a/htdocs/website/class/websitepage.class.php
    +++ b/htdocs/website/class/websitepage.class.php
    @@ -49,7 +49,11 @@ class WebsitePage extends CommonObject
     	 */
     	public $picto = 'label';
     
    +	/**
    +     * @var int ID
    +     */
     	public $fk_website;
    +
     	public $pageurl;
     	public $aliasalt;
     	public $type_container;
    @@ -64,7 +68,12 @@ class WebsitePage extends CommonObject
     	public $htmlheader;
     	public $content;
     	public $grabbed_from;
    +
    +	/**
    +	 * @var int Status
    +	 */
     	public $status;
    +
     	public $date_creation;
     	public $date_modification;
     
    @@ -188,8 +197,11 @@ class WebsitePage extends CommonObject
     
     				$this->fk_website = $obj->fk_website;
     				$this->type_container = $obj->type_container;
    +
     				$this->pageurl = $obj->pageurl;
    +				$this->ref = $obj->pageurl;
     				$this->aliasalt = preg_replace('/,+$/', '', preg_replace('/^,+/', '', $obj->aliasalt));
    +
     				$this->title = $obj->title;
     				$this->description = $obj->description;
     				$this->keywords = $obj->keywords;
    diff --git a/htdocs/website/index.php b/htdocs/website/index.php
    index 1d277c32ed7..f2bf4ad1888 100644
    --- a/htdocs/website/index.php
    +++ b/htdocs/website/index.php
    @@ -207,7 +207,7 @@ $htmlheadercontentdefault.='-->'."\n";
      * Actions
      */
     
    -$backtopage=$_SERVER["PHP_SELF"].'?file_manager=1&website='.$websitekey.'&pageid='.$pageid;	// used after a confirm_deletefile into actions_linkedfiles.inc.php
    +$backtopage=$_SERVER["PHP_SELF"].'?file_manager=1&website='.$websitekey.'&pageid='.$pageid.(GETPOST('section_dir','alpha')?'&section_dir='.urlencode(GETPOST('section_dir','alpha')):'');	// used after a confirm_deletefile into actions_linkedfiles.inc.php
     include DOL_DOCUMENT_ROOT.'/core/actions_linkedfiles.inc.php';
     
     if ($action == 'renamefile') $action='file_manager';		// After actions_linkedfiles, if action were renamefile, we set it to 'file_manager'
    @@ -459,6 +459,7 @@ if ($action == 'addcontainer')
     				//$objectpage->htmlheader = preg_replace('/<meta name="msvalidate.01[^>]*>\n*/ims', '', $objectpage->htmlheader);
     				$objectpage->htmlheader = preg_replace('/<title>[^<]*<\/title>\n*/ims', '', $objectpage->htmlheader);
     				$objectpage->htmlheader = preg_replace('/<link[^>]*rel="shortcut[^>]*>\n/ims', '', $objectpage->htmlheader);
    +				$objectpage->htmlheader = preg_replace('/<link[^>]*rel="canonical[^>]*>\n/ims', '', $objectpage->htmlheader);
     
     				// Now loop to fetch JS
     				$tmp = $objectpage->htmlheader;
    @@ -1749,7 +1750,7 @@ if (count($object->records) > 0)	// There is at least one web site
     
     		$htmltext = $langs->trans("PreviewSiteServedByDolibarr", $langs->transnoentitiesnoconv("Site"), $langs->transnoentitiesnoconv("Site"), $urlint, $dataroot);
     		$htmltext.='<br>'.$langs->trans("CheckVirtualHostPerms", $langs->transnoentitiesnoconv("ReadPerm"), DOL_DOCUMENT_ROOT);
    -		$htmltext.='<br>'.$langs->trans("CheckVirtualHostPerms", $langs->transnoentitiesnoconv("WritePerm"), DOL_DATA_ROOT);
    +		$htmltext.='<br>'.$langs->trans("CheckVirtualHostPerms", $langs->transnoentitiesnoconv("WritePerm"), DOL_DATA_ROOT.'/website<br>'.DOL_DATA_ROOT.'/medias');
     		print '<a class="websitebuttonsitepreview" id="previewsite" href="'.$urlwithroot.'/public/website/index.php?website='.$websitekey.'" target="tab'.$websitekey.'" alt="'.dol_escape_htmltag($htmltext).'">';
     		print $form->textwithpicto('', $htmltext, 1, 'preview');
     		print '</a>';
    @@ -1760,7 +1761,7 @@ if (count($object->records) > 0)	// There is at least one web site
     		$htmltext =$langs->trans("SetHereVirtualHost", $dataroot);
     		$htmltext.='<br>';
     		$htmltext.='<br>'.$langs->trans("CheckVirtualHostPerms", $langs->transnoentitiesnoconv("ReadPerm"), DOL_DOCUMENT_ROOT);
    -		$htmltext.='<br>'.$langs->trans("CheckVirtualHostPerms", $langs->transnoentitiesnoconv("WritePerm"), DOL_DATA_ROOT);
    +		$htmltext.='<br>'.$langs->trans("CheckVirtualHostPerms", $langs->transnoentitiesnoconv("WritePerm"), DOL_DATA_ROOT.'/website<br>'.DOL_DATA_ROOT.'/medias');
     		$htmltext.='<br>';
     		$htmltext.='<br>';
     		$htmltext.=$langs->trans("YouCanAlsoTestWithPHPS", $dataroot);
    @@ -1782,7 +1783,7 @@ if (count($object->records) > 0)	// There is at least one web site
     			$htmltext = $langs->trans("PreviewSiteServedByWebServer", $langs->transnoentitiesnoconv("Site"), $langs->transnoentitiesnoconv("Site"), $dataroot, $urlext?$urlext:'<span class="error">'.$langs->trans("VirtualHostUrlNotDefined").'</span>');
     			$htmltext.='<br>';
     			$htmltext.='<br>'.$langs->trans("CheckVirtualHostPerms", $langs->transnoentitiesnoconv("ReadPerm"), DOL_DOCUMENT_ROOT);
    -			$htmltext.='<br>'.$langs->trans("CheckVirtualHostPerms", $langs->transnoentitiesnoconv("WritePerm"), DOL_DATA_ROOT);
    +			$htmltext.='<br>'.$langs->trans("CheckVirtualHostPerms", $langs->transnoentitiesnoconv("WritePerm"), DOL_DATA_ROOT.'/website<br>'.DOL_DATA_ROOT.'/medias');
     			print '<a class="websitebuttonsitepreview'.($urlext?'':' websitebuttonsitepreviewdisabled cursornotallowed').'" id="previewsiteext" href="'.$urlext.'" target="tab'.$websitekey.'ext" alt="'.dol_escape_htmltag($langs->trans("PreviewSiteServedByWebServer", $langs->transnoentitiesnoconv("Site"), $langs->transnoentitiesnoconv("Site"), $dataroot, $urlext)).'">';
     			print $form->textwithpicto('', $htmltext, 1, 'preview_ext');
     			print '</a>';
    @@ -1926,10 +1927,11 @@ if (count($object->records) > 0)	// There is at least one web site
     					// Create an array for form
     					$preselectedlanguage = GETPOST('newlang', 'az09') ? GETPOST('newlang', 'az09') : ($objectpage->lang ? $objectpage->lang : $langs->defaultlang);
     					$formquestion = array(
    -						array('type' => 'text', 'tdclass'=>'maxwidth200', 'name' => 'pageurl', 'label'=> $langs->trans("WEBSITE_PAGENAME"), 'value'=> 'copy_of_'.$objectpage->pageurl),
    +						array('type' => 'hidden', 'name' => 'sourcepageurl', 'value'=> $objectpage->pageurl),
     						array('type' => 'checkbox', 'tdclass'=>'maxwidth200', 'name' => 'is_a_translation', 'label' => $langs->trans("PageIsANewTranslation"), 'value' => 0),
     						array('type' => 'other','name' => 'newlang', 'label' => $langs->trans("Language"), 'value' => $formadmin->select_language($preselectedlanguage, 'newlang', 0, null, 1, 0, 0, 'minwidth200', 0, 1)),
     						array('type' => 'other','name' => 'newwebsite', 'label' => $langs->trans("WebSite"), 'value' => $formwebsite->selectWebsite($object->id, 'newwebsite', 0)),
    +						array('type' => 'text', 'tdclass'=>'maxwidth200 fieldrequired', 'name' => 'pageurl', 'label'=> $langs->trans("WEBSITE_PAGENAME"), 'value'=> 'copy_of_'.$objectpage->pageurl),
     					);
     
     				   	$formconfirm = $form->formconfirm($_SERVER["PHP_SELF"] . '?website='.$object->ref.'&pageid=' . $pageid, $langs->trans('ClonePage'), '', 'confirm_createpagefromclone', $formquestion, 0, 1, 300, 550);
    @@ -1943,6 +1945,7 @@ if (count($object->records) > 0)	// There is at least one web site
     
     				print '<input type="submit" class="button nobordertransp"'.$disabled.' value="'.dol_escape_htmltag($langs->trans("EditHTMLSource")).'" name="editsource">';
     
    +				print '<!-- button EditInLine and ShowSubcontainers -->'."\n";
     				print '<div class="websiteselectionsection inline-block">';
     				print '<div class="inline-block">';
     				print $langs->trans("EditInLine");
    @@ -1966,12 +1969,12 @@ if (count($object->records) > 0)	// There is at least one web site
     				print '</div>';
     				print '<div class="inline-block">';
     				print $langs->trans("ShowSubcontainers");
    -				if ($websitepage->grabbed_from)
    +				/*if ($websitepage->grabbed_from)
     				{
     					print '<a class="button nobordertransp opacitymedium nohoverborder"'.$disabled.' href="#" disabled="disabled" title="'.dol_escape_htmltag($langs->trans("OnlyEditionOfSourceForGrabbedContent")).'">'.img_picto($langs->trans("OnlyEditionOfSourceForGrabbedContent"),'switch_off','',false,0,0,'','nomarginleft').'</a>';
     				}
     				else
    -				{
    +				{*/
     					if (empty($conf->global->WEBSITE_SUBCONTAINERSINLINE))
     					{
     						print '<a class="button nobordertransp nohoverborder"'.$disabled.' href="'.$_SERVER["PHP_SELF"].'?website='.$object->ref.'&pageid='.$websitepage->id.'&action=setshowsubcontainers">'.img_picto($langs->trans("ShowSubContainersOff"),'switch_off','',false,0,0,'','nomarginleft').'</a>';
    @@ -1980,7 +1983,7 @@ if (count($object->records) > 0)	// There is at least one web site
     					{
     						print '<a class="button nobordertransp nohoverborder"'.$disabled.' href="'.$_SERVER["PHP_SELF"].'?website='.$object->ref.'&pageid='.$websitepage->id.'&action=unsetshowsubcontainers">'.img_picto($langs->trans("ShowSubContainersOn"),'switch_on','',false,0,0,'','nomarginleft').'</a>';
     					}
    -				}
    +				/*}*/
     				print '</div>';
     				print '</div>';
     
    @@ -2002,7 +2005,7 @@ if (count($object->records) > 0)	// There is at least one web site
     
     			$htmltext = $langs->trans("PreviewSiteServedByDolibarr", $langs->transnoentitiesnoconv("Page"), $langs->transnoentitiesnoconv("Page"), $realpage, $dataroot);
     			$htmltext.='<br>'.$langs->trans("CheckVirtualHostPerms", $langs->transnoentitiesnoconv("ReadPerm"), DOL_DOCUMENT_ROOT);
    -			$htmltext.='<br>'.$langs->trans("CheckVirtualHostPerms", $langs->transnoentitiesnoconv("WritePerm"), DOL_DATA_ROOT);
    +			$htmltext.='<br>'.$langs->trans("CheckVirtualHostPerms", $langs->transnoentitiesnoconv("WritePerm"), DOL_DATA_ROOT.'/website<br>'.DOL_DATA_ROOT.'/medias');
     
     			print '<a class="websitebuttonsitepreview" id="previewpage" href="'.$realpage.'&nocache='.dol_now().'" class="button" target="tab'.$websitekey.'" alt="'.dol_escape_htmltag($htmltext).'">';
     			print $form->textwithpicto('', $htmltext, 1, 'preview');
    @@ -2320,7 +2323,7 @@ if ($action == 'createsite')
     	$htmltext = $langs->trans("SetHereVirtualHost", DOL_DATA_ROOT.'/website/<i>websiteref</i>');
     	$htmltext.='<br>';
     	$htmltext.='<br>'.$langs->trans("CheckVirtualHostPerms", $langs->transnoentitiesnoconv("ReadPerm"), DOL_DOCUMENT_ROOT);
    -	$htmltext.='<br>'.$langs->trans("CheckVirtualHostPerms", $langs->transnoentitiesnoconv("WritePerm"), DOL_DATA_ROOT);
    +	$htmltext.='<br>'.$langs->trans("CheckVirtualHostPerms", $langs->transnoentitiesnoconv("WritePerm"), DOL_DATA_ROOT.'/website<br>'.DOL_DATA_ROOT.'/medias');
     
     	print $form->textwithpicto($langs->trans('Virtualhost'), $htmltext, 1, 'help', '', 0, 2, 'tooltipvirtual');
     	print '</td><td>';
    @@ -2517,6 +2520,53 @@ if ($action == 'editmeta' || $action == 'createcontainer')
     	print $formadmin->select_language($pagelang?$pagelang:$langs->defaultlang, 'WEBSITE_LANG', 0, null, '1');
     	print '</td></tr>';
     
    +	if ($action != 'createcontainer')
    +	{
    +		// Translation of
    +		if ($objectpage->fk_page > 0)
    +		{
    +			print '<tr><td>';
    +			print $langs->trans('ThisPageIsTranslationOf');
    +			print '</td><td>';
    +			$sourcepage=new WebsitePage($db);
    +			$result = $sourcepage->fetch($objectpage->fk_page);
    +			if ($result == 0)	// not found, we can reset value
    +			{
    +
    +			}
    +			elseif ($result > 0)
    +			{
    +				print $sourcepage->getNomUrl(1);
    +			}
    +			print '</td></tr>';
    +		}
    +
    +		// Has translation pages
    +		$sql='SELECT rowid, lang from '.MAIN_DB_PREFIX.'website_page where fk_page = '.$objectpage->id;
    +		$resql = $db->query($sql);
    +		if ($resql)
    +		{
    +			$num_rows = $db->num_rows($resql);
    +			if ($num_rows > 0)
    +			{
    +				print '<tr><td>';
    +				print $langs->trans('ThisPageHasTranslationPages');
    +				print '</td><td>';
    +				$i=0;
    +				while ($obj = $db->fetch_object($resql))
    +				{
    +					$tmppage=new WebsitePage($db);
    +					$tmppage->fetch($obj->rowid);
    +					if ($i > 0) print ' - ';
    +					print $tmppage->getNomUrl(1).' ('.$tmppage->lang.')';
    +					$i++;
    +				}
    +				print '</td></tr>';
    +			}
    +		}
    +		else dol_print_error($db);
    +	}
    +
     	print '<tr><td class="titlefieldcreate">';
     	$htmlhelp=$langs->trans("WEBSITE_ALIASALTDesc");
     	print $form->textwithpicto($langs->trans('WEBSITE_ALIASALT'), $htmlhelp, 1, 'help', '', 0, 2, 'htmlheadertooltip');
    diff --git a/test/phpunit/DateLibTest.php b/test/phpunit/DateLibTest.php
    index 30a8c8d1a1a..d7f2ad18877 100644
    --- a/test/phpunit/DateLibTest.php
    +++ b/test/phpunit/DateLibTest.php
    @@ -205,6 +205,26 @@ class DateLibTest extends PHPUnit_Framework_TestCase
             $result=num_public_holiday($date1,$date2,'XX',1);
             print __METHOD__." result=".$result."\n";
             $this->assertEquals(2,$result,'NumPublicHoliday for XX');   // 1 opened day, 2 closed days (even if country unknown)
    +
    +        $conf->global->HOLIDAY_MORE_PUBLIC_HOLIDAYS='12-13,2019-12-14';
    +
    +        $date1=dol_mktime(0, 0, 0, 12, 13, 2018);
    +        $date2=dol_mktime(0, 0, 0, 12, 13, 2018);
    +        $result=num_public_holiday($date1,$date2,'YY',1);
    +        print __METHOD__." result=".$result."\n";
    +        $this->assertEquals(1,$result,'NumPublicHoliday for YY the 2018-12-13');   // 0 opened day, 1 closed days (even if country unknown)
    +
    +        $date1=dol_mktime(0, 0, 0, 12, 14, 2018);
    +        $date2=dol_mktime(0, 0, 0, 12, 14, 2018);
    +        $result=num_public_holiday($date1,$date2,'YY',1);
    +        print __METHOD__." result=".$result."\n";
    +        $this->assertEquals(0,$result,'NumPublicHoliday for YY the 2018-12-14');   // 1 opened day, 0 closed days (even if country unknown)
    +
    +        $date1=dol_mktime(0, 0, 0, 12, 14, 2019);
    +        $date2=dol_mktime(0, 0, 0, 12, 14, 2019);
    +        $result=num_public_holiday($date1,$date2,'YY',1);
    +        print __METHOD__." result=".$result."\n";
    +        $this->assertEquals(1,$result,'NumPublicHoliday for YY the 2019-12-14');   // 0 opened day, 1 closed days (even if country unknown)
         }
     
         /**
    diff --git a/test/phpunit/FactureTest.php b/test/phpunit/FactureTest.php
    index d04844783c5..a1dd46de978 100644
    --- a/test/phpunit/FactureTest.php
    +++ b/test/phpunit/FactureTest.php
    @@ -1,5 +1,6 @@
     <?php
    -/* Copyright (C) 2010 Laurent Destailleur  <eldy@users.sourceforge.net>
    +/* Copyright (C) 2010 Laurent Destailleur   <eldy@users.sourceforge.net>
    + * Copyright (C) 2018 Frédéric France       <frederic.france@netlogic.fr>
      *
      * This program is free software; you can redistribute it and/or modify
      * it under the terms of the GNU General Public License as published by
    @@ -228,7 +229,7 @@ class FactureTest extends PHPUnit_Framework_TestCase
     			$newlocalobject,
     			true,
     			array(
    -				'newref','oldref','id','lines','client','thirdparty','brouillon','user_author','date_creation','date_validation','datem',
    +				'newref','oldref','id','lines','client','thirdparty','brouillon','user_author','date_creation','date_validation','datem','date_modification',
     				'ref','statut','paye','specimen','facnumber','actiontypecode','actionmsg2','actionmsg','mode_reglement','cond_reglement',
     				'cond_reglement_doc','situation_cycle_ref','situation_counter','situation_final','multicurrency_total_ht','multicurrency_total_tva',
     				'multicurrency_total_ttc','fk_multicurrency','multicurrency_code','multicurrency_tx'