Move 124 sale modules to oca-sale, create oca-project with 56 project modules from oca-workflow-process

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Ernad Husremovic 2025-08-30 18:04:10 +02:00
parent 9eb7ae5807
commit 6094c218b2
2332 changed files with 125826 additions and 0 deletions

View file

@ -0,0 +1,137 @@
================
Project Sequence
================
..
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! This file is generated by oca-gen-addon-readme !!
!! changes will be overwritten. !!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! source digest: sha256:caf8dec5efbc49cae19c67dce6e7a6405850468cbc9ad9e642dc6209e1b6bbfb
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
.. |badge1| image:: https://img.shields.io/badge/maturity-Alpha-red.png
:target: https://odoo-community.org/page/development-status
:alt: Alpha
.. |badge2| image:: https://img.shields.io/badge/licence-LGPL--3-blue.png
:target: http://www.gnu.org/licenses/lgpl-3.0-standalone.html
:alt: License: LGPL-3
.. |badge3| image:: https://img.shields.io/badge/github-OCA%2Fproject-lightgray.png?logo=github
:target: https://github.com/OCA/project/tree/16.0/project_sequence
:alt: OCA/project
.. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png
:target: https://translation.odoo-community.org/projects/project-16-0/project-16-0-project_sequence
: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/project&target_branch=16.0
:alt: Try me on Runboat
|badge1| |badge2| |badge3| |badge4| |badge5|
.. This file must be max 2-3 paragraphs, and is required.
It should explain *why* this module exists.
Add a sequence field to projects, filled automatically and add a code sequence filter in tree view project.
.. IMPORTANT::
This is an alpha version, the data model and design can change at any time without warning.
Only for development or testing purpose, do not use in production.
`More details on development status <https://odoo-community.org/page/development-status>`_
**Table of contents**
.. contents::
:local:
Configuration
=============
To change the project display name pattern, follow these steps:
#. Go to *Project > Configuration > Settings*.
#. Edit the *Project display name pattern* field.
The default format is ``%(sequence_code)s - %(name)s``. You can use those
same placeholders to customize the pattern.
Usage
=====
.. This file must be present. It contains the usage instructions
for end-users. As all other rst files included in the README,
it MUST NOT contain reStructuredText sections
only body text (paragraphs, lists, tables, etc). Should you need
a more elaborate structure to explain the addon, please create a
Sphinx documentation (which may include this file as a "quick start"
section).
To use this module, you need to:
#. Go to the project icon.
#. Click the button "create" to create a new project
#. Fill in the field Project name and click the "create" button
#. Now in the Kanban view see the project name when you are created
#. Repeat this operation creating another project without the name.
Bug Tracker
===========
Bugs are tracked on `GitHub Issues <https://github.com/OCA/project/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 <https://github.com/OCA/project/issues/new?body=module:%20project_sequence%0Aversion:%2016.0%0A%0A**Steps%20to%20reproduce**%0A-%20...%0A%0A**Current%20behavior**%0A%0A**Expected%20behavior**>`_.
Do not contact contributors directly about support or help with technical issues.
Credits
=======
Authors
~~~~~~~
* Moduon
Contributors
~~~~~~~~~~~~
* Andrea Cattalani (`Moduon <https://www.moduon.team/>`__)
* Jairo Llopis (`Moduon <https://www.moduon.team/>`__)
* Nils Coenen <nils.coenen@nico-solutions.de>
Other credits
~~~~~~~~~~~~~
.. This file is optional and contains additional credits, other than
authors, contributors, and maintainers.
The development of this module has been financially supported by:
* Moduon
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.
.. |maintainer-yajo| image:: https://github.com/yajo.png?size=40px
:target: https://github.com/yajo
:alt: yajo
.. |maintainer-anddago78| image:: https://github.com/anddago78.png?size=40px
:target: https://github.com/anddago78
:alt: anddago78
Current `maintainers <https://odoo-community.org/page/maintainer-role>`__:
|maintainer-yajo| |maintainer-anddago78|
This module is part of the `OCA/project <https://github.com/OCA/project/tree/16.0/project_sequence>`_ project on GitHub.
You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute.

View file

@ -0,0 +1,2 @@
from . import models
from . import wizards

View file

@ -0,0 +1,22 @@
# Copyright 2023 Moduon Team S.L.
# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl-3.0)
{
"name": "Project Sequence",
"summary": "Add a sequence field to projects, filled automatically",
"version": "16.0.1.0.1",
"development_status": "Alpha",
"category": "Services/Project",
"website": "https://github.com/OCA/project",
"author": "Moduon, Odoo Community Association (OCA)",
"maintainers": ["yajo", "anddago78"],
"license": "LGPL-3",
"application": False,
"installable": True,
"depends": ["project"],
"data": [
"data/ir_sequence.xml",
"views/project_project.xml",
"wizards/res_config_settings_view.xml",
],
}

View file

@ -0,0 +1,13 @@
<?xml version="1.0" encoding="utf-8" ?>
<!-- Copyright 2023 Moduon Team S.L.
License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl-3.0) -->
<data noupdate="1">
<record id="seq_project_sequence" model="ir.sequence">
<field name="name">Project sequence</field>
<field name="code">project.sequence</field>
<field name="prefix">%(range_y)s-</field>
<field name="use_date_range">True</field>
<field name="padding">5</field>
<field name="company_id" eval="False" />
</record>
</data>

View file

@ -0,0 +1,68 @@
# Translation of Odoo Server.
# This file contains the translation of the following modules:
# * project_sequence
#
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: project_sequence
#: model:ir.model,name:project_sequence.model_res_config_settings
msgid "Config Settings"
msgstr "Postavke"
#. module: project_sequence
#: model:ir.model.fields,field_description:project_sequence.field_project_project__name
msgid "Name"
msgstr "Naziv:"
#. module: project_sequence
#: model:ir.model.fields,help:project_sequence.field_project_project__name
msgid ""
"Name of your project. It can be anything you want e.g. the name of a "
"customer or a service."
msgstr ""
#. module: project_sequence
#: model:ir.model,name:project_sequence.model_project_project
msgid "Project"
msgstr "Projekat"
#. module: project_sequence
#: model:ir.model.fields,field_description:project_sequence.field_res_config_settings__project_display_name_pattern
msgid "Project Display Name Pattern"
msgstr "Obrazac imena prikaza projekta"
#. module: project_sequence
#: model:ir.model.constraint,message:project_sequence.constraint_project_project_name_required
msgid "Project name is required"
msgstr "Ime projekta je obavezno"
#. module: project_sequence
#: model:ir.model.fields,field_description:project_sequence.field_project_project__sequence_code
msgid "Sequence Code"
msgstr "Šifra sekvence"
#. module: project_sequence
#: model:ir.model.constraint,message:project_sequence.constraint_project_project_sequence_code_unique
msgid "Sequence code must be unique"
msgstr "Kod sekvence mora biti jedinstven"
#. module: project_sequence
#: model_terms:ir.ui.view,arch_db:project_sequence.project_sequence_form_view
msgid "Sequence code:"
msgstr "Kod sekvence:"
#. module: project_sequence
#: model:ir.model.fields,help:project_sequence.field_res_config_settings__project_display_name_pattern
msgid ""
"Use %(sequence_code)s and %(name)s to include the sequence code and the name"
" of the project in the display name."
msgstr ""

