diff --git a/.copier-answers.yml b/.copier-answers.yml index 146be548f..8c1b35bac 100644 --- a/.copier-answers.yml +++ b/.copier-answers.yml @@ -1,8 +1,7 @@ # Do NOT update manually; changes here will be overwritten by Copier -_commit: v1.29 +_commit: v1.44 _src_path: gh:oca/oca-addons-repo-template additional_ruff_rules: [] -ci: GitHub convert_readme_fragments_to_markdown: true enable_checklog_odoo: false generate_requirements_txt: true @@ -17,6 +16,7 @@ odoo_test_flavor: Both odoo_version: 17.0 org_name: Odoo Community Association (OCA) org_slug: OCA +postgres_image: '' rebel_module_groups: [] repo_description: 'TODO: add repo description.' repo_name: server-env diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 000000000..e0d56685a --- /dev/null +++ b/.gitattributes @@ -0,0 +1 @@ +test-requirements.txt merge=union diff --git a/.github/workflows/pre-commit.yml b/.github/workflows/pre-commit.yml index d19e4918e..7b1a509e8 100644 --- a/.github/workflows/pre-commit.yml +++ b/.github/workflows/pre-commit.yml @@ -1,3 +1,4 @@ + name: pre-commit on: @@ -9,6 +10,10 @@ on: - "17.0" - "17.0-ocabot-*" +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + jobs: pre-commit: runs-on: ubuntu-22.04 @@ -16,7 +21,9 @@ jobs: - uses: actions/checkout@v4 - uses: actions/setup-python@v5 with: - python-version: "3.11" + python-version: "3.10" + cache: 'pip' + cache-dependency-path: '.pre-commit-config.yaml' - name: Get python version run: echo "PY=$(python -VV | sha256sum | cut -d' ' -f1)" >> $GITHUB_ENV - uses: actions/cache@v4 diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 4b79e178c..e58b6415d 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -9,6 +9,10 @@ on: - "17.0" - "17.0-ocabot-*" +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + jobs: unreleased-deps: runs-on: ubuntu-latest @@ -42,7 +46,7 @@ jobs: makepot: "true" services: postgres: - image: postgres:12.0 + image: postgres:12 env: POSTGRES_USER: odoo POSTGRES_PASSWORD: odoo @@ -63,6 +67,13 @@ jobs: run: oca_init_test_database - name: Run tests run: oca_run_tests + - name: Upload screenshots from JS tests + uses: actions/upload-artifact@v4 + if: ${{ failure() }} + with: + name: Screenshots of failed JS tests - ${{ matrix.name }}${{ join(matrix.include) }} + path: /tmp/odoo_tests/${{ env.PGDATABASE }} + if-no-files-found: ignore - uses: codecov/codecov-action@v4 with: token: ${{ secrets.CODECOV_TOKEN }} diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 3940ddd48..227af9c9e 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -21,7 +21,7 @@ exclude: | # You don't usually want a bot to modify your legal texts (LICENSE.*|COPYING.*) default_language_version: - python: python3 + python: python3.10 node: "16.17.0" repos: - repo: local @@ -38,12 +38,17 @@ repos: entry: found a en.po file language: fail files: '[a-zA-Z0-9_]*/i18n/en\.po$' + - id: obsolete dotfiles + name: obsolete dotfiles + entry: found obsolete files; remove them + files: '^(\.travis\.yml|\.t2d\.yml|CONTRIBUTING\.md)$' + language: fail - repo: https://github.com/sbidoul/whool - rev: v1.2 + rev: v1.3 hooks: - id: whool-init - repo: https://github.com/oca/maintainer-tools - rev: d5fab7ee87fceee858a3d01048c78a548974d935 + rev: 31bdbd8e4cb94be6534f0e82b1cafb84a455f671 hooks: # update the NOT INSTALLABLE ADDONS section above - id: oca-update-pre-commit-excluded-addons @@ -95,6 +100,7 @@ repos: additional_dependencies: - "eslint@8.24.0" - "eslint-plugin-jsdoc@" + - "globals@" - repo: https://github.com/pre-commit/pre-commit-hooks rev: v4.3.0 hooks: diff --git a/.pylintrc b/.pylintrc index 874f69669..f680dab56 100644 --- a/.pylintrc +++ b/.pylintrc @@ -4,6 +4,9 @@ load-plugins=pylint_odoo score=n +[IMPORTS] +deprecated-modules=pdb,pudb,ipdb,bs4 + [ODOOLINT] readme-template-url="https://github.com/OCA/maintainer-tools/blob/master/template/module/README.rst" manifest-required-authors=Odoo Community Association (OCA) @@ -25,19 +28,26 @@ disable=all enable=anomalous-backslash-in-string, api-one-deprecated, api-one-multi-together, - assignment-from-none, - attribute-deprecated, class-camelcase, - dangerous-default-value, dangerous-view-replace-wo-priority, - development-status-allowed, duplicate-id-csv, - duplicate-key, duplicate-xml-fields, duplicate-xml-record-id, eval-referenced, - eval-used, incoherent-interpreter-exec-perm, + openerp-exception-warning, + redundant-modulename-xml, + relative-import, + rst-syntax-error, + wrong-tabs-instead-of-spaces, + xml-syntax-error, + assignment-from-none, + attribute-deprecated, + dangerous-default-value, + deprecated-module, + development-status-allowed, + duplicate-key, + eval-used, license-allowed, manifest-author-string, manifest-deprecated-key, @@ -48,73 +58,68 @@ enable=anomalous-backslash-in-string, method-inverse, method-required-super, method-search, - openerp-exception-warning, pointless-statement, pointless-string-statement, print-used, redundant-keyword-arg, - redundant-modulename-xml, reimported, - relative-import, return-in-init, - rst-syntax-error, sql-injection, too-few-format-args, translation-field, translation-required, unreachable, use-vim-comment, - wrong-tabs-instead-of-spaces, - xml-syntax-error, - attribute-string-redundant, character-not-valid-in-resource-link, - consider-merging-classes-inherited, - context-overridden, create-user-wo-reset-password, dangerous-filter-wo-user, dangerous-qweb-replace-wo-priority, deprecated-data-xml-node, deprecated-openerp-xml-node, duplicate-po-message-definition, - except-pass, file-not-used, + missing-newline-extrafiles, + old-api7-method-defined, + po-msgstr-variables, + po-syntax-error, + str-format-used, + unnecessary-utf8-coding-comment, + xml-attribute-translatable, + xml-deprecated-qweb-directive, + xml-deprecated-tree-attribute, + attribute-string-redundant, + consider-merging-classes-inherited, + context-overridden, + except-pass, invalid-commit, manifest-maintainers-list, - missing-newline-extrafiles, missing-readme, missing-return, odoo-addons-relative-import, - old-api7-method-defined, - po-msgstr-variables, - po-syntax-error, renamed-field-parameter, resource-not-exist, - str-format-used, test-folder-imported, translation-contains-variable, translation-positional-used, - unnecessary-utf8-coding-comment, website-manifest-key-not-valid-uri, - xml-attribute-translatable, - xml-deprecated-qweb-directive, - xml-deprecated-tree-attribute, external-request-timeout, - # messages that do not cause the lint step to fail - consider-merging-classes-inherited, + missing-manifest-dependency, + too-complex, create-user-wo-reset-password, dangerous-filter-wo-user, - deprecated-module, file-not-used, - invalid-commit, - missing-manifest-dependency, missing-newline-extrafiles, - missing-readme, no-utf8-coding-comment, - odoo-addons-relative-import, old-api7-method-defined, + unnecessary-utf8-coding-comment, + # messages that do not cause the lint step to fail + consider-merging-classes-inherited, + deprecated-module, + invalid-commit, + missing-readme, + odoo-addons-relative-import, redefined-builtin, - too-complex, - unnecessary-utf8-coding-comment + manifest-external-assets [REPORTS] diff --git a/.pylintrc-mandatory b/.pylintrc-mandatory index 0d7ae0807..d93919239 100644 --- a/.pylintrc-mandatory +++ b/.pylintrc-mandatory @@ -3,6 +3,9 @@ load-plugins=pylint_odoo score=n +[IMPORTS] +deprecated-modules=pdb,pudb,ipdb,bs4 + [ODOOLINT] readme-template-url="https://github.com/OCA/maintainer-tools/blob/master/template/module/README.rst" manifest-required-authors=Odoo Community Association (OCA) @@ -17,19 +20,26 @@ disable=all enable=anomalous-backslash-in-string, api-one-deprecated, api-one-multi-together, - assignment-from-none, - attribute-deprecated, class-camelcase, - dangerous-default-value, dangerous-view-replace-wo-priority, - development-status-allowed, duplicate-id-csv, - duplicate-key, duplicate-xml-fields, duplicate-xml-record-id, eval-referenced, - eval-used, incoherent-interpreter-exec-perm, + openerp-exception-warning, + redundant-modulename-xml, + relative-import, + rst-syntax-error, + wrong-tabs-instead-of-spaces, + xml-syntax-error, + assignment-from-none, + attribute-deprecated, + dangerous-default-value, + deprecated-module, + development-status-allowed, + duplicate-key, + eval-used, license-allowed, manifest-author-string, manifest-deprecated-key, @@ -40,56 +50,50 @@ enable=anomalous-backslash-in-string, method-inverse, method-required-super, method-search, - openerp-exception-warning, pointless-statement, pointless-string-statement, print-used, redundant-keyword-arg, - redundant-modulename-xml, reimported, - relative-import, return-in-init, - rst-syntax-error, sql-injection, too-few-format-args, translation-field, translation-required, unreachable, use-vim-comment, - wrong-tabs-instead-of-spaces, - xml-syntax-error, - attribute-string-redundant, character-not-valid-in-resource-link, - consider-merging-classes-inherited, - context-overridden, create-user-wo-reset-password, dangerous-filter-wo-user, dangerous-qweb-replace-wo-priority, deprecated-data-xml-node, deprecated-openerp-xml-node, duplicate-po-message-definition, - except-pass, file-not-used, + missing-newline-extrafiles, + old-api7-method-defined, + po-msgstr-variables, + po-syntax-error, + str-format-used, + unnecessary-utf8-coding-comment, + xml-attribute-translatable, + xml-deprecated-qweb-directive, + xml-deprecated-tree-attribute, + attribute-string-redundant, + consider-merging-classes-inherited, + context-overridden, + except-pass, invalid-commit, manifest-maintainers-list, - missing-newline-extrafiles, missing-readme, missing-return, odoo-addons-relative-import, - old-api7-method-defined, - po-msgstr-variables, - po-syntax-error, renamed-field-parameter, resource-not-exist, - str-format-used, test-folder-imported, translation-contains-variable, translation-positional-used, - unnecessary-utf8-coding-comment, website-manifest-key-not-valid-uri, - xml-attribute-translatable, - xml-deprecated-qweb-directive, - xml-deprecated-tree-attribute, external-request-timeout [REPORTS] diff --git a/README.md b/README.md index 9e4b34ac4..fe586385a 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,7 @@ +[![Support the OCA](https://odoo-community.org/readme-banner-image)](https://odoo-community.org/get-involved?utm_source=repo-readme) + +# server-env [![Runboat](https://img.shields.io/badge/runboat-Try%20me-875A7B.png)](https://runboat.odoo-community.org/builds?repo=OCA/server-env&target_branch=17.0) [![Pre-commit Status](https://github.com/OCA/server-env/actions/workflows/pre-commit.yml/badge.svg?branch=17.0)](https://github.com/OCA/server-env/actions/workflows/pre-commit.yml?query=branch%3A17.0) [![Build Status](https://github.com/OCA/server-env/actions/workflows/test.yml/badge.svg?branch=17.0)](https://github.com/OCA/server-env/actions/workflows/test.yml?query=branch%3A17.0) @@ -7,8 +10,6 @@ -# server-env - TODO: add repo description. @@ -24,7 +25,7 @@ addon | version | maintainers | summary [data_encryption](data_encryption/) | 17.0.1.0.0 | | Store accounts and credentials encrypted by environment [mail_environment](mail_environment/) | 17.0.1.0.1 | | Configure mail servers with server_environment_files [mail_environment_office365](mail_environment_office365/) | 17.0.1.0.0 | | Configure Office365 parameters with environment variables via server_environment -[server_environment](server_environment/) | 17.0.1.2.1 | | move some configurations out of the database +[server_environment](server_environment/) | 17.0.1.2.2 | | move some configurations out of the database [server_environment_autocreate](server_environment_autocreate/) | 17.0.1.0.0 | | Add ability to auto create records [server_environment_data_encryption](server_environment_data_encryption/) | 17.0.1.0.0 | florian-dacosta | Server Environment Data Encryption [server_environment_ir_config_parameter](server_environment_ir_config_parameter/) | 17.0.1.0.0 | | Override System Parameters from server environment file diff --git a/renovate.json b/renovate.json new file mode 100644 index 000000000..50065478e --- /dev/null +++ b/renovate.json @@ -0,0 +1,6 @@ +{ + "$schema": "https://docs.renovatebot.com/renovate-schema.json", + "extends": ["config:recommended", ":disableDependencyDashboard"], + "baseBranchPatterns": ["18.0", "17.0", "16.0", "15.0", "14.0"], + "enabledManagers": ["copier"] +} diff --git a/server_environment/README.rst b/server_environment/README.rst index 16d7a0cf3..9f0f0c082 100644 --- a/server_environment/README.rst +++ b/server_environment/README.rst @@ -11,7 +11,7 @@ server configuration environment files !! This file is generated by oca-gen-addon-readme !! !! changes will be overwritten. !! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - !! source digest: sha256:a32c7e5f13c20b97b02561de94e20ed507e8fd96e11287ff197692507be5b590 + !! source digest: sha256:bfb242c8cf384684a1067a797167c4d3dccf13cd9fc63a8520ad88d08861aece !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! .. |badge1| image:: https://img.shields.io/badge/maturity-Production%2FStable-green.png @@ -214,6 +214,171 @@ If you want to have a technical name to reference: [...] +Restoring columns on uninstall +------------------------------ + +When ``server.env.mixin`` is bound to an existing model, the ORM drops +the original stored columns for all env-managed fields. If the binding +addon is later uninstalled, those columns must be recreated so the +database remains usable. + +Add an ``uninstall_hook`` to your addon and delegate to +``restore_env_managed_columns``: + +:: + + # your_addon/__init__.py + from ./hooks import uninstall_hook + # your_addon/hooks.py + from odoo.addons.server_environment import uninstall + + def uninstall_hook(env): + uninstall.restore_env_managed_columns( + env, + "storage.backend", + ["directory_path", "other_field"], + ) + + # your_addon/__manifest__.py + { + ... + "uninstall_hook": "uninstall_hook", + } + +The helper creates any missing columns (idempotent: safe to call +multiple times) and repopulates them with each record's current +effective value — whether that value came from an environment +configuration file or from the stored default field +(``x__env_default``). + +The hook must run *before* the ORM extensions are removed, which is +guaranteed by Odoo's uninstall sequence (hooks execute before +``Module.module_uninstall()``). + +Handling required fields +~~~~~~~~~~~~~~~~~~~~~~~~ + +If a restored column is **required** (has a ``NOT NULL`` constraint) but +has no effective value (missing from environment config and no default +field set), the restoration will fail with a ``UserError``. + +**Solution:** pass a ``field_defaults`` dictionary with fallback values: + +:: + + def uninstall_hook(env): + restore_env_managed_columns( + env, + "ir.mail_server", + ["smtp_host", "smtp_authentication"], + field_defaults={ + "smtp_authentication": "login", # fallback for required field + }, + ) + +The helper will use the fallback value if provided and the computed +field value is empty. If no fallback is provided but a required field +has no value, a ``UserError`` is raised with instructions on how to +provide a ``field_defaults`` parameter. + +Migrating when dropping server_environment dependency +----------------------------------------------------- + +When refactoring an existing addon that embeds a ``server.env.mixin`` +binding, you may want to extract the binding into a separate *glue* +addon and drop the ``server_environment`` dependency from the original. +This keeps the base addon lightweight while preserving +server-environment features for those who install the glue addon. + +**Pattern:** + +- **Original addon (v1)**: depends on ``server_environment`` and binds + the mixin directly in model code. +- **Refactored addon (v2)**: removes ``server_environment`` from + dependencies, removes the mixin binding and the related ORM model + inheritance. +- **New glue addon** (optional, same version): depends on both + ``server_environment`` and the original addon v2; re-adds the mixin + binding in a separate module file. + +**Migration checklist:** + +1. In the **original addon's v2 ``__manifest__.py``**: + + - Remove ``"server_environment"`` from ``depends``. + - Remove the model file(s) that contained the mixin binding. + - Update ``depends`` to add the new glue addon *if* the base addon + still needs it (otherwise, make the glue addon optional for users + who want env-binding). + +2. In the **original addon's v2 model code**: + + - Delete or simplify the model class that inherited from + ``server.env.mixin``. + - If the model was only there for the binding, remove it entirely. + - Restore the original field definitions (not as computed fields). + +3. **Create a migration script** (if needed) to restore columns *during + the addon upgrade*, before the ORM model extensions are unloaded. Use + a ``@post_load`` hook or a dedicated migration script: + + :: + + # migrations/18.0.1.0.0/post-restore-columns.py + def migrate(cr, version): + # Call the restoration logic while the v1 model is still active + env = odoo.api.Environment(cr, odoo.SUPERUSER_ID, {}) + # If any field is required and may have no value in the environment, + # provide a fallback via field_defaults + restore_env_managed_columns( + env, + "storage.backend", + ["directory_path", "other_field"], + field_defaults={ + "directory_path": "/tmp", # fallback for required field + }, + ) + +4. **Create the glue addon** with the model re-inheritance: + + :: + + # your_addon_env/__init__.py + from . import models + + # your_addon_env/models/__init__.py + from . import storage_backend + + # your_addon_env/models/storage_backend.py + class StorageBackend(models.Model): + _name = "storage.backend" + _inherit = ["storage.backend", "server.env.mixin"] + + @property + def _server_env_fields(self): + return {"directory_path": {}} + + # your_addon_env/__manifest__.py + { + "name": "Storage Backend – Server Environment", + "version": "18.0.1.0.0", + "depends": ["server_environment", "storage_backend"], + "installable": True, + } + +**Key points:** + +- Column restoration must happen *during the addon upgrade* (step 3), + not as an uninstall hook, because the original model binding is still + active. +- The ``restore_env_managed_columns`` helper is idempotent and safe to + call even if columns already exist. +- Users who do not need server environment features simply do *not* + install the glue addon—the base addon continues to work with plain + database columns. +- Users who do need server environment can install both the base addon + (v2+) and the glue addon (same version) to get the binding back. + Known issues / Roadmap ====================== diff --git a/server_environment/__init__.py b/server_environment/__init__.py index 52bc6e602..85c79f6fd 100644 --- a/server_environment/__init__.py +++ b/server_environment/__init__.py @@ -1,3 +1,4 @@ from . import models from . import server_env from .server_env import serv_config, setboolean +from . import uninstall diff --git a/server_environment/__manifest__.py b/server_environment/__manifest__.py index 91af2f115..a0ebd9f75 100644 --- a/server_environment/__manifest__.py +++ b/server_environment/__manifest__.py @@ -4,7 +4,7 @@ { "name": "server configuration environment files", - "version": "17.0.1.2.1", + "version": "17.0.1.2.2", "depends": ["base", "base_sparse_field"], "author": "Camptocamp,Odoo Community Association (OCA)", "summary": "move some configurations out of the database", diff --git a/server_environment/i18n/am.po b/server_environment/i18n/am.po index 41ef73d55..c60164fb7 100644 --- a/server_environment/i18n/am.po +++ b/server_environment/i18n/am.po @@ -280,6 +280,11 @@ msgstr "" msgid "odoo | list_db" msgstr "" +#. module: server_environment +#: model:ir.model.fields,field_description:server_environment.field_server_config__odoo_I_log_config +msgid "odoo | log_config" +msgstr "" + #. module: server_environment #: model:ir.model.fields,field_description:server_environment.field_server_config__odoo_I_log_db msgid "odoo | log_db" diff --git a/server_environment/i18n/ar.po b/server_environment/i18n/ar.po index abaa7c4cb..68a54bdec 100644 --- a/server_environment/i18n/ar.po +++ b/server_environment/i18n/ar.po @@ -281,6 +281,11 @@ msgstr "" msgid "odoo | list_db" msgstr "" +#. module: server_environment +#: model:ir.model.fields,field_description:server_environment.field_server_config__odoo_I_log_config +msgid "odoo | log_config" +msgstr "" + #. module: server_environment #: model:ir.model.fields,field_description:server_environment.field_server_config__odoo_I_log_db msgid "odoo | log_db" diff --git a/server_environment/i18n/bg.po b/server_environment/i18n/bg.po index 861bf4c8e..3e9f58bca 100644 --- a/server_environment/i18n/bg.po +++ b/server_environment/i18n/bg.po @@ -280,6 +280,11 @@ msgstr "" msgid "odoo | list_db" msgstr "" +#. module: server_environment +#: model:ir.model.fields,field_description:server_environment.field_server_config__odoo_I_log_config +msgid "odoo | log_config" +msgstr "" + #. module: server_environment #: model:ir.model.fields,field_description:server_environment.field_server_config__odoo_I_log_db msgid "odoo | log_db" diff --git a/server_environment/i18n/bs.po b/server_environment/i18n/bs.po index b5f732e75..6493a1bed 100644 --- a/server_environment/i18n/bs.po +++ b/server_environment/i18n/bs.po @@ -281,6 +281,11 @@ msgstr "" msgid "odoo | list_db" msgstr "" +#. module: server_environment +#: model:ir.model.fields,field_description:server_environment.field_server_config__odoo_I_log_config +msgid "odoo | log_config" +msgstr "" + #. module: server_environment #: model:ir.model.fields,field_description:server_environment.field_server_config__odoo_I_log_db msgid "odoo | log_db" diff --git a/server_environment/i18n/ca.po b/server_environment/i18n/ca.po index 30db19852..6ef4cfbd0 100644 --- a/server_environment/i18n/ca.po +++ b/server_environment/i18n/ca.po @@ -280,6 +280,11 @@ msgstr "" msgid "odoo | list_db" msgstr "" +#. module: server_environment +#: model:ir.model.fields,field_description:server_environment.field_server_config__odoo_I_log_config +msgid "odoo | log_config" +msgstr "" + #. module: server_environment #: model:ir.model.fields,field_description:server_environment.field_server_config__odoo_I_log_db msgid "odoo | log_db" diff --git a/server_environment/i18n/cs.po b/server_environment/i18n/cs.po index 29768802d..e094867f4 100644 --- a/server_environment/i18n/cs.po +++ b/server_environment/i18n/cs.po @@ -280,6 +280,11 @@ msgstr "" msgid "odoo | list_db" msgstr "" +#. module: server_environment +#: model:ir.model.fields,field_description:server_environment.field_server_config__odoo_I_log_config +msgid "odoo | log_config" +msgstr "" + #. module: server_environment #: model:ir.model.fields,field_description:server_environment.field_server_config__odoo_I_log_db msgid "odoo | log_db" diff --git a/server_environment/i18n/da.po b/server_environment/i18n/da.po index f1cd9973a..f1bc149a1 100644 --- a/server_environment/i18n/da.po +++ b/server_environment/i18n/da.po @@ -280,6 +280,11 @@ msgstr "" msgid "odoo | list_db" msgstr "" +#. module: server_environment +#: model:ir.model.fields,field_description:server_environment.field_server_config__odoo_I_log_config +msgid "odoo | log_config" +msgstr "" + #. module: server_environment #: model:ir.model.fields,field_description:server_environment.field_server_config__odoo_I_log_db msgid "odoo | log_db" diff --git a/server_environment/i18n/de.po b/server_environment/i18n/de.po index c3c427a56..2fa2fabe9 100644 --- a/server_environment/i18n/de.po +++ b/server_environment/i18n/de.po @@ -283,6 +283,11 @@ msgstr "" msgid "odoo | list_db" msgstr "" +#. module: server_environment +#: model:ir.model.fields,field_description:server_environment.field_server_config__odoo_I_log_config +msgid "odoo | log_config" +msgstr "" + #. module: server_environment #: model:ir.model.fields,field_description:server_environment.field_server_config__odoo_I_log_db msgid "odoo | log_db" diff --git a/server_environment/i18n/el_GR.po b/server_environment/i18n/el_GR.po index af9a99df2..ca91e856b 100644 --- a/server_environment/i18n/el_GR.po +++ b/server_environment/i18n/el_GR.po @@ -280,6 +280,11 @@ msgstr "" msgid "odoo | list_db" msgstr "" +#. module: server_environment +#: model:ir.model.fields,field_description:server_environment.field_server_config__odoo_I_log_config +msgid "odoo | log_config" +msgstr "" + #. module: server_environment #: model:ir.model.fields,field_description:server_environment.field_server_config__odoo_I_log_db msgid "odoo | log_db" diff --git a/server_environment/i18n/en_GB.po b/server_environment/i18n/en_GB.po index 827b65dc7..638ae9efd 100644 --- a/server_environment/i18n/en_GB.po +++ b/server_environment/i18n/en_GB.po @@ -281,6 +281,11 @@ msgstr "" msgid "odoo | list_db" msgstr "" +#. module: server_environment +#: model:ir.model.fields,field_description:server_environment.field_server_config__odoo_I_log_config +msgid "odoo | log_config" +msgstr "" + #. module: server_environment #: model:ir.model.fields,field_description:server_environment.field_server_config__odoo_I_log_db msgid "odoo | log_db" diff --git a/server_environment/i18n/es.po b/server_environment/i18n/es.po index 63ffd46f2..7d52e6909 100644 --- a/server_environment/i18n/es.po +++ b/server_environment/i18n/es.po @@ -283,6 +283,11 @@ msgstr "" msgid "odoo | list_db" msgstr "odoo | list_db" +#. module: server_environment +#: model:ir.model.fields,field_description:server_environment.field_server_config__odoo_I_log_config +msgid "odoo | log_config" +msgstr "" + #. module: server_environment #: model:ir.model.fields,field_description:server_environment.field_server_config__odoo_I_log_db msgid "odoo | log_db" diff --git a/server_environment/i18n/es_AR.po b/server_environment/i18n/es_AR.po index 894c8e1f7..1fafb5cf8 100644 --- a/server_environment/i18n/es_AR.po +++ b/server_environment/i18n/es_AR.po @@ -281,6 +281,11 @@ msgstr "" msgid "odoo | list_db" msgstr "" +#. module: server_environment +#: model:ir.model.fields,field_description:server_environment.field_server_config__odoo_I_log_config +msgid "odoo | log_config" +msgstr "" + #. module: server_environment #: model:ir.model.fields,field_description:server_environment.field_server_config__odoo_I_log_db msgid "odoo | log_db" diff --git a/server_environment/i18n/es_CL.po b/server_environment/i18n/es_CL.po index 73a6b9559..c0505293f 100644 --- a/server_environment/i18n/es_CL.po +++ b/server_environment/i18n/es_CL.po @@ -281,6 +281,11 @@ msgstr "" msgid "odoo | list_db" msgstr "" +#. module: server_environment +#: model:ir.model.fields,field_description:server_environment.field_server_config__odoo_I_log_config +msgid "odoo | log_config" +msgstr "" + #. module: server_environment #: model:ir.model.fields,field_description:server_environment.field_server_config__odoo_I_log_db msgid "odoo | log_db" diff --git a/server_environment/i18n/es_CO.po b/server_environment/i18n/es_CO.po index 679ec7c86..21ce13ef7 100644 --- a/server_environment/i18n/es_CO.po +++ b/server_environment/i18n/es_CO.po @@ -281,6 +281,11 @@ msgstr "" msgid "odoo | list_db" msgstr "" +#. module: server_environment +#: model:ir.model.fields,field_description:server_environment.field_server_config__odoo_I_log_config +msgid "odoo | log_config" +msgstr "" + #. module: server_environment #: model:ir.model.fields,field_description:server_environment.field_server_config__odoo_I_log_db msgid "odoo | log_db" diff --git a/server_environment/i18n/es_CR.po b/server_environment/i18n/es_CR.po index d1e910a39..ab62445e8 100644 --- a/server_environment/i18n/es_CR.po +++ b/server_environment/i18n/es_CR.po @@ -281,6 +281,11 @@ msgstr "" msgid "odoo | list_db" msgstr "" +#. module: server_environment +#: model:ir.model.fields,field_description:server_environment.field_server_config__odoo_I_log_config +msgid "odoo | log_config" +msgstr "" + #. module: server_environment #: model:ir.model.fields,field_description:server_environment.field_server_config__odoo_I_log_db msgid "odoo | log_db" diff --git a/server_environment/i18n/es_DO.po b/server_environment/i18n/es_DO.po index 722bea679..317734a4c 100644 --- a/server_environment/i18n/es_DO.po +++ b/server_environment/i18n/es_DO.po @@ -281,6 +281,11 @@ msgstr "" msgid "odoo | list_db" msgstr "" +#. module: server_environment +#: model:ir.model.fields,field_description:server_environment.field_server_config__odoo_I_log_config +msgid "odoo | log_config" +msgstr "" + #. module: server_environment #: model:ir.model.fields,field_description:server_environment.field_server_config__odoo_I_log_db msgid "odoo | log_db" diff --git a/server_environment/i18n/es_EC.po b/server_environment/i18n/es_EC.po index a0028d6fb..70aa36656 100644 --- a/server_environment/i18n/es_EC.po +++ b/server_environment/i18n/es_EC.po @@ -281,6 +281,11 @@ msgstr "" msgid "odoo | list_db" msgstr "" +#. module: server_environment +#: model:ir.model.fields,field_description:server_environment.field_server_config__odoo_I_log_config +msgid "odoo | log_config" +msgstr "" + #. module: server_environment #: model:ir.model.fields,field_description:server_environment.field_server_config__odoo_I_log_db msgid "odoo | log_db" diff --git a/server_environment/i18n/es_ES.po b/server_environment/i18n/es_ES.po index 066e9f2c7..6b49d4c21 100644 --- a/server_environment/i18n/es_ES.po +++ b/server_environment/i18n/es_ES.po @@ -281,6 +281,11 @@ msgstr "" msgid "odoo | list_db" msgstr "" +#. module: server_environment +#: model:ir.model.fields,field_description:server_environment.field_server_config__odoo_I_log_config +msgid "odoo | log_config" +msgstr "" + #. module: server_environment #: model:ir.model.fields,field_description:server_environment.field_server_config__odoo_I_log_db msgid "odoo | log_db" diff --git a/server_environment/i18n/es_MX.po b/server_environment/i18n/es_MX.po index 4d8f9b999..9f7cba3ff 100644 --- a/server_environment/i18n/es_MX.po +++ b/server_environment/i18n/es_MX.po @@ -281,6 +281,11 @@ msgstr "" msgid "odoo | list_db" msgstr "" +#. module: server_environment +#: model:ir.model.fields,field_description:server_environment.field_server_config__odoo_I_log_config +msgid "odoo | log_config" +msgstr "" + #. module: server_environment #: model:ir.model.fields,field_description:server_environment.field_server_config__odoo_I_log_db msgid "odoo | log_db" diff --git a/server_environment/i18n/es_PE.po b/server_environment/i18n/es_PE.po index 37dc0bdac..5baa12c99 100644 --- a/server_environment/i18n/es_PE.po +++ b/server_environment/i18n/es_PE.po @@ -281,6 +281,11 @@ msgstr "" msgid "odoo | list_db" msgstr "" +#. module: server_environment +#: model:ir.model.fields,field_description:server_environment.field_server_config__odoo_I_log_config +msgid "odoo | log_config" +msgstr "" + #. module: server_environment #: model:ir.model.fields,field_description:server_environment.field_server_config__odoo_I_log_db msgid "odoo | log_db" diff --git a/server_environment/i18n/es_PY.po b/server_environment/i18n/es_PY.po index dfc859740..18e5e21fd 100644 --- a/server_environment/i18n/es_PY.po +++ b/server_environment/i18n/es_PY.po @@ -281,6 +281,11 @@ msgstr "" msgid "odoo | list_db" msgstr "" +#. module: server_environment +#: model:ir.model.fields,field_description:server_environment.field_server_config__odoo_I_log_config +msgid "odoo | log_config" +msgstr "" + #. module: server_environment #: model:ir.model.fields,field_description:server_environment.field_server_config__odoo_I_log_db msgid "odoo | log_db" diff --git a/server_environment/i18n/es_VE.po b/server_environment/i18n/es_VE.po index 14815c651..2e3d94643 100644 --- a/server_environment/i18n/es_VE.po +++ b/server_environment/i18n/es_VE.po @@ -281,6 +281,11 @@ msgstr "" msgid "odoo | list_db" msgstr "" +#. module: server_environment +#: model:ir.model.fields,field_description:server_environment.field_server_config__odoo_I_log_config +msgid "odoo | log_config" +msgstr "" + #. module: server_environment #: model:ir.model.fields,field_description:server_environment.field_server_config__odoo_I_log_db msgid "odoo | log_db" diff --git a/server_environment/i18n/et.po b/server_environment/i18n/et.po index 65f075a47..dfd4b63dc 100644 --- a/server_environment/i18n/et.po +++ b/server_environment/i18n/et.po @@ -280,6 +280,11 @@ msgstr "" msgid "odoo | list_db" msgstr "" +#. module: server_environment +#: model:ir.model.fields,field_description:server_environment.field_server_config__odoo_I_log_config +msgid "odoo | log_config" +msgstr "" + #. module: server_environment #: model:ir.model.fields,field_description:server_environment.field_server_config__odoo_I_log_db msgid "odoo | log_db" diff --git a/server_environment/i18n/eu.po b/server_environment/i18n/eu.po index 2d952aa3a..106c4473c 100644 --- a/server_environment/i18n/eu.po +++ b/server_environment/i18n/eu.po @@ -280,6 +280,11 @@ msgstr "" msgid "odoo | list_db" msgstr "" +#. module: server_environment +#: model:ir.model.fields,field_description:server_environment.field_server_config__odoo_I_log_config +msgid "odoo | log_config" +msgstr "" + #. module: server_environment #: model:ir.model.fields,field_description:server_environment.field_server_config__odoo_I_log_db msgid "odoo | log_db" diff --git a/server_environment/i18n/fa.po b/server_environment/i18n/fa.po index f799082ed..9d759d6ef 100644 --- a/server_environment/i18n/fa.po +++ b/server_environment/i18n/fa.po @@ -280,6 +280,11 @@ msgstr "" msgid "odoo | list_db" msgstr "" +#. module: server_environment +#: model:ir.model.fields,field_description:server_environment.field_server_config__odoo_I_log_config +msgid "odoo | log_config" +msgstr "" + #. module: server_environment #: model:ir.model.fields,field_description:server_environment.field_server_config__odoo_I_log_db msgid "odoo | log_db" diff --git a/server_environment/i18n/fi.po b/server_environment/i18n/fi.po index ff3cfac10..2a45274cc 100644 --- a/server_environment/i18n/fi.po +++ b/server_environment/i18n/fi.po @@ -280,6 +280,11 @@ msgstr "" msgid "odoo | list_db" msgstr "" +#. module: server_environment +#: model:ir.model.fields,field_description:server_environment.field_server_config__odoo_I_log_config +msgid "odoo | log_config" +msgstr "" + #. module: server_environment #: model:ir.model.fields,field_description:server_environment.field_server_config__odoo_I_log_db msgid "odoo | log_db" diff --git a/server_environment/i18n/fr.po b/server_environment/i18n/fr.po index dfe9279ad..396caa8a6 100644 --- a/server_environment/i18n/fr.po +++ b/server_environment/i18n/fr.po @@ -282,6 +282,11 @@ msgstr "odoo | limit_time_worker_cron" msgid "odoo | list_db" msgstr "odoo | list_db" +#. module: server_environment +#: model:ir.model.fields,field_description:server_environment.field_server_config__odoo_I_log_config +msgid "odoo | log_config" +msgstr "" + #. module: server_environment #: model:ir.model.fields,field_description:server_environment.field_server_config__odoo_I_log_db msgid "odoo | log_db" diff --git a/server_environment/i18n/fr_CA.po b/server_environment/i18n/fr_CA.po index 2cfbb87c2..f0cc52107 100644 --- a/server_environment/i18n/fr_CA.po +++ b/server_environment/i18n/fr_CA.po @@ -281,6 +281,11 @@ msgstr "" msgid "odoo | list_db" msgstr "" +#. module: server_environment +#: model:ir.model.fields,field_description:server_environment.field_server_config__odoo_I_log_config +msgid "odoo | log_config" +msgstr "" + #. module: server_environment #: model:ir.model.fields,field_description:server_environment.field_server_config__odoo_I_log_db msgid "odoo | log_db" diff --git a/server_environment/i18n/fr_CH.po b/server_environment/i18n/fr_CH.po index c40696f1c..d522ef80d 100644 --- a/server_environment/i18n/fr_CH.po +++ b/server_environment/i18n/fr_CH.po @@ -281,6 +281,11 @@ msgstr "" msgid "odoo | list_db" msgstr "" +#. module: server_environment +#: model:ir.model.fields,field_description:server_environment.field_server_config__odoo_I_log_config +msgid "odoo | log_config" +msgstr "" + #. module: server_environment #: model:ir.model.fields,field_description:server_environment.field_server_config__odoo_I_log_db msgid "odoo | log_db" diff --git a/server_environment/i18n/gl.po b/server_environment/i18n/gl.po index aefa8fadd..36324031c 100644 --- a/server_environment/i18n/gl.po +++ b/server_environment/i18n/gl.po @@ -280,6 +280,11 @@ msgstr "" msgid "odoo | list_db" msgstr "" +#. module: server_environment +#: model:ir.model.fields,field_description:server_environment.field_server_config__odoo_I_log_config +msgid "odoo | log_config" +msgstr "" + #. module: server_environment #: model:ir.model.fields,field_description:server_environment.field_server_config__odoo_I_log_db msgid "odoo | log_db" diff --git a/server_environment/i18n/gl_ES.po b/server_environment/i18n/gl_ES.po index 14b2e7edc..64700e1a1 100644 --- a/server_environment/i18n/gl_ES.po +++ b/server_environment/i18n/gl_ES.po @@ -281,6 +281,11 @@ msgstr "" msgid "odoo | list_db" msgstr "" +#. module: server_environment +#: model:ir.model.fields,field_description:server_environment.field_server_config__odoo_I_log_config +msgid "odoo | log_config" +msgstr "" + #. module: server_environment #: model:ir.model.fields,field_description:server_environment.field_server_config__odoo_I_log_db msgid "odoo | log_db" diff --git a/server_environment/i18n/he.po b/server_environment/i18n/he.po index a6cfb17f0..1251337f9 100644 --- a/server_environment/i18n/he.po +++ b/server_environment/i18n/he.po @@ -280,6 +280,11 @@ msgstr "" msgid "odoo | list_db" msgstr "" +#. module: server_environment +#: model:ir.model.fields,field_description:server_environment.field_server_config__odoo_I_log_config +msgid "odoo | log_config" +msgstr "" + #. module: server_environment #: model:ir.model.fields,field_description:server_environment.field_server_config__odoo_I_log_db msgid "odoo | log_db" diff --git a/server_environment/i18n/hr.po b/server_environment/i18n/hr.po index 0077d51af..ca6340c81 100644 --- a/server_environment/i18n/hr.po +++ b/server_environment/i18n/hr.po @@ -281,6 +281,11 @@ msgstr "" msgid "odoo | list_db" msgstr "" +#. module: server_environment +#: model:ir.model.fields,field_description:server_environment.field_server_config__odoo_I_log_config +msgid "odoo | log_config" +msgstr "" + #. module: server_environment #: model:ir.model.fields,field_description:server_environment.field_server_config__odoo_I_log_db msgid "odoo | log_db" diff --git a/server_environment/i18n/hr_HR.po b/server_environment/i18n/hr_HR.po index 629dbd4b9..e69f71f58 100644 --- a/server_environment/i18n/hr_HR.po +++ b/server_environment/i18n/hr_HR.po @@ -281,6 +281,11 @@ msgstr "" msgid "odoo | list_db" msgstr "" +#. module: server_environment +#: model:ir.model.fields,field_description:server_environment.field_server_config__odoo_I_log_config +msgid "odoo | log_config" +msgstr "" + #. module: server_environment #: model:ir.model.fields,field_description:server_environment.field_server_config__odoo_I_log_db msgid "odoo | log_db" diff --git a/server_environment/i18n/hu.po b/server_environment/i18n/hu.po index c753cc44b..0017b6a47 100644 --- a/server_environment/i18n/hu.po +++ b/server_environment/i18n/hu.po @@ -280,6 +280,11 @@ msgstr "" msgid "odoo | list_db" msgstr "" +#. module: server_environment +#: model:ir.model.fields,field_description:server_environment.field_server_config__odoo_I_log_config +msgid "odoo | log_config" +msgstr "" + #. module: server_environment #: model:ir.model.fields,field_description:server_environment.field_server_config__odoo_I_log_db msgid "odoo | log_db" diff --git a/server_environment/i18n/id.po b/server_environment/i18n/id.po index ba3a18f62..fcfc59378 100644 --- a/server_environment/i18n/id.po +++ b/server_environment/i18n/id.po @@ -280,6 +280,11 @@ msgstr "" msgid "odoo | list_db" msgstr "" +#. module: server_environment +#: model:ir.model.fields,field_description:server_environment.field_server_config__odoo_I_log_config +msgid "odoo | log_config" +msgstr "" + #. module: server_environment #: model:ir.model.fields,field_description:server_environment.field_server_config__odoo_I_log_db msgid "odoo | log_db" diff --git a/server_environment/i18n/it.po b/server_environment/i18n/it.po index e2f2091de..ded07cdec 100644 --- a/server_environment/i18n/it.po +++ b/server_environment/i18n/it.po @@ -281,6 +281,11 @@ msgstr "odoo | limit_time_worker_cron" msgid "odoo | list_db" msgstr "odoo | list_db" +#. module: server_environment +#: model:ir.model.fields,field_description:server_environment.field_server_config__odoo_I_log_config +msgid "odoo | log_config" +msgstr "" + #. module: server_environment #: model:ir.model.fields,field_description:server_environment.field_server_config__odoo_I_log_db msgid "odoo | log_db" diff --git a/server_environment/i18n/ja.po b/server_environment/i18n/ja.po index 50e47df7c..f614eb76b 100644 --- a/server_environment/i18n/ja.po +++ b/server_environment/i18n/ja.po @@ -280,6 +280,11 @@ msgstr "" msgid "odoo | list_db" msgstr "" +#. module: server_environment +#: model:ir.model.fields,field_description:server_environment.field_server_config__odoo_I_log_config +msgid "odoo | log_config" +msgstr "" + #. module: server_environment #: model:ir.model.fields,field_description:server_environment.field_server_config__odoo_I_log_db msgid "odoo | log_db" diff --git a/server_environment/i18n/ko.po b/server_environment/i18n/ko.po index 0cd79372c..971ece113 100644 --- a/server_environment/i18n/ko.po +++ b/server_environment/i18n/ko.po @@ -280,6 +280,11 @@ msgstr "" msgid "odoo | list_db" msgstr "" +#. module: server_environment +#: model:ir.model.fields,field_description:server_environment.field_server_config__odoo_I_log_config +msgid "odoo | log_config" +msgstr "" + #. module: server_environment #: model:ir.model.fields,field_description:server_environment.field_server_config__odoo_I_log_db msgid "odoo | log_db" diff --git a/server_environment/i18n/lt.po b/server_environment/i18n/lt.po index 5fd3e1b57..b3d03e1df 100644 --- a/server_environment/i18n/lt.po +++ b/server_environment/i18n/lt.po @@ -281,6 +281,11 @@ msgstr "" msgid "odoo | list_db" msgstr "" +#. module: server_environment +#: model:ir.model.fields,field_description:server_environment.field_server_config__odoo_I_log_config +msgid "odoo | log_config" +msgstr "" + #. module: server_environment #: model:ir.model.fields,field_description:server_environment.field_server_config__odoo_I_log_db msgid "odoo | log_db" diff --git a/server_environment/i18n/lt_LT.po b/server_environment/i18n/lt_LT.po index 44df19791..10df2b39f 100644 --- a/server_environment/i18n/lt_LT.po +++ b/server_environment/i18n/lt_LT.po @@ -282,6 +282,11 @@ msgstr "" msgid "odoo | list_db" msgstr "" +#. module: server_environment +#: model:ir.model.fields,field_description:server_environment.field_server_config__odoo_I_log_config +msgid "odoo | log_config" +msgstr "" + #. module: server_environment #: model:ir.model.fields,field_description:server_environment.field_server_config__odoo_I_log_db msgid "odoo | log_db" diff --git a/server_environment/i18n/lv.po b/server_environment/i18n/lv.po index ec470b1c2..8aa44ce93 100644 --- a/server_environment/i18n/lv.po +++ b/server_environment/i18n/lv.po @@ -281,6 +281,11 @@ msgstr "" msgid "odoo | list_db" msgstr "" +#. module: server_environment +#: model:ir.model.fields,field_description:server_environment.field_server_config__odoo_I_log_config +msgid "odoo | log_config" +msgstr "" + #. module: server_environment #: model:ir.model.fields,field_description:server_environment.field_server_config__odoo_I_log_db msgid "odoo | log_db" diff --git a/server_environment/i18n/mk.po b/server_environment/i18n/mk.po index f0e5a14e9..5d086e5fd 100644 --- a/server_environment/i18n/mk.po +++ b/server_environment/i18n/mk.po @@ -280,6 +280,11 @@ msgstr "" msgid "odoo | list_db" msgstr "" +#. module: server_environment +#: model:ir.model.fields,field_description:server_environment.field_server_config__odoo_I_log_config +msgid "odoo | log_config" +msgstr "" + #. module: server_environment #: model:ir.model.fields,field_description:server_environment.field_server_config__odoo_I_log_db msgid "odoo | log_db" diff --git a/server_environment/i18n/mn.po b/server_environment/i18n/mn.po index 805149fda..4827e9055 100644 --- a/server_environment/i18n/mn.po +++ b/server_environment/i18n/mn.po @@ -280,6 +280,11 @@ msgstr "" msgid "odoo | list_db" msgstr "" +#. module: server_environment +#: model:ir.model.fields,field_description:server_environment.field_server_config__odoo_I_log_config +msgid "odoo | log_config" +msgstr "" + #. module: server_environment #: model:ir.model.fields,field_description:server_environment.field_server_config__odoo_I_log_db msgid "odoo | log_db" diff --git a/server_environment/i18n/nb.po b/server_environment/i18n/nb.po index 4723d2b78..5df9b5adf 100644 --- a/server_environment/i18n/nb.po +++ b/server_environment/i18n/nb.po @@ -281,6 +281,11 @@ msgstr "" msgid "odoo | list_db" msgstr "" +#. module: server_environment +#: model:ir.model.fields,field_description:server_environment.field_server_config__odoo_I_log_config +msgid "odoo | log_config" +msgstr "" + #. module: server_environment #: model:ir.model.fields,field_description:server_environment.field_server_config__odoo_I_log_db msgid "odoo | log_db" diff --git a/server_environment/i18n/nb_NO.po b/server_environment/i18n/nb_NO.po index f78eff0ff..7dea71366 100644 --- a/server_environment/i18n/nb_NO.po +++ b/server_environment/i18n/nb_NO.po @@ -281,6 +281,11 @@ msgstr "" msgid "odoo | list_db" msgstr "" +#. module: server_environment +#: model:ir.model.fields,field_description:server_environment.field_server_config__odoo_I_log_config +msgid "odoo | log_config" +msgstr "" + #. module: server_environment #: model:ir.model.fields,field_description:server_environment.field_server_config__odoo_I_log_db msgid "odoo | log_db" diff --git a/server_environment/i18n/nl.po b/server_environment/i18n/nl.po index 3184fa618..2820d0e3e 100644 --- a/server_environment/i18n/nl.po +++ b/server_environment/i18n/nl.po @@ -280,6 +280,11 @@ msgstr "" msgid "odoo | list_db" msgstr "" +#. module: server_environment +#: model:ir.model.fields,field_description:server_environment.field_server_config__odoo_I_log_config +msgid "odoo | log_config" +msgstr "" + #. module: server_environment #: model:ir.model.fields,field_description:server_environment.field_server_config__odoo_I_log_db msgid "odoo | log_db" diff --git a/server_environment/i18n/nl_BE.po b/server_environment/i18n/nl_BE.po index 1b8c390e4..6c31441b9 100644 --- a/server_environment/i18n/nl_BE.po +++ b/server_environment/i18n/nl_BE.po @@ -281,6 +281,11 @@ msgstr "" msgid "odoo | list_db" msgstr "" +#. module: server_environment +#: model:ir.model.fields,field_description:server_environment.field_server_config__odoo_I_log_config +msgid "odoo | log_config" +msgstr "" + #. module: server_environment #: model:ir.model.fields,field_description:server_environment.field_server_config__odoo_I_log_db msgid "odoo | log_db" diff --git a/server_environment/i18n/nl_NL.po b/server_environment/i18n/nl_NL.po index 47747c0d0..8b848552e 100644 --- a/server_environment/i18n/nl_NL.po +++ b/server_environment/i18n/nl_NL.po @@ -281,6 +281,11 @@ msgstr "" msgid "odoo | list_db" msgstr "" +#. module: server_environment +#: model:ir.model.fields,field_description:server_environment.field_server_config__odoo_I_log_config +msgid "odoo | log_config" +msgstr "" + #. module: server_environment #: model:ir.model.fields,field_description:server_environment.field_server_config__odoo_I_log_db msgid "odoo | log_db" diff --git a/server_environment/i18n/pl.po b/server_environment/i18n/pl.po index a083007ac..fe0298f05 100644 --- a/server_environment/i18n/pl.po +++ b/server_environment/i18n/pl.po @@ -282,6 +282,11 @@ msgstr "" msgid "odoo | list_db" msgstr "" +#. module: server_environment +#: model:ir.model.fields,field_description:server_environment.field_server_config__odoo_I_log_config +msgid "odoo | log_config" +msgstr "" + #. module: server_environment #: model:ir.model.fields,field_description:server_environment.field_server_config__odoo_I_log_db msgid "odoo | log_db" diff --git a/server_environment/i18n/pt.po b/server_environment/i18n/pt.po index ebbcd9549..386769773 100644 --- a/server_environment/i18n/pt.po +++ b/server_environment/i18n/pt.po @@ -280,6 +280,11 @@ msgstr "" msgid "odoo | list_db" msgstr "" +#. module: server_environment +#: model:ir.model.fields,field_description:server_environment.field_server_config__odoo_I_log_config +msgid "odoo | log_config" +msgstr "" + #. module: server_environment #: model:ir.model.fields,field_description:server_environment.field_server_config__odoo_I_log_db msgid "odoo | log_db" diff --git a/server_environment/i18n/pt_BR.po b/server_environment/i18n/pt_BR.po index 04e7fcb6a..c791e1a51 100644 --- a/server_environment/i18n/pt_BR.po +++ b/server_environment/i18n/pt_BR.po @@ -300,6 +300,11 @@ msgstr "" msgid "odoo | list_db" msgstr "" +#. module: server_environment +#: model:ir.model.fields,field_description:server_environment.field_server_config__odoo_I_log_config +msgid "odoo | log_config" +msgstr "" + #. module: server_environment #: model:ir.model.fields,field_description:server_environment.field_server_config__odoo_I_log_db msgid "odoo | log_db" diff --git a/server_environment/i18n/pt_PT.po b/server_environment/i18n/pt_PT.po index d9fcc71f4..ce3d9e8d1 100644 --- a/server_environment/i18n/pt_PT.po +++ b/server_environment/i18n/pt_PT.po @@ -281,6 +281,11 @@ msgstr "" msgid "odoo | list_db" msgstr "" +#. module: server_environment +#: model:ir.model.fields,field_description:server_environment.field_server_config__odoo_I_log_config +msgid "odoo | log_config" +msgstr "" + #. module: server_environment #: model:ir.model.fields,field_description:server_environment.field_server_config__odoo_I_log_db msgid "odoo | log_db" diff --git a/server_environment/i18n/ro.po b/server_environment/i18n/ro.po index 7f90433fc..556b79883 100644 --- a/server_environment/i18n/ro.po +++ b/server_environment/i18n/ro.po @@ -281,6 +281,11 @@ msgstr "" msgid "odoo | list_db" msgstr "" +#. module: server_environment +#: model:ir.model.fields,field_description:server_environment.field_server_config__odoo_I_log_config +msgid "odoo | log_config" +msgstr "" + #. module: server_environment #: model:ir.model.fields,field_description:server_environment.field_server_config__odoo_I_log_db msgid "odoo | log_db" diff --git a/server_environment/i18n/ru.po b/server_environment/i18n/ru.po index 9c7b56a91..77ec6e9d2 100644 --- a/server_environment/i18n/ru.po +++ b/server_environment/i18n/ru.po @@ -282,6 +282,11 @@ msgstr "" msgid "odoo | list_db" msgstr "" +#. module: server_environment +#: model:ir.model.fields,field_description:server_environment.field_server_config__odoo_I_log_config +msgid "odoo | log_config" +msgstr "" + #. module: server_environment #: model:ir.model.fields,field_description:server_environment.field_server_config__odoo_I_log_db msgid "odoo | log_db" diff --git a/server_environment/i18n/server_environment.pot b/server_environment/i18n/server_environment.pot index 8ad40d909..239f3cced 100644 --- a/server_environment/i18n/server_environment.pot +++ b/server_environment/i18n/server_environment.pot @@ -275,6 +275,11 @@ msgstr "" msgid "odoo | list_db" msgstr "" +#. module: server_environment +#: model:ir.model.fields,field_description:server_environment.field_server_config__odoo_I_log_config +msgid "odoo | log_config" +msgstr "" + #. module: server_environment #: model:ir.model.fields,field_description:server_environment.field_server_config__odoo_I_log_db msgid "odoo | log_db" diff --git a/server_environment/i18n/sk.po b/server_environment/i18n/sk.po index 82ce79a46..2529b5c18 100644 --- a/server_environment/i18n/sk.po +++ b/server_environment/i18n/sk.po @@ -280,6 +280,11 @@ msgstr "" msgid "odoo | list_db" msgstr "" +#. module: server_environment +#: model:ir.model.fields,field_description:server_environment.field_server_config__odoo_I_log_config +msgid "odoo | log_config" +msgstr "" + #. module: server_environment #: model:ir.model.fields,field_description:server_environment.field_server_config__odoo_I_log_db msgid "odoo | log_db" diff --git a/server_environment/i18n/sl.po b/server_environment/i18n/sl.po index 1d857609a..e93048bc7 100644 --- a/server_environment/i18n/sl.po +++ b/server_environment/i18n/sl.po @@ -284,6 +284,11 @@ msgstr "" msgid "odoo | list_db" msgstr "" +#. module: server_environment +#: model:ir.model.fields,field_description:server_environment.field_server_config__odoo_I_log_config +msgid "odoo | log_config" +msgstr "" + #. module: server_environment #: model:ir.model.fields,field_description:server_environment.field_server_config__odoo_I_log_db msgid "odoo | log_db" diff --git a/server_environment/i18n/sr.po b/server_environment/i18n/sr.po index 740d4e0f8..af5a11285 100644 --- a/server_environment/i18n/sr.po +++ b/server_environment/i18n/sr.po @@ -281,6 +281,11 @@ msgstr "" msgid "odoo | list_db" msgstr "" +#. module: server_environment +#: model:ir.model.fields,field_description:server_environment.field_server_config__odoo_I_log_config +msgid "odoo | log_config" +msgstr "" + #. module: server_environment #: model:ir.model.fields,field_description:server_environment.field_server_config__odoo_I_log_db msgid "odoo | log_db" diff --git a/server_environment/i18n/sr@latin.po b/server_environment/i18n/sr@latin.po index c925ab1d5..bcde409ed 100644 --- a/server_environment/i18n/sr@latin.po +++ b/server_environment/i18n/sr@latin.po @@ -282,6 +282,11 @@ msgstr "" msgid "odoo | list_db" msgstr "" +#. module: server_environment +#: model:ir.model.fields,field_description:server_environment.field_server_config__odoo_I_log_config +msgid "odoo | log_config" +msgstr "" + #. module: server_environment #: model:ir.model.fields,field_description:server_environment.field_server_config__odoo_I_log_db msgid "odoo | log_db" diff --git a/server_environment/i18n/sv.po b/server_environment/i18n/sv.po index 899ccaf9a..b80868ccb 100644 --- a/server_environment/i18n/sv.po +++ b/server_environment/i18n/sv.po @@ -281,6 +281,11 @@ msgstr "" msgid "odoo | list_db" msgstr "odoo | list_db" +#. module: server_environment +#: model:ir.model.fields,field_description:server_environment.field_server_config__odoo_I_log_config +msgid "odoo | log_config" +msgstr "" + #. module: server_environment #: model:ir.model.fields,field_description:server_environment.field_server_config__odoo_I_log_db msgid "odoo | log_db" diff --git a/server_environment/i18n/th.po b/server_environment/i18n/th.po index 4cbabae0f..46a7d6ee4 100644 --- a/server_environment/i18n/th.po +++ b/server_environment/i18n/th.po @@ -280,6 +280,11 @@ msgstr "" msgid "odoo | list_db" msgstr "" +#. module: server_environment +#: model:ir.model.fields,field_description:server_environment.field_server_config__odoo_I_log_config +msgid "odoo | log_config" +msgstr "" + #. module: server_environment #: model:ir.model.fields,field_description:server_environment.field_server_config__odoo_I_log_db msgid "odoo | log_db" diff --git a/server_environment/i18n/tr.po b/server_environment/i18n/tr.po index a298e1294..b17e6474f 100644 --- a/server_environment/i18n/tr.po +++ b/server_environment/i18n/tr.po @@ -280,6 +280,11 @@ msgstr "" msgid "odoo | list_db" msgstr "" +#. module: server_environment +#: model:ir.model.fields,field_description:server_environment.field_server_config__odoo_I_log_config +msgid "odoo | log_config" +msgstr "" + #. module: server_environment #: model:ir.model.fields,field_description:server_environment.field_server_config__odoo_I_log_db msgid "odoo | log_db" diff --git a/server_environment/i18n/tr_TR.po b/server_environment/i18n/tr_TR.po index 91e83613e..d0a3e8508 100644 --- a/server_environment/i18n/tr_TR.po +++ b/server_environment/i18n/tr_TR.po @@ -281,6 +281,11 @@ msgstr "" msgid "odoo | list_db" msgstr "" +#. module: server_environment +#: model:ir.model.fields,field_description:server_environment.field_server_config__odoo_I_log_config +msgid "odoo | log_config" +msgstr "" + #. module: server_environment #: model:ir.model.fields,field_description:server_environment.field_server_config__odoo_I_log_db msgid "odoo | log_db" diff --git a/server_environment/i18n/uk.po b/server_environment/i18n/uk.po index d83f88442..64f09761b 100644 --- a/server_environment/i18n/uk.po +++ b/server_environment/i18n/uk.po @@ -281,6 +281,11 @@ msgstr "" msgid "odoo | list_db" msgstr "" +#. module: server_environment +#: model:ir.model.fields,field_description:server_environment.field_server_config__odoo_I_log_config +msgid "odoo | log_config" +msgstr "" + #. module: server_environment #: model:ir.model.fields,field_description:server_environment.field_server_config__odoo_I_log_db msgid "odoo | log_db" diff --git a/server_environment/i18n/vi.po b/server_environment/i18n/vi.po index 2ed513c0e..b16510a1d 100644 --- a/server_environment/i18n/vi.po +++ b/server_environment/i18n/vi.po @@ -280,6 +280,11 @@ msgstr "" msgid "odoo | list_db" msgstr "" +#. module: server_environment +#: model:ir.model.fields,field_description:server_environment.field_server_config__odoo_I_log_config +msgid "odoo | log_config" +msgstr "" + #. module: server_environment #: model:ir.model.fields,field_description:server_environment.field_server_config__odoo_I_log_db msgid "odoo | log_db" diff --git a/server_environment/i18n/vi_VN.po b/server_environment/i18n/vi_VN.po index 02edad4b3..80ca94b59 100644 --- a/server_environment/i18n/vi_VN.po +++ b/server_environment/i18n/vi_VN.po @@ -281,6 +281,11 @@ msgstr "" msgid "odoo | list_db" msgstr "" +#. module: server_environment +#: model:ir.model.fields,field_description:server_environment.field_server_config__odoo_I_log_config +msgid "odoo | log_config" +msgstr "" + #. module: server_environment #: model:ir.model.fields,field_description:server_environment.field_server_config__odoo_I_log_db msgid "odoo | log_db" diff --git a/server_environment/i18n/zh_CN.po b/server_environment/i18n/zh_CN.po index e89812174..e58f2672d 100644 --- a/server_environment/i18n/zh_CN.po +++ b/server_environment/i18n/zh_CN.po @@ -284,6 +284,11 @@ msgstr "" msgid "odoo | list_db" msgstr "" +#. module: server_environment +#: model:ir.model.fields,field_description:server_environment.field_server_config__odoo_I_log_config +msgid "odoo | log_config" +msgstr "" + #. module: server_environment #: model:ir.model.fields,field_description:server_environment.field_server_config__odoo_I_log_db msgid "odoo | log_db" diff --git a/server_environment/i18n/zh_TW.po b/server_environment/i18n/zh_TW.po index 069604a95..47f128870 100644 --- a/server_environment/i18n/zh_TW.po +++ b/server_environment/i18n/zh_TW.po @@ -281,6 +281,11 @@ msgstr "" msgid "odoo | list_db" msgstr "" +#. module: server_environment +#: model:ir.model.fields,field_description:server_environment.field_server_config__odoo_I_log_config +msgid "odoo | log_config" +msgstr "" + #. module: server_environment #: model:ir.model.fields,field_description:server_environment.field_server_config__odoo_I_log_db msgid "odoo | log_db" diff --git a/server_environment/readme/USAGE.md b/server_environment/readme/USAGE.md index ed811ae09..22b99678d 100644 --- a/server_environment/readme/USAGE.md +++ b/server_environment/readme/USAGE.md @@ -19,3 +19,147 @@ If you want to have a technical name to reference: _inherit = ["storage.backend", "server.env.techname.mixin"] [...] + +## Restoring columns on uninstall + +When `server.env.mixin` is bound to an existing model, the ORM drops the +original stored columns for all env-managed fields. If the binding addon is +later uninstalled, those columns must be recreated so the database remains +usable. + +Add an `uninstall_hook` to your addon and delegate to +`restore_env_managed_columns`: + + # your_addon/__init__.py + from ./hooks import uninstall_hook + # your_addon/hooks.py + from odoo.addons.server_environment import uninstall + + def uninstall_hook(env): + uninstall.restore_env_managed_columns( + env, + "storage.backend", + ["directory_path", "other_field"], + ) + + # your_addon/__manifest__.py + { + ... + "uninstall_hook": "uninstall_hook", + } + +The helper creates any missing columns (idempotent: safe to call multiple +times) and repopulates them with each record's current effective value — +whether that value came from an environment configuration file or from the +stored default field (`x__env_default`). + +The hook must run *before* the ORM extensions are removed, which is guaranteed +by Odoo's uninstall sequence (hooks execute before `Module.module_uninstall()`). + +### Handling required fields + +If a restored column is **required** (has a `NOT NULL` constraint) but has no +effective value (missing from environment config and no default field set), the +restoration will fail with a `UserError`. + +**Solution:** pass a `field_defaults` dictionary with fallback values: + + def uninstall_hook(env): + restore_env_managed_columns( + env, + "ir.mail_server", + ["smtp_host", "smtp_authentication"], + field_defaults={ + "smtp_authentication": "login", # fallback for required field + }, + ) + +The helper will use the fallback value if provided and the computed field value +is empty. If no fallback is provided but a required field has no value, a +`UserError` is raised with instructions on how to provide a `field_defaults` +parameter. + +## Migrating when dropping server_environment dependency + +When refactoring an existing addon that embeds a `server.env.mixin` binding, you +may want to extract the binding into a separate *glue* addon and drop the +`server_environment` dependency from the original. This keeps the base addon +lightweight while preserving server-environment features for those who install +the glue addon. + +**Pattern:** + +- **Original addon (v1)**: depends on `server_environment` and binds the mixin + directly in model code. +- **Refactored addon (v2)**: removes `server_environment` from dependencies, + removes the mixin binding and the related ORM model inheritance. +- **New glue addon** (optional, same version): depends on both `server_environment` + and the original addon v2; re-adds the mixin binding in a separate module file. + +**Migration checklist:** + +1. In the **original addon's v2 `__manifest__.py`**: + - Remove `"server_environment"` from `depends`. + - Remove the model file(s) that contained the mixin binding. + - Update `depends` to add the new glue addon *if* the base addon still needs it + (otherwise, make the glue addon optional for users who want env-binding). + +2. In the **original addon's v2 model code**: + - Delete or simplify the model class that inherited from `server.env.mixin`. + - If the model was only there for the binding, remove it entirely. + - Restore the original field definitions (not as computed fields). + +3. **Create a migration script** (if needed) to restore columns *during the addon + upgrade*, before the ORM model extensions are unloaded. Use a `@post_load` + hook or a dedicated migration script: + + # migrations/18.0.1.0.0/post-restore-columns.py + def migrate(cr, version): + # Call the restoration logic while the v1 model is still active + env = odoo.api.Environment(cr, odoo.SUPERUSER_ID, {}) + # If any field is required and may have no value in the environment, + # provide a fallback via field_defaults + restore_env_managed_columns( + env, + "storage.backend", + ["directory_path", "other_field"], + field_defaults={ + "directory_path": "/tmp", # fallback for required field + }, + ) + +4. **Create the glue addon** with the model re-inheritance: + + # your_addon_env/__init__.py + from . import models + + # your_addon_env/models/__init__.py + from . import storage_backend + + # your_addon_env/models/storage_backend.py + class StorageBackend(models.Model): + _name = "storage.backend" + _inherit = ["storage.backend", "server.env.mixin"] + + @property + def _server_env_fields(self): + return {"directory_path": {}} + + # your_addon_env/__manifest__.py + { + "name": "Storage Backend – Server Environment", + "version": "18.0.1.0.0", + "depends": ["server_environment", "storage_backend"], + "installable": True, + } + +**Key points:** + +- Column restoration must happen *during the addon upgrade* (step 3), not as an + uninstall hook, because the original model binding is still active. +- The `restore_env_managed_columns` helper is idempotent and safe to call even + if columns already exist. +- Users who do not need server environment features simply do *not* install the + glue addon—the base addon continues to work with plain database columns. +- Users who do need server environment can install both the base addon (v2+) and + the glue addon (same version) to get the binding back. diff --git a/server_environment/static/description/index.html b/server_environment/static/description/index.html index 7d724427c..e12e33f5f 100644 --- a/server_environment/static/description/index.html +++ b/server_environment/static/description/index.html @@ -372,7 +372,7 @@

