Prechádzať zdrojové kódy

Merge branch '19.0-mmi' of gogs.iprospective.fr:iProspective/dolibarr into 19.0-mmi

Webmaster Dercya 10 mesiacov pred
rodič
commit
57990beb39
100 zmenil súbory, kde vykonal 2290 pridanie a 2554 odobranie
  1. 0 588
      .github/logToCs.py
  2. 5 13
      .github/workflows/pre-commit.yml
  3. 189 8
      ChangeLog
  4. 1 1
      build/exe/doliwamp/Languages/MyCatalan.isl
  5. 1 1
      build/exe/doliwamp/Languages/MyEnglish.isl
  6. 1 1
      build/exe/doliwamp/Languages/MyFrench.isl
  7. 1 1
      build/exe/doliwamp/Languages/MyGerman.isl
  8. 1 1
      build/exe/doliwamp/Languages/MySpanish.isl
  9. 4 4
      build/exe/doliwamp/doliwamp.iss
  10. 7 7
      build/generate_filelist_xml.php
  11. 3 2
      build/makepack-howto.txt
  12. 2 2
      build/rpm/dolibarr_fedora.spec
  13. 2 2
      build/rpm/dolibarr_generic.spec
  14. 1 1
      dev/initdemo/mysqldump_dolibarr_19.0.0.sql
  15. 1 0
      dev/tools/codespell/codespell-ignore.txt
  16. 0 5
      htdocs/accountancy/admin/categories_list.php
  17. 6 6
      htdocs/accountancy/admin/fiscalyear_card.php
  18. 0 6
      htdocs/accountancy/admin/journals_list.php
  19. 8 4
      htdocs/accountancy/admin/subaccount.php
  20. 6 3
      htdocs/accountancy/bookkeeping/balance.php
  21. 3 0
      htdocs/accountancy/bookkeeping/card.php
  22. 5 2
      htdocs/accountancy/bookkeeping/export.php
  23. 3 3
      htdocs/accountancy/bookkeeping/list.php
  24. 3 2
      htdocs/accountancy/bookkeeping/listbyaccount.php
  25. 7 6
      htdocs/accountancy/class/accountancyexport.class.php
  26. 5 7
      htdocs/accountancy/class/accountancyimport.class.php
  27. 15 14
      htdocs/accountancy/class/bookkeeping.class.php
  28. 28 4
      htdocs/accountancy/class/lettering.class.php
  29. 1 1
      htdocs/accountancy/expensereport/lines.php
  30. 17 3
      htdocs/accountancy/journal/bankjournal.php
  31. 40 36
      htdocs/accountancy/journal/sellsjournal.php
  32. 1 1
      htdocs/accountancy/tpl/export_journal.tpl.php
  33. 1 1
      htdocs/adherents/card.php
  34. 1 1
      htdocs/adherents/list.php
  35. 2 2
      htdocs/adherents/subscription/card.php
  36. 1 1
      htdocs/adherents/subscription/list.php
  37. 2 2
      htdocs/admin/barcode.php
  38. 2 0
      htdocs/admin/bom_extrafields.php
  39. 3 0
      htdocs/admin/bomline_extrafields.php
  40. 1 1
      htdocs/admin/clicktodial.php
  41. 14 14
      htdocs/admin/company.php
  42. 1 1
      htdocs/admin/dict.php
  43. 3 0
      htdocs/admin/eventorganization_confbooth_extrafields.php
  44. 2 0
      htdocs/admin/eventorganization_confboothattendee_extrafields.php
  45. 2 0
      htdocs/admin/expensereport_extrafields.php
  46. 9 3
      htdocs/admin/external_rss.php
  47. 24 12
      htdocs/admin/facture.php
  48. 1 1
      htdocs/admin/holiday.php
  49. 2 0
      htdocs/admin/holiday_extrafields.php
  50. 2 0
      htdocs/admin/knowledgerecord_extrafields.php
  51. 107 107
      htdocs/admin/mails.php
  52. 3 3
      htdocs/admin/mails_templates.php
  53. 4 4
      htdocs/admin/menus/edit.php
  54. 10 8
      htdocs/admin/modules.php
  55. 1 0
      htdocs/admin/mrp_extrafields.php
  56. 2 0
      htdocs/admin/mrp_production_extrafields.php
  57. 210 208
      htdocs/admin/oauthlogintokens.php
  58. 1 1
      htdocs/admin/pdf_other.php
  59. 3 3
      htdocs/admin/stock.php
  60. 13 6
      htdocs/admin/system/security.php
  61. 4 2
      htdocs/api/class/api_documents.class.php
  62. 1 1
      htdocs/asset/class/asset.class.php
  63. 1 1
      htdocs/asset/list.php
  64. 1 1
      htdocs/asset/model/list.php
  65. 1 2
      htdocs/asterisk/wrapper.php
  66. 10 2
      htdocs/barcode/printsheet.php
  67. 22 1
      htdocs/bom/ajax/ajax.php
  68. 3 1
      htdocs/bom/bom_card.php
  69. 1 1
      htdocs/bom/bom_list.php
  70. 1 1
      htdocs/bom/class/bom.class.php
  71. 15 2
      htdocs/bom/tpl/objectline_create.tpl.php
  72. 1 1
      htdocs/bookcal/availabilities_list.php
  73. 1 1
      htdocs/bookcal/calendar_list.php
  74. 3 1
      htdocs/bookmarks/card.php
  75. 1 1
      htdocs/bookmarks/list.php
  76. 5 2
      htdocs/categories/class/categorie.class.php
  77. 11 7
      htdocs/comm/action/card.php
  78. 3 3
      htdocs/comm/action/list.php
  79. 1 0
      htdocs/comm/card.php
  80. 1 1
      htdocs/comm/mailing/list.php
  81. 13 9
      htdocs/comm/propal/card.php
  82. 1 1
      htdocs/comm/propal/class/api_proposals.class.php
  83. 7 14
      htdocs/comm/propal/class/propal.class.php
  84. 1280 1279
      htdocs/comm/propal/list.php
  85. 23 18
      htdocs/commande/card.php
  86. 1 1
      htdocs/commande/class/api_orders.class.php
  87. 41 53
      htdocs/commande/class/commande.class.php
  88. 1 3
      htdocs/commande/list.php
  89. 1 1
      htdocs/commande/list_det.php
  90. 1 1
      htdocs/compta/bank/list.php
  91. 5 2
      htdocs/compta/bank/releve.php
  92. 1 0
      htdocs/compta/bank/various_payment/list.php
  93. 1 1
      htdocs/compta/cashcontrol/cashcontrol_list.php
  94. 18 15
      htdocs/compta/facture/card.php
  95. 1 1
      htdocs/compta/facture/class/api_invoices.class.php
  96. 7 2
      htdocs/compta/facture/class/facture.class.php
  97. 1 1
      htdocs/compta/facture/invoicetemplate_list.php
  98. 2 2
      htdocs/compta/facture/list.php
  99. 2 2
      htdocs/compta/paiement.php
  100. 2 2
      htdocs/compta/paiement/card.php

+ 0 - 588
.github/logToCs.py

@@ -1,588 +0,0 @@
-#!/usr/bin/env python3
-# pylint: disable=invalid-name
-"""
-Convert a log to CheckStyle format.
-
-Url: https://github.com/mdeweerd/LogToCheckStyle
-
-The log can then be used for generating annotations in a github action.
-
-Note: this script is very young and "quick and dirty".
-      Patterns can be added to "PATTERNS" to match more messages.
-
-# Examples
-
-Assumes that logToCs.py is available as .github/logToCs.py.
-
-## Example 1:
-
-
-```yaml
-      - run: |
-          pre-commit run -all-files | tee pre-commit.log
-          .github/logToCs.py pre-commit.log pre-commit.xml
-      - uses: staabm/annotate-pull-request-from-checkstyle-action@v1
-        with:
-          files: pre-commit.xml
-          notices-as-warnings: true # optional
-```
-
-## Example 2:
-
-
-```yaml
-      - run: |
-          pre-commit run --all-files | tee pre-commit.log
-      - name: Add results to PR
-        if: ${{ always() }}
-        run: |
-          .github/logToCs.py pre-commit.log | cs2pr
-```
-
-Author(s):
-  - https://github.com/mdeweerd
-
-License: MIT License
-
-"""
-
-import argparse
-import datetime as dt
-import json
-import os
-import re
-import sys
-import xml.etree.ElementTree as ET  # nosec
-
-
-def remove_prefix(string, prefix):
-    """
-    Remove prefix from string
-
-    Provided for backward compatibility.
-    """
-    if prefix and string.startswith(prefix):
-        return string[len(prefix) :]
-    return string
-
-
-def convert_notices_to_checkstyle(notices, root_path=None):
-    """
-    Convert annotation list to CheckStyle xml string
-    """
-    root = ET.Element("checkstyle")
-    for fields in notices:
-        add_error_entry(root, **fields, root_path=root_path)
-    return ET.tostring(root, encoding="utf_8").decode("utf_8")
-
-
-def convert_lines_to_notices(lines):
-    """
-    Convert provided message to CheckStyle format.
-    """
-    notices = []
-    for line in lines:
-        fields = parse_message(line)
-        if fields:
-            notices.append(fields)
-    return notices
-
-
-def convert_text_to_notices(text):
-    """
-    Convert provided message to CheckStyle format.
-    """
-    return parse_file(text)
-
-
-# Initial version for Checkrun from:
-# https://github.com/tayfun/flake8-your-pr/blob/50a175cde4dd26a656734c5b64ba1e5bb27151cb/src/main.py#L7C1-L123C36
-# MIT Licence
-class CheckRun:
-    """
-    Represents the check run
-    """
-
-    GITHUB_TOKEN = os.environ.get("GITHUB_TOKEN", None)
-    GITHUB_EVENT_PATH = os.environ.get("GITHUB_EVENT_PATH", None)
-
-    URI = "https://api.github.com"
-    API_VERSION = "2022-11-28"
-    ACCEPT_HEADER_VALUE = "application/vnd.github+json"
-    AUTH_HEADER_VALUE = f"Bearer {GITHUB_TOKEN}"
-    # This is the max annotations Github API accepts in one go.
-    MAX_ANNOTATIONS = 50
-
-    def __init__(self):
-        """
-        Initialise Check Run object with information from checkrun
-        """
-        self.read_event_file()
-        self.read_meta_data()
-
-    def read_event_file(self):
-        """
-        Read the event file to get the event information later.
-        """
-        if self.GITHUB_EVENT_PATH is None:
-            raise ValueError("Not running in github workflow")
-        with open(self.GITHUB_EVENT_PATH, encoding="utf_8") as event_file:
-            self.event = json.loads(event_file.read())
-
-    def read_meta_data(self):
-        """
-        Get meta data from event information
-        """
-        self.repo_full_name = self.event["repository"]["full_name"]
-        pull_request = self.event.get("pull_request")
-        print("%r", self.event)
-        if pull_request:
-            self.head_sha = pull_request["head"]["sha"]
-        else:
-            print("%r", self.event)
-            check_suite = self.event.get("check_suite", None)
-            if check_suite is not None:
-                self.head_sha = check_suite["pull_requests"][0]["base"]["sha"]
-            else:
-                self.head_sha = None  # Can't annotate?
-
-    def submit(  # pylint: disable=too-many-arguments
-        self,
-        notices,
-        title=None,
-        summary=None,
-        text=None,
-        conclusion=None,
-    ):
-        """
-        Submit annotations to github
-
-        See:
-        https://docs.github.com/en/rest/checks/runs?apiVersion=2022-11-28
-              #update-a-check-run
-
-        :param conclusion: success, failure
-        """
-        # pylint: disable=import-outside-toplevel
-        import requests  # Import here to not impose presence of module
-
-        if self.head_sha is None:
-            return
-
-        output = {
-            "annotations": notices[: CheckRun.MAX_ANNOTATIONS],
-        }
-        if title is not None:
-            output["title"] = title
-        if summary is not None:
-            output["summary"] = summary
-        if text is not None:
-            output["text"] = text
-        if conclusion is None:
-            # action_required, cancelled, failure, neutral, success
-            # skipped, stale, timed_out
-            if bool(notices):
-                conclusion = "failure"
-            else:
-                conclusion = "success"
-
-        payload = {
-            "name": "log-to-pr-annotation",
-            "head_sha": self.head_sha,
-            "status": "completed",  # queued, in_progress, completed
-            "conclusion": conclusion,
-            # "started_at": dt.datetime.now(dt.timezone.utc).isoformat(),
-            "completed_at": dt.datetime.now(dt.timezone.utc).isoformat(),
-            "output": output,
-        }
-
-        # Create the check-run
-        response = requests.post(
-            f"{self.URI}/repos/{self.repo_full_name}/check-runs",
-            headers={
-                "Accept": self.ACCEPT_HEADER_VALUE,
-                "Authorization": self.AUTH_HEADER_VALUE,
-                "X-GitHub-Api-Version": self.API_VERSION,
-            },
-            json=payload,
-            timeout=30,
-        )
-        print(response.content)
-        response.raise_for_status()
-
-
-ANY_REGEX = r".*?"
-FILE_REGEX = r"\s*(?P<file_name>\S.*?)\s*?"
-FILEGROUP_REGEX = r"\s*(?P<file_group>\S.*?)\s*?"
-EOL_REGEX = r"[\r\n]"
-LINE_REGEX = r"\s*(?P<line>\d+?)\s*?"
-COLUMN_REGEX = r"\s*(?P<column>\d+?)\s*?"
-SEVERITY_REGEX = r"\s*(?P<severity>error|warning|notice|style|info)\s*?"
-MSG_REGEX = r"\s*(?P<message>.+?)\s*?"
-MULTILINE_MSG_REGEX = r"\s*(?P<message>(?:.|.[\r\n])+)"
-# cpplint confidence index
-CONFIDENCE_REGEX = r"\s*\[(?P<confidence>\d+)\]\s*?"
-
-
-# List of message patterns, add more specific patterns earlier in the list
-# Creating patterns by using constants makes them easier to define and read.
-PATTERNS = [
-    # beautysh
-    #  File ftp.sh: error: "esac" before "case" in line 90.
-    re.compile(
-        f"^File {FILE_REGEX}:{SEVERITY_REGEX}:"
-        f" {MSG_REGEX} in line {LINE_REGEX}.$"
-    ),
-    # beautysh
-    #  File socks4echo.sh: error: indent/outdent mismatch: -2.
-    re.compile(f"^File {FILE_REGEX}:{SEVERITY_REGEX}: {MSG_REGEX}$"),
-    # yamllint
-    # ##[group].pre-commit-config.yaml
-    # ##[error]97:14 [trailing-spaces] trailing spaces
-    # ##[endgroup]
-    re.compile(rf"^##\[group\]{FILEGROUP_REGEX}$"),  # Start file group
-    re.compile(
-        rf"^##\[{SEVERITY_REGEX}\]{LINE_REGEX}:{COLUMN_REGEX}{MSG_REGEX}$"
-    ),  # Msg
-    re.compile(r"^##(?P<file_endgroup>\[endgroup\])$"),  # End file group
-    #  File socks4echo.sh: error: indent/outdent mismatch: -2.
-    re.compile(f"^File {FILE_REGEX}:{SEVERITY_REGEX}: {MSG_REGEX}$"),
-    # Emacs style
-    #  path/to/file:845:5: error - Expected 1 space after closing brace
-    re.compile(
-        rf"^{FILE_REGEX}:{LINE_REGEX}:{COLUMN_REGEX}:{SEVERITY_REGEX}"
-        rf"-?\s{MSG_REGEX}$"
-    ),
-    # ESLint (JavaScript Linter), RoboCop, shellcheck
-    #  path/to/file.js:10:2: Some linting issue
-    #  path/to/file.rb:10:5: Style/Indentation: Incorrect indentation detected
-    #  path/to/script.sh:10:1: SC2034: Some shell script issue
-    re.compile(f"^{FILE_REGEX}:{LINE_REGEX}:{COLUMN_REGEX}: {MSG_REGEX}$"),
-    # Cpplint default output:
-    #           '%s:%s:  %s  [%s] [%d]\n'
-    #   % (filename, linenum, message, category, confidence)
-    re.compile(f"^{FILE_REGEX}:{LINE_REGEX}:{MSG_REGEX}{CONFIDENCE_REGEX}$"),
-    # MSVC
-    # file.cpp(10): error C1234: Some error message
-    re.compile(
-        f"^{FILE_REGEX}\\({LINE_REGEX}\\):{SEVERITY_REGEX}{MSG_REGEX}$"
-    ),
-    # Java compiler
-    # File.java:10: error: Some error message
-    re.compile(f"^{FILE_REGEX}:{LINE_REGEX}:{SEVERITY_REGEX}:{MSG_REGEX}$"),
-    # Python
-    # File ".../logToCs.py", line 90 (note: code line follows)
-    re.compile(f'^File "{FILE_REGEX}", line {LINE_REGEX}$'),
-    # Pylint, others
-    # path/to/file.py:10: [C0111] Missing docstring
-    # others
-    re.compile(f"^{FILE_REGEX}:{LINE_REGEX}: {MSG_REGEX}$"),
-    # Shellcheck:
-    # In script.sh line 76:
-    re.compile(
-        f"^In {FILE_REGEX} line {LINE_REGEX}:{EOL_REGEX}?"
-        f"({MULTILINE_MSG_REGEX})?{EOL_REGEX}{EOL_REGEX}"
-    ),
-    # eslint:
-    #  /path/to/filename
-    #    14:5  error  Unexpected trailing comma  comma-dangle
-    re.compile(
-        f"^{FILE_REGEX}{EOL_REGEX}"
-        rf"\s+{LINE_REGEX}:{COLUMN_REGEX}\s+{SEVERITY_REGEX}\s+{MSG_REGEX}$"
-    ),
-]
-
-# Exceptionnaly some regexes match messages that are not error.
-# This pattern matches those exceptions
-EXCLUDE_MSG_PATTERN = re.compile(
-    r"^("
-    r"Placeholder pattern"  # To remove on first message pattern
-    r")"
-)
-
-# Exceptionnaly some regexes match messages that are not error.
-# This pattern matches those exceptions
-EXCLUDE_FILE_PATTERN = re.compile(
-    r"^("
-    # Codespell:  (appears as a file name):
-    r"Used config files\b"
-    r")"
-)
-
-# Severities available in CodeSniffer report format
-SEVERITY_NOTICE = "notice"
-SEVERITY_WARNING = "warning"
-SEVERITY_ERROR = "error"
-
-
-def strip_ansi(text: str):
-    """
-    Strip ANSI escape sequences from string (colors, etc)
-    """
-    return re.sub(r"\x1B(?:[@-Z\\-_]|\[[0-?]*[ -/]*[@-~])", "", text)
-
-
-def parse_file(text):
-    """
-    Parse all messages in a file
-
-    Returns the fields in a dict.
-    """
-    # pylint: disable=too-many-branches,too-many-statements
-    # regex required to allow same group names
-    try:
-        import regex  # pylint: disable=import-outside-toplevel
-    except ImportError as exc:
-        raise ImportError(
-            "The 'parsefile' method requires 'python -m pip install regex'"
-        ) from exc
-
-    patterns = [pattern.pattern for pattern in PATTERNS]
-    # patterns = [PATTERNS[0].pattern]
-
-    file_group = None  # The file name for the group (if any)
-    full_regex = "(?:(?:" + (")|(?:".join(patterns)) + "))"
-    results = []
-
-    for fields in regex.finditer(
-        full_regex, strip_ansi(text), regex.MULTILINE | regex.IGNORECASE
-    ):
-        if not fields:
-            continue
-        result = fields.groupdict()
-
-        if len(result) == 0:
-            continue
-
-        severity = result.get("severity", None)
-        file_name = result.get("file_name", None)
-        confidence = result.pop("confidence", None)
-        new_file_group = result.pop("file_group", None)
-        file_endgroup = result.pop("file_endgroup", None)
-        message = result.get("message", None)
-
-        if new_file_group is not None:
-            # Start of file_group, just store file
-            file_group = new_file_group
-            continue
-
-        if file_endgroup is not None:
-            file_group = None
-            continue
-
-        if file_name is None:
-            if file_group is not None:
-                file_name = file_group
-                result["file_name"] = file_name
-            else:
-                # No filename, skip
-                continue
-        else:
-            if EXCLUDE_FILE_PATTERN.search(file_name):
-                # This file_name is excluded
-                continue
-
-        if message is not None:
-            if EXCLUDE_MSG_PATTERN.search(message):
-                # This message is excluded
-                continue
-
-        if confidence is not None:
-            # Convert confidence level of cpplint
-            # to warning, etc.
-            confidence = int(confidence)
-
-            if confidence <= 1:
-                severity = SEVERITY_NOTICE
-            elif confidence >= 5:
-                severity = SEVERITY_ERROR
-            else:
-                severity = SEVERITY_WARNING
-
-        if severity is None:
-            severity = SEVERITY_ERROR
-        else:
-            severity = severity.lower()
-
-        if severity in ["info", "style"]:
-            severity = SEVERITY_NOTICE
-
-        result["severity"] = severity
-
-        results.append(result)
-
-    return results
-
-
-def parse_message(message):
-    """
-    Parse message until it matches a pattern.
-
-    Returns the fields in a dict.
-    """
-    for pattern in PATTERNS:
-        fields = pattern.match(message, re.IGNORECASE)
-        if not fields:
-            continue
-        result = fields.groupdict()
-        if len(result) == 0:
-            continue
-
-        if "confidence" in result:
-            # Convert confidence level of cpplint
-            # to warning, etc.
-            confidence = int(result["confidence"])
-            del result["confidence"]
-
-            if confidence <= 1:
-                severity = SEVERITY_NOTICE
-            elif confidence >= 5:
-                severity = SEVERITY_ERROR
-            else:
-                severity = SEVERITY_WARNING
-            result["severity"] = severity
-
-        if "severity" not in result:
-            result["severity"] = SEVERITY_ERROR
-        else:
-            result["severity"] = result["severity"].lower()
-
-        if result["severity"] in ["info", "style"]:
-            result["severity"] = SEVERITY_NOTICE
-
-        return result
-
-    # Nothing matched
-    return None
-
-
-def add_error_entry(  # pylint: disable=too-many-arguments
-    root,
-    severity,
-    file_name,
-    line=None,
-    column=None,
-    message=None,
-    source=None,
-    root_path=None,
-):
-    """
-    Add error information to the CheckStyle output being created.
-    """
-    file_element = find_or_create_file_element(
-        root, file_name, root_path=root_path
-    )
-    error_element = ET.SubElement(file_element, "error")
-    error_element.set("severity", severity)
-    if line:
-        error_element.set("line", line)
-    if column:
-        error_element.set("column", column)
-    if message:
-        error_element.set("message", message)
-    if source:
-        # To verify if this is a valid attribute
-        error_element.set("source", source)
-
-
-def find_or_create_file_element(root, file_name: str, root_path=None):
-    """
-    Find/create file element in XML document tree.
-    """
-
-    if root_path is not None:
-        file_name = remove_prefix(file_name, root_path)
-    for file_element in root.findall("file"):
-        if file_element.get("name") == file_name:
-            return file_element
-    file_element = ET.SubElement(root, "file")
-    file_element.set("name", file_name)
-    return file_element
-
-
-def main():
-    """
-    Parse the script arguments and get the conversion done.
-    """
-    parser = argparse.ArgumentParser(
-        description="Convert messages to Checkstyle XML format."
-    )
-    parser.add_argument(
-        "input", help="Input file. Use '-' for stdin.", nargs="?", default="-"
-    )
-    parser.add_argument(
-        "output",
-        help="Output file. Use '-' for stdout.",
-        nargs="?",
-        default="-",
-    )
-    parser.add_argument(
-        "-i",
-        "--in",
-        dest="input_named",
-        help="Input filename. Overrides positional input.",
-    )
-    parser.add_argument(
-        "-o",
-        "--out",
-        dest="output_named",
-        help="Output filename. Overrides positional output.",
-    )
-    parser.add_argument(
-        "--root",
-        metavar="ROOT_PATH",
-        help="Root directory to remove from file paths."
-        "  Defaults to working directory.",
-        default=os.getcwd(),
-    )
-    parser.add_argument(
-        "--github-annotate",
-        action=argparse.BooleanOptionalAction,
-        help="Annotate when in Github workflow.",
-        # Currently disabled,
-        #  Future: (os.environ.get("GITHUB_EVENT_PATH", None) is not None),
-        default=False,
-    )
-
-    args = parser.parse_args()
-
-    if args.input == "-" and args.input_named:
-        with open(
-            args.input_named, encoding="utf_8", errors="surrogateescape"
-        ) as input_file:
-            text = input_file.read()
-    elif args.input != "-":
-        with open(
-            args.input, encoding="utf_8", errors="surrogateescape"
-        ) as input_file:
-            text = input_file.read()
-    else:
-        text = sys.stdin.read()
-
-    root_path = os.path.join(args.root, "")
-
-    try:
-        notices = convert_text_to_notices(text)
-    except ImportError:
-        notices = convert_lines_to_notices(re.split(r"[\r\n]+", text))
-
-    checkstyle_xml = convert_notices_to_checkstyle(
-        notices, root_path=root_path
-    )
-
-    if args.output == "-" and args.output_named:
-        with open(args.output_named, "w", encoding="utf_8") as output_file:
-            output_file.write(checkstyle_xml)
-    elif args.output != "-":
-        with open(args.output, "w", encoding="utf_8") as output_file:
-            output_file.write(checkstyle_xml)
-    else:
-        print(checkstyle_xml)
-
-    if args.github_annotate:
-        checkrun = CheckRun()
-        checkrun.submit(notices)
-
-
-if __name__ == "__main__":
-    main()

+ 5 - 13
.github/workflows/pre-commit.yml

@@ -7,7 +7,6 @@ jobs:
   pre-commit:
     runs-on: ubuntu-latest
     env:
-      LOG_TO_CS: .github/logToCs.py
       RAW_LOG: pre-commit.log
       CS_XML: pre-commit.xml
     steps:
@@ -37,7 +36,7 @@ jobs:
         with:
           cache: pip
           python-version: "3.11"
-      - run: python -m pip install pre-commit regex
+      - run: python -m pip install pre-commit
       # Restore previous cache of precommit
       - uses: actions/cache/restore@v4
         with:
@@ -102,19 +101,12 @@ jobs:
           pre-commit run --hook-stage manual -a php-cs-with-cache | tee -a ${RAW_LOG}
           ls -l ~/.cache/pre-commit/
 
-      # If error, we convert log in the checkstyle format
-      - name: Convert Raw Log to CheckStyle format
-        if: ${{ failure() }}
-        run: |
-          python ${LOG_TO_CS} ${RAW_LOG} ${CS_XML}
-      # Annotate the git sources with the log messages
-      - name: Annotate Source Code with Messages
-        uses: staabm/annotate-pull-request-from-checkstyle-action@v1
+      - name: Convert Raw Log to Annotations
+        uses: mdeweerd/logToCheckStyle@v2024.2.9
         if: ${{ failure() }}
         with:
-          files: ${{ env.CS_XML }}
-          notices-as-warnings: true # optional
-          prepend-filename: true # optional
+          in: ${{ env.RAW_LOG }}
+
       # Save the precommit cache
       - uses: actions/cache/save@v4
         if: ${{ ! cancelled() }}

+ 189 - 8
ChangeLog

@@ -3,12 +3,177 @@ English Dolibarr ChangeLog
 --------------------------------------------------------------
 
 
+***** ChangeLog for 19.0.2 compared to 19.0.1 *****
+FIX: $object->oldcopy may be a stdClass and not original object
+FIX: 16.0 - parent company gets emptied when updating a third party from the card in edit mode (#28269)
+FIX: 16.0 - the e-mail templates configured in the notification module are not used if the recipient is a fixed e-mail address (#29407)
+FIX: 17.0 - $num doesn't take trigger-modified newref into account, leading to inconsistencies if BILL_SUPPLIER_VALIDATE changes the invoice's ref (#28684)
+FIX: #22948
+FIX: #24265 regression cannot see all product on takepos (#28753)
+FIX: #26015
+FIX: #28205
+FIX: #28251 Fixing subpermission name on api_multicurrencies.class.php (#28252)
+FIX: #28347 FIX: occurred#28962 FIX: #29224  FIX: #29035  (#29303)
+FIX: #28369
+FIX: #28429
+FIX: #28491 (#28522)
+FIX: #28518 (#28520)
+FIX: #28533 Mo::deleteLine removes the "main" MoLine if consumed line is delete (#28535)
+FIX: #28564
+FIX: #28978 FIX: #28976
+FIX: #29029 Impossible to delete an order line
+FIX: #29114 Missing contact term in intervention
+FIX: #29114 Translate contact term in intervention
+FIX: #29225
+FIX: #29229
+FIX: #29333 supplier order extrafields of link type displays error (#29334)
+FIX: #29496 - filtering a record should not hide its child not filtered
+FIX: #29531
+FIX: Accolad
+FIX: Accountancy export with file or not
+FIX: Accountancy - Not trunc id_import
+FIX: accounting FEC import (Issue #28306) (#29414)
+FIX: Adding the dependencies list feature for extrafields "select" (#28549)
+FIX: Add new hidden conf "DISABLE_QTY_OVERWRITTEN" (#28523)
+FIX: Amount of localtaxes in foreign currency was wrong on screen and PDF
+FIX: an error in a complex else condition
+FIX: an error occurred when doing a mass vat change de 0% on supplier invoice (#29417)
+FIX: avoid error "Column 'entity' in where clause is ambiguous" (#28270)
+FIX: avoid php warnings (#29247)
+FIX: avoid to delete "lock" and "unlock" files
+FIX: avoid Unknown column 'pfp.ref_fourn' (#28145)
+FIX: avoid warning "error parsing attribute name in Entity" (#28543)
+FIX: background color for enabled modules (#29378)
+FIX: Bad column for total in bom list
+FIX: Bad condition on button back to draft on recruitment job.
+FIX: Bad CRLF when sending text only content. Fix dol_htmlwithnojs()
+FIX: Bad management on error creation of bookkeeping
+FIX: Bad picto on list of permission of a user when user not admin
+FIX: bad search on _ char in like when Debugbar is on
+FIX: bad timezone for the start/end date of an event
+FIX: Better test on validity of compute field syntax with parenthesis
+FIX: Blank list when contract was checked in list of tickets (#29528)
+FIX: Button for disabled modules must not appear.
+FIX: categories protection limit
+FIX: close #28279
+FIX: Condition on newDateLimReglement
+FIX: Conflict with autoload
+FIX: contact/address title is always "New Contact/Address" even if the contact/address already exists (#29581)
+FIX: Count of virtual stock at Services and MoLine with disabled stock change (#28580)
+FIX: css of background of modules that was black
+FIX: default workstation on BOM
+FIX: disabled pito of menu must be greyed.
+FIX: Display the date according to user language on substitutions (#29510)
+FIX: Don't display column when it's out of date (#28271)
+FIX: duplicate error check (#29433)
+FIX: duplicate with lines: 414-416 (#28358)
+FIX: edit bank suggested for credit transfer payment in invoice setup
+FIX: empty array with php8.2
+FIX: Ergonomic fail  part02 (#29373)
+FIX: Error When cloning fourn price no default value for tva_tx (#28368)
+FIX: Error when updating user (#29304)
+FIX: fatal error Unsupported operand types when recording load payment
+FIX: Fix create shipping with product who have negative stocks on warehouse but the negative stock transfer is allowed (#26217)
+FIX: Fix save directory for invoice ODT and multientities
+FIX: hasRight function
+FIX: Hide number beside select contract & added langs to translate c… (#29529)
+FIX: Hierarchy Employee view do not filter on employee = 1 (#29496)
+FIX: incorrect page numbering in PDF #29458 (#29476)
+FIX: Inline edition not implemented
+FIX: inventoryDeletePermission id define twice
+FIX: Issue with special characters in French
+FIX: link type extrafield on warehouse not working (#29339)
+FIX: logo and escape in RSS
+FIX: logo of paypal payment on payment page
+FIX: made invalid code shape error more user friendly (#29498)
+FIX: Manual deletion of a bookkeeping line
+FIX: Merge of thirdparties must also move uploaded files
+FIX: migration missing 2 columns in llx_resource and 1 in llx_user
+FIX: missing comma in query (#29435)
+FIX: Missing declaration of type export FEC/FEC2 for export with file source
+FIX: missing entity parameter for ajax_constantonoff
+FIX: missing hide "new" button where "product" or "service" module are disable
+FIX: missing trans
+FIX: Move the trigger for delete order line before the SQL request
+FIX: MRP divide product not working
+FIX: multiple problems with multicompany
+FIX: navigation after filter in subaccount
+FIX: notification: error 500 in fixed emails due to a bad copy/paste (#29580)
+FIX: notification module: for supplier orders (any of the 3 triggers), user can choose an e-mail template in conf, but the conf is not used when sending the notification (#28216)
+FIX: not redirtect when error occurs on updating card (#29388)
+FIX: Not trancate the multicurrency rate shown on cards (even if the global MAIN_MAX_DECIMALS_SHOWN is set to 0) (#28211)
+FIX: Oauth login
+FIX: Option MAIN_DOC_USE_TIMING can be a string with date format
+FIX: Payment on customer invoice - Remove accountid in url if empty for apply default value (#28156)
+FIX: Pb in redirect of a website page in USEDOLIBARRSERVER mode
+FIX: PDF Fatal error : Backport fix from  #23972
+FIX: PDF Translations Extrafields
+FIX: permission on payment file of a tax
+FIX: peut pas faire mieux !
+FIX: php8: Fatal when empty $tmpvat is an empty string (no silent conversion to '0' when used in arithmetic operations) (#29451)
+FIX: php warning global conf (#29478)
+FIX: PHP Warning: Undefined array key "totalam" on line 1890 (#29489 #29578 #29487)
+FIX: PHP Warning: Undefined properties
+FIX: PHP Warning: Undefined variable $lib (#28342)
+FIX: PHP Warning: Undefined variable $mode (#28697)
+FIX: PHP Warning: Undefined variable $socid on line 55 (#29490)
+FIX: PHP Warning: Undefined variable $tva_npr in /fourn/facture/card.php on line 1695 (#29593)
+FIX: Picto for mime in top menu
+FIX: position of field in list of field in shipment list
+FIX: postgresql error (#28542)
+FIX: PUT /thirdparties/{id} and PUT /contacts/{id} should throw exception if update returns < 0 (#29596)
+FIX: quote in sql request
+FIX: Regression #29340
+FIX: Repair the replenishment list (#29336)
+FIX: Responsive on admin project
+FIX: round capital societe (#29211)
+FIX: Row size of role contact in thirdparty (#29456)
+FIX: Scale for the "second" unit (#29327)
+FIX: search and add extrafields to tasks when conf disabled (#29542)
+FIX: Shipment closing action has wrong value (#28174)
+FIX: skip adding tab if user doesn't have permission (#28698)
+FIX: sometimes a string type instead integer is return, why ?
+FIX: some tooltips has disappeared on invoice action button
+FIX: Special code is now transmitted by args only in order supplier (#28546 #28619)
+FIX: SQL syntax error in DDLUpdateField
+FIX: StockTransfer class has no table_element_line
+FIX: subscription must be editable when accounting isn't reconciled (#28469)
+FIX: supplier price duplicate entry on update supplier product ref (#29290)
+FIX: Support of lot serial not working on TakePOS
+FIX: syntax error (but same result) :-)
+FIX: TakePOS | Add product / Delete line of existing invoice
+FIX: TASK_CREATE Trigger (#29483)
+FIX: The filter ! was broken in emailcollector
+FIX: The localtax must be exported only if activated
+FIX: Ticket new message notification sent twice
+FIX: trackid and temp dir on payment confirmation of event registration
+FIX: Translation for select  (#28677)
+FIX: Undefined array key default on fields (#29243)
+FIX: upload odt files should not start/end with space
+FIX: use $conf->browser->os instead
+FIX: used hasRight function
+FIX: Value of field int = 0 from modulebuilder must not be set to null
+FIX: We should be able to add a workstation on bom lines (#29361 #29360)
+fix: when invoice is created by WORKFLOW_ORDER_AUTOCREATE_INVOICE on ORDER_NEW, the invoice must have the default bank account of the thirdparty is it's empty on order
+FIX: wrong array key (#29317)
+FIX: Wrong currency shown in TakePOS payment page
+FIX: wrong shortcut key for macintosh
+FIX: wrong sql request with product category filter
+FIX: wrong stock permission number
+NEW: Constant to select if typent helps define whether the thirdparty is a company
+NEW: Support Reply-To tracking in emails sending (tickets only for the
+SEC: #yogosha21416
+SEC: Add a protection against installation of external module bypassing
+SEC: A user with export permission can export module data without permissions on module.
+
 ***** ChangeLog for 19.0.1 compared to 19.0.0 *****
 
 FIX: 16.0 - parent company gets emptied when updating a third party from the card in edit mode (#28269)
+FIX: 17.0: $num doesn't take trigger-modified newref into account, leading to inconsistencies if BILL_SUPPLIER_VALIDATE changes the invoice's ref (#28684)
 FIX: #22948
+FIX: #24265 regression cannot see all product on takepos (#28753)
 FIX: #28205
-FIX: 28251 Fixing subpermission name on api_multicurrencies.class.php (#28252)
+FIX: #28251 Fixing subpermission name on api_multicurrencies.class.php (#28252)
 FIX: #28369
 FIX: #28429
 FIX: #28491 (#28522)
@@ -17,6 +182,8 @@ FIX: #28533 Mo::deleteLine removes the "main" MoLine if consumed line is delete
 FIX: #28564
 FIX: Adding the dependencies list feature for extrafields "select" (#28549)
 FIX: Add new hidden conf "DISABLE_QTY_OVERWRITTEN" (#28523)
+FIX: Amount of localtaxes in foreign currency was wrong on screen and PDF
+FIX: an error in a complex else condition
 FIX: avoid error "Column 'entity' in where clause is ambiguous" (#28270)
 FIX: avoid Unknown column 'pfp.ref_fourn' (#28145)
 FIX: avoid warning "error parsing attribute name in Entity" (#28543)
@@ -27,34 +194,48 @@ FIX: Bad picto on list of permission of a user when user not admin
 FIX: bad timezone for the start/end date of an event
 FIX: Better test on validity of compute field syntax with parenthesis
 FIX: close #28279
-FIX: disabled pito of menu must be greyed.
+FIX: Count of virtual stock at Services and MoLine with disabled stock change (#28580)
+FIX: disabled picto of menu must be greyed.
 FIX: Don't display column when it's out of date (#28271)
 FIX: duplicate with lines: 414-416 (#28358)
+FIX: edit bank suggested for credit transfer payment in invoice setup
 FIX: Error When cloning fourn price no default value for tva_tx (#28368)
+FIX: fatal error Unsupported operand types when recording load payment
+FIX: Fix create shipping with product who have negative stocks on warehouse but the negative stock transfer is allowed (#26217)
 FIX: migration missing 2 columns in llx_resource and 1 in llx_user
 FIX: missing trans
 FIX: notification module: for supplier orders (any of the 3 triggers), user can choose an e-mail template in conf, but the conf is not used when sending the notification (#28216)
-FIX: Not truncate the multicurrency rate shown on cards (even if the global MAIN_MAX_DECIMALS_SHOWN is set to 0) (#28211)
+FIX: Not trancate the multicurrency rate shown on cards (even if the global MAIN_MAX_DECIMALS_SHOWN is set to 0) (#28211)
+FIX: Option MAIN_DOC_USE_TIMING can be a string with date format
 FIX: Payment on customer invoice - Remove accountid in url if empty for apply default value (#28156)
 FIX: Pb in redirect of a website page in USEDOLIBARRSERVER mode
+FIX: permission on payment file of a tax
 FIX: PHP Warning: Undefined variable $lib (#28342)
+FIX: PHP Warning: Undefined variable $mode (#28697)
 FIX: Picto for mime
+FIX: Picto in top menu
 FIX: position of field in list of field in shipment list
 FIX: postgresql error (#28542)
 FIX: quote in sql request
 FIX: Responsive on admin project
 FIX: Shipment closing action has wrong value (#28174)
+FIX: skip adding tab if user doesn't have permission (#28698)
 FIX: some tooltips has disappeared on invoice action button
 FIX: Special code is now transmitted by args only in order supplier (#28546)
+FIX: Special code is now transmitted by args only in order supplier (#28619)
 FIX: subscription must be editable when accounting isn't reconciled (#28469)
+FIX: Translation for select  (#28677)
+FIX: upload odt files should not start/end with space
 FIX: Value of field int = 0 from modulebuilder must not be set to null
+FIX: Wrong currency shown in TakePOS payment page
+FIX: #yogosha21416
 
 
 ***** ChangeLog for 19.0.0 compared to 18.0.0 *****
 
 For users:
 ----------
-NEW: Compatibility with PHP 8.2
+NEW: Compatibility with PHP 8.2 (warning must be disabled)
 NEW: Module Workstation (used to enhance the module BOM and Manufacturing Order) is now stable
 NEW: Add a confirmation popup when deleting extrafields
 NEW: Add type 'icon' type for extrafields
@@ -2208,7 +2389,7 @@ FIX: Button text on proposal card for create a invoice
 FIX: calculateCosts of BOM must not be included into fetch
 FIX: calculation of balance in conciliation page on desc sorting.
 FIX: card.php
-FIX: Change date format of the inventorycode to be equal as mass stock transfert
+FIX: Change date format of the inventorycode to be equal as mass stock transfer
 FIX: check if greater 0
 FIX: close cash with some terminals in TakePOS
 FIX: compatibility with Multicompany
@@ -6990,7 +7171,7 @@ FIX: #6253 Supplier invoice list filter does not respect "thirdparty" filter
 FIX: #6277
 FIX: project list and ajax completion return wrong list.
 FIX: bug margin calculation by user with multicompany
-FIX: Can make a stock transfert on product not on sale/purchase.
+FIX: Can make a stock transfer on product not on sale/purchase.
 FIX: extrafield input for varchar was not working with special char within (ie double quotes)
 FIX: javascript error
 FIX: link for not found photo when using gravatar. Must use external url.
@@ -7470,7 +7651,7 @@ FIX: Check of EAN13 barcode when mask was set to use 13 digits instead of 12
 FIX: correct display of minimum buying price
 FIX: Creation of thumb image for size "small" was not done.
 FIX: Damn, where was the project ref ?
-FIX: Default vat is not set correctly when an error occured and we use VAT identified by a code.
+FIX: Default vat is not set correctly when an error occurred and we use VAT identified by a code.
 FIX: dont retrieve new buying price on margin display
 FIX: Duplicate records into export
 FIX: Each time we edit a line, we loose the unit price.
@@ -10229,7 +10410,7 @@ For developers:
 - Can protect a module to not being enabled if javascript disabled.
 - If module numberwords is installed, code can use langs->getLabelFromNumber
   to get value of an amount in text.
-- A module can add subsitution keys in makesubsitutions() functions.
+- A module can add substitution keys in makesubsitutions() functions.
 - Add $conf->browser->phone defined to optimise code for smartphone browsers.
 - All external libs are now in same directory /includes.
 - All install files are now in same directory /install.

+ 1 - 1
build/exe/doliwamp/Languages/MyCatalan.isl

@@ -43,5 +43,5 @@ DoliWampWillStartApacheMysql=L'instal·lador DoliWamp intentarà iniciar o reini
 OldVersionFoundAndMoveInNew=S'ha trobat una versió antiga de base de dades i ha estat moguda per a ser utilitzada per la nova versió de Dolibarr
 OldVersionFoundButFailedToMoveInNew=S'ha trobat una versió antiga de base de dades, però no es pot moure per a ser utilitzada per la nova versió de Dolibarr
 
-DLLMissing=La teva instal·lació windows no té el component "Microsoft Visual C++ Redistributable for Visual Studio 2015". Instal·la primer la versió de 32-bit (vcredist_x86.exe) (pots trobar-la a https://www.microsoft.com/en-us/download/) i reiniciar després la instal·lació/actualització de DoliWamp.
+DLLMissing=La teva instal·lació windows no té el component "Microsoft Visual C++ Redistributable for Visual Studio 2017". Instal·la primer la versió de 32-bit (vcredist_x86.exe) (pots trobar-la a https://www.microsoft.com/en-us/download/) i reiniciar després la instal·lació/actualització de DoliWamp.
 ContinueAnyway=Continua igualment (el procés d'instal·lació podria fallar sense aquest prerequisit)

+ 1 - 1
build/exe/doliwamp/Languages/MyEnglish.isl

@@ -44,5 +44,5 @@ DoliWampWillStartApacheMysql=DoliWamp installer will now start or restart Apache
 OldVersionFoundAndMoveInNew=An old database version has been found and moved to be used by the new Dolibarr version
 OldVersionFoundButFailedToMoveInNew=An old database version has been found but could not be moved to be used with the new Dolibarr version
 
-DLLMissing=Your Windows installation is missing The "Microsoft Visual C++ Redistributable for Visual Studio 2015" component. Please install the 32-bit version (vcredist_x86.exe) first (you can find it at https://www.microsoft.com/en-us/download/) and restart DoliWamp installation/upgrade after.
+DLLMissing=Your Windows installation is missing The "Microsoft Visual C++ Redistributable for Visual Studio 2017" component. Please install the 32-bit version (vcredist_x86.exe) first (you can find it at https://learn.microsoft.com/en-US/cpp/windows/latest-supported-vc-redist?view=msvc-170) and restart DoliWamp installation/upgrade after.
 ContinueAnyway=Continue anyway (install process may fail without this prerequisite)

+ 1 - 1
build/exe/doliwamp/Languages/MyFrench.isl

@@ -44,5 +44,5 @@ DoliWampWillStartApacheMysql=L'installeur DoliWamp va maintenant d
 OldVersionFoundAndMoveInNew=Une ancienne version de base a été trouvée et déplacée pour fonctionner avec la nouvelle version de Dolibarr.
 OldVersionFoundButFailedToMoveInNew=Une ancienne version de base a été trouvée mais ne peut être déplacée pour être utilisée avec la nouvelle version de Dolibarr.
 
-DLLMissing=L'installation de votre Windows est incomplète. Il manque le composant "Micrsoft Visual C++ Redistributable for Visual Studio 2015". Installer la version 32-bit (vcredist_x86.exe) d'abord (vous pourrez le trouver à https://www.microsoft.com/fr-fr/download/) puis relancer l'installation de DoliWamp après.
+DLLMissing=L'installation de votre Windows est incomplète. Il manque le composant "Micrsoft Visual C++ Redistributable for Visual Studio 2017". Installer la version 32-bit (vcredist_x86.exe) d'abord (vous pourrez le trouver à https://www.microsoft.com/fr-fr/download/) puis relancer l'installation de DoliWamp après.
 ContinueAnyway=Continuer malgré tout (le process d'installaton échouera)

+ 1 - 1
build/exe/doliwamp/Languages/MyGerman.isl

@@ -43,5 +43,5 @@ DoliWampWillStartApacheMysql=Die DoliWamp-Installation wird nun starten oder Apa
 OldVersionFoundAndMoveInNew=Eine alte Datenbankversion wurde gefunden und verschoben, um von der neuen Dolibarr-Version verwendet zu werden.
 OldVersionFoundButFailedToMoveInNew=Eine alte Datenbankversion wurde gefunden, konnte jedoch nicht verschoben werden, um mit der neuen Dolibarr-Version verwendet zu werden.
 
-DLLMissing=Your Windows installation is missing The "Micrsoft Visual C++ Redistributable for Visual Studio 2015" component. Please install the 32-bit version (vcredist_x86.exe) first (you can find it at https://www.microsoft.com/en-us/download/) and restart DoliWamp installation/upgrade after.
+DLLMissing=Your Windows installation is missing The "Micrsoft Visual C++ Redistributable for Visual Studio 2017" component. Please install the 32-bit version (vcredist_x86.exe) first (you can find it at https://www.microsoft.com/en-us/download/) and restart DoliWamp installation/upgrade after.
 ContinueAnyway=Fahren Sie trotzdem fort (der Installationsvorgang kann ohne diese Voraussetzung fehlschlagen).

+ 1 - 1
build/exe/doliwamp/Languages/MySpanish.isl

@@ -43,5 +43,5 @@ DoliWampWillStartApacheMysql=El instalador DoliWamp intentará iniciar o reinici
 OldVersionFoundAndMoveInNew=Se ha encontrado una versión antigua de base de datos y ha sido movida para ser utilizada por la nueva versión de Dolibarr
 OldVersionFoundButFailedToMoveInNew=Se ha encontrado una versión antigua de base de datos, pero no se pudo mover para ser utilizada por la nueva versión de Dolibarr
  	  	 
-DLLMissing=Su instalación Windows no tiene el componente "Microsoft Visual C++ Redistributable for Visual Studio 2015". Instale primero la versión de 32-bit (vcredist_x86.exe) (puedes encontrarlo en https://www.microsoft.com/en-us/download/) y reiniciar después la instalación/actualización de DoliWamp.
+DLLMissing=Su instalación Windows no tiene el componente "Microsoft Visual C++ Redistributable for Visual Studio 2017". Instale primero la versión de 32-bit (vcredist_x86.exe) (puedes encontrarlo en https://www.microsoft.com/en-us/download/) y reiniciar después la instalación/actualización de DoliWamp.
 ContinueAnyway=Continua igualmente (el proceso de instalación podría fallar sin este prerequisito)

+ 4 - 4
build/exe/doliwamp/doliwamp.iss

@@ -100,9 +100,9 @@ Source: "build\exe\doliwamp\UsedPort.exe"; DestDir: "{app}\"; Flags: ignoreversi
 
 ; Apache, Php, Mysql
 ; Put here path of Wampserver applications
-; Value OK: apache 2.4.51, php 7.3.33, mariadb10.6.5 (wampserver3.2.6_x64.exe)
+; Value OK: apache 2.4.51, php 7.4.26, mariadb10.6.5 (wampserver3.2.6_x64.exe)
 Source: "C:\wamp64\bin\apache\apache2.4.51\*.*"; DestDir: "{app}\bin\apache\apache2.4.51"; Flags: ignoreversion recursesubdirs; Excludes: "php.ini,httpd.conf,wampserver.conf,*.log,*_log"
-Source: "C:\wamp64\bin\php\php7.3.33\*.*"; DestDir: "{app}\bin\php\php7.3.33"; Flags: ignoreversion recursesubdirs; Excludes: "php.ini,phpForApache.ini,wampserver.conf,*.log,*_log"
+Source: "C:\wamp64\bin\php\php7.4.26\*.*"; DestDir: "{app}\bin\php\php7.4.26"; Flags: ignoreversion recursesubdirs; Excludes: "php.ini,phpForApache.ini,wampserver.conf,*.log,*_log"
 Source: "C:\wamp64\bin\mariadb\mariadb10.6.5\*.*"; DestDir: "{app}\bin\mariadb\mariadb10.6.5"; Flags: ignoreversion recursesubdirs; Excludes: "my.ini,data\*,wampserver.conf,*.log,*_log,MySQLInstanceConfig.exe"
 
 ; Mysql data files (does not overwrite if exists)
@@ -121,7 +121,7 @@ Source: "build\exe\doliwamp\dolibarr.conf.install"; DestDir: "{app}\alias"; Flag
 Source: "build\exe\doliwamp\httpd.conf.install"; DestDir: "{app}\bin\apache\apache2.4.51\conf"; Flags: ignoreversion;
 Source: "build\exe\doliwamp\my.ini.install"; DestDir: "{app}\bin\mysql\mysql5.0.45"; Flags: ignoreversion;
 Source: "build\exe\doliwamp\my.ini.install"; DestDir: "{app}\bin\mariadb\mariadb10.6.5"; Flags: ignoreversion;
-Source: "build\exe\doliwamp\php.ini.install"; DestDir: "{app}\bin\php\php7.3.33"; Flags: ignoreversion;
+Source: "build\exe\doliwamp\php.ini.install"; DestDir: "{app}\bin\php\php7.4.26"; Flags: ignoreversion;
 Source: "build\exe\doliwamp\index.php.install"; DestDir: "{app}\www"; Flags: ignoreversion;
 Source: "build\exe\doliwamp\install.forced.php.install"; DestDir: "{app}\www\dolibarr\htdocs\install"; Flags: ignoreversion;
 Source: "build\exe\doliwamp\openssl.conf"; DestDir: "{app}"; Flags: ignoreversion;
@@ -228,7 +228,7 @@ begin
 
   //version des applis, a modifier pour chaque version de WampServer 2
   apacheVersion := '2.4.51';
-  phpVersion := '7.3.33' ;
+  phpVersion := '7.4.26' ;
   mysqlVersion := '10.6.5';
 
   smtpServer := 'localhost';

+ 7 - 7
build/generate_filelist_xml.php

@@ -33,7 +33,7 @@ $path = dirname(__FILE__).'/';
 // Test if batch mode
 if (substr($sapi_type, 0, 3) == 'cgi') {
 	echo "Error: You are using PHP for CGI. To execute ".$script_file." from command line, you must use PHP for CLI mode.\n";
-	exit;
+	exit(1);
 }
 
 require_once $path."../htdocs/master.inc.php";
@@ -51,7 +51,7 @@ $buildzip = 0;
 if (empty($argv[1])) {
 	print "Usage:   ".$script_file." release=autostable|auto[-mybuild]|x.y.z[-mybuild] [includecustom=1] [includeconstant=CC:MY_CONF_NAME:value] [buildzip=1]\n";
 	print "Example: ".$script_file." release=6.0.0 includecustom=1 includeconstant=FR:INVOICE_CAN_ALWAYS_BE_REMOVED:0 includeconstant=all:MAILING_NO_USING_PHPMAIL:1\n";
-	exit -1;
+	exit(1);
 }
 
 
@@ -87,7 +87,7 @@ while ($i < $argc) {
 if (empty($release)) {
 	print "Error: Missing release parameter\n";
 	print "Usage: ".$script_file." release=autostable|auto[-mybuild]|x.y.z[-mybuild] [includecustom=1] [includeconstant=CC:MY_CONF_NAME:value]\n";
-	exit -1;
+	exit(2);
 }
 
 $savrelease = $release;
@@ -107,21 +107,21 @@ if (empty($includecustom)) {
 		if (DOL_VERSION != $tmpverbis[0] && $savrelease != 'auto') {
 			print 'Error: When parameter "includecustom" is not set and there is no suffix in release parameter, version declared into filefunc.in.php ('.DOL_VERSION.') must be exact same value than "release" parameter ('.$tmpverbis[0].')'."\n";
 			print "Usage:   ".$script_file." release=autostable|auto[-mybuild]|x.y.z[-mybuild] [includecustom=1] [includeconstant=CC:MY_CONF_NAME:value]\n";
-			exit -1;
+			exit(3);
 		}
 	} else {
 		$tmpverter = explode('-', DOL_VERSION, 2);
 		if ($tmpverter[0] != $tmpverbis[0]) {
 			print 'Error: When parameter "includecustom" is not set, version declared into filefunc.in.php ('.DOL_VERSION.') must have value without prefix ('.$tmpverter[0].') that is exact same value than "release" parameter ('.$tmpverbis[0].')'."\n";
 			print "Usage:   ".$script_file." release=autostable|auto[-mybuild]|x.y.z[-mybuild] [includecustom=1] [includeconstant=CC:MY_CONF_NAME:value]\n";
-			exit -1;
+			exit(4);
 		}
 	}
 } else {
 	if (!preg_match('/'.preg_quote(DOL_VERSION, '/').'-/', $release)) {
 		print 'Error: When parameter "includecustom" is set, version declared into filefunc.inc.php ('.DOL_VERSION.') must be used with a suffix into "release" parameter (ex: '.DOL_VERSION.'-mydistrib).'."\n";
 		print "Usage:   ".$script_file." release=autostable|auto[-mybuild]|x.y.z[-mybuild] [includecustom=1] [includeconstant=CC:MY_CONF_NAME:value]\n";
-		exit -1;
+		exit(5);
 	}
 }
 
@@ -147,7 +147,7 @@ $outputfile = $outputdir.'/filelist-'.$release.'.xml';
 $fp = fopen($outputfile, 'w');
 if (empty($fp)) {
 	print 'Failed to open file '.$outputfile."\n";
-	exit(-1);
+	exit(6);
 }
 
 fputs($fp, '<?xml version="1.0" encoding="UTF-8" ?>'."\n");

+ 3 - 2
build/makepack-howto.txt

@@ -29,12 +29,13 @@ Prerequisites to build autoexe DoliWamp package from Windows:
 
 > Install Perl for Windows (https://strawberryperl.com/)
 > Install isetup-5.5.8.exe (https://www.jrsoftware.org)
-> Install WampServer-3.2.*-64.exe (Apache 2.4.51, PHP 7.3.33, MariaDB 10.6.5 for example. Version must match the values found into doliwamp.iss)
+> Install Microsoft Visual C++ Redistributable 2017 (https://learn.microsoft.com/en-US/cpp/windows/latest-supported-vc-redist?view=msvc-170)
+> Install WampServer-3.2.6-64.exe (Apache 2.4.51, PHP 7.4.26, MariaDB 10.6.5 for example. Version must match the values found into doliwamp.iss)
 > Install GIT for Windows (https://git-scm.com/ => You must choose option "Add Git bash profile", "Git commit as-is")
 > Install Dolibarr current version:   
   git clone https://github.com/dolibarr/dolibarr  or  git clone --branch X.Y https://github.com/dolibarr/dolibarr  
 
-> Add the path of PHP (C:\wamp64\bin\php\php7.3.33) and InnoSetup (C:\Program Files (x86)\Inno Setup 5) into the %PATH% of Windows.
+> Add the path of PHP (C:\wamp64\bin\php\php7.4.26) and InnoSetup (C:\Program Files (x86)\Inno Setup 5) into the %PATH% of Windows.
 
 > Create a config file c:\dolibarr\dolibarr\htdocs\conf\conf.php with content
   <?php

+ 2 - 2
build/rpm/dolibarr_fedora.spec

@@ -25,8 +25,8 @@ BuildArch: noarch
 BuildRoot: %{_tmppath}/%{name}-%{version}-build
 
 Group: Applications/Productivity
-Requires: httpd, php >= 5.3.0, php-cli, php-gd, php-ldap, php-imap, php-mysqli, php-nusoap, dejavu-sans-fonts
-Requires: mysql-server, mysql
+Requires: httpd, php >= 5.3.0, php-cli, php-gd, php-ldap, php-mysqli, php-nusoap, dejavu-sans-fonts
+Requires: mariadb-server, mariadb
 #BuildRequires: desktop-file-utils
 
 # Set yes to build test package, no for release (this disable need of /usr/bin/php not found by OpenSuse)

+ 2 - 2
build/rpm/dolibarr_generic.spec

@@ -46,8 +46,8 @@ BuildRoot: %{_tmppath}/%{name}-%{version}-build
 
 %if 0%{?fedora} || 0%{?rhel_version} || 0%{?centos_version}
 Group: Applications/Productivity
-Requires: httpd, php >= 5.3.0, php-cli, php-gd, php-ldap, php-imap, php-mysqli, php-nusoap, dejavu-sans-fonts, php-mbstring, php-xml
-Requires: mysql-server, mysql
+Requires: httpd, php >= 5.3.0, php-cli, php-gd, php-ldap, php-mysqli, php-nusoap, dejavu-sans-fonts, php-mbstring, php-xml
+Requires: mariadb-server, mariadb
 BuildRequires: desktop-file-utils
 %else
 %if 0%{?mdkversion}

+ 1 - 1
dev/initdemo/mysqldump_dolibarr_19.0.0.sql

@@ -2999,7 +2999,7 @@ DROP TABLE IF EXISTS `llx_c_type_contact`;
 /*!40101 SET @saved_cs_client     = @@character_set_client */;
 /*!40101 SET character_set_client = utf8 */;
 CREATE TABLE `llx_c_type_contact` (
-  `rowid` int(11) NOT NULL,
+  `rowid` int(11) NOT NULL AUTO_INCREMENT,
   `element` varchar(30) NOT NULL,
   `source` varchar(8) NOT NULL DEFAULT 'external',
   `code` varchar(32) NOT NULL,

+ 1 - 0
dev/tools/codespell/codespell-ignore.txt

@@ -19,6 +19,7 @@ contaxt
 courant
 datea
 datee
+doubleclick
 errorstring
 exten
 falsy

+ 0 - 5
htdocs/accountancy/admin/categories_list.php

@@ -299,11 +299,6 @@ if (GETPOST('actionadd', 'alpha') || GETPOST('actionmodify', 'alpha')) {
 			setEventMessages($db->error(), null, 'errors');
 		}
 	}
-	//$_GET["id"]=GETPOST('id', 'int');       // Force affichage dictionnaire en cours d'edition
-}
-
-if (GETPOST('actioncancel', 'alpha')) {
-	//$_GET["id"]=GETPOST('id', 'int');       // Force affichage dictionnaire en cours d'edition
 }
 
 if ($action == 'confirm_delete' && $confirm == 'yes') {       // delete

+ 6 - 6
htdocs/accountancy/admin/fiscalyear_card.php

@@ -313,23 +313,23 @@ if ($object->id > 0 && (empty($action) || ($action != 'edit' && $action != 'crea
 
 	// Label
 	print '<tr><td class="tdtop">';
-	print $form->editfieldkey("Label", 'label', $object->label, $object, 1, 'alpha:32');
+	print $form->editfieldkey("Label", 'label', $object->label, $object, 0, 'alpha:32');
 	print '</td><td colspan="2">';
-	print $form->editfieldval("Label", 'label', $object->label, $object, 1, 'alpha:32');
+	print $form->editfieldval("Label", 'label', $object->label, $object, 0, 'alpha:32');
 	print "</td></tr>";
 
 	// Date start
 	print '<tr><td>';
-	print $form->editfieldkey("DateStart", 'date_start', $object->date_start, $object, 1, 'datepicker');
+	print $form->editfieldkey("DateStart", 'date_start', $object->date_start, $object, 0, 'datepicker');
 	print '</td><td colspan="2">';
-	print $form->editfieldval("DateStart", 'date_start', $object->date_start, $object, 1, 'datepicker');
+	print $form->editfieldval("DateStart", 'date_start', $object->date_start, $object, 0, 'datepicker');
 	print '</td></tr>';
 
 	// Date end
 	print '<tr><td>';
-	print $form->editfieldkey("DateEnd", 'date_end', $object->date_end, $object, 1, 'datepicker');
+	print $form->editfieldkey("DateEnd", 'date_end', $object->date_end, $object, 0, 'datepicker');
 	print '</td><td colspan="2">';
-	print $form->editfieldval("DateEnd", 'date_end', $object->date_end, $object, 1, 'datepicker');
+	print $form->editfieldval("DateEnd", 'date_end', $object->date_end, $object, 0, 'datepicker');
 	print '</td></tr>';
 
 	// Status

+ 0 - 6
htdocs/accountancy/admin/journals_list.php

@@ -272,14 +272,8 @@ if (GETPOST('actionadd', 'alpha') || GETPOST('actionmodify', 'alpha')) {
 			setEventMessages($db->error(), null, 'errors');
 		}
 	}
-	//$_GET["id"]=GETPOST('id', 'int');       // Force affichage dictionnaire en cours d'edition
 }
 
-//if (GETPOST('actioncancel', 'alpha'))
-//{
-//	$_GET["id"]=GETPOST('id', 'int');       // Force affichage dictionnaire en cours d'edition
-//}
-
 if ($action == 'confirm_delete' && $confirm == 'yes') {       // delete
 	if ($tabrowid[$id]) {
 		$rowidcol = $tabrowid[$id];

+ 8 - 4
htdocs/accountancy/admin/subaccount.php

@@ -128,6 +128,7 @@ $form = new Form($db);
 // Page Header
 $help_url = 'EN:Module_Double_Entry_Accounting#Setup|FR:Module_Comptabilit&eacute;_en_Partie_Double#Configuration';
 $title = $langs->trans('ChartOfIndividualAccountsOfSubsidiaryLedger');
+
 llxHeader('', $title, $help_url);
 
 
@@ -300,14 +301,17 @@ if ($resql) {
 	if ($limit > 0 && $limit != $conf->liste_limit) {
 		$param .= '&limit='.((int) $limit);
 	}
+	if ($optioncss != '') {
+		$param .= '&optioncss='.urlencode($optioncss);
+	}
 	if ($search_subaccount) {
 		$param .= '&search_subaccount='.urlencode($search_subaccount);
 	}
 	if ($search_label) {
 		$param .= '&search_label='.urlencode($search_label);
 	}
-	if ($optioncss != '') {
-		$param .= '&optioncss='.urlencode($optioncss);
+	if ($search_type) {
+		$param .= '&search_type='.urlencode($search_type);
 	}
 
 	// List of mass actions available
@@ -373,7 +377,7 @@ if ($resql) {
 	print '<tr class="liste_titre">';
 	// Action column
 	if (getDolGlobalString('MAIN_CHECKBOX_LEFT_COLUMN')) {
-		print_liste_field_titre($selectedfields, $_SERVER["PHP_SELF"], "", '', '', '', $sortfield, $sortorder, 'center maxwidthsearch ');
+		print_liste_field_titre($selectedfields, $_SERVER["PHP_SELF"], "", '', $param, '', $sortfield, $sortorder, 'center maxwidthsearch ');
 	}
 	if (!empty($arrayfields['subaccount']['checked'])) {
 		print_liste_field_titre($arrayfields['subaccount']['label'], $_SERVER["PHP_SELF"], "subaccount", "", $param, '', $sortfield, $sortorder);
@@ -391,7 +395,7 @@ if ($resql) {
 	}
 	// Action column
 	if (!getDolGlobalString('MAIN_CHECKBOX_LEFT_COLUMN')) {
-		print_liste_field_titre($selectedfields, $_SERVER["PHP_SELF"], "", '', '', '', $sortfield, $sortorder, 'center maxwidthsearch ');
+		print_liste_field_titre($selectedfields, $_SERVER["PHP_SELF"], "", '', $param, '', $sortfield, $sortorder, 'center maxwidthsearch ');
 	}
 	print "</tr>\n";
 

+ 6 - 3
htdocs/accountancy/bookkeeping/balance.php

@@ -473,9 +473,12 @@ if ($action != 'export_csv') {
 		$resql = $db->query($sql);
 		$nrows = $resql->num_rows;
 		$opening_balances = array();
-		for ($i = 0; $i < $nrows; $i++) {
-			$arr = $resql->fetch_array();
-			$opening_balances["'" . $arr['numero_compte'] . "'"] = $arr['opening_balance'];
+		if ($resql) {
+			$nrows = $db->num_rows($resql);
+			for ($i = 0; $i < $nrows; $i++) {
+				$arr = $db->fetch_array($resql);
+				$opening_balances["'" . $arr['numero_compte'] . "'"] = $arr['opening_balance'];
+			}
 		}
 	}
 

+ 3 - 0
htdocs/accountancy/bookkeeping/card.php

@@ -204,6 +204,8 @@ if ($action == "confirm_update") {
 		$result = $object->createStd($user, false, $mode);
 		if ($result < 0) {
 			setEventMessages($object->error, $object->errors, 'errors');
+
+			$action = 'create';
 		} else {
 			if ($mode != '_tmp') {
 				setEventMessages($langs->trans('RecordSaved'), null, 'mesgs');
@@ -404,6 +406,7 @@ if ($action == 'create') {
 	print '</form>';
 } else {
 	$object = new BookKeeping($db);
+
 	$result = $object->fetchPerMvt($piece_num, $mode);
 	if ($result < 0) {
 		setEventMessages($object->error, $object->errors, 'errors');

+ 5 - 2
htdocs/accountancy/bookkeeping/export.php

@@ -765,8 +765,11 @@ if ($action == 'export_file') {
 		$form_question['separator3'] = array('name'=>'separator3', 'type'=>'separator');
 	}
 
-	// add documents in an archive for accountancy export (Quadratus)
-	if (getDolGlobalString('ACCOUNTING_EXPORT_MODELCSV') == AccountancyExport::$EXPORT_TYPE_QUADRATUS) {
+	// add documents in an archive for some accountancy export format
+	if (getDolGlobalString('ACCOUNTING_EXPORT_MODELCSV') == AccountancyExport::$EXPORT_TYPE_QUADRATUS
+		|| getDolGlobalString('ACCOUNTING_EXPORT_MODELCSV') == AccountancyExport::$EXPORT_TYPE_FEC
+		|| getDolGlobalString('ACCOUNTING_EXPORT_MODELCSV') == AccountancyExport::$EXPORT_TYPE_FEC2
+		) {
 		$form_question['notifiedexportfull'] = array(
 			'name' => 'notifiedexportfull',
 			'type' => 'checkbox',

+ 3 - 3
htdocs/accountancy/bookkeeping/list.php

@@ -484,7 +484,7 @@ if (empty($reshook)) {
 					setEventMessages($object->error, $object->errors, 'errors');
 					$error++;
 					break;
-				} elseif (isset($object->date_validation) || $object->date_validation != '') {
+				} elseif (isset($object->date_validation) && $object->date_validation != '') {
 					setEventMessages($langs->trans("ValidatedRecordWhereFound"), null, 'errors');
 					$error++;
 					break;
@@ -938,7 +938,7 @@ if (!empty($arrayfields['t.tms']['checked'])) {
 	print $form->selectDate($search_date_modification_start, 'search_date_modification_start', 0, 0, 1, '', 1, 0, 0, '', '', '', '', 1, '', $langs->trans("From"));
 	print '</div>';
 	print '<div class="nowrapfordate">';
-	print $form->selectDate($search_date_modification_end, 'search_date_modification_end', 0, 0, 1, '', 1, 0, 0, '', '', '', '', 1, '', $langs->trans("From"));
+	print $form->selectDate($search_date_modification_end, 'search_date_modification_end', 0, 0, 1, '', 1, 0, 0, '', '', '', '', 1, '', $langs->trans("to"));
 	print '</div>';
 	print '</td>';
 }
@@ -1300,7 +1300,7 @@ while ($i < min($num, $limit)) {
 	}
 
 	if (!empty($arrayfields['t.import_key']['checked'])) {
-		print '<td class="tdoverflowmax100">'.$obj->import_key."</td>\n";
+		print '<td class="tdoverflowmax125" title="'.dol_escape_htmltag($obj->import_key).'">'.dol_escape_htmltag($obj->import_key)."</td>\n";
 		if (!$i) {
 			$totalarray['nbfield']++;
 		}

+ 3 - 2
htdocs/accountancy/bookkeeping/listbyaccount.php

@@ -447,7 +447,7 @@ if (empty($reshook)) {
 					setEventMessages($object->error, $object->errors, 'errors');
 					$error++;
 					break;
-				} elseif (isset($object->date_validation) || $object->date_validation != '') {
+				} elseif (isset($object->date_validation) && $object->date_validation != '') {
 					setEventMessages($langs->trans("ValidatedRecordWhereFound"), null, 'errors');
 					$error++;
 					break;
@@ -974,6 +974,7 @@ $sous_total_debit = 0;
 $sous_total_credit = 0;
 $totalarray['val']['totaldebit'] = 0;
 $totalarray['val']['totalcredit'] = 0;
+$totalarray['val']['totalbalance']=0;
 
 while ($i < min($num, $limit)) {
 	$line = $object->lines[$i];
@@ -1295,7 +1296,7 @@ while ($i < min($num, $limit)) {
 	}
 
 	if (!empty($arrayfields['t.import_key']['checked'])) {
-		print '<td class="tdoverflowmax100">'.dol_escape_htmltag($line->import_key)."</td>\n";
+		print '<td class="tdoverflowmax125" title="'.dol_escape_htmltag($line->import_key).'">'.dol_escape_htmltag($line->import_key)."</td>\n";
 		if (!$i) {
 			$totalarray['nbfield']++;
 		}

+ 7 - 6
htdocs/accountancy/class/accountancyexport.class.php

@@ -5,7 +5,7 @@
  * Copyright (C) 2015       Florian Henry       <florian.henry@open-concept.pro>
  * Copyright (C) 2015       Raphaël Doursenaud  <rdoursenaud@gpcsolutions.fr>
  * Copyright (C) 2016       Pierre-Henry Favre  <phf@atm-consulting.fr>
- * Copyright (C) 2016-2023  Alexandre Spangaro  <aspangaro@open-dsi.fr>
+ * Copyright (C) 2016-2024  Alexandre Spangaro  <aspangaro@open-dsi.fr>
  * Copyright (C) 2022  		Lionel Vessiller    <lvessiller@open-dsi.fr>
  * Copyright (C) 2013-2017  Olivier Geffroy     <jeff@jeffinfo.com>
  * Copyright (C) 2017       Elarifr. Ari Elbaz  <github@accedinfo.com>
@@ -389,11 +389,12 @@ class AccountancyExport
 				// directory already created when module is enabled
 				$outputDir .= '/export';
 				$outputDir .= '/'.dol_sanitizePathName($formatexportset);
-				if (!dol_is_dir($outputDir)) {
-					if (dol_mkdir($outputDir) < 0) {
-						$this->errors[] = $langs->trans('ErrorCanNotCreateDir', $outputDir);
-						return -1;
-					}
+			}
+
+			if (!dol_is_dir($outputDir)) {
+				if (dol_mkdir($outputDir) < 0) {
+					$this->errors[] = $langs->trans('ErrorCanNotCreateDir', $outputDir);
+					return -1;
 				}
 			}
 

+ 5 - 7
htdocs/accountancy/class/accountancyimport.class.php

@@ -93,10 +93,9 @@ class AccountancyImport
 	public function computeAmount(&$arrayrecord, $listfields, $record_key)
 	{
 		// get fields indexes
-		$field_index_list = array_flip($listfields);
-		if (isset($field_index_list['debit']) && isset($field_index_list['credit'])) {
-			$debit_index = $field_index_list['debit'];
-			$credit_index = $field_index_list['credit'];
+		if (isset($listfields['b.debit']) && isset($listfields['b.credit'])) {
+			$debit_index = $listfields['b.debit'];
+			$credit_index = $listfields['b.credit'];
 
 			$debit  = (float) $arrayrecord[$debit_index]['val'];
 			$credit = (float) $arrayrecord[$credit_index]['val'];
@@ -123,9 +122,8 @@ class AccountancyImport
 	 */
 	public function computeDirection(&$arrayrecord, $listfields, $record_key)
 	{
-		$field_index_list = array_flip($listfields);
-		if (isset($field_index_list['debit'])) {
-			$debit_index = $field_index_list['debit'];
+		if (isset($listfields['b.debit'])) {
+			$debit_index = $listfields['b.debit'];
 
 			$debit = (float) $arrayrecord[$debit_index]['val'];
 			if (!empty($debit)) {

+ 15 - 14
htdocs/accountancy/class/bookkeeping.class.php

@@ -758,11 +758,10 @@ class BookKeeping extends CommonObject
 	/**
 	 * Load object in memory from the database
 	 *
-	 * @param int $id Id object
-	 * @param string $ref Ref
-	 * @param string $mode 	Mode
-	 *
-	 * @return int Return integer <0 if KO, 0 if not found, >0 if OK
+	 * @param int 		$id 	Id object
+	 * @param string 	$ref 	Ref
+	 * @param string 	$mode 	Mode ('' or 'tmp_')
+	 * @return int 				Return integer <0 if KO, 0 if not found, >0 if OK
 	 */
 	public function fetch($id, $ref = null, $mode = '')
 	{
@@ -1491,17 +1490,18 @@ class BookKeeping extends CommonObject
 	/**
 	 * Delete object in database
 	 *
-	 * @param User $user User that deletes
-	 * @param bool $notrigger false=launch triggers after, true=disable triggers
-	 * @param string $mode Mode
-	 * @return int Return integer <0 if KO, >0 if OK
+	 * @param User 		$user 		User that deletes
+	 * @param int 		$notrigger 	0=launch triggers after, 1=disable triggers
+	 * @param string 	$mode 		Mode ('' or 'tmp_')
+	 * @return int 					Return integer <0 if KO, >0 if OK
 	 */
-	public function delete(User $user, $notrigger = false, $mode = '')
+	public function delete(User $user, $notrigger = 0, $mode = '')
 	{
 		global $langs;
+
 		dol_syslog(__METHOD__, LOG_DEBUG);
 
-		$result = $this->canModifyBookkeeping($this->id);
+		$result = $this->canModifyBookkeeping($this->id, $mode);
 		if ($result < 0) {
 			return -1;
 		} elseif ($result == 0) {
@@ -2303,9 +2303,10 @@ class BookKeeping extends CommonObject
 	 * Is the bookkeeping can be modified or deleted ?
 	 *
 	 * @param 	int		$id		Bookkeeping ID
+	 * @param 	string 	$mode 	Mode ('' or 'tmp_')
 	 * @return 	int				Return integer <0 if KO, == 0 if No, == 1 if Yes
 	 */
-	public function canModifyBookkeeping($id)
+	public function canModifyBookkeeping($id, $mode = '')
 	{
 		global $conf;
 
@@ -2317,7 +2318,7 @@ class BookKeeping extends CommonObject
 			}
 
 			$bookkeeping = new BookKeeping($this->db);
-			$result = $bookkeeping->fetch($id);
+			$result = $bookkeeping->fetch($id, null, $mode);
 			if ($result <= 0) {
 				return $result;
 			}
@@ -2338,7 +2339,7 @@ class BookKeeping extends CommonObject
 			}
 
 			$bookkeeping = new BookKeeping($this->db);
-			$result = $bookkeeping->fetch($id);
+			$result = $bookkeeping->fetch($id, null, $mode);
 			if ($result <= 0) {
 				return $result;
 			}

+ 28 - 4
htdocs/accountancy/class/lettering.class.php

@@ -51,6 +51,10 @@ class Lettering extends BookKeeping
 					'table' => 'societe_remise_except',
 					'fk_doc' => 'fk_facture_source',
 					'fk_link' => 'fk_facture',
+					'fk_line_link' => 'fk_facture_line',
+					'table_link_line' => 'facturedet',
+					'fk_table_link_line' => 'rowid',
+					'fk_table_link_line_parent' => 'fk_facture',
 					'prefix' => 'a',
 					'is_fk_link_is_also_fk_doc' => true,
 				),
@@ -73,6 +77,10 @@ class Lettering extends BookKeeping
 					'table' => 'societe_remise_except',
 					'fk_doc' => 'fk_invoice_supplier_source',
 					'fk_link' => 'fk_invoice_supplier',
+					'fk_line_link' => 'fk_invoice_supplier_line',
+					'table_link_line' => 'facture_fourn_det',
+					'fk_table_link_line' => 'rowid',
+					'fk_table_link_line_parent' => 'fk_facture_fourn',
 					'prefix' => 'a',
 					'is_fk_link_is_also_fk_doc' => true,
 				),
@@ -781,10 +789,26 @@ class Lettering extends BookKeeping
 		$link_by_element = array();
 		$element_by_link = array();
 		foreach ($doc_type_info['linked_info'] as $linked_info) {
-			$sql = "SELECT DISTINCT tl2." . $linked_info['fk_link'] . " AS fk_link, tl2." . $linked_info['fk_doc'] . " AS fk_doc";
-			$sql .= " FROM " . MAIN_DB_PREFIX . $linked_info['table'] . " AS tl";
-			$sql .= " LEFT JOIN " . MAIN_DB_PREFIX . $linked_info['table'] . " AS tl2 ON tl2." . $linked_info['fk_link'] . " = tl." . $linked_info['fk_link'];
-			$sql .= " WHERE tl." . $linked_info['fk_doc'] . " IN (" . $this->db->sanitize(implode(',', $document_ids)) . ")";
+			if (empty($linked_info['fk_line_link'])) {
+				$sql = "SELECT DISTINCT tl2.".$linked_info['fk_link']." AS fk_link, tl2.".$linked_info['fk_doc']." AS fk_doc";
+				$sql .= " FROM ".MAIN_DB_PREFIX.$linked_info['table']." AS tl";
+				$sql .= " LEFT JOIN ".MAIN_DB_PREFIX.$linked_info['table']." AS tl2 ON tl2.".$linked_info['fk_link']." = tl.".$linked_info['fk_link'];
+				$sql .= " WHERE tl.".$linked_info['fk_doc']." IN (".$this->db->sanitize(implode(',', $document_ids)).")";
+			} else {
+				$sql = "SELECT DISTINCT tl2.fk_link, tl2.fk_doc";
+				$sql .= " FROM (";
+				$sql .= "   SELECT DISTINCT " . $this->db->ifsql("tll." . $linked_info['fk_table_link_line_parent'],  "tll." . $linked_info['fk_table_link_line_parent'],  "tl." . $linked_info['fk_link']) . " AS fk_link, tl." . $linked_info['fk_doc'] . " AS fk_doc";
+				$sql .= "   FROM " . MAIN_DB_PREFIX . $linked_info['table'] . " AS tl";
+				$sql .= "   LEFT JOIN " . MAIN_DB_PREFIX . $linked_info['table_link_line'] . " AS tll ON tll." . $linked_info['fk_table_link_line'] . " = tl." . $linked_info['fk_line_link'];
+				$sql .= ") AS tl";
+				$sql .= " LEFT JOIN (";
+				$sql .= "   SELECT DISTINCT " . $this->db->ifsql("tll." . $linked_info['fk_table_link_line_parent'],  "tll." . $linked_info['fk_table_link_line_parent'],  "tl." . $linked_info['fk_link']) . " AS fk_link, tl." . $linked_info['fk_doc'] . " AS fk_doc";
+				$sql .= "   FROM " . MAIN_DB_PREFIX . $linked_info['table'] . " AS tl";
+				$sql .= "   LEFT JOIN " . MAIN_DB_PREFIX . $linked_info['table_link_line'] . " AS tll ON tll." . $linked_info['fk_table_link_line'] . " = tl." . $linked_info['fk_line_link'];
+				$sql .= ") AS tl2 ON tl2.fk_link = tl.fk_link";
+				$sql .= " WHERE tl.fk_doc IN (" . $this->db->sanitize(implode(',', $document_ids)) . ")";
+				$sql .= " AND tl2.fk_doc IS NOT NULL";
+			}
 
 			dol_syslog(__METHOD__ . " - Get document lines", LOG_DEBUG);
 			$resql = $this->db->query($sql);

+ 1 - 1
htdocs/accountancy/expensereport/lines.php

@@ -213,7 +213,7 @@ if (strlen(trim($search_label))) {
 	$sql .= natural_search("f.label", $search_label);
 }
 if (strlen(trim($search_desc))) {
-	$sql .= natural_search("er.comments", $search_desc);
+	$sql .= natural_search("erd.comments", $search_desc);
 }
 if (strlen(trim($search_amount))) {
 	$sql .= natural_search("erd.total_ht", $search_amount, 1);

+ 17 - 3
htdocs/accountancy/journal/bankjournal.php

@@ -222,6 +222,7 @@ if ($result) {
 	// one line tabpay = line into bank
 	// one line for bank record = tabbq
 	// one line for thirdparty record = tabtp
+	// Note: tabcompany is used to store the subledger account
 	$i = 0;
 	while ($i < $num) {
 		$obj = $db->fetch_object($result);
@@ -269,7 +270,8 @@ if ($result) {
 		);
 
 		// Set accountancy code for user
-		// $obj->accountancy_code is the accountancy_code of table u=user but it is defined only if a link with type 'user' exists)
+		// $obj->accountancy_code is the accountancy_code of table u=user (but it is defined only if
+		// a link with type 'user' exists and user as a subledger account)
 		$compta_user = (!empty($obj->accountancy_code) ? $obj->accountancy_code : '');
 
 		$tabuser[$obj->rowid] = array(
@@ -385,13 +387,25 @@ if ($result) {
 					$userstatic->statut = $tabuser[$obj->rowid]['status'];
 					$userstatic->status = $tabuser[$obj->rowid]['status'];
 					$userstatic->accountancy_code = $tabuser[$obj->rowid]['accountancy_code'];
+					// For a payment of social contribution, we have a link sc + user.
+					// but we already fill the $tabpay[$obj->rowid]["soclib"] in the line 'sc'.
+					// If we fill it here to, we must concat
 					if ($userstatic->id > 0) {
-						$tabpay[$obj->rowid]["soclib"] = $userstatic->getNomUrl(1, 'accountancy', 0);
+						if ($is_sc) {
+							$tabpay[$obj->rowid]["soclib"] .= ' '.$userstatic->getNomUrl(1, 'accountancy', 0);
+						} else {
+							$tabpay[$obj->rowid]["soclib"] = $userstatic->getNomUrl(1, 'accountancy', 0);
+						}
 					} else {
 						$tabpay[$obj->rowid]["soclib"] = '???'; // Should not happen, but happens with old data when id of user was not saved on expense report payment.
 					}
+
 					if ($compta_user) {
-						$tabtp[$obj->rowid][$compta_user] += $amounttouse;
+						if ($is_sc) {
+							//$tabcompany[$obj->rowid][$compta_user] += $amounttouse;
+						} else {
+							$tabtp[$obj->rowid][$compta_user] += $amounttouse;
+						}
 					}
 				} elseif ($links[$key]['type'] == 'sc') {
 					$chargestatic->id = $links[$key]['url_id'];

+ 40 - 36
htdocs/accountancy/journal/sellsjournal.php

@@ -469,7 +469,7 @@ if ($action == 'writebookkeeping' && !$error) {
 		}
 
 		// Warranty
-		if (!$errorforline) {
+		if (!$errorforline && getDolGlobalString('INVOICE_USE_RETAINED_WARRANTY') && isset($tabwarranty[$key])) {
 			if (is_array($tabwarranty[$key])) {
 				foreach ($tabwarranty[$key] as $k => $mt) {
 					$bookkeeping = new BookKeeping($db);
@@ -712,7 +712,7 @@ if ($action == 'writebookkeeping' && !$error) {
 
 		// Revenue stamp
 		if (!$errorforline) {
-			if (is_array($tabrevenuestamp[$key])) {
+			if (isset($tabrevenuestamp[$key]) && is_array($tabrevenuestamp[$key])) {
 				foreach ($tabrevenuestamp[$key] as $k => $mt) {
 					if ($mt) {
 						$accountingaccount->fetch(null, $k, true);    // TODO Use a cache for label
@@ -864,22 +864,24 @@ if ($action == 'exportcsv' && !$error) {		// ISO and not UTF8 !
 		}
 
 		// Warranty
-		foreach ($tabwarranty[$key] as $k => $mt) {
-			//if ($mt) {
-			print '"'.$key.'"'.$sep;
-			print '"'.$date.'"'.$sep;
-			print '"'.$val["ref"].'"'.$sep;
-			print '"'.mb_convert_encoding(dol_trunc($companystatic->name, 32), 'ISO-8859-1').'"'.$sep;
-			print '"'.length_accounta(html_entity_decode($k)).'"'.$sep;
-			print '"'.length_accountg(getDolGlobalString('ACCOUNTING_ACCOUNT_CUSTOMER_RETAINED_WARRANTY')).'"'.$sep;
-			print '"'.length_accounta(html_entity_decode($k)).'"'.$sep;
-			print '"'.$langs->trans("Thirdparty").'"'.$sep;
-			print '"'.mb_convert_encoding(dol_trunc($companystatic->name, 16), 'ISO-8859-1').' - '.$invoicestatic->ref.' - '.$langs->trans("Retainedwarranty").'"'.$sep;
-			print '"'.($mt >= 0 ? price($mt) : '').'"'.$sep;
-			print '"'.($mt < 0 ? price(-$mt) : '').'"'.$sep;
-			print '"'.$journal.'"';
-			print "\n";
-			//}
+		if (getDolGlobalString('INVOICE_USE_RETAINED_WARRANTY') && isset($tabwarranty[$key])) {
+			foreach ($tabwarranty[$key] as $k => $mt) {
+				//if ($mt) {
+				print '"'.$key.'"'.$sep;
+				print '"'.$date.'"'.$sep;
+				print '"'.$val["ref"].'"'.$sep;
+				print '"'.mb_convert_encoding(dol_trunc($companystatic->name, 32), 'ISO-8859-1').'"'.$sep;
+				print '"'.length_accounta(html_entity_decode($k)).'"'.$sep;
+				print '"'.length_accountg(getDolGlobalString('ACCOUNTING_ACCOUNT_CUSTOMER_RETAINED_WARRANTY')).'"'.$sep;
+				print '"'.length_accounta(html_entity_decode($k)).'"'.$sep;
+				print '"'.$langs->trans("Thirdparty").'"'.$sep;
+				print '"'.mb_convert_encoding(dol_trunc($companystatic->name, 16), 'ISO-8859-1').' - '.$invoicestatic->ref.' - '.$langs->trans("Retainedwarranty").'"'.$sep;
+				print '"'.($mt >= 0 ? price($mt) : '').'"'.$sep;
+				print '"'.($mt < 0 ? price(-$mt) : '').'"'.$sep;
+				print '"'.$journal.'"';
+				print "\n";
+				//}
+			}
 		}
 
 		// Third party
@@ -953,22 +955,24 @@ if ($action == 'exportcsv' && !$error) {		// ISO and not UTF8 !
 		}
 
 		// Revenue stamp
-		foreach ($tabrevenuestamp[$key] as $k => $mt) {
-			//if ($mt) {
-			print '"'.$key.'"'.$sep;
-			print '"'.$date.'"'.$sep;
-			print '"'.$val["ref"].'"'.$sep;
-			print '"'.mb_convert_encoding(dol_trunc($companystatic->name, 32), 'ISO-8859-1').'"'.$sep;
-			print '"'.length_accountg(html_entity_decode($k)).'"'.$sep;
-			print '"'.length_accountg(html_entity_decode($k)).'"'.$sep;
-			print '""'.$sep;
-			print '"'.$langs->trans("RevenueStamp").'"'.$sep;
-			print '"'.mb_convert_encoding(dol_trunc($companystatic->name, 16), 'ISO-8859-1').' - '.$invoicestatic->ref.' - '.$langs->trans("RevenueStamp").'"'.$sep;
-			print '"'.($mt < 0 ? price(-$mt) : '').'"'.$sep;
-			print '"'.($mt >= 0 ? price($mt) : '').'"'.$sep;
-			print '"'.$journal.'"';
-			print "\n";
-			//}
+		if (isset($tabrevenuestamp[$key])) {
+			foreach ($tabrevenuestamp[$key] as $k => $mt) {
+				//if ($mt) {
+				print '"'.$key.'"'.$sep;
+				print '"'.$date.'"'.$sep;
+				print '"'.$val["ref"].'"'.$sep;
+				print '"'.mb_convert_encoding(dol_trunc($companystatic->name, 32), 'ISO-8859-1').'"'.$sep;
+				print '"'.length_accountg(html_entity_decode($k)).'"'.$sep;
+				print '"'.length_accountg(html_entity_decode($k)).'"'.$sep;
+				print '""'.$sep;
+				print '"'.$langs->trans("RevenueStamp").'"'.$sep;
+				print '"'.mb_convert_encoding(dol_trunc($companystatic->name, 16), 'ISO-8859-1').' - '.$invoicestatic->ref.' - '.$langs->trans("RevenueStamp").'"'.$sep;
+				print '"'.($mt < 0 ? price(-$mt) : '').'"'.$sep;
+				print '"'.($mt >= 0 ? price($mt) : '').'"'.$sep;
+				print '"'.$journal.'"';
+				print "\n";
+				//}
+			}
 		}
 	}
 }
@@ -1150,7 +1154,7 @@ if (empty($action) || $action == 'view') {
 		}
 
 		// Warranty
-		if (is_array($tabwarranty[$key])) {
+		if (getDolGlobalString('INVOICE_USE_RETAINED_WARRANTY') && isset($tabwarranty[$key]) && is_array($tabwarranty[$key])) {
 			foreach ($tabwarranty[$key] as $k => $mt) {
 				print '<tr class="oddeven">';
 				print "<!-- Thirdparty warranty -->";
@@ -1298,7 +1302,7 @@ if (empty($action) || $action == 'view') {
 		}
 
 		// Revenue stamp
-		if (is_array($tabrevenuestamp[$key])) {
+		if (isset($tabrevenuestamp[$key]) && is_array($tabrevenuestamp[$key])) {
 			foreach ($tabrevenuestamp[$key] as $k => $mt) {
 				print '<tr class="oddeven">';
 				print "<!-- Thirdparty revenuestamp -->";

+ 1 - 1
htdocs/accountancy/tpl/export_journal.tpl.php

@@ -63,7 +63,7 @@ if (($accountancyexport->getFormatCode($formatexportset) == 'fec' || $accountanc
 	}
 
 	$endaccountingperiod = dol_print_date(dol_get_last_day($tmparray['year'], $tmparray['mon']), 'dayxcard');
-
+	$siren = str_replace(" ", "", $siren);
 	$completefilename = $siren."FEC".$endaccountingperiod.".txt";
 } elseif ($accountancyexport->getFormatCode($formatexportset) == 'ciel' && $type_export == "general_ledger" && getDolGlobalString('ACCOUNTING_EXPORT_XIMPORT_FORCE_FILENAME')) {
 	$completefilename = "XIMPORT.TXT";

+ 1 - 1
htdocs/adherents/card.php

@@ -1012,7 +1012,7 @@ if (is_object($objcanvas) && $objcanvas->displayCanvasExists($action)) {
 		$listetype = $adht->liste_array(1);
 		print img_picto('', $adht->picto, 'class="pictofixedwidth"');
 		if (count($listetype)) {
-			print $form->selectarray("typeid", $listetype, (GETPOST('typeid', 'int') ? GETPOST('typeid', 'int') : $typeid), (count($listetype) > 1 ? 1 : 0), 0, 0, '', 0, 0, 0, '', '', 1);
+			print $form->selectarray("typeid", $listetype, (GETPOST('typeid', 'int') ? GETPOST('typeid', 'int') : $typeid), (count($listetype) > 1 ? 1 : 0), 0, 0, '', 0, 0, 0, '', 'minwidth150', 1);
 		} else {
 			print '<span class="error">'.$langs->trans("NoTypeDefinedGoToSetup").'</span>';
 		}

+ 1 - 1
htdocs/adherents/list.php

@@ -731,7 +731,7 @@ $moreforfilter = '';
 if (isModEnabled('categorie') && $user->hasRight('categorie', 'lire')) {
 	require_once DOL_DOCUMENT_ROOT.'/categories/class/categorie.class.php';
 	$moreforfilter .= '<div class="divsearchfield">';
-	$moreforfilter .= img_picto($langs->trans('Categories'), 'category', 'class="pictofixedlength"').$formother->select_categories(Categorie::TYPE_MEMBER, $search_categ, 'search_categ', 1, $langs->trans("MembersCategoriesShort"));
+	$moreforfilter .= img_picto($langs->trans('Categories'), 'category', 'class="pictofixedwidth"').$formother->select_categories(Categorie::TYPE_MEMBER, $search_categ, 'search_categ', 1, $langs->trans("MembersCategoriesShort"));
 	$moreforfilter .= '</div>';
 }
 $parameters = array();

+ 2 - 2
htdocs/adherents/subscription/card.php

@@ -238,7 +238,7 @@ if ($user->hasRight('adherent', 'cotisation', 'creer') && $action == 'edit') {
 	// Label
 	print '<tr><td>'.$langs->trans("Label").'</td>';
 	print '<td class="valeur">';
-	print '<input type="text" class="flat" name="note" value="'.$object->note_private.'"></td></tr>';
+	print '<input type="text" class="flat" name="note" value="'.$object->note_public.'"></td></tr>';
 
 	// Bank line
 	if (isModEnabled("banque") && (getDolGlobalString('ADHERENT_BANK_USE') || $object->fk_bank)) {
@@ -334,7 +334,7 @@ if ($rowid && $action != 'edit') {
 	print '<tr><td>'.$langs->trans("Amount").'</td><td class="valeur"><span class="amount">'.price($object->amount).'</span></td></tr>';
 
 	// Label
-	print '<tr><td>'.$langs->trans("Label").'</td><td class="valeur sensiblehtmlcontent">'.dol_string_onlythesehtmltags(dol_htmlentitiesbr($object->note_private)).'</td></tr>';
+	print '<tr><td>'.$langs->trans("Label").'</td><td class="valeur sensiblehtmlcontent">'.dol_string_onlythesehtmltags(dol_htmlentitiesbr($object->note_public)).'</td></tr>';
 
 	// Bank line
 	if (isModEnabled("banque") && (getDolGlobalString('ADHERENT_BANK_USE') || $object->fk_bank)) {

+ 1 - 1
htdocs/adherents/subscription/list.php

@@ -333,7 +333,7 @@ if ($optioncss != '') {
 // Add $param from extra fields
 include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_list_search_param.tpl.php';
 // Add $param from hooks
-$parameters = array();
+$parameters = array('param' => &$param);
 $reshook = $hookmanager->executeHooks('printFieldListSearchParam', $parameters, $object, $action); // Note that $action and $object may have been modified by hook
 $param .= $hookmanager->resPrint;
 

+ 2 - 2
htdocs/admin/barcode.php

@@ -457,7 +457,7 @@ if (isModEnabled('product')) {
 	print '<tr class="oddeven">';
 	print '<td>'.$langs->trans("SetDefaultBarcodeTypeProducts").'</td>';
 	print '<td width="60" class="right">';
-	print $formbarcode->selectBarcodeType($conf->global->PRODUIT_DEFAULT_BARCODE_TYPE, "PRODUIT_DEFAULT_BARCODE_TYPE", 1);
+	print $formbarcode->selectBarcodeType(getDolGlobalString('PRODUIT_DEFAULT_BARCODE_TYPE'), "PRODUIT_DEFAULT_BARCODE_TYPE", 1);
 	print '</td>';
 	print '<td>&nbsp;</td>';
 	print '</tr>';
@@ -468,7 +468,7 @@ if (isModEnabled('societe')) {
 	print '<tr class="oddeven">';
 	print '<td>'.$langs->trans("SetDefaultBarcodeTypeThirdParties").'</td>';
 	print '<td width="60" class="right">';
-	print $formbarcode->selectBarcodeType($conf->global->GENBARCODE_BARCODETYPE_THIRDPARTY, "GENBARCODE_BARCODETYPE_THIRDPARTY", 1);
+	print $formbarcode->selectBarcodeType(getDolGlobalString('GENBARCODE_BARCODETYPE_THIRDPARTY'), "GENBARCODE_BARCODETYPE_THIRDPARTY", 1);
 	print '</td>';
 	print '<td>&nbsp;</td>';
 	print '</tr>';

+ 2 - 0
htdocs/admin/bom_extrafields.php

@@ -65,6 +65,8 @@ require DOL_DOCUMENT_ROOT.'/core/actions_extrafields.inc.php';
  * View
  */
 
+$textobject = $langs->transnoentitiesnoconv("BOM");
+
 $help_url = '';
 llxHeader('', $langs->trans("BOMsSetup"), $help_url);
 

+ 3 - 0
htdocs/admin/bomline_extrafields.php

@@ -64,6 +64,9 @@ require DOL_DOCUMENT_ROOT . '/core/actions_extrafields.inc.php';
  * View
  */
 
+$textobject = $langs->transnoentitiesnoconv("BOM");
+
+
 $help_url = '';
 llxHeader('', $langs->trans("BOMsSetup"), $help_url);
 

+ 1 - 1
htdocs/admin/clicktodial.php

@@ -89,7 +89,7 @@ print "</tr>\n";
 
 print '<tr class="oddeven"><td>';
 print $langs->trans("ClickToDialUseTelLink").'</td><td>';
-print $form->selectyesno("CLICKTODIAL_USE_TEL_LINK_ON_PHONE_NUMBERS", $conf->global->CLICKTODIAL_USE_TEL_LINK_ON_PHONE_NUMBERS, 1).'<br>';
+print $form->selectyesno("CLICKTODIAL_USE_TEL_LINK_ON_PHONE_NUMBERS", getDolGlobalString('CLICKTODIAL_USE_TEL_LINK_ON_PHONE_NUMBERS'), 1).'<br>';
 print '<br>';
 print '<span class="opacitymedium small">'.$langs->trans("ClickToDialUseTelLinkDesc").'</span>';
 print '</td></tr>';

+ 14 - 14
htdocs/admin/company.php

@@ -635,7 +635,7 @@ print '<input name="capital" id="capital" class="maxwidth100" value="'.dol_escap
 // Juridical Status
 print '<tr class="oddeven"><td><label for="forme_juridique_code">'.$langs->trans("JuridicalStatus").'</label></td><td>';
 if ($mysoc->country_code) {
-	print $formcompany->select_juridicalstatus($conf->global->MAIN_INFO_SOCIETE_FORME_JURIDIQUE, $mysoc->country_code, '', 'forme_juridique_code');
+	print $formcompany->select_juridicalstatus(getDolGlobalString('MAIN_INFO_SOCIETE_FORME_JURIDIQUE'), $mysoc->country_code, '', 'forme_juridique_code');
 } else {
 	print $countrynotdefined;
 }
@@ -645,7 +645,7 @@ print '</td></tr>';
 if ($langs->transcountry("ProfId1", $mysoc->country_code) != '-') {
 	print '<tr class="oddeven"><td><label for="profid1">'.$langs->transcountry("ProfId1", $mysoc->country_code).'</label></td><td>';
 	if (!empty($mysoc->country_code)) {
-		print '<input name="siren" id="profid1" class="minwidth200" value="'.dol_escape_htmltag(getDolGlobalString('MAIN_INFO_SIREN') ? $conf->global->MAIN_INFO_SIREN : '').'">';
+		print '<input name="siren" id="profid1" class="minwidth200" value="'.dol_escape_htmltag(getDolGlobalString('MAIN_INFO_SIREN')).'">';
 	} else {
 		print $countrynotdefined;
 	}
@@ -656,7 +656,7 @@ if ($langs->transcountry("ProfId1", $mysoc->country_code) != '-') {
 if ($langs->transcountry("ProfId2", $mysoc->country_code) != '-') {
 	print '<tr class="oddeven"><td><label for="profid2">'.$langs->transcountry("ProfId2", $mysoc->country_code).'</label></td><td>';
 	if (!empty($mysoc->country_code)) {
-		print '<input name="siret" id="profid2" class="minwidth200" value="'.dol_escape_htmltag(getDolGlobalString('MAIN_INFO_SIRET') ? $conf->global->MAIN_INFO_SIRET : '').'">';
+		print '<input name="siret" id="profid2" class="minwidth200" value="'.dol_escape_htmltag(getDolGlobalString('MAIN_INFO_SIRET')).'">';
 	} else {
 		print $countrynotdefined;
 	}
@@ -667,7 +667,7 @@ if ($langs->transcountry("ProfId2", $mysoc->country_code) != '-') {
 if ($langs->transcountry("ProfId3", $mysoc->country_code) != '-') {
 	print '<tr class="oddeven"><td><label for="profid3">'.$langs->transcountry("ProfId3", $mysoc->country_code).'</label></td><td>';
 	if (!empty($mysoc->country_code)) {
-		print '<input name="ape" id="profid3" class="minwidth200" value="'.dol_escape_htmltag(getDolGlobalString('MAIN_INFO_APE') ? $conf->global->MAIN_INFO_APE : '').'">';
+		print '<input name="ape" id="profid3" class="minwidth200" value="'.dol_escape_htmltag(getDolGlobalString('MAIN_INFO_APE')).'">';
 	} else {
 		print $countrynotdefined;
 	}
@@ -678,7 +678,7 @@ if ($langs->transcountry("ProfId3", $mysoc->country_code) != '-') {
 if ($langs->transcountry("ProfId4", $mysoc->country_code) != '-') {
 	print '<tr class="oddeven"><td><label for="profid4">'.$langs->transcountry("ProfId4", $mysoc->country_code).'</label></td><td>';
 	if (!empty($mysoc->country_code)) {
-		print '<input name="rcs" id="profid4" class="minwidth200" value="'.dol_escape_htmltag(getDolGlobalString('MAIN_INFO_RCS') ? $conf->global->MAIN_INFO_RCS : '').'">';
+		print '<input name="rcs" id="profid4" class="minwidth200" value="'.dol_escape_htmltag(getDolGlobalString('MAIN_INFO_RCS')).'">';
 	} else {
 		print $countrynotdefined;
 	}
@@ -689,7 +689,7 @@ if ($langs->transcountry("ProfId4", $mysoc->country_code) != '-') {
 if ($langs->transcountry("ProfId5", $mysoc->country_code) != '-') {
 	print '<tr class="oddeven"><td><label for="profid5">'.$langs->transcountry("ProfId5", $mysoc->country_code).'</label></td><td>';
 	if (!empty($mysoc->country_code)) {
-		print '<input name="MAIN_INFO_PROFID5" id="profid5" class="minwidth200" value="'.dol_escape_htmltag(getDolGlobalString('MAIN_INFO_PROFID5') ? $conf->global->MAIN_INFO_PROFID5 : '').'">';
+		print '<input name="MAIN_INFO_PROFID5" id="profid5" class="minwidth200" value="'.dol_escape_htmltag(getDolGlobalString('MAIN_INFO_PROFID5')).'">';
 	} else {
 		print $countrynotdefined;
 	}
@@ -700,7 +700,7 @@ if ($langs->transcountry("ProfId5", $mysoc->country_code) != '-') {
 if ($langs->transcountry("ProfId6", $mysoc->country_code) != '-') {
 	print '<tr class="oddeven"><td><label for="profid6">'.$langs->transcountry("ProfId6", $mysoc->country_code).'</label></td><td>';
 	if (!empty($mysoc->country_code)) {
-		print '<input name="MAIN_INFO_PROFID6" id="profid6" class="minwidth200" value="'.dol_escape_htmltag(getDolGlobalString('MAIN_INFO_PROFID6') ? $conf->global->MAIN_INFO_PROFID6 : '').'">';
+		print '<input name="MAIN_INFO_PROFID6" id="profid6" class="minwidth200" value="'.dol_escape_htmltag(getDolGlobalString('MAIN_INFO_PROFID6')).'">';
 	} else {
 		print $countrynotdefined;
 	}
@@ -711,7 +711,7 @@ if ($langs->transcountry("ProfId6", $mysoc->country_code) != '-') {
 if ($langs->transcountry("ProfId7", $mysoc->country_code) != '-') {
 	print '<tr class="oddeven"><td><label for="profid7">'.$langs->transcountry("profid7", $mysoc->country_code).'</label></td><td>';
 	if (!empty($mysoc->country_code)) {
-		print '<input name="MAIN_INFO_PROFID7" id="profid7" class="minwidth200" value="'.dol_escape_htmltag(getDolGlobalString('MAIN_INFO_PROFID7') ? $conf->global->MAIN_INFO_PROFID7 : '').'">';
+		print '<input name="MAIN_INFO_PROFID7" id="profid7" class="minwidth200" value="'.dol_escape_htmltag(getDolGlobalString('MAIN_INFO_PROFID7')).'">';
 	} else {
 		print $countrynotdefined;
 	}
@@ -722,7 +722,7 @@ if ($langs->transcountry("ProfId7", $mysoc->country_code) != '-') {
 if ($langs->transcountry("ProfId8", $mysoc->country_code) != '-') {
 	print '<tr class="oddeven"><td><label for="profid8">'.$langs->transcountry("profid8", $mysoc->country_code).'</label></td><td>';
 	if (!empty($mysoc->country_code)) {
-		print '<input name="MAIN_INFO_PROFID8" id="profid8" class="minwidth200" value="'.dol_escape_htmltag(getDolGlobalString('MAIN_INFO_PROFID8') ? $conf->global->MAIN_INFO_PROFID8 : '').'">';
+		print '<input name="MAIN_INFO_PROFID8" id="profid8" class="minwidth200" value="'.dol_escape_htmltag(getDolGlobalString('MAIN_INFO_PROFID8')).'">';
 	} else {
 		print $countrynotdefined;
 	}
@@ -733,7 +733,7 @@ if ($langs->transcountry("ProfId8", $mysoc->country_code) != '-') {
 if ($langs->transcountry("ProfId9", $mysoc->country_code) != '-') {
 	print '<tr class="oddeven"><td><label for="profid9">'.$langs->transcountry("profid9", $mysoc->country_code).'</label></td><td>';
 	if (!empty($mysoc->country_code)) {
-		print '<input name="MAIN_INFO_PROFID9" id="profid9" class="minwidth200" value="'.dol_escape_htmltag(getDolGlobalString('MAIN_INFO_PROFID9') ? $conf->global->MAIN_INFO_PROFID9 : '').'">';
+		print '<input name="MAIN_INFO_PROFID9" id="profid9" class="minwidth200" value="'.dol_escape_htmltag(getDolGlobalString('MAIN_INFO_PROFID9')).'">';
 	} else {
 		print $countrynotdefined;
 	}
@@ -744,7 +744,7 @@ if ($langs->transcountry("ProfId9", $mysoc->country_code) != '-') {
 if ($langs->transcountry("ProfId10", $mysoc->country_code) != '-') {
 	print '<tr class="oddeven"><td><label for="profid10">'.$langs->transcountry("profid10", $mysoc->country_code).'</label></td><td>';
 	if (!empty($mysoc->country_code)) {
-		print '<input name="MAIN_INFO_PROFID10" id="profid10" class="minwidth200" value="'.dol_escape_htmltag(getDolGlobalString('MAIN_INFO_PROFID10') ? $conf->global->MAIN_INFO_PROFID10 : '').'">';
+		print '<input name="MAIN_INFO_PROFID10" id="profid10" class="minwidth200" value="'.dol_escape_htmltag(getDolGlobalString('MAIN_INFO_PROFID10')).'">';
 	} else {
 		print $countrynotdefined;
 	}
@@ -753,12 +753,12 @@ if ($langs->transcountry("ProfId10", $mysoc->country_code) != '-') {
 
 // Intra-community VAT number
 print '<tr class="oddeven"><td><label for="intra_vat">'.$langs->trans("VATIntra").'</label></td><td>';
-print '<input name="tva" id="intra_vat" class="minwidth200" value="'.dol_escape_htmltag(getDolGlobalString('MAIN_INFO_TVAINTRA') ? $conf->global->MAIN_INFO_TVAINTRA : '').'">';
+print '<input name="tva" id="intra_vat" class="minwidth200" value="'.dol_escape_htmltag(getDolGlobalString('MAIN_INFO_TVAINTRA')).'">';
 print '</td></tr>';
 
 // Object of the company
 print '<tr class="oddeven"><td><label for="socialobject">'.$langs->trans("CompanyObject").'</label></td><td>';
-print '<textarea class="flat quatrevingtpercent" name="socialobject" id="socialobject" rows="'.ROWS_5.'">'.(getDolGlobalString('MAIN_INFO_SOCIETE_OBJECT') ? $conf->global->MAIN_INFO_SOCIETE_OBJECT : '').'</textarea></td></tr>';
+print '<textarea class="flat quatrevingtpercent" name="socialobject" id="socialobject" rows="'.ROWS_5.'">'.(getDolGlobalString('MAIN_INFO_SOCIETE_OBJECT')).'</textarea></td></tr>';
 print '</td></tr>';
 
 print '</table>';
@@ -875,7 +875,7 @@ if ($mysoc->useLocalTax(2)) {
 	$tooltiphelp = ($tooltiphelp != "LocalTax2IsUsedExample" ? "<i>".$langs->trans("Example").': '.$langs->transcountry("LocalTax2IsUsedExample", $mysoc->country_code)."</i>\n" : "");
 	if (!isOnlyOneLocalTax(2)) {
 		print '<br><label for="lt2">'.$langs->trans("LTRate").'</label>: ';
-		$formcompany->select_localtax(2, $conf->global->MAIN_INFO_VALUE_LOCALTAX2, "lt2");
+		$formcompany->select_localtax(2, getDolGlobalString('MAIN_INFO_VALUE_LOCALTAX2'), "lt2");
 	}
 	print '<br><label for="clt2">'.$langs->trans("CalcLocaltax").'</label>: ';
 	print $form->selectarray("clt2", $opcions, getDolGlobalString('MAIN_INFO_LOCALTAX_CALC2'));

+ 1 - 1
htdocs/admin/dict.php

@@ -1807,7 +1807,7 @@ if ($id > 0) {
 			}
 
 			if (in_array($value, array('label', 'libelle', 'libelle_facture')) && empty($tabcomplete[$tabname[$id]]['help'][$value])) {
-				if (!is_array($tabcomplete[$tabname[$id]]['help'])) {	// protection when $tabcomplete[$tabname[$id]]['help'] is a an empty string, we must force it into an array
+				if (!isset($tabcomplete[$tabname[$id]]['help']) || !is_array($tabcomplete[$tabname[$id]]['help'])) {	// protection when $tabcomplete[$tabname[$id]]['help'] is a an empty string, we must force it into an array
 					$tabcomplete[$tabname[$id]]['help'] = array();
 				}
 				$tabcomplete[$tabname[$id]]['help'][$value] = $langs->trans('LabelUsedByDefault');

+ 3 - 0
htdocs/admin/eventorganization_confbooth_extrafields.php

@@ -60,6 +60,9 @@ require DOL_DOCUMENT_ROOT.'/core/actions_extrafields.inc.php';
  * View
  */
 
+$textobject = $langs->transnoentitiesnoconv("ConferenceOrBooth");
+
+
 $help_url = '';
 $page_name = "EventOrganizationSetup";
 

+ 2 - 0
htdocs/admin/eventorganization_confboothattendee_extrafields.php

@@ -63,6 +63,8 @@ require DOL_DOCUMENT_ROOT.'/core/actions_extrafields.inc.php';
  * View
  */
 
+$textobject = $langs->transnoentitiesnoconv("ConferenceOrBoothAttendee");
+
 $help_url = '';
 $page_name = 'EventOrganizationSetup';
 

+ 2 - 0
htdocs/admin/expensereport_extrafields.php

@@ -69,6 +69,8 @@ require DOL_DOCUMENT_ROOT.'/core/actions_extrafields.inc.php';
  * View
  */
 
+$textobject = $langs->transnoentitiesnoconv("ExpenseReports");
+
 llxHeader('', $langs->trans("ExpenseReportsSetup"));
 
 $linkback = '<a href="'.DOL_URL_ROOT.'/admin/modules.php?restore_lastsearch_values=1">'.$langs->trans("BackToModuleList").'</a>';

+ 9 - 3
htdocs/admin/external_rss.php

@@ -223,7 +223,9 @@ print '<input type="hidden" name="norss" value="'.($lastexternalrss + 1).'">';
 print '</form>';
 
 print '<br><br>';
-print '<span class="opacitymedium">'.$langs->trans('RssNote').'</span> - <a href="'.DOL_MAIN_URL_ROOT.'/admin/boxes.php">'.$langs->trans('JumpToBoxes').'</a>';
+print '<span class="opacitymedium">'.$langs->trans('RssNote').'</span>';
+print ' - ';
+print '<a href="'.DOL_URL_ROOT.'/admin/boxes.php?backtopage='.urlencode($_SERVER["PHP_SELF"]).'">'.$langs->trans('JumpToBoxes').'</a>';
 print '<br><br>';
 
 $sql = "SELECT rowid, file, note FROM ".MAIN_DB_PREFIX."boxes_def";
@@ -281,7 +283,7 @@ if ($resql) {
 		print "<td>".$langs->trans("Status")."</td>";
 		print "<td>";
 		if ($result > 0 && empty($rss->error)) {
-			print '<span class="ok">'.$langs->trans("Online").'</div>';
+			print '<span class="ok">'.img_picto($langs->trans("Online"), 'tick', 'class="pictofixedwidth"').$langs->trans("Online").'</div>';
 		} else {
 			print '<span class="error">'.$langs->trans("Offline");
 			$langs->load("errors");
@@ -320,7 +322,11 @@ if ($resql) {
 		$active = _isInBoxList($idrss, $boxlist) ? 'yes' : 'no';
 		print '<tr class="oddeven">';
 		print '<td>'.$langs->trans('WidgetAvailable').'</td>';
-		print '<td>'.yn($active).'</td>';
+		print '<td>'.yn($active);
+		print ' &nbsp; - &nbsp; <a href="'.DOL_URL_ROOT.'/admin/boxes.php?backtopage='.urlencode($_SERVER["PHP_SELF"]).'">';
+		print $langs->trans("JumpToBoxes");
+		print '</a>';
+		print '</td>';
 		print '</tr>'."\n";
 
 		print '</table>'."\n";

+ 24 - 12
htdocs/admin/facture.php

@@ -50,6 +50,8 @@ $label = GETPOST('label', 'alpha');
 $scandir = GETPOST('scan_dir', 'alpha');
 $type = 'invoice';
 
+$error = 0;
+
 
 /*
  * Actions
@@ -616,13 +618,14 @@ if (getDolGlobalString('INVOICE_USE_DEFAULT_DOCUMENT')) { // Hidden conf
 	print '<form action="'.$_SERVER["PHP_SELF"].'#default-pdf-modules-by-type-table" method="POST">';
 	print '<input type="hidden" name="token" value="'.newToken().'" />';
 	print '<input type="hidden" name="action" value="setDefaultPDFModulesByType" >';
+	print '<input type="hidden" name="page_y" value="" />';
 
 	print '<div class="div-table-responsive-no-min">';
 	print '<table id="default-pdf-modules-by-type-table" class="noborder centpercent">';
 	print '<tr class="liste_titre">';
 	print '<td>'.$langs->trans("Type").'</td>';
 	print '<td>'.$langs->trans("Name").'</td>';
-	print '<td class="right"><input type="submit" class="button button-edit" value="'.$langs->trans("Modify").'"></td>';
+	print '<td class="right"><input type="submit" class="button button-edit reposition" value="'.$langs->trans("Modify").'"></td>';
 	print "</tr>\n";
 
 	$listtype = array(
@@ -658,6 +661,7 @@ print load_fiche_titre($langs->trans("SuggestedPaymentModesIfNotDefinedInInvoice
 
 print '<form action="'.$_SERVER["PHP_SELF"].'" method="POST">';
 print '<input type="hidden" name="token" value="'.newToken().'" />';
+print '<input type="hidden" name="page_y" value="" />';
 
 print '<div class="div-table-responsive-no-min">';
 print '<table class="noborder centpercent">';
@@ -666,17 +670,16 @@ print '<tr class="liste_titre">';
 print '<td>';
 print '<input type="hidden" name="action" value="setribchq">';
 print $langs->trans("PaymentMode").'</td>';
-print '<td class="right"><input type="submit" class="button button-edit" value="'.$langs->trans("Modify").'"></td>';
+print '<td class="right"><input type="submit" class="button button-edit reposition" value="'.$langs->trans("Modify").'"></td>';
 print "</tr>\n";
 
 print '<tr class="oddeven">';
 print "<td>".$langs->trans("SuggestPaymentByRIBOnAccount")."</td>";
 print "<td>";
 if (isModEnabled('banque')) {
-	$sql = "SELECT rowid, label";
+	$sql = "SELECT rowid, label, clos";
 	$sql .= " FROM ".MAIN_DB_PREFIX."bank_account";
-	$sql .= " WHERE clos = 0";
-	$sql .= " AND courant = 1";
+	$sql .= " WHERE courant = 1";
 	$sql .= " AND entity IN (".getEntity('bank_account').")";
 	$resql = $db->query($sql);
 	if ($resql) {
@@ -686,15 +689,19 @@ if (isModEnabled('banque')) {
 			print '<select name="rib" class="flat" id="rib">';
 			print '<option value="0">'.$langs->trans("DoNotSuggestPaymentMode").'</option>';
 			while ($i < $num) {
-				$row = $db->fetch_row($resql);
+				$obj = $db->fetch_object($resql);
 
-				print '<option value="'.$row[0].'"';
-				print $conf->global->FACTURE_RIB_NUMBER == $row[0] ? ' selected' : '';
-				print '>'.$row[1].'</option>';
+				print '<option value="'.$obj->rowid.'"';
+				print getDolGlobalString('FACTURE_RIB_NUMBER') == $obj->rowid ? ' selected' : '';
+				if (!empty($obj->clos)) {
+					print ' disabled';
+				}
+				print '>'.dol_escape_htmltag($obj->label).'</option>';
 
 				$i++;
 			}
 			print "</select>";
+			print ajax_combobox("rib");
 		} else {
 			print '<span class="opacitymedium">'.$langs->trans("NoActiveBankAccountDefined").'</span>';
 		}
@@ -734,6 +741,8 @@ if ($resql) {
 	}
 }
 print "</select>";
+print ajax_combobox("chq", array(), 0, 0, 'resolve', -2);
+
 print "</td></tr>";
 print "</table>";
 print '</div>';
@@ -756,12 +765,13 @@ print "</tr>\n";
 print '<form action="'.$_SERVER["PHP_SELF"].'" method="POST">';
 print '<input type="hidden" name="token" value="'.newToken().'" />';
 print '<input type="hidden" name="action" value="setforcedate" />';
+print '<input type="hidden" name="page_y" value="" />';
 print '<tr class="oddeven"><td>';
 print $langs->trans("ForceInvoiceDate");
 print '</td><td width="60" class="center">';
 print $form->selectyesno("forcedate", getDolGlobalInt('FAC_FORCE_DATE_VALIDATION', 0), 1);
 print '</td><td class="right">';
-print '<input type="submit" class="button button-edit" value="'.$langs->trans("Modify").'" />';
+print '<input type="submit" class="button button-edit reposition" value="'.$langs->trans("Modify").'" />';
 print "</td></tr>\n";
 print '</form>';
 
@@ -776,6 +786,7 @@ $htmltext .= '</i>';
 print '<form action="'.$_SERVER["PHP_SELF"].'" method="POST">';
 print '<input type="hidden" name="token" value="'.newToken().'" />';
 print '<input type="hidden" name="action" value="set_INVOICE_FREE_TEXT" />';
+print '<input type="hidden" name="page_y" value="" />';
 print '<tr class="oddeven"><td colspan="2">';
 print $form->textwithpicto($langs->trans("FreeLegalTextOnInvoices"), $langs->trans("AddCRIfTooLong").'<br><br>'.$htmltext, 1, 'help', '', 0, 2, 'freetexttooltip').'<br>';
 $variablename = 'INVOICE_FREE_TEXT';
@@ -787,7 +798,7 @@ if (!getDolGlobalString('PDF_ALLOW_HTML_FOR_FREE_TEXT')) {
 	print $doleditor->Create();
 }
 print '</td><td class="right">';
-print '<input type="submit" class="button button-edit" value="'.$langs->trans("Modify").'" />';
+print '<input type="submit" class="button button-edit reposition" value="'.$langs->trans("Modify").'" />';
 print "</td></tr>\n";
 print '</form>';
 
@@ -795,12 +806,13 @@ print '</form>';
 print '<form action="'.$_SERVER["PHP_SELF"].'" method="POST">';
 print '<input type="hidden" name="token" value="'.newToken().'" />';
 print '<input type="hidden" name="action" value="set_FACTURE_DRAFT_WATERMARK" />';
+print '<input type="hidden" name="page_y" value="" />';
 print '<tr class="oddeven"><td>';
 print $form->textwithpicto($langs->trans("WatermarkOnDraftBill"), $htmltext, 1, 'help', '', 0, 2, 'watermarktooltip').'<br>';
 print '</td>';
 print '<td><input class="flat minwidth200imp" type="text" name="FACTURE_DRAFT_WATERMARK" value="'.dol_escape_htmltag(getDolGlobalString('FACTURE_DRAFT_WATERMARK')).'">';
 print '</td><td class="right">';
-print '<input type="submit" class="button button-edit" value="'.$langs->trans("Modify").'" />';
+print '<input type="submit" class="button button-edit reposition" value="'.$langs->trans("Modify").'" />';
 print "</td></tr>\n";
 print '</form>';
 

+ 1 - 1
htdocs/admin/holiday.php

@@ -214,7 +214,7 @@ foreach ($dirmodels as $reldir) {
 					}
 
 					if ($module->isEnabled()) {
-						print '<tr class="oddeven"><td>'.$module->nom."</td><td>\n";
+						print '<tr class="oddeven"><td>'.$module->name."</td><td>\n";
 						print $module->info($langs);
 						print '</td>';
 

+ 2 - 0
htdocs/admin/holiday_extrafields.php

@@ -69,6 +69,8 @@ require DOL_DOCUMENT_ROOT.'/core/actions_extrafields.inc.php';
  * View
  */
 
+$textobject = $langs->transnoentitiesnoconv("Holidays");
+
 llxHeader('', $langs->trans("HolidaySetup"));
 
 $linkback = '<a href="'.DOL_URL_ROOT.'/admin/modules.php?restore_lastsearch_values=1">'.$langs->trans("BackToModuleList").'</a>';

+ 2 - 0
htdocs/admin/knowledgerecord_extrafields.php

@@ -66,6 +66,8 @@ require DOL_DOCUMENT_ROOT.'/core/actions_extrafields.inc.php';
  * View
  */
 
+$textobject = $langs->transnoentitiesnoconv("KnowledgeRecord");
+
 $help_url = '';
 $page_name = 'KnowledgeManagementSetup';
 

+ 107 - 107
htdocs/admin/mails.php

@@ -815,135 +815,135 @@ if ($action == 'edit') {
 		}
 
 		print '<br>';
+	}
 
+	print '<div class="div-table-responsive-no-min">'; // You can use div-table-responsive-no-min if you dont need reserved height for your table
+	print '<table class="noborder centpercent">';
+	print '<tr class="liste_titre"><td class="titlefieldmiddle">'.$langs->trans("ParametersForTestEnvironment").'</td><td>'.$langs->trans("Value").'</td></tr>';
 
-		print '<div class="div-table-responsive-no-min">'; // You can use div-table-responsive-no-min if you dont need reserved height for your table
-		print '<table class="noborder centpercent">';
-		print '<tr class="liste_titre"><td class="titlefieldmiddle">'.$langs->trans("ParametersForTestEnvironment").'</td><td>'.$langs->trans("Value").'</td></tr>';
-
-		// Disable
-		print '<tr class="oddeven"><td>'.$langs->trans("MAIN_DISABLE_ALL_MAILS").'</td><td>'.yn(getDolGlobalString('MAIN_DISABLE_ALL_MAILS'));
-		if (getDolGlobalString('MAIN_DISABLE_ALL_MAILS')) {
-			print img_warning($langs->trans("Disabled"));
-		}
-		print '</td></tr>';
+	// Disable
+	print '<tr class="oddeven"><td>'.$langs->trans("MAIN_DISABLE_ALL_MAILS").'</td><td>'.yn(getDolGlobalString('MAIN_DISABLE_ALL_MAILS'));
+	if (getDolGlobalString('MAIN_DISABLE_ALL_MAILS')) {
+		print img_warning($langs->trans("Disabled"));
+	}
+	print '</td></tr>';
 
-		if (!getDolGlobalString('MAIN_DISABLE_ALL_MAILS')) {
-			// Force e-mail recipient
-			print '<tr class="oddeven"><td>'.$langs->trans("MAIN_MAIL_FORCE_SENDTO").'</td><td>'.getDolGlobalString('MAIN_MAIL_FORCE_SENDTO');
-			if (getDolGlobalString('MAIN_MAIL_FORCE_SENDTO')) {
-				if (!isValidEmail(getDolGlobalString('MAIN_MAIL_FORCE_SENDTO'))) {
-					print img_warning($langs->trans("ErrorBadEMail"));
-				} else {
-					print img_warning($langs->trans("RecipientEmailsWillBeReplacedWithThisValue"));
-				}
+	if (!getDolGlobalString('MAIN_DISABLE_ALL_MAILS')) {
+		// Force e-mail recipient
+		print '<tr class="oddeven"><td>'.$langs->trans("MAIN_MAIL_FORCE_SENDTO").'</td><td>'.getDolGlobalString('MAIN_MAIL_FORCE_SENDTO');
+		if (getDolGlobalString('MAIN_MAIL_FORCE_SENDTO')) {
+			if (!isValidEmail(getDolGlobalString('MAIN_MAIL_FORCE_SENDTO'))) {
+				print img_warning($langs->trans("ErrorBadEMail"));
+			} else {
+				print img_warning($langs->trans("RecipientEmailsWillBeReplacedWithThisValue"));
 			}
-			print '</td></tr>';
 		}
+		print '</td></tr>';
+	}
 
-		print '</table>';
-		print '</div>';
+	print '</table>';
+	print '</div>';
 
 
-		print '<br>';
+	print '<br>';
 
 
-		print '<div class="div-table-responsive-no-min">'; // You can use div-table-responsive-no-min if you dont need reserved height for your table
-		print '<table class="noborder centpercent">';
-		print '<tr class="liste_titre"><td class="titlefieldmiddle">'.$langs->trans("OtherOptions").'</td><td></td></tr>';
+	print '<div class="div-table-responsive-no-min">'; // You can use div-table-responsive-no-min if you dont need reserved height for your table
+	print '<table class="noborder centpercent">';
+	print '<tr class="liste_titre"><td class="titlefieldmiddle">'.$langs->trans("OtherOptions").'</td><td></td></tr>';
 
-		// From
-		$help = $form->textwithpicto('', $langs->trans("EMailHelpMsgSPFDKIM"));
-		print '<tr class="oddeven"><td>';
-		print $langs->trans("MAIN_MAIL_EMAIL_FROM", ini_get('sendmail_from') ? ini_get('sendmail_from') : $langs->transnoentities("Undefined"));
-		print ' '.$help;
-		print '</td>';
-		print '<td>' . getDolGlobalString('MAIN_MAIL_EMAIL_FROM');
-		if (!getDolGlobalString('MAIN_MAIL_EMAIL_FROM')) {
-			print img_warning($langs->trans("Mandatory"));
-		} elseif (!isValidEmail($conf->global->MAIN_MAIL_EMAIL_FROM)) {
-			print img_warning($langs->trans("ErrorBadEMail"));
-		}
-		print '</td></tr>';
+	// From
+	$help = $form->textwithpicto('', $langs->trans("EMailHelpMsgSPFDKIM"));
+	print '<tr class="oddeven"><td>';
+	print $langs->trans("MAIN_MAIL_EMAIL_FROM", ini_get('sendmail_from') ? ini_get('sendmail_from') : $langs->transnoentities("Undefined"));
+	print ' '.$help;
+	print '</td>';
+	print '<td>' . getDolGlobalString('MAIN_MAIL_EMAIL_FROM');
+	if (!getDolGlobalString('MAIN_MAIL_EMAIL_FROM')) {
+		print img_warning($langs->trans("Mandatory"));
+	} elseif (!isValidEmail($conf->global->MAIN_MAIL_EMAIL_FROM)) {
+		print img_warning($langs->trans("ErrorBadEMail"));
+	}
+	print '</td></tr>';
 
-		// Default from type
-		$liste = array();
-		$liste['user'] = $langs->trans('UserEmail');
-		$liste['company'] = $langs->trans('CompanyEmail').' ('.(!getDolGlobalString('MAIN_INFO_SOCIETE_MAIL') ? $langs->trans("NotDefined") : $conf->global->MAIN_INFO_SOCIETE_MAIL).')';
-		$sql = 'SELECT rowid, label, email FROM '.MAIN_DB_PREFIX.'c_email_senderprofile';
-		$sql .= ' WHERE active = 1 AND (private = 0 OR private = '.((int) $user->id).')';
-		$resql = $db->query($sql);
-		if ($resql) {
-			$num = $db->num_rows($resql);
-			$i = 0;
-			while ($i < $num) {
-				$obj = $db->fetch_object($resql);
-				if ($obj) {
-					$liste['senderprofile_'.$obj->rowid] = $obj->label.' <'.$obj->email.'>';
-				}
-				$i++;
+	// Default from type
+	$liste = array();
+	$liste['user'] = $langs->trans('UserEmail');
+	$liste['company'] = $langs->trans('CompanyEmail').' ('.(!getDolGlobalString('MAIN_INFO_SOCIETE_MAIL') ? $langs->trans("NotDefined") : $conf->global->MAIN_INFO_SOCIETE_MAIL).')';
+	$sql = 'SELECT rowid, label, email FROM '.MAIN_DB_PREFIX.'c_email_senderprofile';
+	$sql .= ' WHERE active = 1 AND (private = 0 OR private = '.((int) $user->id).')';
+	$resql = $db->query($sql);
+	if ($resql) {
+		$num = $db->num_rows($resql);
+		$i = 0;
+		while ($i < $num) {
+			$obj = $db->fetch_object($resql);
+			if ($obj) {
+				$liste['senderprofile_'.$obj->rowid] = $obj->label.' <'.$obj->email.'>';
 			}
-		} else {
-			dol_print_error($db);
+			$i++;
 		}
+	} else {
+		dol_print_error($db);
+	}
 
-		print '<tr class="oddeven"><td>'.$langs->trans('MAIN_MAIL_DEFAULT_FROMTYPE').'</td>';
-		print '<td>';
-		if (getDolGlobalString('MAIN_MAIL_DEFAULT_FROMTYPE') === 'robot') {
-			print $langs->trans('RobotEmail');
-		} elseif (getDolGlobalString('MAIN_MAIL_DEFAULT_FROMTYPE') === 'user') {
-			print $langs->trans('UserEmail');
-		} elseif (getDolGlobalString('MAIN_MAIL_DEFAULT_FROMTYPE') === 'company') {
-			print $langs->trans('CompanyEmail').' '.dol_escape_htmltag('<'.$mysoc->email.'>');
-		} else {
-			$id = preg_replace('/senderprofile_/', '', getDolGlobalString('MAIN_MAIL_DEFAULT_FROMTYPE'));
-			if ($id > 0) {
-				include_once DOL_DOCUMENT_ROOT.'/core/class/emailsenderprofile.class.php';
-				$emailsenderprofile = new EmailSenderProfile($db);
-				$emailsenderprofile->fetch($id);
-				print $emailsenderprofile->label.' '.dol_escape_htmltag('<'.$emailsenderprofile->email.'>');
-			}
+	print '<tr class="oddeven"><td>'.$langs->trans('MAIN_MAIL_DEFAULT_FROMTYPE').'</td>';
+	print '<td>';
+	if (getDolGlobalString('MAIN_MAIL_DEFAULT_FROMTYPE') === 'robot') {
+		print $langs->trans('RobotEmail');
+	} elseif (getDolGlobalString('MAIN_MAIL_DEFAULT_FROMTYPE') === 'user') {
+		print $langs->trans('UserEmail');
+	} elseif (getDolGlobalString('MAIN_MAIL_DEFAULT_FROMTYPE') === 'company') {
+		print $langs->trans('CompanyEmail').' '.dol_escape_htmltag('<'.$mysoc->email.'>');
+	} else {
+		$id = preg_replace('/senderprofile_/', '', getDolGlobalString('MAIN_MAIL_DEFAULT_FROMTYPE'));
+		if ($id > 0) {
+			include_once DOL_DOCUMENT_ROOT.'/core/class/emailsenderprofile.class.php';
+			$emailsenderprofile = new EmailSenderProfile($db);
+			$emailsenderprofile->fetch($id);
+			print $emailsenderprofile->label.' '.dol_escape_htmltag('<'.$emailsenderprofile->email.'>');
 		}
-		print '</td></tr>';
+	}
+	print '</td></tr>';
 
-		// Errors To
-		print '<tr class="oddeven"><td>'.$langs->trans("MAIN_MAIL_ERRORS_TO").'</td>';
-		print '<td>'.(getDolGlobalString('MAIN_MAIL_ERRORS_TO'));
-		if (getDolGlobalString('MAIN_MAIL_ERRORS_TO') && !isValidEmail($conf->global->MAIN_MAIL_ERRORS_TO)) {
-			print img_warning($langs->trans("ErrorBadEMail"));
-		}
-		print '</td></tr>';
+	// Errors To
+	print '<tr class="oddeven"><td>'.$langs->trans("MAIN_MAIL_ERRORS_TO").'</td>';
+	print '<td>'.(getDolGlobalString('MAIN_MAIL_ERRORS_TO'));
+	if (getDolGlobalString('MAIN_MAIL_ERRORS_TO') && !isValidEmail($conf->global->MAIN_MAIL_ERRORS_TO)) {
+		print img_warning($langs->trans("ErrorBadEMail"));
+	}
+	print '</td></tr>';
 
-		// Autocopy to
-		print '<tr class="oddeven"><td>'.$langs->trans("MAIN_MAIL_AUTOCOPY_TO").'</td>';
-		print '<td>';
-		if (getDolGlobalString('MAIN_MAIL_AUTOCOPY_TO')) {
-			$listofemail = explode(',', getDolGlobalString('MAIN_MAIL_AUTOCOPY_TO'));
-			$i = 0;
-			foreach ($listofemail as $key => $val) {
-				if ($i) {
-					print ', ';
-				}
-				$val = trim($val);
-				print $val;
-				if (!isValidEmail($val, 0, 1)) {
-					print img_warning($langs->trans("ErrorBadEMail", $val));
-				}
-				$i++;
+	// Autocopy to
+	print '<tr class="oddeven"><td>'.$langs->trans("MAIN_MAIL_AUTOCOPY_TO").'</td>';
+	print '<td>';
+	if (getDolGlobalString('MAIN_MAIL_AUTOCOPY_TO')) {
+		$listofemail = explode(',', getDolGlobalString('MAIN_MAIL_AUTOCOPY_TO'));
+		$i = 0;
+		foreach ($listofemail as $key => $val) {
+			if ($i) {
+				print ', ';
 			}
-		} else {
-			print '&nbsp;';
+			$val = trim($val);
+			print $val;
+			if (!isValidEmail($val, 0, 1)) {
+				print img_warning($langs->trans("ErrorBadEMail", $val));
+			}
+			$i++;
 		}
-		print '</td></tr>';
+	} else {
+		print '&nbsp;';
+	}
+	print '</td></tr>';
 
-		//Add user to select destinaries list
-		print '<tr class="oddeven"><td>'.$langs->trans("MAIN_MAIL_ENABLED_USER_DEST_SELECT").'</td><td>'.yn(getDolGlobalString('MAIN_MAIL_ENABLED_USER_DEST_SELECT')).'</td></tr>';
-		//Disable autoselect to
-		print '<tr class="oddeven"><td>'.$langs->trans("MAIN_MAIL_NO_WITH_TO_SELECTED").'</td><td>'.yn(getDolGlobalString('MAIN_MAIL_NO_WITH_TO_SELECTED')).'</td></tr>';
+	//Add user to select destinaries list
+	print '<tr class="oddeven"><td>'.$langs->trans("MAIN_MAIL_ENABLED_USER_DEST_SELECT").'</td><td>'.yn(getDolGlobalString('MAIN_MAIL_ENABLED_USER_DEST_SELECT')).'</td></tr>';
+	//Disable autoselect to
+	print '<tr class="oddeven"><td>'.$langs->trans("MAIN_MAIL_NO_WITH_TO_SELECTED").'</td><td>'.yn(getDolGlobalString('MAIN_MAIL_NO_WITH_TO_SELECTED')).'</td></tr>';
+
+	print '</table>';
+	print '</div>';
 
-		print '</table>';
-		print '</div>';
-	}
 
 	print dol_get_fiche_end();
 

+ 3 - 3
htdocs/admin/mails_templates.php

@@ -685,7 +685,7 @@ if (!empty($user->admin) && (empty($_SESSION['leftmenu']) || $_SESSION['leftmenu
 
 // Confirm deletion of record
 if ($action == 'delete') {
-	print $form->formconfirm($_SERVER["PHP_SELF"].'?'.($page ? 'page='.$page.'&' : '').'sortfield='.$sortfield.'&sortorder='.$sortorder.'&rowid='.((int) $rowid).'&code='.urlencode($code).'&id='.((int) $id), $langs->trans('DeleteLine'), $langs->trans('ConfirmDeleteLine'), 'confirm_delete', '', 0, 1);
+	print $form->formconfirm($_SERVER["PHP_SELF"].'?'.($page ? 'page='.$page.'&' : '').'sortfield='.$sortfield.'&sortorder='.$sortorder.'&rowid='.((int) $rowid).'&id='.((int) $id), $langs->trans('DeleteLine'), $langs->trans('ConfirmDeleteLine'), 'confirm_delete', '', 0, 1);
 }
 
 
@@ -1044,7 +1044,7 @@ foreach ($fieldlist as $field => $value) {
 		}
 		$sortfieldtouse = ($sortable ? $fieldlist[$field] : '');
 		if ($sortfieldtouse == 'type_template') {
-			$sortfieldtouse.= 'type_template,lang,position,label';
+			$sortfieldtouse .= ',lang,position,label';
 		}
 		print getTitleFieldOfList($valuetoshow, 0, $_SERVER["PHP_SELF"], $sortfieldtouse, ($page ? 'page='.$page.'&' : ''), $param, '', $sortfield, $sortorder, $css.' ');
 	}
@@ -1100,7 +1100,7 @@ if ($num) {
 				}
 				print "</tr>\n";
 
-				print '<tr class="oddeven nohover'.(in_array($tmpfieldlist, array('topic', 'joinfiles')) ? ' nobottom' : '').'" id="tr-'.$tmpfieldlist.'-'.$rowid.'">';
+				print '<tr class="oddeven nohover" id="tr-aaa-'.$rowid.'">';
 				print '<td colspan="10">';
 
 				$fieldsforcontent = array('topic', 'email_from','joinfiles', 'content');

+ 4 - 4
htdocs/admin/menus/edit.php

@@ -360,14 +360,14 @@ if ($action == 'create') {
 	print '<tr><td class="fieldrequired">'.$langs->trans('Title').'</td>';
 	print '<td><input type="text" class="minwidth300" name="titre" value="'.dol_escape_htmltag(GETPOST("titre", 'alphanohtml')).'"></td><td>'.$langs->trans('DetailTitre').'</td></tr>';
 
-	// Picto
-	print '<tr><td class="fieldrequired">'.$langs->trans('Image').'</td>';
-	print '<td><input type="text" class="minwidth300" name="picto" value="'.dol_escape_htmltag(GETPOST("picto", 'alphanohtmlallowclass')).'"></td><td>'.$langs->trans('Example').': fa-global</td></tr>';
-
 	// URL
 	print '<tr><td class="fieldrequired">'.$langs->trans('URL').'</td>';
 	print '<td><input type="text" class="minwidth500" name="url" value="'.dol_escape_htmltag(GETPOST("url", 'alphanohtml')).'"></td><td>'.$langs->trans('DetailUrl').'</td></tr>';
 
+	// Picto
+	print '<tr><td class="fieldrequired">'.$langs->trans('Image').'</td>';
+	print '<td><input type="text" class="minwidth300" name="picto" value="'.dol_escape_htmltag(GETPOST("picto", 'alphanohtml')).'"></td><td>'.$langs->trans('Example').': fa-global</td></tr>';
+
 	// Langs
 	print '<tr><td>'.$langs->trans('LangFile').'</td>';
 	print '<td><input type="text" class="minwidth300" name="langs" value="'.dol_escape_htmltag($parent_langs).'"></td><td>'.$langs->trans('DetailLangs').'</td></tr>';

+ 10 - 8
htdocs/admin/modules.php

@@ -122,6 +122,13 @@ if ($max_time && $max_time < $max_execution_time_for_deploy) {
 	@ini_set("max_execution_time", $max_execution_time_for_deploy); // This work only if safe mode is off. also web servers has timeout of 300
 }
 
+$dolibarrdataroot = preg_replace('/([\\/]+)$/i', '', DOL_DATA_ROOT);
+$allowonlineinstall = true;
+$allowfromweb = 1;
+if (dol_is_file($dolibarrdataroot.'/installmodules.lock')) {
+	$allowonlineinstall = false;
+}
+
 
 /*
  * Actions
@@ -142,7 +149,7 @@ if (GETPOST('buttonreset', 'alpha')) {
 	$search_version = '';
 }
 
-if ($action == 'install') {
+if ($action == 'install' && $allowonlineinstall) {
 	$error = 0;
 
 	// $original_file should match format module_modulename-x.y[.z].zip
@@ -263,6 +270,8 @@ if ($action == 'install') {
 	if (!$error) {
 		setEventMessages($langs->trans("SetupIsReadyForUse", DOL_URL_ROOT.'/admin/modules.php?mainmenu=home', $langs->transnoentitiesnoconv("Home").' - '.$langs->transnoentitiesnoconv("Setup").' - '.$langs->transnoentitiesnoconv("Modules")), null, 'warnings');
 	}
+} elseif ($action == 'install' && !$allowonlineinstall) {
+	httponly_accessforbidden("You try to bypass the protection to disallow deployment of an external module. Hack attempt ?");
 }
 
 if ($action == 'set' && $user->admin) {
@@ -1175,13 +1184,6 @@ if ($mode == 'marketplace') {
 if ($mode == 'deploy') {
 	print dol_get_fiche_head($head, $mode, '', -1);
 
-	$dolibarrdataroot = preg_replace('/([\\/]+)$/i', '', DOL_DATA_ROOT);
-	$allowonlineinstall = true;
-	$allowfromweb = 1;
-	if (dol_is_file($dolibarrdataroot.'/installmodules.lock')) {
-		$allowonlineinstall = false;
-	}
-
 	$fullurl = '<a href="'.$urldolibarrmodules.'" target="_blank" rel="noopener noreferrer">'.$urldolibarrmodules.'</a>';
 	$message = '';
 	if ($allowonlineinstall) {

+ 1 - 0
htdocs/admin/mrp_extrafields.php

@@ -65,6 +65,7 @@ require DOL_DOCUMENT_ROOT.'/core/actions_extrafields.inc.php';
  * View
  */
 
+$textobject = $langs->transnoentitiesnoconv('ManufacturingOrder');
 
 llxHeader('', $langs->trans("MrpSetupPage"), $help_url);
 

+ 2 - 0
htdocs/admin/mrp_production_extrafields.php

@@ -65,6 +65,8 @@ require DOL_DOCUMENT_ROOT.'/core/actions_extrafields.inc.php';
  * View
  */
 
+$textobject = $langs->transnoentitiesnoconv('ManufacturingOrder');
+
 $help_url = '';
 llxHeader('', $langs->trans("MrpSetupPage"), $help_url);
 

+ 210 - 208
htdocs/admin/oauthlogintokens.php

@@ -159,253 +159,255 @@ if ($mode == 'setup' && $user->admin) {
 	$oauthstateanticsrf = bin2hex(random_bytes(128/8));
 
 	// $list is defined into oauth.lib.php to the list of supporter OAuth providers.
-	foreach ($listinsetup as $key) {
-		$supported = 0;
-		$keyforsupportedoauth2array = $key[0];						// May be OAUTH_GOOGLE_NAME or OAUTH_GOOGLE_xxx_NAME
-		$keyforsupportedoauth2array = preg_replace('/^OAUTH_/', '', $keyforsupportedoauth2array);
-		$keyforsupportedoauth2array = preg_replace('/_NAME$/', '', $keyforsupportedoauth2array);
-		if (preg_match('/^.*-/', $keyforsupportedoauth2array)) {
-			$keybeforeprovider = preg_replace('/-.*$/', '', $keyforsupportedoauth2array);
-			$keyforprovider = preg_replace('/^.*-/', '', $keyforsupportedoauth2array);
-		} else {
-			$keybeforeprovider = $keyforsupportedoauth2array;
-			$keyforprovider = '';
-		}
-		$keyforsupportedoauth2array = preg_replace('/-.*$/', '', $keyforsupportedoauth2array);
-		$keyforsupportedoauth2array = 'OAUTH_'.$keyforsupportedoauth2array.'_NAME';
+	if (!empty($listinsetup)) {
+		foreach ($listinsetup as $key) {
+			$supported = 0;
+			$keyforsupportedoauth2array = $key[0];						// May be OAUTH_GOOGLE_NAME or OAUTH_GOOGLE_xxx_NAME
+			$keyforsupportedoauth2array = preg_replace('/^OAUTH_/', '', $keyforsupportedoauth2array);
+			$keyforsupportedoauth2array = preg_replace('/_NAME$/', '', $keyforsupportedoauth2array);
+			if (preg_match('/^.*-/', $keyforsupportedoauth2array)) {
+				$keybeforeprovider = preg_replace('/-.*$/', '', $keyforsupportedoauth2array);
+				$keyforprovider = preg_replace('/^.*-/', '', $keyforsupportedoauth2array);
+			} else {
+				$keybeforeprovider = $keyforsupportedoauth2array;
+				$keyforprovider = '';
+			}
+			$keyforsupportedoauth2array = preg_replace('/-.*$/', '', $keyforsupportedoauth2array);
+			$keyforsupportedoauth2array = 'OAUTH_'.$keyforsupportedoauth2array.'_NAME';
 
 
-		$OAUTH_SERVICENAME = (empty($supportedoauth2array[$keyforsupportedoauth2array]['name']) ? 'Unknown' : $supportedoauth2array[$keyforsupportedoauth2array]['name'].($keyforprovider ? '-'.$keyforprovider : ''));
+			$OAUTH_SERVICENAME = (empty($supportedoauth2array[$keyforsupportedoauth2array]['name']) ? 'Unknown' : $supportedoauth2array[$keyforsupportedoauth2array]['name'].($keyforprovider ? '-'.$keyforprovider : ''));
 
-		$shortscope = '';
-		if (getDolGlobalString($key[4])) {
-			$shortscope = getDolGlobalString($key[4]);
-		}
-		$state = $shortscope;	// TODO USe a better state
-
-		// Define $urltorenew, $urltodelete, $urltocheckperms
-		if ($keyforsupportedoauth2array == 'OAUTH_GITHUB_NAME') {
-			// List of keys that will be converted into scopes (from constants 'SCOPE_state_in_uppercase' in file of service).
-			// We pass this param list in to 'state' because we need it before and after the redirect.
-
-			// Note: github does not accept csrf key inside the state parameter (only known values)
-			$urltorenew = $urlwithroot.'/core/modules/oauth/github_oauthcallback.php?shortscope='.urlencode($shortscope).'&state='.urlencode($shortscope).'&backtourl='.urlencode(DOL_URL_ROOT.'/admin/oauthlogintokens.php');
-			$urltodelete = $urlwithroot.'/core/modules/oauth/github_oauthcallback.php?action=delete&token='.newToken().'&backtourl='.urlencode(DOL_URL_ROOT.'/admin/oauthlogintokens.php');
-			$urltocheckperms = 'https://github.com/settings/applications/';
-		} elseif ($keyforsupportedoauth2array == 'OAUTH_GOOGLE_NAME') {
-			// List of keys that will be converted into scopes (from constants 'SCOPE_state_in_uppercase' in file of service).
-			// List of scopes for Google are here: https://developers.google.com/identity/protocols/oauth2/scopes
-			// We pass this key list into the param 'state' because we need it before and after the redirect.
-			$urltorenew = $urlwithroot.'/core/modules/oauth/google_oauthcallback.php?shortscope='.urlencode($shortscope).'&state='.urlencode($state).'-'.$oauthstateanticsrf.'&backtourl='.urlencode(DOL_URL_ROOT.'/admin/oauthlogintokens.php');
-			$urltodelete = $urlwithroot.'/core/modules/oauth/google_oauthcallback.php?action=delete&token='.newToken().'&backtourl='.urlencode(DOL_URL_ROOT.'/admin/oauthlogintokens.php');
-			$urltocheckperms = 'https://security.google.com/settings/security/permissions';
-		} elseif (!empty($supportedoauth2array[$keyforsupportedoauth2array]['returnurl'])) {
-			$urltorenew = $urlwithroot.$supportedoauth2array[$keyforsupportedoauth2array]['returnurl'].'?shortscope='.urlencode($shortscope).'&state='.urlencode($state).'&backtourl='.urlencode(DOL_URL_ROOT.'/admin/oauthlogintokens.php');
-			$urltodelete = $urlwithroot.$supportedoauth2array[$keyforsupportedoauth2array]['returnurl'].'?action=delete&token='.newToken().'&backtourl='.urlencode(DOL_URL_ROOT.'/admin/oauthlogintokens.php');
-			$urltocheckperms = '';
-		} else {
-			$urltorenew = '';
-			$urltodelete = '';
-			$urltocheckperms = '';
-		}
+			$shortscope = '';
+			if (getDolGlobalString($key[4])) {
+				$shortscope = getDolGlobalString($key[4]);
+			}
+			$state = $shortscope;	// TODO USe a better state
+
+			// Define $urltorenew, $urltodelete, $urltocheckperms
+			if ($keyforsupportedoauth2array == 'OAUTH_GITHUB_NAME') {
+				// List of keys that will be converted into scopes (from constants 'SCOPE_state_in_uppercase' in file of service).
+				// We pass this param list in to 'state' because we need it before and after the redirect.
+
+				// Note: github does not accept csrf key inside the state parameter (only known values)
+				$urltorenew = $urlwithroot.'/core/modules/oauth/github_oauthcallback.php?shortscope='.urlencode($shortscope).'&state='.urlencode($shortscope).'&backtourl='.urlencode(DOL_URL_ROOT.'/admin/oauthlogintokens.php');
+				$urltodelete = $urlwithroot.'/core/modules/oauth/github_oauthcallback.php?action=delete&token='.newToken().'&backtourl='.urlencode(DOL_URL_ROOT.'/admin/oauthlogintokens.php');
+				$urltocheckperms = 'https://github.com/settings/applications/';
+			} elseif ($keyforsupportedoauth2array == 'OAUTH_GOOGLE_NAME') {
+				// List of keys that will be converted into scopes (from constants 'SCOPE_state_in_uppercase' in file of service).
+				// List of scopes for Google are here: https://developers.google.com/identity/protocols/oauth2/scopes
+				// We pass this key list into the param 'state' because we need it before and after the redirect.
+				$urltorenew = $urlwithroot.'/core/modules/oauth/google_oauthcallback.php?shortscope='.urlencode($shortscope).'&state='.urlencode($state).'-'.$oauthstateanticsrf.'&backtourl='.urlencode(DOL_URL_ROOT.'/admin/oauthlogintokens.php');
+				$urltodelete = $urlwithroot.'/core/modules/oauth/google_oauthcallback.php?action=delete&token='.newToken().'&backtourl='.urlencode(DOL_URL_ROOT.'/admin/oauthlogintokens.php');
+				$urltocheckperms = 'https://security.google.com/settings/security/permissions';
+			} elseif (!empty($supportedoauth2array[$keyforsupportedoauth2array]['returnurl'])) {
+				$urltorenew = $urlwithroot.$supportedoauth2array[$keyforsupportedoauth2array]['returnurl'].'?shortscope='.urlencode($shortscope).'&state='.urlencode($state).'&backtourl='.urlencode(DOL_URL_ROOT.'/admin/oauthlogintokens.php');
+				$urltodelete = $urlwithroot.$supportedoauth2array[$keyforsupportedoauth2array]['returnurl'].'?action=delete&token='.newToken().'&backtourl='.urlencode(DOL_URL_ROOT.'/admin/oauthlogintokens.php');
+				$urltocheckperms = '';
+			} else {
+				$urltorenew = '';
+				$urltodelete = '';
+				$urltocheckperms = '';
+			}
 
-		if ($urltorenew) {
-			$urltorenew .= '&keyforprovider='.urlencode($keyforprovider);
-		}
-		if ($urltodelete) {
-			$urltodelete .= '&keyforprovider='.urlencode($keyforprovider);
-		}
+			if ($urltorenew) {
+				$urltorenew .= '&keyforprovider='.urlencode($keyforprovider);
+			}
+			if ($urltodelete) {
+				$urltodelete .= '&keyforprovider='.urlencode($keyforprovider);
+			}
 
-		// Show value of token
-		$tokenobj = null;
-		// Token
-		require_once DOL_DOCUMENT_ROOT.'/includes/OAuth/bootstrap.php';
-		// Dolibarr storage
-		$storage = new DoliStorage($db, $conf, $keyforprovider);
-		try {
-			// $OAUTH_SERVICENAME is for example 'Google-keyforprovider'
-			print '<!-- '.$OAUTH_SERVICENAME.' -->'."\n";
-			$tokenobj = $storage->retrieveAccessToken($OAUTH_SERVICENAME);
-			//print $storage->token.'<br>';
-			//print $tokenobj->getExtraParams()['id_token'].'<br>';
-			//print $tokenobj->getAccessToken().'<br>';
-		} catch (Exception $e) {
-			// Return an error if token not found
-			//print $e->getMessage();
-		}
+			// Show value of token
+			$tokenobj = null;
+			// Token
+			require_once DOL_DOCUMENT_ROOT.'/includes/OAuth/bootstrap.php';
+			// Dolibarr storage
+			$storage = new DoliStorage($db, $conf, $keyforprovider);
+			try {
+				// $OAUTH_SERVICENAME is for example 'Google-keyforprovider'
+				print '<!-- '.$OAUTH_SERVICENAME.' -->'."\n";
+				$tokenobj = $storage->retrieveAccessToken($OAUTH_SERVICENAME);
+				//print $storage->token.'<br>';
+				//print $tokenobj->getExtraParams()['id_token'].'<br>';
+				//print $tokenobj->getAccessToken().'<br>';
+			} catch (Exception $e) {
+				// Return an error if token not found
+				//print $e->getMessage();
+			}
 
-		// Set other properties
-		$refreshtoken = false;
-		$expiredat = '';
+			// Set other properties
+			$refreshtoken = false;
+			$expiredat = '';
 
-		$expire = false;
-		// Is token expired or will token expire in the next 30 seconds
-		if (is_object($tokenobj)) {
-			$expire = ($tokenobj->getEndOfLife() !== $tokenobj::EOL_NEVER_EXPIRES && $tokenobj->getEndOfLife() !== $tokenobj::EOL_UNKNOWN && time() > ($tokenobj->getEndOfLife() - 30));
-		}
-		if ($key[1] != '' && $key[2] != '') {
+			$expire = false;
+			// Is token expired or will token expire in the next 30 seconds
 			if (is_object($tokenobj)) {
-				$refreshtoken = $tokenobj->getRefreshToken();
-
-				$endoflife = $tokenobj->getEndOfLife();
-				if ($endoflife == $tokenobj::EOL_NEVER_EXPIRES) {
-					$expiredat = $langs->trans("Never");
-				} elseif ($endoflife == $tokenobj::EOL_UNKNOWN) {
-					$expiredat = $langs->trans("Unknown");
-				} else {
-					$expiredat = dol_print_date($endoflife, "dayhour", 'tzuserrel');
+				$expire = ($tokenobj->getEndOfLife() !== $tokenobj::EOL_NEVER_EXPIRES && $tokenobj->getEndOfLife() !== $tokenobj::EOL_UNKNOWN && time() > ($tokenobj->getEndOfLife() - 30));
+			}
+			if ($key[1] != '' && $key[2] != '') {
+				if (is_object($tokenobj)) {
+					$refreshtoken = $tokenobj->getRefreshToken();
+
+					$endoflife = $tokenobj->getEndOfLife();
+					if ($endoflife == $tokenobj::EOL_NEVER_EXPIRES) {
+						$expiredat = $langs->trans("Never");
+					} elseif ($endoflife == $tokenobj::EOL_UNKNOWN) {
+						$expiredat = $langs->trans("Unknown");
+					} else {
+						$expiredat = dol_print_date($endoflife, "dayhour", 'tzuserrel');
+					}
 				}
 			}
-		}
-
-		$submit_enabled = 0;
-
-		print '<form method="post" action="'.$_SERVER["PHP_SELF"].'?mode=setup&amp;driver='.$driver.'" autocomplete="off">';
-		print '<input type="hidden" name="token" value="'.newToken().'">';
-		print '<input type="hidden" name="action" value="setconst">';
 
-		print '<div class="div-table-responsive-no-min">';
-		print '<table class="noborder centpercent">'."\n";
+			$submit_enabled = 0;
 
-		// Api Name
-		$label = $langs->trans($keyforsupportedoauth2array);
-		print '<tr class="liste_titre">';
-		print '<th class="titlefieldcreate">';
-		print img_picto('', $supportedoauth2array[$keyforsupportedoauth2array]['picto'], 'class="pictofixedwidth"');
-		if ($label == $keyforsupportedoauth2array) {
-			print $supportedoauth2array[$keyforsupportedoauth2array]['name'];
-		} else {
-			print $label;
-		}
-		if ($keyforprovider) {
-			print ' (<b>'.$keyforprovider.'</b>)';
-		} else {
-			print ' (<b>'.$langs->trans("NoName").'</b>)';
-		}
-		print '</th>';
-		print '<th></th>';
-		print '<th></th>';
-		print "</tr>\n";
+			print '<form method="post" action="'.$_SERVER["PHP_SELF"].'?mode=setup&amp;driver='.$driver.'" autocomplete="off">';
+			print '<input type="hidden" name="token" value="'.newToken().'">';
+			print '<input type="hidden" name="action" value="setconst">';
 
-		print '<tr class="oddeven">';
-		print '<td'.(empty($key['required']) ? '' : ' class="required"').'>';
-		//var_dump($key);
-		print $langs->trans("OAuthIDSecret").'</td>';
-		print '<td>';
-		print '<span class="opacitymedium">'.$langs->trans("SeePreviousTab").'</span>';
-		print '</td>';
-		print '<td>';
-		print '</td>';
-		print '</tr>'."\n";
-
-		// Scopes
-		print '<tr class="oddeven">';
-		print '<td>'.$langs->trans("Scopes").'</td>';
-		print '<td colspan="2">';
-		$currentscopes = getDolGlobalString($key[4]);
-		print $currentscopes;
-		print '</td></tr>';
+			print '<div class="div-table-responsive-no-min">';
+			print '<table class="noborder centpercent">'."\n";
 
-		print '<tr class="oddeven">';
-		print '<td'.(empty($key['required']) ? '' : ' class="required"').'>';
-		//var_dump($key);
-		print $langs->trans("IsTokenGenerated");
-		print '</td>';
-		print '<td>';
-		if (is_object($tokenobj)) {
-			print $form->textwithpicto(yn(1), $langs->trans("HasAccessToken").' : '.dol_print_date($storage->date_modification, 'dayhour').' state='.dol_escape_htmltag($storage->state));
-		} else {
-			print '<span class="opacitymedium">'.$langs->trans("NoAccessToken").'</span>';
-		}
-		print '</td>';
-		print '<td width="50%">';
-		// Links to delete/checks token
-		if (is_object($tokenobj)) {
-			//test on $storage->hasAccessToken($OAUTH_SERVICENAME) ?
-			if ($urltodelete) {
-				print '<a class="button smallpaddingimp" href="'.$urltodelete.'">'.$langs->trans('DeleteAccess').'</a><br>';
+			// Api Name
+			$label = $langs->trans($keyforsupportedoauth2array);
+			print '<tr class="liste_titre">';
+			print '<th class="titlefieldcreate">';
+			print img_picto('', $supportedoauth2array[$keyforsupportedoauth2array]['picto'], 'class="pictofixedwidth"');
+			if ($label == $keyforsupportedoauth2array) {
+				print $supportedoauth2array[$keyforsupportedoauth2array]['name'];
 			} else {
-				print '<span class="opacitymedium">'.$langs->trans('GoOnTokenProviderToDeleteToken').'</span><br>';
+				print $label;
 			}
-		}
-		// Request remote token
-		if ($urltorenew) {
-			print '<a class="button smallpaddingimp" href="'.$urltorenew.'">'.$langs->trans('GetAccess').'</a>';
-			print $form->textwithpicto('', $langs->trans('RequestAccess'));
-			print '<br>';
-		}
-		// Check remote access
-		if ($urltocheckperms) {
-			print '<br>'.$langs->trans("ToCheckDeleteTokenOnProvider", $OAUTH_SERVICENAME).': <a href="'.$urltocheckperms.'" target="_'.strtolower($OAUTH_SERVICENAME).'">'.$urltocheckperms.'</a>';
-		}
-		print '</td>';
-		print '</tr>';
-
-		print '<tr class="oddeven">';
-		print '<td'.(empty($key['required']) ? '' : ' class="required"').'>';
-		//var_dump($key);
-		print $langs->trans("Token").'</td>';
-		print '<td colspan="2">';
-
-		if (is_object($tokenobj)) {
-			$tokentoshow = $tokenobj->getAccessToken();
-			print '<span class="" title="'.dol_escape_htmltag($tokentoshow).'">'.showValueWithClipboardCPButton($tokentoshow, 1, dol_trunc($tokentoshow, 32)).'</span><br>';
-			//print 'Refresh: '.$tokenobj->getRefreshToken().'<br>';
-			//print 'EndOfLife: '.$tokenobj->getEndOfLife().'<br>';
-			//var_dump($tokenobj->getExtraParams());
-			/*print '<br>Extra: <br><textarea class="quatrevingtpercent">';
-			print ''.join(',',$tokenobj->getExtraParams());
-			print '</textarea>';*/
-		}
-		print '</td>';
-		print '</tr>'."\n";
+			if ($keyforprovider) {
+				print ' (<b>'.$keyforprovider.'</b>)';
+			} else {
+				print ' (<b>'.$langs->trans("NoName").'</b>)';
+			}
+			print '</th>';
+			print '<th></th>';
+			print '<th></th>';
+			print "</tr>\n";
 
-		if (is_object($tokenobj)) {
-			// Token refresh
 			print '<tr class="oddeven">';
 			print '<td'.(empty($key['required']) ? '' : ' class="required"').'>';
 			//var_dump($key);
-			print $langs->trans("TOKEN_REFRESH");
+			print $langs->trans("OAuthIDSecret").'</td>';
+			print '<td>';
+			print '<span class="opacitymedium">'.$langs->trans("SeePreviousTab").'</span>';
 			print '</td>';
-			print '<td colspan="2">';
-			print '<span class="" title="'.dol_escape_htmltag($refreshtoken).'">'.showValueWithClipboardCPButton($refreshtoken, 1, dol_trunc($refreshtoken, 32)).'</span>';
+			print '<td>';
 			print '</td>';
-			print '</tr>';
+			print '</tr>'."\n";
+
+			// Scopes
+			print '<tr class="oddeven">';
+			print '<td>'.$langs->trans("Scopes").'</td>';
+			print '<td colspan="2">';
+			$currentscopes = getDolGlobalString($key[4]);
+			print $currentscopes;
+			print '</td></tr>';
 
-			// Token expired
 			print '<tr class="oddeven">';
 			print '<td'.(empty($key['required']) ? '' : ' class="required"').'>';
 			//var_dump($key);
-			print $langs->trans("TOKEN_EXPIRED");
+			print $langs->trans("IsTokenGenerated");
 			print '</td>';
-			print '<td colspan="2">';
-			print yn($expire);
+			print '<td>';
+			if (is_object($tokenobj)) {
+				print $form->textwithpicto(yn(1), $langs->trans("HasAccessToken").' : '.dol_print_date($storage->date_modification, 'dayhour').' state='.dol_escape_htmltag($storage->state));
+			} else {
+				print '<span class="opacitymedium">'.$langs->trans("NoAccessToken").'</span>';
+			}
+			print '</td>';
+			print '<td width="50%">';
+			// Links to delete/checks token
+			if (is_object($tokenobj)) {
+				//test on $storage->hasAccessToken($OAUTH_SERVICENAME) ?
+				if ($urltodelete) {
+					print '<a class="button smallpaddingimp" href="'.$urltodelete.'">'.$langs->trans('DeleteAccess').'</a><br>';
+				} else {
+					print '<span class="opacitymedium">'.$langs->trans('GoOnTokenProviderToDeleteToken').'</span><br>';
+				}
+			}
+			// Request remote token
+			if ($urltorenew) {
+				print '<a class="button smallpaddingimp" href="'.$urltorenew.'">'.$langs->trans('GetAccess').'</a>';
+				print $form->textwithpicto('', $langs->trans('RequestAccess'));
+				print '<br>';
+			}
+			// Check remote access
+			if ($urltocheckperms) {
+				print '<br>'.$langs->trans("ToCheckDeleteTokenOnProvider", $OAUTH_SERVICENAME).': <a href="'.$urltocheckperms.'" target="_'.strtolower($OAUTH_SERVICENAME).'">'.$urltocheckperms.'</a>';
+			}
 			print '</td>';
 			print '</tr>';
 
-			// Token expired at
 			print '<tr class="oddeven">';
 			print '<td'.(empty($key['required']) ? '' : ' class="required"').'>';
 			//var_dump($key);
-			print $langs->trans("TOKEN_EXPIRE_AT");
-			print '</td>';
+			print $langs->trans("Token").'</td>';
 			print '<td colspan="2">';
-			print $expiredat;
+
+			if (is_object($tokenobj)) {
+				$tokentoshow = $tokenobj->getAccessToken();
+				print '<span class="" title="'.dol_escape_htmltag($tokentoshow).'">'.showValueWithClipboardCPButton($tokentoshow, 1, dol_trunc($tokentoshow, 32)).'</span><br>';
+				//print 'Refresh: '.$tokenobj->getRefreshToken().'<br>';
+				//print 'EndOfLife: '.$tokenobj->getEndOfLife().'<br>';
+				//var_dump($tokenobj->getExtraParams());
+				/*print '<br>Extra: <br><textarea class="quatrevingtpercent">';
+				 print ''.join(',',$tokenobj->getExtraParams());
+				 print '</textarea>';*/
+			}
 			print '</td>';
-			print '</tr>';
-		}
+			print '</tr>'."\n";
+
+			if (is_object($tokenobj)) {
+				// Token refresh
+				print '<tr class="oddeven">';
+				print '<td'.(empty($key['required']) ? '' : ' class="required"').'>';
+				//var_dump($key);
+				print $langs->trans("TOKEN_REFRESH");
+				print '</td>';
+				print '<td colspan="2">';
+				print '<span class="" title="'.dol_escape_htmltag($refreshtoken).'">'.showValueWithClipboardCPButton($refreshtoken, 1, dol_trunc($refreshtoken, 32)).'</span>';
+				print '</td>';
+				print '</tr>';
+
+				// Token expired
+				print '<tr class="oddeven">';
+				print '<td'.(empty($key['required']) ? '' : ' class="required"').'>';
+				//var_dump($key);
+				print $langs->trans("TOKEN_EXPIRED");
+				print '</td>';
+				print '<td colspan="2">';
+				print yn($expire);
+				print '</td>';
+				print '</tr>';
+
+				// Token expired at
+				print '<tr class="oddeven">';
+				print '<td'.(empty($key['required']) ? '' : ' class="required"').'>';
+				//var_dump($key);
+				print $langs->trans("TOKEN_EXPIRE_AT");
+				print '</td>';
+				print '<td colspan="2">';
+				print $expiredat;
+				print '</td>';
+				print '</tr>';
+			}
 
-		print '</table>';
-		print '</div>';
+			print '</table>';
+			print '</div>';
 
-		if (!empty($driver)) {
-			if ($submit_enabled) {
-				print $form->buttonsSaveCancel("Modify", '');
+			if (!empty($driver)) {
+				if ($submit_enabled) {
+					print $form->buttonsSaveCancel("Modify", '');
+				}
 			}
-		}
 
-		print '</form>';
-		print '<br>';
+			print '</form>';
+			print '<br>';
+		}
 	}
 }
 

+ 1 - 1
htdocs/admin/pdf_other.php

@@ -275,7 +275,7 @@ if (isModEnabled('facture')) {
 		'1'=>$langs->trans("InvoiceOptionCategoryOfOperationsYes1"),
 		'2'=>$langs->trans("InvoiceOptionCategoryOfOperationsYes2")
 	);
-	print $form->selectarray("INVOICE_CATEGORY_OF_OPERATION", $arrval, $conf->global->INVOICE_CATEGORY_OF_OPERATION, 0, 0, 0, '', 0, 0, 0, '', 'minwidth75imp');
+	print $form->selectarray("INVOICE_CATEGORY_OF_OPERATION", $arrval, getDolGlobalString('INVOICE_CATEGORY_OF_OPERATION'), 0, 0, 0, '', 0, 0, 0, '', 'minwidth75imp');
 	print '</td></tr>';
 
 	print '<tr class="oddeven"><td>';

+ 3 - 3
htdocs/admin/stock.php

@@ -142,7 +142,7 @@ if ($action == 'specimen') {
 } elseif ($action == 'del') {
 	$ret = delDocumentModel($value, $type);
 	if ($ret > 0) {
-		if ($conf->global->STOCK_ADDON_PDF == "$value") {
+		if (getDolGlobalString('STOCK_ADDON_PDF') == "$value") {
 			dolibarr_del_const($db, 'STOCK_ADDON_PDF', $conf->entity);
 		}
 	}
@@ -620,7 +620,7 @@ foreach ($dirmodels as $reldir) {
 
 								// Default
 								print '<td class="center">';
-								if ($conf->global->STOCK_ADDON_PDF == $name) {
+								if (getDolGlobalString('STOCK_ADDON_PDF') == $name) {
 									print img_picto($langs->trans("Default"), 'on');
 								} else {
 									print '<a class="reposition" href="'.$_SERVER["PHP_SELF"].'?action=setdoc&token='.newToken().'&value='.urlencode($name).'&scan_dir='.urlencode($module->scandir).'&label='.urlencode($module->name).'" alt="'.$langs->trans("Default").'">'.img_picto($langs->trans("Disabled"), 'off').'</a>';
@@ -689,7 +689,7 @@ print '<tr class="oddeven">';
 print '<td>'.$langs->trans("MainDefaultWarehouse").'</td>';
 print '<td class="right">';
 print $formproduct->selectWarehouses(getDolGlobalString('MAIN_DEFAULT_WAREHOUSE') ? $conf->global->MAIN_DEFAULT_WAREHOUSE : -1, 'default_warehouse', '', 1, 0, 0, '', 0, 0, array(), 'left reposition');
-print '<input type="submit" class="button button-edit small" value="'.$langs->trans("Modify").'">';
+print '<input type="submit" class="button button-edit smallpaddingimp" value="'.$langs->trans("Modify").'">';
 print "</td>";
 print "</tr>\n";
 

+ 13 - 6
htdocs/admin/system/security.php

@@ -341,12 +341,13 @@ if (!getDolGlobalString('SECURITY_DISABLE_TEST_ON_OBFUSCATED_CONF')) {
 }
 
 print '<strong>$dolibarr_main_stream_to_disable</strong>: ';
+// $arrayofstreamtodisable is defined into filefunc.inc.php
 if (empty($dolibarr_main_stream_to_disable)) {
 	print '<span class="opacitymedium">'.$langs->trans("Undefined").' = '.join(', ', $arrayofstreamtodisable).'</span>';
 } else {
 	print join(', ', $dolibarr_main_stream_to_disable);
 }
-print '<span class="bold"> -> PHP streams allowed = </span>';
+print '<span class="bold"> -> Current PHP streams allowed = </span>';
 $arrayofstreams = stream_get_wrappers();
 if (!empty($arrayofstreams)) {
 	sort($arrayofstreams);
@@ -737,7 +738,7 @@ $examplecsprule = "frame-ancestors 'self'; img-src * data:; font-src *; default-
 print '<strong>MAIN_SECURITY_FORCECSP</strong> = '.getDolGlobalString('MAIN_SECURITY_FORCECSP', '<span class="opacitymedium">'.$langs->trans("Undefined").'</span>').' &nbsp; <span class="opacitymedium">('.$langs->trans("Example").': "'.$examplecsprule.'")</span><br>';
 print '<br>';
 
-print '<strong>MAIN_SECURITY_FORCERP</strong> = '.getDolGlobalString('MAIN_SECURITY_FORCERP', '<span class="opacitymedium">'.$langs->trans("Undefined").'</span>').' &nbsp; <span class="opacitymedium">('.$langs->trans("Recommended").': '.$langs->trans("Undefined").' '.$langs->trans("or")." \"same-origin\" so browser doesn't send any referrer when going into another web site domain)</span><br>";
+print '<strong>MAIN_SECURITY_FORCERP</strong> = '.getDolGlobalString('MAIN_SECURITY_FORCERP', '<span class="opacitymedium">'.$langs->trans("Undefined").'</span>').' &nbsp; <span class="opacitymedium">('.$langs->trans("Recommended").': '.$langs->trans("Undefined").' '.$langs->trans("or")." \"strict-origin-when-cross-origin\" so browser doesn't send any referrer when going into another web site domain)</span><br>";
 print '<br>';
 
 print '<strong>MAIN_SECURITY_FORCE_ACCESS_CONTROL_ALLOW_ORIGIN</strong> = '.getDolGlobalString('MAIN_SECURITY_FORCE_ACCESS_CONTROL_ALLOW_ORIGIN', '<span class="opacitymedium">'.$langs->trans("Undefined").'</span>').' &nbsp; <span class="opacitymedium">('.$langs->trans("Recommended").": 1)</span><br>";
@@ -746,20 +747,26 @@ print '<br>';
 // For websites
 
 print '<strong>WEBSITE_MAIN_SECURITY_FORCECSPRO</strong> = '.getDolGlobalString('WEBSITE_MAIN_SECURITY_FORCECSPRO', '<span class="opacitymedium">'.$langs->trans("Undefined").'</span>');
-print ' &nbsp; <span class="opacitymedium">('.$langs->trans("Example").": \"frame-ancestors 'self'; default-src 'self' 'unsafe-inline'; style-src https://cdnjs.cloudflare.com *.googleapis.com; script-src *.transifex.com *.google-analytics.com *.googletagmanager.com; object-src https://youtube.com; frame-src https://youtube.com; img-src * data:;\")</span><br>";
+print ' &nbsp; <span class="opacitymedium">('.$langs->trans("Example").': "';
+$examplecsprule = "default-src 'self' 'unsafe-inline' matomo.".getDomainFromURL($_SERVER["SERVER_NAME"], 1)." *.transifex.net *.transifex.com *.cloudflare.com *.cloudflareinsights.com *.google-analytics.com *.googletagmanager.com *.google.com *.gstatic.com *.googleapis.com *.googleadservices.com *.ads-twitter.com *.doubleclick.net; frame-ancestors 'self'; object-src https://youtube.com; frame-src 'self' https://youtube.com; img-src * data:;";
+print $examplecsprule;
+print '")</span><br>';
 print '<br>';
 
 print '<strong>WEBSITE_MAIN_SECURITY_FORCECSP</strong> = '.getDolGlobalString('WEBSITE_MAIN_SECURITY_FORCECSP', '<span class="opacitymedium">'.$langs->trans("Undefined").'</span>');
-print ' &nbsp; <span class="opacitymedium">('.$langs->trans("Example").": \"frame-ancestors 'self'; default-src 'self' 'unsafe-inline'; style-src https://cdnjs.cloudflare.com *.googleapis.com; script-src *.transifex.com *.google-analytics.com *.googletagmanager.com; object-src https://youtube.com; frame-src https://youtube.com; img-src * data:;\")</span><br>";
+print ' &nbsp; <span class="opacitymedium">('.$langs->trans("Example").': "';
+$examplecsprule = "default-src 'self' 'unsafe-inline' matomo.".getDomainFromURL($_SERVER["SERVER_NAME"], 1)." *.transifex.net *.transifex.com *.cloudflare.com *.cloudflareinsights.com *.google-analytics.com *.googletagmanager.com *.google.com *.gstatic.com *.googleapis.com *.googleadservices.com *.ads-twitter.com *.doubleclick.net; frame-ancestors 'self'; object-src https://youtube.com; frame-src 'self' https://youtube.com; img-src * data:;";
+print $examplecsprule;
+print '")</span><br>';
 print '<br>';
 
-print '<strong>WEBSITE_MAIN_SECURITY_FORCERP</strong> = '.getDolGlobalString('WEBSITE_MAIN_SECURITY_FORCERP', '<span class="opacitymedium">'.$langs->trans("Undefined").'</span>').' &nbsp; <span class="opacitymedium">('.$langs->trans("Recommended").': '.$langs->trans("Undefined")."=\"strict-origin\" ".$langs->trans("or")." \"strict-origin-when-cross-origin\")</span><br>";
+print '<strong>WEBSITE_MAIN_SECURITY_FORCERP</strong> = '.getDolGlobalString('WEBSITE_MAIN_SECURITY_FORCERP', '<span class="opacitymedium">'.$langs->trans("Undefined").'</span>').' &nbsp; <span class="opacitymedium">('.$langs->trans("Recommended").': '.$langs->trans("Undefined").'="strict-origin-when-cross-origin" '.$langs->trans("or").' "same-origin"=more secured)</span><br>';
 print '<br>';
 
 print '<strong>WEBSITE_MAIN_SECURITY_FORCESTS</strong> = '.getDolGlobalString('WEBSITE_MAIN_SECURITY_FORCESTS', '<span class="opacitymedium">'.$langs->trans("Undefined").'</span>').' &nbsp; <span class="opacitymedium">('.$langs->trans("Example").": \"max-age=31536000; includeSubDomains\")</span><br>";
 print '<br>';
 
-print '<strong>WEBSITE_MAIN_SECURITY_FORCEPP</strong> = '.getDolGlobalString('WEBSITE_MAIN_SECURITY_FORCEPP', '<span class="opacitymedium">'.$langs->trans("Undefined").'</span>').' &nbsp; <span class="opacitymedium">('.$langs->trans("Example").": \"camera: (); microphone: ();\")</span><br>";
+print '<strong>WEBSITE_MAIN_SECURITY_FORCEPP</strong> = '.getDolGlobalString('WEBSITE_MAIN_SECURITY_FORCEPP', '<span class="opacitymedium">'.$langs->trans("Undefined").'</span>').' &nbsp; <span class="opacitymedium">('.$langs->trans("Example").": \"camera=(), microphone=(), geolocation=*\")</span><br>";
 print '<br>';
 
 

+ 4 - 2
htdocs/api/class/api_documents.class.php

@@ -596,8 +596,10 @@ class Documents extends DolibarrApi
 				} elseif (is_array($ecmfile->lines) && count($ecmfile->lines) > 0) {
 					$count = count($filearray);
 					for ($i = 0 ; $i < $count ; $i++) {
-						if ($filearray[$i]['name'] == $ecmfile->lines[$i]->filename) {
-							$filearray[$i] = array_merge($filearray[$i], (array) $ecmfile->lines[0]);
+						foreach ($ecmfile->lines as $line) {
+							if ($filearray[$i]['name'] == $line->filename) {
+								$filearray[$i] = array_merge($filearray[$i], (array) $line);
+							}
 						}
 					}
 				}

+ 1 - 1
htdocs/asset/class/asset.class.php

@@ -874,7 +874,7 @@ class Asset extends CommonObject
 			// Get fiscal period
 			require_once DOL_DOCUMENT_ROOT . '/core/lib/date.lib.php';
 			require_once DOL_DOCUMENT_ROOT . '/core/lib/accounting.lib.php';
-			$dates = getDefaultDatesForTransfer();
+			$dates = getCurrentPeriodOfFiscalYear($this->db, $conf, $this->date_start > $this->date_acquisition ? $this->date_start : $this->date_acquisition);
 			$init_fiscal_period_start = $dates['date_start'];
 			$init_fiscal_period_end = $dates['date_end'];
 			if (empty($init_fiscal_period_start) || empty($init_fiscal_period_end)) {

+ 1 - 1
htdocs/asset/list.php

@@ -382,7 +382,7 @@ if ($optioncss != '') {
 // Add $param from extra fields
 include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_list_search_param.tpl.php';
 // Add $param from hooks
-$parameters = array();
+$parameters = array('param' => &$param);
 $reshook = $hookmanager->executeHooks('printFieldListSearchParam', $parameters, $object); // Note that $action and $object may have been modified by hook
 $param .= $hookmanager->resPrint;
 

+ 1 - 1
htdocs/asset/model/list.php

@@ -385,7 +385,7 @@ if ($optioncss != '') {
 // Add $param from extra fields
 include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_list_search_param.tpl.php';
 // Add $param from hooks
-$parameters = array();
+$parameters = array('param' => &$param);
 $reshook = $hookmanager->executeHooks('printFieldListSearchParam', $parameters, $object); // Note that $action and $object may have been modified by hook
 $param .= $hookmanager->resPrint;
 

+ 1 - 2
htdocs/asterisk/wrapper.php

@@ -18,8 +18,7 @@
 /**
  *	\file       htdocs/asterisk/wrapper.php
  *  \brief      File that is entry point to call an Asterisk server
- *	\remarks	To be used, an Asterisk user must be created by adding this
- * 				in /etc/asterisk/manager.conf
+ *	\remarks	To be used, an Asterisk user must be created by adding this in /etc/asterisk/manager.conf
  * 				[dolibarr]
  * 				secret = dolibarr
  * 				deny=0.0.0.0/0.0.0.0

+ 10 - 2
htdocs/barcode/printsheet.php

@@ -256,10 +256,18 @@ if ($action == 'builddoc') {
 
 			if (!$mesg) {
 				$outputlangs = $langs;
+				$previousConf = getDolGlobalInt('TCPDF_THROW_ERRORS_INSTEAD_OF_DIE');
+				$conf->global->TCPDF_THROW_ERRORS_INSTEAD_OF_DIE = 1;
+
 
 				// This generates and send PDF to output
 				// TODO Move
-				$result = doc_label_pdf_create($db, $arrayofrecords, $modellabel, $outputlangs, $diroutput, $template, dol_sanitizeFileName($outfile));
+				try {
+					$result = doc_label_pdf_create($db, $arrayofrecords, $modellabel, $outputlangs, $diroutput, $template, dol_sanitizeFileName($outfile));
+				} catch (Exception $e) {
+					$mesg = $langs->trans('ErrorGeneratingBarcode');
+				}
+				$conf->global->TCPDF_THROW_ERRORS_INSTEAD_OF_DIE = $previousConf;
 			}
 		}
 
@@ -314,7 +322,7 @@ foreach (array_keys($_Avery_Labels) as $codecards) {
 	$arrayoflabels[$codecards] = $labeltoshow;
 }
 asort($arrayoflabels);
-print $form->selectarray('modellabel', $arrayoflabels, (GETPOST('modellabel') ? GETPOST('modellabel') : $conf->global->ADHERENT_ETIQUETTE_TYPE), 1, 0, 0, '', 0, 0, 0, '', '', 1);
+print $form->selectarray('modellabel', $arrayoflabels, (GETPOST('modellabel') ? GETPOST('modellabel') : getDolGlobalString('ADHERENT_ETIQUETTE_TYPE')), 1, 0, 0, '', 0, 0, 0, '', '', 1);
 print '</div></div>';
 
 // Number of stickers to print

+ 22 - 1
htdocs/bom/ajax/ajax.php

@@ -53,7 +53,7 @@ $idproduct = GETPOST('idproduct', 'int');
  * View
  */
 
-top_httphead();
+top_httphead('application/json');
 
 if ($action == 'getDurationUnitByProduct' && $user->hasRight('product', 'lire')) {
 	$product = new Product($db);
@@ -65,3 +65,24 @@ if ($action == 'getDurationUnitByProduct' && $user->hasRight('product', 'lire'))
 	echo json_encode($fk_unit);
 	exit();
 }
+
+if ($action == 'getWorkstationByProduct' && $user->hasRight('product', 'lire')) {
+	$product = new Product($db);
+	$res = $product->fetch($idproduct);
+
+	$result = array();
+
+	if ($res < 0) {
+		$error = 'SQL ERROR';
+	} elseif ($res == 0) {
+		$error = 'NOT FOUND';
+	} else {
+		$error = null;
+		$result['defaultWk']=$product->fk_default_workstation;
+	}
+
+	$result['error']=$error;
+
+	echo json_encode($result);
+	exit();
+}

+ 3 - 1
htdocs/bom/bom_card.php

@@ -169,6 +169,7 @@ if (empty($reshook)) {
 		$qty = price2num(GETPOST('qty', 'alpha'), 'MS');
 		$qty_frozen = price2num(GETPOST('qty_frozen', 'alpha'), 'MS');
 		$disable_stock_change = GETPOST('disable_stock_change', 'int');
+		$fk_workstation = GETPOST('idworkstations', 'int');
 		$efficiency = price2num(GETPOST('efficiency', 'alpha'));
 		$fk_unit = GETPOST('fk_unit', 'alphanohtml');
 
@@ -177,7 +178,8 @@ if (empty($reshook)) {
 			$product = new Product($db);
 			$res = $product->fetch($idprod);
 			if ($res > 0 && $product->type == Product::TYPE_SERVICE) {
-				$fk_default_workstation = $product->fk_default_workstation;
+				if (!empty($fk_workstation)) $fk_default_workstation = $fk_workstation;
+				else $fk_default_workstation = $product->fk_default_workstation;
 			}
 			if (empty($fk_unit)) {
 				$fk_unit = $product->fk_unit;

+ 1 - 1
htdocs/bom/bom_list.php

@@ -467,7 +467,7 @@ foreach ($search as $key => $val) {
 // Add $param from extra fields
 include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_list_search_param.tpl.php';
 // Add $param from hooks
-$parameters = array();
+$parameters = array('param' => &$param);
 $reshook = $hookmanager->executeHooks('printFieldListSearchParam', $parameters, $object, $action); // Note that $action and $object may have been modified by hook
 $param .= $hookmanager->resPrint;
 

+ 1 - 1
htdocs/bom/class/bom.class.php

@@ -792,7 +792,7 @@ class BOM extends CommonObject
 					$line->array_options[$key] = $array_options[$key];
 				}
 			}
-			if ($fk_default_workstation > 0 && $line->fk_default_workstation != $fk_default_workstation) {
+			if ($line->fk_default_workstation != $fk_default_workstation) {
 				$line->fk_default_workstation = $fk_default_workstation;
 			}
 

+ 15 - 2
htdocs/bom/tpl/objectline_create.tpl.php

@@ -185,7 +185,7 @@ if ($filtertype != 1) {
 
 	$coldisplay++;
 	print '<td class="bordertop nobottom nowrap linecolworkstation right">';
-	print '&nbsp;';
+	print $formproduct->selectWorkstations('', 'idworkstations', 1);
 	print '</td>';
 
 	$coldisplay++;
@@ -235,14 +235,27 @@ jQuery(document).ready(function() {
 				,type: 'POST'
 				,data: {
 					'action': 'getDurationUnitByProduct'
+					,'token' : "<?php echo newToken() ?>"
 					,'idproduct' : idproduct
 				}
 			}).done(function(data) {
 
 				console.log(data);
-				var data = JSON.parse(data);
 				$("#fk_unit").val(data).change();
 			});
+
+			$.ajax({
+				url : "<?php echo dol_buildpath('/bom/ajax/ajax.php', 1); ?>"
+				,type: 'POST'
+				,data: {
+					'action': 'getWorkstationByProduct'
+					,'token' :  "<?php echo newToken() ?>"
+					,'idproduct' : idproduct
+				}
+			}).done(function(data) {
+				$('#idworkstations').val(data.defaultWk).select2();
+
+			});
 	});
 	<?php } ?>
 });

+ 1 - 1
htdocs/bookcal/availabilities_list.php

@@ -426,7 +426,7 @@ foreach ($search as $key => $val) {
 // Add $param from extra fields
 include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_list_search_param.tpl.php';
 // Add $param from hooks
-$parameters = array();
+$parameters = array('param' => &$param);
 $reshook = $hookmanager->executeHooks('printFieldListSearchParam', $parameters, $object, $action); // Note that $action and $object may have been modified by hook
 $param .= $hookmanager->resPrint;
 

+ 1 - 1
htdocs/bookcal/calendar_list.php

@@ -446,7 +446,7 @@ foreach ($search as $key => $val) {
 // Add $param from extra fields
 include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_list_search_param.tpl.php';
 // Add $param from hooks
-$parameters = array();
+$parameters = array('param' => &$param);
 $reshook = $hookmanager->executeHooks('printFieldListSearchParam', $parameters, $object, $action); // Note that $action and $object may have been modified by hook
 $param .= $hookmanager->resPrint;
 

+ 3 - 1
htdocs/bookmarks/card.php

@@ -228,6 +228,7 @@ if ($id > 0 && !preg_match('/^add/i', $action)) {
 	print '<div class="underbanner clearboth"></div>';
 	print '<table class="border centpercent tableforfield">';
 
+	// Title
 	print '<tr><td class="titlefield">';
 	if ($action == 'edit') {
 		print '<span class="fieldrequired">';
@@ -247,6 +248,7 @@ if ($id > 0 && !preg_match('/^add/i', $action)) {
 	}
 	print '</td></tr>';
 
+	// URL
 	print '<tr><td>';
 	if ($action == 'edit') {
 		print '<span class="fieldrequired">';
@@ -255,7 +257,7 @@ if ($id > 0 && !preg_match('/^add/i', $action)) {
 	if ($action == 'edit') {
 		print '</span>';
 	}
-	print '</td><td>';
+	print '</td><td class="tdoverflowmax500">';
 	if ($action == 'edit') {
 		print '<input class="flat minwidth500 quatrevingtpercent" name="url" value="'.(GETPOSTISSET("url") ? GETPOST("url") : $object->url).'">';
 	} else {

+ 1 - 1
htdocs/bookmarks/list.php

@@ -233,7 +233,7 @@ if ($optioncss != '') {
 // Add $param from extra fields
 include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_list_search_param.tpl.php';
 // Add $param from hooks
-$parameters = array();
+$parameters = array('param' => &$param);
 $reshook = $hookmanager->executeHooks('printFieldListSearchParam', $parameters, $object); // Note that $action and $object may have been modified by hook
 $param .= $hookmanager->resPrint;
 

+ 5 - 2
htdocs/categories/class/categorie.class.php

@@ -11,7 +11,7 @@
  * Copyright (C) 2015       Raphaël Doursenaud      <rdoursenaud@gpcsolutions.fr>
  * Copyright (C) 2016       Charlie Benke           <charlie@patas-monkey.com>
  * Copyright (C) 2018-2023  Frédéric France         <frederic.france@netlogic.fr>
- * Copyright (C) 2023		Benjamin Falière		<benjamin.faliere@altairis.fr>
+ * Copyright (C) 2023-2024	Benjamin Falière		<benjamin.faliere@altairis.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
@@ -1159,6 +1159,7 @@ class Categorie extends CommonObject
 		}
 
 		$this->cats = array();
+		$nbcateg = 0;
 
 		// Init this->motherof that is array(id_son=>id_parent, ...)
 		$this->load_motherof();
@@ -1180,6 +1181,8 @@ class Categorie extends CommonObject
 		$resql = $this->db->query($sql);
 		if ($resql) {
 			$i = 0;
+			$nbcateg = $this->db->num_rows($resql);
+
 			while ($obj = $this->db->fetch_object($resql)) {
 				$this->cats[$obj->rowid]['rowid'] = $obj->rowid;
 				$this->cats[$obj->rowid]['id'] = $obj->rowid;
@@ -1201,7 +1204,7 @@ class Categorie extends CommonObject
 		dol_syslog(get_class($this)."::get_full_arbo call to buildPathFromId", LOG_DEBUG);
 		foreach ($this->cats as $key => $val) {
 			//print 'key='.$key.'<br>'."\n";
-			$this->buildPathFromId($key, 0); // Process a branch from the root category key (this category has no parent)
+			$this->buildPathFromId($key, $nbcateg); // Process a branch from the root category key (this category has no parent)
 		}
 
 		// Include or exclude leaf including $markafterid from tree

+ 11 - 7
htdocs/comm/action/card.php

@@ -361,7 +361,8 @@ if (empty($reshook) && $action == 'add') {
 		$object->label = GETPOST('label', 'alphanohtml');
 
 		if (GETPOST("elementtype", 'alpha')) {
-			$modulecodetouseforpermissioncheck = GETPOST("elementtype", 'alpha');
+			$elProp = getElementProperties(GETPOST("elementtype", 'alpha'));
+			$modulecodetouseforpermissioncheck = $elProp['module'];
 
 			$hasPermissionOnLinkedObject = 0;
 			if ($user->hasRight($modulecodetouseforpermissioncheck, 'read')) {
@@ -771,11 +772,11 @@ if (empty($reshook) && $action == 'update') {
 		if ($fulldayevent) {
 			$tzforfullday = getDolGlobalString('MAIN_STORE_FULL_EVENT_IN_GMT');
 			// For "full day" events, we must store date in GMT (It must be viewed as same moment everywhere)
-			$datep = dol_mktime($fulldayevent ? '00' : GETPOST("aphour", 'int'), $fulldayevent ? '00' : GETPOST("apmin", 'int'), $fulldayevent ? '00' : GETPOST("apsec", 'int'), GETPOST("apmonth", 'int'), GETPOST("apday", 'int'), GETPOST("apyear", 'int'), $tzforfullday ? $tzforfullday : 'tzuserrel');
-			$datef = dol_mktime($fulldayevent ? '23' : GETPOST("p2hour", 'int'), $fulldayevent ? '59' : GETPOST("p2min", 'int'), $fulldayevent ? '59' : GETPOST("apsec", 'int'), GETPOST("p2month", 'int'), GETPOST("p2day", 'int'), GETPOST("p2year", 'int'), $tzforfullday ? $tzforfullday : 'tzuserrel');
+			$datep = dol_mktime('00', '00', '00', GETPOST("apmonth", 'int'), GETPOST("apday", 'int'), GETPOST("apyear", 'int'), $tzforfullday ? $tzforfullday : 'tzuserrel');
+			$datef = dol_mktime('23', '59', '59', GETPOST("p2month", 'int'), GETPOST("p2day", 'int'), GETPOST("p2year", 'int'), $tzforfullday ? $tzforfullday : 'tzuserrel');
 		} else {
-			$datep = dol_mktime($fulldayevent ? '00' : GETPOST("aphour", 'int'), $fulldayevent ? '00' : GETPOST("apmin", 'int'), $fulldayevent ? '00' : GETPOST("apsec", 'int'), GETPOST("apmonth", 'int'), GETPOST("apday", 'int'), GETPOST("apyear", 'int'), 'tzuserrel');
-			$datef = dol_mktime($fulldayevent ? '23' : GETPOST("p2hour", 'int'), $fulldayevent ? '59' : GETPOST("p2min", 'int'), $fulldayevent ? '59' : GETPOST("apsec", 'int'), GETPOST("p2month", 'int'), GETPOST("p2day", 'int'), GETPOST("p2year", 'int'), 'tzuserrel');
+			$datep = dol_mktime(GETPOST("aphour", 'int'), GETPOST("apmin", 'int'), GETPOST("apsec", 'int'), GETPOST("apmonth", 'int'), GETPOST("apday", 'int'), GETPOST("apyear", 'int'), 'tzuserrel');
+			$datef = dol_mktime(GETPOST("p2hour", 'int'), GETPOST("p2min", 'int'), GETPOST("apsec", 'int'), GETPOST("p2month", 'int'), GETPOST("p2day", 'int'), GETPOST("p2year", 'int'), 'tzuserrel');
 		}
 
 		if ($object->elementtype == 'ticket') {	// code should be TICKET_MSG, TICKET_MSG_PRIVATE, TICKET_MSG_SENTBYMAIL, TICKET_MSG_PRIVATE_SENTBYMAIL
@@ -822,7 +823,8 @@ if (empty($reshook) && $action == 'update') {
 		$object->note_private = trim(GETPOST("note", "restricthtml"));
 
 		if (GETPOST("elementtype", 'alpha')) {
-			$modulecodetouseforpermissioncheck = GETPOST("elementtype", 'alpha');
+			$elProp = getElementProperties(GETPOST("elementtype", 'alpha'));
+			$modulecodetouseforpermissioncheck = $elProp['module'];
 
 			$hasPermissionOnLinkedObject = 0;
 			if ($user->hasRight($modulecodetouseforpermissioncheck, 'read')) {
@@ -1606,7 +1608,9 @@ if ($action == 'create') {
 		include_once DOL_DOCUMENT_ROOT.'/core/lib/functions2.lib.php';
 
 		$hasPermissionOnLinkedObject = 0;
-		if ($user->hasRight($origin, 'read')) {
+
+		$elProp = getElementProperties($origin);
+		if ($user->hasRight($elProp['module'], 'read') || $user->hasRight($elProp['module'], $elProp['element'], 'read')) {
 			$hasPermissionOnLinkedObject = 1;
 		}
 		//var_dump('origin='.$origin.' originid='.$originid.' hasPermissionOnLinkedObject='.$hasPermissionOnLinkedObject);

+ 3 - 3
htdocs/comm/action/list.php

@@ -267,7 +267,7 @@ if (empty($reshook)) {
 	$objectlabel = 'Events';
 	$uploaddir = true;
 	// Only users that can delete any event can remove records.
-	$permissiontodelete = $user->rights->agenda->allactions->delete;
+	$permissiontodelete = $user->hasRight('agenda', 'allactions', 'delete');
 	$permissiontoadd = $user->hasRight('agenda', 'myactions', 'create');
 	include DOL_DOCUMENT_ROOT.'/core/actions_massactions.inc.php';
 }
@@ -341,7 +341,7 @@ if ($type) {
 	$param .= "&search_type=".urlencode($type);
 }
 if ($search_id != '') {
-	$param .= '&search_title='.urlencode($search_id);
+	$param .= '&search_id='.urlencode($search_id);
 }
 if ($search_title != '') {
 	$param .= '&search_title='.urlencode($search_title);
@@ -708,7 +708,7 @@ $url = DOL_URL_ROOT.'/comm/action/card.php?action=create';
 $url .= '&datep='.sprintf("%04d%02d%02d", $tmpforcreatebutton['year'], $tmpforcreatebutton['mon'], $tmpforcreatebutton['mday']).$hourminsec;
 $url .= '&backtopage='.urlencode($_SERVER["PHP_SELF"].($newparam ? '?'.$newparam : ''));
 
-$newcardbutton = dolGetButtonTitle($langs->trans('AddAction'), '', 'fa fa-plus-circle', $url, '', $user->rights->agenda->myactions->create || $user->hasRight('agenda', 'allactions', 'create'));
+$newcardbutton = dolGetButtonTitle($langs->trans('AddAction'), '', 'fa fa-plus-circle', $url, '', $user->hasRight('agenda', 'myactions', 'create') || $user->hasRight('agenda', 'allactions', 'create'));
 
 $param .= '&mode='.$mode;
 

+ 1 - 0
htdocs/comm/card.php

@@ -36,6 +36,7 @@
 require '../main.inc.php';
 require_once DOL_DOCUMENT_ROOT.'/core/lib/company.lib.php';
 require_once DOL_DOCUMENT_ROOT.'/core/lib/date.lib.php';
+require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
 require_once DOL_DOCUMENT_ROOT.'/societe/class/client.class.php';
 require_once DOL_DOCUMENT_ROOT.'/contact/class/contact.class.php';
 require_once DOL_DOCUMENT_ROOT.'/core/class/html.formcompany.class.php';

+ 1 - 1
htdocs/comm/mailing/list.php

@@ -282,7 +282,7 @@ if ($filteremail) {
 // Add $param from extra fields
 include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_list_search_param.tpl.php';
 // Add $param from hooks
-$parameters = array();
+$parameters = array('param' => &$param);
 $reshook = $hookmanager->executeHooks('printFieldListSearchParam', $parameters, $object); // Note that $action and $object may have been modified by hook
 $param .= $hookmanager->resPrint;
 

+ 13 - 9
htdocs/comm/propal/card.php

@@ -2882,19 +2882,23 @@ if ($action == 'create') {
 			print '<td class="titlefieldmiddle">' . $langs->transcountry("AmountLT1", $mysoc->country_code) . '</td>';
 			print '<td class="nowrap amountcard right">' . price($object->total_localtax1, '', $langs, 1, -1, -1, $conf->currency) . '</td>';
 			if (isModEnabled("multicurrency") && ($object->multicurrency_code && $object->multicurrency_code != $conf->currency)) {
-				print '<td class="nowrap amountcard right">' . price($object->total_localtax1, '', $langs, 1, -1, -1, $object->multicurrency_code) . '</td>';
+				$object->multicurrency_total_localtax1 = price2num($object->total_localtax1 * $object->multicurrency_tx, 'MT');
+
+				print '<td class="nowrap amountcard right">' . price($object->multicurrency_total_localtax1, '', $langs, 1, -1, -1, $object->multicurrency_code) . '</td>';
 			}
 			print '</tr>';
+		}
 
-			if ($mysoc->localtax2_assuj == "1" || $object->total_localtax2 != 0) {
-				print '<tr>';
-				print '<td>' . $langs->transcountry("AmountLT2", $mysoc->country_code) . '</td>';
-				print '<td class="nowrap amountcard right">' . price($object->total_localtax2, '', $langs, 1, -1, -1, $conf->currency) . '</td>';
-				if (isModEnabled("multicurrency") && ($object->multicurrency_code && $object->multicurrency_code != $conf->currency)) {
-					print '<td class="nowrap amountcard right">' . price($object->total_localtax2, '', $langs, 1, -1, -1, $object->multicurrency_code) . '</td>';
-				}
-				print '</tr>';
+		if ($mysoc->localtax2_assuj == "1" || $object->total_localtax2 != 0) {
+			print '<tr>';
+			print '<td>' . $langs->transcountry("AmountLT2", $mysoc->country_code) . '</td>';
+			print '<td class="nowrap amountcard right">' . price($object->total_localtax2, '', $langs, 1, -1, -1, $conf->currency) . '</td>';
+			if (isModEnabled("multicurrency") && ($object->multicurrency_code && $object->multicurrency_code != $conf->currency)) {
+				$object->multicurrency_total_localtax2 = price2num($object->total_localtax2 * $object->multicurrency_tx, 'MT');
+
+				print '<td class="nowrap amountcard right">' . price($object->multicurrency_total_localtax2, '', $langs, 1, -1, -1, $object->multicurrency_code) . '</td>';
 			}
+			print '</tr>';
 		}
 
 		print '<tr>';

+ 1 - 1
htdocs/comm/propal/class/api_proposals.class.php

@@ -283,7 +283,7 @@ class Proposals extends DolibarrApi
 			throw new RestException(500, "Error creating order", array_merge(array($this->propal->error), $this->propal->errors));
 		}
 
-		return $this->propal->id;
+		return ((int) $this->propal->id);
 	}
 
 	/**

+ 7 - 14
htdocs/comm/propal/class/propal.class.php

@@ -279,18 +279,6 @@ class Propal extends CommonObject
 	public $labelStatus = array();
 	public $labelStatusShort = 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;
-
 
 	/**
 	 *  'type' if the field format ('integer', 'integer:ObjectClass:PathToClass[:AddCreateButtonOrNot[:Filter]]', 'varchar(x)', 'double(24,8)', 'real', 'price', 'text', 'html', 'date', 'datetime', 'timestamp', 'duration', 'mail', 'phone', 'url', 'password')
@@ -1422,7 +1410,9 @@ class Propal extends CommonObject
 			}
 
 			// reset ref_client
-			$object->ref_client = '';
+			if (!getDolGlobalString('MAIN_KEEP_REF_CUSTOMER_ON_CLONING')) {
+				$object->ref_client = '';
+			}
 
 			// TODO Change product price if multi-prices
 		} else {
@@ -2701,7 +2691,10 @@ class Propal extends CommonObject
 		}
 
 		$sql  = "UPDATE ".MAIN_DB_PREFIX."propal";
-		$sql .= " SET fk_statut = ".((int) $status).", note_private = '".$this->db->escape($newprivatenote)."', date_signature='".$this->db->idate($date_signature)."', fk_user_signature=".$fk_user_signature;
+		$sql .= " SET fk_statut = ".((int) $status).", note_private = '".$this->db->escape($newprivatenote)."'";
+		if ($status == self::STATUS_SIGNED) {
+			$sql .= ", date_signature='".$this->db->idate($now)."', fk_user_signature = ".($fk_user_signature);
+		}
 		$sql .= " WHERE rowid = ".((int) $this->id);
 
 		$resql = $this->db->query($sql);

+ 1280 - 1279
htdocs/comm/propal/list.php

@@ -1085,1390 +1085,1391 @@ if ($search_date_signature_endyear) {
 	$param .= '&search_date_signature_endyear='.urlencode($search_date_signature_endyear);
 }
 
-	// Add $param from extra fields
-	include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_list_search_param.tpl.php';
-	// Add $param from hooks
-	$parameters = array();
-	$reshook = $hookmanager->executeHooks('printFieldListSearchParam', $parameters, $object, $action); // Note that $action and $object may have been modified by hook
-	$param .= $hookmanager->resPrint;
-
-	// List of mass actions available
-	$arrayofmassactions = array(
-		'generate_doc'=>img_picto('', 'pdf', 'class="pictofixedwidth"').$langs->trans("ReGeneratePDF"),
-		'builddoc'=>img_picto('', 'pdf', 'class="pictofixedwidth"').$langs->trans("PDFMerge"),
-	);
-	if ($permissiontosendbymail) {
-		$arrayofmassactions['presend']=img_picto('', 'email', 'class="pictofixedwidth"').$langs->trans("SendByMail");
-	}
-	if ($permissiontovalidate) {
-		$arrayofmassactions['prevalidate']=img_picto('', 'check', 'class="pictofixedwidth"').$langs->trans("Validate");
-	}
-	if ($permissiontoclose) {
-		$arrayofmassactions['presign']=img_picto('', 'propal', 'class="pictofixedwidth"').$langs->trans("Sign");
-		$arrayofmassactions['nopresign']=img_picto('', 'propal', 'class="pictofixedwidth"').$langs->trans("NoSign");
-		$arrayofmassactions['setbilled'] =img_picto('', 'bill', 'class="pictofixedwidth"').$langs->trans("ClassifyBilled");
-	}
-	if ($permissiontodelete) {
-		$arrayofmassactions['predelete'] = img_picto('', 'delete', 'class="pictofixedwidth"').$langs->trans("Delete");
-	}
+// Add $param from extra fields
+include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_list_search_param.tpl.php';
+// Add $param from hooks
+$parameters = array('param' => &$param);
+$reshook = $hookmanager->executeHooks('printFieldListSearchParam', $parameters, $object, $action); // Note that $action and $object may have been modified by hook
+$param .= $hookmanager->resPrint;
+
+// List of mass actions available
+$arrayofmassactions = array(
+	'generate_doc'=>img_picto('', 'pdf', 'class="pictofixedwidth"').$langs->trans("ReGeneratePDF"),
+	'builddoc'=>img_picto('', 'pdf', 'class="pictofixedwidth"').$langs->trans("PDFMerge"),
+);
+if ($permissiontosendbymail) {
+	$arrayofmassactions['presend']=img_picto('', 'email', 'class="pictofixedwidth"').$langs->trans("SendByMail");
+}
+if ($permissiontovalidate) {
+	$arrayofmassactions['prevalidate']=img_picto('', 'check', 'class="pictofixedwidth"').$langs->trans("Validate");
+}
+if ($permissiontoclose) {
+	$arrayofmassactions['presign']=img_picto('', 'propal', 'class="pictofixedwidth"').$langs->trans("Sign");
+	$arrayofmassactions['nopresign']=img_picto('', 'propal', 'class="pictofixedwidth"').$langs->trans("NoSign");
+	$arrayofmassactions['setbilled'] =img_picto('', 'bill', 'class="pictofixedwidth"').$langs->trans("ClassifyBilled");
+}
+if ($permissiontodelete) {
+	$arrayofmassactions['predelete'] = img_picto('', 'delete', 'class="pictofixedwidth"').$langs->trans("Delete");
+}
 
-	if (in_array($massaction, array('presend', 'predelete', 'closed'))) {
-		$arrayofmassactions = array();
-	}
-	$massactionbutton = $form->selectMassAction('', $arrayofmassactions);
+if (in_array($massaction, array('presend', 'predelete', 'closed'))) {
+	$arrayofmassactions = array();
+}
+$massactionbutton = $form->selectMassAction('', $arrayofmassactions);
 
-	$url = DOL_URL_ROOT.'/comm/propal/card.php?action=create';
-	if (!empty($socid)) {
-		$url .= '&socid='.$socid;
-	}
-	$newcardbutton = '';
-	$newcardbutton .= dolGetButtonTitle($langs->trans('ViewList'), '', 'fa fa-bars imgforviewmode', $_SERVER["PHP_SELF"].'?mode=common'.preg_replace('/(&|\?)*mode=[^&]+/', '', $param), '', ((empty($mode) || $mode == 'common') ? 2 : 1), array('morecss'=>'reposition'));
-	$newcardbutton .= dolGetButtonTitle($langs->trans('ViewKanban'), '', 'fa fa-th-list imgforviewmode', $_SERVER["PHP_SELF"].'?mode=kanban'.preg_replace('/(&|\?)*mode=[^&]+/', '', $param), '', ($mode == 'kanban' ? 2 : 1), array('morecss'=>'reposition'));
-	$newcardbutton .= dolGetButtonTitleSeparator();
-	$newcardbutton .= dolGetButtonTitle($langs->trans('NewPropal'), '', 'fa fa-plus-circle', $url, '', $user->hasRight('propal', 'creer'));
-
-	// Fields title search
-	print '<form method="POST" id="searchFormList" action="'.$_SERVER["PHP_SELF"].'">';
-	if ($optioncss != '') {
-		print '<input type="hidden" name="optioncss" value="'.$optioncss.'">';
-	}
-	print '<input type="hidden" name="token" value="'.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="contextpage" value="'.$contextpage.'">';
-	print '<input type="hidden" name="mode"value="'.$mode.'">';
-
-	print_barre_liste($title, $page, $_SERVER["PHP_SELF"], $param, $sortfield, $sortorder, $massactionbutton, $num, $nbtotalofrecords, 'propal', 0, $newcardbutton, '', $limit, 0, 0, 1);
-
-	$topicmail = "SendPropalRef";
-	$modelmail = "propal_send";
-	$objecttmp = new Propal($db);
-	$trackid = 'pro'.$object->id;
-	include DOL_DOCUMENT_ROOT.'/core/tpl/massactions_pre.tpl.php';
-
-	if ($massaction == 'prevalidate') {
-		print $form->formconfirm($_SERVER["PHP_SELF"], $langs->trans("ConfirmMassValidation"), $langs->trans("ConfirmMassValidationQuestion"), "validate", null, '', 0, 200, 500, 1);
-	}
+$url = DOL_URL_ROOT.'/comm/propal/card.php?action=create';
+if (!empty($socid)) {
+	$url .= '&socid='.$socid;
+}
+$newcardbutton = '';
+$newcardbutton .= dolGetButtonTitle($langs->trans('ViewList'), '', 'fa fa-bars imgforviewmode', $_SERVER["PHP_SELF"].'?mode=common'.preg_replace('/(&|\?)*mode=[^&]+/', '', $param), '', ((empty($mode) || $mode == 'common') ? 2 : 1), array('morecss'=>'reposition'));
+$newcardbutton .= dolGetButtonTitle($langs->trans('ViewKanban'), '', 'fa fa-th-list imgforviewmode', $_SERVER["PHP_SELF"].'?mode=kanban'.preg_replace('/(&|\?)*mode=[^&]+/', '', $param), '', ($mode == 'kanban' ? 2 : 1), array('morecss'=>'reposition'));
+$newcardbutton .= dolGetButtonTitleSeparator();
+$newcardbutton .= dolGetButtonTitle($langs->trans('NewPropal'), '', 'fa fa-plus-circle', $url, '', $user->hasRight('propal', 'creer'));
 
-	if ($massaction == 'presign') {
-		print $form->formconfirm($_SERVER["PHP_SELF"], $langs->trans("ConfirmMassSignature"), $langs->trans("ConfirmMassSignatureQuestion"), "sign", null, '', 0, 200, 500, 1);
-	}
+// Fields title search
+print '<form method="POST" id="searchFormList" action="'.$_SERVER["PHP_SELF"].'">';
+if ($optioncss != '') {
+	print '<input type="hidden" name="optioncss" value="'.$optioncss.'">';
+}
+print '<input type="hidden" name="token" value="'.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="contextpage" value="'.$contextpage.'">';
+print '<input type="hidden" name="mode"value="'.$mode.'">';
 
-	if ($massaction == 'nopresign') {
-		print $form->formconfirm($_SERVER["PHP_SELF"], $langs->trans("ConfirmMassNoSignature"), $langs->trans("ConfirmMassNoSignatureQuestion"), "nosign", null, '', 0, 200, 500, 1);
-	}
+print_barre_liste($title, $page, $_SERVER["PHP_SELF"], $param, $sortfield, $sortorder, $massactionbutton, $num, $nbtotalofrecords, 'propal', 0, $newcardbutton, '', $limit, 0, 0, 1);
 
-	if ($search_all) {
-		foreach ($fieldstosearchall as $key => $val) {
-			$fieldstosearchall[$key] = $langs->trans($val);
-		}
-		print '<div class="divsearchfieldfilter">'.$langs->trans("FilterOnInto", $search_all).join(', ', $fieldstosearchall).'</div>';
-	}
+$topicmail = "SendPropalRef";
+$modelmail = "propal_send";
+$objecttmp = new Propal($db);
+$trackid = 'pro'.$object->id;
+include DOL_DOCUMENT_ROOT.'/core/tpl/massactions_pre.tpl.php';
 
-	$i = 0;
+if ($massaction == 'prevalidate') {
+	print $form->formconfirm($_SERVER["PHP_SELF"], $langs->trans("ConfirmMassValidation"), $langs->trans("ConfirmMassValidationQuestion"), "validate", null, '', 0, 200, 500, 1);
+}
 
-	$moreforfilter = '';
+if ($massaction == 'presign') {
+	print $form->formconfirm($_SERVER["PHP_SELF"], $langs->trans("ConfirmMassSignature"), $langs->trans("ConfirmMassSignatureQuestion"), "sign", null, '', 0, 200, 500, 1);
+}
 
-	// If the user can view prospects other than his'
-	if ($user->hasRight('user', 'user', 'lire')) {
-		$langs->load("commercial");
-		$moreforfilter .= '<div class="divsearchfield">';
-		$tmptitle = $langs->trans('ThirdPartiesOfSaleRepresentative');
-		$moreforfilter .= img_picto($tmptitle, 'user', 'class="pictofixedwidth"').$formother->select_salesrepresentatives($search_sale, 'search_sale', $user, 0, $tmptitle, 'maxwidth250 widthcentpercentminusx', 1);
-		$moreforfilter .= '</div>';
-	}
-	// If the user can view prospects other than his'
-	if ($user->hasRight('user', 'user', 'lire')) {
-		$moreforfilter .= '<div class="divsearchfield">';
-		$tmptitle = $langs->trans('LinkedToSpecificUsers');
-		$moreforfilter .= img_picto($tmptitle, 'user', 'class="pictofixedwidth"').$form->select_dolusers($search_user, 'search_user', $tmptitle, '', 0, '', '', 0, 0, 0, '', 0, '', 'maxwidth250 widthcentpercentminusx');
-		$moreforfilter .= '</div>';
-	}
-	// If the user can view products
-	if (isModEnabled('categorie') && $user->hasRight('categorie', 'read') && ($user->hasRight('product', 'read') || $user->hasRight('service', 'read'))) {
-		$searchCategoryProductOperator = -1;
-		include_once DOL_DOCUMENT_ROOT.'/categories/class/categorie.class.php';
-		$tmptitle = $langs->trans('IncludingProductWithTag');
-		$formcategory = new FormCategory($db);
-		$moreforfilter .= $formcategory->getFilterBox(Categorie::TYPE_PRODUCT, array($search_product_category), 'maxwidth300', $searchCategoryProductOperator, 0, 0, $tmptitle);
-	}
-	if (isModEnabled('categorie') && $user->hasRight('categorie', 'lire')) {
-		require_once DOL_DOCUMENT_ROOT.'/categories/class/categorie.class.php';
-		$moreforfilter .= '<div class="divsearchfield">';
-		$tmptitle = $langs->trans('CustomersProspectsCategoriesShort');
-		$moreforfilter .= img_picto($tmptitle, 'category', 'class="pictofixedwidth"').$formother->select_categories('customer', $search_categ_cus, 'search_categ_cus', 1, $tmptitle, (empty($conf->dol_optimize_smallscreen) ? 'maxwidth300 widthcentpercentminusx' : 'maxwidth250 widthcentpercentminusx'));
-		$moreforfilter .= '</div>';
-	}
-	if (isModEnabled('stock') && getDolGlobalString('WAREHOUSE_ASK_WAREHOUSE_DURING_PROPAL')) {
-		require_once DOL_DOCUMENT_ROOT.'/product/class/html.formproduct.class.php';
-		$formproduct = new FormProduct($db);
-		$moreforfilter .= '<div class="divsearchfield">';
-		$tmptitle = $langs->trans('Warehouse');
-		$moreforfilter .= img_picto($tmptitle, 'stock', 'class="pictofixedwidth"').$formproduct->selectWarehouses($search_warehouse, 'search_warehouse', '', $tmptitle, 0, 0, $tmptitle);
-		$moreforfilter .= '</div>';
-	}
-	$parameters = array();
-	$reshook = $hookmanager->executeHooks('printFieldPreListTitle', $parameters, $object, $action); // Note that $action and $object may have been modified by hook
-	if (empty($reshook)) {
-		$moreforfilter .= $hookmanager->resPrint;
-	} else {
-		$moreforfilter = $hookmanager->resPrint;
-	}
+if ($massaction == 'nopresign') {
+	print $form->formconfirm($_SERVER["PHP_SELF"], $langs->trans("ConfirmMassNoSignature"), $langs->trans("ConfirmMassNoSignatureQuestion"), "nosign", null, '', 0, 200, 500, 1);
+}
 
-	if (!empty($moreforfilter)) {
-		print '<div class="liste_titre liste_titre_bydiv centpercent">';
-		print $moreforfilter;
-		print '</div>';
+if ($search_all) {
+	foreach ($fieldstosearchall as $key => $val) {
+		$fieldstosearchall[$key] = $langs->trans($val);
 	}
+	print '<div class="divsearchfieldfilter">'.$langs->trans("FilterOnInto", $search_all).join(', ', $fieldstosearchall).'</div>';
+}
 
-	$varpage = empty($contextpage) ? $_SERVER["PHP_SELF"] : $contextpage;
-	$selectedfields = $form->multiSelectArrayWithCheckbox('selectedfields', $arrayfields, $varpage, getDolGlobalString('MAIN_CHECKBOX_LEFT_COLUMN', '')); // This also change content of $arrayfields
-	$selectedfields .= (count($arrayofmassactions) ? $form->showCheckAddButtons('checkforselect', 1) : '');
+$i = 0;
 
-	print '<div class="div-table-responsive">';
-	print '<table class="tagtable nobottomiftotal liste'.($moreforfilter ? " listwithfilterbefore" : "").'">'."\n";
+$moreforfilter = '';
 
-	print '<tr class="liste_titre_filter">';
+// If the user can view prospects other than his'
+if ($user->hasRight('user', 'user', 'lire')) {
+	$langs->load("commercial");
+	$moreforfilter .= '<div class="divsearchfield">';
+	$tmptitle = $langs->trans('ThirdPartiesOfSaleRepresentative');
+	$moreforfilter .= img_picto($tmptitle, 'user', 'class="pictofixedwidth"').$formother->select_salesrepresentatives($search_sale, 'search_sale', $user, 0, $tmptitle, 'maxwidth250 widthcentpercentminusx', 1);
+	$moreforfilter .= '</div>';
+}
+// If the user can view prospects other than his'
+if ($user->hasRight('user', 'user', 'lire')) {
+	$moreforfilter .= '<div class="divsearchfield">';
+	$tmptitle = $langs->trans('LinkedToSpecificUsers');
+	$moreforfilter .= img_picto($tmptitle, 'user', 'class="pictofixedwidth"').$form->select_dolusers($search_user, 'search_user', $tmptitle, '', 0, '', '', 0, 0, 0, '', 0, '', 'maxwidth250 widthcentpercentminusx');
+	$moreforfilter .= '</div>';
+}
+// If the user can view products
+if (isModEnabled('categorie') && $user->hasRight('categorie', 'read') && ($user->hasRight('product', 'read') || $user->hasRight('service', 'read'))) {
+	$searchCategoryProductOperator = -1;
+	include_once DOL_DOCUMENT_ROOT.'/categories/class/categorie.class.php';
+	$tmptitle = $langs->trans('IncludingProductWithTag');
+	$formcategory = new FormCategory($db);
+	$moreforfilter .= $formcategory->getFilterBox(Categorie::TYPE_PRODUCT, array($search_product_category), 'maxwidth300', $searchCategoryProductOperator, 0, 0, $tmptitle);
+}
+if (isModEnabled('categorie') && $user->hasRight('categorie', 'lire')) {
+	require_once DOL_DOCUMENT_ROOT.'/categories/class/categorie.class.php';
+	$moreforfilter .= '<div class="divsearchfield">';
+	$tmptitle = $langs->trans('CustomersProspectsCategoriesShort');
+	$moreforfilter .= img_picto($tmptitle, 'category', 'class="pictofixedwidth"').$formother->select_categories('customer', $search_categ_cus, 'search_categ_cus', 1, $tmptitle, (empty($conf->dol_optimize_smallscreen) ? 'maxwidth300 widthcentpercentminusx' : 'maxwidth250 widthcentpercentminusx'));
+	$moreforfilter .= '</div>';
+}
+if (isModEnabled('stock') && getDolGlobalString('WAREHOUSE_ASK_WAREHOUSE_DURING_PROPAL')) {
+	require_once DOL_DOCUMENT_ROOT.'/product/class/html.formproduct.class.php';
+	$formproduct = new FormProduct($db);
+	$moreforfilter .= '<div class="divsearchfield">';
+	$tmptitle = $langs->trans('Warehouse');
+	$moreforfilter .= img_picto($tmptitle, 'stock', 'class="pictofixedwidth"').$formproduct->selectWarehouses($search_warehouse, 'search_warehouse', '', $tmptitle, 0, 0, $tmptitle);
+	$moreforfilter .= '</div>';
+}
+$parameters = array();
+$reshook = $hookmanager->executeHooks('printFieldPreListTitle', $parameters, $object, $action); // Note that $action and $object may have been modified by hook
+if (empty($reshook)) {
+	$moreforfilter .= $hookmanager->resPrint;
+} else {
+	$moreforfilter = $hookmanager->resPrint;
+}
 
-	// Action column
-	if (getDolGlobalString('MAIN_CHECKBOX_LEFT_COLUMN')) {
-		print '<td class="liste_titre" align="middle">';
-		$searchpicto = $form->showFilterButtons('left');
-		print $searchpicto;
-		print '</td>';
-	}
+if (!empty($moreforfilter)) {
+	print '<div class="liste_titre liste_titre_bydiv centpercent">';
+	print $moreforfilter;
+	print '</div>';
+}
 
-	if (!empty($arrayfields['p.ref']['checked'])) {
-		print '<td class="liste_titre">';
-		print '<input class="flat maxwidth50" type="text" name="search_ref" value="'.dol_escape_htmltag($search_ref).'">';
-		print '</td>';
-	}
-	if (!empty($arrayfields['p.ref_client']['checked'])) {
-		print '<td class="liste_titre">';
-		print '<input class="flat maxwidth50" type="text" name="search_refcustomer" value="'.dol_escape_htmltag($search_refcustomer).'">';
-		print '</td>';
-	}
-	if (!empty($arrayfields['pr.ref']['checked'])) {
-		print '<td class="liste_titre">';
-		print '<input class="flat maxwidth50" type="text" name="search_refproject" value="'.dol_escape_htmltag($search_refproject).'">';
-		print '</td>';
-	}
-	if (!empty($arrayfields['pr.title']['checked'])) {
-		print '<td class="liste_titre">';
-		print '<input class="flat maxwidth50" type="text" name="search_project" value="'.dol_escape_htmltag($search_project).'">';
-		print '</td>';
-	}
-	if (!empty($arrayfields['s.nom']['checked'])) {
-		print '<td class="liste_titre" align="left">';
-		print '<input class="flat maxwidth100" type="text" name="search_societe" value="'.dol_escape_htmltag($search_societe).'">';
-		print '</td>';
-	}
-	if (!empty($arrayfields['s.name_alias']['checked'])) {
-		print '<td class="liste_titre" align="left">';
-		print '<input class="flat maxwidth100" type="text" name="search_societe_alias" value="'.dol_escape_htmltag($search_societe_alias).'">';
-		print '</td>';
-	}
-	if (!empty($arrayfields['s.town']['checked'])) {
-		print '<td class="liste_titre"><input class="flat maxwidth50" type="text" name="search_town" value="'.$search_town.'"></td>';
-	}
-	if (!empty($arrayfields['s.zip']['checked'])) {
-		print '<td class="liste_titre"><input class="flat maxwidth50" type="text" name="search_zip" value="'.$search_zip.'"></td>';
-	}
-	// State
-	if (!empty($arrayfields['state.nom']['checked'])) {
-		print '<td class="liste_titre">';
-		print '<input class="flat maxwidth50" type="text" name="search_state" value="'.dol_escape_htmltag($search_state).'">';
-		print '</td>';
-	}
-	// Country
-	if (!empty($arrayfields['country.code_iso']['checked'])) {
-		print '<td class="liste_titre" align="center">';
-		print $form->select_country($search_country, 'search_country', '', 0, 'minwidth100imp maxwidth100');
-		print '</td>';
-	}
-	// Email
-	if (!empty($arrayfields['s.email']['checked'])) {
-		print '<td class="liste_titre"><input class="flat maxwidth50" type="text" name="search_email" value="'.$search_email.'"></td>';
-	}
-	// Phone
-	if (!empty($arrayfields['s.phone']['checked'])) {
-		print '<td class="liste_titre"><input class="flat maxwidth50" type="text" name="search_phone" value="'.$search_phone.'"></td>';
-	}
-	// Company type
-	if (!empty($arrayfields['typent.code']['checked'])) {
-		print '<td class="liste_titre maxwidth100onsmartphone" align="center">';
-		print $form->selectarray("search_type_thirdparty", $formcompany->typent_array(0), $search_type_thirdparty, 1, 0, 0, '', 0, 0, 0, (!getDolGlobalString('SOCIETE_SORT_ON_TYPEENT') ? 'ASC' : $conf->global->SOCIETE_SORT_ON_TYPEENT), '', 1);
-		print ajax_combobox('search_type_thirdparty');
-		print '</td>';
-	}
-	// Date
-	if (!empty($arrayfields['p.date']['checked'])) {
-		print '<td class="liste_titre center">';
-		print '<div class="nowrapfordate">';
-		print $form->selectDate($search_date_start ? $search_date_start : -1, 'search_date_start', 0, 0, 1, '', 1, 0, 0, '', '', '', '', 1, '', $langs->trans('From'));
-		print '</div>';
-		print '<div class="nowrapfordate">';
-		print $form->selectDate($search_date_end ? $search_date_end : -1, 'search_date_end', 0, 0, 1, '', 1, 0, 0, '', '', '', '', 1, '', $langs->trans('to'));
-		print '</div>';
-		print '</td>';
-	}
-	// Date end
-	if (!empty($arrayfields['p.fin_validite']['checked'])) {
-		print '<td class="liste_titre center">';
-		print '<div class="nowrapfordate">';
-		print $form->selectDate($search_date_end_start ? $search_date_end_start : -1, 'search_date_end_start', 0, 0, 1, '', 1, 0, 0, '', '', '', '', 1, '', $langs->trans('From'));
-		print '</div>';
-		print '<div class="nowrapfordate">';
-		print $form->selectDate($search_date_end_end ? $search_date_end_end : -1, 'search_date_end_end', 0, 0, 1, '', 1, 0, 0, '', '', '', '', 1, '', $langs->trans('to'));
-		print '</div>';
-		print '</td>';
-	}
-	// Date delivery
-	if (!empty($arrayfields['p.date_livraison']['checked'])) {
-		print '<td class="liste_titre center">';
-		print '<div class="nowrapfordate">';
-		print $form->selectDate($search_date_delivery_start ? $search_date_delivery_start : -1, 'search_date_delivery_start', 0, 0, 1, '', 1, 0, 0, '', '', '', '', 1, '', $langs->trans('From'));
-		print '</div>';
-		print '<div class="nowrapfordate">';
-		print $form->selectDate($search_date_delivery_end ? $search_date_delivery_end : -1, 'search_date_delivery_end', 0, 0, 1, '', 1, 0, 0, '', '', '', '', 1, '', $langs->trans('From'));
-		print '</div>';
-		print '</td>';
-	}
-	// Date Signature
-	if (!empty($arrayfields['p.date_signature']['checked'])) {
-		print '<td class="liste_titre center">';
-		print '<div class="nowrapfordate">';
-		print $form->selectDate($search_date_signature_start ? $search_date_signature_start : -1, 'search_date_signature_start', 0, 0, 1, '', 1, 0, 0, '', '', '', '', 1, '', $langs->trans('From'));
-		print '</div>';
-		print '<div class="nowrapfordate">';
-		print $form->selectDate($search_date_signature_end ? $search_date_signature_end : -1, 'search_date_signature_end', 0, 0, 1, '', 1, 0, 0, '', '', '', '', 1, '', $langs->trans('From'));
-		print '</div>';
-		print '</td>';
-	}
-	// Availability
-	if (!empty($arrayfields['ava.rowid']['checked'])) {
-		print '<td class="liste_titre maxwidth100onsmartphone center">';
-		$form->selectAvailabilityDelay($search_availability, 'search_availability', '', 1);
-		print ajax_combobox('search_availability');
-		print '</td>';
-	}
-	// Shipping Method
-	if (!empty($arrayfields['p.fk_shipping_method']['checked'])) {
-		print '<td class="liste_titre">';
-		$form->selectShippingMethod($search_fk_shipping_method, 'search_fk_shipping_method', '', 1, '', 1);
-		print '</td>';
-	}
-	// Source - Input reason
-	if (!empty($arrayfields['p.fk_input_reason']['checked'])) {
-		print '<td class="liste_titre">';
-		$form->selectInputReason($search_fk_input_reason, 'search_fk_input_reason', '', 1, 'maxwidth125', 1);
-		print '</td>';
-	}
-	// Payment term
-	if (!empty($arrayfields['p.fk_cond_reglement']['checked'])) {
-		print '<td class="liste_titre">';
-		print $form->getSelectConditionsPaiements($search_fk_cond_reglement, 'search_fk_cond_reglement', 1, 1, 1);
-		print '</td>';
-	}
-	// Payment mode
-	if (!empty($arrayfields['p.fk_mode_reglement']['checked'])) {
-		print '<td class="liste_titre">';
-		print $form->select_types_paiements($search_fk_mode_reglement, 'search_fk_mode_reglement', '', 0, 1, 1, 0, -1, '', 1);
-		print '</td>';
-	}
-	if (!empty($arrayfields['p.total_ht']['checked'])) {
-		// Amount
-		print '<td class="liste_titre right">';
-		print '<input class="flat" type="text" size="5" name="search_montant_ht" value="'.dol_escape_htmltag($search_montant_ht).'">';
-		print '</td>';
-	}
-	if (!empty($arrayfields['p.total_tva']['checked'])) {
-		// Amount
-		print '<td class="liste_titre right">';
-		print '<input class="flat" type="text" size="5" name="search_montant_vat" value="'.dol_escape_htmltag($search_montant_vat).'">';
-		print '</td>';
-	}
-	if (!empty($arrayfields['p.total_ttc']['checked'])) {
-		// Amount
-		print '<td class="liste_titre right">';
-		print '<input class="flat" type="text" size="5" name="search_montant_ttc" value="'.dol_escape_htmltag($search_montant_ttc).'">';
-		print '</td>';
-	}
-	if (!empty($arrayfields['p.total_ht_invoiced']['checked'])) {
-		// Amount invoiced
-		print '<td class="liste_titre right">';
-		print '</td>';
-	}
-	if (!empty($arrayfields['p.total_invoiced']['checked'])) {
-		// Amount invoiced
-		print '<td class="liste_titre right">';
-		print '</td>';
-	}
-	if (!empty($arrayfields['p.multicurrency_code']['checked'])) {
-		// Currency
-		print '<td class="liste_titre">';
-		print $form->selectMultiCurrency($search_multicurrency_code, 'search_multicurrency_code', 1);
-		print '</td>';
-	}
-	if (!empty($arrayfields['p.multicurrency_tx']['checked'])) {
-		// Currency rate
-		print '<td class="liste_titre">';
-		print '<input class="flat" type="text" size="4" name="search_multicurrency_tx" value="'.dol_escape_htmltag($search_multicurrency_tx).'">';
-		print '</td>';
-	}
-	if (!empty($arrayfields['p.multicurrency_total_ht']['checked'])) {
-		// Amount
-		print '<td class="liste_titre right">';
-		print '<input class="flat" type="text" size="4" name="search_multicurrency_montant_ht" value="'.dol_escape_htmltag($search_multicurrency_montant_ht).'">';
-		print '</td>';
-	}
-	if (!empty($arrayfields['p.multicurrency_total_tva']['checked'])) {
-		// Amount
-		print '<td class="liste_titre right">';
-		print '<input class="flat" type="text" size="4" name="search_multicurrency_montant_vat" value="'.dol_escape_htmltag($search_multicurrency_montant_vat).'">';
-		print '</td>';
-	}
-	if (!empty($arrayfields['p.multicurrency_total_ttc']['checked'])) {
-		// Amount
-		print '<td class="liste_titre right">';
-		print '<input class="flat" type="text" size="4" name="search_multicurrency_montant_ttc" value="'.dol_escape_htmltag($search_multicurrency_montant_ttc).'">';
-		print '</td>';
-	}
-	if (!empty($arrayfields['p.multicurrency_total_ht_invoiced']['checked'])) {
-		// Amount invoiced
-		print '<td class="liste_titre right">';
-		print '</td>';
-	}
-	if (!empty($arrayfields['p.multicurrency_total_invoiced']['checked'])) {
-		// Amount invoiced
-		print '<td class="liste_titre right">';
-		print '</td>';
-	}
-	if (!empty($arrayfields['u.login']['checked'])) {
-		// Author
-		print '<td class="liste_titre">';
-		print '<input class="flat maxwidth75" type="text" name="search_login" value="'.dol_escape_htmltag($search_login).'">';
-		print '</td>';
-	}
-	if (!empty($arrayfields['sale_representative']['checked'])) {
-		print '<td class="liste_titre"></td>';
-	}
-	if (!empty($arrayfields['total_pa']['checked'])) {
-		print '<td class="liste_titre right">';
-		print '</td>';
-	}
-	if (!empty($arrayfields['total_margin']['checked'])) {
-		print '<td class="liste_titre right">';
-		print '</td>';
-	}
-	if (!empty($arrayfields['total_margin_rate']['checked'])) {
-		print '<td class="liste_titre right">';
-		print '</td>';
-	}
-	if (!empty($arrayfields['total_mark_rate']['checked'])) {
-		print '<td class="liste_titre right">';
-		print '</td>';
-	}
-	// Extra fields
-	include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_list_search_input.tpl.php';
-
-	// Fields from hook
-	$parameters = array('arrayfields'=>$arrayfields);
-	$reshook = $hookmanager->executeHooks('printFieldListOption', $parameters, $object, $action); // Note that $action and $object may have been modified by hook
-	print $hookmanager->resPrint;
-	// Date creation
-	if (!empty($arrayfields['p.datec']['checked'])) {
-		print '<td class="liste_titre">';
-		print '</td>';
-	}
-	// Date modification
-	if (!empty($arrayfields['p.tms']['checked'])) {
-		print '<td class="liste_titre">';
-		print '</td>';
-	}
-	// Date cloture
-	if (!empty($arrayfields['p.date_cloture']['checked'])) {
-		print '<td class="liste_titre">';
-		print '</td>';
-	}
-	if (!empty($arrayfields['p.note_public']['checked'])) {
-		// Note public
-		print '<td class="liste_titre">';
-		print '</td>';
-	}
-	if (!empty($arrayfields['p.note_private']['checked'])) {
-		// Note private
-		print '<td class="liste_titre">';
-		print '</td>';
-	}
-	// Status
-	if (!empty($arrayfields['p.fk_statut']['checked'])) {
-		print '<td class="liste_titre center parentonrightofpage">';
-		$formpropal->selectProposalStatus($search_status, 1, 0, 1, 'customer', 'search_statut', 'search_status width100 onrightofpage');
-		print '</td>';
-	}
-	// Action column
-	if (!getDolGlobalString('MAIN_CHECKBOX_LEFT_COLUMN')) {
-		print '<td class="liste_titre" align="middle">';
-		$searchpicto = $form->showFilterButtons();
-		print $searchpicto;
-		print '</td>';
-	}
-	print "</tr>\n";
-
-	$totalarray = array(
-		'nbfield' => 0,
-		'val' => array(
-			'p.total_ht' => 0,
-			'p.total_tva' => 0,
-			'p.total_ttc' => 0,
-		),
-	);
-
-	// Fields title
-	print '<tr class="liste_titre">';
-	if (getDolGlobalString('MAIN_CHECKBOX_LEFT_COLUMN')) {
-		print_liste_field_titre($selectedfields, $_SERVER["PHP_SELF"], "", '', '', 'align="center"', $sortfield, $sortorder, 'maxwidthsearch ');
-		$totalarray['nbfield']++;
-	}
-	if (!empty($arrayfields['p.ref']['checked'])) {
-		print_liste_field_titre($arrayfields['p.ref']['label'], $_SERVER["PHP_SELF"], 'p.ref', '', $param, '', $sortfield, $sortorder);
-		$totalarray['nbfield']++;
-	}
-	if (!empty($arrayfields['p.ref_client']['checked'])) {
-		print_liste_field_titre($arrayfields['p.ref_client']['label'], $_SERVER["PHP_SELF"], 'p.ref_client', '', $param, '', $sortfield, $sortorder);
-		$totalarray['nbfield']++;
-	}
-	if (!empty($arrayfields['pr.ref']['checked'])) {
-		print_liste_field_titre($arrayfields['pr.ref']['label'], $_SERVER["PHP_SELF"], 'pr.ref', '', $param, '', $sortfield, $sortorder);
-		$totalarray['nbfield']++;
-	}
-	if (!empty($arrayfields['pr.title']['checked'])) {
-		print_liste_field_titre($arrayfields['pr.title']['label'], $_SERVER["PHP_SELF"], 'pr.title', '', $param, '', $sortfield, $sortorder);
-		$totalarray['nbfield']++;
-	}
-	if (!empty($arrayfields['s.nom']['checked'])) {
-		print_liste_field_titre($arrayfields['s.nom']['label'], $_SERVER["PHP_SELF"], 's.nom', '', $param, '', $sortfield, $sortorder);
-		$totalarray['nbfield']++;
-	}
-	if (!empty($arrayfields['s.name_alias']['checked'])) {
-		print_liste_field_titre($arrayfields['s.name_alias']['label'], $_SERVER["PHP_SELF"], 's.name_alias', '', $param, '', $sortfield, $sortorder);
-		$totalarray['nbfield']++;
-	}
-	if (!empty($arrayfields['s.town']['checked'])) {
-		print_liste_field_titre($arrayfields['s.town']['label'], $_SERVER["PHP_SELF"], 's.town', '', $param, '', $sortfield, $sortorder);
-		$totalarray['nbfield']++;
-	}
-	if (!empty($arrayfields['s.zip']['checked'])) {
-		print_liste_field_titre($arrayfields['s.zip']['label'], $_SERVER["PHP_SELF"], 's.zip', '', $param, '', $sortfield, $sortorder);
-		$totalarray['nbfield']++;
-	}
-	if (!empty($arrayfields['state.nom']['checked'])) {
-		print_liste_field_titre($arrayfields['state.nom']['label'], $_SERVER["PHP_SELF"], "state.nom", "", $param, '', $sortfield, $sortorder);
-		$totalarray['nbfield']++;
-	}
-	if (!empty($arrayfields['country.code_iso']['checked'])) {
-		print_liste_field_titre($arrayfields['country.code_iso']['label'], $_SERVER["PHP_SELF"], "country.code_iso", "", $param, 'class="center"', $sortfield, $sortorder);
-		$totalarray['nbfield']++;
-	}
-	if (!empty($arrayfields['s.email']['checked'])) {
-		print_liste_field_titre($arrayfields['s.email']['label'], $_SERVER["PHP_SELF"], 's.email', '', $param, '', $sortfield, $sortorder);
-	}
-	if (!empty($arrayfields['s.phone']['checked'])) {
-		print_liste_field_titre($arrayfields['s.phone']['label'], $_SERVER["PHP_SELF"], 's.phone', '', $param, '', $sortfield, $sortorder);
-	}
-	if (!empty($arrayfields['typent.code']['checked'])) {
-		print_liste_field_titre($arrayfields['typent.code']['label'], $_SERVER["PHP_SELF"], "typent.code", "", $param, 'class="center"', $sortfield, $sortorder);
-		$totalarray['nbfield']++;
-	}
-	if (!empty($arrayfields['p.date']['checked'])) {
-		print_liste_field_titre($arrayfields['p.date']['label'], $_SERVER["PHP_SELF"], 'p.datep', '', $param, 'class="center"', $sortfield, $sortorder);
-		$totalarray['nbfield']++;
-	}
-	if (!empty($arrayfields['p.fin_validite']['checked'])) {
-		print_liste_field_titre($arrayfields['p.fin_validite']['label'], $_SERVER["PHP_SELF"], 'dfv', '', $param, 'class="center"', $sortfield, $sortorder);
-		$totalarray['nbfield']++;
-	}
-	if (!empty($arrayfields['p.date_livraison']['checked'])) {
-		print_liste_field_titre($arrayfields['p.date_livraison']['label'], $_SERVER["PHP_SELF"], 'p.date_livraison', '', $param, 'class="center"', $sortfield, $sortorder);
-		$totalarray['nbfield']++;
-	}
-	if (!empty($arrayfields['p.date_signature']['checked'])) {
-		print_liste_field_titre($arrayfields['p.date_signature']['label'], $_SERVER["PHP_SELF"], 'p.date_signature', '', $param, 'class="center"', $sortfield, $sortorder);
-		$totalarray['nbfield']++;
-	}
-	if (!empty($arrayfields['ava.rowid']['checked'])) {
-		print_liste_field_titre($arrayfields['ava.rowid']['label'], $_SERVER["PHP_SELF"], 'availability', '', $param, '', $sortfield, $sortorder);
-		$totalarray['nbfield']++;
-	}
-	if (!empty($arrayfields['p.fk_shipping_method']['checked'])) {
-		print_liste_field_titre($arrayfields['p.fk_shipping_method']['label'], $_SERVER["PHP_SELF"], "p.fk_shipping_method", "", $param, '', $sortfield, $sortorder);
-		$totalarray['nbfield']++;
-	}
-	if (!empty($arrayfields['p.fk_input_reason']['checked'])) {
-		print_liste_field_titre($arrayfields['p.fk_input_reason']['label'], $_SERVER["PHP_SELF"], "p.fk_input_reason", "", $param, '', $sortfield, $sortorder);
-		$totalarray['nbfield']++;
-	}
-	if (!empty($arrayfields['p.fk_cond_reglement']['checked'])) {
-		print_liste_field_titre($arrayfields['p.fk_cond_reglement']['label'], $_SERVER["PHP_SELF"], "p.fk_cond_reglement", "", $param, '', $sortfield, $sortorder);
-		$totalarray['nbfield']++;
-	}
-	if (!empty($arrayfields['p.fk_mode_reglement']['checked'])) {
-		print_liste_field_titre($arrayfields['p.fk_mode_reglement']['label'], $_SERVER["PHP_SELF"], "p.fk_mode_reglement", "", $param, '', $sortfield, $sortorder);
-		$totalarray['nbfield']++;
-	}
-	if (!empty($arrayfields['p.total_ht']['checked'])) {
-		print_liste_field_titre($arrayfields['p.total_ht']['label'], $_SERVER["PHP_SELF"], 'p.total_ht', '', $param, '', $sortfield, $sortorder, 'right ');
-		$totalarray['nbfield']++;
-	}
-	if (!empty($arrayfields['p.total_tva']['checked'])) {
-		print_liste_field_titre($arrayfields['p.total_tva']['label'], $_SERVER["PHP_SELF"], 'p.total_tva', '', $param, '', $sortfield, $sortorder, 'right ');
-		$totalarray['nbfield']++;
-	}
-	if (!empty($arrayfields['p.total_ttc']['checked'])) {
-		print_liste_field_titre($arrayfields['p.total_ttc']['label'], $_SERVER["PHP_SELF"], 'p.total_ttc', '', $param, '', $sortfield, $sortorder, 'right ');
-		$totalarray['nbfield']++;
-	}
-	if (!empty($arrayfields['p.total_ht_invoiced']['checked'])) {
-		print_liste_field_titre($arrayfields['p.total_ht_invoiced']['label'], $_SERVER["PHP_SELF"], '', '', $param, '', $sortfield, $sortorder, 'right ');
-		$totalarray['nbfield']++;
-	}
-	if (!empty($arrayfields['p.total_invoiced']['checked'])) {
-		print_liste_field_titre($arrayfields['p.total_invoiced']['label'], $_SERVER["PHP_SELF"], '', '', $param, '', $sortfield, $sortorder, 'right ');
-		$totalarray['nbfield']++;
-	}
-	if (!empty($arrayfields['p.multicurrency_code']['checked'])) {
-		print_liste_field_titre($arrayfields['p.multicurrency_code']['label'], $_SERVER['PHP_SELF'], 'p.multicurrency_code', '', $param, '', $sortfield, $sortorder);
-		$totalarray['nbfield']++;
-	}
-	if (!empty($arrayfields['p.multicurrency_tx']['checked'])) {
-		print_liste_field_titre($arrayfields['p.multicurrency_tx']['label'], $_SERVER['PHP_SELF'], 'p.multicurrency_tx', '', $param, '', $sortfield, $sortorder);
-		$totalarray['nbfield']++;
-	}
-	if (!empty($arrayfields['p.multicurrency_total_ht']['checked'])) {
-		print_liste_field_titre($arrayfields['p.multicurrency_total_ht']['label'], $_SERVER['PHP_SELF'], 'p.multicurrency_total_ht', '', $param, '', $sortfield, $sortorder, 'right ');
-		$totalarray['nbfield']++;
-	}
-	if (!empty($arrayfields['p.multicurrency_total_tva']['checked'])) {
-		print_liste_field_titre($arrayfields['p.multicurrency_total_tva']['label'], $_SERVER['PHP_SELF'], 'p.multicurrency_total_tva', '', $param, '', $sortfield, $sortorder, 'right ');
-		$totalarray['nbfield']++;
-	}
-	if (!empty($arrayfields['p.multicurrency_total_ttc']['checked'])) {
-		print_liste_field_titre($arrayfields['p.multicurrency_total_ttc']['label'], $_SERVER['PHP_SELF'], 'p.multicurrency_total_ttc', '', $param, '', $sortfield, $sortorder, 'right ');
-		$totalarray['nbfield']++;
-	}
-	if (!empty($arrayfields['p.multicurrency_total_ht_invoiced']['checked'])) {
-		print_liste_field_titre($arrayfields['p.multicurrency_total_ht_invoiced']['label'], $_SERVER["PHP_SELF"], '', '', $param, '', $sortfield, $sortorder, 'right ');
-		$totalarray['nbfield']++;
-	}
-	if (!empty($arrayfields['p.multicurrency_total_invoiced']['checked'])) {
-		print_liste_field_titre($arrayfields['p.multicurrency_total_invoiced']['label'], $_SERVER["PHP_SELF"], '', '', $param, '', $sortfield, $sortorder, 'right ');
-		$totalarray['nbfield']++;
-	}
-	if (!empty($arrayfields['u.login']['checked'])) {
-		print_liste_field_titre($arrayfields['u.login']['label'], $_SERVER["PHP_SELF"], 'u.login', '', $param, '', $sortfield, $sortorder, 'center ');
-		$totalarray['nbfield']++;
-	}
-	if (!empty($arrayfields['sale_representative']['checked'])) {
-		print_liste_field_titre($arrayfields['sale_representative']['label'], $_SERVER["PHP_SELF"], "", "", "$param", '', $sortfield, $sortorder);
-		$totalarray['nbfield']++;
-	}
-	if (!empty($arrayfields['total_pa']['checked'])) {
-		print_liste_field_titre($arrayfields['total_pa']['label'], $_SERVER['PHP_SELF'], '', '', $param, '', $sortfield, $sortorder, 'right ');
-		$totalarray['nbfield']++;
-	}
-	if (!empty($arrayfields['total_margin']['checked'])) {
-		print_liste_field_titre($arrayfields['total_margin']['label'], $_SERVER['PHP_SELF'], '', '', $param, '', $sortfield, $sortorder, 'right ');
-		$totalarray['nbfield']++;
-	}
-	if (!empty($arrayfields['total_margin_rate']['checked'])) {
-		print_liste_field_titre($arrayfields['total_margin_rate']['label'], $_SERVER['PHP_SELF'], '', '', $param, '', $sortfield, $sortorder, 'right ');
-		$totalarray['nbfield']++;
-	}
-	if (!empty($arrayfields['total_mark_rate']['checked'])) {
-		print_liste_field_titre($arrayfields['total_mark_rate']['label'], $_SERVER['PHP_SELF'], '', '', $param, '', $sortfield, $sortorder, 'right ');
-		$totalarray['nbfield']++;
-	}
-	// Extra fields
-	include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_list_search_title.tpl.php';
-	// Hook fields
-	$parameters = array(
-		'arrayfields' => $arrayfields,
-		'param' => $param,
-		'sortfield' => $sortfield,
-		'sortorder' => $sortorder,
-		'totalarray' => &$totalarray,
-	);
-
-	$reshook = $hookmanager->executeHooks('printFieldListTitle', $parameters, $object, $action); // Note that $action and $object may have been modified by hook
-
-	print $hookmanager->resPrint;
-	if (!empty($arrayfields['p.datec']['checked'])) {
-		print_liste_field_titre($arrayfields['p.datec']['label'], $_SERVER["PHP_SELF"], "p.datec", "", $param, '', $sortfield, $sortorder, 'center nowraponall ');
-		$totalarray['nbfield']++;
-	}
-	if (!empty($arrayfields['p.tms']['checked'])) {
-		print_liste_field_titre($arrayfields['p.tms']['label'], $_SERVER["PHP_SELF"], "p.tms", "", $param, '', $sortfield, $sortorder, 'center nowraponall ');
-		$totalarray['nbfield']++;
-	}
-	if (!empty($arrayfields['p.date_cloture']['checked'])) {
-		print_liste_field_titre($arrayfields['p.date_cloture']['label'], $_SERVER["PHP_SELF"], "p.date_cloture", "", $param, 'align="center" class="nowrap"', $sortfield, $sortorder);
-		$totalarray['nbfield']++;
-	}
-	if (!empty($arrayfields['p.note_public']['checked'])) {
-		print_liste_field_titre($arrayfields['p.note_public']['label'], $_SERVER["PHP_SELF"], "p.note_public", "", $param, '', $sortfield, $sortorder, 'center nowrap ');
-		$totalarray['nbfield']++;
-	}
-	if (!empty($arrayfields['p.note_private']['checked'])) {
-		print_liste_field_titre($arrayfields['p.note_private']['label'], $_SERVER["PHP_SELF"], "p.note_private", "", $param, '', $sortfield, $sortorder, 'center nowrap ');
-		$totalarray['nbfield']++;
-	}
-	if (!empty($arrayfields['p.fk_statut']['checked'])) {
-		print_liste_field_titre($arrayfields['p.fk_statut']['label'], $_SERVER["PHP_SELF"], "p.fk_statut", "", $param, '', $sortfield, $sortorder, 'center ');
-		$totalarray['nbfield']++;
-	}
-	if (!getDolGlobalString('MAIN_CHECKBOX_LEFT_COLUMN')) {
-		print_liste_field_titre($selectedfields, $_SERVER["PHP_SELF"], "", '', '', 'align="center"', $sortfield, $sortorder, 'maxwidthsearch ');
-		$totalarray['nbfield']++;
-	}
-	print '</tr>'."\n";
-
-	// Loop on record
-	// --------------------------------------------------------------------
-	$typenArray = null;
-	$now = dol_now();
-
-	$with_margin_info = false;
-	if (isModEnabled('margin') && (
-		!empty($arrayfields['total_pa']['checked'])
-		|| !empty($arrayfields['total_margin']['checked'])
-		|| !empty($arrayfields['total_margin_rate']['checked'])
-		|| !empty($arrayfields['total_mark_rate']['checked'])
-	)
-	) {
-		$with_margin_info = true;
-	}
-	$total_ht = 0;
-	$total_margin = 0;
-
-	$i = 0;
-	$savnbfield = $totalarray['nbfield'];
-	$totalarray = array();
-	$totalarray['nbfield'] = 0;
-	$imaxinloop = ($limit ? min($num, $limit) : $num);
-	while ($i < $imaxinloop) {
-		$obj = $db->fetch_object($resql);
-		if (empty($obj)) {
-			break; // Should not happen
-		}
-
-		$objectstatic->id = $obj->rowid;
-		$objectstatic->ref = $obj->ref;
-		$objectstatic->ref_client = $obj->ref_client;
-		$objectstatic->note_public = $obj->note_public;
-		$objectstatic->note_private = $obj->note_private;
-		$objectstatic->statut = $obj->status;
-		$objectstatic->status = $obj->status;
-
-		$companystatic->id = $obj->socid;
-		$companystatic->name = $obj->name;
-		$companystatic->name_alias = $obj->alias;
-		$companystatic->client = $obj->client;
-		$companystatic->fournisseur = $obj->fournisseur;
-		$companystatic->code_client = $obj->code_client;
-		$companystatic->email = $obj->email;
-		$companystatic->phone = $obj->phone;
-		$companystatic->address = $obj->address;
-		$companystatic->zip = $obj->zip;
-		$companystatic->town = $obj->town;
-		$companystatic->country_code = $obj->country_code;
-
-		$projectstatic->id = $obj->project_id;
-		$projectstatic->ref = $obj->project_ref;
-		$projectstatic->title = $obj->project_label;
-
-		$totalInvoicedHT = 0;
-		$totalInvoicedTTC = 0;
-		$multicurrency_totalInvoicedHT = 0;
-		$multicurrency_totalInvoicedTTC = 0;
-
-		$TInvoiceData = $objectstatic->InvoiceArrayList($obj->rowid);
-
-		if (!empty($TInvoiceData)) {
-			foreach ($TInvoiceData as $invoiceData) {
-				$invoice = new Facture($db);
-				$invoice->fetch($invoiceData->facid);
-
-				if (getDolGlobalString('FACTURE_DEPOSITS_ARE_JUST_PAYMENTS') && $invoice->type == Facture::TYPE_DEPOSIT) {
-					continue;
-				}
+$varpage = empty($contextpage) ? $_SERVER["PHP_SELF"] : $contextpage;
+$selectedfields = $form->multiSelectArrayWithCheckbox('selectedfields', $arrayfields, $varpage, getDolGlobalString('MAIN_CHECKBOX_LEFT_COLUMN', '')); // This also change content of $arrayfields
+$selectedfields .= (count($arrayofmassactions) ? $form->showCheckAddButtons('checkforselect', 1) : '');
+
+print '<div class="div-table-responsive">';
+print '<table class="tagtable nobottomiftotal liste'.($moreforfilter ? " listwithfilterbefore" : "").'">'."\n";
+
+print '<tr class="liste_titre_filter">';
+
+// Action column
+if (getDolGlobalString('MAIN_CHECKBOX_LEFT_COLUMN')) {
+	print '<td class="liste_titre" align="middle">';
+	$searchpicto = $form->showFilterButtons('left');
+	print $searchpicto;
+	print '</td>';
+}
+
+if (!empty($arrayfields['p.ref']['checked'])) {
+	print '<td class="liste_titre">';
+	print '<input class="flat maxwidth50" type="text" name="search_ref" value="'.dol_escape_htmltag($search_ref).'">';
+	print '</td>';
+}
+if (!empty($arrayfields['p.ref_client']['checked'])) {
+	print '<td class="liste_titre">';
+	print '<input class="flat maxwidth50" type="text" name="search_refcustomer" value="'.dol_escape_htmltag($search_refcustomer).'">';
+	print '</td>';
+}
+if (!empty($arrayfields['pr.ref']['checked'])) {
+	print '<td class="liste_titre">';
+	print '<input class="flat maxwidth50" type="text" name="search_refproject" value="'.dol_escape_htmltag($search_refproject).'">';
+	print '</td>';
+}
+if (!empty($arrayfields['pr.title']['checked'])) {
+	print '<td class="liste_titre">';
+	print '<input class="flat maxwidth50" type="text" name="search_project" value="'.dol_escape_htmltag($search_project).'">';
+	print '</td>';
+}
+if (!empty($arrayfields['s.nom']['checked'])) {
+	print '<td class="liste_titre" align="left">';
+	print '<input class="flat maxwidth100" type="text" name="search_societe" value="'.dol_escape_htmltag($search_societe).'">';
+	print '</td>';
+}
+if (!empty($arrayfields['s.name_alias']['checked'])) {
+	print '<td class="liste_titre" align="left">';
+	print '<input class="flat maxwidth100" type="text" name="search_societe_alias" value="'.dol_escape_htmltag($search_societe_alias).'">';
+	print '</td>';
+}
+if (!empty($arrayfields['s.town']['checked'])) {
+	print '<td class="liste_titre"><input class="flat maxwidth50" type="text" name="search_town" value="'.$search_town.'"></td>';
+}
+if (!empty($arrayfields['s.zip']['checked'])) {
+	print '<td class="liste_titre"><input class="flat maxwidth50" type="text" name="search_zip" value="'.$search_zip.'"></td>';
+}
+// State
+if (!empty($arrayfields['state.nom']['checked'])) {
+	print '<td class="liste_titre">';
+	print '<input class="flat maxwidth50" type="text" name="search_state" value="'.dol_escape_htmltag($search_state).'">';
+	print '</td>';
+}
+// Country
+if (!empty($arrayfields['country.code_iso']['checked'])) {
+	print '<td class="liste_titre" align="center">';
+	print $form->select_country($search_country, 'search_country', '', 0, 'minwidth100imp maxwidth100');
+	print '</td>';
+}
+// Email
+if (!empty($arrayfields['s.email']['checked'])) {
+	print '<td class="liste_titre"><input class="flat maxwidth50" type="text" name="search_email" value="'.$search_email.'"></td>';
+}
+// Phone
+if (!empty($arrayfields['s.phone']['checked'])) {
+	print '<td class="liste_titre"><input class="flat maxwidth50" type="text" name="search_phone" value="'.$search_phone.'"></td>';
+}
+// Company type
+if (!empty($arrayfields['typent.code']['checked'])) {
+	print '<td class="liste_titre maxwidth100onsmartphone" align="center">';
+	print $form->selectarray("search_type_thirdparty", $formcompany->typent_array(0), $search_type_thirdparty, 1, 0, 0, '', 0, 0, 0, (!getDolGlobalString('SOCIETE_SORT_ON_TYPEENT') ? 'ASC' : $conf->global->SOCIETE_SORT_ON_TYPEENT), '', 1);
+	print ajax_combobox('search_type_thirdparty');
+	print '</td>';
+}
+// Date
+if (!empty($arrayfields['p.date']['checked'])) {
+	print '<td class="liste_titre center">';
+	print '<div class="nowrapfordate">';
+	print $form->selectDate($search_date_start ? $search_date_start : -1, 'search_date_start', 0, 0, 1, '', 1, 0, 0, '', '', '', '', 1, '', $langs->trans('From'));
+	print '</div>';
+	print '<div class="nowrapfordate">';
+	print $form->selectDate($search_date_end ? $search_date_end : -1, 'search_date_end', 0, 0, 1, '', 1, 0, 0, '', '', '', '', 1, '', $langs->trans('to'));
+	print '</div>';
+	print '</td>';
+}
+// Date end
+if (!empty($arrayfields['p.fin_validite']['checked'])) {
+	print '<td class="liste_titre center">';
+	print '<div class="nowrapfordate">';
+	print $form->selectDate($search_date_end_start ? $search_date_end_start : -1, 'search_date_end_start', 0, 0, 1, '', 1, 0, 0, '', '', '', '', 1, '', $langs->trans('From'));
+	print '</div>';
+	print '<div class="nowrapfordate">';
+	print $form->selectDate($search_date_end_end ? $search_date_end_end : -1, 'search_date_end_end', 0, 0, 1, '', 1, 0, 0, '', '', '', '', 1, '', $langs->trans('to'));
+	print '</div>';
+	print '</td>';
+}
+// Date delivery
+if (!empty($arrayfields['p.date_livraison']['checked'])) {
+	print '<td class="liste_titre center">';
+	print '<div class="nowrapfordate">';
+	print $form->selectDate($search_date_delivery_start ? $search_date_delivery_start : -1, 'search_date_delivery_start', 0, 0, 1, '', 1, 0, 0, '', '', '', '', 1, '', $langs->trans('From'));
+	print '</div>';
+	print '<div class="nowrapfordate">';
+	print $form->selectDate($search_date_delivery_end ? $search_date_delivery_end : -1, 'search_date_delivery_end', 0, 0, 1, '', 1, 0, 0, '', '', '', '', 1, '', $langs->trans('From'));
+	print '</div>';
+	print '</td>';
+}
+// Date Signature
+if (!empty($arrayfields['p.date_signature']['checked'])) {
+	print '<td class="liste_titre center">';
+	print '<div class="nowrapfordate">';
+	print $form->selectDate($search_date_signature_start ? $search_date_signature_start : -1, 'search_date_signature_start', 0, 0, 1, '', 1, 0, 0, '', '', '', '', 1, '', $langs->trans('From'));
+	print '</div>';
+	print '<div class="nowrapfordate">';
+	print $form->selectDate($search_date_signature_end ? $search_date_signature_end : -1, 'search_date_signature_end', 0, 0, 1, '', 1, 0, 0, '', '', '', '', 1, '', $langs->trans('From'));
+	print '</div>';
+	print '</td>';
+}
+// Availability
+if (!empty($arrayfields['ava.rowid']['checked'])) {
+	print '<td class="liste_titre maxwidth100onsmartphone center">';
+	$form->selectAvailabilityDelay($search_availability, 'search_availability', '', 1);
+	print ajax_combobox('search_availability');
+	print '</td>';
+}
+// Shipping Method
+if (!empty($arrayfields['p.fk_shipping_method']['checked'])) {
+	print '<td class="liste_titre">';
+	$form->selectShippingMethod($search_fk_shipping_method, 'search_fk_shipping_method', '', 1, '', 1);
+	print '</td>';
+}
+// Source - Input reason
+if (!empty($arrayfields['p.fk_input_reason']['checked'])) {
+	print '<td class="liste_titre">';
+	$form->selectInputReason($search_fk_input_reason, 'search_fk_input_reason', '', 1, 'maxwidth125', 1);
+	print '</td>';
+}
+// Payment term
+if (!empty($arrayfields['p.fk_cond_reglement']['checked'])) {
+	print '<td class="liste_titre">';
+	print $form->getSelectConditionsPaiements($search_fk_cond_reglement, 'search_fk_cond_reglement', 1, 1, 1);
+	print '</td>';
+}
+// Payment mode
+if (!empty($arrayfields['p.fk_mode_reglement']['checked'])) {
+	print '<td class="liste_titre">';
+	print $form->select_types_paiements($search_fk_mode_reglement, 'search_fk_mode_reglement', '', 0, 1, 1, 0, -1, '', 1);
+	print '</td>';
+}
+if (!empty($arrayfields['p.total_ht']['checked'])) {
+	// Amount
+	print '<td class="liste_titre right">';
+	print '<input class="flat" type="text" size="5" name="search_montant_ht" value="'.dol_escape_htmltag($search_montant_ht).'">';
+	print '</td>';
+}
+if (!empty($arrayfields['p.total_tva']['checked'])) {
+	// Amount
+	print '<td class="liste_titre right">';
+	print '<input class="flat" type="text" size="5" name="search_montant_vat" value="'.dol_escape_htmltag($search_montant_vat).'">';
+	print '</td>';
+}
+if (!empty($arrayfields['p.total_ttc']['checked'])) {
+	// Amount
+	print '<td class="liste_titre right">';
+	print '<input class="flat" type="text" size="5" name="search_montant_ttc" value="'.dol_escape_htmltag($search_montant_ttc).'">';
+	print '</td>';
+}
+if (!empty($arrayfields['p.total_ht_invoiced']['checked'])) {
+	// Amount invoiced
+	print '<td class="liste_titre right">';
+	print '</td>';
+}
+if (!empty($arrayfields['p.total_invoiced']['checked'])) {
+	// Amount invoiced
+	print '<td class="liste_titre right">';
+	print '</td>';
+}
+if (!empty($arrayfields['p.multicurrency_code']['checked'])) {
+	// Currency
+	print '<td class="liste_titre">';
+	print $form->selectMultiCurrency($search_multicurrency_code, 'search_multicurrency_code', 1);
+	print '</td>';
+}
+if (!empty($arrayfields['p.multicurrency_tx']['checked'])) {
+	// Currency rate
+	print '<td class="liste_titre">';
+	print '<input class="flat" type="text" size="4" name="search_multicurrency_tx" value="'.dol_escape_htmltag($search_multicurrency_tx).'">';
+	print '</td>';
+}
+if (!empty($arrayfields['p.multicurrency_total_ht']['checked'])) {
+	// Amount
+	print '<td class="liste_titre right">';
+	print '<input class="flat" type="text" size="4" name="search_multicurrency_montant_ht" value="'.dol_escape_htmltag($search_multicurrency_montant_ht).'">';
+	print '</td>';
+}
+if (!empty($arrayfields['p.multicurrency_total_tva']['checked'])) {
+	// Amount
+	print '<td class="liste_titre right">';
+	print '<input class="flat" type="text" size="4" name="search_multicurrency_montant_vat" value="'.dol_escape_htmltag($search_multicurrency_montant_vat).'">';
+	print '</td>';
+}
+if (!empty($arrayfields['p.multicurrency_total_ttc']['checked'])) {
+	// Amount
+	print '<td class="liste_titre right">';
+	print '<input class="flat" type="text" size="4" name="search_multicurrency_montant_ttc" value="'.dol_escape_htmltag($search_multicurrency_montant_ttc).'">';
+	print '</td>';
+}
+if (!empty($arrayfields['p.multicurrency_total_ht_invoiced']['checked'])) {
+	// Amount invoiced
+	print '<td class="liste_titre right">';
+	print '</td>';
+}
+if (!empty($arrayfields['p.multicurrency_total_invoiced']['checked'])) {
+	// Amount invoiced
+	print '<td class="liste_titre right">';
+	print '</td>';
+}
+if (!empty($arrayfields['u.login']['checked'])) {
+	// Author
+	print '<td class="liste_titre">';
+	print '<input class="flat maxwidth75" type="text" name="search_login" value="'.dol_escape_htmltag($search_login).'">';
+	print '</td>';
+}
+if (!empty($arrayfields['sale_representative']['checked'])) {
+	print '<td class="liste_titre"></td>';
+}
+if (!empty($arrayfields['total_pa']['checked'])) {
+	print '<td class="liste_titre right">';
+	print '</td>';
+}
+if (!empty($arrayfields['total_margin']['checked'])) {
+	print '<td class="liste_titre right">';
+	print '</td>';
+}
+if (!empty($arrayfields['total_margin_rate']['checked'])) {
+	print '<td class="liste_titre right">';
+	print '</td>';
+}
+if (!empty($arrayfields['total_mark_rate']['checked'])) {
+	print '<td class="liste_titre right">';
+	print '</td>';
+}
+// Extra fields
+include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_list_search_input.tpl.php';
+
+// Fields from hook
+$parameters = array('arrayfields'=>$arrayfields);
+$reshook = $hookmanager->executeHooks('printFieldListOption', $parameters, $object, $action); // Note that $action and $object may have been modified by hook
+print $hookmanager->resPrint;
+// Date creation
+if (!empty($arrayfields['p.datec']['checked'])) {
+	print '<td class="liste_titre">';
+	print '</td>';
+}
+// Date modification
+if (!empty($arrayfields['p.tms']['checked'])) {
+	print '<td class="liste_titre">';
+	print '</td>';
+}
+// Date cloture
+if (!empty($arrayfields['p.date_cloture']['checked'])) {
+	print '<td class="liste_titre">';
+	print '</td>';
+}
+if (!empty($arrayfields['p.note_public']['checked'])) {
+	// Note public
+	print '<td class="liste_titre">';
+	print '</td>';
+}
+if (!empty($arrayfields['p.note_private']['checked'])) {
+	// Note private
+	print '<td class="liste_titre">';
+	print '</td>';
+}
+// Status
+if (!empty($arrayfields['p.fk_statut']['checked'])) {
+	print '<td class="liste_titre center parentonrightofpage">';
+	$formpropal->selectProposalStatus($search_status, 1, 0, 1, 'customer', 'search_statut', 'search_status width100 onrightofpage');
+	print '</td>';
+}
+// Action column
+if (!getDolGlobalString('MAIN_CHECKBOX_LEFT_COLUMN')) {
+	print '<td class="liste_titre" align="middle">';
+	$searchpicto = $form->showFilterButtons();
+	print $searchpicto;
+	print '</td>';
+}
+print "</tr>\n";
+
+$totalarray = array(
+	'nbfield' => 0,
+	'val' => array(
+		'p.total_ht' => 0,
+		'p.total_tva' => 0,
+		'p.total_ttc' => 0,
+	),
+);
+
+// Fields title
+print '<tr class="liste_titre">';
+if (getDolGlobalString('MAIN_CHECKBOX_LEFT_COLUMN')) {
+	print_liste_field_titre($selectedfields, $_SERVER["PHP_SELF"], "", '', '', 'align="center"', $sortfield, $sortorder, 'maxwidthsearch ');
+	$totalarray['nbfield']++;
+}
+if (!empty($arrayfields['p.ref']['checked'])) {
+	print_liste_field_titre($arrayfields['p.ref']['label'], $_SERVER["PHP_SELF"], 'p.ref', '', $param, '', $sortfield, $sortorder);
+	$totalarray['nbfield']++;
+}
+if (!empty($arrayfields['p.ref_client']['checked'])) {
+	print_liste_field_titre($arrayfields['p.ref_client']['label'], $_SERVER["PHP_SELF"], 'p.ref_client', '', $param, '', $sortfield, $sortorder);
+	$totalarray['nbfield']++;
+}
+if (!empty($arrayfields['pr.ref']['checked'])) {
+	print_liste_field_titre($arrayfields['pr.ref']['label'], $_SERVER["PHP_SELF"], 'pr.ref', '', $param, '', $sortfield, $sortorder);
+	$totalarray['nbfield']++;
+}
+if (!empty($arrayfields['pr.title']['checked'])) {
+	print_liste_field_titre($arrayfields['pr.title']['label'], $_SERVER["PHP_SELF"], 'pr.title', '', $param, '', $sortfield, $sortorder);
+	$totalarray['nbfield']++;
+}
+if (!empty($arrayfields['s.nom']['checked'])) {
+	print_liste_field_titre($arrayfields['s.nom']['label'], $_SERVER["PHP_SELF"], 's.nom', '', $param, '', $sortfield, $sortorder);
+	$totalarray['nbfield']++;
+}
+if (!empty($arrayfields['s.name_alias']['checked'])) {
+	print_liste_field_titre($arrayfields['s.name_alias']['label'], $_SERVER["PHP_SELF"], 's.name_alias', '', $param, '', $sortfield, $sortorder);
+	$totalarray['nbfield']++;
+}
+if (!empty($arrayfields['s.town']['checked'])) {
+	print_liste_field_titre($arrayfields['s.town']['label'], $_SERVER["PHP_SELF"], 's.town', '', $param, '', $sortfield, $sortorder);
+	$totalarray['nbfield']++;
+}
+if (!empty($arrayfields['s.zip']['checked'])) {
+	print_liste_field_titre($arrayfields['s.zip']['label'], $_SERVER["PHP_SELF"], 's.zip', '', $param, '', $sortfield, $sortorder);
+	$totalarray['nbfield']++;
+}
+if (!empty($arrayfields['state.nom']['checked'])) {
+	print_liste_field_titre($arrayfields['state.nom']['label'], $_SERVER["PHP_SELF"], "state.nom", "", $param, '', $sortfield, $sortorder);
+	$totalarray['nbfield']++;
+}
+if (!empty($arrayfields['country.code_iso']['checked'])) {
+	print_liste_field_titre($arrayfields['country.code_iso']['label'], $_SERVER["PHP_SELF"], "country.code_iso", "", $param, 'class="center"', $sortfield, $sortorder);
+	$totalarray['nbfield']++;
+}
+if (!empty($arrayfields['s.email']['checked'])) {
+	print_liste_field_titre($arrayfields['s.email']['label'], $_SERVER["PHP_SELF"], 's.email', '', $param, '', $sortfield, $sortorder);
+	$totalarray['nbfield']++;
+}
+if (!empty($arrayfields['s.phone']['checked'])) {
+	print_liste_field_titre($arrayfields['s.phone']['label'], $_SERVER["PHP_SELF"], 's.phone', '', $param, '', $sortfield, $sortorder);
+	$totalarray['nbfield']++;
+}
+if (!empty($arrayfields['typent.code']['checked'])) {
+	print_liste_field_titre($arrayfields['typent.code']['label'], $_SERVER["PHP_SELF"], "typent.code", "", $param, 'class="center"', $sortfield, $sortorder);
+	$totalarray['nbfield']++;
+}
+if (!empty($arrayfields['p.date']['checked'])) {
+	print_liste_field_titre($arrayfields['p.date']['label'], $_SERVER["PHP_SELF"], 'p.datep', '', $param, 'class="center"', $sortfield, $sortorder);
+	$totalarray['nbfield']++;
+}
+if (!empty($arrayfields['p.fin_validite']['checked'])) {
+	print_liste_field_titre($arrayfields['p.fin_validite']['label'], $_SERVER["PHP_SELF"], 'dfv', '', $param, 'class="center"', $sortfield, $sortorder);
+	$totalarray['nbfield']++;
+}
+if (!empty($arrayfields['p.date_livraison']['checked'])) {
+	print_liste_field_titre($arrayfields['p.date_livraison']['label'], $_SERVER["PHP_SELF"], 'p.date_livraison', '', $param, 'class="center"', $sortfield, $sortorder);
+	$totalarray['nbfield']++;
+}
+if (!empty($arrayfields['p.date_signature']['checked'])) {
+	print_liste_field_titre($arrayfields['p.date_signature']['label'], $_SERVER["PHP_SELF"], 'p.date_signature', '', $param, 'class="center"', $sortfield, $sortorder);
+	$totalarray['nbfield']++;
+}
+if (!empty($arrayfields['ava.rowid']['checked'])) {
+	print_liste_field_titre($arrayfields['ava.rowid']['label'], $_SERVER["PHP_SELF"], 'availability', '', $param, '', $sortfield, $sortorder);
+	$totalarray['nbfield']++;
+}
+if (!empty($arrayfields['p.fk_shipping_method']['checked'])) {
+	print_liste_field_titre($arrayfields['p.fk_shipping_method']['label'], $_SERVER["PHP_SELF"], "p.fk_shipping_method", "", $param, '', $sortfield, $sortorder);
+	$totalarray['nbfield']++;
+}
+if (!empty($arrayfields['p.fk_input_reason']['checked'])) {
+	print_liste_field_titre($arrayfields['p.fk_input_reason']['label'], $_SERVER["PHP_SELF"], "p.fk_input_reason", "", $param, '', $sortfield, $sortorder);
+	$totalarray['nbfield']++;
+}
+if (!empty($arrayfields['p.fk_cond_reglement']['checked'])) {
+	print_liste_field_titre($arrayfields['p.fk_cond_reglement']['label'], $_SERVER["PHP_SELF"], "p.fk_cond_reglement", "", $param, '', $sortfield, $sortorder);
+	$totalarray['nbfield']++;
+}
+if (!empty($arrayfields['p.fk_mode_reglement']['checked'])) {
+	print_liste_field_titre($arrayfields['p.fk_mode_reglement']['label'], $_SERVER["PHP_SELF"], "p.fk_mode_reglement", "", $param, '', $sortfield, $sortorder);
+	$totalarray['nbfield']++;
+}
+if (!empty($arrayfields['p.total_ht']['checked'])) {
+	print_liste_field_titre($arrayfields['p.total_ht']['label'], $_SERVER["PHP_SELF"], 'p.total_ht', '', $param, '', $sortfield, $sortorder, 'right ');
+	$totalarray['nbfield']++;
+}
+if (!empty($arrayfields['p.total_tva']['checked'])) {
+	print_liste_field_titre($arrayfields['p.total_tva']['label'], $_SERVER["PHP_SELF"], 'p.total_tva', '', $param, '', $sortfield, $sortorder, 'right ');
+	$totalarray['nbfield']++;
+}
+if (!empty($arrayfields['p.total_ttc']['checked'])) {
+	print_liste_field_titre($arrayfields['p.total_ttc']['label'], $_SERVER["PHP_SELF"], 'p.total_ttc', '', $param, '', $sortfield, $sortorder, 'right ');
+	$totalarray['nbfield']++;
+}
+if (!empty($arrayfields['p.total_ht_invoiced']['checked'])) {
+	print_liste_field_titre($arrayfields['p.total_ht_invoiced']['label'], $_SERVER["PHP_SELF"], '', '', $param, '', $sortfield, $sortorder, 'right ');
+	$totalarray['nbfield']++;
+}
+if (!empty($arrayfields['p.total_invoiced']['checked'])) {
+	print_liste_field_titre($arrayfields['p.total_invoiced']['label'], $_SERVER["PHP_SELF"], '', '', $param, '', $sortfield, $sortorder, 'right ');
+	$totalarray['nbfield']++;
+}
+if (!empty($arrayfields['p.multicurrency_code']['checked'])) {
+	print_liste_field_titre($arrayfields['p.multicurrency_code']['label'], $_SERVER['PHP_SELF'], 'p.multicurrency_code', '', $param, '', $sortfield, $sortorder);
+	$totalarray['nbfield']++;
+}
+if (!empty($arrayfields['p.multicurrency_tx']['checked'])) {
+	print_liste_field_titre($arrayfields['p.multicurrency_tx']['label'], $_SERVER['PHP_SELF'], 'p.multicurrency_tx', '', $param, '', $sortfield, $sortorder);
+	$totalarray['nbfield']++;
+}
+if (!empty($arrayfields['p.multicurrency_total_ht']['checked'])) {
+	print_liste_field_titre($arrayfields['p.multicurrency_total_ht']['label'], $_SERVER['PHP_SELF'], 'p.multicurrency_total_ht', '', $param, '', $sortfield, $sortorder, 'right ');
+	$totalarray['nbfield']++;
+}
+if (!empty($arrayfields['p.multicurrency_total_tva']['checked'])) {
+	print_liste_field_titre($arrayfields['p.multicurrency_total_tva']['label'], $_SERVER['PHP_SELF'], 'p.multicurrency_total_tva', '', $param, '', $sortfield, $sortorder, 'right ');
+	$totalarray['nbfield']++;
+}
+if (!empty($arrayfields['p.multicurrency_total_ttc']['checked'])) {
+	print_liste_field_titre($arrayfields['p.multicurrency_total_ttc']['label'], $_SERVER['PHP_SELF'], 'p.multicurrency_total_ttc', '', $param, '', $sortfield, $sortorder, 'right ');
+	$totalarray['nbfield']++;
+}
+if (!empty($arrayfields['p.multicurrency_total_ht_invoiced']['checked'])) {
+	print_liste_field_titre($arrayfields['p.multicurrency_total_ht_invoiced']['label'], $_SERVER["PHP_SELF"], '', '', $param, '', $sortfield, $sortorder, 'right ');
+	$totalarray['nbfield']++;
+}
+if (!empty($arrayfields['p.multicurrency_total_invoiced']['checked'])) {
+	print_liste_field_titre($arrayfields['p.multicurrency_total_invoiced']['label'], $_SERVER["PHP_SELF"], '', '', $param, '', $sortfield, $sortorder, 'right ');
+	$totalarray['nbfield']++;
+}
+if (!empty($arrayfields['u.login']['checked'])) {
+	print_liste_field_titre($arrayfields['u.login']['label'], $_SERVER["PHP_SELF"], 'u.login', '', $param, '', $sortfield, $sortorder, 'center ');
+	$totalarray['nbfield']++;
+}
+if (!empty($arrayfields['sale_representative']['checked'])) {
+	print_liste_field_titre($arrayfields['sale_representative']['label'], $_SERVER["PHP_SELF"], "", "", "$param", '', $sortfield, $sortorder);
+	$totalarray['nbfield']++;
+}
+if (!empty($arrayfields['total_pa']['checked'])) {
+	print_liste_field_titre($arrayfields['total_pa']['label'], $_SERVER['PHP_SELF'], '', '', $param, '', $sortfield, $sortorder, 'right ');
+	$totalarray['nbfield']++;
+}
+if (!empty($arrayfields['total_margin']['checked'])) {
+	print_liste_field_titre($arrayfields['total_margin']['label'], $_SERVER['PHP_SELF'], '', '', $param, '', $sortfield, $sortorder, 'right ');
+	$totalarray['nbfield']++;
+}
+if (!empty($arrayfields['total_margin_rate']['checked'])) {
+	print_liste_field_titre($arrayfields['total_margin_rate']['label'], $_SERVER['PHP_SELF'], '', '', $param, '', $sortfield, $sortorder, 'right ');
+	$totalarray['nbfield']++;
+}
+if (!empty($arrayfields['total_mark_rate']['checked'])) {
+	print_liste_field_titre($arrayfields['total_mark_rate']['label'], $_SERVER['PHP_SELF'], '', '', $param, '', $sortfield, $sortorder, 'right ');
+	$totalarray['nbfield']++;
+}
+// Extra fields
+include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_list_search_title.tpl.php';
+// Hook fields
+$parameters = array(
+	'arrayfields' => $arrayfields,
+	'param' => $param,
+	'sortfield' => $sortfield,
+	'sortorder' => $sortorder,
+	'totalarray' => &$totalarray,
+);
 
-				$totalInvoicedHT += $invoice->total_ht;
-				$totalInvoicedTTC += $invoice->total_ttc;
-				$multicurrency_totalInvoicedHT += $invoice->multicurrency_total_ht;
-				$multicurrency_totalInvoicedTTC += $invoice->multicurrency_total_ttc;
+$reshook = $hookmanager->executeHooks('printFieldListTitle', $parameters, $object, $action); // Note that $action and $object may have been modified by hook
+
+print $hookmanager->resPrint;
+if (!empty($arrayfields['p.datec']['checked'])) {
+	print_liste_field_titre($arrayfields['p.datec']['label'], $_SERVER["PHP_SELF"], "p.datec", "", $param, '', $sortfield, $sortorder, 'center nowraponall ');
+	$totalarray['nbfield']++;
+}
+if (!empty($arrayfields['p.tms']['checked'])) {
+	print_liste_field_titre($arrayfields['p.tms']['label'], $_SERVER["PHP_SELF"], "p.tms", "", $param, '', $sortfield, $sortorder, 'center nowraponall ');
+	$totalarray['nbfield']++;
+}
+if (!empty($arrayfields['p.date_cloture']['checked'])) {
+	print_liste_field_titre($arrayfields['p.date_cloture']['label'], $_SERVER["PHP_SELF"], "p.date_cloture", "", $param, 'align="center" class="nowrap"', $sortfield, $sortorder);
+	$totalarray['nbfield']++;
+}
+if (!empty($arrayfields['p.note_public']['checked'])) {
+	print_liste_field_titre($arrayfields['p.note_public']['label'], $_SERVER["PHP_SELF"], "p.note_public", "", $param, '', $sortfield, $sortorder, 'center nowrap ');
+	$totalarray['nbfield']++;
+}
+if (!empty($arrayfields['p.note_private']['checked'])) {
+	print_liste_field_titre($arrayfields['p.note_private']['label'], $_SERVER["PHP_SELF"], "p.note_private", "", $param, '', $sortfield, $sortorder, 'center nowrap ');
+	$totalarray['nbfield']++;
+}
+if (!empty($arrayfields['p.fk_statut']['checked'])) {
+	print_liste_field_titre($arrayfields['p.fk_statut']['label'], $_SERVER["PHP_SELF"], "p.fk_statut", "", $param, '', $sortfield, $sortorder, 'center ');
+	$totalarray['nbfield']++;
+}
+if (!getDolGlobalString('MAIN_CHECKBOX_LEFT_COLUMN')) {
+	print_liste_field_titre($selectedfields, $_SERVER["PHP_SELF"], "", '', '', 'align="center"', $sortfield, $sortorder, 'maxwidthsearch ');
+	$totalarray['nbfield']++;
+}
+print '</tr>'."\n";
+
+// Loop on record
+// --------------------------------------------------------------------
+$typenArray = null;
+$now = dol_now();
+
+$with_margin_info = false;
+if (isModEnabled('margin') && (
+	!empty($arrayfields['total_pa']['checked'])
+	|| !empty($arrayfields['total_margin']['checked'])
+	|| !empty($arrayfields['total_margin_rate']['checked'])
+	|| !empty($arrayfields['total_mark_rate']['checked'])
+)
+) {
+	$with_margin_info = true;
+}
+$total_ht = 0;
+$total_margin = 0;
+
+$i = 0;
+$savnbfield = $totalarray['nbfield'];
+$totalarray = array();
+$totalarray['nbfield'] = 0;
+$imaxinloop = ($limit ? min($num, $limit) : $num);
+while ($i < $imaxinloop) {
+	$obj = $db->fetch_object($resql);
+	if (empty($obj)) {
+		break; // Should not happen
+	}
+
+	$objectstatic->id = $obj->rowid;
+	$objectstatic->ref = $obj->ref;
+	$objectstatic->ref_client = $obj->ref_client;
+	$objectstatic->note_public = $obj->note_public;
+	$objectstatic->note_private = $obj->note_private;
+	$objectstatic->statut = $obj->status;
+	$objectstatic->status = $obj->status;
+
+	$companystatic->id = $obj->socid;
+	$companystatic->name = $obj->name;
+	$companystatic->name_alias = $obj->alias;
+	$companystatic->client = $obj->client;
+	$companystatic->fournisseur = $obj->fournisseur;
+	$companystatic->code_client = $obj->code_client;
+	$companystatic->email = $obj->email;
+	$companystatic->phone = $obj->phone;
+	$companystatic->address = $obj->address;
+	$companystatic->zip = $obj->zip;
+	$companystatic->town = $obj->town;
+	$companystatic->country_code = $obj->country_code;
+
+	$projectstatic->id = $obj->project_id;
+	$projectstatic->ref = $obj->project_ref;
+	$projectstatic->title = $obj->project_label;
+
+	$totalInvoicedHT = 0;
+	$totalInvoicedTTC = 0;
+	$multicurrency_totalInvoicedHT = 0;
+	$multicurrency_totalInvoicedTTC = 0;
+
+	$TInvoiceData = $objectstatic->InvoiceArrayList($obj->rowid);
+
+	if (!empty($TInvoiceData)) {
+		foreach ($TInvoiceData as $invoiceData) {
+			$invoice = new Facture($db);
+			$invoice->fetch($invoiceData->facid);
+
+			if (getDolGlobalString('FACTURE_DEPOSITS_ARE_JUST_PAYMENTS') && $invoice->type == Facture::TYPE_DEPOSIT) {
+				continue;
 			}
+
+			$totalInvoicedHT += $invoice->total_ht;
+			$totalInvoicedTTC += $invoice->total_ttc;
+			$multicurrency_totalInvoicedHT += $invoice->multicurrency_total_ht;
+			$multicurrency_totalInvoicedTTC += $invoice->multicurrency_total_ttc;
 		}
+	}
+
+	$marginInfo = array();
+	if ($with_margin_info === true) {
+		$objectstatic->fetch_lines();
+		$marginInfo = $formmargin->getMarginInfosArray($objectstatic);
+		$total_ht += $obj->total_ht;
+		$total_margin += $marginInfo['total_margin'];
+	}
 
-		$marginInfo = array();
-		if ($with_margin_info === true) {
-			$objectstatic->fetch_lines();
-			$marginInfo = $formmargin->getMarginInfosArray($objectstatic);
-			$total_ht += $obj->total_ht;
-			$total_margin += $marginInfo['total_margin'];
+	if ($mode == 'kanban') {
+		if ($i == 0) {
+			print '<tr class="trkanban"><td colspan="'.$savnbfield.'">';
+			print '<div class="box-flex-container kanban">';
+		}
+		// Output Kanban
+		$userstatic->fetch($obj->fk_user_author);
+		$arrayofparams = array('selected' => in_array($object->id, $arrayofselected), 'authorlink' => $userstatic->getNomUrl(-2), 'projectlink' => $projectstatic->getNomUrl(2));
+		print $objectstatic->getKanbanView('', $arrayofparams);
+		if ($i == ($imaxinloop - 1)) {
+			print '</div>';
+			print '</td></tr>';
 		}
+	} else {
+		print '<tr class="oddeven">';
 
-		if ($mode == 'kanban') {
-			if ($i == 0) {
-				print '<tr class="trkanban"><td colspan="'.$savnbfield.'">';
-				print '<div class="box-flex-container kanban">';
+		// Action column
+		if (getDolGlobalString('MAIN_CHECKBOX_LEFT_COLUMN')) {
+			print '<td class="nowrap" align="center">';
+			if ($massactionbutton || $massaction) {   // If we are in select mode (massactionbutton defined) or if we have already selected and sent an action ($massaction) defined
+				$selected = 0;
+				if (in_array($obj->rowid, $arrayofselected)) {
+					$selected = 1;
+				}
+				print '<input id="cb'.$obj->rowid.'" class="flat checkforselect" type="checkbox" name="toselect[]" value="'.$obj->rowid.'"'.($selected ? ' checked="checked"' : '').'>';
 			}
-			// Output Kanban
-			$userstatic->fetch($obj->fk_user_author);
-			$arrayofparams = array('selected' => in_array($object->id, $arrayofselected), 'authorlink' => $userstatic->getNomUrl(-2), 'projectlink' => $projectstatic->getNomUrl(2));
-			print $objectstatic->getKanbanView('', $arrayofparams);
-			if ($i == ($imaxinloop - 1)) {
-				print '</div>';
-				print '</td></tr>';
+			print '</td>';
+			if (!$i) {
+				$totalarray['nbfield']++;
 			}
-		} else {
-			print '<tr class="oddeven">';
-
-			// Action column
-			if (getDolGlobalString('MAIN_CHECKBOX_LEFT_COLUMN')) {
-				print '<td class="nowrap" align="center">';
-				if ($massactionbutton || $massaction) {   // If we are in select mode (massactionbutton defined) or if we have already selected and sent an action ($massaction) defined
-					$selected = 0;
-					if (in_array($obj->rowid, $arrayofselected)) {
-						$selected = 1;
-					}
-					print '<input id="cb'.$obj->rowid.'" class="flat checkforselect" type="checkbox" name="toselect[]" value="'.$obj->rowid.'"'.($selected ? ' checked="checked"' : '').'>';
-				}
+		}
+
+		if (!empty($arrayfields['p.ref']['checked'])) {
+			print '<td class="nowraponall">';
+
+			print '<table class="nobordernopadding"><tr class="nocellnopadd">';
+			// Picto + Ref
+			print '<td class="nobordernopadding nowraponall">';
+			print $objectstatic->getNomUrl(1, '', '', 0, 1, (isset($conf->global->PROPAL_LIST_SHOW_NOTES) ? $conf->global->PROPAL_LIST_SHOW_NOTES : 1));
+			print '</td>';
+			// Warning
+			$warnornote = '';
+			if ($obj->status == Propal::STATUS_VALIDATED && $db->jdate($obj->dfv) < ($now - $conf->propal->cloture->warning_delay)) {
+				$warnornote .= img_warning($langs->trans("Late"));
+			}
+			if ($warnornote) {
+				print '<td style="min-width: 20px" class="nobordernopadding nowrap">';
+				print $warnornote;
 				print '</td>';
-				if (!$i) {
-					$totalarray['nbfield']++;
-				}
 			}
+			// Other picto tool
+			print '<td width="16" class="nobordernopadding right">';
+			$filename = dol_sanitizeFileName($obj->ref);
+			$filedir = $conf->propal->multidir_output[$obj->propal_entity].'/'.dol_sanitizeFileName($obj->ref);
+			$urlsource = $_SERVER['PHP_SELF'].'?id='.$obj->rowid;
+			print $formfile->getDocumentsLink($objectstatic->element, $filename, $filedir);
+			print '</td></tr></table>';
+
+			print "</td>\n";
+			if (!$i) {
+				$totalarray['nbfield']++;
+			}
+		}
 
-			if (!empty($arrayfields['p.ref']['checked'])) {
-				print '<td class="nowraponall">';
+		if (!empty($arrayfields['p.ref_client']['checked'])) {
+			// Customer ref
+			print '<td class="nowrap tdoverflowmax200">';
+			print dol_escape_htmltag($obj->ref_client);
+			print '</td>';
+			if (!$i) {
+				$totalarray['nbfield']++;
+			}
+		}
 
-				print '<table class="nobordernopadding"><tr class="nocellnopadd">';
-				// Picto + Ref
-				print '<td class="nobordernopadding nowraponall">';
-				print $objectstatic->getNomUrl(1, '', '', 0, 1, (isset($conf->global->PROPAL_LIST_SHOW_NOTES) ? $conf->global->PROPAL_LIST_SHOW_NOTES : 1));
-				print '</td>';
-				// Warning
-				$warnornote = '';
-				if ($obj->status == Propal::STATUS_VALIDATED && $db->jdate($obj->dfv) < ($now - $conf->propal->cloture->warning_delay)) {
-					$warnornote .= img_warning($langs->trans("Late"));
-				}
-				if ($warnornote) {
-					print '<td style="min-width: 20px" class="nobordernopadding nowrap">';
-					print $warnornote;
-					print '</td>';
-				}
-				// Other picto tool
-				print '<td width="16" class="nobordernopadding right">';
-				$filename = dol_sanitizeFileName($obj->ref);
-				$filedir = $conf->propal->multidir_output[$obj->propal_entity].'/'.dol_sanitizeFileName($obj->ref);
-				$urlsource = $_SERVER['PHP_SELF'].'?id='.$obj->rowid;
-				print $formfile->getDocumentsLink($objectstatic->element, $filename, $filedir);
-				print '</td></tr></table>';
-
-				print "</td>\n";
-				if (!$i) {
-					$totalarray['nbfield']++;
-				}
+		if (!empty($arrayfields['pr.ref']['checked'])) {
+			// Project ref
+			print '<td class="nowraponall">';
+			if ($obj->project_id > 0) {
+				print $projectstatic->getNomUrl(1);
 			}
+			print '</td>';
+			if (!$i) {
+				$totalarray['nbfield']++;
+			}
+		}
 
-			if (!empty($arrayfields['p.ref_client']['checked'])) {
-				// Customer ref
-				print '<td class="nowrap tdoverflowmax200">';
-				print dol_escape_htmltag($obj->ref_client);
-				print '</td>';
-				if (!$i) {
-					$totalarray['nbfield']++;
-				}
+		if (!empty($arrayfields['pr.title']['checked'])) {
+			// Project label
+			print '<td class="nowrap">';
+			if ($obj->project_id > 0) {
+				print dol_escape_htmltag($projectstatic->title);
+			}
+			print '</td>';
+			if (!$i) {
+				$totalarray['nbfield']++;
 			}
+		}
 
-			if (!empty($arrayfields['pr.ref']['checked'])) {
-				// Project ref
-				print '<td class="nowraponall">';
-				if ($obj->project_id > 0) {
-					print $projectstatic->getNomUrl(1);
-				}
-				print '</td>';
-				if (!$i) {
-					$totalarray['nbfield']++;
-				}
+		// Thirdparty
+		if (!empty($arrayfields['s.nom']['checked'])) {
+			print '<td class="tdoverflowmax150">';
+			print $companystatic->getNomUrl(1, 'customer', 0, 0, 1, empty($arrayfields['s.name_alias']['checked']) ? 0 : 1);
+			print '</td>';
+			if (!$i) {
+				$totalarray['nbfield']++;
 			}
+		}
 
-			if (!empty($arrayfields['pr.title']['checked'])) {
-				// Project label
-				print '<td class="nowrap">';
-				if ($obj->project_id > 0) {
-					print dol_escape_htmltag($projectstatic->title);
-				}
-				print '</td>';
-				if (!$i) {
-					$totalarray['nbfield']++;
-				}
+		// Alias
+		if (!empty($arrayfields['s.name_alias']['checked'])) {
+			print '<td class="tdoverflowmax200">';
+			print $obj->alias;
+			print '</td>';
+			if (!$i) {
+				$totalarray['nbfield']++;
 			}
+		}
 
-			// Thirdparty
-			if (!empty($arrayfields['s.nom']['checked'])) {
-				print '<td class="tdoverflowmax150">';
-				print $companystatic->getNomUrl(1, 'customer', 0, 0, 1, empty($arrayfields['s.name_alias']['checked']) ? 0 : 1);
-				print '</td>';
-				if (!$i) {
-					$totalarray['nbfield']++;
-				}
+		// Town
+		if (!empty($arrayfields['s.town']['checked'])) {
+			print '<td class="tdoverflowmax100" title="'.dol_escape_htmltag($obj->town).'">';
+			print dol_escape_htmltag($obj->town);
+			print '</td>';
+			if (!$i) {
+				$totalarray['nbfield']++;
+			}
+		}
+		// Zip
+		if (!empty($arrayfields['s.zip']['checked'])) {
+			print '<td class="nocellnopadd">';
+			print $obj->zip;
+			print '</td>';
+			if (!$i) {
+				$totalarray['nbfield']++;
+			}
+		}
+		// State
+		if (!empty($arrayfields['state.nom']['checked'])) {
+			print "<td>".$obj->state_name."</td>\n";
+			if (!$i) {
+				$totalarray['nbfield']++;
+			}
+		}
+		// Country
+		if (!empty($arrayfields['country.code_iso']['checked'])) {
+			print '<td class="center">';
+			$tmparray = getCountry($obj->fk_pays, 'all');
+			print $tmparray['label'];
+			print '</td>';
+			if (!$i) {
+				$totalarray['nbfield']++;
+			}
+		}
+		// Email (MMI Hack)
+		if (!empty($arrayfields['s.email']['checked'])) {
+			print '<td class="nocellnopadd">';
+			print $obj->email;
+			print '</td>';
+			if (!$i) {
+				$totalarray['nbfield']++;
+			}
+		}
+		// Phone (MMI Hack)
+		if (!empty($arrayfields['s.phone']['checked'])) {
+			print '<td class="nocellnopadd">';
+			print $obj->phone;
+			print '</td>';
+			if (!$i) {
+				$totalarray['nbfield']++;
+			}
+		}
+		// Type ent
+		if (!empty($arrayfields['typent.code']['checked'])) {
+			if (!is_array($typenArray) || empty($typenArray)) {
+				$typenArray = $formcompany->typent_array(1);
 			}
 
-			// Alias
-			if (!empty($arrayfields['s.name_alias']['checked'])) {
-				print '<td class="tdoverflowmax200">';
-				print $obj->alias;
-				print '</td>';
-				if (!$i) {
-					$totalarray['nbfield']++;
-				}
+			print '<td class="center">';
+			print $typenArray[$obj->typent_code];
+			print '</td>';
+			if (!$i) {
+				$totalarray['nbfield']++;
 			}
+		}
 
-			// Town
-			if (!empty($arrayfields['s.town']['checked'])) {
-				print '<td class="tdoverflowmax100" title="'.dol_escape_htmltag($obj->town).'">';
-				print dol_escape_htmltag($obj->town);
-				print '</td>';
-				if (!$i) {
-					$totalarray['nbfield']++;
-				}
+		// Date proposal
+		if (!empty($arrayfields['p.date']['checked'])) {
+			print '<td class="center">';
+			print dol_print_date($db->jdate($obj->dp), 'day');
+			print "</td>\n";
+			if (!$i) {
+				$totalarray['nbfield']++;
 			}
-			// Zip
-			if (!empty($arrayfields['s.zip']['checked'])) {
-				print '<td class="nocellnopadd">';
-				print $obj->zip;
+		}
+
+		// Date end validity
+		if (!empty($arrayfields['p.fin_validite']['checked'])) {
+			if ($obj->dfv) {
+				print '<td class="center">'.dol_print_date($db->jdate($obj->dfv), 'day');
 				print '</td>';
-				if (!$i) {
-					$totalarray['nbfield']++;
-				}
+			} else {
+				print '<td>&nbsp;</td>';
 			}
-			// State
-			if (!empty($arrayfields['state.nom']['checked'])) {
-				print "<td>".$obj->state_name."</td>\n";
-				if (!$i) {
-					$totalarray['nbfield']++;
-				}
+			if (!$i) {
+				$totalarray['nbfield']++;
 			}
-			// Country
-			if (!empty($arrayfields['country.code_iso']['checked'])) {
-				print '<td class="center">';
-				$tmparray = getCountry($obj->fk_pays, 'all');
-				print $tmparray['label'];
+		}
+		// Date delivery
+		if (!empty($arrayfields['p.date_livraison']['checked'])) {
+			if ($obj->ddelivery) {
+				print '<td class="center">'.dol_print_date($db->jdate($obj->ddelivery), 'day');
 				print '</td>';
-				if (!$i) {
-					$totalarray['nbfield']++;
-				}
+			} else {
+				print '<td>&nbsp;</td>';
 			}
-			// Email (MMI Hack)
-			if (!empty($arrayfields['s.email']['checked'])) {
-				print '<td class="nocellnopadd">';
-				print $obj->email;
-				print '</td>';
-				if (!$i) {
-					$totalarray['nbfield']++;
-				}
+			if (!$i) {
+				$totalarray['nbfield']++;
 			}
-			// Phone (MMI Hack)
-			if (!empty($arrayfields['s.phone']['checked'])) {
-				print '<td class="nocellnopadd">';
-				print $obj->phone;
+		}
+		// Date Signature
+		if (!empty($arrayfields['p.date_signature']['checked'])) {
+			if ($obj->dsignature) {
+				print '<td class="center">'.dol_print_date($db->jdate($obj->dsignature), 'day');
 				print '</td>';
-				if (!$i) {
-					$totalarray['nbfield']++;
-				}
+			} else {
+				print '<td>&nbsp;</td>';
 			}
-			// Type ent
-			if (!empty($arrayfields['typent.code']['checked'])) {
-				if (!is_array($typenArray) || empty($typenArray)) {
-					$typenArray = $formcompany->typent_array(1);
-				}
-
-				print '<td class="center">';
-				print $typenArray[$obj->typent_code];
-				print '</td>';
-				if (!$i) {
-					$totalarray['nbfield']++;
-				}
+			if (!$i) {
+				$totalarray['nbfield']++;
 			}
-
-			// Date proposal
-			if (!empty($arrayfields['p.date']['checked'])) {
-				print '<td class="center">';
-				print dol_print_date($db->jdate($obj->dp), 'day');
-				print "</td>\n";
-				if (!$i) {
-					$totalarray['nbfield']++;
-				}
+		}
+		// Availability
+		if (!empty($arrayfields['ava.rowid']['checked'])) {
+			print '<td class="center">';
+			$form->form_availability('', $obj->availability, 'none', 1);
+			print '</td>';
+			if (!$i) {
+				$totalarray['nbfield']++;
 			}
-
-			// Date end validity
-			if (!empty($arrayfields['p.fin_validite']['checked'])) {
-				if ($obj->dfv) {
-					print '<td class="center">'.dol_print_date($db->jdate($obj->dfv), 'day');
-					print '</td>';
-				} else {
-					print '<td>&nbsp;</td>';
-				}
-				if (!$i) {
-					$totalarray['nbfield']++;
-				}
+		}
+		// Shipping Method
+		if (!empty($arrayfields['p.fk_shipping_method']['checked'])) {
+			print '<td>';
+			$form->formSelectShippingMethod('', $obj->fk_shipping_method, 'none', 1);
+			print '</td>';
+			if (!$i) {
+				$totalarray['nbfield']++;
 			}
-			// Date delivery
-			if (!empty($arrayfields['p.date_livraison']['checked'])) {
-				if ($obj->ddelivery) {
-					print '<td class="center">'.dol_print_date($db->jdate($obj->ddelivery), 'day');
-					print '</td>';
-				} else {
-					print '<td>&nbsp;</td>';
-				}
-				if (!$i) {
-					$totalarray['nbfield']++;
-				}
+		}
+		// Source - input reason
+		if (!empty($arrayfields['p.fk_input_reason']['checked'])) {
+			print '<td class="tdoverflowmax125" title="'.dol_escape_htmltag($form->cache_demand_reason[$obj->fk_input_reason]['label']).'">';
+			if ($obj->fk_input_reason > 0) {
+				print $form->cache_demand_reason[$obj->fk_input_reason]['label'];
 			}
-			// Date Signature
-			if (!empty($arrayfields['p.date_signature']['checked'])) {
-				if ($obj->dsignature) {
-					print '<td class="center">'.dol_print_date($db->jdate($obj->dsignature), 'day');
-					print '</td>';
-				} else {
-					print '<td>&nbsp;</td>';
-				}
-				if (!$i) {
-					$totalarray['nbfield']++;
-				}
+			print '</td>';
+			if (!$i) {
+				$totalarray['nbfield']++;
 			}
-			// Availability
-			if (!empty($arrayfields['ava.rowid']['checked'])) {
-				print '<td class="center">';
-				$form->form_availability('', $obj->availability, 'none', 1);
-				print '</td>';
-				if (!$i) {
-					$totalarray['nbfield']++;
-				}
+		}
+		// Payment terms
+		if (!empty($arrayfields['p.fk_cond_reglement']['checked'])) {
+			print '<td>';
+			$form->form_conditions_reglement($_SERVER['PHP_SELF'], $obj->fk_cond_reglement, 'none', 0, '', 1, $obj->deposit_percent);
+			print '</td>';
+			if (!$i) {
+				$totalarray['nbfield']++;
 			}
-			// Shipping Method
-			if (!empty($arrayfields['p.fk_shipping_method']['checked'])) {
-				print '<td>';
-				$form->formSelectShippingMethod('', $obj->fk_shipping_method, 'none', 1);
-				print '</td>';
-				if (!$i) {
-					$totalarray['nbfield']++;
-				}
+		}
+		// Payment mode
+		if (!empty($arrayfields['p.fk_mode_reglement']['checked'])) {
+			print '<td>';
+			$form->form_modes_reglement($_SERVER['PHP_SELF'], $obj->fk_mode_reglement, 'none', '', -1);
+			print '</td>';
+			if (!$i) {
+				$totalarray['nbfield']++;
 			}
-			// Source - input reason
-			if (!empty($arrayfields['p.fk_input_reason']['checked'])) {
-				print '<td class="tdoverflowmax125" title="'.dol_escape_htmltag($form->cache_demand_reason[$obj->fk_input_reason]['label']).'">';
-				if ($obj->fk_input_reason > 0) {
-					print $form->cache_demand_reason[$obj->fk_input_reason]['label'];
-				}
-				print '</td>';
-				if (!$i) {
-					$totalarray['nbfield']++;
-				}
+		}
+		// Amount HT
+		if (!empty($arrayfields['p.total_ht']['checked'])) {
+			print '<td class="nowrap right"><span class="amount">'.price($obj->total_ht)."</span></td>\n";
+			if (!$i) {
+				$totalarray['nbfield']++;
 			}
-			// Payment terms
-			if (!empty($arrayfields['p.fk_cond_reglement']['checked'])) {
-				print '<td>';
-				$form->form_conditions_reglement($_SERVER['PHP_SELF'], $obj->fk_cond_reglement, 'none', 0, '', 1, $obj->deposit_percent);
-				print '</td>';
-				if (!$i) {
-					$totalarray['nbfield']++;
-				}
+			if (!$i) {
+				$totalarray['pos'][$totalarray['nbfield']] = 'p.total_ht';
 			}
-			// Payment mode
-			if (!empty($arrayfields['p.fk_mode_reglement']['checked'])) {
-				print '<td>';
-				$form->form_modes_reglement($_SERVER['PHP_SELF'], $obj->fk_mode_reglement, 'none', '', -1);
-				print '</td>';
-				if (!$i) {
-					$totalarray['nbfield']++;
-				}
+			if (empty($totalarray['val']['p.total_ht'])) {
+				$totalarray['val']['p.total_ht'] = $obj->total_ht;
+			} else {
+				$totalarray['val']['p.total_ht'] += $obj->total_ht;
 			}
-			// Amount HT
-			if (!empty($arrayfields['p.total_ht']['checked'])) {
-				print '<td class="nowrap right"><span class="amount">'.price($obj->total_ht)."</span></td>\n";
-				if (!$i) {
-					$totalarray['nbfield']++;
-				}
-				if (!$i) {
-					$totalarray['pos'][$totalarray['nbfield']] = 'p.total_ht';
-				}
-				if (empty($totalarray['val']['p.total_ht'])) {
-					$totalarray['val']['p.total_ht'] = $obj->total_ht;
-				} else {
-					$totalarray['val']['p.total_ht'] += $obj->total_ht;
-				}
+		}
+		// Amount VAT
+		if (!empty($arrayfields['p.total_tva']['checked'])) {
+			print '<td class="nowrap right"><span class="amount">'.price($obj->total_tva)."</span></td>\n";
+			if (!$i) {
+				$totalarray['nbfield']++;
 			}
-			// Amount VAT
-			if (!empty($arrayfields['p.total_tva']['checked'])) {
-				print '<td class="nowrap right"><span class="amount">'.price($obj->total_tva)."</span></td>\n";
-				if (!$i) {
-					$totalarray['nbfield']++;
-				}
-				if (!$i) {
-					$totalarray['pos'][$totalarray['nbfield']] = 'p.total_tva';
-				}
-				if (empty($totalarray['val']['p.total_tva'])) {
-					$totalarray['val']['p.total_tva'] = $obj->total_tva;
-				} else {
-					$totalarray['val']['p.total_tva'] += $obj->total_tva;
-				}
+			if (!$i) {
+				$totalarray['pos'][$totalarray['nbfield']] = 'p.total_tva';
 			}
-			// Amount TTC
-			if (!empty($arrayfields['p.total_ttc']['checked'])) {
-				print '<td class="nowrap right"><span class="amount">'.price($obj->total_ttc)."</span></td>\n";
-				if (!$i) {
-					$totalarray['nbfield']++;
-				}
-				if (!$i) {
-					$totalarray['pos'][$totalarray['nbfield']] = 'p.total_ttc';
-				}
-				if (empty($totalarray['val']['p.total_ttc'])) {
-					$totalarray['val']['p.total_ttc'] = $obj->total_ttc;
-				} else {
-					$totalarray['val']['p.total_ttc'] += $obj->total_ttc;
-				}
+			if (empty($totalarray['val']['p.total_tva'])) {
+				$totalarray['val']['p.total_tva'] = $obj->total_tva;
+			} else {
+				$totalarray['val']['p.total_tva'] += $obj->total_tva;
 			}
-			// Amount invoiced HT
-			if (!empty($arrayfields['p.total_ht_invoiced']['checked'])) {
-				print '<td class="nowrap right"><span class="amount">'.price($totalInvoicedHT)."</span></td>\n";
-				if (!$i) {
-					$totalarray['nbfield']++;
-				}
-				if (!$i) {
-					$totalarray['pos'][$totalarray['nbfield']] = 'p.total_ht_invoiced';
-				}
-				if (empty($totalarray['val']['p.total_ht_invoiced'])) {
-					$totalarray['val']['p.total_ht_invoiced'] = $totalInvoicedHT;
-				} else {
-					$totalarray['val']['p.total_ht_invoiced'] += $totalInvoicedHT;
-				}
+		}
+		// Amount TTC
+		if (!empty($arrayfields['p.total_ttc']['checked'])) {
+			print '<td class="nowrap right"><span class="amount">'.price($obj->total_ttc)."</span></td>\n";
+			if (!$i) {
+				$totalarray['nbfield']++;
 			}
-			// Amount invoiced TTC
-			if (!empty($arrayfields['p.total_invoiced']['checked'])) {
-				print '<td class="nowrap right"><span class="amount">'.price($totalInvoicedTTC)."</span></td>\n";
-				if (!$i) {
-					$totalarray['nbfield']++;
-				}
-				if (!$i) {
-					$totalarray['pos'][$totalarray['nbfield']] = 'p.total_invoiced';
-				}
-				if (empty($totalarray['val']['p.total_invoiced'])) {
-					$totalarray['val']['p.total_invoiced'] = $totalInvoicedTTC;
-				} else {
-					$totalarray['val']['p.total_invoiced'] += $totalInvoicedTTC;
-				}
+			if (!$i) {
+				$totalarray['pos'][$totalarray['nbfield']] = 'p.total_ttc';
 			}
-			// Currency
-			if (!empty($arrayfields['p.multicurrency_code']['checked'])) {
-				print '<td class="nowrap">'.$obj->multicurrency_code.' - '.$langs->trans('Currency'.$obj->multicurrency_code)."</td>\n";
-				if (!$i) {
-					$totalarray['nbfield']++;
-				}
+			if (empty($totalarray['val']['p.total_ttc'])) {
+				$totalarray['val']['p.total_ttc'] = $obj->total_ttc;
+			} else {
+				$totalarray['val']['p.total_ttc'] += $obj->total_ttc;
 			}
-
-			// Currency rate
-			if (!empty($arrayfields['p.multicurrency_tx']['checked'])) {
-				print '<td class="nowrap">';
-				$form->form_multicurrency_rate($_SERVER['PHP_SELF'].'?id='.$obj->rowid, $obj->multicurrency_tx, 'none', $obj->multicurrency_code);
-				print "</td>\n";
-				if (!$i) {
-					$totalarray['nbfield']++;
-				}
+		}
+		// Amount invoiced HT
+		if (!empty($arrayfields['p.total_ht_invoiced']['checked'])) {
+			print '<td class="nowrap right"><span class="amount">'.price($totalInvoicedHT)."</span></td>\n";
+			if (!$i) {
+				$totalarray['nbfield']++;
 			}
-			// Amount HT
-			if (!empty($arrayfields['p.multicurrency_total_ht']['checked'])) {
-				print '<td class="right nowrap"><span class="amount">'.price($obj->multicurrency_total_ht)."</span></td>\n";
-				if (!$i) {
-					$totalarray['nbfield']++;
-				}
+			if (!$i) {
+				$totalarray['pos'][$totalarray['nbfield']] = 'p.total_ht_invoiced';
 			}
-			// Amount VAT
-			if (!empty($arrayfields['p.multicurrency_total_tva']['checked'])) {
-				print '<td class="right nowrap"><span class="amount">'.price($obj->multicurrency_total_tva)."</span></td>\n";
-				if (!$i) {
-					$totalarray['nbfield']++;
-				}
+			if (empty($totalarray['val']['p.total_ht_invoiced'])) {
+				$totalarray['val']['p.total_ht_invoiced'] = $totalInvoicedHT;
+			} else {
+				$totalarray['val']['p.total_ht_invoiced'] += $totalInvoicedHT;
 			}
-			// Amount TTC
-			if (!empty($arrayfields['p.multicurrency_total_ttc']['checked'])) {
-				print '<td class="right nowrap"><span class="amount">'.price($obj->multicurrency_total_ttc)."</span></td>\n";
-				if (!$i) {
-					$totalarray['nbfield']++;
-				}
+		}
+		// Amount invoiced TTC
+		if (!empty($arrayfields['p.total_invoiced']['checked'])) {
+			print '<td class="nowrap right"><span class="amount">'.price($totalInvoicedTTC)."</span></td>\n";
+			if (!$i) {
+				$totalarray['nbfield']++;
 			}
-			// Amount invoiced
-			if (!empty($arrayfields['p.multicurrency_total_ht_invoiced']['checked'])) {
-				print '<td class="nowrap right"><span class="amount">'.price($multicurrency_totalInvoicedHT)."</span></td>\n";
-				if (!$i) {
-					$totalarray['nbfield']++;
-				}
+			if (!$i) {
+				$totalarray['pos'][$totalarray['nbfield']] = 'p.total_invoiced';
 			}
-			// Amount invoiced
-			if (!empty($arrayfields['p.multicurrency_total_invoiced']['checked'])) {
-				print '<td class="nowrap right"><span class="amount">'.price($multicurrency_totalInvoicedTTC)."</span></td>\n";
-				if (!$i) {
-					$totalarray['nbfield']++;
-				}
+			if (empty($totalarray['val']['p.total_invoiced'])) {
+				$totalarray['val']['p.total_invoiced'] = $totalInvoicedTTC;
+			} else {
+				$totalarray['val']['p.total_invoiced'] += $totalInvoicedTTC;
+			}
+		}
+		// Currency
+		if (!empty($arrayfields['p.multicurrency_code']['checked'])) {
+			print '<td class="nowrap">'.$obj->multicurrency_code.' - '.$langs->trans('Currency'.$obj->multicurrency_code)."</td>\n";
+			if (!$i) {
+				$totalarray['nbfield']++;
 			}
+		}
+		// Currency rate
+		if (!empty($arrayfields['p.multicurrency_tx']['checked'])) {
+			print '<td class="nowrap">';
+			$form->form_multicurrency_rate($_SERVER['PHP_SELF'].'?id='.$obj->rowid, $obj->multicurrency_tx, 'none', $obj->multicurrency_code);
+			print "</td>\n";
+			if (!$i) {
+				$totalarray['nbfield']++;
+			}
+		}
+		// Amount HT
+		if (!empty($arrayfields['p.multicurrency_total_ht']['checked'])) {
+			print '<td class="right nowrap"><span class="amount">'.price($obj->multicurrency_total_ht)."</span></td>\n";
+			if (!$i) {
+				$totalarray['nbfield']++;
+			}
+		}
+		// Amount VAT
+		if (!empty($arrayfields['p.multicurrency_total_tva']['checked'])) {
+			print '<td class="right nowrap"><span class="amount">'.price($obj->multicurrency_total_tva)."</span></td>\n";
+			if (!$i) {
+				$totalarray['nbfield']++;
+			}
+		}
+		// Amount TTC
+		if (!empty($arrayfields['p.multicurrency_total_ttc']['checked'])) {
+			print '<td class="right nowrap"><span class="amount">'.price($obj->multicurrency_total_ttc)."</span></td>\n";
+			if (!$i) {
+				$totalarray['nbfield']++;
+			}
+		}
+		// Amount invoiced
+		if (!empty($arrayfields['p.multicurrency_total_ht_invoiced']['checked'])) {
+			print '<td class="nowrap right"><span class="amount">'.price($multicurrency_totalInvoicedHT)."</span></td>\n";
+			if (!$i) {
+				$totalarray['nbfield']++;
+			}
+		}
+		// Amount invoiced
+		if (!empty($arrayfields['p.multicurrency_total_invoiced']['checked'])) {
+			print '<td class="nowrap right"><span class="amount">'.price($multicurrency_totalInvoicedTTC)."</span></td>\n";
+			if (!$i) {
+				$totalarray['nbfield']++;
+			}
+		}
 
-			$userstatic->id = $obj->fk_user_author;
-			$userstatic->login = $obj->login;
-			$userstatic->lastname = $obj->lastname;
-			$userstatic->firstname = $obj->firstname;
-			$userstatic->email = $obj->user_email;
-			$userstatic->statut = $obj->user_statut;
-			$userstatic->entity = $obj->user_entity;
-			$userstatic->photo = $obj->photo;
-			$userstatic->office_phone = $obj->office_phone;
-			$userstatic->office_fax = $obj->office_fax;
-			$userstatic->user_mobile = $obj->user_mobile;
-			$userstatic->job = $obj->job;
-			$userstatic->gender = $obj->gender;
-
-			// Author
-			if (!empty($arrayfields['u.login']['checked'])) {
-				print '<td class="tdoverflowmax150">';
-				if ($userstatic->id) {
-					print $userstatic->getNomUrl(-1);
-				}
-				print "</td>\n";
-				if (!$i) {
-					$totalarray['nbfield']++;
-				}
+		$userstatic->id = $obj->fk_user_author;
+		$userstatic->login = $obj->login;
+		$userstatic->lastname = $obj->lastname;
+		$userstatic->firstname = $obj->firstname;
+		$userstatic->email = $obj->user_email;
+		$userstatic->statut = $obj->user_statut;
+		$userstatic->entity = $obj->user_entity;
+		$userstatic->photo = $obj->photo;
+		$userstatic->office_phone = $obj->office_phone;
+		$userstatic->office_fax = $obj->office_fax;
+		$userstatic->user_mobile = $obj->user_mobile;
+		$userstatic->job = $obj->job;
+		$userstatic->gender = $obj->gender;
+
+		// Author
+		if (!empty($arrayfields['u.login']['checked'])) {
+			print '<td class="tdoverflowmax150">';
+			if ($userstatic->id) {
+				print $userstatic->getNomUrl(-1);
+			}
+			print "</td>\n";
+			if (!$i) {
+				$totalarray['nbfield']++;
 			}
+		}
 
-			if (!empty($arrayfields['sale_representative']['checked'])) {
-				// Sales representatives
-				print '<td class="tdoverflowmax125">';
-				if ($obj->socid > 0) {
-					$listsalesrepresentatives = $companystatic->getSalesRepresentatives($user);
-					if ($listsalesrepresentatives < 0) {
-						dol_print_error($db);
-					}
-					$nbofsalesrepresentative = count($listsalesrepresentatives);
-					if ($nbofsalesrepresentative > 6) {
-						// We print only number
-						print $nbofsalesrepresentative;
-					} elseif ($nbofsalesrepresentative > 0) {
-						$userstatic = new User($db);
-						$j = 0;
-						foreach ($listsalesrepresentatives as $val) {
-							$userstatic->id = $val['id'];
-							$userstatic->lastname = $val['lastname'];
-							$userstatic->firstname = $val['firstname'];
-							$userstatic->email = $val['email'];
-							$userstatic->statut = $val['statut'];
-							$userstatic->entity = $val['entity'];
-							$userstatic->photo = $val['photo'];
-							$userstatic->login = $val['login'];
-							$userstatic->office_phone = $val['office_phone'];
-							$userstatic->office_fax = $val['office_fax'];
-							$userstatic->user_mobile = $val['user_mobile'];
-							$userstatic->job = $val['job'];
-							$userstatic->gender = $val['gender'];
-							//print '<div class="float">':
-							print ($nbofsalesrepresentative < 2) ? $userstatic->getNomUrl(-1, '', 0, 0, 12) : $userstatic->getNomUrl(-2);
-							$j++;
-							if ($j < $nbofsalesrepresentative) {
-								print ' ';
-							}
-							//print '</div>';
+		if (!empty($arrayfields['sale_representative']['checked'])) {
+			// Sales representatives
+			print '<td class="tdoverflowmax125">';
+			if ($obj->socid > 0) {
+				$listsalesrepresentatives = $companystatic->getSalesRepresentatives($user);
+				if ($listsalesrepresentatives < 0) {
+					dol_print_error($db);
+				}
+				$nbofsalesrepresentative = count($listsalesrepresentatives);
+				if ($nbofsalesrepresentative > 6) {
+					// We print only number
+					print $nbofsalesrepresentative;
+				} elseif ($nbofsalesrepresentative > 0) {
+					$userstatic = new User($db);
+					$j = 0;
+					foreach ($listsalesrepresentatives as $val) {
+						$userstatic->id = $val['id'];
+						$userstatic->lastname = $val['lastname'];
+						$userstatic->firstname = $val['firstname'];
+						$userstatic->email = $val['email'];
+						$userstatic->statut = $val['statut'];
+						$userstatic->entity = $val['entity'];
+						$userstatic->photo = $val['photo'];
+						$userstatic->login = $val['login'];
+						$userstatic->office_phone = $val['office_phone'];
+						$userstatic->office_fax = $val['office_fax'];
+						$userstatic->user_mobile = $val['user_mobile'];
+						$userstatic->job = $val['job'];
+						$userstatic->gender = $val['gender'];
+						//print '<div class="float">':
+						print ($nbofsalesrepresentative < 2) ? $userstatic->getNomUrl(-1, '', 0, 0, 12) : $userstatic->getNomUrl(-2);
+						$j++;
+						if ($j < $nbofsalesrepresentative) {
+							print ' ';
 						}
+						//print '</div>';
 					}
-					//else print $langs->trans("NoSalesRepresentativeAffected");
-				} else {
-					print '&nbsp;';
-				}
-				print '</td>';
-				if (!$i) {
-					$totalarray['nbfield']++;
 				}
+				//else print $langs->trans("NoSalesRepresentativeAffected");
+			} else {
+				print '&nbsp;';
 			}
+			print '</td>';
+			if (!$i) {
+				$totalarray['nbfield']++;
+			}
+		}
 
-			// Total buying or cost price
-			if (!empty($arrayfields['total_pa']['checked'])) {
-				print '<td class="right nowrap">'.price($marginInfo['pa_total']).'</td>';
-				if (!$i) {
-					$totalarray['nbfield']++;
-				}
+		// Total buying or cost price
+		if (!empty($arrayfields['total_pa']['checked'])) {
+			print '<td class="right nowrap">'.price($marginInfo['pa_total']).'</td>';
+			if (!$i) {
+				$totalarray['nbfield']++;
 			}
-			// Total margin
-			if (!empty($arrayfields['total_margin']['checked'])) {
-				print '<td class="right nowrap">'.price($marginInfo['total_margin']).'</td>';
-				if (!$i) {
-					$totalarray['nbfield']++;
-				}
-				if (!$i) {
-					$totalarray['pos'][$totalarray['nbfield']] = 'total_margin';
-				}
-				$totalarray['val']['total_margin'] = $total_margin;
+		}
+		// Total margin
+		if (!empty($arrayfields['total_margin']['checked'])) {
+			print '<td class="right nowrap">'.price($marginInfo['total_margin']).'</td>';
+			if (!$i) {
+				$totalarray['nbfield']++;
 			}
-			// Total margin rate
-			if (!empty($arrayfields['total_margin_rate']['checked'])) {
-				print '<td class="right nowrap">'.(($marginInfo['total_margin_rate'] == '') ? '' : price($marginInfo['total_margin_rate'], null, null, null, null, 2).'%').'</td>';
-				if (!$i) {
-					$totalarray['nbfield']++;
-				}
+			if (!$i) {
+				$totalarray['pos'][$totalarray['nbfield']] = 'total_margin';
 			}
-			// Total mark rate
-			if (!empty($arrayfields['total_mark_rate']['checked'])) {
-				print '<td class="right nowrap">'.(($marginInfo['total_mark_rate'] == '') ? '' : price($marginInfo['total_mark_rate'], null, null, null, null, 2).'%').'</td>';
-				if (!$i) {
-					$totalarray['nbfield']++;
-				}
-				if (!$i) {
-					$totalarray['pos'][$totalarray['nbfield']] = 'total_mark_rate';
-				}
-				if ($i >= $imaxinloop - 1) {
-					if (!empty($total_ht)) {
-						$totalarray['val']['total_mark_rate'] = price2num($total_margin * 100 / $total_ht, 'MT');
-					} else {
-						$totalarray['val']['total_mark_rate'] = '';
-					}
+			$totalarray['val']['total_margin'] = $total_margin;
+		}
+		// Total margin rate
+		if (!empty($arrayfields['total_margin_rate']['checked'])) {
+			print '<td class="right nowrap">'.(($marginInfo['total_margin_rate'] == '') ? '' : price($marginInfo['total_margin_rate'], null, null, null, null, 2).'%').'</td>';
+			if (!$i) {
+				$totalarray['nbfield']++;
+			}
+		}
+		// Total mark rate
+		if (!empty($arrayfields['total_mark_rate']['checked'])) {
+			print '<td class="right nowrap">'.(($marginInfo['total_mark_rate'] == '') ? '' : price($marginInfo['total_mark_rate'], null, null, null, null, 2).'%').'</td>';
+			if (!$i) {
+				$totalarray['nbfield']++;
+			}
+			if (!$i) {
+				$totalarray['pos'][$totalarray['nbfield']] = 'total_mark_rate';
+			}
+			if ($i >= $imaxinloop - 1) {
+				if (!empty($total_ht)) {
+					$totalarray['val']['total_mark_rate'] = price2num($total_margin * 100 / $total_ht, 'MT');
+				} else {
+					$totalarray['val']['total_mark_rate'] = '';
 				}
 			}
+		}
 
-			// Extra fields
-			include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_list_print_fields.tpl.php';
-			// Fields from hook
-			$parameters = array('arrayfields'=>$arrayfields, 'obj'=>$obj, 'i'=>$i, 'totalarray'=>&$totalarray);
-			$reshook = $hookmanager->executeHooks('printFieldListValue', $parameters, $object, $action); // Note that $action and $object may have been modified by hook
-			print $hookmanager->resPrint;
-			// Date creation
-			if (!empty($arrayfields['p.datec']['checked'])) {
-				print '<td align="center" class="nowrap">';
-				print dol_print_date($db->jdate($obj->date_creation), 'dayhour', 'tzuser');
-				print '</td>';
-				if (!$i) {
-					$totalarray['nbfield']++;
-				}
+		// Extra fields
+		include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_list_print_fields.tpl.php';
+		// Fields from hook
+		$parameters = array('arrayfields'=>$arrayfields, 'obj'=>$obj, 'i'=>$i, 'totalarray'=>&$totalarray);
+		$reshook = $hookmanager->executeHooks('printFieldListValue', $parameters, $object, $action); // Note that $action and $object may have been modified by hook
+		print $hookmanager->resPrint;
+		// Date creation
+		if (!empty($arrayfields['p.datec']['checked'])) {
+			print '<td align="center" class="nowrap">';
+			print dol_print_date($db->jdate($obj->date_creation), 'dayhour', 'tzuser');
+			print '</td>';
+			if (!$i) {
+				$totalarray['nbfield']++;
 			}
-			// Date modification
-			if (!empty($arrayfields['p.tms']['checked'])) {
-				print '<td align="center" class="nowrap">';
-				print dol_print_date($db->jdate($obj->date_update), 'dayhour', 'tzuser');
-				print '</td>';
-				if (!$i) {
-					$totalarray['nbfield']++;
-				}
+		}
+		// Date modification
+		if (!empty($arrayfields['p.tms']['checked'])) {
+			print '<td align="center" class="nowrap">';
+			print dol_print_date($db->jdate($obj->date_update), 'dayhour', 'tzuser');
+			print '</td>';
+			if (!$i) {
+				$totalarray['nbfield']++;
 			}
-			// Date cloture
-			if (!empty($arrayfields['p.date_cloture']['checked'])) {
-				print '<td align="center" class="nowrap">';
-				print dol_print_date($db->jdate($obj->date_cloture), 'dayhour', 'tzuser');
-				print '</td>';
-				if (!$i) {
-					$totalarray['nbfield']++;
-				}
+		}
+		// Date cloture
+		if (!empty($arrayfields['p.date_cloture']['checked'])) {
+			print '<td align="center" class="nowrap">';
+			print dol_print_date($db->jdate($obj->date_cloture), 'dayhour', 'tzuser');
+			print '</td>';
+			if (!$i) {
+				$totalarray['nbfield']++;
 			}
-			// Note public
-			if (!empty($arrayfields['p.note_public']['checked'])) {
-				print '<td class="center">';
-				print dol_string_nohtmltag($obj->note_public);
-				print '</td>';
-				if (!$i) {
-					$totalarray['nbfield']++;
-				}
+		}
+		// Note public
+		if (!empty($arrayfields['p.note_public']['checked'])) {
+			print '<td class="center">';
+			print dol_string_nohtmltag($obj->note_public);
+			print '</td>';
+			if (!$i) {
+				$totalarray['nbfield']++;
 			}
-			// Note private
-			if (!empty($arrayfields['p.note_private']['checked'])) {
-				print '<td class="center">';
-				print dol_string_nohtmltag($obj->note_private);
-				print '</td>';
-				if (!$i) {
-					$totalarray['nbfield']++;
-				}
+		}
+		// Note private
+		if (!empty($arrayfields['p.note_private']['checked'])) {
+			print '<td class="center">';
+			print dol_string_nohtmltag($obj->note_private);
+			print '</td>';
+			if (!$i) {
+				$totalarray['nbfield']++;
 			}
-			// Status
-			if (!empty($arrayfields['p.fk_statut']['checked'])) {
-				print '<td class="nowrap center">'.$objectstatic->getLibStatut(5).'</td>';
-				if (!$i) {
-					$totalarray['nbfield']++;
-				}
+		}
+		// Status
+		if (!empty($arrayfields['p.fk_statut']['checked'])) {
+			print '<td class="nowrap center">'.$objectstatic->getLibStatut(5).'</td>';
+			if (!$i) {
+				$totalarray['nbfield']++;
 			}
-			// Action column
-			if (!getDolGlobalString('MAIN_CHECKBOX_LEFT_COLUMN')) {
-				print '<td class="nowrap" align="center">';
-				if ($massactionbutton || $massaction) {   // If we are in select mode (massactionbutton defined) or if we have already selected and sent an action ($massaction) defined
-					$selected = 0;
-					if (in_array($obj->rowid, $arrayofselected)) {
-						$selected = 1;
-					}
-					print '<input id="cb'.$obj->rowid.'" class="flat checkforselect" type="checkbox" name="toselect[]" value="'.$obj->rowid.'"'.($selected ? ' checked="checked"' : '').'>';
-				}
-				print '</td>';
-				if (!$i) {
-					$totalarray['nbfield']++;
-				}
+		}
+		// Action column
+		if (!getDolGlobalString('MAIN_CHECKBOX_LEFT_COLUMN')) {
+			print '<td class="nowrap" align="center">';
+			if ($massactionbutton || $massaction) {   // If we are in select mode (massactionbutton defined) or if we have already selected and sent an action ($massaction) defined
+				$selected = 0;
+				if (in_array($obj->rowid, $arrayofselected)) {
+					$selected = 1;
+				}
+				print '<input id="cb'.$obj->rowid.'" class="flat checkforselect" type="checkbox" name="toselect[]" value="'.$obj->rowid.'"'.($selected ? ' checked="checked"' : '').'>';
+			}
+			print '</td>';
+			if (!$i) {
+				$totalarray['nbfield']++;
 			}
-
-
-			print '</tr>'."\n";
 		}
 
-		$i++;
+
+		print '</tr>'."\n";
 	}
 
-	// Show total line
-	include DOL_DOCUMENT_ROOT.'/core/tpl/list_print_total.tpl.php';
+	$i++;
+}
 
-	// If no record found
-	if ($num == 0) {
-		$colspan = 1;
-		foreach ($arrayfields as $key => $val) {
-			if (!empty($val['checked'])) {
-				$colspan++;
-			}
+// Show total line
+include DOL_DOCUMENT_ROOT.'/core/tpl/list_print_total.tpl.php';
+
+// If no record found
+if ($num == 0) {
+	$colspan = 1;
+	foreach ($arrayfields as $key => $val) {
+		if (!empty($val['checked'])) {
+			$colspan++;
 		}
-		print '<tr><td colspan="'.$colspan.'"><span class="opacitymedium">'.$langs->trans("NoRecordFound").'</span></td></tr>';
 	}
+	print '<tr><td colspan="'.$colspan.'"><span class="opacitymedium">'.$langs->trans("NoRecordFound").'</span></td></tr>';
+}
 
-	$db->free($resql);
+$db->free($resql);
 
-	$parameters = array('arrayfields'=>$arrayfields, 'sql'=>$sql);
-	$reshook = $hookmanager->executeHooks('printFieldListFooter', $parameters, $object, $action); // Note that $action and $object may have been modified by hook
-	print $hookmanager->resPrint;
+$parameters = array('arrayfields'=>$arrayfields, 'sql'=>$sql);
+$reshook = $hookmanager->executeHooks('printFieldListFooter', $parameters, $object, $action); // Note that $action and $object may have been modified by hook
+print $hookmanager->resPrint;
 
-	print '</table>'."\n";
-	print '</div>'."\n";
+print '</table>'."\n";
+print '</div>'."\n";
 
-	print '</form>'."\n";
+print '</form>'."\n";
 
-	if (in_array('builddoc', array_keys($arrayofmassactions)) && ($nbtotalofrecords === '' || $nbtotalofrecords)) {
-		$hidegeneratedfilelistifempty = 1;
-		if ($massaction == 'builddoc' || $action == 'remove_file' || $show_files) {
-			$hidegeneratedfilelistifempty = 0;
-		}
+if (in_array('builddoc', array_keys($arrayofmassactions)) && ($nbtotalofrecords === '' || $nbtotalofrecords)) {
+	$hidegeneratedfilelistifempty = 1;
+	if ($massaction == 'builddoc' || $action == 'remove_file' || $show_files) {
+		$hidegeneratedfilelistifempty = 0;
+	}
 
-		require_once DOL_DOCUMENT_ROOT.'/core/class/html.formfile.class.php';
-		$formfile = new FormFile($db);
+	require_once DOL_DOCUMENT_ROOT.'/core/class/html.formfile.class.php';
+	$formfile = new FormFile($db);
 
-		// Show list of available documents
-		$urlsource = $_SERVER['PHP_SELF'].'?sortfield='.$sortfield.'&sortorder='.$sortorder;
-		$urlsource .= str_replace('&amp;', '&', $param);
+	// Show list of available documents
+	$urlsource = $_SERVER['PHP_SELF'].'?sortfield='.$sortfield.'&sortorder='.$sortorder;
+	$urlsource .= str_replace('&amp;', '&', $param);
 
-		$filedir = $diroutputmassaction;
-		$genallowed = $permissiontoread;
-		$delallowed = $permissiontoadd;
+	$filedir = $diroutputmassaction;
+	$genallowed = $permissiontoread;
+	$delallowed = $permissiontoadd;
 
-		print $formfile->showdocuments('massfilesarea_proposals', '', $filedir, $urlsource, 0, $delallowed, '', 1, 1, 0, 48, 1, $param, $title, '', '', '', null, $hidegeneratedfilelistifempty);
-	}
+	print $formfile->showdocuments('massfilesarea_proposals', '', $filedir, $urlsource, 0, $delallowed, '', 1, 1, 0, 48, 1, $param, $title, '', '', '', null, $hidegeneratedfilelistifempty);
+}
 
-	// End of page
-	llxFooter();
-	$db->close();
+// End of page
+llxFooter();
+$db->close();

+ 23 - 18
htdocs/commande/card.php

@@ -14,7 +14,7 @@
  * Copyright (C) 2015       Jean-François Ferry		<jfefe@aternatik.fr>
  * Copyright (C) 2018-2021  Frédéric France         <frederic.france@netlogic.fr>
  * Copyright (C) 2022	    Gauthier VERDOL     	<gauthier.verdol@atm-consulting.fr>
- * Copyright (C) 2023		Benjamin Falière		<benjamin.faliere@altairis.fr>
+ * Copyright (C) 2023-2024	Benjamin Falière		<benjamin.faliere@altairis.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
@@ -875,8 +875,8 @@ if (empty($reshook)) {
 					}
 				}
 
-				$tmpvat = price2num(preg_replace('/\s*\(.*\)/', '', $tva_tx));
-				$tmpprodvat = price2num(preg_replace('/\s*\(.*\)/', '', $prod->tva_tx));
+				$tmpvat = (float) price2num(preg_replace('/\s*\(.*\)/', '', $tva_tx));
+				$tmpprodvat = (float) price2num(preg_replace('/\s*\(.*\)/', '', $prod->tva_tx));
 
 				// Set unit price to use
 				if (!empty($price_ht) || $price_ht === '0') {
@@ -2797,20 +2797,24 @@ if ($action == 'create' && $usercancreate) {
 				print '<td class="titlefieldmiddle">' . $langs->transcountry("AmountLT1", $mysoc->country_code) . '</td>';
 				print '<td class="nowrap amountcard right">' . price($object->total_localtax1, '', $langs, 0, -1, -1, $conf->currency) . '</td>';
 				if (isModEnabled("multicurrency") && ($object->multicurrency_code && $object->multicurrency_code != $conf->currency)) {
-					print '<td class="nowrap amountcard right">' . price($object->total_localtax1, '', $langs, 0, -1, -1, $object->multicurrency_code) . '</td>';
+					$object->multicurrency_total_localtax1 = price2num($object->total_localtax1 * $object->multicurrency_tx, 'MT');
+
+					print '<td class="nowrap amountcard right">' . price($object->multicurrency_total_localtax1, '', $langs, 0, -1, -1, $object->multicurrency_code) . '</td>';
 				}
 				print '</tr>';
+			}
 
-				// Amount Local Taxes
-				if ($mysoc->localtax2_assuj == "1" || $object->total_localtax2 != 0) {
-					print '<tr>';
-					print '<td>' . $langs->transcountry("AmountLT2", $mysoc->country_code) . '</td>';
-					print '<td class="nowrap amountcard right">' . price($object->total_localtax2, '', $langs, 0, -1, -1, $conf->currency) . '</td>';
-					if (isModEnabled("multicurrency") && ($object->multicurrency_code && $object->multicurrency_code != $conf->currency)) {
-						print '<td class="nowrap amountcard right">' . price($object->total_localtax2, '', $langs, 0, -1, -1, $object->multicurrency_code) . '</td>';
-					}
-					print '</tr>';
+			// Amount Local Taxes
+			if ($mysoc->localtax2_assuj == "1" || $object->total_localtax2 != 0) {
+				print '<tr>';
+				print '<td>' . $langs->transcountry("AmountLT2", $mysoc->country_code) . '</td>';
+				print '<td class="nowrap amountcard right">' . price($object->total_localtax2, '', $langs, 0, -1, -1, $conf->currency) . '</td>';
+				if (isModEnabled("multicurrency") && ($object->multicurrency_code && $object->multicurrency_code != $conf->currency)) {
+					$object->multicurrency_total_localtax2 = price2num($object->total_localtax2 * $object->multicurrency_tx, 'MT');
+
+					print '<td class="nowrap amountcard right">' . price($object->multicurrency_total_localtax2, '', $langs, 0, -1, -1, $object->multicurrency_code) . '</td>';
 				}
+				print '</tr>';
 			}
 
 			print '<tr>';
@@ -2890,8 +2894,6 @@ if ($action == 'create' && $usercancreate) {
 				$object->printObjectLines($action, $mysoc, $soc, $lineid, 1);
 			}
 
-			$numlines = count($object->lines);
-
 			/*
 			 * Form to add new line
 			 */
@@ -2931,6 +2933,8 @@ if ($action == 'create' && $usercancreate) {
 			// Note that $action and $object may be modified by hook
 			$reshook = $hookmanager->executeHooks('addMoreActionsButtons', $parameters, $object, $action);
 			if (empty($reshook)) {
+				$numlines = count($object->lines);
+
 				// Reopen a closed order
 				if (($object->statut == Commande::STATUS_CLOSED || $object->statut == Commande::STATUS_CANCELED) && $usercancreate) {
 					print dolGetButtonAction('', $langs->trans('ReOpen'), 'default', $_SERVER["PHP_SELF"].'?action=reopen&amp;token='.newToken().'&amp;id='.$object->id, '');
@@ -2961,11 +2965,12 @@ if ($action == 'create' && $usercancreate) {
 				}
 
 				$arrayforbutaction = array();
-
 				// Create a purchase order
-				$arrayforbutaction[] = array('lang'=>'orders', 'enabled'=>(isModEnabled("supplier_order") && $object->statut > Commande::STATUS_DRAFT && $object->getNbOfServicesLines() > 0), 'perm'=>$usercancreatepurchaseorder, 'label'=>'AddPurchaseOrder', 'url'=>'/fourn/commande/card.php?action=create&amp;origin='.$object->element.'&amp;originid='.$object->id);
+				if (getDolGlobalInt('COMMANDE_DISABLE_ADD_PURCHASE_ORDER') == 0) {
+					$arrayforbutaction[] = array('lang'=>'orders', 'enabled'=>(isModEnabled("supplier_order") && $object->statut > Commande::STATUS_DRAFT && $object->getNbLinesProductOrServiceOnBuy(getDolGlobalInt('COMMANDE_ADD_PURCHASE_ORDER_IGNORE_FREE_PRODUCTS')) > 0), 'perm'=>$usercancreatepurchaseorder, 'label'=>'AddPurchaseOrder', 'url'=>'/fourn/commande/card.php?action=create&amp;origin='.$object->element.'&amp;originid='.$object->id);
+				}
 				/*if (isModEnabled("supplier_order") && $object->statut > Commande::STATUS_DRAFT && $object->getNbOfServicesLines() > 0) {
-					if ($usercancreatepurchaseorder) {
+					if ($usercancreatepurchaseorder) { isModEnabled("supplier_order") && $object->statut > Commande::STATUS_DRAFT && $object->getNbOfServicesLines() > 0
 						print dolGetButtonAction('', $langs->trans('AddPurchaseOrder'), 'default', DOL_URL_ROOT.'/fourn/commande/card.php?action=create&amp;origin='.$object->element.'&amp;originid='.$object->id, '');
 					}
 				}*/

+ 1 - 1
htdocs/commande/class/api_orders.class.php

@@ -300,7 +300,7 @@ class Orders extends DolibarrApi
 			throw new RestException(500, "Error creating order", array_merge(array($this->commande->error), $this->commande->errors));
 		}
 
-		return $this->commande->id;
+		return ((int) $this->commande->id);
 	}
 
 	/**

+ 41 - 53
htdocs/commande/class/commande.class.php

@@ -255,20 +255,6 @@ class Commande extends CommonOrder
 	 */
 	public $lines = array();
 
-	// Multicurrency
-	/**
-	 * @var int Currency ID
-	 */
-	public $fk_multicurrency;
-
-	/**
-	 * @var string multicurrency code
-	 */
-	public $multicurrency_code;
-	public $multicurrency_tx;
-	public $multicurrency_total_ht;
-	public $multicurrency_total_tva;
-	public $multicurrency_total_ttc;
 
 	//! key of module source when order generated from a dedicated module ('cashdesk', 'takepos', ...)
 	public $module_source;
@@ -3369,7 +3355,7 @@ class Commande extends CommonOrder
 		$sql .= " total_ht=".(isset($this->total_ht) ? $this->total_ht : "null").",";
 		$sql .= " total_ttc=".(isset($this->total_ttc) ? $this->total_ttc : "null").",";
 		$sql .= " fk_statut=".(isset($this->statut) ? $this->statut : "null").",";
-		$sql .= " fk_user_author=".(isset($this->user_author_id) ? $this->user_author_id : "null").",";
+		$sql .= " fk_user_modif=".(isset($user->id) ? $user->id : "null").",";
 		$sql .= " fk_user_valid=".((isset($this->user_validation_id) && $this->user_validation_id > 0) ? $this->user_validation_id : "null").",";
 		$sql .= " fk_projet=".(isset($this->fk_project) ? $this->fk_project : "null").",";
 		$sql .= " fk_cond_reglement=".(isset($this->cond_reglement_id) ? $this->cond_reglement_id : "null").",";
@@ -4395,20 +4381,20 @@ class OrderLine extends CommonOrderLine
 
 		$error = 0;
 
-		if (empty($this->id) && !empty($this->rowid)) {		// For backward compatibility
+		if (empty($this->id) && !empty($this->rowid)) {        // For backward compatibility
 			$this->id = $this->rowid;
 		}
 
 		// check if order line is not in a shipment line before deleting
-		$sqlCheckShipmentLine  = "SELECT";
+		$sqlCheckShipmentLine = "SELECT";
 		$sqlCheckShipmentLine .= " ed.rowid";
-		$sqlCheckShipmentLine .= " FROM ".MAIN_DB_PREFIX."expeditiondet ed";
-		$sqlCheckShipmentLine .= " WHERE ed.fk_origin_line = ".((int) $this->id);
+		$sqlCheckShipmentLine .= " FROM " . MAIN_DB_PREFIX . "expeditiondet ed";
+		$sqlCheckShipmentLine .= " WHERE ed.fk_origin_line = " . ((int) $this->id);
 
 		$resqlCheckShipmentLine = $this->db->query($sqlCheckShipmentLine);
 		if (!$resqlCheckShipmentLine) {
 			$error++;
-			$this->error    = $this->db->lasterror();
+			$this->error = $this->db->lasterror();
 			$this->errors[] = $this->error;
 		} else {
 			$langs->load('errors');
@@ -4416,56 +4402,58 @@ class OrderLine extends CommonOrderLine
 			if ($num > 0) {
 				$error++;
 				$objCheckShipmentLine = $this->db->fetch_object($resqlCheckShipmentLine);
-				$this->error = $langs->trans('ErrorRecordAlreadyExists').' : '.$langs->trans('ShipmentLine').' '.$objCheckShipmentLine->rowid;
+				$this->error = $langs->trans('ErrorRecordAlreadyExists') . ' : ' . $langs->trans('ShipmentLine') . ' ' . $objCheckShipmentLine->rowid;
 				$this->errors[] = $this->error;
 			}
 			$this->db->free($resqlCheckShipmentLine);
 		}
 		if ($error) {
-			dol_syslog(__METHOD__.'Error ; '.$this->error, LOG_ERR);
+			dol_syslog(__METHOD__ . 'Error ; ' . $this->error, LOG_ERR);
 			return -1;
 		}
 
 		$this->db->begin();
 
-		$sql = 'DELETE FROM '.MAIN_DB_PREFIX."commandedet WHERE rowid = ".((int) $this->id);
-
-		dol_syslog("OrderLine::delete", LOG_DEBUG);
-		$resql = $this->db->query($sql);
-		if ($resql) {
-			if (!$error && !$notrigger) {
-				// Call trigger
-				$result = $this->call_trigger('LINEORDER_DELETE', $user);
-				if ($result < 0) {
-					$error++;
-				}
-				// End call triggers
+		if (!$notrigger) {
+			// Call trigger
+			$result = $this->call_trigger('LINEORDER_DELETE', $user);
+			if ($result < 0) {
+				$error++;
 			}
+			// End call triggers
+		}
 
-			// Remove extrafields
-			if (!$error) {
-				$result = $this->deleteExtraFields();
-				if ($result < 0) {
-					$error++;
-					dol_syslog(get_class($this)."::delete error -4 ".$this->error, LOG_ERR);
-				}
-			}
+		if (!$error) {
+			$sql = 'DELETE FROM ' . MAIN_DB_PREFIX . "commandedet WHERE rowid = " . ((int) $this->id);
 
-			if (!$error) {
-				$this->db->commit();
-				return 1;
+			dol_syslog("OrderLine::delete", LOG_DEBUG);
+			$resql = $this->db->query($sql);
+			if (!$resql) {
+				$this->error = $this->db->lasterror();
+				$error++;
 			}
+		}
 
-			foreach ($this->errors as $errmsg) {
-				dol_syslog(get_class($this)."::delete ".$errmsg, LOG_ERR);
-				$this->error .= ($this->error ? ', '.$errmsg : $errmsg);
+		// Remove extrafields
+		if (!$error) {
+			$result = $this->deleteExtraFields();
+			if ($result < 0) {
+				$error++;
+				dol_syslog(get_class($this) . "::delete error -4 " . $this->error, LOG_ERR);
 			}
-			$this->db->rollback();
-			return -1 * $error;
-		} else {
-			$this->error = $this->db->lasterror();
-			return -1;
 		}
+
+		if (!$error) {
+			$this->db->commit();
+			return 1;
+		}
+
+		foreach ($this->errors as $errmsg) {
+			dol_syslog(get_class($this) . "::delete " . $errmsg, LOG_ERR);
+			$this->error .= ($this->error ? ', ' . $errmsg : $errmsg);
+		}
+		$this->db->rollback();
+		return -1 * $error;
 	}
 
 	/**

+ 1 - 3
htdocs/commande/list.php

@@ -485,6 +485,7 @@ if (empty($reshook)) {
 							$rang = ($nbOrders > 1) ? -1 : $lines[$i]->rang;
 							//there may already be rows from previous orders
 							if (!empty($createbills_onebythird)) {
+								$TFactThirdNbLines[$cmd->socid]++;
 								$rang = $TFactThirdNbLines[$cmd->socid];
 							}
 
@@ -520,9 +521,6 @@ if (empty($reshook)) {
 							);
 							if ($result > 0) {
 								$lineid = $result;
-								if (!empty($createbills_onebythird)) { //increment rang to keep order
-									$TFactThirdNbLines[$cmd->socid]++;
-								}
 							} else {
 								$lineid = 0;
 								$error++;

+ 1 - 1
htdocs/commande/list_det.php

@@ -860,7 +860,7 @@ if ($resql) {
 	include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_list_search_param.tpl.php';
 
 	// Add $param from hooks
-	$parameters = array();
+	$parameters = array('param' => &$param);
 	$reshook = $hookmanager->executeHooks('printFieldListSearchParam', $parameters, $object); // Note that $action and $object may have been modified by hook
 	$param .= $hookmanager->resPrint;
 

+ 1 - 1
htdocs/compta/bank/list.php

@@ -341,7 +341,7 @@ if ($show_files) {
 // Add $param from extra fields
 include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_list_search_param.tpl.php';
 // Add $param from hooks
-$parameters = array();
+$parameters = array('param' => &$param);
 $reshook = $hookmanager->executeHooks('printFieldListSearchParam', $parameters, $object, $action); // Note that $action and $object may have been modified by hook
 $param .= $hookmanager->resPrint;
 

+ 5 - 2
htdocs/compta/bank/releve.php

@@ -125,6 +125,7 @@ $foundnext = '';
 $sql = "SELECT b.num_releve as num";
 $sql .= " FROM ".MAIN_DB_PREFIX."bank as b";
 $sql .= " WHERE b.num_releve < '".$db->escape($numref)."'";
+$sql .= " AND b.num_releve <> ''";
 $sql .= " AND b.fk_account = ".((int) $object->id);
 $sql .= " ORDER BY b.num_releve DESC";
 $sql .= $db->plimit(1);
@@ -380,6 +381,7 @@ if (empty($numref)) {
 				$sql = "SELECT sum(b.amount) as amount";
 				$sql .= " FROM ".MAIN_DB_PREFIX."bank as b";
 				$sql .= " WHERE b.num_releve < '".$db->escape($objp->numr)."'";
+				$sql .= " AND b.num_releve <> ''";
 				$sql .= " AND b.fk_account = ".((int) $object->id);
 				$resql = $db->query($sql);
 				if ($resql) {
@@ -464,6 +466,7 @@ if (empty($numref)) {
 	$sql = "SELECT sum(b.amount) as amount";
 	$sql .= " FROM ".MAIN_DB_PREFIX."bank as b";
 	$sql .= " WHERE b.num_releve < '".$db->escape($numref)."'";
+	$sql .= " AND b.num_releve <> ''";
 	$sql .= " AND b.fk_account = ".((int) $object->id);
 
 	$resql = $db->query($sql);
@@ -529,10 +532,10 @@ if (empty($numref)) {
 			print '<a href="'.DOL_URL_ROOT.'/compta/bank/line.php?rowid='.$objp->rowid.'&account='.$object->id.'">';
 			$reg = array();
 			preg_match('/\((.+)\)/i', $objp->label, $reg); // Si texte entoure de parenthese on tente recherche de traduction
-			if ($reg[1] && $langs->trans($reg[1]) != $reg[1]) {
+			if (!empty($reg[1]) && $langs->trans($reg[1]) != $reg[1]) {
 				print $langs->trans($reg[1]);
 			} else {
-				print $objp->label;
+				print dol_escape_htmltag($objp->label);
 			}
 			print '</a>';
 

+ 1 - 0
htdocs/compta/bank/various_payment/list.php

@@ -40,6 +40,7 @@ $langs->loadLangs(array("compta", "banks", "bills", "accountancy"));
 $optioncss = GETPOST('optioncss', 'alpha');
 $mode      = GETPOST('mode', 'alpha');
 $massaction = GETPOST('massaction', 'aZ09');
+$toselect   = GETPOST('toselect', 'array'); // Array of ids of elements selected into a list
 $contextpage = GETPOST('contextpage', 'aZ') ? GETPOST('contextpage', 'aZ') : 'directdebitcredittransferlist'; // To manage different context of search
 
 $limit = GETPOST('limit', 'int') ? GETPOST('limit', 'int') : $conf->liste_limit;

+ 1 - 1
htdocs/compta/cashcontrol/cashcontrol_list.php

@@ -371,7 +371,7 @@ if ($optioncss != '') {
 // Add $param from extra fields
 include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_list_search_param.tpl.php';
 // Add $param from hooks
-$parameters = array();
+$parameters = array('param' => &$param);
 $reshook = $hookmanager->executeHooks('printFieldListSearchParam', $parameters, $object); // Note that $action and $object may have been modified by hook
 $param .= $hookmanager->resPrint;
 

+ 18 - 15
htdocs/compta/facture/card.php

@@ -12,7 +12,7 @@
  * Copyright (C) 2013       Jean-Francois FERRY     <jfefe@aternatik.fr>
  * Copyright (C) 2013-2014  Florian Henry           <florian.henry@open-concept.pro>
  * Copyright (C) 2013       Cédric Salvador         <csalvador@gpcsolutions.fr>
- * Copyright (C) 2014-2019  Ferran Marcet           <fmarcet@2byte.es>
+ * Copyright (C) 2014-2024  Ferran Marcet           <fmarcet@2byte.es>
  * Copyright (C) 2015-2016  Marcos García           <marcosgdf@gmail.com>
  * Copyright (C) 2018-2023  Frédéric France         <frederic.france@netlogic.fr>
  * Copyright (C) 2022       Gauthier VERDOL         <gauthier.verdol@atm-consulting.fr>
@@ -455,7 +455,7 @@ if (empty($reshook)) {
 
 		$object->date = $newdate;
 		$new_date_lim_reglement = $object->calculate_date_lim_reglement();
-		if ($new_date_lim_reglement > $old_date_lim_reglement) {
+		if ($new_date_lim_reglement) {
 			$object->date_lim_reglement = $new_date_lim_reglement;
 		}
 		if ($object->date_lim_reglement < $object->date) {
@@ -495,7 +495,7 @@ if (empty($reshook)) {
 		if (!$error) {
 			$old_date_lim_reglement = $object->date_lim_reglement;
 			$new_date_lim_reglement = $object->calculate_date_lim_reglement();
-			if ($new_date_lim_reglement > $old_date_lim_reglement) {
+			if ($new_date_lim_reglement) {
 				$object->date_lim_reglement = $new_date_lim_reglement;
 			}
 			if ($object->date_lim_reglement < $object->date) {
@@ -1634,7 +1634,7 @@ if (empty($reshook)) {
 									null,
 									0,
 									'',
-									1
+									(!empty($conf->global->MAIN_DEPOSIT_MULTI_TVA)?0:1)
 								);
 							}
 
@@ -4497,7 +4497,7 @@ if ($action == 'create') {
 			'remove_file',
 			'',
 			'no',
-			2
+			1
 		);
 	}
 
@@ -4990,22 +4990,25 @@ if ($action == 'create') {
 			print '<td class="titlefieldmiddle">' . $langs->transcountry("AmountLT1", $mysoc->country_code) . '</td>';
 			print '<td class="nowrap amountcard right">' . price($sign * $object->total_localtax1, '', $langs, 0, -1, -1, $conf->currency) . '</td>';
 			if (isModEnabled("multicurrency") && ($object->multicurrency_code && $object->multicurrency_code != $conf->currency)) {
-				print '<td class="nowrap amountcard right">' . price($sign * $object->total_localtax1, '', $langs, 0, -1, -1, $object->multicurrency_code) . '</td>';
+				$object->multicurrency_total_localtax1 = price2num($object->total_localtax1 * $object->multicurrency_tx, 'MT');
+
+				print '<td class="nowrap amountcard right">' . price($sign * $object->multicurrency_total_localtax1, '', $langs, 0, -1, -1, $object->multicurrency_code) . '</td>';
 			}
 			print '</tr>';
+		}
 
-			if (($mysoc->localtax2_assuj == "1" && $mysoc->useLocalTax(2)) || $object->total_localtax2 != 0) {
-				print '<tr>';
-				print '<td>' . $langs->transcountry("AmountLT2", $mysoc->country_code) . '</td>';
-				print '<td class="nowrap amountcard right">' . price($sign * $object->total_localtax2, '', $langs, 0, -1, -1, $conf->currency) . '</td>';
-				if (isModEnabled("multicurrency") && ($object->multicurrency_code && $object->multicurrency_code != $conf->currency)) {
-					print '<td class="nowrap amountcard right">' . price($sign * $object->total_localtax2, '', $langs, 0, -1, -1, $object->multicurrency_code) . '</td>';
-				}
-				print '</tr>';
+		if (($mysoc->localtax2_assuj == "1" && $mysoc->useLocalTax(2)) || $object->total_localtax2 != 0) {
+			print '<tr>';
+			print '<td>' . $langs->transcountry("AmountLT2", $mysoc->country_code) . '</td>';
+			print '<td class="nowrap amountcard right">' . price($sign * $object->total_localtax2, '', $langs, 0, -1, -1, $conf->currency) . '</td>';
+			if (isModEnabled("multicurrency") && ($object->multicurrency_code && $object->multicurrency_code != $conf->currency)) {
+				$object->multicurrency_total_localtax2 = price2num($object->total_localtax2 * $object->multicurrency_tx, 'MT');
+
+				print '<td class="nowrap amountcard right">' . price($sign * $object->multicurrency_total_localtax2, '', $langs, 0, -1, -1, $object->multicurrency_code) . '</td>';
 			}
+			print '</tr>';
 		}
 
-
 		// Add the revenue stamp
 		if ($selleruserevenustamp) {
 			print '<tr><td class="titlefieldmiddle">';

+ 1 - 1
htdocs/compta/facture/class/api_invoices.class.php

@@ -323,7 +323,7 @@ class Invoices extends DolibarrApi
 		if ($this->invoice->create(DolibarrApiAccess::$user, 0, (empty($request_data["date_lim_reglement"]) ? 0 : $request_data["date_lim_reglement"])) < 0) {
 			throw new RestException(500, "Error creating invoice", array_merge(array($this->invoice->error), $this->invoice->errors));
 		}
-		return $this->invoice->id;
+		return ((int) $this->invoice->id);
 	}
 
 	/**

+ 7 - 2
htdocs/compta/facture/class/facture.class.php

@@ -204,6 +204,7 @@ class Facture extends CommonInvoice
 
 	public $date_pointoftax;
 
+
 	/**
 	 * @var int Situation cycle reference number
 	 */
@@ -3154,7 +3155,7 @@ class Facture extends CommonInvoice
 	 *
 	 * @param	User	$user           Object user that validate
 	 * @param   string	$force_number	Reference to force on invoice
-	 * @param	int		$idwarehouse	Id of warehouse to use for stock decrease if option to decreasenon stock is on (0=no decrease)
+	 * @param	int		$idwarehouse	Id of warehouse to use for stock decrease if option to decrease on stock is on (0=no decrease)
 	 * @param	int		$notrigger		1=Does not execute triggers, 0= execute triggers
 	 * @param	int		$batch_rule		0=do not decrement batch, else batch rule to use, 1=take in batches ordered by sellby and eatby dates
 	 * @return	int						Return integer <0 if KO, 0=Nothing done because invoice is not a draft, >0 if OK
@@ -3369,6 +3370,10 @@ class Facture extends CommonInvoice
 							$mouvP = new MouvementStock($this->db);
 							$mouvP->origin = &$this;
 							$mouvP->setOrigin($this->element, $this->id);
+
+							// TODO If warehouseid has been set into invoice line, we should use this value in priority
+							// $idwarehouse = $this->lines[$i]->fk_warehouse;
+
 							// We decrease stock for product
 							if ($this->type == self::TYPE_CREDIT_NOTE) {
 								$result = $mouvP->reception($user, $this->lines[$i]->fk_product, $idwarehouse, $this->lines[$i]->qty, 0, $langs->trans("InvoiceValidatedInDolibarr", $num));
@@ -4030,7 +4035,7 @@ class Facture extends CommonInvoice
 				return -2;
 			}
 		} else {
-			$this->errors[]='status of invoice must be Draft to allow use of ->addline()';
+			$this->errors[] = 'status of invoice must be Draft to allow use of ->addline()';
 			dol_syslog(get_class($this)."::addline status of invoice must be Draft to allow use of ->addline()", LOG_ERR);
 			return -3;
 		}

+ 1 - 1
htdocs/compta/facture/invoicetemplate_list.php

@@ -518,7 +518,7 @@ if ($optioncss != '') {
 // Add $param from extra fields
 include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_list_search_param.tpl.php';
 // Add $param from hooks
-$parameters = array();
+$parameters = array('param' => &$param);
 $reshook = $hookmanager->executeHooks('printFieldListSearchParam', $parameters, $object); // Note that $action and $object may have been modified by hook
 $param .= $hookmanager->resPrint;
 

+ 2 - 2
htdocs/compta/facture/list.php

@@ -1188,7 +1188,7 @@ if (!empty($search_fac_rec_source_title)) {
 // Add $param from extra fields
 include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_list_search_param.tpl.php';
 // Add $param from hooks
-$parameters = array();
+$parameters = array('param' => &$param);
 $reshook = $hookmanager->executeHooks('printFieldListSearchParam', $parameters, $object, $action); // Note that $action and $object may have been modified by hook
 $param .= $hookmanager->resPrint;
 
@@ -1646,7 +1646,7 @@ if (!empty($arrayfields['f.fk_fac_rec_source']['checked'])) {
 }
 // Status
 if (!empty($arrayfields['f.fk_statut']['checked'])) {
-	print '<td class="liste_titre right parentonrightofpage">';
+	print '<td class="liste_titre center parentonrightofpage">';
 	$liststatus = array('0'=>$langs->trans("BillShortStatusDraft"), '0,1'=>$langs->trans("BillShortStatusDraft").'+'.$langs->trans("BillShortStatusNotPaid"), '1'=>$langs->trans("BillShortStatusNotPaid"), '1,2'=>$langs->trans("BillShortStatusNotPaid").'+'.$langs->trans("BillShortStatusPaid"), '2'=>$langs->trans("BillShortStatusPaid"), '3'=>$langs->trans("BillShortStatusCanceled"));
 	print $form->selectarray('search_status', $liststatus, $search_status, 1, 0, 0, '', 0, 0, 0, '', 'search_status width100 onrightofpage', 1);
 	print '</td>';

+ 2 - 2
htdocs/compta/paiement.php

@@ -897,10 +897,10 @@ if ($action == 'create' || $action == 'confirm_paiement' || $action == 'add_paie
 
 			print '<br>';
 			if (!empty($totalpayment)) {
-				$text = $langs->trans('ConfirmCustomerPayment', $totalpayment, $langs->trans("Currency".$conf->currency));
+				$text = $langs->trans('ConfirmCustomerPayment', $totalpayment, $langs->transnoentitiesnoconv("Currency".$conf->currency));
 			}
 			if (!empty($multicurrency_totalpayment)) {
-				$text .= '<br>'.$langs->trans('ConfirmCustomerPayment', $multicurrency_totalpayment, $langs->trans("paymentInInvoiceCurrency"));
+				$text .= '<br>'.$langs->trans('ConfirmCustomerPayment', $multicurrency_totalpayment, $langs->transnoentitiesnoconv("paymentInInvoiceCurrency"));
 			}
 			if (GETPOST('closepaidinvoices')) {
 				$text .= '<br>'.$langs->trans("AllCompletelyPayedInvoiceWillBeClosed");

+ 2 - 2
htdocs/compta/paiement/card.php

@@ -288,8 +288,8 @@ if ($action == 'delete') {
 
 // Confirmation of payment validation
 if ($action == 'valide') {
-	$facid = $_GET['facid'];
-	print $form->formconfirm($_SERVER['PHP_SELF'].'?id='.$object->id.'&amp;facid='.$facid, $langs->trans("ValidatePayment"), $langs->trans("ConfirmValidatePayment"), 'confirm_validate', '', 0, 2);
+	$facid = GETPOSTINT('facid');
+	print $form->formconfirm($_SERVER['PHP_SELF'].'?id='.$object->id.'&facid='.((int) $facid), $langs->trans("ValidatePayment"), $langs->trans("ConfirmValidatePayment"), 'confirm_validate', '', 0, 2);
 }
 
 $linkback = '<a href="'.DOL_URL_ROOT.'/compta/paiement/list.php?restore_lastsearch_values=1">'.$langs->trans("BackToList").'</a>';

Niektoré súbory nie sú zobrazené, pretože je v týchto rozdielových dátach zmenené mnoho súborov