Initial commit: OCA Technical packages (595 packages)

This commit is contained in:
Ernad Husremovic 2025-08-29 15:43:03 +02:00
commit 2cc02aac6e
24950 changed files with 2318079 additions and 0 deletions

View file

@ -0,0 +1,11 @@
# Copyright (C) 2010 Savoir-faire Linux (<http://www.savoirfairelinux.com>).
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from . import mgmtsystem_nonconformity_stage
from . import mgmtsystem_nonconformity_cause
from . import mgmtsystem_nonconformity_origin
from . import mgmtsystem_nonconformity_severity
from . import mgmtsystem_nonconformity
from . import mgmtsystem_action
from . import mgmtsystem_nonconformity_abstract

View file

@ -0,0 +1,20 @@
# Copyright (C) 2010 Savoir-faire Linux (<http://www.savoirfairelinux.com>).
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from odoo import fields, models
class MgmtsystemAction(models.Model):
_inherit = "mgmtsystem.action"
nonconformity_immediate_id = fields.One2many(
"mgmtsystem.nonconformity", "immediate_action_id", readonly=True
)
nonconformity_ids = fields.Many2many(
"mgmtsystem.nonconformity",
"mgmtsystem_nonconformity_action_rel",
"action_id",
"nonconformity_id",
"Nonconformities",
readonly=True,
)

View file

@ -0,0 +1,243 @@
# Copyright (C) 2010 Savoir-faire Linux (<http://www.savoirfairelinux.com>).
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from odoo import _, api, fields, models
class MgmtsystemNonconformity(models.Model):
_name = "mgmtsystem.nonconformity"
_description = "Nonconformity"
_inherit = ["mail.thread", "mail.activity.mixin"]
_order = "create_date desc"
@api.model
def _default_stage(self):
"""Return the default stage."""
return self.env.ref("mgmtsystem_nonconformity.stage_draft", False) or self.env[
"mgmtsystem.nonconformity.stage"
].search([("is_starting", "=", True)], limit=1)
@api.model
def _stage_groups(self, stages, domain, order):
stage_ids = self.env["mgmtsystem.nonconformity.stage"].search([])
return stage_ids
# 1. Description
name = fields.Char()
ref = fields.Char("Reference", required=True, readonly=True, default="NEW")
# Compute data
number_of_nonconformities = fields.Integer(
"# of nonconformities", readonly=True, default=1
)
days_since_updated = fields.Integer(
readonly=True, compute="_compute_days_since_updated", store=True
)
number_of_days_to_close = fields.Integer(
"# of days to close",
compute="_compute_number_of_days_to_close",
store=True,
readonly=True,
)
closing_date = fields.Datetime(readonly=True)
partner_id = fields.Many2one("res.partner", "Partner", required=True)
reference = fields.Char(
"Related to", default=lambda self: self._default_reference()
)
responsible_user_id = fields.Many2one(
"res.users", "Responsible", required=True, tracking=True
)
manager_user_id = fields.Many2one(
"res.users", "Manager", required=True, tracking=True
)
user_id = fields.Many2one(
"res.users",
"Filled in by",
required=True,
default=lambda self: self.env.user,
tracking=True,
)
origin_ids = fields.Many2many(
"mgmtsystem.nonconformity.origin",
"mgmtsystem_nonconformity_origin_rel",
"nonconformity_id",
"origin_id",
"Origin",
required=True,
)
procedure_ids = fields.Many2many(
"document.page",
"mgmtsystem_nonconformity_procedure_rel",
"nonconformity_id",
"procedure_id",
"Procedure",
)
description = fields.Text(required=True)
system_id = fields.Many2one("mgmtsystem.system", "System")
stage_id = fields.Many2one(
"mgmtsystem.nonconformity.stage",
"Stage",
tracking=True,
copy=False,
default=_default_stage,
group_expand="_stage_groups",
)
state = fields.Selection(related="stage_id.state", store=True)
kanban_state = fields.Selection(
[
("normal", "In Progress"),
("done", "Ready for next stage"),
("blocked", "Blocked"),
],
default="normal",
tracking=True,
help="A kanban state indicates special situations affecting it:\n"
" * Normal is the default situation\n"
" * Blocked indicates something is preventing"
" the progress of this task\n"
" * Ready for next stage indicates the"
" task is ready to be pulled to the next stage",
required=True,
copy=False,
)
# 2. Root Cause Analysis
cause_ids = fields.Many2many(
"mgmtsystem.nonconformity.cause",
"mgmtsystem_nonconformity_cause_rel",
"nonconformity_id",
"cause_id",
"Cause",
)
severity_id = fields.Many2one("mgmtsystem.nonconformity.severity", "Severity")
analysis = fields.Text()
immediate_action_id = fields.Many2one(
"mgmtsystem.action",
domain="[('nonconformity_ids', '=', id)]",
)
# 3. Action Plan
action_ids = fields.Many2many(
"mgmtsystem.action",
"mgmtsystem_nonconformity_action_rel",
"nonconformity_id",
"action_id",
"Actions",
)
action_comments = fields.Text(
"Action Plan Comments", help="Comments on the action plan."
)
# 4. Effectiveness Evaluation
evaluation_comments = fields.Text(
help="Conclusions from the last effectiveness evaluation.",
)
# Multi-company
company_id = fields.Many2one(
"res.company", "Company", default=lambda self: self.env.company
)
res_model = fields.Char(index=True)
res_id = fields.Integer(index=True)
@api.model
def _default_reference(self):
if self.env.context.get("active_model") and self.env.context.get("active_id"):
return (
self.env[self.env.context["active_model"]]
.browse(self.env.context.get("active_id"))
.exists()
.display_name
)
return ""
def _get_all_actions(self):
self.ensure_one()
return self.action_ids + self.immediate_action_id
@api.constrains("stage_id")
def _check_open_with_action_comments(self):
for nc in self:
if nc.state == "open" and not nc.action_comments:
raise models.ValidationError(
_(
"Action plan comments are required "
"in order to put a nonconformity In Progress."
)
)
@api.constrains("stage_id")
def _check_close_with_evaluation(self):
for nc in self:
if nc.state == "done":
if not nc.evaluation_comments:
raise models.ValidationError(
_(
"Evaluation Comments are required "
"in order to close a Nonconformity."
)
)
actions_are_closed = nc._get_all_actions().mapped("stage_id.is_ending")
if not all(actions_are_closed):
raise models.ValidationError(
_("All actions must be done " "before closing a Nonconformity.")
)
@api.model
def _elapsed_days(self, dt1, dt2):
return (dt2 - dt1).days if dt1 and dt2 else 0
@api.depends("closing_date", "create_date")
def _compute_number_of_days_to_close(self):
for nc in self:
nc.number_of_days_to_close = self._elapsed_days(
nc.create_date, nc.closing_date
)
@api.depends("write_date")
def _compute_days_since_updated(self):
for nc in self:
nc.days_since_updated = self._elapsed_days(nc.create_date, nc.write_date)
@api.model_create_multi
def create(self, vals):
for value in vals:
value.update(
{
"ref": self.env["ir.sequence"].next_by_code(
"mgmtsystem.nonconformity"
)
}
)
return super().create(vals)
def write(self, vals):
is_writing = self.env.context.get("is_writing", False)
is_state_change = "stage_id" in vals or "state" in vals
# Reset Kanban State on Stage change
if is_state_change:
was_not_open = {
x.id: x.state in ("draft", "analysis", "pending") for x in self
}
if any(self.filtered(lambda x: x.kanban_state != "normal")):
vals["kanban_state"] = "normal"
result = super().write(vals)
# Set/reset the closing date
if not is_writing and is_state_change:
for nc in self.with_context(is_writing=True):
# On Close set Closing Date
if nc.state == "done" and not nc.closing_date:
nc.closing_date = fields.Datetime.now()
# On reopen resete Closing Date
elif nc.state != "done" and nc.closing_date:
nc.closing_date = None
# On action plan approval, Open the Actions
if nc.state == "open" and was_not_open[nc.id]:
for action in nc._get_all_actions():
if action.stage_id.is_starting:
action.case_open()
return result

