# HG changeset patch
# User Etienne Ferriere <etienne.ferriere@xcg-consulting.fr>
# Date 1655468442 -7200
#      Fri Jun 17 14:20:42 2022 +0200
# Branch 11.0
# Node ID 8b1ac54ab5decf615eb05ed14a21cb73cf2e64cf
# Parent  3931edcf2fe415296220e1d306eb0b0b0591f180
The analytic code name and description can be computed by a class. Field names
can still be used.

diff --git a/MetaAnalytic.py b/MetaAnalytic.py
--- a/MetaAnalytic.py
+++ b/MetaAnalytic.py
@@ -67,6 +67,20 @@
     def __init__(self, name, bases, nmspc):
         return super(MetaAnalytic, self).__init__(name, bases, nmspc)
 
+    def generate_formatter(fieldname):
+
+        if not isinstance(fieldname, str):
+            return fieldname
+
+        class analytic_code_formatter(object):
+
+            fields = [fieldname]
+
+            def generate(model, vals):
+                return vals.get(fieldname)
+
+        return analytic_code_formatter
+
     @classmethod
     def _setup_analytic_fields(
         cls, analytic, para, defaults, orm_name, name, bases, nmspc
@@ -260,8 +274,10 @@
         if ref_id is None:
             ref_id = orm_name.replace(".", "_") + "_analytic_dimension_id"
 
-        code_name = dimension.get("code_name", "name")
-        code_description = dimension.get("code_description", "description")
+        code_name = cls.generate_formatter(dimension.get("code_name", "name"))
+        code_description = cls.generate_formatter(
+            dimension.get("code_description", "description")
+        )
 
         # To use an inherited, renamed parent field, you have to give its name.
         sync_parent = dimension.get("sync_parent", False)
@@ -452,8 +468,12 @@
             if use_inherits:
                 code_vals.update(vals)
             else:
-                code_vals["name"] = vals.get(code_name)
-                code_vals["description"] = vals.get(code_description)
+                if set(code_name.fields).issubset(set(vals.keys())):
+                    code_vals["name"] = code_name.generate(self, vals)
+                if set(code_description.fields).issubset(set(vals.keys())):
+                    code_vals["description"] = code_description.generate(
+                        self, vals
+                    )
 
             if code_vals.get("name"):
 
@@ -529,7 +549,12 @@
                             if field
                             in (
                                 list(vals.keys())
-                                + [code_name, code_description]
+                                + list(
+                                    set(
+                                        code_name.fields
+                                        + code_description.fields
+                                    )
+                                )
                             )
                         },
                         code_vals,
@@ -590,10 +615,14 @@
                         if rel_description
                         else code_description
                     )
-                    if name_col in vals:
-                        code_vals["name"] = vals[name_col]
-                    if description_col in vals:
-                        code_vals["description"] = vals[description_col]
+
+                    if set(name_col.fields).issubset(set(vals.keys())):
+                        code_vals["name"] = name_col.generate(self, vals)
+
+                    if set(description_col.fields).issubset(set(vals.keys())):
+                        code_vals["description"] = description_col.generate(
+                            self, vals
+                        )
                     standard_process = True
 
                 res = super(superclass, self).write(vals, **kwargs)
@@ -610,13 +639,15 @@
                         rec_vals = dict().copy()
 
                         if not rec_code_vals.get("name"):
-                            rec_code_vals["name"] = rec.read([name_col])[0][
-                                name_col
-                            ]
+                            rec_code_vals["name"] = name_col.generate(
+                                rec, rec.read(name_col.fields)[0]
+                            )
                         if not rec_code_vals.get("description"):
-                            rec_code_vals["description"] = self.read(
-                                [description_col]
-                            )[0][description_col]
+                            rec_code_vals[
+                                "description"
+                            ] = description_col.generate(
+                                rec, rec.read(description_col.fields)[0]
+                            )
 
                         if not code and rec_code_vals.get("name"):
                             news.append(rec.id)
diff --git a/NEWS.rst b/NEWS.rst
--- a/NEWS.rst
+++ b/NEWS.rst
@@ -2,9 +2,9 @@
 Changes
 =======
 
-.. _10.0.1.1.0:
+.. _11.0.1.1.0:
 
-10.0.1.1.0
+11.0.1.1.0
 ----------
 
 Corrected a bug, when seeking if analytic codes are required in a form or tree
@@ -12,6 +12,9 @@
 which did not match the original model technical name, the system was unable to
 determine, if the analytic codes were wanted as required.
 
