diff --git a/odoo_project/README.rst b/odoo_project/README.rst new file mode 100644 index 00000000..9b967099 --- /dev/null +++ b/odoo_project/README.rst @@ -0,0 +1,94 @@ +.. image:: https://odoo-community.org/readme-banner-image + :target: https://odoo-community.org/get-involved?utm_source=readme + :alt: Odoo Community Association + +============ +Odoo Project +============ + +.. + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! This file is generated by oca-gen-addon-readme !! + !! changes will be overwritten. !! + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! source digest: sha256:3331542182c08aa9be85d1710d7fea6e5eb548ce72a9634c889bee41d66da216 + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + +.. |badge1| image:: https://img.shields.io/badge/maturity-Beta-yellow.png + :target: https://odoo-community.org/page/development-status + :alt: Beta +.. |badge2| image:: https://img.shields.io/badge/license-AGPL--3-blue.png + :target: http://www.gnu.org/licenses/agpl-3.0-standalone.html + :alt: License: AGPL-3 +.. |badge3| image:: https://img.shields.io/badge/github-OCA%2Fmodule--composition--analysis-lightgray.png?logo=github + :target: https://github.com/OCA/module-composition-analysis/tree/18.0/odoo_project + :alt: OCA/module-composition-analysis +.. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png + :target: https://translation.odoo-community.org/projects/module-composition-analysis-18-0/module-composition-analysis-18-0-odoo_project + :alt: Translate me on Weblate +.. |badge5| image:: https://img.shields.io/badge/runboat-Try%20me-875A7B.png + :target: https://runboat.odoo-community.org/builds?repo=OCA/module-composition-analysis&target_branch=18.0 + :alt: Try me on Runboat + +|badge1| |badge2| |badge3| |badge4| |badge5| + +This module allows you to declare your Odoo projects with the list of +installed modules. + +Based on the data collected by ``odoo_repository`` module, it will: + +- give some code stats (lines of code, and how they are spread among + Odoo/OCA/your organization) +- give the list of modules available for upgrade in current Odoo version + (based on module versions) +- list modules still hosted in a pending Pull Request (so not yet + merged, could be considered as technical debt) +- list modules available in your project repository (if any) but not + installed in your database (dead code) + +**Table of contents** + +.. contents:: + :local: + +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 +`feedback `_. + +Do not contact contributors directly about support or help with technical issues. + +Credits +======= + +Authors +------- + +* Camptocamp + +Contributors +------------ + +- Camptocamp + + - Sébastien Alix + +Maintainers +----------- + +This module is maintained by the OCA. + +.. image:: https://odoo-community.org/logo.png + :alt: Odoo Community Association + :target: https://odoo-community.org + +OCA, or the Odoo Community Association, is a nonprofit organization whose +mission is to support the collaborative development of Odoo features and +promote its widespread use. + +This module is part of the `OCA/module-composition-analysis `_ project on GitHub. + +You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute. diff --git a/odoo_project/__init__.py b/odoo_project/__init__.py new file mode 100644 index 00000000..aee8895e --- /dev/null +++ b/odoo_project/__init__.py @@ -0,0 +1,2 @@ +from . import models +from . import wizards diff --git a/odoo_project/__manifest__.py b/odoo_project/__manifest__.py new file mode 100644 index 00000000..eee01808 --- /dev/null +++ b/odoo_project/__manifest__.py @@ -0,0 +1,24 @@ +# Copyright 2023 Camptocamp SA +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl) +{ + "name": "Odoo Project", + "summary": "Analyze your Odoo projects code bases.", + "version": "18.0.1.0.0", + "category": "Tools", + "author": "Camptocamp, Odoo Community Association (OCA)", + "website": "https://github.com/OCA/module-composition-analysis", + "data": [ + "security/ir.model.access.csv", + "views/menu.xml", + "views/odoo_module_branch.xml", + "views/odoo_project.xml", + "views/odoo_project_module.xml", + "views/odoo_repository.xml", + "wizards/odoo_project_import_modules.xml", + ], + "installable": True, + "depends": [ + "odoo_repository", + ], + "license": "AGPL-3", +} diff --git a/odoo_project/data/queue_job.xml b/odoo_project/data/queue_job.xml new file mode 100644 index 00000000..921e430c --- /dev/null +++ b/odoo_project/data/queue_job.xml @@ -0,0 +1,14 @@ + + + + + + _remap_to_specific_module + + + + diff --git a/odoo_project/i18n/it.po b/odoo_project/i18n/it.po new file mode 100644 index 00000000..c7af44b5 --- /dev/null +++ b/odoo_project/i18n/it.po @@ -0,0 +1,784 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * odoo_project +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 16.0\n" +"Report-Msgid-Bugs-To: \n" +"Last-Translator: Automatically generated\n" +"Language-Team: none\n" +"Language: it\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" + +#. module: odoo_project +#: model_terms:ir.ui.view,arch_db:odoo_project.odoo_project_import_modules_view_form +msgid "" +"# One module per line with an optional version number (separated by any special character like space, tabulation, comma...). E.g:\n" +"sale\n" +"server_environment 17.0.1.1.0" +msgstr "" + +#. module: odoo_project +#: model_terms:ir.ui.view,arch_db:odoo_project.odoo_project_view_form +msgid " Modules inst." +msgstr "" + +#. module: odoo_project +#: model:ir.model.fields,field_description:odoo_project.field_odoo_project__message_needaction +msgid "Action Needed" +msgstr "" + +#. module: odoo_project +#: model:ir.model.fields,field_description:odoo_project.field_odoo_project__active +msgid "Active" +msgstr "" + +#. module: odoo_project +#: model:ir.model.fields,field_description:odoo_project.field_odoo_project_import_modules__additional_module_ids +msgid "Additional Modules" +msgstr "" + +#. module: odoo_project +#: model_terms:ir.ui.view,arch_db:odoo_project.odoo_project_import_modules_view_form +msgid "Additional modules" +msgstr "" + +#. module: odoo_project +#: model:ir.model.fields,field_description:odoo_project.field_odoo_project_module__addons_path +msgid "Addons Path" +msgstr "" + +#. module: odoo_project +#: model:ir.model.fields,help:odoo_project.field_odoo_project_module__branch_name +msgid "" +"An Odoo version is also used as an Odoo branch name in generic repositories " +"(Odoo, OCA...)." +msgstr "" + +#. module: odoo_project +#: model:ir.model.fields,field_description:odoo_project.field_odoo_project_module__application +msgid "Application" +msgstr "" + +#. module: odoo_project +#: model:ir.model.fields,field_description:odoo_project.field_odoo_project__message_attachment_count +msgid "Attachment Count" +msgstr "" + +#. module: odoo_project +#: model:ir.model.fields,field_description:odoo_project.field_odoo_project_module__author_ids +msgid "Authors" +msgstr "" + +#. module: odoo_project +#: model:ir.model.fields,field_description:odoo_project.field_odoo_project_module__auto_install +msgid "Auto-Install" +msgstr "" + +#. module: odoo_project +#: model:ir.model.fields,field_description:odoo_project.field_odoo_project__available_odoo_version_ids +msgid "Available Odoo Versions" +msgstr "" + +#. module: odoo_project +#: model:ir.model.fields,help:odoo_project.field_odoo_project_module__migration_scripts +msgid "Available migration scripts between installed and last version." +msgstr "" + +#. module: odoo_project +#: model:ir.model.fields,field_description:odoo_project.field_odoo_project_module__branch_name +msgid "Branch Name" +msgstr "" + +#. module: odoo_project +#: model:ir.model.fields,field_description:odoo_project.field_odoo_project_module__branch_sequence +msgid "Branch Sequence" +msgstr "" + +#. module: odoo_project +#: model_terms:ir.ui.view,arch_db:odoo_project.odoo_project_import_modules_view_form +msgid "" +"Build your project by adding modules. This can help to get some figures " +"before a launch to estimate maintenance cost for instance." +msgstr "" + +#. module: odoo_project +#: model:ir.model.fields,field_description:odoo_project.field_odoo_project_module__sloc_css +msgid "CSS" +msgstr "" + +#. module: odoo_project +#: model:ir.model.fields,help:odoo_project.field_odoo_project_module__sloc_css +msgid "CSS source lines of code" +msgstr "" + +#. module: odoo_project +#: model_terms:ir.ui.view,arch_db:odoo_project.odoo_project_import_modules_view_form +msgid "Cancel" +msgstr "" + +#. module: odoo_project +#: model:ir.model.fields,field_description:odoo_project.field_odoo_project_module__category_id +msgid "Category" +msgstr "" + +#. module: odoo_project +#: model:ir.model.fields,field_description:odoo_project.field_odoo_project_module__is_community +msgid "Community?" +msgstr "" + +#. module: odoo_project +#: model:ir.model.fields,help:odoo_project.field_odoo_project_import_modules__modules_list +msgid "" +"Copy/paste your list of technical module names here.\n" +"One module per line with an optional version number (separated by any special character (space, tabulation, comma...)." +msgstr "" + +#. module: odoo_project +#: model:ir.model.fields,field_description:odoo_project.field_odoo_project__create_uid +#: model:ir.model.fields,field_description:odoo_project.field_odoo_project_import_modules__create_uid +#: model:ir.model.fields,field_description:odoo_project.field_odoo_project_module__create_uid +msgid "Created by" +msgstr "" + +#. module: odoo_project +#: model:ir.model.fields,field_description:odoo_project.field_odoo_project__create_date +#: model:ir.model.fields,field_description:odoo_project.field_odoo_project_import_modules__create_date +#: model:ir.model.fields,field_description:odoo_project.field_odoo_project_module__create_date +msgid "Created on" +msgstr "" + +#. module: odoo_project +#: model:ir.actions.act_window,name:odoo_project.odoo_project_module_action_recursive_dependencies +#: model:ir.model.fields,field_description:odoo_project.field_odoo_project_module__dependency_ids +msgid "Dependencies" +msgstr "" + +#. module: odoo_project +#: model:ir.model.fields,help:odoo_project.field_odoo_project_module__non_std_dependency_level +msgid "Dependency level excluding all standard Odoo modules." +msgstr "" + +#. module: odoo_project +#: model:ir.model.fields,help:odoo_project.field_odoo_project_module__global_dependency_level +msgid "Dependency level including all standard Odoo modules." +msgstr "" + +#. module: odoo_project +#: model:ir.model.fields,field_description:odoo_project.field_odoo_module_branch__odoo_project_module_ids +#: model:ir.model.fields,field_description:odoo_project.field_odoo_project__project_module_ids +#: model:ir.model.fields,field_description:odoo_project.field_odoo_project_module__odoo_project_module_ids +msgid "Deployed Modules" +msgstr "" + +#. module: odoo_project +#: model:ir.model.fields,help:odoo_project.field_odoo_project_module__title +msgid "Descriptive name" +msgstr "" + +#. module: odoo_project +#: model:ir.model.fields,field_description:odoo_project.field_odoo_project_module__development_status_id +msgid "Develoment Status" +msgstr "" + +#. module: odoo_project +#: model:ir.model.fields,field_description:odoo_project.field_odoo_project__display_name +#: model:ir.model.fields,field_description:odoo_project.field_odoo_project_import_modules__display_name +#: model:ir.model.fields,field_description:odoo_project.field_odoo_project_module__display_name +msgid "Display Name" +msgstr "" + +#. module: odoo_project +#: model:ir.model.fields,field_description:odoo_project.field_odoo_project_module__is_enterprise +msgid "Enterprise?" +msgstr "" + +#. module: odoo_project +#: model:ir.model.fields,field_description:odoo_project.field_odoo_project_module__external_dependencies +msgid "External Dependencies" +msgstr "" + +#. module: odoo_project +#: model_terms:ir.ui.view,arch_db:odoo_project.odoo_project_view_form +msgid "Find modules" +msgstr "" + +#. module: odoo_project +#: model:ir.model.fields,field_description:odoo_project.field_odoo_project__message_follower_ids +msgid "Followers" +msgstr "" + +#. module: odoo_project +#: model:ir.model.fields,field_description:odoo_project.field_odoo_project__message_partner_ids +msgid "Followers (Partners)" +msgstr "" + +#. module: odoo_project +#: model:ir.model.fields,field_description:odoo_project.field_odoo_project_module__full_path +msgid "Full Path" +msgstr "" + +#. module: odoo_project +#: model:ir.model.fields,field_description:odoo_project.field_odoo_project_module__global_dependency_level +msgid "Global Dep. Level" +msgstr "" + +#. module: odoo_project +#: model_terms:ir.ui.view,arch_db:odoo_project.odoo_project_view_search +msgid "Group By" +msgstr "" + +#. module: odoo_project +#: model:ir.model.fields,field_description:odoo_project.field_odoo_project__has_message +msgid "Has Message" +msgstr "" + +#. module: odoo_project +#: model:ir.model.fields,field_description:odoo_project.field_odoo_project__id +#: model:ir.model.fields,field_description:odoo_project.field_odoo_project_import_modules__id +#: model:ir.model.fields,field_description:odoo_project.field_odoo_project_module__id +msgid "ID" +msgstr "" + +#. module: odoo_project +#: model:ir.model.fields,help:odoo_project.field_odoo_project__message_needaction +msgid "If checked, new messages require your attention." +msgstr "" + +#. module: odoo_project +#: model:ir.model.fields,help:odoo_project.field_odoo_project__message_has_error +msgid "If checked, some messages have a delivery error." +msgstr "" + +#. module: odoo_project +#: model:ir.model.fields,help:odoo_project.field_odoo_project_module__installed_version_id +msgid "" +"If the real installed version is not available in the history of versions " +"(could come from a pending merge not scanned), this field computes the " +"nearest version available." +msgstr "" + +#. module: odoo_project +#: model_terms:ir.ui.view,arch_db:odoo_project.odoo_project_import_modules_view_form +msgid "Import" +msgstr "" + +#. module: odoo_project +#: model:ir.model.fields,field_description:odoo_project.field_odoo_project_import_modules__import_missing_dependencies +msgid "Import Missing Dependencies" +msgstr "" + +#. module: odoo_project +#: model:ir.actions.act_window,name:odoo_project.odoo_project_import_modules_action +msgid "Import Project Modules" +msgstr "" + +#. module: odoo_project +#: model:ir.model.fields,help:odoo_project.field_odoo_project_import_modules__import_missing_dependencies +msgid "" +"Import module dependencies that are not part of the list above to get an " +"exhaustive list of modules installed in the project." +msgstr "" + +#. module: odoo_project +#: model_terms:ir.ui.view,arch_db:odoo_project.odoo_project_view_form +msgid "Import modules" +msgstr "" + +#. module: odoo_project +#: model:ir.model,name:odoo_project.model_odoo_project_import_modules +msgid "Import modules for an Odoo project" +msgstr "" + +#. module: odoo_project +#: model_terms:ir.ui.view,arch_db:odoo_project.odoo_project_import_modules_view_form +msgid "Initialize from modules list" +msgstr "" + +#. module: odoo_project +#: model_terms:ir.ui.view,arch_db:odoo_project.odoo_project_import_modules_view_form +msgid "" +"Initialize the list of modules that are installed in your project. This will" +" wipe the current installed modules.
The list can be copied-pasted from " +"columns 'Technical Name' and 'Latest Version' put side by side from a " +"standard Odoo export of modules installed." +msgstr "" + +#. module: odoo_project +#: model:ir.model.fields,field_description:odoo_project.field_odoo_project_module__installable +msgid "Installable" +msgstr "" + +#. module: odoo_project +#: model:ir.actions.act_window,name:odoo_project.odoo_project_module_action +#: model:ir.actions.act_window,name:odoo_project.odoo_project_module_for_project_action +#: model:ir.ui.menu,name:odoo_project.odoo_project_module_menu +msgid "Installed Modules" +msgstr "" + +#. module: odoo_project +#: model:ir.model.fields,field_description:odoo_project.field_odoo_project_module__installed_reverse_dependency_ids +msgid "Installed Reverse Dependencies" +msgstr "" + +#. module: odoo_project +#: model:ir.model.fields,field_description:odoo_project.field_odoo_project_module__installed_version +msgid "Installed Version" +msgstr "" + +#. module: odoo_project +#: model_terms:ir.ui.view,arch_db:odoo_project.odoo_project_module_view_tree +msgid "Installed in" +msgstr "" + +#. module: odoo_project +#: model_terms:ir.ui.view,arch_db:odoo_project.odoo_module_branch_view_search +msgid "Installed in projects" +msgstr "" + +#. module: odoo_project +#: model_terms:ir.ui.view,arch_db:odoo_project.odoo_project_module_view_form +msgid "Installed reverse dependencies" +msgstr "" + +#. module: odoo_project +#: model:ir.model.fields,help:odoo_project.field_odoo_project_module__installed_version +msgid "Installed version in project database." +msgstr "" + +#. module: odoo_project +#: model:ir.model.fields,field_description:odoo_project.field_odoo_project__message_is_follower +msgid "Is Follower" +msgstr "" + +#. module: odoo_project +#: model:ir.model.fields,help:odoo_project.field_odoo_project_module__is_community +msgid "Is this module a contribution of the community?" +msgstr "" + +#. module: odoo_project +#: model:ir.model.fields,help:odoo_project.field_odoo_project_module__is_enterprise +msgid "Is this module designed for Odoo Enterprise only?" +msgstr "" + +#. module: odoo_project +#: model:ir.model.fields,help:odoo_project.field_odoo_project_module__is_standard +msgid "Is this module part of Odoo standard?" +msgstr "" + +#. module: odoo_project +#: model:ir.model.fields,field_description:odoo_project.field_odoo_project_module__sloc_js +msgid "JS" +msgstr "" + +#. module: odoo_project +#: model:ir.model.fields,help:odoo_project.field_odoo_project_module__sloc_js +msgid "JavaScript source lines of code" +msgstr "" + +#. module: odoo_project +#: model:ir.model.fields,field_description:odoo_project.field_odoo_project____last_update +#: model:ir.model.fields,field_description:odoo_project.field_odoo_project_import_modules____last_update +#: model:ir.model.fields,field_description:odoo_project.field_odoo_project_module____last_update +msgid "Last Modified on" +msgstr "" + +#. module: odoo_project +#: model:ir.model.fields,field_description:odoo_project.field_odoo_project_module__last_scanned_commit +msgid "Last Scanned Commit" +msgstr "" + +#. module: odoo_project +#: model:ir.model.fields,field_description:odoo_project.field_odoo_project__write_uid +#: model:ir.model.fields,field_description:odoo_project.field_odoo_project_import_modules__write_uid +#: model:ir.model.fields,field_description:odoo_project.field_odoo_project_module__write_uid +msgid "Last Updated by" +msgstr "" + +#. module: odoo_project +#: model:ir.model.fields,field_description:odoo_project.field_odoo_project__write_date +#: model:ir.model.fields,field_description:odoo_project.field_odoo_project_import_modules__write_date +#: model:ir.model.fields,field_description:odoo_project.field_odoo_project_module__write_date +msgid "Last Updated on" +msgstr "" + +#. module: odoo_project +#: model_terms:ir.ui.view,arch_db:odoo_project.odoo_project_module_view_form +#: model_terms:ir.ui.view,arch_db:odoo_project.odoo_project_module_view_tree +msgid "Last Version" +msgstr "" + +#. module: odoo_project +#: model:ir.model.fields,field_description:odoo_project.field_odoo_project_module__version +msgid "Last version" +msgstr "" + +#. module: odoo_project +#: model:ir.model.fields,field_description:odoo_project.field_odoo_project_module__license_id +msgid "License" +msgstr "" + +#. module: odoo_project +#: model:ir.model.fields,field_description:odoo_project.field_odoo_project__message_main_attachment_id +msgid "Main Attachment" +msgstr "" + +#. module: odoo_project +#: model:ir.model.fields,field_description:odoo_project.field_odoo_project_module__maintainer_ids +msgid "Maintainers" +msgstr "" + +#. module: odoo_project +#: model:ir.model.fields,field_description:odoo_project.field_odoo_project__message_has_error +msgid "Message Delivery error" +msgstr "" + +#. module: odoo_project +#: model:ir.model.fields,field_description:odoo_project.field_odoo_project__message_ids +msgid "Messages" +msgstr "" + +#. module: odoo_project +#: model:ir.model.fields,field_description:odoo_project.field_odoo_project_module__migration_scripts +msgid "Migration Scripts" +msgstr "" + +#. module: odoo_project +#: model_terms:ir.ui.view,arch_db:odoo_project.odoo_project_module_view_search +msgid "Migration Scripts to play" +msgstr "" + +#. module: odoo_project +#: model_terms:ir.ui.view,arch_db:odoo_project.odoo_project_view_search +msgid "Module" +msgstr "" + +#. module: odoo_project +#: model:ir.model.fields,field_description:odoo_project.field_odoo_project_module__module_name +msgid "Module Technical Name" +msgstr "" + +#. module: odoo_project +#: model:ir.model.fields,help:odoo_project.field_odoo_project_module__specific +msgid "" +"Module specific to a project repository.It cannot be used across different " +"projects." +msgstr "" + +#. module: odoo_project +#: model:ir.model.fields,field_description:odoo_project.field_odoo_project__module_ids +#: model_terms:ir.ui.view,arch_db:odoo_project.odoo_project_view_form +msgid "Modules" +msgstr "" + +#. module: odoo_project +#: model:ir.model.fields,field_description:odoo_project.field_odoo_project__modules_count +msgid "Modules Count" +msgstr "" + +#. module: odoo_project +#: model:ir.model.fields,field_description:odoo_project.field_odoo_project_import_modules__modules_list +msgid "Modules List" +msgstr "" + +#. module: odoo_project +#: model:ir.model.fields,help:odoo_project.field_odoo_project__module_not_installed_ids +msgid "Modules available in the project repository but not installed." +msgstr "" + +#. module: odoo_project +#: model:ir.model.fields,help:odoo_project.field_odoo_project__unmerged_module_ids +msgid "Modules installed belonging to an open PR." +msgstr "" + +#. module: odoo_project +#: model:ir.model.fields,help:odoo_project.field_odoo_project__unknown_module_ids +msgid "Modules installed but cannot be found among repositories/branches." +msgstr "" + +#. module: odoo_project +#: model:ir.model.fields,field_description:odoo_project.field_odoo_project__module_not_installed_ids +#: model_terms:ir.ui.view,arch_db:odoo_project.odoo_project_view_form +msgid "Modules not installed" +msgstr "" + +#. module: odoo_project +#: model:ir.model.fields,field_description:odoo_project.field_odoo_project__unmerged_module_ids +#: model_terms:ir.ui.view,arch_db:odoo_project.odoo_project_view_form +msgid "Modules to merge" +msgstr "" + +#. module: odoo_project +#: model:ir.model.fields,field_description:odoo_project.field_odoo_project__unknown_module_ids +msgid "Modules unknown" +msgstr "" + +#. module: odoo_project +#: model:ir.model.fields,field_description:odoo_project.field_odoo_project__name +msgid "Name" +msgstr "" + +#. module: odoo_project +#: model:ir.model.fields,field_description:odoo_project.field_odoo_project_module__installed_version_id +msgid "Nearest installed version" +msgstr "" + +#. module: odoo_project +#: model_terms:ir.ui.view,arch_db:odoo_project.odoo_module_branch_view_search +msgid "No project" +msgstr "" + +#. module: odoo_project +#: model:ir.model.fields,field_description:odoo_project.field_odoo_project_module__non_std_dependency_level +msgid "Non-Std Dep. Level" +msgstr "" + +#. module: odoo_project +#: model:ir.model.fields,field_description:odoo_project.field_odoo_project_module__not_installed_reverse_dependency_ids +msgid "Not Installed Reverse Dependencies" +msgstr "" + +#. module: odoo_project +#: model_terms:ir.ui.view,arch_db:odoo_project.odoo_project_module_view_form +msgid "Not installed reverse dependencies" +msgstr "" + +#. module: odoo_project +#: model:ir.model.fields,field_description:odoo_project.field_odoo_project__message_needaction_counter +msgid "Number of Actions" +msgstr "" + +#. module: odoo_project +#: model:ir.model.fields,field_description:odoo_project.field_odoo_project__message_has_error_counter +msgid "Number of errors" +msgstr "" + +#. module: odoo_project +#: model:ir.model.fields,help:odoo_project.field_odoo_project__message_needaction_counter +msgid "Number of messages requiring action" +msgstr "" + +#. module: odoo_project +#: model:ir.model.fields,help:odoo_project.field_odoo_project__message_has_error_counter +msgid "Number of messages with delivery error" +msgstr "" + +#. module: odoo_project +#: model:ir.model,name:odoo_project.model_odoo_module_branch +msgid "Odoo Module Branch" +msgstr "" + +#. module: odoo_project +#: model:ir.model,name:odoo_project.model_odoo_repository +msgid "Odoo Modules Repository" +msgstr "" + +#. module: odoo_project +#: model:ir.model,name:odoo_project.model_odoo_project +msgid "Odoo Project" +msgstr "" + +#. module: odoo_project +#: model:ir.model,name:odoo_project.model_odoo_project_module +msgid "Odoo Project Module" +msgstr "" + +#. module: odoo_project +#: model:ir.model.fields,field_description:odoo_project.field_odoo_project__odoo_version_id +#: model:ir.model.fields,field_description:odoo_project.field_odoo_project_import_modules__odoo_version_id +#: model:ir.model.fields,field_description:odoo_project.field_odoo_project_module__branch_id +#: model_terms:ir.ui.view,arch_db:odoo_project.odoo_project_view_search +msgid "Odoo Version" +msgstr "" + +#. module: odoo_project +#: model:ir.model.fields,field_description:odoo_project.field_odoo_project_module__org_id +msgid "Organization" +msgstr "" + +#. module: odoo_project +#: model:ir.model.fields,field_description:odoo_project.field_odoo_project_module__pr_url +msgid "PR URL" +msgstr "" + +#. module: odoo_project +#: model:ir.model.fields,field_description:odoo_project.field_odoo_project_import_modules__odoo_project_id +#: model:ir.model.fields,field_description:odoo_project.field_odoo_project_module__odoo_project_id +#: model_terms:ir.ui.view,arch_db:odoo_project.odoo_module_branch_view_search +msgid "Project" +msgstr "" + +#. module: odoo_project +#: model:ir.model.fields,field_description:odoo_project.field_odoo_repository__project_count +msgid "Project Count" +msgstr "" + +#. module: odoo_project +#: model_terms:ir.ui.view,arch_db:odoo_project.odoo_project_view_form +msgid "Project Name" +msgstr "" + +#. module: odoo_project +#: model:ir.actions.act_window,name:odoo_project.odoo_project_action +#: model:ir.model.fields,field_description:odoo_project.field_odoo_module_branch__odoo_project_ids +#: model:ir.model.fields,field_description:odoo_project.field_odoo_project_module__odoo_project_ids +#: model:ir.model.fields,field_description:odoo_project.field_odoo_repository__project_ids +#: model:ir.ui.menu,name:odoo_project.odoo_project_main_menu +#: model:ir.ui.menu,name:odoo_project.odoo_project_menu +#: model_terms:ir.ui.view,arch_db:odoo_project.odoo_module_branch_view_form +#: model_terms:ir.ui.view,arch_db:odoo_project.odoo_repository_view_form +msgid "Projects" +msgstr "" + +#. module: odoo_project +#: model:ir.model.fields,field_description:odoo_project.field_odoo_project_module__sloc_python +msgid "Python" +msgstr "" + +#. module: odoo_project +#: model:ir.model.fields,field_description:odoo_project.field_odoo_project_module__python_dependency_ids +msgid "Python Dependencies" +msgstr "" + +#. module: odoo_project +#: model:ir.model.fields,help:odoo_project.field_odoo_project_module__sloc_python +msgid "Python source lines of code" +msgstr "" + +#. module: odoo_project +#: model:ir.model.fields,field_description:odoo_project.field_odoo_project_module__removed +msgid "Removed" +msgstr "" + +#. module: odoo_project +#: model:ir.model.fields,field_description:odoo_project.field_odoo_project__repository_id +#: model:ir.model.fields,field_description:odoo_project.field_odoo_project_module__repository_id +msgid "Repository" +msgstr "" + +#. module: odoo_project +#: model:ir.model.fields,field_description:odoo_project.field_odoo_project__repository_branch_id +msgid "Repository / Branch" +msgstr "" + +#. module: odoo_project +#: model:ir.model.fields,field_description:odoo_project.field_odoo_project_module__repository_branch_id +msgid "Repository Branch" +msgstr "" + +#. module: odoo_project +#: model:ir.model.fields,help:odoo_project.field_odoo_project__repository_id +msgid "" +"Repository this project is based on (optional). You can start to " +"build/simulate a project without repository to get some figures." +msgstr "" + +#. module: odoo_project +#: model:ir.model.fields,field_description:odoo_project.field_odoo_project_module__reverse_dependency_ids +msgid "Reverse Dependencies" +msgstr "" + +#. module: odoo_project +#: model_terms:ir.ui.view,arch_db:odoo_project.odoo_project_view_form +msgid "Scan" +msgstr "" + +#. module: odoo_project +#: model_terms:ir.ui.view,arch_db:odoo_project.odoo_project_view_form +msgid "Scan all the repositories used by this project." +msgstr "" + +#. module: odoo_project +#: model:ir.model.fields,field_description:odoo_project.field_odoo_project_module__repository_sequence +msgid "Sequence" +msgstr "" + +#. module: odoo_project +#: model:ir.model.fields,field_description:odoo_project.field_odoo_project_module__specific +msgid "Specific" +msgstr "" + +#. module: odoo_project +#: model:ir.model.fields,field_description:odoo_project.field_odoo_project_module__is_standard +msgid "Standard?" +msgstr "" + +#. module: odoo_project +#: model_terms:ir.ui.view,arch_db:odoo_project.odoo_project_view_form +msgid "Status" +msgstr "" + +#. module: odoo_project +#: model:ir.model.fields,field_description:odoo_project.field_odoo_project_module__summary +msgid "Summary" +msgstr "" + +#. module: odoo_project +#: model:ir.model.fields,field_description:odoo_project.field_odoo_project_module__name +msgid "Techname" +msgstr "" + +#. module: odoo_project +#: model:ir.model.fields,help:odoo_project.field_odoo_project_module__module_name +msgid "Technical Name" +msgstr "" + +#. module: odoo_project +#: model:ir.model.fields,help:odoo_project.field_odoo_project_module__addons_path +msgid "Technical field. Where the module is located in the repository." +msgstr "" + +#. module: odoo_project +#: model:ir.model.fields,field_description:odoo_project.field_odoo_project_module__module_id +msgid "Technical name" +msgstr "" + +#. module: odoo_project +#: model:ir.model.constraint,message:odoo_project.constraint_odoo_project_name_uniq +msgid "This project already exists." +msgstr "" + +#. module: odoo_project +#: model:ir.model.fields,field_description:odoo_project.field_odoo_project_module__title +msgid "Title" +msgstr "" + +#. module: odoo_project +#: model:ir.model.fields,field_description:odoo_project.field_odoo_project_module__to_upgrade +#: model_terms:ir.ui.view,arch_db:odoo_project.odoo_project_module_view_search +msgid "To Upgrade" +msgstr "" + +#. module: odoo_project +#: model:ir.model.fields,field_description:odoo_project.field_odoo_project_module__url +msgid "URL" +msgstr "" + +#. module: odoo_project +#: model_terms:ir.ui.view,arch_db:odoo_project.odoo_project_view_form +msgid "Unknown modules" +msgstr "" + +#. module: odoo_project +#: model:ir.model.fields,field_description:odoo_project.field_odoo_project_module__module_branch_id +msgid "Upstream Module" +msgstr "" + +#. module: odoo_project +#: model:ir.model.fields,field_description:odoo_project.field_odoo_project_module__version_ids +msgid "Versions" +msgstr "" + +#. module: odoo_project +#: model:ir.model.fields,field_description:odoo_project.field_odoo_project_module__sloc_xml +msgid "XML" +msgstr "" + +#. module: odoo_project +#: model:ir.model.fields,help:odoo_project.field_odoo_project_module__sloc_xml +msgid "XML source lines of code" +msgstr "" diff --git a/odoo_project/i18n/odoo_project.pot b/odoo_project/i18n/odoo_project.pot new file mode 100644 index 00000000..170bac0d --- /dev/null +++ b/odoo_project/i18n/odoo_project.pot @@ -0,0 +1,783 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * odoo_project +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 16.0\n" +"Report-Msgid-Bugs-To: \n" +"Last-Translator: \n" +"Language-Team: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: \n" + +#. module: odoo_project +#: model_terms:ir.ui.view,arch_db:odoo_project.odoo_project_import_modules_view_form +msgid "" +"# One module per line with an optional version number (separated by any special character like space, tabulation, comma...). E.g:\n" +"sale\n" +"server_environment 17.0.1.1.0" +msgstr "" + +#. module: odoo_project +#: model_terms:ir.ui.view,arch_db:odoo_project.odoo_project_view_form +msgid " Modules inst." +msgstr "" + +#. module: odoo_project +#: model:ir.model.fields,field_description:odoo_project.field_odoo_project__message_needaction +msgid "Action Needed" +msgstr "" + +#. module: odoo_project +#: model:ir.model.fields,field_description:odoo_project.field_odoo_project__active +msgid "Active" +msgstr "" + +#. module: odoo_project +#: model:ir.model.fields,field_description:odoo_project.field_odoo_project_import_modules__additional_module_ids +msgid "Additional Modules" +msgstr "" + +#. module: odoo_project +#: model_terms:ir.ui.view,arch_db:odoo_project.odoo_project_import_modules_view_form +msgid "Additional modules" +msgstr "" + +#. module: odoo_project +#: model:ir.model.fields,field_description:odoo_project.field_odoo_project_module__addons_path +msgid "Addons Path" +msgstr "" + +#. module: odoo_project +#: model:ir.model.fields,help:odoo_project.field_odoo_project_module__branch_name +msgid "" +"An Odoo version is also used as an Odoo branch name in generic repositories " +"(Odoo, OCA...)." +msgstr "" + +#. module: odoo_project +#: model:ir.model.fields,field_description:odoo_project.field_odoo_project_module__application +msgid "Application" +msgstr "" + +#. module: odoo_project +#: model:ir.model.fields,field_description:odoo_project.field_odoo_project__message_attachment_count +msgid "Attachment Count" +msgstr "" + +#. module: odoo_project +#: model:ir.model.fields,field_description:odoo_project.field_odoo_project_module__author_ids +msgid "Authors" +msgstr "" + +#. module: odoo_project +#: model:ir.model.fields,field_description:odoo_project.field_odoo_project_module__auto_install +msgid "Auto-Install" +msgstr "" + +#. module: odoo_project +#: model:ir.model.fields,field_description:odoo_project.field_odoo_project__available_odoo_version_ids +msgid "Available Odoo Versions" +msgstr "" + +#. module: odoo_project +#: model:ir.model.fields,help:odoo_project.field_odoo_project_module__migration_scripts +msgid "Available migration scripts between installed and last version." +msgstr "" + +#. module: odoo_project +#: model:ir.model.fields,field_description:odoo_project.field_odoo_project_module__branch_name +msgid "Branch Name" +msgstr "" + +#. module: odoo_project +#: model:ir.model.fields,field_description:odoo_project.field_odoo_project_module__branch_sequence +msgid "Branch Sequence" +msgstr "" + +#. module: odoo_project +#: model_terms:ir.ui.view,arch_db:odoo_project.odoo_project_import_modules_view_form +msgid "" +"Build your project by adding modules. This can help to get some figures " +"before a launch to estimate maintenance cost for instance." +msgstr "" + +#. module: odoo_project +#: model:ir.model.fields,field_description:odoo_project.field_odoo_project_module__sloc_css +msgid "CSS" +msgstr "" + +#. module: odoo_project +#: model:ir.model.fields,help:odoo_project.field_odoo_project_module__sloc_css +msgid "CSS source lines of code" +msgstr "" + +#. module: odoo_project +#: model_terms:ir.ui.view,arch_db:odoo_project.odoo_project_import_modules_view_form +msgid "Cancel" +msgstr "" + +#. module: odoo_project +#: model:ir.model.fields,field_description:odoo_project.field_odoo_project_module__category_id +msgid "Category" +msgstr "" + +#. module: odoo_project +#: model:ir.model.fields,field_description:odoo_project.field_odoo_project_module__is_community +msgid "Community?" +msgstr "" + +#. module: odoo_project +#: model:ir.model.fields,help:odoo_project.field_odoo_project_import_modules__modules_list +msgid "" +"Copy/paste your list of technical module names here.\n" +"One module per line with an optional version number (separated by any special character (space, tabulation, comma...)." +msgstr "" + +#. module: odoo_project +#: model:ir.model.fields,field_description:odoo_project.field_odoo_project__create_uid +#: model:ir.model.fields,field_description:odoo_project.field_odoo_project_import_modules__create_uid +#: model:ir.model.fields,field_description:odoo_project.field_odoo_project_module__create_uid +msgid "Created by" +msgstr "" + +#. module: odoo_project +#: model:ir.model.fields,field_description:odoo_project.field_odoo_project__create_date +#: model:ir.model.fields,field_description:odoo_project.field_odoo_project_import_modules__create_date +#: model:ir.model.fields,field_description:odoo_project.field_odoo_project_module__create_date +msgid "Created on" +msgstr "" + +#. module: odoo_project +#: model:ir.actions.act_window,name:odoo_project.odoo_project_module_action_recursive_dependencies +#: model:ir.model.fields,field_description:odoo_project.field_odoo_project_module__dependency_ids +msgid "Dependencies" +msgstr "" + +#. module: odoo_project +#: model:ir.model.fields,help:odoo_project.field_odoo_project_module__non_std_dependency_level +msgid "Dependency level excluding all standard Odoo modules." +msgstr "" + +#. module: odoo_project +#: model:ir.model.fields,help:odoo_project.field_odoo_project_module__global_dependency_level +msgid "Dependency level including all standard Odoo modules." +msgstr "" + +#. module: odoo_project +#: model:ir.model.fields,field_description:odoo_project.field_odoo_module_branch__odoo_project_module_ids +#: model:ir.model.fields,field_description:odoo_project.field_odoo_project__project_module_ids +#: model:ir.model.fields,field_description:odoo_project.field_odoo_project_module__odoo_project_module_ids +msgid "Deployed Modules" +msgstr "" + +#. module: odoo_project +#: model:ir.model.fields,help:odoo_project.field_odoo_project_module__title +msgid "Descriptive name" +msgstr "" + +#. module: odoo_project +#: model:ir.model.fields,field_description:odoo_project.field_odoo_project_module__development_status_id +msgid "Develoment Status" +msgstr "" + +#. module: odoo_project +#: model:ir.model.fields,field_description:odoo_project.field_odoo_project__display_name +#: model:ir.model.fields,field_description:odoo_project.field_odoo_project_import_modules__display_name +#: model:ir.model.fields,field_description:odoo_project.field_odoo_project_module__display_name +msgid "Display Name" +msgstr "" + +#. module: odoo_project +#: model:ir.model.fields,field_description:odoo_project.field_odoo_project_module__is_enterprise +msgid "Enterprise?" +msgstr "" + +#. module: odoo_project +#: model:ir.model.fields,field_description:odoo_project.field_odoo_project_module__external_dependencies +msgid "External Dependencies" +msgstr "" + +#. module: odoo_project +#: model_terms:ir.ui.view,arch_db:odoo_project.odoo_project_view_form +msgid "Find modules" +msgstr "" + +#. module: odoo_project +#: model:ir.model.fields,field_description:odoo_project.field_odoo_project__message_follower_ids +msgid "Followers" +msgstr "" + +#. module: odoo_project +#: model:ir.model.fields,field_description:odoo_project.field_odoo_project__message_partner_ids +msgid "Followers (Partners)" +msgstr "" + +#. module: odoo_project +#: model:ir.model.fields,field_description:odoo_project.field_odoo_project_module__full_path +msgid "Full Path" +msgstr "" + +#. module: odoo_project +#: model:ir.model.fields,field_description:odoo_project.field_odoo_project_module__global_dependency_level +msgid "Global Dep. Level" +msgstr "" + +#. module: odoo_project +#: model_terms:ir.ui.view,arch_db:odoo_project.odoo_project_view_search +msgid "Group By" +msgstr "" + +#. module: odoo_project +#: model:ir.model.fields,field_description:odoo_project.field_odoo_project__has_message +msgid "Has Message" +msgstr "" + +#. module: odoo_project +#: model:ir.model.fields,field_description:odoo_project.field_odoo_project__id +#: model:ir.model.fields,field_description:odoo_project.field_odoo_project_import_modules__id +#: model:ir.model.fields,field_description:odoo_project.field_odoo_project_module__id +msgid "ID" +msgstr "" + +#. module: odoo_project +#: model:ir.model.fields,help:odoo_project.field_odoo_project__message_needaction +msgid "If checked, new messages require your attention." +msgstr "" + +#. module: odoo_project +#: model:ir.model.fields,help:odoo_project.field_odoo_project__message_has_error +msgid "If checked, some messages have a delivery error." +msgstr "" + +#. module: odoo_project +#: model:ir.model.fields,help:odoo_project.field_odoo_project_module__installed_version_id +msgid "" +"If the real installed version is not available in the history of versions " +"(could come from a pending merge not scanned), this field computes the " +"nearest version available." +msgstr "" + +#. module: odoo_project +#: model_terms:ir.ui.view,arch_db:odoo_project.odoo_project_import_modules_view_form +msgid "Import" +msgstr "" + +#. module: odoo_project +#: model:ir.model.fields,field_description:odoo_project.field_odoo_project_import_modules__import_missing_dependencies +msgid "Import Missing Dependencies" +msgstr "" + +#. module: odoo_project +#: model:ir.actions.act_window,name:odoo_project.odoo_project_import_modules_action +msgid "Import Project Modules" +msgstr "" + +#. module: odoo_project +#: model:ir.model.fields,help:odoo_project.field_odoo_project_import_modules__import_missing_dependencies +msgid "" +"Import module dependencies that are not part of the list above to get an " +"exhaustive list of modules installed in the project." +msgstr "" + +#. module: odoo_project +#: model_terms:ir.ui.view,arch_db:odoo_project.odoo_project_view_form +msgid "Import modules" +msgstr "" + +#. module: odoo_project +#: model:ir.model,name:odoo_project.model_odoo_project_import_modules +msgid "Import modules for an Odoo project" +msgstr "" + +#. module: odoo_project +#: model_terms:ir.ui.view,arch_db:odoo_project.odoo_project_import_modules_view_form +msgid "Initialize from modules list" +msgstr "" + +#. module: odoo_project +#: model_terms:ir.ui.view,arch_db:odoo_project.odoo_project_import_modules_view_form +msgid "" +"Initialize the list of modules that are installed in your project. This will" +" wipe the current installed modules.
The list can be copied-pasted from " +"columns 'Technical Name' and 'Latest Version' put side by side from a " +"standard Odoo export of modules installed." +msgstr "" + +#. module: odoo_project +#: model:ir.model.fields,field_description:odoo_project.field_odoo_project_module__installable +msgid "Installable" +msgstr "" + +#. module: odoo_project +#: model:ir.actions.act_window,name:odoo_project.odoo_project_module_action +#: model:ir.actions.act_window,name:odoo_project.odoo_project_module_for_project_action +#: model:ir.ui.menu,name:odoo_project.odoo_project_module_menu +msgid "Installed Modules" +msgstr "" + +#. module: odoo_project +#: model:ir.model.fields,field_description:odoo_project.field_odoo_project_module__installed_reverse_dependency_ids +msgid "Installed Reverse Dependencies" +msgstr "" + +#. module: odoo_project +#: model:ir.model.fields,field_description:odoo_project.field_odoo_project_module__installed_version +msgid "Installed Version" +msgstr "" + +#. module: odoo_project +#: model_terms:ir.ui.view,arch_db:odoo_project.odoo_project_module_view_tree +msgid "Installed in" +msgstr "" + +#. module: odoo_project +#: model_terms:ir.ui.view,arch_db:odoo_project.odoo_module_branch_view_search +msgid "Installed in projects" +msgstr "" + +#. module: odoo_project +#: model_terms:ir.ui.view,arch_db:odoo_project.odoo_project_module_view_form +msgid "Installed reverse dependencies" +msgstr "" + +#. module: odoo_project +#: model:ir.model.fields,help:odoo_project.field_odoo_project_module__installed_version +msgid "Installed version in project database." +msgstr "" + +#. module: odoo_project +#: model:ir.model.fields,field_description:odoo_project.field_odoo_project__message_is_follower +msgid "Is Follower" +msgstr "" + +#. module: odoo_project +#: model:ir.model.fields,help:odoo_project.field_odoo_project_module__is_community +msgid "Is this module a contribution of the community?" +msgstr "" + +#. module: odoo_project +#: model:ir.model.fields,help:odoo_project.field_odoo_project_module__is_enterprise +msgid "Is this module designed for Odoo Enterprise only?" +msgstr "" + +#. module: odoo_project +#: model:ir.model.fields,help:odoo_project.field_odoo_project_module__is_standard +msgid "Is this module part of Odoo standard?" +msgstr "" + +#. module: odoo_project +#: model:ir.model.fields,field_description:odoo_project.field_odoo_project_module__sloc_js +msgid "JS" +msgstr "" + +#. module: odoo_project +#: model:ir.model.fields,help:odoo_project.field_odoo_project_module__sloc_js +msgid "JavaScript source lines of code" +msgstr "" + +#. module: odoo_project +#: model:ir.model.fields,field_description:odoo_project.field_odoo_project____last_update +#: model:ir.model.fields,field_description:odoo_project.field_odoo_project_import_modules____last_update +#: model:ir.model.fields,field_description:odoo_project.field_odoo_project_module____last_update +msgid "Last Modified on" +msgstr "" + +#. module: odoo_project +#: model:ir.model.fields,field_description:odoo_project.field_odoo_project_module__last_scanned_commit +msgid "Last Scanned Commit" +msgstr "" + +#. module: odoo_project +#: model:ir.model.fields,field_description:odoo_project.field_odoo_project__write_uid +#: model:ir.model.fields,field_description:odoo_project.field_odoo_project_import_modules__write_uid +#: model:ir.model.fields,field_description:odoo_project.field_odoo_project_module__write_uid +msgid "Last Updated by" +msgstr "" + +#. module: odoo_project +#: model:ir.model.fields,field_description:odoo_project.field_odoo_project__write_date +#: model:ir.model.fields,field_description:odoo_project.field_odoo_project_import_modules__write_date +#: model:ir.model.fields,field_description:odoo_project.field_odoo_project_module__write_date +msgid "Last Updated on" +msgstr "" + +#. module: odoo_project +#: model_terms:ir.ui.view,arch_db:odoo_project.odoo_project_module_view_form +#: model_terms:ir.ui.view,arch_db:odoo_project.odoo_project_module_view_tree +msgid "Last Version" +msgstr "" + +#. module: odoo_project +#: model:ir.model.fields,field_description:odoo_project.field_odoo_project_module__version +msgid "Last version" +msgstr "" + +#. module: odoo_project +#: model:ir.model.fields,field_description:odoo_project.field_odoo_project_module__license_id +msgid "License" +msgstr "" + +#. module: odoo_project +#: model:ir.model.fields,field_description:odoo_project.field_odoo_project__message_main_attachment_id +msgid "Main Attachment" +msgstr "" + +#. module: odoo_project +#: model:ir.model.fields,field_description:odoo_project.field_odoo_project_module__maintainer_ids +msgid "Maintainers" +msgstr "" + +#. module: odoo_project +#: model:ir.model.fields,field_description:odoo_project.field_odoo_project__message_has_error +msgid "Message Delivery error" +msgstr "" + +#. module: odoo_project +#: model:ir.model.fields,field_description:odoo_project.field_odoo_project__message_ids +msgid "Messages" +msgstr "" + +#. module: odoo_project +#: model:ir.model.fields,field_description:odoo_project.field_odoo_project_module__migration_scripts +msgid "Migration Scripts" +msgstr "" + +#. module: odoo_project +#: model_terms:ir.ui.view,arch_db:odoo_project.odoo_project_module_view_search +msgid "Migration Scripts to play" +msgstr "" + +#. module: odoo_project +#: model_terms:ir.ui.view,arch_db:odoo_project.odoo_project_view_search +msgid "Module" +msgstr "" + +#. module: odoo_project +#: model:ir.model.fields,field_description:odoo_project.field_odoo_project_module__module_name +msgid "Module Technical Name" +msgstr "" + +#. module: odoo_project +#: model:ir.model.fields,help:odoo_project.field_odoo_project_module__specific +msgid "" +"Module specific to a project repository.It cannot be used across different " +"projects." +msgstr "" + +#. module: odoo_project +#: model:ir.model.fields,field_description:odoo_project.field_odoo_project__module_ids +#: model_terms:ir.ui.view,arch_db:odoo_project.odoo_project_view_form +msgid "Modules" +msgstr "" + +#. module: odoo_project +#: model:ir.model.fields,field_description:odoo_project.field_odoo_project__modules_count +msgid "Modules Count" +msgstr "" + +#. module: odoo_project +#: model:ir.model.fields,field_description:odoo_project.field_odoo_project_import_modules__modules_list +msgid "Modules List" +msgstr "" + +#. module: odoo_project +#: model:ir.model.fields,help:odoo_project.field_odoo_project__module_not_installed_ids +msgid "Modules available in the project repository but not installed." +msgstr "" + +#. module: odoo_project +#: model:ir.model.fields,help:odoo_project.field_odoo_project__unmerged_module_ids +msgid "Modules installed belonging to an open PR." +msgstr "" + +#. module: odoo_project +#: model:ir.model.fields,help:odoo_project.field_odoo_project__unknown_module_ids +msgid "Modules installed but cannot be found among repositories/branches." +msgstr "" + +#. module: odoo_project +#: model:ir.model.fields,field_description:odoo_project.field_odoo_project__module_not_installed_ids +#: model_terms:ir.ui.view,arch_db:odoo_project.odoo_project_view_form +msgid "Modules not installed" +msgstr "" + +#. module: odoo_project +#: model:ir.model.fields,field_description:odoo_project.field_odoo_project__unmerged_module_ids +#: model_terms:ir.ui.view,arch_db:odoo_project.odoo_project_view_form +msgid "Modules to merge" +msgstr "" + +#. module: odoo_project +#: model:ir.model.fields,field_description:odoo_project.field_odoo_project__unknown_module_ids +msgid "Modules unknown" +msgstr "" + +#. module: odoo_project +#: model:ir.model.fields,field_description:odoo_project.field_odoo_project__name +msgid "Name" +msgstr "" + +#. module: odoo_project +#: model:ir.model.fields,field_description:odoo_project.field_odoo_project_module__installed_version_id +msgid "Nearest installed version" +msgstr "" + +#. module: odoo_project +#: model_terms:ir.ui.view,arch_db:odoo_project.odoo_module_branch_view_search +msgid "No project" +msgstr "" + +#. module: odoo_project +#: model:ir.model.fields,field_description:odoo_project.field_odoo_project_module__non_std_dependency_level +msgid "Non-Std Dep. Level" +msgstr "" + +#. module: odoo_project +#: model:ir.model.fields,field_description:odoo_project.field_odoo_project_module__not_installed_reverse_dependency_ids +msgid "Not Installed Reverse Dependencies" +msgstr "" + +#. module: odoo_project +#: model_terms:ir.ui.view,arch_db:odoo_project.odoo_project_module_view_form +msgid "Not installed reverse dependencies" +msgstr "" + +#. module: odoo_project +#: model:ir.model.fields,field_description:odoo_project.field_odoo_project__message_needaction_counter +msgid "Number of Actions" +msgstr "" + +#. module: odoo_project +#: model:ir.model.fields,field_description:odoo_project.field_odoo_project__message_has_error_counter +msgid "Number of errors" +msgstr "" + +#. module: odoo_project +#: model:ir.model.fields,help:odoo_project.field_odoo_project__message_needaction_counter +msgid "Number of messages requiring action" +msgstr "" + +#. module: odoo_project +#: model:ir.model.fields,help:odoo_project.field_odoo_project__message_has_error_counter +msgid "Number of messages with delivery error" +msgstr "" + +#. module: odoo_project +#: model:ir.model,name:odoo_project.model_odoo_module_branch +msgid "Odoo Module Branch" +msgstr "" + +#. module: odoo_project +#: model:ir.model,name:odoo_project.model_odoo_repository +msgid "Odoo Modules Repository" +msgstr "" + +#. module: odoo_project +#: model:ir.model,name:odoo_project.model_odoo_project +msgid "Odoo Project" +msgstr "" + +#. module: odoo_project +#: model:ir.model,name:odoo_project.model_odoo_project_module +msgid "Odoo Project Module" +msgstr "" + +#. module: odoo_project +#: model:ir.model.fields,field_description:odoo_project.field_odoo_project__odoo_version_id +#: model:ir.model.fields,field_description:odoo_project.field_odoo_project_import_modules__odoo_version_id +#: model:ir.model.fields,field_description:odoo_project.field_odoo_project_module__branch_id +#: model_terms:ir.ui.view,arch_db:odoo_project.odoo_project_view_search +msgid "Odoo Version" +msgstr "" + +#. module: odoo_project +#: model:ir.model.fields,field_description:odoo_project.field_odoo_project_module__org_id +msgid "Organization" +msgstr "" + +#. module: odoo_project +#: model:ir.model.fields,field_description:odoo_project.field_odoo_project_module__pr_url +msgid "PR URL" +msgstr "" + +#. module: odoo_project +#: model:ir.model.fields,field_description:odoo_project.field_odoo_project_import_modules__odoo_project_id +#: model:ir.model.fields,field_description:odoo_project.field_odoo_project_module__odoo_project_id +#: model_terms:ir.ui.view,arch_db:odoo_project.odoo_module_branch_view_search +msgid "Project" +msgstr "" + +#. module: odoo_project +#: model:ir.model.fields,field_description:odoo_project.field_odoo_repository__project_count +msgid "Project Count" +msgstr "" + +#. module: odoo_project +#: model_terms:ir.ui.view,arch_db:odoo_project.odoo_project_view_form +msgid "Project Name" +msgstr "" + +#. module: odoo_project +#: model:ir.actions.act_window,name:odoo_project.odoo_project_action +#: model:ir.model.fields,field_description:odoo_project.field_odoo_module_branch__odoo_project_ids +#: model:ir.model.fields,field_description:odoo_project.field_odoo_project_module__odoo_project_ids +#: model:ir.model.fields,field_description:odoo_project.field_odoo_repository__project_ids +#: model:ir.ui.menu,name:odoo_project.odoo_project_main_menu +#: model:ir.ui.menu,name:odoo_project.odoo_project_menu +#: model_terms:ir.ui.view,arch_db:odoo_project.odoo_module_branch_view_form +#: model_terms:ir.ui.view,arch_db:odoo_project.odoo_repository_view_form +msgid "Projects" +msgstr "" + +#. module: odoo_project +#: model:ir.model.fields,field_description:odoo_project.field_odoo_project_module__sloc_python +msgid "Python" +msgstr "" + +#. module: odoo_project +#: model:ir.model.fields,field_description:odoo_project.field_odoo_project_module__python_dependency_ids +msgid "Python Dependencies" +msgstr "" + +#. module: odoo_project +#: model:ir.model.fields,help:odoo_project.field_odoo_project_module__sloc_python +msgid "Python source lines of code" +msgstr "" + +#. module: odoo_project +#: model:ir.model.fields,field_description:odoo_project.field_odoo_project_module__removed +msgid "Removed" +msgstr "" + +#. module: odoo_project +#: model:ir.model.fields,field_description:odoo_project.field_odoo_project__repository_id +#: model:ir.model.fields,field_description:odoo_project.field_odoo_project_module__repository_id +msgid "Repository" +msgstr "" + +#. module: odoo_project +#: model:ir.model.fields,field_description:odoo_project.field_odoo_project__repository_branch_id +msgid "Repository / Branch" +msgstr "" + +#. module: odoo_project +#: model:ir.model.fields,field_description:odoo_project.field_odoo_project_module__repository_branch_id +msgid "Repository Branch" +msgstr "" + +#. module: odoo_project +#: model:ir.model.fields,help:odoo_project.field_odoo_project__repository_id +msgid "" +"Repository this project is based on (optional). You can start to " +"build/simulate a project without repository to get some figures." +msgstr "" + +#. module: odoo_project +#: model:ir.model.fields,field_description:odoo_project.field_odoo_project_module__reverse_dependency_ids +msgid "Reverse Dependencies" +msgstr "" + +#. module: odoo_project +#: model_terms:ir.ui.view,arch_db:odoo_project.odoo_project_view_form +msgid "Scan" +msgstr "" + +#. module: odoo_project +#: model_terms:ir.ui.view,arch_db:odoo_project.odoo_project_view_form +msgid "Scan all the repositories used by this project." +msgstr "" + +#. module: odoo_project +#: model:ir.model.fields,field_description:odoo_project.field_odoo_project_module__repository_sequence +msgid "Sequence" +msgstr "" + +#. module: odoo_project +#: model:ir.model.fields,field_description:odoo_project.field_odoo_project_module__specific +msgid "Specific" +msgstr "" + +#. module: odoo_project +#: model:ir.model.fields,field_description:odoo_project.field_odoo_project_module__is_standard +msgid "Standard?" +msgstr "" + +#. module: odoo_project +#: model_terms:ir.ui.view,arch_db:odoo_project.odoo_project_view_form +msgid "Status" +msgstr "" + +#. module: odoo_project +#: model:ir.model.fields,field_description:odoo_project.field_odoo_project_module__summary +msgid "Summary" +msgstr "" + +#. module: odoo_project +#: model:ir.model.fields,field_description:odoo_project.field_odoo_project_module__name +msgid "Techname" +msgstr "" + +#. module: odoo_project +#: model:ir.model.fields,help:odoo_project.field_odoo_project_module__module_name +msgid "Technical Name" +msgstr "" + +#. module: odoo_project +#: model:ir.model.fields,help:odoo_project.field_odoo_project_module__addons_path +msgid "Technical field. Where the module is located in the repository." +msgstr "" + +#. module: odoo_project +#: model:ir.model.fields,field_description:odoo_project.field_odoo_project_module__module_id +msgid "Technical name" +msgstr "" + +#. module: odoo_project +#: model:ir.model.constraint,message:odoo_project.constraint_odoo_project_name_uniq +msgid "This project already exists." +msgstr "" + +#. module: odoo_project +#: model:ir.model.fields,field_description:odoo_project.field_odoo_project_module__title +msgid "Title" +msgstr "" + +#. module: odoo_project +#: model:ir.model.fields,field_description:odoo_project.field_odoo_project_module__to_upgrade +#: model_terms:ir.ui.view,arch_db:odoo_project.odoo_project_module_view_search +msgid "To Upgrade" +msgstr "" + +#. module: odoo_project +#: model:ir.model.fields,field_description:odoo_project.field_odoo_project_module__url +msgid "URL" +msgstr "" + +#. module: odoo_project +#: model_terms:ir.ui.view,arch_db:odoo_project.odoo_project_view_form +msgid "Unknown modules" +msgstr "" + +#. module: odoo_project +#: model:ir.model.fields,field_description:odoo_project.field_odoo_project_module__module_branch_id +msgid "Upstream Module" +msgstr "" + +#. module: odoo_project +#: model:ir.model.fields,field_description:odoo_project.field_odoo_project_module__version_ids +msgid "Versions" +msgstr "" + +#. module: odoo_project +#: model:ir.model.fields,field_description:odoo_project.field_odoo_project_module__sloc_xml +msgid "XML" +msgstr "" + +#. module: odoo_project +#: model:ir.model.fields,help:odoo_project.field_odoo_project_module__sloc_xml +msgid "XML source lines of code" +msgstr "" diff --git a/odoo_project/models/__init__.py b/odoo_project/models/__init__.py new file mode 100644 index 00000000..db978dc8 --- /dev/null +++ b/odoo_project/models/__init__.py @@ -0,0 +1,4 @@ +from . import odoo_project +from . import odoo_project_module +from . import odoo_module_branch +from . import odoo_repository diff --git a/odoo_project/models/odoo_module_branch.py b/odoo_project/models/odoo_module_branch.py new file mode 100644 index 00000000..66969759 --- /dev/null +++ b/odoo_project/models/odoo_module_branch.py @@ -0,0 +1,57 @@ +# Copyright 2023 Camptocamp SA +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl) + +from odoo import api, fields, models + + +class OdooModuleBranch(models.Model): + _inherit = "odoo.module.branch" + + odoo_project_module_ids = fields.One2many( + comodel_name="odoo.project.module", + inverse_name="module_branch_id", + string="Deployed Modules", + ) + odoo_project_ids = fields.Many2many( + comodel_name="odoo.project", + relation="odoo_project_module_branch_rel", + column1="module_branch_id", + column2="odoo_project_id", + string="Projects", + compute="_compute_module_ids", + store=True, + ) + + @api.depends("odoo_project_module_ids.odoo_project_id") + def _compute_module_ids(self): + for rec in self: + rec.odoo_project_ids = rec.odoo_project_module_ids.odoo_project_id.ids + + def _filter_module_to_update(self, repo_branch, module_branch): + # A module found in a specific repository cannot be linked to an orphaned + # module that is already listed/installed in different projects (chances + # are these projects refer to a generic version of the module). + # For such specific module we want to create a dedicated 'odoo.module.branch'. + if ( + repo_branch.repository_id.specific + # Orphaned module + and module_branch + and not module_branch.repository_id + # Installed in multiple projects + # NOTE: we could have multiple project instances using the same + # repository, so we check the underlying repo instead + and len(module_branch.odoo_project_ids.repository_id) > 1 + ): + repo_projects = repo_branch.repository_id.project_ids + if repo_projects: + # Corner case: if the current project(s) are referring to this + # orphaned module, remove them as they will now have a dedicated + # specific module created. + # Spawn a job to re-map project modules to the new (not yet created) + # specific module. + project_modules = module_branch.odoo_project_module_ids.filtered( + lambda o: o.odoo_project_id in repo_projects + ) + project_modules.with_delay()._remap_to_specific_module() + return False + return module_branch diff --git a/odoo_project/models/odoo_project.py b/odoo_project/models/odoo_project.py new file mode 100644 index 00000000..6f613e6e --- /dev/null +++ b/odoo_project/models/odoo_project.py @@ -0,0 +1,192 @@ +# Copyright 2023 Camptocamp SA +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl) + +import ast + +from odoo import api, fields, models + + +class OdooProject(models.Model): + _name = "odoo.project" + _inherit = "mail.thread" + _description = "Odoo Project" + _order = "name" + + name = fields.Char(required=True, index=True) + active = fields.Boolean(default=True) + repository_id = fields.Many2one( + comodel_name="odoo.repository", + string="Repository", + domain=[("specific", "=", True)], + store=True, + index=True, + help=( + "Repository this project is based on (optional). " + "You can start to build/simulate a project without repository " + "to get some figures." + ), + ) + available_odoo_version_ids = fields.One2many( + comodel_name="odoo.branch", + compute="_compute_available_odoo_version_ids", + string="Available Odoo Versions", + ) + odoo_version_id = fields.Many2one( + comodel_name="odoo.branch", + ondelete="restrict", + string="Odoo Version", + store=True, + index=True, + ) + repository_branch_id = fields.Many2one( + comodel_name="odoo.repository.branch", + string="Repository / Branch", + compute="_compute_repository_branch_id", + store=True, + index=True, + ) + project_module_ids = fields.One2many( + comodel_name="odoo.project.module", + inverse_name="odoo_project_id", + string="Deployed Modules", + ) + module_ids = fields.Many2many( + comodel_name="odoo.module", + relation="odoo_project_module_rel", + column1="odoo_project_id", + column2="module_id", + string="Modules", + compute="_compute_module_ids", + store=True, + ) + modules_count = fields.Integer(compute="_compute_modules_count") + module_not_installed_ids = fields.Many2many( + comodel_name="odoo.module.branch", + string="Modules not installed", + help="Modules available in the project repository but not installed.", + compute="_compute_module_not_installed_ids", + ) + unmerged_module_ids = fields.Many2many( + comodel_name="odoo.module.branch", + string="Modules to merge", + help="Modules installed belonging to an open PR.", + compute="_compute_unmerged_module_ids", + ) + unknown_module_ids = fields.Many2many( + comodel_name="odoo.module.branch", + string="Modules unknown", + help="Modules installed but cannot be found among repositories/branches.", + compute="_compute_unknown_module_ids", + ) + + _sql_constraints = [ + ("name_uniq", "UNIQUE (name)", "This project already exists."), + ] + + @api.depends("repository_id") + def _compute_available_odoo_version_ids(self): + all_versions = self.env["odoo.branch"]._get_all_odoo_versions() + for rec in self: + rec.available_odoo_version_ids = all_versions + if rec.repository_id: + rec.available_odoo_version_ids = rec.repository_id.branch_ids.branch_id + + @api.depends("repository_id", "odoo_version_id") + def _compute_repository_branch_id(self): + for rec in self: + rec.repository_branch_id = False + if not rec.repository_id or not rec.odoo_version_id: + continue + rec.repository_branch_id = rec.repository_id.branch_ids.filtered( + lambda rb, rec=rec: rb.branch_id == rec.odoo_version_id + ) + + @api.depends("project_module_ids.module_id") + def _compute_module_ids(self): + for rec in self: + rec.module_ids = rec.project_module_ids.module_id.ids + + @api.depends("project_module_ids") + def _compute_modules_count(self): + for rec in self: + rec.modules_count = len(rec.project_module_ids) + + @api.depends( + "repository_branch_id.module_ids", "project_module_ids.module_branch_id" + ) + def _compute_module_not_installed_ids(self): + for rec in self: + all_module_ids = set(rec.repository_branch_id.module_ids.ids) + installed_module_ids = set(rec.project_module_ids.module_branch_id.ids) + rec.module_not_installed_ids = list(all_module_ids - installed_module_ids) + + @api.depends("project_module_ids.pr_url") + def _compute_unmerged_module_ids(self): + for rec in self: + rec.unmerged_module_ids = rec.project_module_ids.module_branch_id.filtered( + lambda module: module.pr_url + ) + + @api.depends("project_module_ids.repository_id") + def _compute_unknown_module_ids(self): + for rec in self: + rec.unknown_module_ids = rec.project_module_ids.module_branch_id.filtered( + lambda module: not module.repository_id + ) + + def open_import_modules(self): + """Open a wizard to import the modules of this Odoo project.""" + self.ensure_one() + action = self.env["ir.actions.actions"]._for_xml_id( + "odoo_project.odoo_project_import_modules_action" + ) + ctx = action.get("context", {}) + if isinstance(ctx, str): + ctx = ast.literal_eval(ctx) + ctx["default_odoo_project_id"] = self.id + action["context"] = ctx + return action + + def open_modules(self): + self.ensure_one() + action = self.env["ir.actions.actions"]._for_xml_id( + "odoo_project.odoo_project_module_for_project_action" + ) + ctx = action.get("context", {}) + if isinstance(ctx, str): + ctx = ast.literal_eval(ctx) + action["domain"] = [("id", "in", self.project_module_ids.ids)] + ctx["search_default_group_by_org_id"] = 1 + ctx["search_default_group_by_repository_id"] = 2 + action["context"] = ctx + return action + + def action_find_unknown_modules(self): + """Try to locate unknown modules.""" + for module in self.unknown_module_ids: + module.action_find_pr_url() + + def _get_repositories_to_scan(self): + """Return the repositories to scan.""" + domain = self.env["odoo.repository"]._cron_scanner_domain() + return self.project_module_ids.repository_id.filtered_domain(domain) + + def _get_branches_to_scan(self): + """Return the branches/versions to scan.""" + return self.project_module_ids.repository_branch_id.branch_id + + def action_scan(self, force=False): + """Scan all the repositories used by the project.""" + # Scan all the repositories used within the project with relevant branches + repositories = self._get_repositories_to_scan().with_context( + strict_branches_scan=True + ) + repositories -= self.repository_id + branches = self._get_branches_to_scan() + if branches: + repositories.action_scan( + branch_ids=branches.ids, force=force, raise_exc=False + ) + # Scan the underlying project repository itself + self.repository_id.action_scan(force=force, raise_exc=True) + return True diff --git a/odoo_project/models/odoo_project_module.py b/odoo_project/models/odoo_project_module.py new file mode 100644 index 00000000..767179bc --- /dev/null +++ b/odoo_project/models/odoo_project_module.py @@ -0,0 +1,151 @@ +# Copyright 2023 Camptocamp SA +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl) + +from odoo import api, fields, models +from odoo.tools.parse_version import parse_version as v + + +class OdooProjectModule(models.Model): + _name = "odoo.project.module" + _inherits = {"odoo.module.branch": "module_branch_id"} + _description = "Odoo Project Module" + _order = "name" + + odoo_project_id = fields.Many2one( + comodel_name="odoo.project", + ondelete="cascade", + string="Project", + ) + module_branch_id = fields.Many2one( + comodel_name="odoo.module.branch", + ondelete="cascade", + string="Upstream Module", + required=True, + ) + installed_version = fields.Char(help="Installed version in project database.") + installed_version_id = fields.Many2one( + comodel_name="odoo.module.branch.version", + string="Nearest installed version", + help=( + "If the real installed version is not available in the history of " + "versions (could come from a pending merge not scanned), this field " + "computes the nearest version available." + ), + compute="_compute_installed_version_id", + ) + to_upgrade = fields.Boolean( + compute="_compute_to_upgrade", + store=True, + ) + migration_scripts = fields.Boolean( + compute="_compute_migration_scripts", + store=True, + help="Available migration scripts between installed and last version.", + ) + installed_reverse_dependency_ids = fields.Many2many( + comodel_name="odoo.project.module", + compute="_compute_installed_reverse_dependency_ids", + string="Installed Reverse Dependencies", + ) + not_installed_reverse_dependency_ids = fields.Many2many( + comodel_name="odoo.module.branch", + compute="_compute_installed_reverse_dependency_ids", + string="Not Installed Reverse Dependencies", + ) + + @api.depends("installed_version") + def _compute_installed_version_id(self): + for rec in self: + rec.installed_version_id = rec.version_ids.browse() + if not rec.installed_version: + continue + # Installed version could not be available in inventoried versions + # if it is coming from a pending-merge. In such case we take the + # nearest version matching the installed one. + # - Available versions upstream = "14.0.2.0.0" & "14.0.2.1.0" + # - Installed version = "14.0.2.0.1" (in a pending-merge) + # - Computed installed version = "14.0.2.0.0" + inst_ver = [int(n) for n in rec.installed_version.split(".")] + for version in rec.version_ids.sorted("sequence"): + ver = [int(n) for n in version.name.split(".")] + if ver > inst_ver: + break + rec.installed_version_id = version + + @api.depends("version", "installed_version") + def _compute_to_upgrade(self): + for rec in self: + rec.to_upgrade = False + installed_version = rec.installed_version or rec.version + if installed_version and rec.version: + rec.to_upgrade = v(installed_version) < v(rec.version) + + @api.depends( + "to_upgrade", + "installed_version", + "version_ids.name", + "version_ids.has_migration_script", + ) + def _compute_migration_scripts(self): + for rec in self: + rec.migration_scripts = False + if not rec.to_upgrade: + continue + installed_version = rec.installed_version_id + versions_with_mig_script = rec.version_ids.filtered( + lambda v, installed_version=installed_version: ( + v.sequence > installed_version.sequence and v.has_migration_script + ) + ) + rec.migration_scripts = bool(versions_with_mig_script) + + @api.depends("odoo_project_id", "reverse_dependency_ids") + def _compute_installed_reverse_dependency_ids(self): + for rec in self: + installed_project_modules = rec.odoo_project_id.project_module_ids + installed_modules = installed_project_modules.module_branch_id + installed_reverse_dependencies = rec.reverse_dependency_ids.filtered( + lambda dep, installed_modules=installed_modules: ( + dep in installed_modules + ) + ) + # Installed rev. deps. are 'odoo.project.module' records + rec.installed_reverse_dependency_ids = ( + installed_reverse_dependencies.odoo_project_module_ids.filtered_domain( + [("odoo_project_id", "=", rec.odoo_project_id.id)] + ) + ) + # Not installed rev. deps. are 'odoo.module.branch' records + rec.not_installed_reverse_dependency_ids = ( + rec.reverse_dependency_ids - installed_reverse_dependencies + ) + + def open_recursive_dependencies(self): + self.ensure_one() + xml_id = "odoo_project.odoo_project_module_action_recursive_dependencies" + action = self.env["ir.actions.actions"]._for_xml_id(xml_id) + action["name"] = "All dependencies" + dependencies = self.module_branch_id._get_recursive_dependencies() + project_dependencies = dependencies.odoo_project_module_ids.filtered( + lambda o: o.odoo_project_id == self.odoo_project_id + ) + action["domain"] = [("id", "in", project_dependencies.ids)] + return action + + def _remap_to_specific_module(self): + """Re-map orphaned project modules. + + As soon as an orphaned module has been scanned as a specific module + of a project repository, all project modules that were targeting this + orphaned module will inherit from this newly specific module instead. + """ + for rec in self: + if not rec.odoo_project_id.repository_id: + continue + specific_module_branch = self.env["odoo.module.branch"]._get_module_branch( + rec.branch_id, + rec.module_id, + repo=rec.odoo_project_id.repository_id, + ) + if specific_module_branch: + rec.write({"module_branch_id": specific_module_branch.id}) diff --git a/odoo_project/models/odoo_repository.py b/odoo_project/models/odoo_repository.py new file mode 100644 index 00000000..40cbb3f4 --- /dev/null +++ b/odoo_project/models/odoo_repository.py @@ -0,0 +1,48 @@ +# Copyright 2024 Camptocamp SA +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl) + +from odoo import api, fields, models + + +class OdooRepository(models.Model): + _inherit = "odoo.repository" + + project_ids = fields.One2many( + comodel_name="odoo.project", + inverse_name="repository_id", + string="Projects", + ) + project_count = fields.Integer(compute="_compute_project_count") + + @api.depends("project_ids") + def _compute_project_count(self): + for rec in self: + rec.project_count = len(rec.project_ids) + + def action_view_projects(self): + self.ensure_one() + projects = self.project_ids + action = self.env["ir.actions.actions"]._for_xml_id( + "odoo_project.odoo_project_action" + ) + if len(projects) > 1: + action["domain"] = [("id", "in", projects.ids)] + elif len(projects) == 1: + form_view = [ + (self.env.ref("odoo_project.odoo_project_view_form").id, "form") + ] + if "views" in action: + action["views"] = form_view + [ + (state, view) for state, view in action["views"] if view != "form" + ] + else: + action["views"] = form_view + action["res_id"] = projects.id + else: + action = {"type": "ir.actions.act_window_close"} + + context = { + "default_repository_id": self.id, + } + action["context"] = context + return action diff --git a/odoo_project/pyproject.toml b/odoo_project/pyproject.toml new file mode 100644 index 00000000..4231d0cc --- /dev/null +++ b/odoo_project/pyproject.toml @@ -0,0 +1,3 @@ +[build-system] +requires = ["whool"] +build-backend = "whool.buildapi" diff --git a/odoo_project/readme/CONTRIBUTORS.md b/odoo_project/readme/CONTRIBUTORS.md new file mode 100644 index 00000000..17752927 --- /dev/null +++ b/odoo_project/readme/CONTRIBUTORS.md @@ -0,0 +1,2 @@ +- Camptocamp + - Sébastien Alix \ diff --git a/odoo_project/readme/DESCRIPTION.md b/odoo_project/readme/DESCRIPTION.md new file mode 100644 index 00000000..f78abb84 --- /dev/null +++ b/odoo_project/readme/DESCRIPTION.md @@ -0,0 +1,8 @@ +This module allows you to declare your Odoo projects with the list of installed modules. + +Based on the data collected by `odoo_repository` module, it will: + +- give some code stats (lines of code, and how they are spread among Odoo/OCA/your organization) +- give the list of modules available for upgrade in current Odoo version (based on module versions) +- list modules still hosted in a pending Pull Request (so not yet merged, could be considered as technical debt) +- list modules available in your project repository (if any) but not installed in your database (dead code) diff --git a/odoo_project/security/ir.model.access.csv b/odoo_project/security/ir.model.access.csv new file mode 100644 index 00000000..48748488 --- /dev/null +++ b/odoo_project/security/ir.model.access.csv @@ -0,0 +1,5 @@ +id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink +access_odoo_project_user,odoo_project_user,model_odoo_project,odoo_repository.group_odoo_repository_user,1,1,1,0 +access_odoo_project_manager,odoo_project_manager,model_odoo_project,odoo_repository.group_odoo_repository_manager,1,1,1,1 +access_odoo_project_module_user,odoo_project_module_user,model_odoo_project_module,odoo_repository.group_odoo_repository_user,1,0,0,0 +access_odoo_project_import_modules_user,odoo_project_import_modules_user,model_odoo_project_import_modules,odoo_repository.group_odoo_repository_user,1,1,1,1 diff --git a/odoo_project/static/description/icon.png b/odoo_project/static/description/icon.png new file mode 100644 index 00000000..1dcc49c2 Binary files /dev/null and b/odoo_project/static/description/icon.png differ diff --git a/odoo_project/static/description/index.html b/odoo_project/static/description/index.html new file mode 100644 index 00000000..848eb740 --- /dev/null +++ b/odoo_project/static/description/index.html @@ -0,0 +1,444 @@ + + + + + +README.rst + + + +
+ + + +Odoo Community Association + +
+

Odoo Project

+ +

Beta License: AGPL-3 OCA/module-composition-analysis Translate me on Weblate Try me on Runboat

+

This module allows you to declare your Odoo projects with the list of +installed modules.

+

Based on the data collected by odoo_repository module, it will:

+
    +
  • give some code stats (lines of code, and how they are spread among +Odoo/OCA/your organization)
  • +
  • give the list of modules available for upgrade in current Odoo version +(based on module versions)
  • +
  • list modules still hosted in a pending Pull Request (so not yet +merged, could be considered as technical debt)
  • +
  • list modules available in your project repository (if any) but not +installed in your database (dead code)
  • +
+

Table of contents

+ +
+

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 +feedback.

+

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

+
+
+

Credits

+
+

Authors

+
    +
  • Camptocamp
  • +
+
+
+

Contributors

+ +
+
+

Maintainers

+

This module is maintained by the OCA.

+ +Odoo Community Association + +

OCA, or the Odoo Community Association, is a nonprofit organization whose +mission is to support the collaborative development of Odoo features and +promote its widespread use.

+

This module is part of the OCA/module-composition-analysis project on GitHub.

+

You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute.

+
+
+
+
+ + diff --git a/odoo_project/tests/__init__.py b/odoo_project/tests/__init__.py new file mode 100644 index 00000000..9c82a9f7 --- /dev/null +++ b/odoo_project/tests/__init__.py @@ -0,0 +1 @@ +from . import test_import_modules diff --git a/odoo_project/tests/common.py b/odoo_project/tests/common.py new file mode 100644 index 00000000..b387a9d5 --- /dev/null +++ b/odoo_project/tests/common.py @@ -0,0 +1,30 @@ +# Copyright 2024 Camptocamp SA +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl) + +from odoo.tests import Form + +from odoo.addons.odoo_repository.tests import common + + +class Common(common.Common): + def setUp(self): + super().setUp() + self.project = self.env["odoo.project"].create( + { + "name": "TEST", + "odoo_version_id": self.branch.id, + } + ) + self.wiz_model = self.env["odoo.project.import.modules"] + + @classmethod + def _run_import_modules(cls, project, modules_list_text, **kwargs): + wiz_model = cls.env["odoo.project.import.modules"].with_context( + default_odoo_project_id=project.id + ) + with Form(wiz_model) as form: + form.modules_list = modules_list_text + wiz = form.save() + wiz.action_import() + cls.env.flush_all() # Force fields computation + return wiz diff --git a/odoo_project/tests/test_import_modules.py b/odoo_project/tests/test_import_modules.py new file mode 100644 index 00000000..361de268 --- /dev/null +++ b/odoo_project/tests/test_import_modules.py @@ -0,0 +1,165 @@ +# Copyright 2024 Camptocamp SA +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl) + +from .common import Common + + +class TestImportModules(Common): + def test_import_modules_names(self): + mod1 = "test1" + mod2 = "test2" + # Ensure these modules don't exist + existing_mods = self.module_branch_model.search( + [("module_name", "in", [mod1, mod2])] + ) + self.assertFalse(existing_mods) + # Import them through the wizard + modules_list_text = f"{mod1}\n{mod2}" + self._run_import_modules(self.project, modules_list_text) + # They now exists as orphaned modules and are linked to the project + existing_mods = self.module_branch_model.search( + [ + ("module_name", "in", [mod1, mod2]), + ("repository_id", "=", False), + ("odoo_project_ids", "=", self.project.id), + ] + ) + self.assertEqual(len(existing_mods), 2) + # Project modules are also created + self.assertEqual(len(existing_mods.odoo_project_module_ids), 2) + + def test_import_modules_names_versions(self): + mod1 = "test1" + mod2 = "test2" + # Ensure these modules don't exist + existing_mods = self.module_branch_model.search( + [("module_name", "in", [mod1, mod2])] + ) + self.assertFalse(existing_mods) + # Import them through the wizard with their installed versions + modules_list_text = f"{mod1} 1.0.0\n{mod2} {self.branch}.1.0.0" + self._run_import_modules(self.project, modules_list_text) + # They now exists as orphaned modules and are linked to the project + existing_mods = self.module_branch_model.search( + [ + ("module_name", "in", [mod1, mod2]), + ("repository_id", "=", False), + ("odoo_project_ids", "=", self.project.id), + ] + ) + self.assertEqual(len(existing_mods), 2) + # Project modules are also created + self.assertEqual(len(existing_mods.odoo_project_module_ids), 2) + pm1 = existing_mods.odoo_project_module_ids.filtered( + lambda m: m.module_name == mod1 + ) + self.assertEqual(pm1.installed_version, "1.0.0") + pm2 = existing_mods.odoo_project_module_ids.filtered( + lambda m: m.module_name == mod2 + ) + self.assertEqual(pm2.installed_version, f"{self.branch}.1.0.0") + + def test_match_blacklisted_module(self): + mod1 = "test1" + mod2 = "test2" + mod1_blacklisted = self.wiz_model._get_module(mod1) + mod1_blacklisted.blacklisted = True + # Import them through the wizard + modules_list_text = f"{mod1}\n{mod2}" + self._run_import_modules(self.project, modules_list_text) + # Only one module has been imported as an orphaned module + existing_mods = self.module_branch_model.search( + [ + ("module_name", "in", [mod1, mod2]), + ("repository_id", "=", False), + ("odoo_project_ids", "=", self.project.id), + ] + ) + self.assertEqual(len(existing_mods), 1) + # Project modules are also created + self.assertEqual(len(existing_mods.odoo_project_module_ids), 1) + + def test_match_orphaned_module(self): + mod1 = "test1" + mod2 = "test2" + mod1_orphaned = self.wiz_model._get_module(mod1) + mod1_branch_orphaned = self.module_branch_model._create_orphaned_module_branch( + self.branch, mod1_orphaned + ) + # Import them through the wizard + modules_list_text = f"{mod1}\n{mod2}" + self._run_import_modules(self.project, modules_list_text) + # They now exists as orphaned modules and are linked to the project + existing_mods = self.module_branch_model.search( + [ + ("module_name", "in", [mod1, mod2]), + ("repository_id", "=", False), + ("odoo_project_ids", "=", self.project.id), + ] + ) + self.assertEqual(len(existing_mods), 2) + # One of them matched the existing orphaned module + self.assertIn(mod1_branch_orphaned, existing_mods) + # Project modules are also created + self.assertEqual(len(existing_mods.odoo_project_module_ids), 2) + + def test_match_generic_module(self): + mod1 = "test1" + mod2 = "test2" + mod1_generic = self.wiz_model._get_module(mod1) + repo_branch = self._create_odoo_repository_branch( + self.odoo_repository, self.branch + ) + mod1_branch_generic = self._create_odoo_module_branch( + mod1_generic, + self.branch, + specific=False, + repository_branch_id=repo_branch.id, + ) + # Import them through the wizard + modules_list_text = f"{mod1}\n{mod2}" + self._run_import_modules(self.project, modules_list_text) + # They now exists and are linked to the project + existing_mods = self.module_branch_model.search( + [ + ("module_name", "in", [mod1, mod2]), + ("odoo_project_ids", "=", self.project.id), + ] + ) + self.assertEqual(len(existing_mods), 2) + # One of them matched the existing generic module + self.assertIn(mod1_branch_generic, existing_mods) + # Project modules are also created + self.assertEqual(len(existing_mods.odoo_project_module_ids), 2) + + def test_match_project_repo_module(self): + # Assign a repository to the project + self.project.repository_id = self.odoo_repository + self.project.odoo_version_id = self.branch + mod1 = "test1" + mod2 = "test2" + mod1_in_repo = self.wiz_model._get_module(mod1) + repo_branch = self._create_odoo_repository_branch( + self.odoo_repository, self.branch + ) + mod1_branch_in_repo = self._create_odoo_module_branch( + mod1_in_repo, + self.branch, + specific=True, + repository_branch_id=repo_branch.id, + ) + # Import them through the wizard + modules_list_text = f"{mod1}\n{mod2}" + self._run_import_modules(self.project, modules_list_text) + # They now exists and are linked to the project + existing_mods = self.module_branch_model.search( + [ + ("module_name", "in", [mod1, mod2]), + ("odoo_project_ids", "=", self.project.id), + ] + ) + self.assertEqual(len(existing_mods), 2) + # One of them matched the existing module hosted in project repository + self.assertIn(mod1_branch_in_repo, existing_mods) + # Project modules are also created + self.assertEqual(len(existing_mods.odoo_project_module_ids), 2) diff --git a/odoo_project/views/menu.xml b/odoo_project/views/menu.xml new file mode 100644 index 00000000..5b44227b --- /dev/null +++ b/odoo_project/views/menu.xml @@ -0,0 +1,11 @@ + + + + + diff --git a/odoo_project/views/odoo_module_branch.xml b/odoo_project/views/odoo_module_branch.xml new file mode 100644 index 00000000..4671da77 --- /dev/null +++ b/odoo_project/views/odoo_module_branch.xml @@ -0,0 +1,44 @@ + + + + + odoo.module.branch.form.inherit + odoo.module.branch + + + + + + + + + + + + odoo.module.branch.search.inherit + odoo.module.branch + + + + + + + + + + + + diff --git a/odoo_project/views/odoo_project.xml b/odoo_project/views/odoo_project.xml new file mode 100644 index 00000000..ac0e1556 --- /dev/null +++ b/odoo_project/views/odoo_project.xml @@ -0,0 +1,172 @@ + + + + + odoo.project.form + odoo.project + +
+
+
+ + +
+ +
+
+

+ +

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
diff --git a/odoo_project/wizards/__init__.py b/odoo_project/wizards/__init__.py new file mode 100644 index 00000000..7b4f991f --- /dev/null +++ b/odoo_project/wizards/__init__.py @@ -0,0 +1 @@ +from . import odoo_project_import_modules diff --git a/odoo_project/wizards/odoo_project_import_modules.py b/odoo_project/wizards/odoo_project_import_modules.py new file mode 100644 index 00000000..42858cc7 --- /dev/null +++ b/odoo_project/wizards/odoo_project_import_modules.py @@ -0,0 +1,146 @@ +# Copyright 2023 Camptocamp SA +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl) + +import re + +from odoo import api, fields, models + + +class OdooProjectImportModules(models.TransientModel): + _name = "odoo.project.import.modules" + _description = "Import modules for an Odoo project" + + odoo_project_id = fields.Many2one( + comodel_name="odoo.project", + string="Project", + required=True, + ) + odoo_version_id = fields.Many2one(related="odoo_project_id.odoo_version_id") + additional_module_ids = fields.Many2many( + comodel_name="odoo.module.branch", + string="Additional Modules", + domain="[('branch_id', '=', odoo_version_id), ('repository_id', '!=', False)]", + ) + modules_list = fields.Text( + help=( + "Copy/paste your list of technical module names here.\n" + "One module per line with an optional version number (separated by " + "any special character (space, tabulation, comma...)." + ), + ) + import_missing_dependencies = fields.Boolean( + default=False, + help=( + "Import module dependencies that are not part of the list above " + "to get an exhaustive list of modules installed in the project." + ), + ) + + @api.onchange("additional_module_ids") + def _onchange_additional_module_ids(self): + if self.additional_module_ids: + self.import_missing_dependencies = True + + def action_import(self): + """Import the modules for the given Odoo project.""" + self.ensure_one() + project_module_ids = [] + if self.modules_list: + project_module_ids = self._action_import_modules_list() + project_module_ids.extend(self._action_import_additional_modules()) + if self.import_missing_dependencies: + self._action_import_missing_dependencies(project_module_ids) + + def _action_import_modules_list(self): + """Import a fresh list of installed modules into the project.""" + self.odoo_project_id.sudo().project_module_ids = False + module_lines = list(filter(None, self.modules_list.split("\n"))) + project_module_ids = [] + for line in module_lines: + # Ignore comments + if line.strip().startswith("#"): + continue + data = re.split(r"\W+", line, maxsplit=1) + if len(data) > 1: + module_name, version = data + else: + module_name, version = data[0], False + # for module_name in module_names: + module = self._get_module(module_name) + if module.blacklisted: + continue + module_branch = self._get_module_branch(module) + project_module = self._get_project_module(module_branch, version) + project_module_ids.append(project_module.id) + self.odoo_project_id.sudo().project_module_ids = project_module_ids + return project_module_ids + + def _action_import_additional_modules(self): + """Import additional modules into the project.""" + project_module_ids = [] + for module_branch in self.additional_module_ids: + project_module = self._get_project_module(module_branch, version=False) + project_module_ids.append(project_module.id) + return project_module_ids + + def _action_import_missing_dependencies(self, project_module_ids): + """Complete list of modules by adding all dependencies.""" + project_modules = self.env["odoo.project.module"].browse(project_module_ids) + branch_modules = project_modules.module_branch_id + all_dependencies = branch_modules._get_recursive_dependencies() + missing_dependencies = all_dependencies - branch_modules + for missing_dependency in missing_dependencies: + self._get_project_module(missing_dependency, missing_dependency.version) + return True + + def _get_module(self, module_name): + """Return a `odoo.module` record. + + If it doesn't exist it'll be automatically created. + """ + module_model = self.env["odoo.module"] + module = module_model.search([("name", "=", module_name)]) + if not module: + module = module_model.sudo().create({"name": module_name}) + return module + + def _get_module_branch(self, module): + """Return a `odoo.module.branch` record. + + If it doesn't exist it'll be automatically created. + """ + module_branch_model = self.env["odoo.module.branch"] + module_branch = False + branch = self.odoo_project_id.odoo_version_id + module_branch = module_branch_model._find_or_create( + branch, module, self.odoo_project_id.repository_id + ) + if not module_branch.repository_branch_id and not module_branch.specific: + # If the module hasn't been found in existing repositories content, + # it could be available somewhere on GitHub as a PR that could help + # to identity its repository + module_branch.with_delay().action_find_pr_url() + return module_branch + + def _get_project_module(self, module_branch, version): + """Return a `odoo.project.module` record for the project. + + If it doesn't exist it'll be automatically created. + """ + project_module_model = self.env["odoo.project.module"] + domain = [ + ("module_branch_id", "=", module_branch.id), + ("odoo_project_id", "=", self.odoo_project_id.id), + ] + project_module = project_module_model.search(domain) + values = { + "module_branch_id": module_branch.id, + "odoo_project_id": self.odoo_project_id.id, + "installed_version": version, + } + if project_module: + project_module.sudo().write(values) + else: + # Create the module to make it available for the project + project_module = project_module_model.sudo().create(values) + return project_module diff --git a/odoo_project/wizards/odoo_project_import_modules.xml b/odoo_project/wizards/odoo_project_import_modules.xml new file mode 100644 index 00000000..2e8f7ec5 --- /dev/null +++ b/odoo_project/wizards/odoo_project_import_modules.xml @@ -0,0 +1,60 @@ + + + + + odoo.project.import.modules.form + odoo.project.import.modules + +
+ + + + + + + + + + + + + + + + + +
+
+
+
+
+ + + Import Project Modules + ir.actions.act_window + odoo.project.import.modules + form + new + +