View file

@ -0,0 +1,90 @@
# Copyright (C) 2010 Savoir-faire Linux (<http://www.savoirfairelinux.com>).
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from lxml import etree
from odoo import api, fields, models
from odoo.tools.misc import frozendict
class MgmtsystemNonconformityAbstract(models.AbstractModel):
# TODO: Remove this on 17.0 and move everything on mail.thread
_name = "mgmtsystem.nonconformity.abstract"
_description = "Nonconformity Abstract"
non_conformity_ids = fields.One2many(
"mgmtsystem.nonconformity",
inverse_name="res_id",
domain=lambda r: [("res_model", "=", r._name)],
readonly=True,
)
non_conformity_count = fields.Integer(compute="_compute_non_conformity_count")
@api.depends("non_conformity_ids")
def _compute_non_conformity_count(self):
for record in self:
record.non_conformity_count = len(record.non_conformity_ids)
def _get_non_conformities_domain(self):
return [("res_model", "=", self._name), ("res_id", "=", self.id)]
def _get_non_conformities_context(self):
return {}
def action_view_non_conformities(self):
self.ensure_one()
action = self.env.ref(
"mgmtsystem_nonconformity.open_mgmtsystem_nonconformity_list"
).read()[0]
action["domain"] = self._get_non_conformities_domain()
action["context"] = self._get_non_conformities_context()
return action
class MailThread(models.AbstractModel):
_name = "mail.thread"
_inherit = ["mail.thread", "mgmtsystem.nonconformity.abstract"]
@api.model
def get_view(self, view_id=None, view_type="form", **options):
res = super().get_view(view_id=view_id, view_type=view_type, **options)
if view_type == "form" and self.env.user.has_group(
"mgmtsystem.group_mgmtsystem_viewer"
):
View = self.env["ir.ui.view"]
if view_id and res.get("base_model", self._name) != self._name:
View = View.with_context(base_model_name=res["base_model"])
doc = etree.XML(res["arch"])
# We need to copy, because it is a frozen dict
all_models = res["models"].copy()
for node in doc.xpath("/form/div[hasclass('oe_chatter')]"):
# _add_tier_validation_label process
new_node = etree.fromstring(
"<field name='non_conformity_count' invisible='1'/>"
)
new_arch, new_models = View.postprocess_and_fields(new_node, self._name)
new_node = etree.fromstring(new_arch)
for model in list(filter(lambda x: x not in all_models, new_models)):
if model not in res["models"]:
all_models[model] = new_models[model]
else:
all_models[model] = res["models"][model]
node.addprevious(new_node)
res["arch"] = etree.tostring(doc)
res["models"] = frozendict(all_models)
return res
@api.model
def _get_view_fields(self, view_type, models):
"""
We need to add this in order to fix the usage of form opening from
trees inside a form
"""
result = super()._get_view_fields(view_type, models)
if view_type == "form" and self.env.user.has_group(
"mgmtsystem.group_mgmtsystem_viewer"
):
result[self._name].add("non_conformity_count")
return result