+The analytic code name and description can be computed by a class. Field names
+can still be used.
+
 .. _10.0.1.0.0:
 
 10.0.1.0.0
@@ -19,9 +22,9 @@
 
 Port to Odoo 10.
 Added three options to bind an analytic dimension to a model: 
-    - code_name 
-    - code_description
-    - parent_column
+- code_name 
+- code_description
+- parent_column
 New partners without name, does not trigger an analytic_code creation.
 
 .. _2.2:
diff --git a/README.rst b/README.rst
--- a/README.rst
+++ b/README.rst
@@ -35,7 +35,7 @@
 A model that is declared with the ``_analytic`` attribute (see AnalyticFields_) can reference dimension objects.
 The ``MetaAnalytic`` will automatically create a number of M2O fields that point to analytic codes.
 The number of fields that will be added depends on the configuration (See ConfigureAnalyticFields_).
-They are named with a predefined prefix and a number or slot eg. ``a1_id``, ``a2_id``, ``a3_id``, ...
+They are named with a predefined prefix and a number or slot eg. ``a1_id``, ``a2_id``, ``a3_id``.
 
 These analytic fields will be displayed in views with the names of the dimensions they point to thanks to view manipulation magic.
 
@@ -316,10 +316,13 @@
 along with the entry's name in many2one fields targeting the model.
 
 ``code_name`` (``name``): Name of the record field, which will define the name of the 
-created analytic code. The default value is 'name'.
+created analytic code. The default value is 'name'. The parameter can be a
+class, it must be defined as in section 'Name and description generation'.
 
 ``code_description`` (``description``): Name of the record field, which will define the 
 description of the created analytic code. The default value is 'description'.
+The parameter can be a class, it must be defined as in section 'Name and
+description generation'.
 
 ``parent_column`` (column): Name of the parent record (sync_parent) field, which contains
 the parent code of the analytic code to create. The default value is given by ``column``.
@@ -332,6 +335,43 @@
 Set to ``True``, which is the default value, if analytic code creation and update must
 work as defined by default on create or write operation.
 
+Name and description generation
+-------------------------------
+
+The analytic code name and description can be computed by a class. Field names
+can still be used.
+
+The class must be defined under this format, with a field named ``fields``, 
+listing the field names implied in the name or description computation and 
+a method ``generate`` with two parameters (the model class and the field value
+dictionary) for the computation:
+
+class Example(object):
+
+    fields = ["xxx", "yyy" ...]  # The list of field names implied in the
+                                 # name or description computation. 
+
+    # This method must always be called ``generate``. It receives two
+    # parameters, which can be named differently.
+    # The first parameter ``model_obj`` is the Odoo class of the model from
+    # which the analytic code is generated.
+    # The second parameter ``vals`` is the field value dictionary. The
+    # MetaAnalytic metaclass works in such a way, that the field names defined
+    # in ``fields`` will always be present in ``vals``.
+    
+    def generate(model_obj, vals):
+
+        # Computation code.
+        # Example:
+        result = model_obj.xxx_method(vals["xxx"], vals["yyy"])
+
+        return result  # The method returns the name or description computed
+                       # from the values read in ``vals`` and corresponding to
+                       # the keys defined in ``fields``. ``model_obj`` can be
+                       # called in this code, to use specific methods defined
+                       # in this class.
+
+
 Active / View type / Disabled in my company
 -------------------------------------------
 
@@ -339,7 +379,6 @@
 
 - Active: Determines whether an analytic code is in the referential.
 - View type: Determines whether an analytic code is not selectable (but still
-in the referential).
+  in the referential).
 - Disabled per company: Determines whether an analytic code is disabled for the