View file

@ -0,0 +1,75 @@
# Translation of Odoo Server.
# This file contains the translation of the following modules:
# * project_sequence
#
msgid ""
msgstr ""
"Project-Id-Version: Odoo Server 16.0\n"
"Report-Msgid-Bugs-To: \n"
"PO-Revision-Date: 2023-08-08 15:08+0000\n"
"Last-Translator: Nils Coenen <nils.coenen@nico-solutions.de>\n"
"Language-Team: none\n"
"Language: de\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: \n"
"Plural-Forms: nplurals=2; plural=n != 1;\n"
"X-Generator: Weblate 4.17\n"
#. module: project_sequence
#: model:ir.model,name:project_sequence.model_res_config_settings
msgid "Config Settings"
msgstr "Konfigurationseinstellungen"
#. module: project_sequence
#: model:ir.model.fields,field_description:project_sequence.field_project_project__name
msgid "Name"
msgstr "Name"
#. module: project_sequence
#: model:ir.model.fields,help:project_sequence.field_project_project__name
msgid ""
"Name of your project. It can be anything you want e.g. the name of a "
"customer or a service."
msgstr ""
"Name Ihres Projekts. Es kann alles sein, was Sie wollen, z.B. der Name eines "
"Kunden oder einer Dienstleistung."
#. module: project_sequence
#: model:ir.model,name:project_sequence.model_project_project
msgid "Project"
msgstr "Projekt"
#. module: project_sequence
#: model:ir.model.fields,field_description:project_sequence.field_res_config_settings__project_display_name_pattern
msgid "Project Display Name Pattern"
msgstr "Muster für den Projektanzeigenamen"
#. module: project_sequence
#: model:ir.model.constraint,message:project_sequence.constraint_project_project_name_required
msgid "Project name is required"
msgstr "Projektname ist erforderlich"
#. module: project_sequence
#: model:ir.model.fields,field_description:project_sequence.field_project_project__sequence_code
msgid "Sequence Code"
msgstr "Sequenzcode"
#. module: project_sequence
#: model:ir.model.constraint,message:project_sequence.constraint_project_project_sequence_code_unique
msgid "Sequence code must be unique"
msgstr "Der Sequenzcode muss eindeutig sein"
#. module: project_sequence
#: model_terms:ir.ui.view,arch_db:project_sequence.project_sequence_form_view
msgid "Sequence code:"
msgstr "Sequenzcode:"
#. module: project_sequence
#: model:ir.model.fields,help:project_sequence.field_res_config_settings__project_display_name_pattern
msgid ""
"Use %(sequence_code)s and %(name)s to include the sequence code and the name "
"of the project in the display name."
msgstr ""
"Verwenden Sie %(sequence_code)s und %(name)s, um den Sequenzcode und den "
"Namen des Projekts in den Anzeigenamen aufzunehmen."

View file

@ -0,0 +1,88 @@
# Translation of Odoo Server.
# This file contains the translation of the following modules:
# * project_sequence
#
msgid ""
msgstr ""
"Project-Id-Version: Odoo Server 14.0+e\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2023-04-10 10:29+0000\n"
"PO-Revision-Date: 2023-09-03 13:36+0000\n"
"Last-Translator: Ivorra78 <informatica@totmaterial.es>\n"
"Language-Team: \n"
"Language: es\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=n != 1;\n"
"X-Generator: Weblate 4.17\n"
#. module: project_sequence
#: model:ir.model,name:project_sequence.model_res_config_settings
msgid "Config Settings"
msgstr "Configuración de Ajustes"
#. module: project_sequence
#: model:ir.model.fields,field_description:project_sequence.field_project_project__name
msgid "Name"
msgstr "Nombre"
#. module: project_sequence
#: model:ir.model.fields,help:project_sequence.field_project_project__name
msgid ""
"Name of your project. It can be anything you want e.g. the name of a "
"customer or a service."
msgstr ""
"Nombre de su proyecto. Puede ser cualquier cosa, por ejemplo, el nombre de "
"un cliente o de un servicio."
#. module: project_sequence
#: model:ir.model,name:project_sequence.model_project_project
msgid "Project"
msgstr "Proyecto"
#. module: project_sequence
#: model:ir.model.fields,field_description:project_sequence.field_res_config_settings__project_display_name_pattern
msgid "Project Display Name Pattern"
msgstr "Patrón de nombre para mostrar del proyecto"
#. module: project_sequence
#: model:ir.model.constraint,message:project_sequence.constraint_project_project_name_required
msgid "Project name is required"
msgstr "El nombre del proyecto es obligatorio"
#. module: project_sequence
#: model:ir.model.fields,field_description:project_sequence.field_project_project__sequence_code
msgid "Sequence Code"
msgstr "Código secuencial"
#. module: project_sequence
#: model:ir.model.constraint,message:project_sequence.constraint_project_project_sequence_code_unique
msgid "Sequence code must be unique"
msgstr "El código secuencial debe ser único"
#. module: project_sequence
#: model_terms:ir.ui.view,arch_db:project_sequence.project_sequence_form_view
msgid "Sequence code:"
msgstr "Código secuencial:"
#. module: project_sequence
#: model:ir.model.fields,help:project_sequence.field_res_config_settings__project_display_name_pattern
msgid ""
"Use %(sequence_code)s and %(name)s to include the sequence code and the name "
"of the project in the display name."
msgstr ""
"Utilice %(sequence_code)s y %(name)s para incluir el código de secuencia y "
"el nombre del proyecto en el nombre de visualización."
#~ msgid "Display Name"
#~ msgstr "Nombre"
#~ msgid "ID"
#~ msgstr "ID"
#~ msgid "Last Modified on"
#~ msgstr "Última modificación el"
#~ msgid "Code"
#~ msgstr "Código"

