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 @@
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