├── .editorconfig ├── .eslintrc.yml ├── .gitignore ├── .pre-commit-config.yaml ├── .prettierrc.yml ├── .pylintrc ├── .ruff.toml ├── README.md ├── auth_impersonate_user ├── LICENSE ├── README.rst ├── __init__.py ├── __manifest__.py ├── controllers │ ├── __init__.py │ └── main.py ├── demo │ └── res_users.xml ├── i18n │ └── de.po ├── images │ └── screen.png ├── models │ ├── __init__.py │ └── res_users.py ├── pyproject.toml ├── security │ └── security.xml ├── static │ └── description │ │ ├── icon.png │ │ └── index.html └── views │ └── res_users.xml ├── auth_totp_ip_check ├── LICENSE ├── README.rst ├── __init__.py ├── __manifest__.py ├── images │ └── screen.png ├── models │ ├── __init__.py │ ├── allowed_cidrs.py │ └── res_users.py ├── pyproject.toml ├── security │ └── ir.model.access.csv ├── static │ └── description │ │ ├── icon.png │ │ └── index.html └── views │ └── auth_totp_cidr.xml ├── base_action_manager_access ├── LICENSE ├── README.rst ├── __init__.py ├── __manifest__.py ├── images │ └── screen.png ├── models │ ├── __init__.py │ └── ir_actions.py ├── pyproject.toml ├── security │ └── ir.model.access.csv └── static │ └── description │ ├── icon.png │ └── index.html ├── base_db_anonymization ├── LICENSE ├── README.rst ├── __init__.py ├── __manifest__.py ├── data │ └── ir_model_fields.xml ├── demo │ └── res_groups.xml ├── images │ └── screen.png ├── models │ ├── __init__.py │ └── ir_model_fields.py ├── pyproject.toml ├── security │ ├── ir.model.access.csv │ └── security.xml ├── static │ └── description │ │ ├── icon.png │ │ └── index.html └── views │ ├── ir_model_fields.xml │ └── ir_models_fields_anonymize.xml ├── base_module_user_acl ├── LICENSE ├── README.rst ├── __manifest__.py ├── i18n │ └── de_CH.po ├── images │ └── screen.png ├── security │ └── security.xml ├── static │ └── description │ │ ├── icon.png │ │ └── index.html └── views │ └── menu.xml ├── base_user_acl ├── LICENSE ├── README.rst ├── __manifest__.py ├── i18n │ └── de_CH.po ├── images │ └── screen.png ├── security │ └── security.xml └── static │ └── description │ ├── icon.png │ └── index.html ├── base_vat_required_vies ├── LICENSE ├── README.rst ├── __init__.py ├── __manifest__.py ├── i18n │ ├── de.po │ └── de_CH.po ├── images │ └── screen.png ├── models │ ├── __init__.py │ └── res_partner.py ├── pyproject.toml └── static │ └── description │ ├── icon.png │ └── index.html ├── board_user_acl ├── LICENSE ├── README.rst ├── __manifest__.py ├── i18n │ └── de_CH.po ├── images │ └── screen.png ├── security │ └── security.xml ├── static │ └── description │ │ ├── icon.png │ │ └── index.html └── views │ └── menu.xml ├── home_background_image ├── LICENSE ├── README.rst ├── __init__.py ├── __manifest__.py ├── images │ └── screen.png ├── models │ ├── __init__.py │ └── res_company.py ├── pyproject.toml ├── static │ ├── description │ │ ├── icon.png │ │ └── index.html │ └── src │ │ └── webclient │ │ └── home_menu │ │ └── home_menu_background.scss └── views │ └── base.xml ├── mail_disable_translation ├── LICENSE ├── README.rst ├── __init__.py ├── __manifest__.py ├── images │ └── screen.png ├── models │ ├── __init__.py │ └── mail_template.py ├── pyproject.toml └── static │ └── description │ ├── icon.png │ └── index.html ├── mail_format_with_parent ├── LICENSE ├── README.rst ├── __init__.py ├── __manifest__.py ├── images │ └── screen.png ├── models │ ├── __init__.py │ ├── mail_mail.py │ └── res_partner.py ├── pyproject.toml └── static │ └── description │ ├── icon.png │ └── index.html ├── mail_server_filter ├── LICENSE ├── README.rst ├── __init__.py ├── __manifest__.py ├── images │ └── screen.png ├── models │ ├── __init__.py │ ├── fetchmail_server.py │ └── ir_mail_server.py ├── pyproject.toml ├── static │ └── description │ │ ├── icon.png │ │ └── index.html └── views │ ├── fetchmail_server.xml │ └── ir_mail_server.xml ├── mail_service_users ├── LICENSE ├── README.rst ├── __init__.py ├── __manifest__.py ├── i18n │ └── de_CH.po ├── images │ └── screen.png ├── models │ ├── __init__.py │ ├── res_config_settings.py │ ├── res_users.py │ └── update.py ├── pyproject.toml ├── static │ └── description │ │ ├── icon.png │ │ └── index.html └── views │ └── base.xml ├── mail_tracking_helpdesk_bounce_ticket ├── LICENSE ├── README.rst ├── __init__.py ├── __manifest__.py ├── images │ └── screen.png ├── models │ ├── __init__.py │ └── mail_message.py ├── pyproject.toml ├── static │ └── description │ │ ├── icon.png │ │ └── index.html └── tests │ ├── __init__.py │ └── test_mail_message.py ├── product_disable_translation ├── LICENSE ├── README.rst ├── __init__.py ├── __manifest__.py ├── images │ └── screen.png ├── models │ ├── __init__.py │ └── product_template.py ├── pyproject.toml └── static │ └── description │ ├── icon.png │ └── index.html ├── prometheus_exporter ├── LICENSE ├── README.rst ├── __init__.py ├── __manifest__.py ├── controllers │ ├── __init__.py │ └── prometheus_metrics.py ├── data │ └── ir_metric.xml ├── images │ └── screen.png ├── models │ ├── __init__.py │ └── ir_metric.py ├── pyproject.toml ├── security │ └── ir.model.access.csv ├── static │ └── description │ │ ├── icon.png │ │ └── index.html └── views │ └── ir_metric.xml ├── requirements.txt ├── server_config_environment ├── LICENSE ├── README.rst ├── __init__.py ├── __manifest__.py ├── data │ └── data.xml ├── images │ └── screen.png ├── models │ ├── __init__.py │ └── server_config_environment.py ├── pyproject.toml ├── security │ ├── ir.model.access.csv │ └── security.xml ├── static │ └── description │ │ ├── icon.png │ │ └── index.html └── views │ └── server_config_environment_views.xml ├── task ├── url_slug ├── LICENSE ├── README.rst ├── __init__.py ├── __manifest__.py ├── images │ └── screen.png ├── models │ ├── __init__.py │ └── url_slug_mixin.py ├── pyproject.toml └── static │ └── description │ ├── icon.png │ └── index.html ├── web_editor_disable_convert_inline ├── LICENSE ├── README.rst ├── __init__.py ├── __manifest__.py ├── images │ └── screen.png ├── pyproject.toml ├── static │ ├── description │ │ ├── icon.png │ │ └── index.html │ └── src │ │ └── js │ │ └── backend │ │ └── html_field.esm.js └── tests │ └── TEST_INSTRUCTIONS.rst ├── web_enterprise_admin_expiration_panel ├── LICENSE ├── README.rst ├── __init__.py ├── __manifest__.py ├── images │ └── screen.png ├── pyproject.toml └── static │ ├── description │ ├── icon.png │ └── index.html │ └── src │ └── js │ ├── expiration_panel.js │ └── expiration_panel.xml └── web_font_arial ├── LICENSE ├── README.rst ├── __init__.py ├── __manifest__.py ├── models ├── __init__.py └── res_company.py ├── pyproject.toml └── static └── description ├── icon.png └── index.html /.editorconfig: -------------------------------------------------------------------------------- 1 | # Configuration for known file extensions 2 | [*.{css,js,json,less,md,py,rst,sass,scss,xml,yaml,yml}] 3 | charset = utf-8 4 | end_of_line = lf 5 | indent_size = 4 6 | indent_style = space 7 | insert_final_newline = true 8 | trim_trailing_whitespace = true 9 | 10 | [*.{json,yml,yaml,rst,md}] 11 | indent_size = 2 12 | 13 | # Do not configure editor for libs and autogenerated content 14 | [{*/static/{lib,src/lib}/**,*/static/description/index.html,*/readme/../README.rst}] 15 | charset = unset 16 | end_of_line = unset 17 | indent_size = unset 18 | indent_style = unset 19 | insert_final_newline = false 20 | trim_trailing_whitespace = false 21 | -------------------------------------------------------------------------------- /.eslintrc.yml: -------------------------------------------------------------------------------- 1 | env: 2 | browser: true 3 | es6: true 4 | 5 | # See https://github.com/OCA/odoo-community.org/issues/37#issuecomment-470686449 6 | parserOptions: 7 | ecmaVersion: 2019 8 | 9 | overrides: 10 | - files: 11 | - "**/*.esm.js" 12 | parserOptions: 13 | sourceType: module 14 | 15 | # Globals available in Odoo that shouldn't produce errorings 16 | globals: 17 | _: readonly 18 | $: readonly 19 | fuzzy: readonly 20 | jQuery: readonly 21 | moment: readonly 22 | odoo: readonly 23 | openerp: readonly 24 | owl: readonly 25 | luxon: readonly 26 | 27 | # Styling is handled by Prettier, so we only need to enable AST rules; 28 | # see https://github.com/OCA/maintainer-quality-tools/pull/618#issuecomment-558576890 29 | rules: 30 | accessor-pairs: warn 31 | array-callback-return: warn 32 | callback-return: warn 33 | capitalized-comments: 34 | - warn 35 | - always 36 | - ignoreConsecutiveComments: true 37 | ignoreInlineComments: true 38 | complexity: 39 | - warn 40 | - 15 41 | constructor-super: warn 42 | dot-notation: warn 43 | eqeqeq: warn 44 | global-require: warn 45 | handle-callback-err: warn 46 | id-blacklist: warn 47 | id-match: warn 48 | init-declarations: error 49 | max-depth: warn 50 | max-nested-callbacks: warn 51 | max-statements-per-line: warn 52 | no-alert: warn 53 | no-array-constructor: warn 54 | no-caller: warn 55 | no-case-declarations: warn 56 | no-class-assign: warn 57 | no-cond-assign: error 58 | no-const-assign: error 59 | no-constant-condition: warn 60 | no-control-regex: warn 61 | no-debugger: error 62 | no-delete-var: warn 63 | no-div-regex: warn 64 | no-dupe-args: error 65 | no-dupe-class-members: error 66 | no-dupe-keys: error 67 | no-duplicate-case: error 68 | no-duplicate-imports: error 69 | no-else-return: warn 70 | no-empty-character-class: warn 71 | no-empty-function: error 72 | no-empty-pattern: error 73 | no-empty: warn 74 | no-eq-null: error 75 | no-eval: error 76 | no-ex-assign: error 77 | no-extend-native: warn 78 | no-extra-bind: warn 79 | no-extra-boolean-cast: warn 80 | no-extra-label: warn 81 | no-fallthrough: warn 82 | no-func-assign: error 83 | no-global-assign: error 84 | no-implicit-coercion: 85 | - warn 86 | - allow: ["~"] 87 | no-implicit-globals: warn 88 | no-implied-eval: warn 89 | no-inline-comments: warn 90 | no-inner-declarations: warn 91 | no-invalid-regexp: warn 92 | no-irregular-whitespace: warn 93 | no-iterator: warn 94 | no-label-var: warn 95 | no-labels: warn 96 | no-lone-blocks: warn 97 | no-lonely-if: error 98 | no-mixed-requires: error 99 | no-multi-str: warn 100 | no-native-reassign: error 101 | no-negated-condition: warn 102 | no-negated-in-lhs: error 103 | no-new-func: warn 104 | no-new-object: warn 105 | no-new-require: warn 106 | no-new-symbol: warn 107 | no-new-wrappers: warn 108 | no-new: warn 109 | no-obj-calls: warn 110 | no-octal-escape: warn 111 | no-octal: warn 112 | no-param-reassign: warn 113 | no-path-concat: warn 114 | no-process-env: warn 115 | no-process-exit: warn 116 | no-proto: warn 117 | no-prototype-builtins: warn 118 | no-redeclare: warn 119 | no-regex-spaces: warn 120 | no-restricted-globals: warn 121 | no-restricted-imports: warn 122 | no-restricted-modules: warn 123 | no-restricted-syntax: warn 124 | no-return-assign: error 125 | no-script-url: warn 126 | no-self-assign: warn 127 | no-self-compare: warn 128 | no-sequences: warn 129 | no-shadow-restricted-names: warn 130 | no-shadow: warn 131 | no-sparse-arrays: warn 132 | no-sync: warn 133 | no-this-before-super: warn 134 | no-throw-literal: warn 135 | no-undef-init: warn 136 | no-undef: error 137 | no-unmodified-loop-condition: warn 138 | no-unneeded-ternary: error 139 | no-unreachable: error 140 | no-unsafe-finally: error 141 | no-unused-expressions: error 142 | no-unused-labels: error 143 | no-unused-vars: error 144 | no-use-before-define: error 145 | no-useless-call: warn 146 | no-useless-computed-key: warn 147 | no-useless-concat: warn 148 | no-useless-constructor: warn 149 | no-useless-escape: warn 150 | no-useless-rename: warn 151 | no-void: warn 152 | no-with: warn 153 | operator-assignment: [error, always] 154 | prefer-const: warn 155 | radix: warn 156 | require-yield: warn 157 | sort-imports: warn 158 | spaced-comment: [error, always] 159 | strict: [error, function] 160 | use-isnan: error 161 | valid-jsdoc: 162 | - warn 163 | - prefer: 164 | arg: param 165 | argument: param 166 | augments: extends 167 | constructor: class 168 | exception: throws 169 | func: function 170 | method: function 171 | prop: property 172 | return: returns 173 | virtual: abstract 174 | yield: yields 175 | preferType: 176 | array: Array 177 | bool: Boolean 178 | boolean: Boolean 179 | number: Number 180 | object: Object 181 | str: String 182 | string: String 183 | requireParamDescription: false 184 | requireReturn: false 185 | requireReturnDescription: false 186 | requireReturnType: false 187 | valid-typeof: warn 188 | yoda: warn 189 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | /.venv 5 | /.pytest_cache 6 | /.ruff_cache 7 | 8 | # C extensions 9 | *.so 10 | 11 | # Distribution / packaging 12 | .Python 13 | env/ 14 | bin/ 15 | build/ 16 | develop-eggs/ 17 | dist/ 18 | eggs/ 19 | lib64/ 20 | parts/ 21 | sdist/ 22 | var/ 23 | *.egg-info/ 24 | .installed.cfg 25 | *.egg 26 | *.eggs 27 | 28 | # Windows installers 29 | *.msi 30 | 31 | # Debian packages 32 | *.deb 33 | 34 | # Redhat packages 35 | *.rpm 36 | 37 | # MacOS packages 38 | *.dmg 39 | *.pkg 40 | 41 | # Installer logs 42 | pip-log.txt 43 | pip-delete-this-directory.txt 44 | 45 | # Unit test / coverage reports 46 | htmlcov/ 47 | .tox/ 48 | .coverage 49 | .cache 50 | nosetests.xml 51 | coverage.xml 52 | 53 | # Translations 54 | *.mo 55 | 56 | # Pycharm 57 | .idea 58 | 59 | # Eclipse 60 | .settings 61 | 62 | # Visual Studio cache/options directory 63 | .vs/ 64 | .vscode 65 | 66 | # OSX Files 67 | .DS_Store 68 | 69 | # Django stuff: 70 | *.log 71 | 72 | # Mr Developer 73 | .mr.developer.cfg 74 | .project 75 | .pydevproject 76 | 77 | # Rope 78 | .ropeproject 79 | 80 | # Sphinx documentation 81 | docs/_build/ 82 | 83 | # Backup files 84 | *~ 85 | *.swp 86 | 87 | # OCA rules 88 | !static/lib/ 89 | -------------------------------------------------------------------------------- /.pre-commit-config.yaml: -------------------------------------------------------------------------------- 1 | exclude: | 2 | (?x) 3 | # NOT INSTALLABLE ADDONS 4 | # END NOT INSTALLABLE ADDONS 5 | # Files and folders generated by bots, to avoid loops 6 | ^setup/|/static/description/index\.html$| 7 | # We don't want to mess with tool-generated files 8 | .svg$|/tests/([^/]+/)?cassettes/|^.copier-answers.yml$|^.github/|^eslint.config.cjs|^prettier.config.cjs| 9 | # Maybe reactivate this when all README files include prettier ignore tags? 10 | ^README\.md$| 11 | # Library files can have extraneous formatting (even minimized) 12 | /static/(src/)?lib/| 13 | # Repos using Sphinx to generate docs don't need prettying 14 | ^docs/_templates/.*\.html$| 15 | # Don't bother non-technical authors with formatting issues in docs 16 | readme/.*\.(rst|md)$| 17 | # Ignore build and dist directories in addons 18 | /build/|/dist/| 19 | # Ignore test files in addons 20 | /tests/samples/.*| 21 | # You don't usually want a bot to modify your legal texts 22 | (LICENSE.*|COPYING.*) 23 | default_language_version: 24 | python: python3 25 | node: "16.17.0" 26 | repos: 27 | - repo: local 28 | hooks: 29 | # These files are most likely copier diff rejection junks; if found, 30 | # review them manually, fix the problem (if needed) and remove them 31 | - id: forbidden-files 32 | name: forbidden files 33 | entry: found forbidden files; remove them 34 | language: fail 35 | files: "\\.rej$" 36 | - id: en-po-files 37 | name: en.po files cannot exist 38 | entry: found a en.po file 39 | language: fail 40 | files: '[a-zA-Z0-9_]*/i18n/en\.po$' 41 | - repo: https://github.com/sbidoul/whool 42 | rev: v1.2 43 | hooks: 44 | - id: whool-init 45 | - repo: https://github.com/oca/maintainer-tools 46 | rev: d5fab7ee87fceee858a3d01048c78a548974d935 47 | hooks: 48 | # update the NOT INSTALLABLE ADDONS section above 49 | - id: oca-update-pre-commit-excluded-addons 50 | - id: oca-fix-manifest-website 51 | args: ["https://www.mint-system.ch/"] 52 | - id: oca-gen-addon-readme 53 | args: 54 | - --addons-dir=. 55 | - --branch=16.0 56 | - --org-name=Mint-System 57 | - --repo-name=template 58 | - --if-source-changed 59 | - --keep-source-digest 60 | - id: oca-gen-external-dependencies 61 | - repo: https://github.com/OCA/odoo-pre-commit-hooks 62 | rev: v0.0.25 63 | hooks: 64 | - id: oca-checks-odoo-module 65 | args: 66 | - --disable=translation-positional-used 67 | - id: oca-checks-po 68 | args: 69 | - --disable=po-pretty-format 70 | - repo: local 71 | hooks: 72 | - id: prettier 73 | name: prettier (with plugin-xml) 74 | entry: prettier 75 | args: 76 | - --write 77 | - --list-different 78 | - --ignore-unknown 79 | types: [text] 80 | files: \.(css|htm|html|js|json|jsx|less|md|scss|toml|ts|xml|yaml|yml)$ 81 | language: node 82 | additional_dependencies: 83 | - "prettier@2.7.1" 84 | - "@prettier/plugin-xml@2.2.0" 85 | - repo: local 86 | hooks: 87 | - id: eslint 88 | name: eslint 89 | entry: eslint 90 | args: 91 | - --color 92 | - --fix 93 | verbose: true 94 | types: [javascript] 95 | language: node 96 | additional_dependencies: 97 | - "eslint@8.24.0" 98 | - "eslint-plugin-jsdoc@" 99 | - repo: https://github.com/pre-commit/pre-commit-hooks 100 | rev: v4.3.0 101 | hooks: 102 | - id: trailing-whitespace 103 | # exclude autogenerated files 104 | exclude: /README\.rst$|\.pot?$ 105 | - id: end-of-file-fixer 106 | # exclude autogenerated files 107 | exclude: /README\.rst$|\.pot?$ 108 | - id: debug-statements 109 | - id: fix-encoding-pragma 110 | args: ["--remove"] 111 | - id: check-case-conflict 112 | - id: check-docstring-first 113 | - id: check-executables-have-shebangs 114 | - id: check-merge-conflict 115 | # exclude files where underlines are not distinguishable from merge conflicts 116 | exclude: /README\.rst$|^docs/.*\.rst$ 117 | - id: check-symlinks 118 | - id: check-xml 119 | - id: mixed-line-ending 120 | args: ["--fix=lf"] 121 | - repo: https://github.com/astral-sh/ruff-pre-commit 122 | rev: v0.1.3 123 | hooks: 124 | - id: ruff 125 | args: [--fix, --exit-non-zero-on-fix] 126 | - id: ruff-format 127 | - repo: https://github.com/OCA/pylint-odoo 128 | rev: v8.0.19 129 | hooks: 130 | - id: pylint_odoo 131 | name: pylint with optional checks 132 | args: 133 | - --rcfile=.pylintrc 134 | - --exit-zero 135 | verbose: true 136 | -------------------------------------------------------------------------------- /.prettierrc.yml: -------------------------------------------------------------------------------- 1 | # Defaults for all prettier-supported languages. 2 | # Prettier will complete this with settings from .editorconfig file. 3 | bracketSpacing: false 4 | printWidth: 88 5 | proseWrap: always 6 | semi: true 7 | trailingComma: "es5" 8 | xmlWhitespaceSensitivity: "strict" 9 | -------------------------------------------------------------------------------- /.pylintrc: -------------------------------------------------------------------------------- 1 | 2 | 3 | [MASTER] 4 | load-plugins=pylint_odoo 5 | score=n 6 | 7 | [ODOOLINT] 8 | readme-template-url="https://github.com/OCA/maintainer-tools/blob/master/template/module/README.rst" 9 | manifest-required-authors=Mint System GmbH 10 | manifest-required-keys=license 11 | manifest-deprecated-keys=description,active 12 | license-allowed=AGPL-3,GPL-2,GPL-2 or any later version,GPL-3,GPL-3 or any later version,LGPL-3 13 | valid-odoo-versions=16.0 14 | 15 | [MESSAGES CONTROL] 16 | disable=all 17 | 18 | # This .pylintrc contains optional AND mandatory checks and is meant to be 19 | # loaded in an IDE to have it check everything, in the hope this will make 20 | # optional checks more visible to contributors who otherwise never look at a 21 | # green travis to see optional checks that failed. 22 | # .pylintrc-mandatory containing only mandatory checks is used the pre-commit 23 | # config as a blocking check. 24 | 25 | enable=anomalous-backslash-in-string, 26 | api-one-deprecated, 27 | api-one-multi-together, 28 | assignment-from-none, 29 | attribute-deprecated, 30 | class-camelcase, 31 | dangerous-default-value, 32 | dangerous-view-replace-wo-priority, 33 | development-status-allowed, 34 | duplicate-id-csv, 35 | duplicate-key, 36 | duplicate-xml-fields, 37 | eval-referenced, 38 | eval-used, 39 | incoherent-interpreter-exec-perm, 40 | license-allowed, 41 | manifest-author-string, 42 | manifest-deprecated-key, 43 | manifest-required-author, 44 | manifest-required-key, 45 | manifest-version-format, 46 | method-compute, 47 | method-inverse, 48 | method-required-super, 49 | method-search, 50 | openerp-exception-warning, 51 | pointless-statement, 52 | pointless-string-statement, 53 | print-used, 54 | redundant-keyword-arg, 55 | redundant-modulename-xml, 56 | reimported, 57 | relative-import, 58 | return-in-init, 59 | rst-syntax-error, 60 | sql-injection, 61 | too-few-format-args, 62 | translation-field, 63 | translation-required, 64 | unreachable, 65 | use-vim-comment, 66 | wrong-tabs-instead-of-spaces, 67 | xml-syntax-error, 68 | attribute-string-redundant, 69 | character-not-valid-in-resource-link, 70 | consider-merging-classes-inherited, 71 | context-overridden, 72 | create-user-wo-reset-password, 73 | dangerous-filter-wo-user, 74 | dangerous-qweb-replace-wo-priority, 75 | deprecated-data-xml-node, 76 | deprecated-openerp-xml-node, 77 | duplicate-po-message-definition, 78 | except-pass, 79 | file-not-used, 80 | invalid-commit, 81 | manifest-maintainers-list, 82 | missing-newline-extrafiles, 83 | missing-readme, 84 | odoo-addons-relative-import, 85 | old-api7-method-defined, 86 | po-msgstr-variables, 87 | po-syntax-error, 88 | renamed-field-parameter, 89 | resource-not-exist, 90 | str-format-used, 91 | test-folder-imported, 92 | translation-contains-variable, 93 | translation-positional-used, 94 | unnecessary-utf8-coding-comment, 95 | website-manifest-key-not-valid-uri, 96 | xml-attribute-translatable, 97 | xml-deprecated-qweb-directive, 98 | xml-deprecated-tree-attribute, 99 | external-request-timeout, 100 | # messages that do not cause the lint step to fail 101 | consider-merging-classes-inherited, 102 | create-user-wo-reset-password, 103 | dangerous-filter-wo-user, 104 | deprecated-module, 105 | file-not-used, 106 | invalid-commit, 107 | missing-manifest-dependency, 108 | missing-newline-extrafiles, 109 | missing-readme, 110 | no-utf8-coding-comment, 111 | odoo-addons-relative-import, 112 | old-api7-method-defined, 113 | redefined-builtin, 114 | too-complex, 115 | unnecessary-utf8-coding-comment 116 | 117 | 118 | [REPORTS] 119 | msg-template={path}:{line}: [{msg_id}({symbol}), {obj}] {msg} 120 | output-format=colorized 121 | reports=no 122 | -------------------------------------------------------------------------------- /.ruff.toml: -------------------------------------------------------------------------------- 1 | line-length = 120 2 | target-version = "py310" 3 | fix = true 4 | 5 | [lint] 6 | extend-select = [ 7 | "B", 8 | "C90", 9 | "E501", # line too long (default 88) 10 | "I", # isort 11 | "UP", # pyupgrade 12 | ] 13 | extend-safe-fixes = ["UP008"] 14 | exclude = ["setup/*"] 15 | 16 | [format] 17 | exclude = ["setup/*"] 18 | 19 | [per-file-ignores] 20 | "__init__.py" = ["F401", "I001"] # ignore unused and unsorted imports in __init__.py 21 | "__manifest__.py" = ["B018"] # useless expression 22 | 23 | [isort] 24 | section-order = ["future", "standard-library", "third-party", "odoo", "odoo-addons", "first-party", "local-folder"] 25 | 26 | [isort.sections] 27 | "odoo" = ["odoo"] 28 | "odoo-addons" = ["odoo.addons"] 29 | 30 | [mccabe] 31 | max-complexity = 16 32 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Odoo Apps: Server Tools 2 | 3 | Collection of Odoo apps to improve technical features. 4 | 5 | ## Usage 6 | 7 | Clone module into Odoo addon directory. 8 | 9 | ```bash 10 | git clone git@github.com:mint-system/odoo-apps-server-tools.git ./addons/server_tools 11 | ``` 12 | 13 | ## Available modules 14 | 15 | | Module | Summary | 16 | | --- | --- | 17 | | [auth_impersonate_user](auth_impersonate_user) | Impersonate another users. | 18 | | [auth_totp_ip_check](auth_totp_ip_check) | Disable totp for specific ip networks. | 19 | | [base_action_manager_access](base_action_manager_access) | Grant server action access to erp manager group. | 20 | | [base_db_anonymization](base_db_anonymization) | Anonymize content of selected database fields. | 21 | | [base_module_user_acl](base_module_user_acl) | Restricted access to apps app. | 22 | | [base_user_acl](base_user_acl) | Base module for ACL modules. | 23 | | [base_vat_required_vies](base_vat_required_vies) | Make VIES VAT check mandatory. | 24 | | [board_user_acl](board_user_acl) | Restrict access to dashboards app. | 25 | | [home_background_image](home_background_image) | Set a background image for the Odoo company. | 26 | | [mail_disable_translation](mail_disable_translation) | Disable translation for fields of the mail module. | 27 | | [mail_format_with_parent](mail_format_with_parent) | Use name of parent for mailing if partner has no name. | 28 | | [mail_server_filter](mail_server_filter) | Filter outgoing and incoming mail server by database name. | 29 | | [mail_service_users](mail_service_users) | Exclude service users from warranty contract. | 30 | | [mail_tracking_helpdesk_bounce_ticket](mail_tracking_helpdesk_bounce_ticket) | When email is bounced create a helpdesk ticket. | 31 | | [product_disable_translation](product_disable_translation) | Disable translation for fields of the product module. | 32 | | [prometheus_exporter](prometheus_exporter) | Monitor Odoo metrics with Prometheus. | 33 | | [server_config_environment](server_config_environment) | Define environments for server configurations. | 34 | | [url_slug](url_slug) | Generate slug from record name for web urls. | 35 | | [web_editor_disable_convert_inline](web_editor_disable_convert_inline) | Disable inline conversion in Odoo editor. | 36 | | [web_enterprise_admin_expiration_panel](web_enterprise_admin_expiration_panel) | Show database expiration panel for Admins only. | 37 | | [web_font_arial](web_font_arial) | Add Arial font to font selection. | 38 | -------------------------------------------------------------------------------- /auth_impersonate_user/README.rst: -------------------------------------------------------------------------------- 1 | .. image:: https://img.shields.io/badge/licence-GPL--3-blue.svg 2 | :target: http://www.gnu.org/licenses/gpl-3.0-standalone.html 3 | :alt: License: GPL-3 4 | 5 | ===================== 6 | Auth Impersonate User 7 | ===================== 8 | 9 | Impersonate another users. 10 | 11 | For a detailed documentation have a look at https://www.odoo-wiki.org/. 12 | 13 | .. image:: https://raw.githubusercontent.com/Mint-System/Wiki/master/assets/icon-box.png 14 | :height: 100 15 | :width: 100 16 | :alt: Icon 17 | 18 | Configuration 19 | ~~~~~~~~~~~~~ 20 | 21 | * No additional configurations needed 22 | 23 | Maintainer 24 | ========== 25 | 26 | .. image:: https://raw.githubusercontent.com/Mint-System/Wiki/master/assets/mint-system-logo.png 27 | :target: https://www.mint-system.ch 28 | 29 | This module is maintained by Mint System GmbH. 30 | 31 | For support and more information, please visit `our Website `__. 32 | -------------------------------------------------------------------------------- /auth_impersonate_user/__init__.py: -------------------------------------------------------------------------------- 1 | from . import controllers, models 2 | -------------------------------------------------------------------------------- /auth_impersonate_user/__manifest__.py: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Auth Impersonate User", 3 | "summary": """ 4 | Impersonate another users. 5 | """, 6 | "author": "Mint System GmbH", 7 | "website": "https://www.mint-system.ch/", 8 | "category": "Technical", 9 | "version": "16.0.1.1.1", 10 | "license": "AGPL-3", 11 | "depends": ["web"], 12 | "demo": ["demo/res_users.xml"], 13 | "data": ["views/res_users.xml", "security/security.xml"], 14 | "installable": True, 15 | "application": False, 16 | "auto_install": False, 17 | "images": ["images/screen.png"], 18 | } 19 | -------------------------------------------------------------------------------- /auth_impersonate_user/controllers/__init__.py: -------------------------------------------------------------------------------- 1 | from . import main 2 | -------------------------------------------------------------------------------- /auth_impersonate_user/controllers/main.py: -------------------------------------------------------------------------------- 1 | import logging 2 | 3 | from odoo import http 4 | from odoo.http import request 5 | from odoo.service import security 6 | 7 | from odoo.addons.web.controllers.home import Home 8 | 9 | _logger = logging.getLogger(__name__) 10 | 11 | 12 | class ImpersonateHome(Home): 13 | @http.route("/web/impersonate", type="http", auth="user", sitemap=False) 14 | def impersonate_user(self, **kw): 15 | uid = request.env.user.id 16 | if request.env.user.can_impersonate_user: 17 | _logger.info("User <%s> impersonates user <%s>.", uid, int(request.params["uid"])) 18 | 19 | # Backup original session info 20 | request.session.impersonator_uid = request.session.uid 21 | request.session.impersonator_login = request.session.login 22 | 23 | # Set new session info 24 | uid = request.session.uid = int(request.params["uid"]) 25 | request.env["res.users"].clear_caches() 26 | request.session.session_token = security.compute_session_token(request.session, request.env) 27 | 28 | return request.redirect(self._login_redirect(uid)) 29 | 30 | @http.route("/web/session/logout", type="http", auth="none") 31 | def logout(self, redirect="/web"): 32 | # Exit impersonation first 33 | if request.session.impersonator_uid: 34 | _logger.info( 35 | "User <%s> exits impersonation of user <%s>.", 36 | request.session.impersonator_uid, 37 | request.session.uid, 38 | ) 39 | 40 | # Restore session info 41 | request.session.uid = request.session.impersonator_uid 42 | request.session.login = request.session.impersonator_login 43 | del request.session["impersonator_uid"] 44 | del request.session["impersonator_login"] 45 | request.env["res.users"].clear_caches() 46 | request.session.session_token = security.compute_session_token(request.session, request.env) 47 | 48 | return request.redirect(self._login_redirect(request.session.uid)) 49 | 50 | request.session.logout(keep_db=True) 51 | return request.redirect(redirect, 303) 52 | -------------------------------------------------------------------------------- /auth_impersonate_user/demo/res_users.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 9 | 10 | 11 | 12 | 13 | 14 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /auth_impersonate_user/i18n/de.po: -------------------------------------------------------------------------------- 1 | # Translation of Odoo Server. 2 | # This file contains the translation of the following modules: 3 | # * auth_impersonate_user 4 | # 5 | msgid "" 6 | msgstr "" 7 | "Project-Id-Version: Odoo Server 16.0+e\n" 8 | "Report-Msgid-Bugs-To: \n" 9 | "POT-Creation-Date: 2023-11-03 07:54+0000\n" 10 | "PO-Revision-Date: 2023-11-03 07:54+0000\n" 11 | "Last-Translator: \n" 12 | "Language-Team: \n" 13 | "MIME-Version: 1.0\n" 14 | "Content-Type: text/plain; charset=UTF-8\n" 15 | "Content-Transfer-Encoding: \n" 16 | "Plural-Forms: \n" 17 | 18 | #. module: auth_impersonate_user 19 | #: model:ir.model.fields,field_description:auth_impersonate_user.field_res_users__can_be_impersonated 20 | msgid "Can Be Impersonated" 21 | msgstr "" 22 | 23 | #. module: auth_impersonate_user 24 | #: model:ir.model.fields,field_description:auth_impersonate_user.field_res_users__can_impersonate_user 25 | msgid "Can Impersonate User" 26 | msgstr "" 27 | 28 | #. module: auth_impersonate_user 29 | #: model:res.groups,name:auth_impersonate_user.impersonate_user_group 30 | msgid "Can be impersonated" 31 | msgstr "Kann impersoniert werden" 32 | 33 | #. module: auth_impersonate_user 34 | #: model:res.groups,name:auth_impersonate_user.impersonate_admin_group 35 | msgid "Can impersonate user" 36 | msgstr "Kann Benutzer impersonieren" 37 | 38 | #. module: auth_impersonate_user 39 | #: model_terms:ir.ui.view,arch_db:auth_impersonate_user.view_users_form 40 | #: model_terms:ir.ui.view,arch_db:auth_impersonate_user.view_users_tree 41 | msgid "Impersonate" 42 | msgstr "Mit Benutzer einloggen" 43 | 44 | #. module: auth_impersonate_user 45 | #: model:ir.model,name:auth_impersonate_user.model_res_users 46 | msgid "User" 47 | msgstr "" 48 | -------------------------------------------------------------------------------- /auth_impersonate_user/images/screen.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mint-System/Odoo-Apps-Server-Tools/35647358e84a842ae110cc11983611124c0fd39a/auth_impersonate_user/images/screen.png -------------------------------------------------------------------------------- /auth_impersonate_user/models/__init__.py: -------------------------------------------------------------------------------- 1 | from . import res_users 2 | -------------------------------------------------------------------------------- /auth_impersonate_user/models/res_users.py: -------------------------------------------------------------------------------- 1 | import logging 2 | 3 | from odoo import fields, models 4 | 5 | _logger = logging.getLogger(__name__) 6 | 7 | 8 | class ResUsers(models.Model): 9 | _inherit = "res.users" 10 | 11 | can_be_impersonated = fields.Boolean(compute="_compute_can_be_impersonated") 12 | can_impersonate_user = fields.Boolean(compute="_compute_can_impersonate_user") 13 | 14 | def _compute_can_impersonate_user(self): 15 | for user in self: 16 | user.can_impersonate_user = self.env.user.has_group("auth_impersonate_user.impersonate_admin_group") 17 | 18 | def _compute_can_be_impersonated(self): 19 | for user in self: 20 | user.can_be_impersonated = ( 21 | user.has_group("auth_impersonate_user.impersonate_user_group") if self.env.user != user else False 22 | ) 23 | 24 | def impersonate_user(self): 25 | self.ensure_one() 26 | if self.env.user.can_impersonate_user and self.can_be_impersonated: 27 | self._update_last_login() 28 | return { 29 | "type": "ir.actions.act_url", 30 | "target": "self", 31 | "url": f"/web/impersonate?uid={self.id}", 32 | } 33 | -------------------------------------------------------------------------------- /auth_impersonate_user/pyproject.toml: -------------------------------------------------------------------------------- 1 | [build-system] 2 | requires = ["whool"] 3 | build-backend = "whool.buildapi" 4 | -------------------------------------------------------------------------------- /auth_impersonate_user/security/security.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Can be impersonated 6 | 7 | 8 | 9 | 10 | Can impersonate user 11 | 12 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /auth_impersonate_user/static/description/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mint-System/Odoo-Apps-Server-Tools/35647358e84a842ae110cc11983611124c0fd39a/auth_impersonate_user/static/description/icon.png -------------------------------------------------------------------------------- /auth_impersonate_user/views/res_users.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | auth_impersonate_user.view_users_tree 5 | res.users 6 | 7 | 8 | 9 | 10 | 11 |