View file

@ -0,0 +1,78 @@
# Translation of Odoo Server.
# This file contains the translation of the following modules:
# * project_sequence
#
msgid ""
msgstr ""
"Project-Id-Version: Odoo Server 15.0\n"
"Report-Msgid-Bugs-To: \n"
"PO-Revision-Date: 2023-07-31 10:11+0000\n"
"Last-Translator: mymage <stefano.consolaro@mymage.it>\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"
"X-Generator: Weblate 4.17\n"
#. module: project_sequence
#: model:ir.model,name:project_sequence.model_res_config_settings
msgid "Config Settings"
msgstr "Impostazioni configurazione"
#. module: project_sequence
#: model:ir.model.fields,field_description:project_sequence.field_project_project__name
msgid "Name"
msgstr "Nome"
#. module: project_sequence
#: model:ir.model.fields,help:project_sequence.field_project_project__name
msgid ""
"Name of your project. It can be anything you want e.g. the name of a "
"customer or a service."
msgstr ""
"Nome del progetto. Può essere qualsiasi cosa es. il nome di un cliente o di "
"un servizio."
#. module: project_sequence
#: model:ir.model,name:project_sequence.model_project_project
msgid "Project"
msgstr "Progetto"
#. module: project_sequence
#: model:ir.model.fields,field_description:project_sequence.field_res_config_settings__project_display_name_pattern
msgid "Project Display Name Pattern"
msgstr "Nome visualizzato schema progetto"
#. module: project_sequence
#: model:ir.model.constraint,message:project_sequence.constraint_project_project_name_required
msgid "Project name is required"
msgstr "È richiesto il nome progetto"
#. module: project_sequence
#: model:ir.model.fields,field_description:project_sequence.field_project_project__sequence_code
msgid "Sequence Code"
msgstr "Codice sequenza"
#. module: project_sequence
#: model:ir.model.constraint,message:project_sequence.constraint_project_project_sequence_code_unique
msgid "Sequence code must be unique"
msgstr "Il codice sequenza deve essere univoco"
#. module: project_sequence
#: model_terms:ir.ui.view,arch_db:project_sequence.project_sequence_form_view
msgid "Sequence code:"
msgstr "Codice sequenza:"
#. module: project_sequence
#: model:ir.model.fields,help:project_sequence.field_res_config_settings__project_display_name_pattern
msgid ""
"Use %(sequence_code)s and %(name)s to include the sequence code and the name "
"of the project in the display name."
msgstr ""
"Utilizzare %(sequence_code)s e %(name)s per includere il codice sequenza e "
"il nome del progetto nel nome visualizzato."
#~ msgid "WBS element"
#~ msgstr "Elemento WBS"

View file

@ -0,0 +1,75 @@
# Translation of Odoo Server.
# This file contains the translation of the following modules:
# * project_sequence
#
msgid ""
msgstr ""
"Project-Id-Version: Odoo Server 16.0\n"
"Report-Msgid-Bugs-To: \n"
"PO-Revision-Date: 2023-10-09 02:52+0000\n"
"Last-Translator: \"Jan Tapper [Onestein]\" <j.tapper@onestein.nl>\n"
"Language-Team: none\n"
"Language: nl\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: \n"
"Plural-Forms: nplurals=2; plural=n != 1;\n"
"X-Generator: Weblate 4.17\n"
#. module: project_sequence
#: model:ir.model,name:project_sequence.model_res_config_settings
msgid "Config Settings"
msgstr "Configuratie-instellingen"
#. module: project_sequence
#: model:ir.model.fields,field_description:project_sequence.field_project_project__name
msgid "Name"
msgstr "Naam"
#. module: project_sequence
#: model:ir.model.fields,help:project_sequence.field_project_project__name
msgid ""
"Name of your project. It can be anything you want e.g. the name of a "
"customer or a service."
msgstr ""
"Naam van uw project. Het kan alles zijn wat je wilt, b.v. de naam van een "
"klant of dienst."
#. module: project_sequence
#: model:ir.model,name:project_sequence.model_project_project
msgid "Project"
msgstr ""
#. module: project_sequence
#: model:ir.model.fields,field_description:project_sequence.field_res_config_settings__project_display_name_pattern
msgid "Project Display Name Pattern"
msgstr "Patroon weergavenaam project"
#. module: project_sequence
#: model:ir.model.constraint,message:project_sequence.constraint_project_project_name_required
msgid "Project name is required"
msgstr "Projectnaam is vereist"
#. module: project_sequence
#: model:ir.model.fields,field_description:project_sequence.field_project_project__sequence_code
msgid "Sequence Code"
msgstr "Sequentiecode"
#. module: project_sequence
#: model:ir.model.constraint,message:project_sequence.constraint_project_project_sequence_code_unique
msgid "Sequence code must be unique"
msgstr "De sequentiecode moet uniek zijn"
#. module: project_sequence
#: model_terms:ir.ui.view,arch_db:project_sequence.project_sequence_form_view
msgid "Sequence code:"
msgstr "Sequentiecode:"
#. module: project_sequence
#: model:ir.model.fields,help:project_sequence.field_res_config_settings__project_display_name_pattern
msgid ""
"Use %(sequence_code)s and %(name)s to include the sequence code and the name "
"of the project in the display name."
msgstr ""
"Gebruik %(sequence_code)s en %(name)s om de sequentiecode en de naam van het "
"project op te nemen in de weergavenaam."

View file

@ -0,0 +1,68 @@
# Translation of Odoo Server.
# This file contains the translation of the following modules:
# * project_sequence
#
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: project_sequence
#: model:ir.model,name:project_sequence.model_res_config_settings
msgid "Config Settings"
msgstr ""
#. module: project_sequence
#: model:ir.model.fields,field_description:project_sequence.field_project_project__name
msgid "Name"
msgstr ""
#. module: project_sequence
#: model:ir.model.fields,help:project_sequence.field_project_project__name
msgid ""
"Name of your project. It can be anything you want e.g. the name of a "
"customer or a service."
msgstr ""
#. module: project_sequence
#: model:ir.model,name:project_sequence.model_project_project
msgid "Project"
msgstr ""
#. module: project_sequence
#: model:ir.model.fields,field_description:project_sequence.field_res_config_settings__project_display_name_pattern
msgid "Project Display Name Pattern"
msgstr ""
#. module: project_sequence
#: model:ir.model.constraint,message:project_sequence.constraint_project_project_name_required
msgid "Project name is required"
msgstr ""
#. module: project_sequence
#: model:ir.model.fields,field_description:project_sequence.field_project_project__sequence_code
msgid "Sequence Code"
msgstr ""
#. module: project_sequence
#: model:ir.model.constraint,message:project_sequence.constraint_project_project_sequence_code_unique
msgid "Sequence code must be unique"
msgstr ""
#. module: project_sequence
#: model_terms:ir.ui.view,arch_db:project_sequence.project_sequence_form_view
msgid "Sequence code:"
msgstr ""
#. module: project_sequence
#: model:ir.model.fields,help:project_sequence.field_res_config_settings__project_display_name_pattern
msgid ""
"Use %(sequence_code)s and %(name)s to include the sequence code and the name"
" of the project in the display name."
msgstr ""

