mirror of
https://github.com/bringout/oca-technical.git
synced 2026-04-19 05:32:00 +02:00
Initial commit: OCA Technical packages (595 packages)
This commit is contained in:
commit
2cc02aac6e
24950 changed files with 2318079 additions and 0 deletions
|
|
@ -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
|
||||
|
|
@ -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,
|
||||
)
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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)
|
||||
|
|
@ -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.",
|
||||
)
|
||||
Loading…
Add table
Add a link
Reference in a new issue