server configuration environment files

!! This file is generated by oca-gen-addon-readme !! !! changes will be overwritten. !! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -!! source digest: sha256:a32c7e5f13c20b97b02561de94e20ed507e8fd96e11287ff197692507be5b590 +!! source digest: sha256:bfb242c8cf384684a1067a797167c4d3dccf13cd9fc63a8520ad88d08861aece !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -->

Production/Stable License: LGPL-3 OCA/server-env Translate me on Weblate Try me on Runboat

This module provides a way to define an environment in the main Odoo @@ -398,13 +398,20 @@

server configuration environment files

  • Server environment integration
  • -
  • Usage
  • -
  • Known issues / Roadmap
  • -
  • Bug Tracker
  • -
  • Credits @@ -544,9 +551,165 @@

    Usage

    [...] +
    +

    Restoring columns on uninstall

    +

    When server.env.mixin is bound to an existing model, the ORM drops +the original stored columns for all env-managed fields. If the binding +addon is later uninstalled, those columns must be recreated so the +database remains usable.

    +

    Add an uninstall_hook to your addon and delegate to +restore_env_managed_columns:

    +
    +# your_addon/__init__.py
    +from ./hooks import uninstall_hook
    +# your_addon/hooks.py
    +from odoo.addons.server_environment import uninstall
    +
    +def uninstall_hook(env):
    +    uninstall.restore_env_managed_columns(
    +        env,
    +        "storage.backend",
    +        ["directory_path", "other_field"],
    +    )
    +
    +# your_addon/__manifest__.py
    +{
    +    ...
    +    "uninstall_hook": "uninstall_hook",
    +}
    +
    +

    The helper creates any missing columns (idempotent: safe to call +multiple times) and repopulates them with each record’s current +effective value — whether that value came from an environment +configuration file or from the stored default field +(x_<field>_env_default).

    +

    The hook must run before the ORM extensions are removed, which is +guaranteed by Odoo’s uninstall sequence (hooks execute before +Module.module_uninstall()).

    +
    +

    Handling required fields

    +

    If a restored column is required (has a NOT NULL constraint) but +has no effective value (missing from environment config and no default +field set), the restoration will fail with a UserError.

    +

    Solution: pass a field_defaults dictionary with fallback values:

    +
    +def uninstall_hook(env):
    +    restore_env_managed_columns(
    +        env,
    +        "ir.mail_server",
    +        ["smtp_host", "smtp_authentication"],
    +        field_defaults={
    +            "smtp_authentication": "login",  # fallback for required field
    +        },
    +    )
    +
    +

    The helper will use the fallback value if provided and the computed +field value is empty. If no fallback is provided but a required field +has no value, a UserError is raised with instructions on how to +provide a field_defaults parameter.

    +
    +
    +
    +

    Migrating when dropping server_environment dependency

    +

    When refactoring an existing addon that embeds a server.env.mixin +binding, you may want to extract the binding into a separate glue +addon and drop the server_environment dependency from the original. +This keeps the base addon lightweight while preserving +server-environment features for those who install the glue addon.

    +

    Pattern:

    +
      +
    • Original addon (v1): depends on server_environment and binds +the mixin directly in model code.
    • +
    • Refactored addon (v2): removes server_environment from +dependencies, removes the mixin binding and the related ORM model +inheritance.
    • +
    • New glue addon (optional, same version): depends on both +server_environment and the original addon v2; re-adds the mixin +binding in a separate module file.
    • +
    +

    Migration checklist:

    +
      +
    1. In the original addon’s v2 ``__manifest__.py``:

      +
        +
      • Remove "server_environment" from depends.
      • +
      • Remove the model file(s) that contained the mixin binding.
      • +
      • Update depends to add the new glue addon if the base addon +still needs it (otherwise, make the glue addon optional for users +who want env-binding).
      • +
      +
    2. +
    3. In the original addon’s v2 model code:

      +
        +
      • Delete or simplify the model class that inherited from +server.env.mixin.
      • +
      • If the model was only there for the binding, remove it entirely.
      • +
      • Restore the original field definitions (not as computed fields).
      • +
      +
    4. +
    5. Create a migration script (if needed) to restore columns during +the addon upgrade, before the ORM model extensions are unloaded. Use +a @post_load hook or a dedicated migration script:

      +
      +# migrations/18.0.1.0.0/post-restore-columns.py
      +def migrate(cr, version):
      +    # Call the restoration logic while the v1 model is still active
      +    env = odoo.api.Environment(cr, odoo.SUPERUSER_ID, {})
      +    # If any field is required and may have no value in the environment,
      +    # provide a fallback via field_defaults
      +    restore_env_managed_columns(
      +        env,
      +        "storage.backend",
      +        ["directory_path", "other_field"],
      +        field_defaults={
      +            "directory_path": "/tmp",  # fallback for required field
      +        },
      +    )
      +
      +
    6. +
    7. Create the glue addon with the model re-inheritance:

      +
      +# your_addon_env/__init__.py
      +from . import models
      +
      +# your_addon_env/models/__init__.py
      +from . import storage_backend
      +
      +# your_addon_env/models/storage_backend.py
      +class StorageBackend(models.Model):
      +    _name = "storage.backend"
      +    _inherit = ["storage.backend", "server.env.mixin"]
      +
      +    @property
      +    def _server_env_fields(self):
      +        return {"directory_path": {}}
      +
      +# your_addon_env/__manifest__.py
      +{
      +    "name": "Storage Backend – Server Environment",
      +    "version": "18.0.1.0.0",
      +    "depends": ["server_environment", "storage_backend"],
      +    "installable": True,
      +}
      +
      +
    8. +
    +

    Key points:

    +
      +
    • Column restoration must happen during the addon upgrade (step 3), +not as an uninstall hook, because the original model binding is still +active.
    • +
    • The restore_env_managed_columns helper is idempotent and safe to +call even if columns already exist.
    • +
    • Users who do not need server environment features simply do not +install the glue addon—the base addon continues to work with plain +database columns.
    • +
    • Users who do need server environment can install both the base addon +(v2+) and the glue addon (same version) to get the binding back.
    • +
    +
    -

    Known issues / Roadmap

    +

    Known issues / Roadmap

    • it is not possible to set the environment from the command line. A configuration file must be used.
    • @@ -558,7 +721,7 @@

      Known issues / Roadmap

    -

    Bug Tracker

    +

    Bug Tracker

    Bugs are tracked on GitHub Issues. In case of trouble, please check there if your issue has already been reported. If you spotted it first, help us to smash it by providing a detailed and welcomed @@ -566,15 +729,15 @@

    Bug Tracker

    Do not contact contributors directly about support or help with technical issues.

    -

    Credits

    +

    Credits

    -

    Authors

    +

    Authors

    • Camptocamp
    -

    Contributors

    +

    Contributors

    -

    Maintainers

    +

    Maintainers

    This module is maintained by the OCA.

    Odoo Community Association diff --git a/server_environment/tests/test_server_environment.py b/server_environment/tests/test_server_environment.py index 9f605942a..bf3ce0c8a 100644 --- a/server_environment/tests/test_server_environment.py +++ b/server_environment/tests/test_server_environment.py @@ -6,6 +6,8 @@ from odoo.tools.config import config as odoo_config +from odoo.addons.server_environment.uninstall import restore_env_managed_columns + from .. import server_env from . import common @@ -88,3 +90,14 @@ def test_default_hidden_password(self): self.assertIn("odoo_I_db_password", defaults) self.assertIn("odoo_I_smtp_password", defaults) self.assertIn("outgoing_mail_provider_promail_I_smtp_pass", defaults) + + def test_restore_env_managed_columns_unknown_field(self): + """Helper gracefully skips a field that doesn't exist on the model.""" + # Must not raise even when the field name doesn't exist. + restore_env_managed_columns( + self.env, "res.partner", ["__nonexistent_field_xyz__"] + ) + + def test_restore_env_managed_columns_no_fields(self): + """Helper is a no-op when given an empty field list.""" + restore_env_managed_columns(self.env, "res.partner", []) diff --git a/server_environment/uninstall.py b/server_environment/uninstall.py new file mode 100644 index 000000000..ba8a54268 --- /dev/null +++ b/server_environment/uninstall.py @@ -0,0 +1,98 @@ +# Copyright 2026 Camptocamp (https://www.camptocamp.com) +import logging + +from odoo.tools import SQL, sql + +_logger = logging.getLogger(__name__) + + +def restore_env_managed_columns(env, model_name, field_names, field_defaults=None): + """Restore database columns for fields formerly managed via server.env.mixin. + + When an addon binds ``server.env.mixin`` to an existing model, the ORM + drops the original stored columns. Call this helper from an + ``uninstall_hook`` so those columns are recreated and repopulated + with their current effective values before the addon is removed. + + The hook must run *while* the module's ORM extensions are still active + (guaranteed by Odoo's uninstall sequence: hooks execute before + ``Module.module_uninstall()``), so the env-computed fields are still + readable and their values can be written back to freshly created columns. + + The operation is idempotent: calling it multiple times will not fail. + + **Defaults:** If a restored field value is NULL/empty, the helper will + use the fallback from ``field_defaults`` (if provided) or the field's + ORM-level default (if defined). + + Note: ``field.required`` is set to False by the mixin, so we cannot detect + which fields are required. Provide explicit ``field_defaults`` for fields + that must have values. + + :param str model_name: dotted model name, e.g. ``"ir.mail_server"`` + :param field_names: iterable of field names whose columns to restore + :param dict field_defaults: optional mapping of field name to fallback + value used when restoring a column that has no effective env-computed + value, e.g. ``{"smtp_authentication": ""}`` + """ + model = env[model_name] + cr = env.cr + field_defaults = field_defaults or {} + + for field_name in field_names: + field = model._fields.get(field_name) + if field is None: + _logger.warning( + "restore_env_managed_columns: field %r not found on %s, skipping", + field_name, + model_name, + ) + continue + column_type = field.column_type + if column_type is None: + _logger.warning( + "restore_env_managed_columns: " + "field %r on %s has no SQL column type, skipping", + field_name, + model_name, + ) + continue + table = model._table + if not sql.column_exists(cr, table, field_name): + sql.create_column(cr, table, field_name, column_type[1], field.string) + _logger.info( + "restore_env_managed_columns: created column %s.%s (%s)", + table, + field_name, + column_type[1], + ) + # Repopulate every existing record with the current computed value. + # The hook runs while the ORM extensions are still active, so the + # env-computed field is still readable via the normal accessor. + for record in model.search([]): + value = record[field_name] + # The ORM returns False for NULL on non-boolean fields; map + # that back to None so psycopg2 writes a proper SQL NULL. + if value is False and field.type != "boolean": + value = None + elif value == "": + value = None + + # Try to get a default value if we have None. + # Note: field.required is False after mixin transformation, + # so we apply defaults for all None values when available. + if value is None: + if field_name in field_defaults: + value = field_defaults[field_name] + elif field_name in model.default_get([field_name]): + value = model.default_get([field_name])[field_name] + + cr.execute( + SQL( + "UPDATE %s SET %s = %s WHERE id = %s", + SQL.identifier(table), + SQL.identifier(field_name), + value, + record.id, + ) + )