View file

@ -0,0 +1 @@
from . import project_project

View file

@ -0,0 +1,98 @@
# Copyright 2023 Moduon Team S.L.
# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl-3.0)
from odoo import api, fields, models
class ProjectProject(models.Model):
_inherit = "project.project"
_sql_constraints = [
# Ensure compatibility with other modules that always expect a value in name
("name_required", "CHECK(name IS NOT NULL)", "Project name is required"),
(
"sequence_code_unique",
"UNIQUE(sequence_code)",
"Sequence code must be unique",
),
]
sequence_code = fields.Char(
copy=False,
readonly=True,
)
name = fields.Char(
# We actually require it with the SQL constraint, but it is disabled
# here to let users create/write projects without name, and let this module
# add a default name if needed
required=False,
)
def _sync_analytic_account_name(self):
"""Set analytic account name equal to project's display name."""
for rec in self:
if not rec.analytic_account_id:
continue
rec.analytic_account_id.name = rec.display_name
def name_get(self):
"""Prefix name with sequence code if they are different."""
old_result = super().name_get()
result = []
sequence_pattern = (
self.env["ir.config_parameter"]
.sudo()
.get_param(
"project_sequence.display_name_pattern",
default="%(sequence_code)s - %(name)s",
)
)
for id_, name in old_result:
project = self.browse(id_)
if project.sequence_code and project.sequence_code != name:
name = sequence_pattern % {
"name": name,
"sequence_code": project.sequence_code,
}
result.append((id_, name))
return result
@api.model
def name_search(self, name="", args=None, operator="ilike", limit=100):
"""Allow searching by sequence code by default."""
# Do not add any domain when user just clicked on search widget
if not (name == "" and operator == "ilike"):
# The dangling | is needed to combine with the domain added by super()
args = (args or []) + ["|", ("sequence_code", operator, name)]
return super().name_search(name, args, operator, limit)
@api.model_create_multi
def create(self, vals_list):
"""Apply sequence code and a default name if not set."""
# It is important to set sequence_code before calling super() because
# other modules such as hr_timesheet expect the name to always have a value
for vals in vals_list:
if not vals.get("sequence_code", False):
vals["sequence_code"] = self.env["ir.sequence"].next_by_code(
"project.sequence"
)
if not vals.get("name"):
vals["name"] = vals["sequence_code"]
res = super().create(vals_list)
# The analytic account is created with just the project name, but
# it is more useful to let it contain the project sequence too
res._sync_analytic_account_name()
return res
def write(self, vals):
"""Sync name and analytic account name when name is changed."""
# If name isn't changing, nothing special to do
if "name" not in vals and "sequence_name" not in vals:
return super().write(vals)
# When changing name, we need to update the analytic account name too
for one in self:
sequence_code = vals.get("sequence_code", one.sequence_code)
name = vals.get("name") or sequence_code
super().write(dict(vals, name=name))
self._sync_analytic_account_name()
return True

View file

@ -0,0 +1,7 @@
To change the project display name pattern, follow these steps:
#. Go to *Project > Configuration > Settings*.
#. Edit the *Project display name pattern* field.
The default format is ``%(sequence_code)s - %(name)s``. You can use those
same placeholders to customize the pattern.

View file

@ -0,0 +1,3 @@
* Andrea Cattalani (`Moduon <https://www.moduon.team/>`__)
* Jairo Llopis (`Moduon <https://www.moduon.team/>`__)
* Nils Coenen <nils.coenen@nico-solutions.de>

View file

@ -0,0 +1,6 @@
.. This file is optional and contains additional credits, other than
authors, contributors, and maintainers.
The development of this module has been financially supported by:
* Moduon

View file

@ -0,0 +1,4 @@
.. This file must be max 2-3 paragraphs, and is required.
It should explain *why* this module exists.
Add a sequence field to projects, filled automatically and add a code sequence filter in tree view project.

View file

@ -0,0 +1,15 @@
.. This file must be present. It contains the usage instructions
for end-users. As all other rst files included in the README,
it MUST NOT contain reStructuredText sections
only body text (paragraphs, lists, tables, etc). Should you need
a more elaborate structure to explain the addon, please create a
Sphinx documentation (which may include this file as a "quick start"
section).
To use this module, you need to:
#. Go to the project icon.
#. Click the button "create" to create a new project
#. Fill in the field Project name and click the "create" button
#. Now in the Kanban view see the project name when you are created
#. Repeat this operation creating another project without the name.

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.2 KiB

View file