View file

@ -0,0 +1,36 @@
# Copyright (C) 2010 Savoir-faire Linux (<http://www.savoirfairelinux.com>).
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from odoo import fields, models
class MgmtsystemNonconformityCause(models.Model):
"""Cause of the nonconformity of the management system."""
_name = "mgmtsystem.nonconformity.cause"
_description = "Cause of the nonconformity of the management system"
_order = "parent_id, sequence"
_parent_store = True
name = fields.Char("Cause", required=True, translate=True)
description = fields.Text()
sequence = fields.Integer(help="Defines the order to present items")
parent_path = fields.Char(index=True, unaccent=False)
parent_id = fields.Many2one(
"mgmtsystem.nonconformity.cause", "Group", ondelete="restrict"
)
child_ids = fields.One2many(
"mgmtsystem.nonconformity.cause", "parent_id", "Child Causes"
)
ref_code = fields.Char("Reference Code")
def name_get(self):
res = []
for obj in self:
if obj.parent_id:
name = obj.parent_id.name_get()[0][1] + " / " + obj.name
else:
name = obj.name
res.append((obj.id, name))
return res

View file

@ -0,0 +1,35 @@
# Copyright (C) 2010 Savoir-faire Linux (<http://www.savoirfairelinux.com>).
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from odoo import fields, models
class MgmtsystemNonconformityOrigin(models.Model):
_name = "mgmtsystem.nonconformity.origin"
_description = "Origin of nonconformity of the management system"
_order = "parent_id, sequence"
_parent_store = True
name = fields.Char("Origin", required=True, translate=True)
description = fields.Text()
sequence = fields.Integer(help="Defines the order to present items")
parent_path = fields.Char(index=True, unaccent=False)
parent_id = fields.Many2one(
"mgmtsystem.nonconformity.origin", "Group", ondelete="restrict"
)
child_ids = fields.One2many(
"mgmtsystem.nonconformity.origin", "parent_id", "Childs"
)
ref_code = fields.Char("Reference Code")
active = fields.Boolean(default=True)
def name_get(self):
res = []
for obj in self:
name = obj.name
if obj.parent_id:
name = obj.parent_id.name_get()[0][1] + " / " + name
res.append((obj.id, name))
return res

View file

@ -0,0 +1,17 @@
# Copyright (C) 2010 Savoir-faire Linux (<http://www.savoirfairelinux.com>).
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from odoo import fields, models
class MgmtsystemNonconformitySeverity(models.Model):
"""Nonconformity Severity - Critical, Major, Minor, Invalid, ..."""
_name = "mgmtsystem.nonconformity.severity"
_description = "Severity of Complaints and Nonconformities"
name = fields.Char("Title", required=True, translate=True)
sequence = fields.Integer()
description = fields.Text(translate=True)
active = fields.Boolean("Active?", default=True)

View file

@ -0,0 +1,37 @@
# Copyright (C) 2010 Savoir-faire Linux (<http://www.savoirfairelinux.com>).
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from odoo import _, fields, models
_STATES = [
("draft", _("Draft")),
("analysis", _("Analysis")),
("pending", _("Action Plan")),
("open", _("In Progress")),
("done", _("Closed")),
("cancel", _("Cancelled")),
]
class MgmtsystemNonconformityStage(models.Model):
"""This object is used to defined different state for non conformity."""
_name = "mgmtsystem.nonconformity.stage"
_description = "Nonconformity Stages"
_order = "sequence"
name = fields.Char("Stage Name", required=True, translate=True)
sequence = fields.Integer(
help="Used to order states. Lower is better.", default=100
)
state = fields.Selection(_STATES, default="draft")
is_starting = fields.Boolean(
string="Is starting Stage",
help="select stis checkbox if this is the default stage \n"
"for new nonconformities",
)
fold = fields.Boolean(
string="Folded in Kanban",
help="This stage is folded in the kanban view when there are \n"
"no records in that stage to display.",
)