From b89ebd9d761f535f6fba2af0204a6faf8aff3f97 Mon Sep 17 00:00:00 2001 From: Alexandre Fayolle Date: Wed, 25 Mar 2026 15:40:12 +0100 Subject: [PATCH 1/4] [IMP] server_environment: module uninstallation Add a helper to manage the restoring of the database columns when a module using `server_environment` is uninstalled or the dependency on `server_environment` is dropped. Document how to use the helper in an uninstall script or in an upgrade script (if a new version of the addon drops the dependency). --- server_environment/README.rst | 227 ++++++++++++++--- server_environment/__init__.py | 1 + server_environment/readme/USAGE.md | 144 +++++++++++ .../static/description/index.html | 231 +++++++++++++++--- .../tests/test_environment_variable.py | 1 - .../tests/test_server_environment.py | 16 ++ server_environment/uninstall.py | 98 ++++++++ 7 files changed, 651 insertions(+), 67 deletions(-) create mode 100644 server_environment/uninstall.py diff --git a/server_environment/README.rst b/server_environment/README.rst index 13eddd43c..c512c6a57 100644 --- a/server_environment/README.rst +++ b/server_environment/README.rst @@ -1,7 +1,3 @@ -.. image:: https://odoo-community.org/readme-banner-image - :target: https://odoo-community.org/get-involved?utm_source=readme - :alt: Odoo Community Association - ====================================== server configuration environment files ====================================== @@ -17,7 +13,7 @@ server configuration environment files .. |badge1| image:: https://img.shields.io/badge/maturity-Production%2FStable-green.png :target: https://odoo-community.org/page/development-status :alt: Production/Stable -.. |badge2| image:: https://img.shields.io/badge/license-LGPL--3-blue.png +.. |badge2| image:: https://img.shields.io/badge/licence-LGPL--3-blue.png :target: http://www.gnu.org/licenses/lgpl-3.0-standalone.html :alt: License: LGPL-3 .. |badge3| image:: https://img.shields.io/badge/github-OCA%2Fserver--env-lightgray.png?logo=github @@ -100,12 +96,19 @@ You can edit the settings you need in the ``server_environment_files`` addon. The ``server_environment_files_sample`` can be used as an example: -- values common to all / most environments can be stored in the - ``default/`` directory using the .ini file syntax; -- each environment you need to define is stored in its own directory and - can override or extend default values; -- you can override or extend values in the main configuration file of - your instance; +- values common to all / most environments can be stored in the + ``default/`` directory using the .ini file syntax; +- each environment you need to define is stored in its own directory + and can override or extend default values; +- you can override or extend values in the main configuration file of + your instance; +- In some platforms (like odoo.sh where production config file is + copied to staging) it can be useful to overwrite options written in + the ``[options]`` section. You must allow the override by adding + ``server_environment_allow_overwrite_options_section = True`` to the + former ``odoo.cfg`` config file or through the environment variable: + ``export SERVER_ENVIRONMENT_ALLOW_OVERWRITE_OPTIONS_SECTION=True`` + (if both are set config file takes precedence). Environment variable -------------------- @@ -214,16 +217,180 @@ 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 . import hooks + # your_addon/hooks.py + from odoo.addons.server_environment.uninstall import restore_env_managed_columns + + def uninstall_hook(env): + 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 ====================== -- it is not possible to set the environment from the command line. A - configuration file must be used. -- the module does not allow to set low level attributes such as database - server, etc. -- server.env.techname.mixin's tech_name field could leverage the new - option for computable / writable fields and get rid of some onchange / - read / write code. +- it is not possible to set the environment from the command line. A + configuration file must be used. +- the module does not allow to set low level attributes such as + database server, etc. +- server.env.techname.mixin's tech_name field could leverage the new + option for computable / writable fields and get rid of some onchange + / read / write code. Bug Tracker =========== @@ -246,18 +413,18 @@ Authors Contributors ------------ -- Florent Xicluna (Wingo) -- Nicolas Bessi -- Alexandre Fayolle -- Daniel Reis -- Holger Brunn -- Leonardo Pistone -- Adrien Peiffer -- Thierry Ducrest -- Guewen Baconnier -- Thomas Binfeld -- Stéphane Bidoul -- Simone Orsi +- Florent Xicluna (Wingo) +- Nicolas Bessi +- Alexandre Fayolle +- Daniel Reis +- Holger Brunn +- Leonardo Pistone +- Adrien Peiffer +- Thierry Ducrest +- Guewen Baconnier +- Thomas Binfeld +- Stéphane Bidoul +- Simone Orsi Maintainers ----------- diff --git a/server_environment/__init__.py b/server_environment/__init__.py index e59d3799a..5073e5a68 100644 --- a/server_environment/__init__.py +++ b/server_environment/__init__.py @@ -2,3 +2,4 @@ from . import models from . import server_env from .server_env import serv_config, setboolean +from . import uninstall 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 9b59c3a54..c4a91d161 100644 --- a/server_environment/static/description/index.html +++ b/server_environment/static/description/index.html @@ -3,7 +3,7 @@ -README.rst +server configuration environment files -
+
+

server configuration environment files

- - -Odoo Community Association - -
-

server configuration environment files

-

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

+

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 configuration file and to read some configurations from files depending on the configured environment: you define the environment in the main @@ -398,19 +393,26 @@