@ -0,0 +1,477 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta name="generator" content="Docutils: https://docutils.sourceforge.io/" />
<title>Project Sequence</title>
<style type="text/css">
/*
:Author: David Goodger (goodger@python.org)
:Id: $Id: html4css1.css 9511 2024-01-13 09:50:07Z milde $
:Copyright: This stylesheet has been placed in the public domain.
Default cascading style sheet for the HTML output of Docutils.
Despite the name, some widely supported CSS2 features are used.
See https://docutils.sourceforge.io/docs/howto/html-stylesheets.html for how to
customize this style sheet.
*/
/* used to remove borders from tables and images */
.borderless, table.borderless td, table.borderless th {
border: 0 }
table.borderless td, table.borderless th {
/* Override padding for "table.docutils td" with "! important".
The right padding separates the table cells. */
padding: 0 0.5em 0 0 ! important }
.first {
/* Override more specific margin styles with "! important". */
margin-top: 0 ! important }
.last, .with-subtitle {
margin-bottom: 0 ! important }
.hidden {
display: none }
.subscript {
vertical-align: sub;
font-size: smaller }
.superscript {
vertical-align: super;
font-size: smaller }
a.toc-backref {
text-decoration: none ;
color: black }
blockquote.epigraph {
margin: 2em 5em ; }
dl.docutils dd {
margin-bottom: 0.5em }
object[type="image/svg+xml"], object[type="application/x-shockwave-flash"] {
overflow: hidden;
}
/* Uncomment (and remove this text!) to get bold-faced definition list terms
dl.docutils dt {
font-weight: bold }
*/
div.abstract {
margin: 2em 5em }
div.abstract p.topic-title {
font-weight: bold ;
text-align: center }
div.admonition, div.attention, div.caution, div.danger, div.error,
div.hint, div.important, div.note, div.tip, div.warning {
margin: 2em ;
border: medium outset ;
padding: 1em }
div.admonition p.admonition-title, div.hint p.admonition-title,
div.important p.admonition-title, div.note p.admonition-title,
div.tip p.admonition-title {
font-weight: bold ;
font-family: sans-serif }
div.attention p.admonition-title, div.caution p.admonition-title,
div.danger p.admonition-title, div.error p.admonition-title,
div.warning p.admonition-title, .code .error {
color: red ;
font-weight: bold ;
font-family: sans-serif }
/* Uncomment (and remove this text!) to get reduced vertical space in
compound paragraphs.
div.compound .compound-first, div.compound .compound-middle {
margin-bottom: 0.5em }
div.compound .compound-last, div.compound .compound-middle {
margin-top: 0.5em }
*/
div.dedication {
margin: 2em 5em ;
text-align: center ;
font-style: italic }
div.dedication p.topic-title {
font-weight: bold ;
font-style: normal }
div.figure {
margin-left: 2em ;
margin-right: 2em }
div.footer, div.header {
clear: both;
font-size: smaller }
div.line-block {
display: block ;
margin-top: 1em ;
margin-bottom: 1em }
div.line-block div.line-block {
margin-top: 0 ;
margin-bottom: 0 ;
margin-left: 1.5em }
div.sidebar {
margin: 0 0 0.5em 1em ;
border: medium outset ;
padding: 1em ;
background-color: #ffffee ;
width: 40% ;
float: right ;
clear: right }
div.sidebar p.rubric {
font-family: sans-serif ;
font-size: medium }
div.system-messages {
margin: 5em }
div.system-messages h1 {
color: red }
div.system-message {
border: medium outset ;
padding: 1em }
div.system-message p.system-message-title {
color: red ;
font-weight: bold }
div.topic {
margin: 2em }
h1.section-subtitle, h2.section-subtitle, h3.section-subtitle,
h4.section-subtitle, h5.section-subtitle, h6.section-subtitle {
margin-top: 0.4em }
h1.title {
text-align: center }
h2.subtitle {
text-align: center }
hr.docutils {
width: 75% }
img.align-left, .figure.align-left, object.align-left, table.align-left {
clear: left ;
float: left ;
margin-right: 1em }
img.align-right, .figure.align-right, object.align-right, table.align-right {
clear: right ;
float: right ;
margin-left: 1em }
img.align-center, .figure.align-center, object.align-center {
display: block;
margin-left: auto;
margin-right: auto;
}
table.align-center {
margin-left: auto;
margin-right: auto;
}
.align-left {
text-align: left }
.align-center {
clear: both ;
text-align: center }
.align-right {
text-align: right }
/* reset inner alignment in figures */
div.align-right {
text-align: inherit }
/* div.align-center * { */
/* text-align: left } */
.align-top {
vertical-align: top }
.align-middle {
vertical-align: middle }
.align-bottom {
vertical-align: bottom }
ol.simple, ul.simple {
margin-bottom: 1em }
ol.arabic {
list-style: decimal }
ol.loweralpha {
list-style: lower-alpha }
ol.upperalpha {
list-style: upper-alpha }
ol.lowerroman {
list-style: lower-roman }
ol.upperroman {
list-style: upper-roman }
p.attribution {
text-align: right ;
margin-left: 50% }
p.caption {
font-style: italic }
p.credits {
font-style: italic ;
font-size: smaller }
p.label {
white-space: nowrap }
p.rubric {
font-weight: bold ;
font-size: larger ;
color: maroon ;
text-align: center }
p.sidebar-title {
font-family: sans-serif ;
font-weight: bold ;
font-size: larger }
p.sidebar-subtitle {
font-family: sans-serif ;
font-weight: bold }
p.topic-title {
font-weight: bold }
pre.address {
margin-bottom: 0 ;
margin-top: 0 ;
font: inherit }
pre.literal-block, pre.doctest-block, pre.math, pre.code {
margin-left: 2em ;
margin-right: 2em }
pre.code .ln { color: gray; } /* line numbers */
pre.code, code { background-color: #eeeeee }
pre.code .comment, code .comment { color: #5C6576 }
pre.code .keyword, code .keyword { color: #3B0D06; font-weight: bold }
pre.code .literal.string, code .literal.string { color: #0C5404 }
pre.code .name.builtin, code .name.builtin { color: #352B84 }
pre.code .deleted, code .deleted { background-color: #DEB0A1}
pre.code .inserted, code .inserted { background-color: #A3D289}
span.classifier {
font-family: sans-serif ;
font-style: oblique }
span.classifier-delimiter {
font-family: sans-serif ;
font-weight: bold }
span.interpreted {
font-family: sans-serif }
span.option {
white-space: nowrap }
span.pre {
white-space: pre }
span.problematic, pre.problematic {
color: red }
span.section-subtitle {
/* font-size relative to parent (h1..h6 element) */
font-size: 80% }
table.citation {
border-left: solid 1px gray;
margin-left: 1px }
table.docinfo {
margin: 2em 4em }
table.docutils {
margin-top: 0.5em ;
margin-bottom: 0.5em }
table.footnote {
border-left: solid 1px black;
margin-left: 1px }
table.docutils td, table.docutils th,
table.docinfo td, table.docinfo th {
padding-left: 0.5em ;
padding-right: 0.5em ;
vertical-align: top }
table.docutils th.field-name, table.docinfo th.docinfo-name {
font-weight: bold ;
text-align: left ;
white-space: nowrap ;
padding-left: 0 }
/* "booktabs" style (no vertical lines) */
table.docutils.booktabs {
border: 0px;
border-top: 2px solid;
border-bottom: 2px solid;
border-collapse: collapse;
}
table.docutils.booktabs * {
border: 0px;
}
table.docutils.booktabs th {
border-bottom: thin solid;
text-align: left;
}
h1 tt.docutils, h2 tt.docutils, h3 tt.docutils,
h4 tt.docutils, h5 tt.docutils, h6 tt.docutils {
font-size: 100% }
ul.auto-toc {
list-style-type: none }
</style>
</head>
<body>
<div class="document" id="project-sequence">
<h1 class="title">Project Sequence</h1>
<!-- !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! This file is generated by oca-gen-addon-readme !!
!! changes will be overwritten. !!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! source digest: sha256:caf8dec5efbc49cae19c67dce6e7a6405850468cbc9ad9e642dc6209e1b6bbfb
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -->
<p><a class="reference external image-reference" href="https://odoo-community.org/page/development-status"><img alt="Alpha" src="https://img.shields.io/badge/maturity-Alpha-red.png" /></a> <a class="reference external image-reference" href="http://www.gnu.org/licenses/lgpl-3.0-standalone.html"><img alt="License: LGPL-3" src="https://img.shields.io/badge/licence-LGPL--3-blue.png" /></a> <a class="reference external image-reference" href="https://github.com/OCA/project/tree/16.0/project_sequence"><img alt="OCA/project" src="https://img.shields.io/badge/github-OCA%2Fproject-lightgray.png?logo=github" /></a> <a class="reference external image-reference" href="https://translation.odoo-community.org/projects/project-16-0/project-16-0-project_sequence"><img alt="Translate me on Weblate" src="https://img.shields.io/badge/weblate-Translate%20me-F47D42.png" /></a> <a class="reference external image-reference" href="https://runboat.odoo-community.org/builds?repo=OCA/project&amp;target_branch=16.0"><img alt="Try me on Runboat" src="https://img.shields.io/badge/runboat-Try%20me-875A7B.png" /></a></p>
<!-- This file must be max 2-3 paragraphs, and is required.
It should explain *why* this module exists. -->
<p>Add a sequence field to projects, filled automatically and add a code sequence filter in tree view project.</p>
<div class="admonition important">
<p class="first admonition-title">Important</p>
<p class="last">This is an alpha version, the data model and design can change at any time without warning.
Only for development or testing purpose, do not use in production.
<a class="reference external" href="https://odoo-community.org/page/development-status">More details on development status</a></p>
</div>
<p><strong>Table of contents</strong></p>
<div class="contents local topic" id="contents">
<ul class="simple">
<li><a class="reference internal" href="#configuration" id="toc-entry-1">Configuration</a></li>
<li><a class="reference internal" href="#usage" id="toc-entry-2">Usage</a></li>
<li><a class="reference internal" href="#bug-tracker" id="toc-entry-3">Bug Tracker</a></li>
<li><a class="reference internal" href="#credits" id="toc-entry-4">Credits</a><ul>
<li><a class="reference internal" href="#authors" id="toc-entry-5">Authors</a></li>
<li><a class="reference internal" href="#contributors" id="toc-entry-6">Contributors</a></li>
<li><a class="reference internal" href="#other-credits" id="toc-entry-7">Other credits</a></li>
<li><a class="reference internal" href="#maintainers" id="toc-entry-8">Maintainers</a></li>
</ul>
</li>
</ul>
</div>
<div class="section" id="configuration">
<h1><a class="toc-backref" href="#toc-entry-1">Configuration</a></h1>
<p>To change the project display name pattern, follow these steps:</p>
<ol class="arabic">
<li><p class="first">Go to <em>Project &gt; Configuration &gt; Settings</em>.</p>
</li>
<li><p class="first">Edit the <em>Project display name pattern</em> field.</p>
<p>The default format is <tt class="docutils literal">%(sequence_code)s - %(name)s</tt>. You can use those
same placeholders to customize the pattern.</p>
</li>
</ol>
</div>
<div class="section" id="usage">
<h1><a class="toc-backref" href="#toc-entry-2">Usage</a></h1>
<!-- This file must be present. It contains the usage instructions
for end-users. As all other rst files included in the README,
it MUST NOT contain reStructuredText sections
only body text (paragraphs, lists, tables, etc). Should you need
a more elaborate structure to explain the addon, please create a
Sphinx documentation (which may include this file as a "quick start"
section). -->
<p>To use this module, you need to:</p>
<ol class="arabic simple">
<li>Go to the project icon.</li>
<li>Click the button “create” to create a new project</li>
<li>Fill in the field Project name and click the “create” button</li>
<li>Now in the Kanban view see the project name when you are created</li>
<li>Repeat this operation creating another project without the name.</li>
</ol>
</div>
<div class="section" id="bug-tracker">
<h1><a class="toc-backref" href="#toc-entry-3">Bug Tracker</a></h1>
<p>Bugs are tracked on <a class="reference external" href="https://github.com/OCA/project/issues">GitHub Issues</a>.
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
<a class="reference external" href="https://github.com/OCA/project/issues/new?body=module:%20project_sequence%0Aversion:%2016.0%0A%0A**Steps%20to%20reproduce**%0A-%20...%0A%0A**Current%20behavior**%0A%0A**Expected%20behavior**">feedback</a>.</p>
<p>Do not contact contributors directly about support or help with technical issues.</p>
</div>
<div class="section" id="credits">
<h1><a class="toc-backref" href="#toc-entry-4">Credits</a></h1>
<div class="section" id="authors">
<h2><a class="toc-backref" href="#toc-entry-5">Authors</a></h2>
<ul class="simple">
<li>Moduon</li>
</ul>
</div>
<div class="section" id="contributors">
<h2><a class="toc-backref" href="#toc-entry-6">Contributors</a></h2>
<ul class="simple">
<li>Andrea Cattalani (<a class="reference external" href="https://www.moduon.team/">Moduon</a>)</li>
<li>Jairo Llopis (<a class="reference external" href="https://www.moduon.team/">Moduon</a>)</li>
<li>Nils Coenen &lt;<a class="reference external" href="mailto:nils.coenen&#64;nico-solutions.de">nils.coenen&#64;nico-solutions.de</a>&gt;</li>
</ul>
</div>
<div class="section" id="other-credits">
<h2><a class="toc-backref" href="#toc-entry-7">Other credits</a></h2>
<!-- This file is optional and contains additional credits, other than
authors, contributors, and maintainers. -->
<p>The development of this module has been financially supported by:</p>
<ul class="simple">
<li>Moduon</li>
</ul>
</div>
<div class="section" id="maintainers">
<h2><a class="toc-backref" href="#toc-entry-8">Maintainers</a></h2>
<p>This module is maintained by the OCA.</p>
<a class="reference external image-reference" href="https://odoo-community.org">
<img alt="Odoo Community Association" src="https://odoo-community.org/logo.png" />
</a>
<p>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.</p>
<p>Current <a class="reference external" href="https://odoo-community.org/page/maintainer-role">maintainers</a>:</p>
<p><a class="reference external image-reference" href="https://github.com/yajo"><img alt="yajo" src="https://github.com/yajo.png?size=40px" /></a> <a class="reference external image-reference" href="https://github.com/anddago78"><img alt="anddago78" src="https://github.com/anddago78.png?size=40px" /></a></p>
<p>This module is part of the <a class="reference external" href="https://github.com/OCA/project/tree/16.0/project_sequence">OCA/project</a> project on GitHub.</p>
<p>You are welcome to contribute. To learn how please visit <a class="reference external" href="https://odoo-community.org/page/Contribute">https://odoo-community.org/page/Contribute</a>.</p>
</div>
</div>
</div>
</body>
</html>

View file

@ -0,0 +1 @@
from . import test_project_sequence

View file

@ -0,0 +1,225 @@
# Copyright 2023 Moduon Team S.L.
# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl-3.0)
from freezegun import freeze_time
from psycopg2 import IntegrityError
from odoo import fields
from odoo.tests.common import Form, TransactionCase, new_test_user, users
from odoo.tools import mute_logger
@freeze_time("2023-01-01 12:00:00")
class TestProjectSequence(TransactionCase):
@classmethod
def setUpClass(cls):
super().setUpClass()
new_test_user(
cls.env,
"manager",
"project.group_project_manager,analytic.group_analytic_accounting",
)
cls.pjr_seq = cls.env.ref("project_sequence.seq_project_sequence")
cls.pjr_seq.date_range_ids.unlink()
default_plan_id = (
cls.env["account.analytic.plan"]
.sudo()
.search(
[
"|",
("company_id", "=", False),
("company_id", "=", cls.env.company.id),
],
limit=1,
)
)
cls.analytic_account = cls.env["account.analytic.account"].create(
{
"name": "aaa",
"plan_id": default_plan_id.id,
"company_id": cls.env.company.id,
"create_uid": cls.env.uid,
"write_uid": cls.env.uid,
"create_date": fields.Datetime.now(),
"write_date": fields.Datetime.now(),
}
)
def setUp(self):
super(TestProjectSequence, self).setUp()
self.pjr_seq._get_current_sequence().number_next = 11
@users("manager")
def test_sequence_after_creation(self):
"""Sequence is applied only after project creation."""
prj_f = Form(self.env["project.project"])
self.assertFalse(prj_f.name)
self.assertFalse(prj_f.sequence_code)
proj = prj_f.save()
self.assertTrue(proj.sequence_code)
self.assertEqual(proj.name, proj.sequence_code)
self.assertEqual(proj.sequence_code, "23-00011")
self.assertEqual(proj.display_name, "23-00011")
def test_analytic_account_after_creation_no_name(self):
"""Project's analytic account is named like project's default name."""
proj = self.env["project.project"].create(
{"analytic_account_id": self.analytic_account.id}
)
self.assertEqual(proj.sequence_code, "23-00011")
self.assertEqual(proj.name, "23-00011")
self.assertEqual(proj.display_name, "23-00011")
self.assertEqual(proj.analytic_account_id.name, "23-00011")
def test_analytic_account_after_creation_named(self):
"""Project's analytic account is named like project's display name."""
proj = self.env["project.project"].create(
{"name": "whatever", "analytic_account_id": self.analytic_account.id}
)
self.assertEqual(proj.sequence_code, "23-00011")
self.assertEqual(proj.name, "whatever")
self.assertEqual(proj.display_name, "23-00011 - whatever")
self.assertEqual(proj.analytic_account_id.name, "23-00011 - whatever")
@users("manager")
def test_sequence_copied_to_name_if_emptied(self):
"""Sequence is copied to project name if user removes it."""
proj = self.env["project.project"].create(
{"name": "whatever", "analytic_account_id": self.analytic_account.id}
)
self.assertEqual(proj.name, "whatever")
self.assertEqual(proj.sequence_code, "23-00011")
self.assertEqual(proj.display_name, "23-00011 - whatever")
self.assertEqual(proj.analytic_account_id.name, "23-00011 - whatever")
with Form(proj) as prj_f:
prj_f.name = False
self.assertEqual(proj.name, "23-00011")
self.assertEqual(proj.sequence_code, "23-00011")
self.assertEqual(proj.display_name, "23-00011")
self.assertEqual(proj.analytic_account_id.name, "23-00011")
@users("manager")
def test_sequence_not_copied_to_another_project(self):
"""Sequence is not duplicated to another project."""
proj1 = self.env["project.project"].create({"name": "whatever"})
proj2 = proj1.copy()
self.assertEqual(proj1.sequence_code, "23-00011")
self.assertEqual(proj2.sequence_code, "23-00012")
@users("manager")
@mute_logger("odoo.sql_db")
def test_sequence_unique(self):
"""Sequence cannot have duplicates."""
proj1 = self.env["project.project"].create({"name": "one"})
self.assertEqual(proj1.sequence_code, "23-00011")
self.pjr_seq._get_current_sequence().number_next = 11
with self.assertRaises(IntegrityError), self.env.cr.savepoint():
proj1 = self.env["project.project"].create({"name": "two"})
@users("manager")
def test_project_without_sequence(self):
"""Preexisting projects had no sequence, and they should display fine."""
proj1 = self.env["project.project"].search(
[
("sequence_code", "=", False),
],
limit=1,
)
proj1.name = "one"
self.assertFalse(proj1.sequence_code)
self.assertEqual(proj1.display_name, "one")
# Make sure that the sequence is not increased
proj2 = self.env["project.project"].create({"name": "two"})
self.assertEqual(proj2.sequence_code, "23-00011")
self.assertEqual(proj2.display_name, "23-00011 - two")
@users("manager")
def test_project_with_empty_sequence(self):
"""Sequence is applied when creating project with an empty sequence"""
proj1 = self.env["project.project"].create(
{"name": "whatever", "sequence_code": ""}
)
self.assertEqual(proj1.sequence_code, "23-00011")
self.assertEqual(proj1.display_name, "23-00011 - whatever")
# Sequence is applied when creating project with sequence in False
proj2 = self.env["project.project"].create(
{"name": "whatever", "sequence_code": False}
)
self.assertEqual(proj2.sequence_code, "23-00012")
self.assertEqual(proj2.display_name, "23-00012 - whatever")
def test_custom_pattern(self):
"""Display name pattern can be customized."""
self.env["ir.config_parameter"].set_param(
"project_sequence.display_name_pattern", "%(name)s/%(sequence_code)s"
)
proj = self.env["project.project"].create({"name": "one"})
self.assertEqual(proj.display_name, "one/23-00011")
self.assertEqual(proj.sequence_code, "23-00011")
self.env["ir.config_parameter"].set_param(
"project_sequence.display_name_pattern", "%(name)s"
)
proj = self.env["project.project"].create({"name": "two"})
self.assertEqual(proj.display_name, "two")
self.assertEqual(proj.sequence_code, "23-00012")
self.env["ir.config_parameter"].set_param(
"project_sequence.display_name_pattern", "%(sequence_code)s"
)
proj = self.env["project.project"].create({"name": "three"})
self.assertEqual(proj.display_name, "23-00013")
self.assertEqual(proj.sequence_code, "23-00013")
def test_sync_analytic_account_name(self):
"""Set analytic account name equal to project's display name."""
proj = self.env["project.project"].create({"name": "one"})
default_plan_id = (
self.env["account.analytic.plan"]
.sudo()
.search(
[
"|",
("company_id", "=", False),
("company_id", "=", self.env.company.id),
],
limit=1,
)
)
analytic_account = self.env["account.analytic.account"].create(
{
"name": proj.display_name,
"plan_id": default_plan_id.id,
"company_id": self.env.company.id,
"create_uid": self.env.uid,
"write_uid": self.env.uid,
"create_date": fields.Datetime.now(),
"write_date": fields.Datetime.now(),
}
)
proj.analytic_account_id = analytic_account
proj._sync_analytic_account_name()
self.assertEqual(proj.analytic_account_id.name, proj.display_name)
# Test when analytic_account_id is not set
proj.analytic_account_id = False
proj._sync_analytic_account_name()
self.assertTrue(True) # Placeholder assertion to ensure the code execution
def test_name_search(self):
"""Allow searching by sequence code by default."""
proj1 = self.env["project.project"].create({"name": "one"})
self.assertEqual(proj1.sequence_code, "23-00011")
proj2 = self.env["project.project"].create({"name": "two"})
self.assertEqual(proj2.sequence_code, "23-00012")
proj3 = self.env["project.project"].create({"name": "three"})
self.assertEqual(proj3.sequence_code, "23-00013")
# Search by name
results = self.env["project.project"].name_search("two")
self.assertIn((proj2.id, "23-00012 - two"), results)
self.assertNotIn((proj1.id, "23-00011 - one"), results)
self.assertNotIn((proj3.id, "23-00013 - three"), results)
# Search by sequence code
results = self.env["project.project"].name_search("23-00012")
self.assertIn((proj2.id, "23-00012 - two"), results)
self.assertNotIn((proj1.id, "23-00011 - one"), results)
self.assertNotIn((proj3.id, "23-00013 - three"), results)

View file

@ -0,0 +1,68 @@
<?xml version="1.0" encoding="utf-8" ?>
<!-- Copyright 2023 Moduon Team S.L.
License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl-3.0) -->
<data>
<record id="project_sequence_form_view" model="ir.ui.view">
<field name="name">Project.sequence.project.edit</field>
<field name="model">project.project</field>
<field name="inherit_id" ref="project.edit_project" />
<field name="arch" type="xml">
<xpath expr="//div[hasclass('oe_title')]//h1" position="after">
<div name="sequence_code">
<div>
<label
for="sequence_code"
class="oe_inline"
string="Sequence code:"
/>
<field name="sequence_code" class="oe_inline oe_input_align" />
</div>
</div>
</xpath>
</field>
</record>
<record id="project_sequence_tree_view" model="ir.ui.view">
<field name="name">Project_sequence_project_view</field>
<field name="model">project.project</field>
<field name="inherit_id" ref="project.view_project" />
<field name="arch" type="xml">
<xpath expr="//field[@name='display_name']" position="after">
<field name="sequence_code" optional="hide" />
</xpath>
</field>
</record>
<record id="project_sequence_kanban_view" model="ir.ui.view">
<field name="name">Project.sequence.project.kanban</field>
<field name="model">project.project</field>
<field name="inherit_id" ref="project.view_project_kanban" />
<field name="arch" type="xml">
<xpath expr="//field[@name='display_name']" position="after">
<field name="name" />
</xpath>
<xpath
expr="//span[t[@t-esc='record.display_name.value']]"
position="attributes"
>
<attribute name="invisible">1</attribute>
</xpath>
<xpath
expr="//span[t[@t-esc='record.display_name.value']]"
position="after"
>
<span><t t-esc="record.display_name.value" /></span>
</xpath>
</field>
</record>
<record id="project_sequence_search_view" model="ir.ui.view">
<field name="name">Project.sequence.project.view.search</field>
<field name="model">project.project</field>
<field name="inherit_id" ref="project.view_project_project_filter" />
<field name="arch" type="xml">
<field name="name" position="attributes">
<attribute
name="filter_domain"
>['|', ('name', 'ilike', self), ('sequence_code', 'ilike', self)]</attribute>
</field>
</field>
</record>
</data>

View file

@ -0,0 +1 @@
from . import res_config_settings

View file

@ -0,0 +1,18 @@
# Copyright 2023 Moduon Team S.L.
# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl-3.0)
from odoo import fields, models
class ResConfigSettings(models.TransientModel):
_inherit = "res.config.settings"
project_display_name_pattern = fields.Char(
config_parameter="project_sequence.display_name_pattern",
default="%(sequence_code)s - %(name)s",
help=(
"Use %(sequence_code)s and %(name)s to include the sequence code "
"and the name of the project in the display name."
),
)

View file

@ -0,0 +1,23 @@
<?xml version="1.0" encoding="utf-8" ?>
<!-- Copyright 2023 Moduon Team S.L.
License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl-3.0) -->
<data>
<record id="res_config_settings_view_form" model="ir.ui.view">
<field name="name">Configure project display name</field>
<field name="model">res.config.settings</field>
<field name="inherit_id" ref="project.res_config_settings_view_form" />
<field name="arch" type="xml">
<xpath expr="//div[@id='tasks_management']" position="inside">
<div
id="project_display_name_pattern"
class="col-12 col-lg-6 o_setting_box"
>
<div class="o_setting_right_pane" name="pad_project_right_pane">
<label for="project_display_name_pattern" class="d-block" />
<field name="project_display_name_pattern" />
</div>
</div>
</xpath>
</field>
</record>
</data>