-current company.
-
+  current company.
diff --git a/__manifest__.py b/__manifest__.py
--- a/__manifest__.py
+++ b/__manifest__.py
@@ -20,7 +20,7 @@
 
 {
     "name": "Analytic Structure",
-    "version": "11.0.1.0.1",
+    "version": "11.0.1.1.0",
     "author": "XCG Consulting",
     "category": "Dependency",
     "website": "http://odoo.consulting",
diff --git a/doc/Makefile b/doc/Makefile
--- a/doc/Makefile
+++ b/doc/Makefile
@@ -1,197 +1,41 @@
-# Makefile for Sphinx documentation
+# Minimal makefile for Sphinx documentation
 #
 
-# You can set these variables from the command line.
-SPHINXOPTS    =
-SPHINXBUILD   = sphinx-build
-PAPER         =
-BUILDDIR      = _build
+# You can set these variables from the command line, and also
+# from the environment for the first two.
+SPHINXOPTS     ?=
+SPHINXBUILD    ?= sphinx-build
+SOURCEDIR      = .
+BUILDDIR       = _build
+LANGUAGE       ?= en
+BUILDDIRSUFFIX =
 
 # User-friendly check for sphinx-build
 ifeq ($(shell which $(SPHINXBUILD) >/dev/null 2>&1; echo $$?), 1)
 $(error The '$(SPHINXBUILD)' command was not found. Make sure you have Sphinx installed, then set the SPHINXBUILD environment variable to point to the full path of the '$(SPHINXBUILD)' executable. Alternatively you can add the directory with the executable to your PATH. If you don't have Sphinx installed, grab it from http://sphinx-doc.org/)
 endif
 
-project:=$(shell basename $(shell readlink -f ..))
-branch:=$(shell hg identify --branch)
+.PHONY: help Makefile gettext clean
 
-# Internal variables.
-PAPEROPT_a4     = -D latex_paper_size=a4
-PAPEROPT_letter = -D latex_paper_size=letter
-ALLSPHINXOPTS   = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
-# the i18n builder cannot share the environment and doctrees with the others
-I18NSPHINXOPTS  = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
-
-.PHONY: help
+# Put it first so that "make" without argument is like "make help".
 help:
-	@echo "Please use \`make <target>' where <target> is one of"
-	@echo "  html       to make standalone HTML files"
-	@echo "  dirhtml    to make HTML files named index.html in directories"
-	@echo "  singlehtml to make a single large HTML file"
-	@echo "  pickle     to make pickle files"
-	@echo "  json       to make JSON files"
-	@echo "  htmlhelp   to make HTML files and a HTML help project"
-	@echo "  qthelp     to make HTML files and a qthelp project"
-	@echo "  applehelp  to make an Apple Help Book"
-	@echo "  devhelp    to make HTML files and a Devhelp project"
-	@echo "  epub       to make an epub"
-	@echo "  latex      to make LaTeX files, you can set PAPER=a4 or PAPER=letter"
-	@echo "  latexpdf   to make LaTeX files and run them through pdflatex"
-	@echo "  latexpdfja to make LaTeX files and run them through platex/dvipdfmx"
-	@echo "  text       to make text files"
-	@echo "  man        to make manual pages"
-	@echo "  texinfo    to make Texinfo files"
-	@echo "  info       to make Texinfo files and run them through makeinfo"
-	@echo "  gettext    to make PO message catalogs"
-	@echo "  changes    to make an overview of all changed/added/deprecated items"
-	@echo "  xml        to make Docutils-native XML files"
-	@echo "  pseudoxml  to make pseudoxml-XML files for display purposes"
-	@echo "  linkcheck  to check all external links for integrity"
-	@echo "  doctest    to run all doctests embedded in the documentation (if enabled)"
-	@echo "  coverage   to run coverage check of the documentation (if enabled)"
+	@$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)/$(LANGUAGE)$(BUILDDIRSUFFIX)" $(SPHINXOPTS) $(O)
 
-.PHONY: clean
 clean:
 	rm -rf $(BUILDDIR)/*
-	rm -f autotodo manifest
-
-.PHONY: html
-html: autotodo manifest
-	$(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html
-	@echo
-	@echo "Build finished. The HTML pages are in $(BUILDDIR)/html."
-
-.PHONY: dirhtml
-dirhtml: autotodo manifest
-	$(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml
-	@echo
-	@echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml."
-
-.PHONY: singlehtml
-singlehtml: autotodo manifest
-	$(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml
-	@echo
-	@echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml."
-
-.PHONY: pickle
-pickle:
-	$(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle
-	@echo
-	@echo "Build finished; now you can process the pickle files."
-
-.PHONY: json
-json:
-	$(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json
-	@echo
-	@echo "Build finished; now you can process the JSON files."
-
-.PHONY: htmlhelp
-htmlhelp: autotodo manifest
-	$(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp
-	@echo
-	@echo "Build finished; now you can run HTML Help Workshop with the" \
-	      ".hhp project file in $(BUILDDIR)/htmlhelp."
-
-.PHONY: epub
-epub:
-	$(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub
-	@echo
-	@echo "Build finished. The epub file is in $(BUILDDIR)/epub."
-
-.PHONY: latex
-latex:
-	$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
-	@echo
-	@echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex."
-	@echo "Run \`make' in that directory to run these through (pdf)latex" \
-	      "(use \`make latexpdf' here to do that automatically)."
-
-.PHONY: latexpdf
-latexpdf:
-	$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
-	@echo "Running LaTeX files through pdflatex..."
-	$(MAKE) -C $(BUILDDIR)/latex all-pdf
-	@echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex."
-
-.PHONY: latexpdfja
-latexpdfja:
-	$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
-	@echo "Running LaTeX files through platex and dvipdfmx..."
-	$(MAKE) -C $(BUILDDIR)/latex all-pdf-ja
-	@echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex."
-
-.PHONY: text
-text:
-	$(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text
-	@echo
-	@echo "Build finished. The text files are in $(BUILDDIR)/text."
-
-.PHONY: man
-man:
-	$(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man
-	@echo
-	@echo "Build finished. The manual pages are in $(BUILDDIR)/man."
-
-.PHONY: texinfo
-texinfo:
-	$(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
-	@echo
-	@echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo."
-	@echo "Run \`make' in that directory to run these through makeinfo" \
-	      "(use \`make info' here to do that automatically)."
-
-.PHONY: info
-info:
-	$(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
-	@echo "Running Texinfo files through makeinfo..."
-	make -C $(BUILDDIR)/texinfo info
-	@echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo."
-
-.PHONY: gettext
-gettext:
-	$(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale
-	@echo
-	@echo "Build finished. The message catalogs are in $(BUILDDIR)/locale."
-
-.PHONY: changes
-changes:
-	$(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes
-	@echo
-	@echo "The overview file is in $(BUILDDIR)/changes."
-
-.PHONY: linkcheck
-linkcheck:
-	$(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck
-	@echo
-	@echo "Link check complete; look for any errors in the above output " \
-	      "or in $(BUILDDIR)/linkcheck/output.txt."
-
-.PHONY: doctest
-doctest:
-	$(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest
-	@echo "Testing of doctests in the sources finished, look at the " \
-	      "results in $(BUILDDIR)/doctest/output.txt."
-
-.PHONY: coverage
-coverage:
-	$(SPHINXBUILD) -b coverage $(ALLSPHINXOPTS) $(BUILDDIR)/coverage
-	@echo "Testing of coverage in the sources finished, look at the " \
-	      "results in $(BUILDDIR)/coverage/python.txt."
-
-.PHONY: xml
-xml:
-	$(SPHINXBUILD) -b xml $(ALLSPHINXOPTS) $(BUILDDIR)/xml
-	@echo
-	@echo "Build finished. The XML files are in $(BUILDDIR)/xml."
-
-.PHONY: pseudoxml
-pseudoxml:
-	$(SPHINXBUILD) -b pseudoxml $(ALLSPHINXOPTS) $(BUILDDIR)/pseudoxml
-	@echo
-	@echo "Build finished. The pseudo-XML files are in $(BUILDDIR)/pseudoxml."
+	rm -f autotodo
 
 autotodo: autotodo.py
 	@./autotodo.py ../ .py TODO,FIXME,XXX
 
-manifest: ../__manifest__.py manifest.py
-	@./manifest.py
+gettext: Makefile
+	@$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)$(BUILDDIRSUFFIX)" $(SPHINXOPTS) $(O)
+
+# Use to update *.po files
+update_locale: Makefile gettext
+	@sphinx-intl update -p "$(BUILDDIR)$(BUILDDIRSUFFIX)/gettext" -l $(LANGUAGE)
+
+# Catch-all target: route all unknown targets to Sphinx using the new
+# "make mode" option.  $(O) is meant as a shortcut for $(SPHINXOPTS).
+%: Makefile
+	@$(SPHINXBUILD) -b $@ "$(SOURCEDIR)" "$(BUILDDIR)/$@/$(LANGUAGE)$(BUILDDIRSUFFIX)" -d "$(BUILDDIR)$(BUILDDIRSUFFIX)/doctrees/$(LANGUAGE)" $(SPHINXOPTS) -D language=$(LANGUAGE) $(O)
diff --git a/doc/TODO.rst b/doc/TODO.rst
deleted file mode 100644
--- a/doc/TODO.rst
+++ /dev/null
@@ -1,7 +0,0 @@
-====
-TODO
-====
-
-.. todolist::
-
-.. include:: autotodo
diff --git a/doc/analytic_structure.rst b/doc/analytic_structure.rst
deleted file mode 100644
--- a/doc/analytic_structure.rst
+++ /dev/null
@@ -1,46 +0,0 @@
-openerp.addons.analytic_structure package
-=========================================
-
-Submodules
-----------
-
-openerp.addons.analytic_structure.MetaAnalytic module
------------------------------------------------------
-
-.. automodule:: openerp.addons.analytic_structure.MetaAnalytic
-    :members:
-    :undoc-members:
-    :show-inheritance:
-
-openerp.addons.analytic_structure.analytic_code module
-------------------------------------------------------
-
-.. automodule:: openerp.addons.analytic_structure.analytic_code
-    :members:
-    :undoc-members:
-    :show-inheritance:
-
-openerp.addons.analytic_structure.analytic_dimension module
------------------------------------------------------------
-
-.. automodule:: openerp.addons.analytic_structure.analytic_dimension
-    :members:
-    :undoc-members:
-    :show-inheritance:
-
-openerp.addons.analytic_structure.analytic_structure module
------------------------------------------------------------
-
-.. automodule:: openerp.addons.analytic_structure.analytic_structure
-    :members:
-    :undoc-members:
-    :show-inheritance:
-
-
-Module contents
----------------
-
-.. automodule:: openerp.addons.analytic_structure
-    :members:
-    :undoc-members:
-    :show-inheritance:
diff --git a/doc/autotodo.py b/doc/autotodo.py
deleted file mode 100755
--- a/doc/autotodo.py
+++ /dev/null
@@ -1,112 +0,0 @@
-#!/usr/bin/env python3
-##############################################################################
-#
-#    OpenERP, Open Source Management Solution
-#    Copyright (C) 2014, 2018 XCG Consulting
-#
-#    This program is free software: you can redistribute it and/or modify
-#    it under the terms of the GNU Affero General Public License as
-#    published by the Free Software Foundation, either version 3 of the
-#    License, or (at your option) any later version.
-#
-#    This program is distributed in the hope that it will be useful,
-#    but WITHOUT ANY WARRANTY; without even the implied warranty of
-#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-#    GNU Affero General Public License for more details.
-#
-#    You should have received a copy of the GNU Affero General Public License
-#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
-#
-##############################################################################
-
-import os
-import os.path
-import sys
-
-
-def main():
-    if len(sys.argv) != 4:
-        print("usage: autotodo.py <folder> <exts> <tags>")
-        sys.exit(1)
-
-    folder = sys.argv[1]
-    exts = sys.argv[2].split(",")
-    tags = sys.argv[3].split(",")
-    todolist = {tag: [] for tag in tags}
-
-    for root, dirs, files in os.walk(folder):
-        scan_folder((exts, tags, todolist), root, files)
-    create_autotodo(folder, todolist)
-
-
-def write_info(f, infos, folder):
-    # Check sphinx version for lineno-start support
-
-    import sphinx
-
-    if sphinx.version_info < (1, 3):
-        lineno_start = False
-    else:
-        lineno_start = True
-
-    for i in infos:
-        path = i[0]
-        line = i[1]
-        lines = (line - 3, line + 4)
-        class_name = ":class:`%s`" % os.path.basename(
-            os.path.splitext(path)[0]
-        )
-        f.write(
-            "%s\n"
-            "%s\n\n"
-            "Line %s\n"
-            "\t.. literalinclude:: %s\n"
-            "\t\t:language: python\n"
-            "\t\t:lines: %s-%s\n"
-            "\t\t:emphasize-lines: %s\n"
-            % (
-                class_name,
-                "-" * len(class_name),
-                line,
-                path,
-                lines[0],
-                lines[1],
-                line,
-            )
-        )
-        if lineno_start:
-            f.write("\t\t:lineno-start: %s\n" % lines[0])
-        f.write("\n")
-
-
-def create_autotodo(folder, todolist):
-    with open("autotodo", "w+") as f:
-        for tag, info in todolist.items():
-            f.write("%s\n%s\n\n" % (tag, "=" * len(tag)))
-            write_info(f, info, folder)
-
-
-def scan_folder(data_tuple, dirname, names):
-    (exts, tags, res) = data_tuple
-    file_info = {}
-    for name in names:
-        (root, ext) = os.path.splitext(name)
-        if ext in exts:
-            file_info = scan_file(os.path.join(dirname, name), tags)
-            for tag, info in file_info.items():
-                if info:
-                    res[tag].extend(info)
-
-
-def scan_file(filename, tags):
-    res = {tag: [] for tag in tags}
-    with open(filename, "r") as f:
-        for line_num, line in enumerate(f):
-            for tag in tags:
-                if tag in line:
-                    res[tag].append((filename, line_num, line[:-1].strip()))
-    return res
-
-
-if __name__ == "__main__":
-    main()
diff --git a/doc/conf.py b/doc/conf.py
--- a/doc/conf.py
+++ b/doc/conf.py
@@ -1,3 +1,6 @@
+# Trustpilot documentation build configuration file,
+# created by sphinx-quickstart on Fri Oct 6 15:55:00 2017.
+#
 # This file is execfile()d with the current directory set to its
 # containing dir.
 #
@@ -21,6 +24,9 @@
 
 # -- General configuration ------------------------------------------------
 
+# If your documentation needs a minimal Sphinx version, state it here.
+# needs_sphinx = '1.0'
+
 # Add any Sphinx extension module names here, as strings. They can be
 # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
 # ones.
@@ -30,8 +36,7 @@
     "sphinx.ext.intersphinx",
     "sphinx.ext.todo",
     "sphinx.ext.coverage",
-    "sphinx.ext.ifconfig",
-    "sphinx.ext.viewcode",
+    "sphinx.ext.graphviz",
     "sphinxodoo.ext.autodoc",
 ]
 
@@ -40,8 +45,12 @@
 
 # The suffix(es) of source filenames.
 # You can specify multiple suffix as a list of string:
+# source_suffix = ['.rst', '.md']
 source_suffix = ".rst"
 
+# The encoding of source files.
+# source_encoding = 'utf-8-sig'
+
 # The master toctree document.
 master_doc = "index"
 
@@ -59,7 +68,7 @@
 
 # General information about the project.
 project = d["name"]
-copyright = "2013-2016, XCG Consulting"
+copyright = "2021 XCG Consulting"
 author = d["author"]
 module_nospace = project.replace(" ", "")
 module_description = d.get("summary", "")
diff --git a/doc/index.rst b/doc/index.rst
--- a/doc/index.rst
+++ b/doc/index.rst
@@ -1,4 +1,4 @@
-.. include:: manifest
+.. include:: README.rst
 
 Contents:
 
@@ -6,9 +6,7 @@
    :maxdepth: 2
 
    README
-   modules
    NEWS
-   TODO
 
 Indices and tables
 ==================
diff --git a/doc/locale/fr/LC_MESSAGES/NEWS.po b/doc/locale/fr/LC_MESSAGES/NEWS.po
deleted file mode 100644
--- a/doc/locale/fr/LC_MESSAGES/NEWS.po
+++ /dev/null
@@ -1,191 +0,0 @@
-# SOME DESCRIPTIVE TITLE.
-# Copyright (C) 2013-2016, XCG Consulting
-# This file is distributed under the same license as the Analytic Structure package.
-# Vincent Hatakeyama <vincent.hatakeyama@xcg-consulting.fr>, 2016.
-msgid ""
-msgstr ""
-"Project-Id-Version: Analytic Structure 2.2\n"
-"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2016-12-09 16:39+0000\n"
-"PO-Revision-Date: 2016-12-09 17:43+0200\n"
-"Last-Translator: Vincent Hatakeyama <vincent.hatakeyama@xcg-consulting.fr>\n"
-"Language-Team: XCG Consulting\n"
-"Language: fr\n"
-"MIME-Version: 1.0\n"
-"Content-Type: text/plain; charset=UTF-8\n"
-"Content-Transfer-Encoding: 8bit\n"
-"Plural-Forms: nplurals=2; plural=(n > 1);\n"
-"X-Generator: Virtaal 0.7.1\n"
-
-#: ../../NEWS.rst:3
-msgid "Changes"
-msgstr "Changements"
-
-#: ../../NEWS.rst:8
-msgid "2.2"
-msgstr "2.2"
-
-#: ../../NEWS.rst:10
-msgid "Changed method to allow having readonly in a view on analytic dimensions placeholder so that all analytic fields will get readonly too. Example: <field name=\"analytic_dimensions\" readonly=\"1\"/> The values that can be set are only 1, True or true. It should already be working with invisible, etc. but a modifiers=\"{'invisible': True}\" might be needed too."
-msgstr ""
-
-#: ../../NEWS.rst:17
-msgid "2.1"
-msgstr "2.1"
-
-#: ../../NEWS.rst:19
-msgid "Odoo 8: new feature, add coherence constraints"
-msgstr ""
-
-#: ../../NEWS.rst:20
-msgid "Odoo 8: new feature, allowing choosing models with a dropdown list in analytic structures"
-msgstr ""
-
-#: ../../NEWS.rst:21
-msgid "Odoo 8: new feature, add validation hook for analytic models"
-msgstr ""
-
-#: ../../NEWS.rst:22
-msgid "Odoo 8: new feature, add analytic code synchronization button in analytic.dimension form view"
-msgstr ""
-
-#: ../../NEWS.rst:24
-msgid "Factorize getting analytic size and provide a function for other modules to determine the value."
-msgstr ""
-
-#: ../../NEWS.rst:28
-msgid "2.0"
-msgstr "2.0"
-
-#: ../../NEWS.rst:30
-msgid "Fix issues when there is no analytic structure"
-msgstr ""
-
-#: ../../NEWS.rst:33
-msgid "1.9"
-msgstr "1.9"
-
-#: ../../NEWS.rst:35
-msgid "Add License and Copyright (AGPL & XCG)"
-msgstr "Ajout de la license et du copyright (AGPL & XCG)"
-
-#: ../../NEWS.rst:37
-msgid "Remove field 'validated'"
-msgstr "Champ validé retiré"
-
-#: ../../NEWS.rst:40
-msgid "1.8"
-msgstr ""
-
-#: ../../NEWS.rst:42
-msgid "Odoo8 Fix: Find the class oe_analytic on all elements (not only div)"
-msgstr ""
-"Fix sur Odoo8: Trouver la classe oe_analytic dans tout les éléments, pas "
-"seulement les div"
-
-#: ../../NEWS.rst:45
-msgid "1.7"
-msgstr "1.7"
-
-#: ../../NEWS.rst:47
-#: ../../NEWS.rst:63
-#: ../../NEWS.rst:85
-msgid "Production release"
-msgstr ""
-
-#: ../../NEWS.rst:50
-msgid "1.6.2"
-msgstr ""
-
-#: ../../NEWS.rst:52
-msgid "[fix] error on write"
-msgstr "[Correction] Erreur à l'écriture"
-
-#: ../../NEWS.rst:55
-msgid "1.6.1"
-msgstr ""
-
-#: ../../NEWS.rst:57
-msgid "Added possibility to give particular external ID on bound dimensions."
-msgstr ""
-"Ajout de la possibilité de donner des ID externes particuliers sur les "
-"dimensions liées."
-
-#: ../../NEWS.rst:58
-msgid "[fix] issue with the tree view with analytic"
-msgstr "[Correction] Correction concernant la vue Tree et l'analytique"
-
-#: ../../NEWS.rst:61
-msgid "1.6"
-msgstr ""
-
-#: ../../NEWS.rst:65
-msgid "1.5.1 ---"
-msgstr ""
-
-#: ../../NEWS.rst:68
-msgid "[fix] searching for disabled analytic structures"
-msgstr "[Correction] Recherche des structures analytiques désactivés"
-
-#: ../../NEWS.rst:71
-msgid "1.5"
-msgstr ""
-
-#: ../../NEWS.rst:73
-msgid "[l10n] Updated French translation"
-msgstr "[l10n] Mise à jour des traductions en Français"
-
-#: ../../NEWS.rst:74
-msgid "Analytic codes can be blacklisted per company"
-msgstr "Les codes analytiques peuvent être blacklistés par compagnie"
-
-#: ../../NEWS.rst:75
-msgid "Renamed fields for clarity"
-msgstr "Champs renommés pour plus de clarté"
-
-#: ../../NEWS.rst:78
-msgid "1.4.1"
-msgstr ""
-
-#: ../../NEWS.rst:80
-msgid "Improve ease of use of the module by other module"
-msgstr "Amélioration de l'utilisation du module par d'autres modules"
-
-#: ../../NEWS.rst:83
-msgid "1.4"
-msgstr ""
-
-#: ../../NEWS.rst:88
-msgid "1.3.8"
-msgstr ""
-
-#: ../../NEWS.rst:90
-msgid "[fix] bug in some view when using analytic."
-msgstr "[Correction] Bug dans certaines vues utilisant l'analytic."
-
-#: ../../NEWS.rst:91
-msgid "Added support for para-analytic fields."
-msgstr "Ajout d'un support pour les champs para-analytics."
-
-#: ../../NEWS.rst:94
-msgid "1.3.7"
-msgstr ""
-
-#: ../../NEWS.rst:96
-msgid "Structures can now be restricted to one company."
-msgstr "Structures peuvent désormais être limitées à une seule entreprise."
-
-#: ../../NEWS.rst:97
-msgid "Bound dimensions: added the code_ref_ids (and code_ref_module) options to generate external IDs for all analytic codes of the dimension. Generated during a write operation."
-msgstr ""
-"Dimensions liés : Ajout des code_ref_ids ( et code_ref_module ) en options "
-"pour générer des ID externes pour tous les codes analytiques de la dimension "
-". Généré pendant une opération d'écriture."
-
-#: ../../NEWS.rst:100
-msgid "1.3.6"
-msgstr ""
-
-#: ../../NEWS.rst:102
-msgid "…"
-msgstr ""
diff --git a/doc/locale/fr/LC_MESSAGES/index.po b/doc/locale/fr/LC_MESSAGES/index.po
deleted file mode 100644
--- a/doc/locale/fr/LC_MESSAGES/index.po
+++ /dev/null
@@ -1,38 +0,0 @@
-# SOME DESCRIPTIVE TITLE.
-# Copyright (C) 2013-2016, XCG Consulting
-# This file is distributed under the same license as the Analytic Structure package.
-# Vincent Hatakeyama <vincent.hatakeyama@xcg-consulting.fr>, 2016.
-msgid ""
-msgstr ""
-"Project-Id-Version: Analytic Structure 2.2\n"
-"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2016-12-09 16:39+0000\n"
-"PO-Revision-Date: 2016-12-09 17:39+0200\n"
-"Last-Translator: Vincent Hatakeyama <vincent.hatakeyama@xcg-consulting.fr>\n"
-"Language-Team: XCG Consulting\n"
-"Language: fr\n"
-"MIME-Version: 1.0\n"
-"Content-Type: text/plain; charset=UTF-8\n"
-"Content-Transfer-Encoding: 8bit\n"
-"Plural-Forms: nplurals=2; plural=(n > 1);\n"
-"X-Generator: Virtaal 0.7.1\n"
-
-#: ../../index.rst:3
-msgid "Contents:"
-msgstr "Contenu :"
-
-#: ../../index.rst:14
-msgid "Indices and tables"
-msgstr ""
-
-#: ../../index.rst:16
-msgid ":ref:`genindex`"
-msgstr ""
-
-#: ../../index.rst:17
-msgid ":ref:`modindex`"
-msgstr ""
-
-#: ../../index.rst:18
-msgid ":ref:`search`"
-msgstr ""
diff --git a/doc/manifest.py b/doc/manifest.py
deleted file mode 100755
--- a/doc/manifest.py
+++ /dev/null
@@ -1,43 +0,0 @@
-#!/usr/bin/env python3
-###############################################################################
-#
-#    OpenERP, Open Source Management Solution
-#    Copyright (C) 2016, 2018 XCG Consulting (http://www.xcg-consulting.fr/)
-#
-#    This program is free software: you can redistribute it and/or modify
-#    it under the terms of the GNU Affero General Public License as
-#    published by the Free Software Foundation, either version 3 of the
-#    License, or (at your option) any later version.
-#
-#    This program is distributed in the hope that it will be useful,
-#    but WITHOUT ANY WARRANTY; without even the implied warranty of
-#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-#    GNU Affero General Public License for more details.
-#
-#    You should have received a copy of the GNU Affero General Public License
-#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
-#
-###############################################################################
-import os
-
-from odoo.modules import load_information_from_description_file
-
-
-def main():
-    module = os.path.basename(
-        os.path.dirname(os.path.dirname(os.path.realpath(__file__)))
-    )
-    d = load_information_from_description_file(module)
-    with open("manifest", "w") as out:
-        manifest_content = (
-            d["description"]
-            if "description" in d
-            else d["summary"]
-            if "summary" in d
-            else ""
-        )
-        out.write(manifest_content)
-
-
-if __name__ == "__main__":
-    main()
diff --git a/doc/modules.rst b/doc/modules.rst
deleted file mode 100644
--- a/doc/modules.rst
+++ /dev/null
@@ -1,7 +0,0 @@
-analytic_structure
-==================
-
-.. toctree::
-   :maxdepth: 4
-
-   analytic_structure