server configuration environment files

  • Server environment integration
  • -
  • Usage
  • -
  • Known issues / Roadmap
  • -
  • Bug Tracker
  • -
  • Credits
  • -

    Installation

    +

    Installation

    By itself, this module does little. See for instance the mail_environment addon which depends on this one to allow configuring the incoming and outgoing mail servers depending on the @@ -422,7 +424,7 @@

    Installation

    SERVER_ENV_CONFIG and SERVER_ENV_CONFIG_SECRET.

    -

    Configuration

    +

    Configuration

    To configure this module, you need to edit the main configuration file of your instance, and add a directive called running_env. Commonly used values are ‘dev’, ‘test’, ‘production’:

    @@ -441,21 +443,28 @@

    Configuration

    If you don’t provide any value, test is used as a safe default.

    You have several possibilities to set configuration values:

    -

    server_environment_files

    +

    server_environment_files

    You can edit the settings you need in the server_environment_files addon. The server_environment_files_sample can be used as an example:

    • values common to all / most environments can be stored in the default/ directory using the .ini file syntax;
    • -
    • each environment you need to define is stored in its own directory and -can override or extend default values;
    • +
    • each environment you need to define is stored in its own directory +and can override or extend default values;
    • you can override or extend values in the main configuration file of your instance;
    • +
    • In some platforms (like odoo.sh where production config file is +copied to staging) it can be useful to overwrite options written in +the [options] section. You must allow the override by adding +server_environment_allow_overwrite_options_section = True to the +former odoo.cfg config file or through the environment variable: +export SERVER_ENVIRONMENT_ALLOW_OVERWRITE_OPTIONS_SECTION=True +(if both are set config file takes precedence).
    -

    Environment variable

    +

    Environment variable

    You can define configuration in the environment variable SERVER_ENV_CONFIG and/or SERVER_ENV_CONFIG_SECRET. The 2 variables are handled the exact same way, this is only a convenience for @@ -505,7 +514,7 @@

    Environment variable

    reference records. See “USAGE”.
    -

    Default values

    +

    Default values

    When using the server.env.mixin mixin, for each env-computed field, a companion field <field>_env_default is created. This field is not environment-dependent. It’s a fallback value used when no key is set in @@ -514,7 +523,7 @@

    Default values

    Note: empty environment keys always take precedence over default fields

    -

    Server environment integration

    +

    Server environment integration

    Read the documentation of the class models/server_env_mixin.py and [models/server_env_tech_name_mixin.py] @@ -522,7 +531,7 @@

    Server environment integration

    -

    Usage

    +

    Usage

    You can include a mixin in your model and configure the env-computed fields by an override of _server_env_fields.

    @@ -544,21 +553,172 @@ 

    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 . import models
    +
    +def uninstall_hook(env):
    +    env["server.env.mixin"].restore_env_managed_columns(
    +        "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):
    +    env["server.env.mixin"].restore_env_managed_columns(
    +        "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
      +    env["server.env.mixin"].restore_env_managed_columns(
      +        "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.
    • -
    • the module does not allow to set low level attributes such as database -server, etc.
    • +
    • the module does not allow to set low level attributes such as +database server, etc.
    • server.env.techname.mixin’s tech_name field could leverage the new -option for computable / writable fields and get rid of some onchange / -read / write code.
    • +option for computable / writable fields and get rid of some onchange +/ read / write code.
    -

    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 +726,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 @@ -604,6 +764,5 @@

    Maintainers

    -
    diff --git a/server_environment/tests/test_environment_variable.py b/server_environment/tests/test_environment_variable.py index 74df177e4..5568c525b 100644 --- a/server_environment/tests/test_environment_variable.py +++ b/server_environment/tests/test_environment_variable.py @@ -1,4 +1,3 @@ -# Copyright 2018 Camptocamp (https://www.camptocamp.com). # License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html) from unittest.mock import patch diff --git a/server_environment/tests/test_server_environment.py b/server_environment/tests/test_server_environment.py index 5ecdec43b..417bb2099 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,17 @@ 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. + with self.assertLogs( + "odoo.addons.server_environment.uninstall", level="WARNING" + ): + 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, + ) + ) From 34b9185b51f1450fb96a6f3655b644db1340fa53 Mon Sep 17 00:00:00 2001 From: OCA-git-bot Date: Wed, 1 Jul 2026 12:26:23 +0000 Subject: [PATCH 2/4] [BOT] post-merge updates --- README.md | 2 +- server_environment/README.rst | 126 +++++++++--------- server_environment/__manifest__.py | 2 +- .../static/description/index.html | 80 +++++------ 4 files changed, 106 insertions(+), 104 deletions(-) diff --git a/README.md b/README.md index b710ec29e..aa743aa17 100644 --- a/README.md +++ b/README.md @@ -22,7 +22,7 @@ Available addons addon | version | maintainers | summary --- | --- | --- | --- [mail_environment](mail_environment/) | 19.0.1.0.0 | | Configure mail servers with server_environment_files -[server_environment](server_environment/) | 19.0.1.0.1 | | move some configurations out of the database +[server_environment](server_environment/) | 19.0.1.0.2 | | move some configurations out of the database [server_environment_ir_config_parameter](server_environment_ir_config_parameter/) | 19.0.1.0.0 | | Override System Parameters from server environment file [//]: # (end addons) diff --git a/server_environment/README.rst b/server_environment/README.rst index 72b10248e..33219af70 100644 --- a/server_environment/README.rst +++ b/server_environment/README.rst @@ -1,3 +1,7 @@ +.. image:: https://odoo-community.org/readme-banner-image + :target: https://odoo-community.org/get-involved?utm_source=readme + :alt: Odoo Community Association + ====================================== server configuration environment files ====================================== @@ -7,13 +11,13 @@ server configuration environment files !! This file is generated by oca-gen-addon-readme !! !! changes will be overwritten. !! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - !! source digest: sha256:7b570ae57a4da880788d2bf7fa2ee6bb7c7b051eb1bb92364a566ca36e082c92 + !! source digest: sha256:a33c0b46ddf893a0c6c856bf944637008d0f08d60c7646e6c5e3bc13e9ccb847 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! .. |badge1| image:: https://img.shields.io/badge/maturity-Production%2FStable-green.png :target: https://odoo-community.org/page/development-status :alt: Production/Stable -.. |badge2| image:: https://img.shields.io/badge/licence-LGPL--3-blue.png +.. |badge2| image:: https://img.shields.io/badge/license-LGPL--3-blue.png :target: http://www.gnu.org/licenses/lgpl-3.0-standalone.html :alt: License: LGPL-3 .. |badge3| image:: https://img.shields.io/badge/github-OCA%2Fserver--env-lightgray.png?logo=github @@ -96,19 +100,12 @@ You can edit the settings you need in the ``server_environment_files`` addon. The ``server_environment_files_sample`` can be used as an example: -- values common to all / most environments can be stored in the - ``default/`` directory using the .ini file syntax; -- each environment you need to define is stored in its own directory - and can override or extend default values; -- you can override or extend values in the main configuration file of - your instance; -- In some platforms (like odoo.sh where production config file is - copied to staging) it can be useful to overwrite options written in - the ``[options]`` section. You must allow the override by adding - ``server_environment_allow_overwrite_options_section = True`` to the - former ``odoo.cfg`` config file or through the environment variable: - ``export SERVER_ENVIRONMENT_ALLOW_OVERWRITE_OPTIONS_SECTION=True`` - (if both are set config file takes precedence). +- values common to all / most environments can be stored in the + ``default/`` directory using the .ini file syntax; +- each environment you need to define is stored in its own directory and + can override or extend default values; +- you can override or extend values in the main configuration file of + your instance; Environment variable -------------------- @@ -229,13 +226,14 @@ Add an ``uninstall_hook`` to your addon and delegate to ``restore_env_managed_columns``: :: + # your_addon/__init__.py - from . import hooks + from ./hooks import uninstall_hook # your_addon/hooks.py - from odoo.addons.server_environment.uninstall import restore_env_managed_columns + from odoo.addons.server_environment import uninstall def uninstall_hook(env): - restore_env_managed_columns( + uninstall.restore_env_managed_columns( env, "storage.backend", ["directory_path", "other_field"], @@ -294,31 +292,31 @@ 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. +- **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). + - 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). + - 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 @@ -370,27 +368,27 @@ server-environment features for those who install the glue addon. **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. +- 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 ====================== -- it is not possible to set the environment from the command line. A - configuration file must be used. -- the module does not allow to set low level attributes such as - database server, etc. -- server.env.techname.mixin's tech_name field could leverage the new - option for computable / writable fields and get rid of some onchange - / read / write code. +- it is not possible to set the environment from the command line. A + configuration file must be used. +- the module does not allow to set low level attributes such as database + server, etc. +- server.env.techname.mixin's tech_name field could leverage the new + option for computable / writable fields and get rid of some onchange / + read / write code. Bug Tracker =========== @@ -413,18 +411,18 @@ Authors Contributors ------------ -- Florent Xicluna (Wingo) -- Nicolas Bessi -- Alexandre Fayolle -- Daniel Reis -- Holger Brunn -- Leonardo Pistone -- Adrien Peiffer -- Thierry Ducrest -- Guewen Baconnier -- Thomas Binfeld -- Stéphane Bidoul -- Simone Orsi +- Florent Xicluna (Wingo) +- Nicolas Bessi +- Alexandre Fayolle +- Daniel Reis +- Holger Brunn +- Leonardo Pistone +- Adrien Peiffer +- Thierry Ducrest +- Guewen Baconnier +- Thomas Binfeld +- Stéphane Bidoul +- Simone Orsi Maintainers ----------- diff --git a/server_environment/__manifest__.py b/server_environment/__manifest__.py index 180289d56..8e0b0ffb2 100644 --- a/server_environment/__manifest__.py +++ b/server_environment/__manifest__.py @@ -4,7 +4,7 @@ { "name": "server configuration environment files", - "version": "19.0.1.0.1", + "version": "19.0.1.0.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/static/description/index.html b/server_environment/static/description/index.html index aa3cde76c..b751235c0 100644 --- a/server_environment/static/description/index.html +++ b/server_environment/static/description/index.html @@ -3,7 +3,7 @@ -server configuration environment files +README.rst -
    -

    server configuration environment files

    +
    + + +Odoo Community Association + +
    +

    server configuration environment files

    -

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

    +

    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 configuration file and to read some configurations from files depending on the configured environment: you define the environment in the main @@ -412,7 +417,7 @@

    server configuration environment files

    -

    Installation

    +

    Installation

    By itself, this module does little. See for instance the mail_environment addon which depends on this one to allow configuring the incoming and outgoing mail servers depending on the @@ -424,7 +429,7 @@

    Installation

    SERVER_ENV_CONFIG and SERVER_ENV_CONFIG_SECRET.

    -

    Configuration

    +

    Configuration

    To configure this module, you need to edit the main configuration file of your instance, and add a directive called running_env. Commonly used values are ‘dev’, ‘test’, ‘production’:

    @@ -443,28 +448,21 @@

    Configuration

    If you don’t provide any value, test is used as a safe default.

    You have several possibilities to set configuration values:

    -

    server_environment_files

    +

    server_environment_files

    You can edit the settings you need in the server_environment_files addon. The server_environment_files_sample can be used as an example:

    • values common to all / most environments can be stored in the default/ directory using the .ini file syntax;
    • -
    • each environment you need to define is stored in its own directory -and can override or extend default values;
    • +
    • each environment you need to define is stored in its own directory and +can override or extend default values;
    • you can override or extend values in the main configuration file of your instance;
    • -
    • In some platforms (like odoo.sh where production config file is -copied to staging) it can be useful to overwrite options written in -the [options] section. You must allow the override by adding -server_environment_allow_overwrite_options_section = True to the -former odoo.cfg config file or through the environment variable: -export SERVER_ENVIRONMENT_ALLOW_OVERWRITE_OPTIONS_SECTION=True -(if both are set config file takes precedence).
    -

    Environment variable

    +

    Environment variable

    You can define configuration in the environment variable SERVER_ENV_CONFIG and/or SERVER_ENV_CONFIG_SECRET. The 2 variables are handled the exact same way, this is only a convenience for @@ -514,7 +512,7 @@

    Environment variable

    reference records. See “USAGE”.
    -

    Default values

    +

    Default values

    When using the server.env.mixin mixin, for each env-computed field, a companion field <field>_env_default is created. This field is not environment-dependent. It’s a fallback value used when no key is set in @@ -523,7 +521,7 @@

    Default values

    Note: empty environment keys always take precedence over default fields

    -

    Server environment integration

    +

    Server environment integration

    Read the documentation of the class models/server_env_mixin.py and [models/server_env_tech_name_mixin.py] @@ -531,7 +529,7 @@

    Server environment integration

    -

    Usage

    +

    Usage

    You can include a mixin in your model and configure the env-computed fields by an override of _server_env_fields.

    @@ -554,7 +552,7 @@ 

    Usage

    [...]
    -

    Restoring columns on uninstall

    +

    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 @@ -563,10 +561,13 @@

    Restoring columns on uninstallrestore_env_managed_columns:

     # your_addon/__init__.py
    -from . import models
    +from ./hooks import uninstall_hook
    +# your_addon/hooks.py
    +from odoo.addons.server_environment import uninstall
     
     def uninstall_hook(env):
    -    env["server.env.mixin"].restore_env_managed_columns(
    +    uninstall.restore_env_managed_columns(
    +        env,
             "storage.backend",
             ["directory_path", "other_field"],
         )
    @@ -586,14 +587,15 @@ 

    Restoring columns on uninstallModule.module_uninstall()).

    -

    Handling required fields

    +

    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):
    -    env["server.env.mixin"].restore_env_managed_columns(
    +    restore_env_managed_columns(
    +        env,
             "ir.mail_server",
             ["smtp_host", "smtp_authentication"],
             field_defaults={
    @@ -608,7 +610,7 @@ 

    Handling required fields

    -

    Known issues / Roadmap

    +

    Known issues / Roadmap

    • it is not possible to set the environment from the command line. A configuration file must be used.
    • -
    • the module does not allow to set low level attributes such as -database server, etc.
    • +
    • the module does not allow to set low level attributes such as database +server, etc.
    • server.env.techname.mixin’s tech_name field could leverage the new -option for computable / writable fields and get rid of some onchange -/ read / write code.
    • +option for computable / writable fields and get rid of some onchange / +read / write code.
    -

    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 @@ -726,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 @@ -764,5 +767,6 @@

    Maintainers

    +
    From 0276712cea6ee318f032d1cbda0a7ce45f3e1d0c Mon Sep 17 00:00:00 2001 From: Laura V Date: Wed, 1 Jul 2026 14:35:18 +0000 Subject: [PATCH 3/4] Translated using Weblate (Swedish) Currently translated at 100.0% (112 of 112 strings) Translation: server-env-19.0/server-env-19.0-server_environment Translate-URL: https://translation.odoo-community.org/projects/server-env-19-0/server-env-19-0-server_environment/sv/ --- server_environment/i18n/sv.po | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/server_environment/i18n/sv.po b/server_environment/i18n/sv.po index 92aee87ca..f0598420d 100644 --- a/server_environment/i18n/sv.po +++ b/server_environment/i18n/sv.po @@ -9,15 +9,15 @@ msgstr "" "Project-Id-Version: Odoo Server 10.0\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2017-05-01 10:39+0000\n" -"PO-Revision-Date: 2024-06-12 11:35+0000\n" -"Last-Translator: jakobkrabbe \n" +"PO-Revision-Date: 2026-07-01 16:46+0000\n" +"Last-Translator: Laura V \n" "Language-Team: Swedish (https://www.transifex.com/oca/teams/23907/sv/)\n" "Language: sv\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: \n" "Plural-Forms: nplurals=2; plural=n != 1;\n" -"X-Generator: Weblate 4.17\n" +"X-Generator: Weblate 5.15.2\n" #. module: server_environment #: model:ir.model.fields,field_description:server_environment.field_server_config__config @@ -159,12 +159,12 @@ msgstr "odoo | db_port" #. module: server_environment #: model:ir.model.fields,field_description:server_environment.field_server_config__odoo_I_db_replica_host msgid "odoo | db_replica_host" -msgstr "" +msgstr "odoo | db_replica_host" #. module: server_environment #: model:ir.model.fields,field_description:server_environment.field_server_config__odoo_I_db_replica_port msgid "odoo | db_replica_port" -msgstr "" +msgstr "odoo | db_replica_port" #. module: server_environment #: model:ir.model.fields,field_description:server_environment.field_server_config__odoo_I_db_sslmode @@ -259,7 +259,7 @@ msgstr "odoo | limit_memory_hard" #. module: server_environment #: model:ir.model.fields,field_description:server_environment.field_server_config__odoo_I_limit_memory_hard_gevent msgid "odoo | limit_memory_hard_gevent" -msgstr "" +msgstr "odoo | limit_memory_hard_gevent" #. module: server_environment #: model:ir.model.fields,field_description:server_environment.field_server_config__odoo_I_limit_memory_soft @@ -269,7 +269,7 @@ msgstr "odoo | limit_memory_soft" #. module: server_environment #: model:ir.model.fields,field_description:server_environment.field_server_config__odoo_I_limit_memory_soft_gevent msgid "odoo | limit_memory_soft_gevent" -msgstr "" +msgstr "odoo | limit_memory_soft_gevent" #. module: server_environment #: model:ir.model.fields,field_description:server_environment.field_server_config__odoo_I_limit_request @@ -294,7 +294,7 @@ msgstr "odoo | limit_time_real_cron" #. module: server_environment #: model:ir.model.fields,field_description:server_environment.field_server_config__odoo_I_limit_time_worker_cron msgid "odoo | limit_time_worker_cron" -msgstr "" +msgstr "odoo | limit_time_worker_cron" #. module: server_environment #: model:ir.model.fields,field_description:server_environment.field_server_config__odoo_I_list_db @@ -354,7 +354,7 @@ msgstr "odoo | pidfile" #. module: server_environment #: model:ir.model.fields,field_description:server_environment.field_server_config__odoo_I_pre_upgrade_scripts msgid "odoo | pre_upgrade_scripts" -msgstr "" +msgstr "odoo | pre_upgrade_scripts" #. module: server_environment #: model:ir.model.fields,field_description:server_environment.field_server_config__odoo_I_proxy_mode From c4343a4872f8b4e699a3406946aefee209e35519 Mon Sep 17 00:00:00 2001 From: Laura V Date: Wed, 1 Jul 2026 14:34:37 +0000 Subject: [PATCH 4/4] Translated using Weblate (Danish) Currently translated at 100.0% (112 of 112 strings) Translation: server-env-19.0/server-env-19.0-server_environment Translate-URL: https://translation.odoo-community.org/projects/server-env-19-0/server-env-19-0-server_environment/da/ --- server_environment/i18n/da.po | 219 +++++++++++++++++----------------- 1 file changed, 110 insertions(+), 109 deletions(-) diff --git a/server_environment/i18n/da.po b/server_environment/i18n/da.po index 2a9174a5a..742cc8726 100644 --- a/server_environment/i18n/da.po +++ b/server_environment/i18n/da.po @@ -9,19 +9,20 @@ msgstr "" "Project-Id-Version: Odoo Server 10.0\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2017-05-01 10:39+0000\n" -"PO-Revision-Date: 2017-05-01 10:39+0000\n" -"Last-Translator: OCA Transbot , 2017\n" +"PO-Revision-Date: 2026-07-01 16:46+0000\n" +"Last-Translator: Laura V \n" "Language-Team: Danish (https://www.transifex.com/oca/teams/23907/da/)\n" "Language: da\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: \n" -"Plural-Forms: nplurals=2; plural=(n != 1);\n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" +"X-Generator: Weblate 5.15.2\n" #. module: server_environment #: model:ir.model.fields,field_description:server_environment.field_server_config__config msgid "Config" -msgstr "" +msgstr "Konfiguration" #. module: server_environment #: model:ir.model.fields,field_description:server_environment.field_server_config__create_uid @@ -41,7 +42,7 @@ msgstr "Vist navn" #. module: server_environment #: model:ir.model,name:server_environment.model_server_config msgid "Display server configuration" -msgstr "" +msgstr "Vis serverkonfiguration" #. module: server_environment #: model:ir.model.fields,field_description:server_environment.field_server_config__id @@ -61,524 +62,524 @@ msgstr "Sidst opdateret den" #. module: server_environment #: model:ir.model,name:server_environment.model_server_env_mixin msgid "Mixin to add server environment in existing models" -msgstr "" +msgstr "Mixin til at tilføje servermiljø i eksisterende modeller" #. module: server_environment #: model:ir.model.fields,field_description:server_environment.field_server_env_mixin__server_env_defaults #: model:ir.model.fields,field_description:server_environment.field_server_env_techname_mixin__server_env_defaults msgid "Server Env Defaults" -msgstr "" +msgstr "Standardværdier for servermiljø" #. module: server_environment #: model:ir.actions.act_window,name:server_environment.server_env_act_show_config #: model:ir.ui.menu,name:server_environment.menu_server_show_config msgid "Server Environment" -msgstr "" +msgstr "Servermiljø" #. module: server_environment #: model:ir.model,name:server_environment.model_server_env_techname_mixin msgid "Server environment technical name" -msgstr "" +msgstr "Teknisk navn på servermiljø" #. module: server_environment #: model:ir.model.fields,field_description:server_environment.field_server_env_techname_mixin__tech_name msgid "Tech Name" -msgstr "" +msgstr "Teknisk navn" #. module: server_environment #: model:ir.model.fields,help:server_environment.field_server_env_techname_mixin__tech_name msgid "Unique name for technical purposes. Eg: server env keys." -msgstr "" +msgstr "Unikt navn til tekniske formål. F.eks.: servernøgler til miljøet." #. module: server_environment #: model:res.groups,name:server_environment.has_server_configuration_access msgid "View Server Environment Configuration" -msgstr "" +msgstr "Vis konfiguration af servermiljø" #. module: server_environment #: model:ir.model.constraint,message:server_environment.constraint_server_env_techname_mixin_tech_name_uniq msgid "`tech_name` must be unique!" -msgstr "" +msgstr "`tech_name` skal være unik!" #. module: server_environment #: model:ir.model.fields,field_description:server_environment.field_server_config__odoo_I_addons_path msgid "odoo | addons_path" -msgstr "" +msgstr "odoo | addons_path" #. module: server_environment #: model:ir.model.fields,field_description:server_environment.field_server_config__odoo_I_admin_passwd msgid "odoo | admin_passwd" -msgstr "" +msgstr "odoo | admin_passwd" #. module: server_environment #: model:ir.model.fields,field_description:server_environment.field_server_config__odoo_I_config msgid "odoo | config" -msgstr "" +msgstr "odoo | config" #. module: server_environment #: model:ir.model.fields,field_description:server_environment.field_server_config__odoo_I_csv_internal_sep msgid "odoo | csv_internal_sep" -msgstr "" +msgstr "odoo | csv_internal_sep" #. module: server_environment #: model:ir.model.fields,field_description:server_environment.field_server_config__odoo_I_data_dir msgid "odoo | data_dir" -msgstr "" +msgstr "odoo | data_dir" #. module: server_environment #: model:ir.model.fields,field_description:server_environment.field_server_config__odoo_I_db_host msgid "odoo | db_host" -msgstr "" +msgstr "odoo | db_host" #. module: server_environment #: model:ir.model.fields,field_description:server_environment.field_server_config__odoo_I_db_maxconn msgid "odoo | db_maxconn" -msgstr "" +msgstr "odoo | db_maxconn" #. module: server_environment #: model:ir.model.fields,field_description:server_environment.field_server_config__odoo_I_db_maxconn_gevent msgid "odoo | db_maxconn_gevent" -msgstr "" +msgstr "odoo | db_maxconn_gevent" #. module: server_environment #: model:ir.model.fields,field_description:server_environment.field_server_config__odoo_I_db_name msgid "odoo | db_name" -msgstr "" +msgstr "odoo | db_name" #. module: server_environment #: model:ir.model.fields,field_description:server_environment.field_server_config__odoo_I_db_password msgid "odoo | db_password" -msgstr "" +msgstr "odoo | db_password" #. module: server_environment #: model:ir.model.fields,field_description:server_environment.field_server_config__odoo_I_db_port msgid "odoo | db_port" -msgstr "" +msgstr "odoo | db_port" #. module: server_environment #: model:ir.model.fields,field_description:server_environment.field_server_config__odoo_I_db_replica_host msgid "odoo | db_replica_host" -msgstr "" +msgstr "odoo | db_replica_host" #. module: server_environment #: model:ir.model.fields,field_description:server_environment.field_server_config__odoo_I_db_replica_port msgid "odoo | db_replica_port" -msgstr "" +msgstr "odoo | db_replica_port" #. module: server_environment #: model:ir.model.fields,field_description:server_environment.field_server_config__odoo_I_db_sslmode msgid "odoo | db_sslmode" -msgstr "" +msgstr "odoo | db_sslmode" #. module: server_environment #: model:ir.model.fields,field_description:server_environment.field_server_config__odoo_I_db_template msgid "odoo | db_template" -msgstr "" +msgstr "odoo | db_template" #. module: server_environment #: model:ir.model.fields,field_description:server_environment.field_server_config__odoo_I_db_user msgid "odoo | db_user" -msgstr "" +msgstr "odoo | db_user" #. module: server_environment #: model:ir.model.fields,field_description:server_environment.field_server_config__odoo_I_dbfilter msgid "odoo | dbfilter" -msgstr "" +msgstr "odoo | dbfilter" #. module: server_environment #: model:ir.model.fields,field_description:server_environment.field_server_config__odoo_I_demo msgid "odoo | demo" -msgstr "" +msgstr "odoo | demo" #. module: server_environment #: model:ir.model.fields,field_description:server_environment.field_server_config__odoo_I_dev_mode msgid "odoo | dev_mode" -msgstr "" +msgstr "odoo | dev_mode" #. module: server_environment #: model:ir.model.fields,field_description:server_environment.field_server_config__odoo_I_email_from msgid "odoo | email_from" -msgstr "" +msgstr "odoo | email_from" #. module: server_environment #: model:ir.model.fields,field_description:server_environment.field_server_config__odoo_I_from_filter msgid "odoo | from_filter" -msgstr "" +msgstr "odoo | from_filter" #. module: server_environment #: model:ir.model.fields,field_description:server_environment.field_server_config__odoo_I_geoip_city_db msgid "odoo | geoip_city_db" -msgstr "" +msgstr "odoo | geoip_city_db" #. module: server_environment #: model:ir.model.fields,field_description:server_environment.field_server_config__odoo_I_geoip_country_db msgid "odoo | geoip_country_db" -msgstr "" +msgstr "odoo | geoip_country_db" #. module: server_environment #: model:ir.model.fields,field_description:server_environment.field_server_config__odoo_I_gevent_port msgid "odoo | gevent_port" -msgstr "" +msgstr "odoo | gevent_port" #. module: server_environment #: model:ir.model.fields,field_description:server_environment.field_server_config__odoo_I_http_enable msgid "odoo | http_enable" -msgstr "" +msgstr "odoo | http_enable" #. module: server_environment #: model:ir.model.fields,field_description:server_environment.field_server_config__odoo_I_http_interface msgid "odoo | http_interface" -msgstr "" +msgstr "odoo | http_interface" #. module: server_environment #: model:ir.model.fields,field_description:server_environment.field_server_config__odoo_I_http_port msgid "odoo | http_port" -msgstr "" +msgstr "odoo | http_port" #. module: server_environment #: model:ir.model.fields,field_description:server_environment.field_server_config__odoo_I_import_partial msgid "odoo | import_partial" -msgstr "" +msgstr "odoo | import_partial" #. module: server_environment #: model:ir.model.fields,field_description:server_environment.field_server_config__odoo_I_init msgid "odoo | init" -msgstr "" +msgstr "odoo | init" #. module: server_environment #: model:ir.model.fields,field_description:server_environment.field_server_config__odoo_I_language msgid "odoo | language" -msgstr "" +msgstr "odoo | language" #. module: server_environment #: model:ir.model.fields,field_description:server_environment.field_server_config__odoo_I_limit_memory_hard msgid "odoo | limit_memory_hard" -msgstr "" +msgstr "odoo | limit_memory_hard" #. module: server_environment #: model:ir.model.fields,field_description:server_environment.field_server_config__odoo_I_limit_memory_hard_gevent msgid "odoo | limit_memory_hard_gevent" -msgstr "" +msgstr "odoo | limit_memory_hard_gevent" #. module: server_environment #: model:ir.model.fields,field_description:server_environment.field_server_config__odoo_I_limit_memory_soft msgid "odoo | limit_memory_soft" -msgstr "" +msgstr "odoo | limit_memory_soft" #. module: server_environment #: model:ir.model.fields,field_description:server_environment.field_server_config__odoo_I_limit_memory_soft_gevent msgid "odoo | limit_memory_soft_gevent" -msgstr "" +msgstr "odoo | limit_memory_soft_gevent" #. module: server_environment #: model:ir.model.fields,field_description:server_environment.field_server_config__odoo_I_limit_request msgid "odoo | limit_request" -msgstr "" +msgstr "odoo | limit_request" #. module: server_environment #: model:ir.model.fields,field_description:server_environment.field_server_config__odoo_I_limit_time_cpu msgid "odoo | limit_time_cpu" -msgstr "" +msgstr "odoo | limit_time_cpu" #. module: server_environment #: model:ir.model.fields,field_description:server_environment.field_server_config__odoo_I_limit_time_real msgid "odoo | limit_time_real" -msgstr "" +msgstr "odoo | limit_time_real" #. module: server_environment #: model:ir.model.fields,field_description:server_environment.field_server_config__odoo_I_limit_time_real_cron msgid "odoo | limit_time_real_cron" -msgstr "" +msgstr "odoo | limit_time_real_cron" #. module: server_environment #: model:ir.model.fields,field_description:server_environment.field_server_config__odoo_I_limit_time_worker_cron msgid "odoo | limit_time_worker_cron" -msgstr "" +msgstr "odoo | limit_time_worker_cron" #. module: server_environment #: model:ir.model.fields,field_description:server_environment.field_server_config__odoo_I_list_db msgid "odoo | list_db" -msgstr "" +msgstr "odoo | list_db" #. module: server_environment #: model:ir.model.fields,field_description:server_environment.field_server_config__odoo_I_log_db msgid "odoo | log_db" -msgstr "" +msgstr "odoo | log_db" #. module: server_environment #: model:ir.model.fields,field_description:server_environment.field_server_config__odoo_I_log_db_level msgid "odoo | log_db_level" -msgstr "" +msgstr "odoo | log_db_level" #. module: server_environment #: model:ir.model.fields,field_description:server_environment.field_server_config__odoo_I_log_handler msgid "odoo | log_handler" -msgstr "" +msgstr "odoo | log_handler" #. module: server_environment #: model:ir.model.fields,field_description:server_environment.field_server_config__odoo_I_log_level msgid "odoo | log_level" -msgstr "" +msgstr "odoo | log_level" #. module: server_environment #: model:ir.model.fields,field_description:server_environment.field_server_config__odoo_I_logfile msgid "odoo | logfile" -msgstr "" +msgstr "odoo | logfile" #. module: server_environment #: model:ir.model.fields,field_description:server_environment.field_server_config__odoo_I_max_cron_threads msgid "odoo | max_cron_threads" -msgstr "" +msgstr "odoo | max_cron_threads" #. module: server_environment #: model:ir.model.fields,field_description:server_environment.field_server_config__odoo_I_osv_memory_count_limit msgid "odoo | osv_memory_count_limit" -msgstr "" +msgstr "odoo | osv_memory_count_limit" #. module: server_environment #: model:ir.model.fields,field_description:server_environment.field_server_config__odoo_I_overwrite_existing_translations msgid "odoo | overwrite_existing_translations" -msgstr "" +msgstr "odoo | overwrite_existing_translations" #. module: server_environment #: model:ir.model.fields,field_description:server_environment.field_server_config__odoo_I_pg_path msgid "odoo | pg_path" -msgstr "" +msgstr "odoo | pg_path" #. module: server_environment #: model:ir.model.fields,field_description:server_environment.field_server_config__odoo_I_pidfile msgid "odoo | pidfile" -msgstr "" +msgstr "odoo | pidfile" #. module: server_environment #: model:ir.model.fields,field_description:server_environment.field_server_config__odoo_I_pre_upgrade_scripts msgid "odoo | pre_upgrade_scripts" -msgstr "" +msgstr "odoo | pre_upgrade_scripts" #. module: server_environment #: model:ir.model.fields,field_description:server_environment.field_server_config__odoo_I_proxy_mode msgid "odoo | proxy_mode" -msgstr "" +msgstr "odoo | proxy_mode" #. module: server_environment #: model:ir.model.fields,field_description:server_environment.field_server_config__odoo_I_publisher_warranty_url msgid "odoo | publisher_warranty_url" -msgstr "" +msgstr "odoo | publisher_warranty_url" #. module: server_environment #: model:ir.model.fields,field_description:server_environment.field_server_config__odoo_I_reportgz msgid "odoo | reportgz" -msgstr "" +msgstr "odoo | reportgz" #. module: server_environment #: model:ir.model.fields,field_description:server_environment.field_server_config__odoo_I_root_path msgid "odoo | root_path" -msgstr "" +msgstr "odoo | root_path" #. module: server_environment #: model:ir.model.fields,field_description:server_environment.field_server_config__odoo_I_running_env msgid "odoo | running_env" -msgstr "" +msgstr "odoo | running_env" #. module: server_environment #: model:ir.model.fields,field_description:server_environment.field_server_config__odoo_I_save msgid "odoo | save" -msgstr "" +msgstr "odoo | save" #. module: server_environment #: model:ir.model.fields,field_description:server_environment.field_server_config__odoo_I_screencasts msgid "odoo | screencasts" -msgstr "" +msgstr "odoo | screencasts" #. module: server_environment #: model:ir.model.fields,field_description:server_environment.field_server_config__odoo_I_screenshots msgid "odoo | screenshots" -msgstr "" +msgstr "odoo | screenshots" #. module: server_environment #: model:ir.model.fields,field_description:server_environment.field_server_config__odoo_I_server_wide_modules msgid "odoo | server_wide_modules" -msgstr "" +msgstr "odoo | server_wide_modules" #. module: server_environment #: model:ir.model.fields,field_description:server_environment.field_server_config__odoo_I_shell_interface msgid "odoo | shell_interface" -msgstr "" +msgstr "odoo | shell_interface" #. module: server_environment #: model:ir.model.fields,field_description:server_environment.field_server_config__odoo_I_smtp_password msgid "odoo | smtp_password" -msgstr "" +msgstr "odoo | smtp_password" #. module: server_environment #: model:ir.model.fields,field_description:server_environment.field_server_config__odoo_I_smtp_port msgid "odoo | smtp_port" -msgstr "" +msgstr "odoo | smtp_port" #. module: server_environment #: model:ir.model.fields,field_description:server_environment.field_server_config__odoo_I_smtp_server msgid "odoo | smtp_server" -msgstr "" +msgstr "odoo | smtp_server" #. module: server_environment #: model:ir.model.fields,field_description:server_environment.field_server_config__odoo_I_smtp_ssl msgid "odoo | smtp_ssl" -msgstr "" +msgstr "odoo | smtp_ssl" #. module: server_environment #: model:ir.model.fields,field_description:server_environment.field_server_config__odoo_I_smtp_ssl_certificate_filename msgid "odoo | smtp_ssl_certificate_filename" -msgstr "" +msgstr "odoo | smtp_ssl_certificate_filename" #. module: server_environment #: model:ir.model.fields,field_description:server_environment.field_server_config__odoo_I_smtp_ssl_private_key_filename msgid "odoo | smtp_ssl_private_key_filename" -msgstr "" +msgstr "odoo | smtp_ssl_private_key_filename" #. module: server_environment #: model:ir.model.fields,field_description:server_environment.field_server_config__odoo_I_smtp_user msgid "odoo | smtp_user" -msgstr "" +msgstr "odoo | smtp_user" #. module: server_environment #: model:ir.model.fields,field_description:server_environment.field_server_config__odoo_I_stop_after_init msgid "odoo | stop_after_init" -msgstr "" +msgstr "odoo | stop_after_init" #. module: server_environment #: model:ir.model.fields,field_description:server_environment.field_server_config__odoo_I_syslog msgid "odoo | syslog" -msgstr "" +msgstr "odoo | syslog" #. module: server_environment #: model:ir.model.fields,field_description:server_environment.field_server_config__odoo_I_test_enable msgid "odoo | test_enable" -msgstr "" +msgstr "odoo | test_enable" #. module: server_environment #: model:ir.model.fields,field_description:server_environment.field_server_config__odoo_I_test_file msgid "odoo | test_file" -msgstr "" +msgstr "odoo | test_file" #. module: server_environment #: model:ir.model.fields,field_description:server_environment.field_server_config__odoo_I_test_tags msgid "odoo | test_tags" -msgstr "" +msgstr "odoo | test_tags" #. module: server_environment #: model:ir.model.fields,field_description:server_environment.field_server_config__odoo_I_transient_age_limit msgid "odoo | transient_age_limit" -msgstr "" +msgstr "odoo | transient_age_limit" #. module: server_environment #: model:ir.model.fields,field_description:server_environment.field_server_config__odoo_I_translate_in msgid "odoo | translate_in" -msgstr "" +msgstr "odoo | translate_in" #. module: server_environment #: model:ir.model.fields,field_description:server_environment.field_server_config__odoo_I_translate_modules msgid "odoo | translate_modules" -msgstr "" +msgstr "odoo | translate_modules" #. module: server_environment #: model:ir.model.fields,field_description:server_environment.field_server_config__odoo_I_translate_out msgid "odoo | translate_out" -msgstr "" +msgstr "odoo | translate_out" #. module: server_environment #: model:ir.model.fields,field_description:server_environment.field_server_config__odoo_I_unaccent msgid "odoo | unaccent" -msgstr "" +msgstr "odoo | unaccent" #. module: server_environment #: model:ir.model.fields,field_description:server_environment.field_server_config__odoo_I_update msgid "odoo | update" -msgstr "" +msgstr "odoo | update" #. module: server_environment #: model:ir.model.fields,field_description:server_environment.field_server_config__odoo_I_upgrade_path msgid "odoo | upgrade_path" -msgstr "" +msgstr "odoo | upgrade_path" #. module: server_environment #: model:ir.model.fields,field_description:server_environment.field_server_config__odoo_I_websocket_keep_alive_timeout msgid "odoo | websocket_keep_alive_timeout" -msgstr "" +msgstr "odoo | websocket_keep_alive_timeout" #. module: server_environment #: model:ir.model.fields,field_description:server_environment.field_server_config__odoo_I_websocket_rate_limit_burst msgid "odoo | websocket_rate_limit_burst" -msgstr "" +msgstr "odoo | websocket_rate_limit_burst" #. module: server_environment #: model:ir.model.fields,field_description:server_environment.field_server_config__odoo_I_websocket_rate_limit_delay msgid "odoo | websocket_rate_limit_delay" -msgstr "" +msgstr "odoo | websocket_rate_limit_delay" #. module: server_environment #: model:ir.model.fields,field_description:server_environment.field_server_config__odoo_I_without_demo msgid "odoo | without_demo" -msgstr "" +msgstr "odoo | without_demo" #. module: server_environment #: model:ir.model.fields,field_description:server_environment.field_server_config__odoo_I_workers msgid "odoo | workers" -msgstr "" +msgstr "odoo | workers" #. module: server_environment #: model:ir.model.fields,field_description:server_environment.field_server_config__odoo_I_x_sendfile msgid "odoo | x_sendfile" -msgstr "" +msgstr "odoo | x_sendfile" #. module: server_environment #: model:ir.model.fields,field_description:server_environment.field_server_config__system_I_architecture msgid "system | architecture" -msgstr "" +msgstr "system | architecture" #. module: server_environment #: model:ir.model.fields,field_description:server_environment.field_server_config__system_I_locale msgid "system | locale" -msgstr "" +msgstr "system | locale" #. module: server_environment #: model:ir.model.fields,field_description:server_environment.field_server_config__system_I_lsb_release msgid "system | lsb_release" -msgstr "" +msgstr "system | lsb_release" #. module: server_environment #: model:ir.model.fields,field_description:server_environment.field_server_config__system_I_odoo msgid "system | odoo" -msgstr "" +msgstr "system | odoo" #. module: server_environment #: model:ir.model.fields,field_description:server_environment.field_server_config__system_I_os_name msgid "system | os_name" -msgstr "" +msgstr "system | os_name" #. module: server_environment #: model:ir.model.fields,field_description:server_environment.field_server_config__system_I_platform msgid "system | platform" -msgstr "" +msgstr "system | platform" #. module: server_environment #: model:ir.model.fields,field_description:server_environment.field_server_config__system_I_python msgid "system | python" -msgstr "" +msgstr "system | python" #. module: server_environment #: model:ir.model.fields,field_description:server_environment.field_server_config__system_I_release msgid "system | release" -msgstr "" +msgstr "system | release" #. module: server_environment #: model:ir.model.fields,field_description:server_environment.field_server_config__system_I_revision msgid "system | revision" -msgstr "" +msgstr "system | revision" #. module: server_environment #: model:ir.model.fields,field_description:server_environment.field_server_config__system_I_version msgid "system | version" -msgstr "" +msgstr "system | version" #~ msgid "Last Modified on" #~ msgstr "Sidst ændret den"