Initial commit: OCA Workflow Process packages (456 packages)

This commit is contained in:
Ernad Husremovic 2025-08-29 15:43:00 +02:00
commit d366e42934
18799 changed files with 1284507 additions and 0 deletions

View file

@ -0,0 +1,4 @@
# License LGPLv3.0 or later (https://www.gnu.org/licenses/lgpl-3.0.en.html).
from . import project_project
from . import project_task

View file

@ -0,0 +1,208 @@
# Copyright 2017 - 2018 Modoolar <info@modoolar.com>
# License LGPLv3.0 or later (https://www.gnu.org/licenses/lgpl-3.0.en.html).
from odoo import _, api, fields, models
from odoo.tools import config
class Project(models.Model):
_inherit = "project.project"
_rec_names_search = ["key", "name", "id"]
task_key_sequence_id = fields.Many2one(
comodel_name="ir.sequence", string="Key Sequence", ondelete="restrict"
)
key = fields.Char(size=10, required=False, index=True, copy=False)
_sql_constraints = [
("project_key_unique", "UNIQUE(key)", "Project key must be unique")
]
@api.onchange("name")
def _onchange_project_name(self):
for rec in self:
if rec.key:
continue
if rec.name:
rec.key = self.generate_project_key(rec.name)
else:
rec.key = ""
@api.model_create_multi
def create(self, vals_list):
for vals in vals_list:
key = vals.get("key", False)
if not key:
vals["key"] = self.generate_project_key(vals["name"])
# Tasks must be created after the project.
if vals.get("task_ids", False):
task_vals = vals.pop("task_ids")
else:
task_vals = []
# The key sequences to create stories and tasks with keys, created with
# a project, must be linked to the project company to avoid security
# issues.
# Propagate the company ID, using the context key, to fill the
# sequences company.
company_id = vals.get("company_id")
if company_id:
self = self.with_context(project_sequence_company=company_id)
new_project = super(Project, self).create(vals)
new_project.create_sequence()
# Tasks must be created after the project.
if task_vals:
new_project.write({"task_ids": task_vals})
return new_project
def write(self, values):
update_key = False
if "key" in values:
key = values["key"]
update_key = self.key != key
res = super(Project, self).write(values)
if update_key:
# Here we don't expect to have more than one record
# because we can not have multiple projects with the same KEY.
self.update_sequence()
self._update_task_keys()
return res
def unlink(self):
for project in self:
sequence = project.task_key_sequence_id
project.task_key_sequence_id = False
sequence.sudo().unlink()
return super(Project, self).unlink()
def create_sequence(self):
"""
This method creates ir.sequence fot the current project
:return: Returns create sequence
"""
self.ensure_one()
sequence_data = self._prepare_sequence_data()
sequence = self.env["ir.sequence"].sudo().create(sequence_data)
self.write({"task_key_sequence_id": sequence.id})
return sequence
def update_sequence(self):
"""
This method updates existing task sequence
:return:
"""
sequence_data = self._prepare_sequence_data(init=False)
self.task_key_sequence_id.sudo().write(sequence_data)
def _prepare_sequence_data(self, init=True):
"""
This method prepares data for create/update_sequence methods
:param init: Set to False in case you don't want to set initial values
for number_increment and number_next_actual
"""
values = {
"name": "{} {}".format(_("Project task sequence for project"), self.name),
"implementation": "standard",
"code": "project.task.key.{}".format(self.id),
"prefix": "{}-".format(self.key),
"use_date_range": False,
}
# The key sequences to create stories and tasks with keys, created with
# a project, must be linked to the project company to avoid security
# issues.
company_id = self.env.context.get("project_sequence_company")
if company_id:
values["company_id"] = company_id
if init:
values.update(dict(number_increment=1, number_next_actual=1))
return values
def get_next_task_key(self):
test_project_key = self.env.context.get("test_project_key")
if (config["test_enable"] and not test_project_key) or (
config["demo"].get("project_key") and not test_project_key
):
return False
return self.sudo().task_key_sequence_id.next_by_id()
def generate_project_key(self, text):
test_project_key = self.env.context.get("test_project_key")
if (config["test_enable"] and not test_project_key) or (
config["demo"].get("project_key") and not test_project_key
):
return False
if not text:
return ""
data = text.split(" ")
if len(data) == 1:
return self._generate_project_unique_key(data[0][:3].upper())
key = []
for item in data:
key.append(item[:1].upper())
return self._generate_project_unique_key("".join(key))
def _generate_project_unique_key(self, text):
self_context = self.with_context(active_test=False)
res = text
unique_key = False
counter = 0
while not unique_key:
if counter != 0:
res = "%s%s" % (text, counter)
unique_key = not bool(self_context.search([("key", "=", res)]))
counter += 1
return res
def _update_task_keys(self):
"""
This method will update task keys of the current project.
"""
self.ensure_one()
self.flush_model()
reindex_query = """
UPDATE project_task
SET key = x.key
FROM (
SELECT t.id, p.key || '-' || split_part(t.key, '-', 2) AS key
FROM project_task t
INNER JOIN project_project p ON t.project_id = p.id
WHERE t.project_id = %s
) AS x
WHERE project_task.id = x.id;
"""
self.env.cr.execute(reindex_query, (self.id,))
self.task_ids.invalidate_model(["key"])
@api.model
def _set_default_project_key(self):
"""
This method will be called from the post_init hook in order to set
default values on project.project and
project.task, so we leave those tables nice and clean after module
installation.
:return:
"""
for project in self.search([("key", "=", False)]):
project.key = self.generate_project_key(project.name)
project.create_sequence()
for task in project.task_ids:
task.key = project.get_next_task_key()

