mirror of
https://github.com/bringout/oca-mrp.git
synced 2026-04-25 01:12:00 +02:00
Initial commit: OCA Mrp packages (117 packages)
This commit is contained in:
commit
277e84fd7a
4403 changed files with 395154 additions and 0 deletions
|
|
@ -0,0 +1,13 @@
|
|||
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
|
||||
|
||||
from . import qc_trigger
|
||||
from . import qc_trigger_line
|
||||
from . import qc_test_category
|
||||
from . import qc_test
|
||||
from . import qc_inspection
|
||||
from . import product_product
|
||||
from . import product_template
|
||||
from . import product_category
|
||||
from . import qc_trigger_product_category_line
|
||||
from . import qc_trigger_product_line
|
||||
from . import qc_trigger_product_template_line
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
# Copyright 2010 NaN Projectes de Programari Lliure, S.L.
|
||||
# Copyright 2014 Serv. Tec. Avanzados - Pedro M. Baeza
|
||||
# Copyright 2014 Oihane Crucelaegui - AvanzOSC
|
||||
# Copyright 2017 ForgeFlow S.L.
|
||||
# Copyright 2017 Simone Rubino - Agile Business Group
|
||||
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
|
||||
|
||||
from odoo import fields, models
|
||||
|
||||
|
||||
class ProductCategory(models.Model):
|
||||
_inherit = "product.category"
|
||||
|
||||
qc_triggers = fields.One2many(
|
||||
comodel_name="qc.trigger.product_category_line",
|
||||
inverse_name="product_category",
|
||||
string="Quality control triggers",
|
||||
)
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
# Copyright 2010 NaN Projectes de Programari Lliure, S.L.
|
||||
# Copyright 2014 Serv. Tec. Avanzados - Pedro M. Baeza
|
||||
# Copyright 2014 Oihane Crucelaegui - AvanzOSC
|
||||
# Copyright 2017 ForgeFlow S.L.
|
||||
# Copyright 2017 Simone Rubino - Agile Business Group
|
||||
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
|
||||
|
||||
from odoo import fields, models
|
||||
|
||||
|
||||
class ProductProduct(models.Model):
|
||||
_inherit = "product.product"
|
||||
|
||||
qc_triggers = fields.One2many(
|
||||
comodel_name="qc.trigger.product_line",
|
||||
inverse_name="product",
|
||||
string="Quality control triggers",
|
||||
)
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
# Copyright 2010 NaN Projectes de Programari Lliure, S.L.
|
||||
# Copyright 2014 Serv. Tec. Avanzados - Pedro M. Baeza
|
||||
# Copyright 2014 Oihane Crucelaegui - AvanzOSC
|
||||
# Copyright 2017 ForgeFlow S.L.
|
||||
# Copyright 2017 Simone Rubino - Agile Business Group
|
||||
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
|
||||
|
||||
from odoo import fields, models
|
||||
|
||||
|
||||
class ProductTemplate(models.Model):
|
||||
_inherit = "product.template"
|
||||
|
||||
qc_triggers = fields.One2many(
|
||||
comodel_name="qc.trigger.product_template_line",
|
||||
inverse_name="product_template",
|
||||
string="Quality control triggers",
|
||||
)
|
||||
|
|
@ -0,0 +1,376 @@
|
|||
# Copyright 2010 NaN Projectes de Programari Lliure, S.L.
|
||||
# Copyright 2014 Serv. Tec. Avanzados - Pedro M. Baeza
|
||||
# Copyright 2014 Oihane Crucelaegui - AvanzOSC
|
||||
# Copyright 2017 ForgeFlow S.L.
|
||||
# Copyright 2017 Simone Rubino - Agile Business Group
|
||||
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
|
||||
|
||||
from datetime import datetime
|
||||
|
||||
from odoo import _, api, exceptions, fields, models
|
||||
from odoo.tools import formatLang
|
||||
|
||||
|
||||
class QcInspection(models.Model):
|
||||
_name = "qc.inspection"
|
||||
_description = "Quality control inspection"
|
||||
_inherit = ["mail.thread", "mail.activity.mixin"]
|
||||
|
||||
@api.depends("inspection_lines", "inspection_lines.success")
|
||||
def _compute_success(self):
|
||||
for i in self:
|
||||
i.success = all([x.success for x in i.inspection_lines])
|
||||
|
||||
def object_selection_values(self):
|
||||
"""
|
||||
Overridable method for adding more object models to an inspection.
|
||||
:return: A list with the selection's possible values.
|
||||
"""
|
||||
return [("product.product", "Product")]
|
||||
|
||||
@api.depends("object_id")
|
||||
def _compute_product_id(self):
|
||||
for i in self:
|
||||
if i.object_id and i.object_id._name == "product.product":
|
||||
i.product_id = i.object_id
|
||||
else:
|
||||
i.product_id = False
|
||||
|
||||
name = fields.Char(
|
||||
string="Inspection number",
|
||||
required=True,
|
||||
default="/",
|
||||
readonly=True,
|
||||
states={"draft": [("readonly", False)]},
|
||||
copy=False,
|
||||
)
|
||||
date = fields.Datetime(
|
||||
string="Plan Date",
|
||||
required=True,
|
||||
readonly=True,
|
||||
copy=False,
|
||||
default=fields.Datetime.now,
|
||||
states={"plan": [("readonly", False)], "draft": [("readonly", False)]},
|
||||
)
|
||||
date_done = fields.Datetime("Completion Date", readonly=True)
|
||||
object_id = fields.Reference(
|
||||
string="Reference",
|
||||
selection="object_selection_values",
|
||||
readonly=True,
|
||||
states={"draft": [("readonly", False)]},
|
||||
ondelete="set null",
|
||||
)
|
||||
product_id = fields.Many2one(
|
||||
comodel_name="product.product",
|
||||
compute="_compute_product_id",
|
||||
store=True,
|
||||
help="Product associated with the inspection",
|
||||
)
|
||||
qty = fields.Float(string="Quantity", default=1.0)
|
||||
test = fields.Many2one(comodel_name="qc.test", readonly=True)
|
||||
inspection_lines = fields.One2many(
|
||||
comodel_name="qc.inspection.line",
|
||||
inverse_name="inspection_id",
|
||||
readonly=True,
|
||||
states={"ready": [("readonly", False)]},
|
||||
)
|
||||
internal_notes = fields.Text(string="Internal notes")
|
||||
external_notes = fields.Text(
|
||||
states={"success": [("readonly", True)], "failed": [("readonly", True)]},
|
||||
)
|
||||
state = fields.Selection(
|
||||
[
|
||||
("plan", "Plan"),
|
||||
("draft", "Draft"),
|
||||
("ready", "Ready"),
|
||||
("waiting", "Waiting supervisor approval"),
|
||||
("success", "Quality success"),
|
||||
("failed", "Quality failed"),
|
||||
("canceled", "Canceled"),
|
||||
],
|
||||
readonly=True,
|
||||
default="draft",
|
||||
tracking=True,
|
||||
)
|
||||
success = fields.Boolean(
|
||||
compute="_compute_success",
|
||||
help="This field will be marked if all tests have succeeded.",
|
||||
store=True,
|
||||
)
|
||||
auto_generated = fields.Boolean(
|
||||
string="Auto-generated",
|
||||
readonly=True,
|
||||
copy=False,
|
||||
help="If an inspection is auto-generated, it can be canceled but not removed.",
|
||||
)
|
||||
company_id = fields.Many2one(
|
||||
comodel_name="res.company",
|
||||
string="Company",
|
||||
readonly=True,
|
||||
states={"draft": [("readonly", False)]},
|
||||
default=lambda self: self.env.company,
|
||||
)
|
||||
user = fields.Many2one(
|
||||
comodel_name="res.users",
|
||||
string="Responsible",
|
||||
tracking=True,
|
||||
default=lambda self: self.env.user,
|
||||
)
|
||||
|
||||
@api.model_create_multi
|
||||
def create(self, vals_list):
|
||||
for vals in vals_list:
|
||||
if vals.get("name", "/") == "/":
|
||||
vals["name"] = self.env["ir.sequence"].next_by_code("qc.inspection")
|
||||
return super().create(vals_list)
|
||||
|
||||
def write(self, vals):
|
||||
if "state" in vals:
|
||||
if vals["state"] in ["success", "failed"]:
|
||||
vals["date_done"] = datetime.now()
|
||||
elif vals["state"] == "draft":
|
||||
vals["date_done"] = False
|
||||
return super().write(vals)
|
||||
|
||||
@api.ondelete(at_uninstall=False)
|
||||
def _unlink_except_autogenerated_and_non_draft(self):
|
||||
if self.auto_generated and not self.env.is_superuser():
|
||||
raise exceptions.UserError(
|
||||
_("You cannot remove an auto-generated inspection.")
|
||||
)
|
||||
if self.state != "draft":
|
||||
raise exceptions.UserError(
|
||||
_("You cannot remove an inspection that is not in draft state.")
|
||||
)
|
||||
|
||||
def action_draft(self):
|
||||
self.write({"state": "draft"})
|
||||
|
||||
def action_todo(self):
|
||||
for inspection in self:
|
||||
if not inspection.test:
|
||||
raise exceptions.UserError(_("You must first set the test to perform."))
|
||||
self.write({"state": "ready"})
|
||||
|
||||
def action_confirm(self):
|
||||
for inspection in self:
|
||||
for line in inspection.inspection_lines:
|
||||
if line.question_type == "qualitative" and not line.qualitative_value:
|
||||
raise exceptions.UserError(
|
||||
_(
|
||||
"You should provide an answer for all "
|
||||
"qualitative questions."
|
||||
)
|
||||
)
|
||||
if line.question_type != "qualitative" and not line.uom_id:
|
||||
raise exceptions.UserError(
|
||||
_(
|
||||
"You should provide a unit of measure for "
|
||||
"quantitative questions."
|
||||
)
|
||||
)
|
||||
if inspection.success:
|
||||
inspection.state = "success"
|
||||
else:
|
||||
inspection.state = "waiting"
|
||||
|
||||
def action_approve(self):
|
||||
for inspection in self:
|
||||
if inspection.success:
|
||||
inspection.state = "success"
|
||||
else:
|
||||
inspection.state = "failed"
|
||||
|
||||
def action_cancel(self):
|
||||
self.write({"state": "canceled"})
|
||||
|
||||
def set_test(self, trigger_line, force_fill=False):
|
||||
for inspection in self:
|
||||
header = self._prepare_inspection_header(inspection.object_id, trigger_line)
|
||||
del header["state"] # don't change current status
|
||||
del header["auto_generated"] # don't change auto_generated flag
|
||||
del header["user"] # don't change current user
|
||||
inspection.write(header)
|
||||
inspection.inspection_lines.unlink()
|
||||
inspection.inspection_lines = inspection._prepare_inspection_lines(
|
||||
trigger_line.test, force_fill=force_fill
|
||||
)
|
||||
|
||||
def _make_inspection(self, object_ref, trigger_line, date=None):
|
||||
"""Overridable hook method for creating inspection from test.
|
||||
:param object_ref: Object instance
|
||||
:param trigger_line: Trigger line instance
|
||||
:return: Inspection object
|
||||
"""
|
||||
inspection = self.create(
|
||||
self._prepare_inspection_header(object_ref, trigger_line)
|
||||
)
|
||||
if date:
|
||||
inspection.date = date
|
||||
inspection.set_test(trigger_line)
|
||||
return inspection
|
||||
|
||||
def _prepare_inspection_header(self, object_ref, trigger_line):
|
||||
"""Overridable hook method for preparing inspection header.
|
||||
:param object_ref: Object instance
|
||||
:param trigger_line: Trigger line instance
|
||||
:return: List of values for creating the inspection
|
||||
"""
|
||||
return {
|
||||
"object_id": object_ref
|
||||
and "{},{}".format(object_ref._name, object_ref.id)
|
||||
or False,
|
||||
"state": trigger_line.timing == "plan_ahead" and "plan" or "ready",
|
||||
"test": trigger_line.test.id,
|
||||
"user": trigger_line.user.id,
|
||||
"auto_generated": True,
|
||||
}
|
||||
|
||||
def _prepare_inspection_lines(self, test, force_fill=False):
|
||||
new_data = []
|
||||
for line in test.test_lines:
|
||||
data = self._prepare_inspection_line(
|
||||
test, line, fill=test.fill_correct_values or force_fill
|
||||
)
|
||||
new_data.append((0, 0, data))
|
||||
return new_data
|
||||
|
||||
def _prepare_inspection_line(self, test, line, fill=None):
|
||||
data = {
|
||||
"name": line.name,
|
||||
"test_line": line.id,
|
||||
"notes": line.notes,
|
||||
"min_value": line.min_value,
|
||||
"max_value": line.max_value,
|
||||
"test_uom_id": line.uom_id.id,
|
||||
"uom_id": line.uom_id.id,
|
||||
"question_type": line.type,
|
||||
"possible_ql_values": [x.id for x in line.ql_values],
|
||||
}
|
||||
if fill:
|
||||
if line.type == "qualitative":
|
||||
# Fill with the first correct value found
|
||||
for value in line.ql_values:
|
||||
if value.ok:
|
||||
data["qualitative_value"] = value.id
|
||||
break
|
||||
else:
|
||||
# Fill with a value inside the interval
|
||||
data["quantitative_value"] = (line.min_value + line.max_value) * 0.5
|
||||
return data
|
||||
|
||||
def _get_existing_inspections(self, records):
|
||||
reference_vals = []
|
||||
for rec in records:
|
||||
reference_vals.append(",".join([rec._name, str(rec.id)]))
|
||||
return self.sudo().search([("object_id", "in", reference_vals)])
|
||||
|
||||
|
||||
class QcInspectionLine(models.Model):
|
||||
_name = "qc.inspection.line"
|
||||
_description = "Quality control inspection line"
|
||||
|
||||
@api.depends(
|
||||
"question_type",
|
||||
"uom_id",
|
||||
"test_uom_id",
|
||||
"max_value",
|
||||
"min_value",
|
||||
"quantitative_value",
|
||||
"qualitative_value",
|
||||
"possible_ql_values",
|
||||
)
|
||||
def _compute_quality_test_check(self):
|
||||
for insp_line in self:
|
||||
if insp_line.question_type == "qualitative":
|
||||
insp_line.success = insp_line.qualitative_value.ok
|
||||
else:
|
||||
if insp_line.uom_id.id == insp_line.test_uom_id.id:
|
||||
amount = insp_line.quantitative_value
|
||||
else:
|
||||
amount = self.env["uom.uom"]._compute_quantity(
|
||||
insp_line.quantitative_value, insp_line.test_uom_id.id
|
||||
)
|
||||
insp_line.success = insp_line.max_value >= amount >= insp_line.min_value
|
||||
|
||||
@api.depends(
|
||||
"possible_ql_values", "min_value", "max_value", "test_uom_id", "question_type"
|
||||
)
|
||||
def _compute_valid_values(self):
|
||||
for insp_line in self:
|
||||
if insp_line.question_type == "qualitative":
|
||||
insp_line.valid_values = ", ".join(
|
||||
[x.name for x in insp_line.possible_ql_values if x.ok]
|
||||
)
|
||||
else:
|
||||
insp_line.valid_values = "{} ~ {}".format(
|
||||
formatLang(self.env, insp_line.min_value),
|
||||
formatLang(self.env, insp_line.max_value),
|
||||
)
|
||||
if self.env.ref("uom.group_uom") in self.env.user.groups_id:
|
||||
insp_line.valid_values += " %s" % insp_line.test_uom_id.name
|
||||
|
||||
inspection_id = fields.Many2one(
|
||||
comodel_name="qc.inspection", string="Inspection", ondelete="cascade"
|
||||
)
|
||||
name = fields.Char(string="Question", readonly=True)
|
||||
product_id = fields.Many2one(
|
||||
comodel_name="product.product",
|
||||
related="inspection_id.product_id",
|
||||
store=True,
|
||||
)
|
||||
test_line = fields.Many2one(
|
||||
comodel_name="qc.test.question", string="Test question", readonly=True
|
||||
)
|
||||
possible_ql_values = fields.Many2many(
|
||||
comodel_name="qc.test.question.value", string="Answers"
|
||||
)
|
||||
quantitative_value = fields.Float(
|
||||
string="Quantitative value",
|
||||
digits="Quality Control",
|
||||
help="Value of the result for a quantitative question.",
|
||||
)
|
||||
qualitative_value = fields.Many2one(
|
||||
comodel_name="qc.test.question.value",
|
||||
string="Qualitative value",
|
||||
help="Value of the result for a qualitative question.",
|
||||
domain="[('id', 'in', possible_ql_values)]",
|
||||
)
|
||||
notes = fields.Text()
|
||||
min_value = fields.Float(
|
||||
string="Min",
|
||||
digits="Quality Control",
|
||||
readonly=True,
|
||||
help="Minimum valid value for a quantitative question.",
|
||||
)
|
||||
max_value = fields.Float(
|
||||
string="Max",
|
||||
digits="Quality Control",
|
||||
readonly=True,
|
||||
help="Maximum valid value for a quantitative question.",
|
||||
)
|
||||
test_uom_id = fields.Many2one(
|
||||
comodel_name="uom.uom",
|
||||
string="Test UoM",
|
||||
readonly=True,
|
||||
help="UoM for minimum and maximum values for a quantitative " "question.",
|
||||
)
|
||||
test_uom_category = fields.Many2one(
|
||||
comodel_name="uom.category", related="test_uom_id.category_id", store=True
|
||||
)
|
||||
uom_id = fields.Many2one(
|
||||
comodel_name="uom.uom",
|
||||
string="UoM",
|
||||
domain="[('category_id', '=', test_uom_category)]",
|
||||
help="UoM of the inspection value for a quantitative question.",
|
||||
)
|
||||
question_type = fields.Selection(
|
||||
[("qualitative", "Qualitative"), ("quantitative", "Quantitative")],
|
||||
readonly=True,
|
||||
)
|
||||
valid_values = fields.Char(
|
||||
string="Valid values", store=True, compute="_compute_valid_values"
|
||||
)
|
||||
success = fields.Boolean(
|
||||
compute="_compute_quality_test_check", string="Success?", store=True
|
||||
)
|
||||
|
|
@ -0,0 +1,116 @@
|
|||
# Copyright 2010 NaN Projectes de Programari Lliure, S.L.
|
||||
# Copyright 2014 Serv. Tec. Avanzados - Pedro M. Baeza
|
||||
# Copyright 2014 Oihane Crucelaegui - AvanzOSC
|
||||
# Copyright 2017 ForgeFlow S.L.
|
||||
# Copyright 2017 Simone Rubino - Agile Business Group
|
||||
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
|
||||
|
||||
from odoo import _, api, exceptions, fields, models
|
||||
|
||||
|
||||
class QcTest(models.Model):
|
||||
"""
|
||||
A test is a group of questions along with the values that make them valid.
|
||||
"""
|
||||
|
||||
_name = "qc.test"
|
||||
_description = "Quality control test"
|
||||
_inherit = "mail.thread"
|
||||
|
||||
def object_selection_values(self):
|
||||
return set()
|
||||
|
||||
@api.onchange("type")
|
||||
def onchange_type(self):
|
||||
if self.type == "generic":
|
||||
self.object_id = False
|
||||
|
||||
active = fields.Boolean(default=True)
|
||||
name = fields.Char(required=True, translate=True)
|
||||
test_lines = fields.One2many(
|
||||
comodel_name="qc.test.question",
|
||||
inverse_name="test",
|
||||
string="Questions",
|
||||
copy=True,
|
||||
)
|
||||
object_id = fields.Reference(
|
||||
string="Reference object",
|
||||
selection="object_selection_values",
|
||||
)
|
||||
fill_correct_values = fields.Boolean(string="Pre-fill with correct values")
|
||||
type = fields.Selection(
|
||||
[("generic", "Generic"), ("related", "Related")],
|
||||
required=True,
|
||||
default="generic",
|
||||
)
|
||||
category = fields.Many2one(comodel_name="qc.test.category")
|
||||
company_id = fields.Many2one(
|
||||
comodel_name="res.company",
|
||||
default=lambda self: self.env.company,
|
||||
)
|
||||
|
||||
|
||||
class QcTestQuestion(models.Model):
|
||||
"""Each test line is a question with its valid value(s)."""
|
||||
|
||||
_name = "qc.test.question"
|
||||
_description = "Quality control question"
|
||||
_order = "sequence, id"
|
||||
|
||||
@api.constrains("ql_values")
|
||||
def _check_valid_answers(self):
|
||||
for tc in self:
|
||||
if (
|
||||
tc.type == "qualitative"
|
||||
and tc.ql_values
|
||||
and not tc.ql_values.filtered("ok")
|
||||
):
|
||||
raise exceptions.ValidationError(
|
||||
_(
|
||||
"Question '%s' is not valid: "
|
||||
"you have to mark at least one value as OK."
|
||||
)
|
||||
% tc.name_get()[0][1]
|
||||
)
|
||||
|
||||
@api.constrains("min_value", "max_value")
|
||||
def _check_valid_range(self):
|
||||
for tc in self:
|
||||
if tc.type == "quantitative" and tc.min_value > tc.max_value:
|
||||
raise exceptions.ValidationError(
|
||||
_(
|
||||
"Question '%s' is not valid: "
|
||||
"minimum value can't be higher than maximum value."
|
||||
)
|
||||
% tc.name_get()[0][1]
|
||||
)
|
||||
|
||||
sequence = fields.Integer(required=True, default="10")
|
||||
test = fields.Many2one(comodel_name="qc.test")
|
||||
name = fields.Char(required=True, translate=True)
|
||||
type = fields.Selection(
|
||||
[("qualitative", "Qualitative"), ("quantitative", "Quantitative")],
|
||||
required=True,
|
||||
)
|
||||
ql_values = fields.One2many(
|
||||
comodel_name="qc.test.question.value",
|
||||
inverse_name="test_line",
|
||||
string="Qualitative values",
|
||||
copy=True,
|
||||
)
|
||||
notes = fields.Text()
|
||||
min_value = fields.Float(string="Min", digits="Quality Control")
|
||||
max_value = fields.Float(string="Max", digits="Quality Control")
|
||||
uom_id = fields.Many2one(comodel_name="uom.uom", string="Uom")
|
||||
|
||||
|
||||
class QcTestQuestionValue(models.Model):
|
||||
_name = "qc.test.question.value"
|
||||
_description = "Possible values for qualitative questions."
|
||||
|
||||
test_line = fields.Many2one(comodel_name="qc.test.question", string="Test question")
|
||||
name = fields.Char(required=True, translate=True)
|
||||
ok = fields.Boolean(
|
||||
string="Correct answer?",
|
||||
help="When this field is marked, the answer is considered correct.",
|
||||
)
|
||||
|
|
@ -0,0 +1,47 @@
|
|||
# Copyright 2010 NaN Projectes de Programari Lliure, S.L.
|
||||
# Copyright 2014 Serv. Tec. Avanzados - Pedro M. Baeza
|
||||
# Copyright 2014 Oihane Crucelaegui - AvanzOSC
|
||||
# Copyright 2017 ForgeFlow S.L.
|
||||
# Copyright 2017 Simone Rubino - Agile Business Group
|
||||
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
|
||||
|
||||
from odoo import _, api, exceptions, fields, models
|
||||
|
||||
|
||||
class QcTestTemplateCategory(models.Model):
|
||||
_name = "qc.test.category"
|
||||
_description = "Test category"
|
||||
|
||||
@api.depends("name", "parent_id")
|
||||
def _compute_get_complete_name(self):
|
||||
for record in self:
|
||||
names = [record.name or ""]
|
||||
parent = record.parent_id
|
||||
while parent:
|
||||
names.append(parent.name)
|
||||
parent = parent.parent_id
|
||||
record.complete_name = " / ".join(reversed(names))
|
||||
|
||||
@api.constrains("parent_id")
|
||||
def _check_parent_id(self):
|
||||
if not self._check_recursion():
|
||||
raise exceptions.UserError(
|
||||
_("Error! You can not create recursive categories.")
|
||||
)
|
||||
|
||||
name = fields.Char(required=True, translate=True)
|
||||
parent_id = fields.Many2one(
|
||||
comodel_name="qc.test.category", string="Parent category"
|
||||
)
|
||||
complete_name = fields.Char(
|
||||
compute="_compute_get_complete_name", string="Full name"
|
||||
)
|
||||
child_ids = fields.One2many(
|
||||
comodel_name="qc.test.category",
|
||||
inverse_name="parent_id",
|
||||
string="Child categories",
|
||||
)
|
||||
active = fields.Boolean(
|
||||
default=True,
|
||||
help="This field allows you to hide the category without removing it.",
|
||||
)
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
# Copyright 2010 NaN Projectes de Programari Lliure, S.L.
|
||||
# Copyright 2014 Serv. Tec. Avanzados - Pedro M. Baeza
|
||||
# Copyright 2014 Oihane Crucelaegui - AvanzOSC
|
||||
# Copyright 2017 ForgeFlow S.L.
|
||||
# Copyright 2017 Simone Rubino - Agile Business Group
|
||||
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
|
||||
|
||||
from odoo import fields, models
|
||||
|
||||
|
||||
class QcTrigger(models.Model):
|
||||
_name = "qc.trigger"
|
||||
_description = "Quality control trigger"
|
||||
|
||||
name = fields.Char(required=True, translate=True)
|
||||
active = fields.Boolean(default=True)
|
||||
company_id = fields.Many2one(
|
||||
comodel_name="res.company",
|
||||
string="Company",
|
||||
default=lambda self: self.env.company,
|
||||
)
|
||||
partner_selectable = fields.Boolean(
|
||||
string="Selectable by partner",
|
||||
default=False,
|
||||
readonly=True,
|
||||
help="This technical field is to allow to filter by partner in triggers",
|
||||
)
|
||||
|
|
@ -0,0 +1,67 @@
|
|||
# Copyright 2010 NaN Projectes de Programari Lliure, S.L.
|
||||
# Copyright 2014 Serv. Tec. Avanzados - Pedro M. Baeza
|
||||
# Copyright 2014 Oihane Crucelaegui - AvanzOSC
|
||||
# Copyright 2017 ForgeFlow S.L.
|
||||
# Copyright 2017 Simone Rubino - Agile Business Group
|
||||
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
|
||||
|
||||
from odoo import fields, models
|
||||
|
||||
|
||||
def _filter_trigger_lines(trigger_lines):
|
||||
filtered_trigger_lines = []
|
||||
unique_tests = []
|
||||
for trigger_line in trigger_lines:
|
||||
if trigger_line.test not in unique_tests:
|
||||
filtered_trigger_lines.append(trigger_line)
|
||||
unique_tests.append(trigger_line.test)
|
||||
return filtered_trigger_lines
|
||||
|
||||
|
||||
class QcTriggerLine(models.AbstractModel):
|
||||
_name = "qc.trigger.line"
|
||||
_inherit = "mail.thread"
|
||||
_description = "Abstract line for defining triggers"
|
||||
|
||||
trigger = fields.Many2one(comodel_name="qc.trigger", required=True)
|
||||
test = fields.Many2one(comodel_name="qc.test", required=True)
|
||||
user = fields.Many2one(
|
||||
comodel_name="res.users",
|
||||
string="Responsible",
|
||||
tracking=True,
|
||||
default=lambda self: self.env.user,
|
||||
)
|
||||
partners = fields.Many2many(
|
||||
comodel_name="res.partner",
|
||||
help="If filled, the test will only be created when the action is done"
|
||||
" for one of the specified partners. If empty, the test will always be"
|
||||
" created.",
|
||||
domain="[('parent_id', '=', False)]",
|
||||
)
|
||||
timing = fields.Selection(
|
||||
selection=[
|
||||
("before", "Before"),
|
||||
("after", "After"),
|
||||
("plan_ahead", "Plan Ahead"),
|
||||
],
|
||||
default="after",
|
||||
help="* Before: An executable inspection is generated before the record "
|
||||
"related to the trigger is completed (e.g. when picking is confirmed).\n"
|
||||
"* After: An executable inspection is generated when the record related to the "
|
||||
"trigger is completed (e.g. when picking is done).\n"
|
||||
"* Plan Ahead: A non-executable inspection is generated before the record "
|
||||
"related to the trigger is completed (e.g. when picking is confirmed), and the "
|
||||
"inspection becomes executable when the record related to the trigger is "
|
||||
"completed (e.g. when picking is done).",
|
||||
)
|
||||
|
||||
def get_trigger_line_for_product(self, trigger, timings, product, partner=False):
|
||||
"""Overridable method for getting trigger_line associated to a product.
|
||||
Each inherited model will complete this module to make the search by
|
||||
product, template or category.
|
||||
:param trigger: Trigger instance.
|
||||
:param product: Product instance.
|
||||
:return: Set of trigger_lines that matches to the given product and
|
||||
trigger.
|
||||
"""
|
||||
return set()
|
||||
|
|
@ -0,0 +1,35 @@
|
|||
# Copyright 2010 NaN Projectes de Programari Lliure, S.L.
|
||||
# Copyright 2014 Serv. Tec. Avanzados - Pedro M. Baeza
|
||||
# Copyright 2014 Oihane Crucelaegui - AvanzOSC
|
||||
# Copyright 2017 ForgeFlow S.L.
|
||||
# Copyright 2017 Simone Rubino - Agile Business Group
|
||||
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
|
||||
|
||||
from odoo import fields, models
|
||||
|
||||
|
||||
class QcTriggerProductCategoryLine(models.Model):
|
||||
_inherit = "qc.trigger.line"
|
||||
_name = "qc.trigger.product_category_line"
|
||||
_description = "Quality Control Trigger Product Category Line"
|
||||
|
||||
product_category = fields.Many2one(comodel_name="product.category")
|
||||
|
||||
def get_trigger_line_for_product(self, trigger, timings, product, partner=False):
|
||||
trigger_lines = super().get_trigger_line_for_product(
|
||||
trigger, timings, product, partner=partner
|
||||
)
|
||||
category = product.categ_id
|
||||
while category:
|
||||
for trigger_line in category.qc_triggers.filtered(
|
||||
lambda r: r.trigger == trigger
|
||||
and r.timing in timings
|
||||
and (
|
||||
not r.partners
|
||||
or not partner
|
||||
or partner.commercial_partner_id in r.partners
|
||||
)
|
||||
):
|
||||
trigger_lines.add(trigger_line)
|
||||
category = category.parent_id
|
||||
return trigger_lines
|
||||
|
|
@ -0,0 +1,33 @@
|
|||
# Copyright 2010 NaN Projectes de Programari Lliure, S.L.
|
||||
# Copyright 2014 Serv. Tec. Avanzados - Pedro M. Baeza
|
||||
# Copyright 2014 Oihane Crucelaegui - AvanzOSC
|
||||
# Copyright 2017 ForgeFlow S.L.
|
||||
# Copyright 2017 Simone Rubino - Agile Business Group
|
||||
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
|
||||
|
||||
from odoo import fields, models
|
||||
|
||||
|
||||
class QcTriggerProductLine(models.Model):
|
||||
_inherit = "qc.trigger.line"
|
||||
_name = "qc.trigger.product_line"
|
||||
_description = "Quality Control Trigger Product Line"
|
||||
|
||||
product = fields.Many2one(comodel_name="product.product")
|
||||
|
||||
def get_trigger_line_for_product(self, trigger, timings, product, partner=False):
|
||||
trigger_lines = super().get_trigger_line_for_product(
|
||||
trigger, timings, product, partner=partner
|
||||
)
|
||||
for trigger_line in product.qc_triggers.filtered(
|
||||
lambda r: r.trigger == trigger
|
||||
and r.timing in timings
|
||||
and (
|
||||
not r.partners
|
||||
or not partner
|
||||
or partner.commercial_partner_id in r.partners
|
||||
)
|
||||
and r.test.active
|
||||
):
|
||||
trigger_lines.add(trigger_line)
|
||||
return trigger_lines
|
||||
|
|
@ -0,0 +1,33 @@
|
|||
# Copyright 2010 NaN Projectes de Programari Lliure, S.L.
|
||||
# Copyright 2014 Serv. Tec. Avanzados - Pedro M. Baeza
|
||||
# Copyright 2014 Oihane Crucelaegui - AvanzOSC
|
||||
# Copyright 2017 ForgeFlow S.L.
|
||||
# Copyright 2017 Simone Rubino - Agile Business Group
|
||||
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
|
||||
|
||||
from odoo import fields, models
|
||||
|
||||
|
||||
class QcTriggerProductTemplateLine(models.Model):
|
||||
_inherit = "qc.trigger.line"
|
||||
_name = "qc.trigger.product_template_line"
|
||||
_description = "Quality Control Trigger Product Template Line"
|
||||
|
||||
product_template = fields.Many2one(comodel_name="product.template")
|
||||
|
||||
def get_trigger_line_for_product(self, trigger, timings, product, partner=False):
|
||||
trigger_lines = super().get_trigger_line_for_product(
|
||||
trigger, timings, product, partner=partner
|
||||
)
|
||||
for trigger_line in product.product_tmpl_id.qc_triggers.filtered(
|
||||
lambda r: r.trigger == trigger
|
||||
and r.timing in timings
|
||||
and (
|
||||
not r.partners
|
||||
or not partner
|
||||
or partner.commercial_partner_id in r.partners
|
||||
)
|
||||
and r.test.active
|
||||
):
|
||||
trigger_lines.add(trigger_line)
|
||||
return trigger_lines
|
||||
Loading…
Add table
Add a link
Reference in a new issue