View file

@ -0,0 +1,75 @@
# Copyright 2017 - 2018 Modoolar <info@modoolar.com>
# License LGPLv3.0 or later (https://www.gnu.org/licenses/lgpl-3.0.en.html).
from odoo import api, fields, models
TASK_URL = "/web#id=%s&view_type=form&model=project.task&action=%s"
class Task(models.Model):
_inherit = "project.task"
_rec_names_search = ["key", "name"]
key = fields.Char(size=20, required=False, index=True)
url = fields.Char(string="URL", compute="_compute_task_url")
_sql_constraints = [("task_key_unique", "UNIQUE(key)", "Task key must be unique!")]
def _compute_task_url(self):
action_id = self.env.ref("project.action_view_task").id
for task in self:
task.url = TASK_URL % (task.id, action_id)
@api.model_create_multi
def create(self, vals_list):
ctx = self.env.context.get
for vals in vals_list:
project_id = vals.get("project_id", False)
if not project_id:
project_id = ctx("default_project_id", False)
if not project_id and ctx("active_model", False) == "project.project":
project_id = ctx("active_id", False)
if project_id:
project = self.env["project.project"].browse(project_id)
vals["key"] = project.get_next_task_key()
return super(Task, self).create(vals_list)
def write(self, vals):
project_id = vals.get("project_id", False)
if not project_id:
return super(Task, self).write(vals)
project = self.env["project.project"].browse(project_id)
for task in self:
if task.key and task.project_id.id == project.id:
continue
values = self.prepare_task_for_project_switch(task, project)
super(Task, task).write(values)
return super(Task, self).write(vals)
def prepare_task_for_project_switch(self, task, project):
data = {"key": project.get_next_task_key(), "project_id": project.id}
if len(task.child_ids) > 0:
data["child_ids"] = [
(1, child.id, self.prepare_task_for_project_switch(child, project))
for child in task.child_ids
]
return data
def name_get(self):
result = []
for record in self:
task_name = []
if record.key:
task_name.append(record.key)
task_name.append(record.name)
result.append((record.id, " - ".join(task_name)))
return result